From a60a6abbc4da294afb0f8fd9038af741e4196263 Mon Sep 17 00:00:00 2001 From: benfry Date: Thu, 6 Dec 2012 22:54:39 +0000 Subject: [PATCH 001/608] renaming the java2 mode --- pdex/.classpath | 23 + pdex/.project | 17 + pdex/.settings/org.eclipse.jdt.core.prefs | 11 + pdex/build.xml | 59 + pdex/mode/readme.txt | 3 + .../processing/mode/java2/ArrayFieldNode.java | 65 + .../mode/java2/ClassLoadListener.java | 37 + pdex/src/processing/mode/java2/Compiler.java | 367 +++++ .../src/processing/mode/java2/DebugBuild.java | 73 + .../processing/mode/java2/DebugEditor.java | 1216 +++++++++++++++ pdex/src/processing/mode/java2/DebugMode.java | 165 ++ .../processing/mode/java2/DebugRunner.java | 85 + .../processing/mode/java2/DebugToolbar.java | 248 +++ pdex/src/processing/mode/java2/Debugger.java | 1364 +++++++++++++++++ pdex/src/processing/mode/java2/ErrorBar.java | 373 +++++ .../mode/java2/ErrorCheckerService.java | 1097 +++++++++++++ .../processing/mode/java2/ErrorMarker.java | 36 + .../processing/mode/java2/ErrorWindow.java | 374 +++++ pdex/src/processing/mode/java2/FieldNode.java | 65 + .../mode/java2/ImportStatement.java | 51 + .../processing/mode/java2/LineBreakpoint.java | 218 +++ .../processing/mode/java2/LineHighlight.java | 196 +++ pdex/src/processing/mode/java2/LineID.java | 269 ++++ .../processing/mode/java2/LineListener.java | 35 + .../mode/java2/LocalVariableNode.java | 66 + pdex/src/processing/mode/java2/Problem.java | 160 ++ pdex/src/processing/mode/java2/TextArea.java | 335 ++++ .../mode/java2/TextAreaPainter.java | 313 ++++ .../mode/java2/VMEventListener.java | 36 + .../processing/mode/java2/VMEventReader.java | 68 + .../mode/java2/VariableInspector.form | 53 + .../mode/java2/VariableInspector.java | 929 +++++++++++ .../processing/mode/java2/VariableNode.java | 358 +++++ .../mode/java2/XQConsoleToggle.java | 131 ++ .../processing/mode/java2/XQErrorTable.java | 161 ++ .../processing/mode/java2/XQPreprocessor.java | 245 +++ pdex/theme/buttons.gif | Bin 0 -> 6428 bytes pdex/theme/tab-sel-left.gif | Bin 0 -> 62 bytes pdex/theme/tab-sel-menu.gif | Bin 0 -> 104 bytes pdex/theme/tab-sel-mid.gif | Bin 0 -> 54 bytes pdex/theme/tab-sel-right.gif | Bin 0 -> 839 bytes pdex/theme/tab-unsel-left.gif | Bin 0 -> 62 bytes pdex/theme/tab-unsel-menu.gif | Bin 0 -> 104 bytes pdex/theme/tab-unsel-mid.gif | Bin 0 -> 54 bytes pdex/theme/tab-unsel-right.gif | Bin 0 -> 63 bytes pdex/theme/theme.txt | 133 ++ pdex/theme/var-icons.gif | Bin 0 -> 5152 bytes 47 files changed, 9435 insertions(+) create mode 100644 pdex/.classpath create mode 100644 pdex/.project create mode 100644 pdex/.settings/org.eclipse.jdt.core.prefs create mode 100644 pdex/build.xml create mode 100644 pdex/mode/readme.txt create mode 100755 pdex/src/processing/mode/java2/ArrayFieldNode.java create mode 100755 pdex/src/processing/mode/java2/ClassLoadListener.java create mode 100755 pdex/src/processing/mode/java2/Compiler.java create mode 100755 pdex/src/processing/mode/java2/DebugBuild.java create mode 100755 pdex/src/processing/mode/java2/DebugEditor.java create mode 100755 pdex/src/processing/mode/java2/DebugMode.java create mode 100755 pdex/src/processing/mode/java2/DebugRunner.java create mode 100755 pdex/src/processing/mode/java2/DebugToolbar.java create mode 100755 pdex/src/processing/mode/java2/Debugger.java create mode 100755 pdex/src/processing/mode/java2/ErrorBar.java create mode 100755 pdex/src/processing/mode/java2/ErrorCheckerService.java create mode 100755 pdex/src/processing/mode/java2/ErrorMarker.java create mode 100755 pdex/src/processing/mode/java2/ErrorWindow.java create mode 100755 pdex/src/processing/mode/java2/FieldNode.java create mode 100755 pdex/src/processing/mode/java2/ImportStatement.java create mode 100755 pdex/src/processing/mode/java2/LineBreakpoint.java create mode 100755 pdex/src/processing/mode/java2/LineHighlight.java create mode 100755 pdex/src/processing/mode/java2/LineID.java create mode 100755 pdex/src/processing/mode/java2/LineListener.java create mode 100755 pdex/src/processing/mode/java2/LocalVariableNode.java create mode 100755 pdex/src/processing/mode/java2/Problem.java create mode 100755 pdex/src/processing/mode/java2/TextArea.java create mode 100755 pdex/src/processing/mode/java2/TextAreaPainter.java create mode 100755 pdex/src/processing/mode/java2/VMEventListener.java create mode 100755 pdex/src/processing/mode/java2/VMEventReader.java create mode 100755 pdex/src/processing/mode/java2/VariableInspector.form create mode 100755 pdex/src/processing/mode/java2/VariableInspector.java create mode 100755 pdex/src/processing/mode/java2/VariableNode.java create mode 100755 pdex/src/processing/mode/java2/XQConsoleToggle.java create mode 100755 pdex/src/processing/mode/java2/XQErrorTable.java create mode 100755 pdex/src/processing/mode/java2/XQPreprocessor.java create mode 100755 pdex/theme/buttons.gif create mode 100755 pdex/theme/tab-sel-left.gif create mode 100755 pdex/theme/tab-sel-menu.gif create mode 100755 pdex/theme/tab-sel-mid.gif create mode 100755 pdex/theme/tab-sel-right.gif create mode 100755 pdex/theme/tab-unsel-left.gif create mode 100755 pdex/theme/tab-unsel-menu.gif create mode 100755 pdex/theme/tab-unsel-mid.gif create mode 100755 pdex/theme/tab-unsel-right.gif create mode 100755 pdex/theme/theme.txt create mode 100755 pdex/theme/var-icons.gif diff --git a/pdex/.classpath b/pdex/.classpath new file mode 100644 index 000000000..5bb5a9eb3 --- /dev/null +++ b/pdex/.classpath @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pdex/.project b/pdex/.project new file mode 100644 index 000000000..c754d21c8 --- /dev/null +++ b/pdex/.project @@ -0,0 +1,17 @@ + + + processing-java2 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/pdex/.settings/org.eclipse.jdt.core.prefs b/pdex/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..8000cd6ca --- /dev/null +++ b/pdex/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/pdex/build.xml b/pdex/build.xml new file mode 100644 index 000000000..2e0f18baa --- /dev/null +++ b/pdex/build.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pdex/mode/readme.txt b/pdex/mode/readme.txt new file mode 100644 index 000000000..3ec74a7e8 --- /dev/null +++ b/pdex/mode/readme.txt @@ -0,0 +1,3 @@ +Packages from Eclipse 4.2.1: +http://download.eclipse.org/eclipse/downloads/ + diff --git a/pdex/src/processing/mode/java2/ArrayFieldNode.java b/pdex/src/processing/mode/java2/ArrayFieldNode.java new file mode 100755 index 000000000..0037a84ec --- /dev/null +++ b/pdex/src/processing/mode/java2/ArrayFieldNode.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.Value; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Specialized {@link VariableNode} for representing single fields in an array. + * Overrides {@link #setValue} to properly change the value of the encapsulated + * array field. + * + * @author Martin Leopold + */ +public class ArrayFieldNode extends VariableNode { + + protected ArrayReference array; + protected int index; + + /** + * Construct an {@link ArrayFieldNode}. + * + * @param name the name + * @param type the type + * @param value the value + * @param array a reference to the array + * @param index the index inside the array + */ + public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) { + super(name, type, value); + this.array = array; + this.index = index; + } + + @Override + public void setValue(Value value) { + try { + array.setValue(index, value); + } catch (InvalidTypeException ex) { + Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotLoadedException ex) { + Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); + } + this.value = value; + } +} diff --git a/pdex/src/processing/mode/java2/ClassLoadListener.java b/pdex/src/processing/mode/java2/ClassLoadListener.java new file mode 100755 index 000000000..03c474e15 --- /dev/null +++ b/pdex/src/processing/mode/java2/ClassLoadListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.ReferenceType; + +/** + * Listener to be notified when a class is loaded in the debugger. Used by + * {@link LineBreakpoint}s to activate themselves as soon as the respective + * class is loaded. + * + * @author Martin Leopold + */ +public interface ClassLoadListener { + + /** + * Event handler called when a class is loaded. + * + * @param theClass the class + */ + public void classLoaded(ReferenceType theClass); +} diff --git a/pdex/src/processing/mode/java2/Compiler.java b/pdex/src/processing/mode/java2/Compiler.java new file mode 100755 index 000000000..ae1c9c09f --- /dev/null +++ b/pdex/src/processing/mode/java2/Compiler.java @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.io.*; +import java.lang.reflect.Method; +import processing.app.Base; +import processing.app.SketchException; +import processing.core.PApplet; + +/** + * Copied from processing.mode.java.Compiler, just added -g switch to generate + * debugging info. + * + * @author Martin Leopold + */ +public class Compiler extends processing.mode.java.Compiler { + /** + * Compile with ECJ. See http://j.mp/8paifz for documentation. + * + * @return true if successful. + * @throws RunnerException Only if there's a problem. Only then. + */ +// public boolean compile(Sketch sketch, +// File srcFolder, +// File binFolder, +// String primaryClassName, +// String sketchClassPath, +// String bootClassPath) throws RunnerException { + static public boolean compile(DebugBuild build) throws SketchException { + + // This will be filled in if anyone gets angry + SketchException exception = null; + boolean success = false; + + String baseCommand[] = new String[] { + "-g", + "-Xemacs", + //"-noExit", // not necessary for ecj + "-source", "1.6", + "-target", "1.6", + "-classpath", build.getClassPath(), + "-nowarn", // we're not currently interested in warnings (works in ecj) + "-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath + }; + //PApplet.println(baseCommand); + + // make list of code files that need to be compiled +// String[] sourceFiles = new String[sketch.getCodeCount()]; +// int sourceCount = 0; +// sourceFiles[sourceCount++] = +// new File(buildPath, primaryClassName + ".java").getAbsolutePath(); +// +// for (SketchCode code : sketch.getCode()) { +// if (code.isExtension("java")) { +// String path = new File(buildPath, code.getFileName()).getAbsolutePath(); +// sourceFiles[sourceCount++] = path; +// } +// } + String[] sourceFiles = Base.listFiles(build.getSrcFolder(), false, ".java"); + +// String[] command = new String[baseCommand.length + sourceFiles.length]; +// System.arraycopy(baseCommand, 0, command, 0, baseCommand.length); +// // append each of the files to the command string +// System.arraycopy(sourceFiles, 0, command, baseCommand.length, sourceCount); + String[] command = PApplet.concat(baseCommand, sourceFiles); + + //PApplet.println(command); + + try { + // Load errors into a local StringBuffer + final StringBuffer errorBuffer = new StringBuffer(); + + // Create single method dummy writer class to slurp errors from ecj + Writer internalWriter = new Writer() { + public void write(char[] buf, int off, int len) { + errorBuffer.append(buf, off, len); + } + + public void flush() { } + + public void close() { } + }; + // Wrap as a PrintWriter since that's what compile() wants + PrintWriter writer = new PrintWriter(internalWriter); + + //result = com.sun.tools.javac.Main.compile(command, writer); + + PrintWriter outWriter = new PrintWriter(System.out); + + // Version that's not dynamically loaded + //CompilationProgress progress = null; + //success = BatchCompiler.compile(command, outWriter, writer, progress); + + // Version that *is* dynamically loaded. First gets the mode class loader + // so that it can grab the compiler JAR files from it. + ClassLoader loader = build.getMode().getJavaModeClassLoader(); + //ClassLoader loader = build.getMode().getClassLoader(); + try { + Class batchClass = + Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader); + Class progressClass = + Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader); + Class[] compileArgs = + new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass }; + Method compileMethod = batchClass.getMethod("compile", compileArgs); + success = (Boolean) + compileMethod.invoke(null, new Object[] { command, outWriter, writer, null }); + } catch (Exception e) { + e.printStackTrace(); + throw new SketchException("Unknown error inside the compiler."); + } + + // Close out the stream for good measure + writer.flush(); + writer.close(); + + BufferedReader reader = + new BufferedReader(new StringReader(errorBuffer.toString())); + //System.err.println(errorBuffer.toString()); + + String line = null; + while ((line = reader.readLine()) != null) { + //System.out.println("got line " + line); // debug + + // get first line, which contains file name, line number, + // and at least the first line of the error message + String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*"; + String[] pieces = PApplet.match(line, errorFormat); + //PApplet.println(pieces); + + // if it's something unexpected, die and print the mess to the console + if (pieces == null) { + exception = new SketchException("Cannot parse error text: " + line); + exception.hideStackTrace(); + // Send out the rest of the error message to the console. + System.err.println(line); + while ((line = reader.readLine()) != null) { + System.err.println(line); + } + break; + } + + // translate the java filename and line number into a un-preprocessed + // location inside a source file or tab in the environment. + String dotJavaFilename = pieces[1]; + // Line numbers are 1-indexed from javac + int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1; + String errorMessage = pieces[4]; + + exception = build.placeException(errorMessage, + dotJavaFilename, + dotJavaLineIndex); + /* + int codeIndex = 0; //-1; + int codeLine = -1; + + // first check to see if it's a .java file + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode code = sketch.getCode(i); + if (code.isExtension("java")) { + if (dotJavaFilename.equals(code.getFileName())) { + codeIndex = i; + codeLine = dotJavaLineIndex; + } + } + } + + // if it's not a .java file, codeIndex will still be 0 + if (codeIndex == 0) { // main class, figure out which tab + //for (int i = 1; i < sketch.getCodeCount(); i++) { + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode code = sketch.getCode(i); + + if (code.isExtension("pde")) { + if (code.getPreprocOffset() <= dotJavaLineIndex) { + codeIndex = i; + //System.out.println("i'm thinkin file " + i); + codeLine = dotJavaLineIndex - code.getPreprocOffset(); + } + } + } + } + //System.out.println("code line now " + codeLine); + exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false); + */ + + if (exception == null) { + exception = new SketchException(errorMessage); + } + + // for a test case once message parsing is implemented, + // use new Font(...) since that wasn't getting picked up properly. + + /* + if (errorMessage.equals("cannot find symbol")) { + handleCannotFindSymbol(reader, exception); + + } else if (errorMessage.indexOf("is already defined") != -1) { + reader.readLine(); // repeats the line of code w/ error + int codeColumn = caretColumn(reader.readLine()); + exception = new RunnerException(errorMessage, + codeIndex, codeLine, codeColumn); + + } else if (errorMessage.startsWith("package") && + errorMessage.endsWith("does not exist")) { + // Because imports are stripped out and re-added to the 0th line of + // the preprocessed code, codeLine will always be wrong for imports. + exception = new RunnerException("P" + errorMessage.substring(1) + + ". You might be missing a library."); + } else { + exception = new RunnerException(errorMessage); + } + */ + if (errorMessage.startsWith("The import ") && + errorMessage.endsWith("cannot be resolved")) { + // The import poo cannot be resolved + //import poo.shoe.blah.*; + //String what = errorMessage.substring("The import ".length()); + String[] m = PApplet.match(errorMessage, "The import (.*) cannot be resolved"); + //what = what.substring(0, what.indexOf(' ')); + if (m != null) { +// System.out.println("'" + m[1] + "'"); + if (m[1].equals("processing.xml")) { + exception.setMessage("processing.xml no longer exists, this code needs to be updated for 2.0."); + System.err.println("The processing.xml library has been replaced " + + "with a new 'XML' class that's built-in."); + handleCrustyCode(); + + } else { + exception.setMessage("The package " + + "\u201C" + m[1] + "\u201D" + + " does not exist. " + + "You might be missing a library."); + System.err.println("Libraries must be " + + "installed in a folder named 'libraries' " + + "inside the 'sketchbook' folder."); + } + } + +// // Actually create the folder and open it for the user +// File sketchbookLibraries = Base.getSketchbookLibrariesFolder(); +// if (!sketchbookLibraries.exists()) { +// if (sketchbookLibraries.mkdirs()) { +// Base.openFolder(sketchbookLibraries); +// } +// } + + } else if (errorMessage.endsWith("cannot be resolved to a type")) { + // xxx cannot be resolved to a type + //xxx c; + + String what = errorMessage.substring(0, errorMessage.indexOf(' ')); + + if (what.equals("BFont") || + what.equals("BGraphics") || + what.equals("BImage")) { + exception.setMessage(what + " has been replaced with P" + what.substring(1)); + handleCrustyCode(); + + } else { + exception.setMessage("Cannot find a class or type " + + "named \u201C" + what + "\u201D"); + } + + } else if (errorMessage.endsWith("cannot be resolved")) { + // xxx cannot be resolved + //println(xxx); + + String what = errorMessage.substring(0, errorMessage.indexOf(' ')); + + if (what.equals("LINE_LOOP") || + what.equals("LINE_STRIP")) { + exception.setMessage("LINE_LOOP and LINE_STRIP are not available, " + + "please update your code."); + handleCrustyCode(); + + } else if (what.equals("framerate")) { + exception.setMessage("framerate should be changed to frameRate."); + handleCrustyCode(); + + } else if (what.equals("screen")) { + exception.setMessage("Change screen.width and screen.height to " + + "displayWidth and displayHeight."); + handleCrustyCode(); + + } else if (what.equals("screenWidth") || + what.equals("screenHeight")) { + exception.setMessage("Change screenWidth and screenHeight to " + + "displayWidth and displayHeight."); + handleCrustyCode(); + + } else { + exception.setMessage("Cannot find anything " + + "named \u201C" + what + "\u201D"); + } + + } else if (errorMessage.startsWith("Duplicate")) { + // "Duplicate nested type xxx" + // "Duplicate local variable xxx" + + } else { + String[] parts = null; + + // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX + //xxx("blah"); + // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX + //xxx("blah", 34); + // The method xxx(String, int) is undefined for the type PApplet + //PApplet.sub("ding"); + String undefined = + "The method (\\S+\\(.*\\)) is undefined for the type (.*)"; + parts = PApplet.match(errorMessage, undefined); + if (parts != null) { + if (parts[1].equals("framerate(int)")) { + exception.setMessage("framerate() no longer exists, use frameRate() instead."); + handleCrustyCode(); + + } else if (parts[1].equals("push()")) { + exception.setMessage("push() no longer exists, use pushMatrix() instead."); + handleCrustyCode(); + + } else if (parts[1].equals("pop()")) { + exception.setMessage("pop() no longer exists, use popMatrix() instead."); + handleCrustyCode(); + + } else { + String mess = "The function " + parts[1] + " does not exist."; + exception.setMessage(mess); + } + break; + } + } + if (exception != null) { + // The stack trace just shows that this happened inside the compiler, + // which is a red herring. Don't ever show it for compiler stuff. + exception.hideStackTrace(); + break; + } + } + } catch (IOException e) { + String bigSigh = "Error while compiling. (" + e.getMessage() + ")"; + exception = new SketchException(bigSigh); + e.printStackTrace(); + success = false; + } + // In case there was something else. + if (exception != null) throw exception; + + return success; + } +} diff --git a/pdex/src/processing/mode/java2/DebugBuild.java b/pdex/src/processing/mode/java2/DebugBuild.java new file mode 100755 index 000000000..7ef1b38fa --- /dev/null +++ b/pdex/src/processing/mode/java2/DebugBuild.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.io.File; +import processing.app.Sketch; +import processing.app.SketchException; +import processing.mode.java.JavaBuild; + +/** + * Copied from processing.mode.java.JavaBuild, just changed compiler. + * + * @author Martin Leopold + */ +public class DebugBuild extends JavaBuild { + + public DebugBuild(Sketch sketch) { + super(sketch); + } + + /** + * Preprocess and compile sketch. Copied from + * processing.mode.java.JavaBuild, just changed compiler. + * + * @param srcFolder + * @param binFolder + * @param sizeWarning + * @return main class name or null on compile failure + * @throws SketchException + */ + @Override + public String build(File srcFolder, File binFolder, boolean sizeWarning) throws SketchException { + this.srcFolder = srcFolder; + this.binFolder = binFolder; + +// Base.openFolder(srcFolder); +// Base.openFolder(binFolder); + + // run the preprocessor + String classNameFound = preprocess(srcFolder, sizeWarning); + + // compile the program. errors will happen as a RunnerException + // that will bubble up to whomever called build(). +// Compiler compiler = new Compiler(this); +// String bootClasses = System.getProperty("sun.boot.class.path"); +// if (compiler.compile(this, srcFolder, binFolder, primaryClassName, getClassPath(), bootClasses)) { + + if (Compiler.compile(this)) { // use compiler with debug info enabled (-g switch flicked) + sketchClassName = classNameFound; + return classNameFound; + } + return null; + } + + public DebugMode getMode() { + return (DebugMode)mode; + } +} diff --git a/pdex/src/processing/mode/java2/DebugEditor.java b/pdex/src/processing/mode/java2/DebugEditor.java new file mode 100755 index 000000000..eb41c5e2b --- /dev/null +++ b/pdex/src/processing/mode/java2/DebugEditor.java @@ -0,0 +1,1216 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.Box; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.border.EtchedBorder; +import javax.swing.table.TableModel; +import javax.swing.text.Document; +import processing.app.*; +import processing.app.syntax.JEditTextArea; +import processing.app.syntax.PdeTextAreaDefaults; +import processing.core.PApplet; +import processing.mode.java.JavaEditor; + +/** + * Main View Class. Handles the editor window including tool bar and menu. Has + * access to the Sketch. Provides line highlighting (for breakpoints and the + * debuggers current line). + * + * @author Martin Leopold + * @author Manindra Moharana <me@mkmoharana.com> + * + * + */ +public class DebugEditor extends JavaEditor implements ActionListener { + // important fields from superclass + //protected Sketch sketch; + //private JMenu fileMenu; + //protected EditorToolbar toolbar; + + // highlighting + protected Color breakpointColor = new Color(240, 240, 240); // the background color for highlighting lines + protected Color currentLineColor = new Color(255, 255, 150); // the background color for highlighting lines + protected Color breakpointMarkerColor = new Color(74, 84, 94); // the color of breakpoint gutter markers + protected Color currentLineMarkerColor = new Color(226, 117, 0); // the color of current line gutter markers + protected List breakpointedLines = new ArrayList(); // breakpointed lines + protected LineHighlight currentLine; // line the debugger is currently suspended at + protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment + // menus + protected JMenu debugMenu; // the debug menu + // debugger control + protected JMenuItem debugMenuItem; + protected JMenuItem continueMenuItem; + protected JMenuItem stopMenuItem; + // breakpoints + protected JMenuItem toggleBreakpointMenuItem; + protected JMenuItem listBreakpointsMenuItem; + // stepping + protected JMenuItem stepOverMenuItem; + protected JMenuItem stepIntoMenuItem; + protected JMenuItem stepOutMenuItem; + // info + protected JMenuItem printStackTraceMenuItem; + protected JMenuItem printLocalsMenuItem; + protected JMenuItem printThisMenuItem; + protected JMenuItem printSourceMenuItem; + protected JMenuItem printThreads; + // variable inspector + protected JMenuItem toggleVariableInspectorMenuItem; + // references + protected DebugMode dmode; // the mode + protected Debugger dbg; // the debugger + protected VariableInspector vi; // the variable inspector frame + protected TextArea ta; // the text area + + + protected ErrorBar errorBar; + /** + * Show Console button + */ + protected XQConsoleToggle btnShowConsole; + + /** + * Show Problems button + */ + protected XQConsoleToggle btnShowErrors; + + /** + * Scroll pane for Error Table + */ + protected JScrollPane errorTableScrollPane; + + /** + * Panel with card layout which contains the p5 console and Error Table + * panes + */ + protected JPanel consoleProblemsPane; + + protected XQErrorTable errorTable; + + /** + * Enable/Disable compilation checking + */ + protected boolean compilationCheckEnabled = true; + + public DebugEditor(Base base, String path, EditorState state, Mode mode) { + super(base, path, state, mode); + + // get mode + dmode = (DebugMode) mode; + + // init controller class + dbg = new Debugger(this); + + // variable inspector window + vi = new VariableInspector(this); + + // access to customized (i.e. subclassed) text area + ta = (TextArea) textarea; + + // set action on frame close +// addWindowListener(new WindowAdapter() { +// @Override +// public void windowClosing(WindowEvent e) { +// onWindowClosing(e); +// } +// }); + + // load settings from theme.txt + DebugMode theme = dmode; + breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor); + breakpointMarkerColor = theme.getThemeColor("breakpoint.marker.color", breakpointMarkerColor); + currentLineColor = theme.getThemeColor("currentline.bgcolor", currentLineColor); + currentLineMarkerColor = theme.getThemeColor("currentline.marker.color", currentLineMarkerColor); + + // set breakpoints from marker comments + for (LineID lineID : stripBreakpointComments()) { + //System.out.println("setting: " + lineID); + dbg.setBreakpoint(lineID); + } + getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here + + checkForJavaTabs(); + initializeErrorChecker(); + ta.setECSandThemeforTextArea(errorCheckerService, dmode); + addXQModeUI(); + } + + private void addXQModeUI(){ + + // Adding ErrorBar + JPanel textAndError = new JPanel(); + Box box = (Box) textarea.getParent(); + box.remove(2); // Remove textArea from it's container, i.e Box + textAndError.setLayout(new BorderLayout()); + errorBar = new ErrorBar(this, textarea.getMinimumSize().height, dmode); + textAndError.add(errorBar, BorderLayout.EAST); + textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight()); + textAndError.add(textarea); + box.add(textAndError); + + // Adding Error Table in a scroll pane + errorTableScrollPane = new JScrollPane(); + errorTable = new XQErrorTable(errorCheckerService); + // errorTableScrollPane.setBorder(new EmptyBorder(2, 2, 2, 2)); + errorTableScrollPane.setBorder(new EtchedBorder()); + errorTableScrollPane.setViewportView(errorTable); + + // Adding toggle console button + consolePanel.remove(2); + JPanel lineStatusPanel = new JPanel(); + lineStatusPanel.setLayout(new BorderLayout()); + btnShowConsole = new XQConsoleToggle(this, + XQConsoleToggle.text[0], lineStatus.getHeight()); + btnShowErrors = new XQConsoleToggle(this, + XQConsoleToggle.text[1], lineStatus.getHeight()); + btnShowConsole.addMouseListener(btnShowConsole); + + // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST); + // lineStatusPanel.add(btnShowErrors); + btnShowErrors.addMouseListener(btnShowErrors); + + JPanel toggleButtonPanel = new JPanel(new BorderLayout()); + toggleButtonPanel.add(btnShowConsole, BorderLayout.EAST); + toggleButtonPanel.add(btnShowErrors, BorderLayout.WEST); + lineStatusPanel.add(toggleButtonPanel, BorderLayout.EAST); + lineStatus.setBounds(0, 0, toggleButtonPanel.getX() - 1, + toggleButtonPanel.getHeight()); + lineStatusPanel.add(lineStatus); + consolePanel.add(lineStatusPanel, BorderLayout.SOUTH); + lineStatusPanel.repaint(); + + // Adding JPanel with CardLayout for Console/Problems Toggle + consolePanel.remove(1); + consoleProblemsPane = new JPanel(new CardLayout()); + consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.text[1]); + consoleProblemsPane.add(console, XQConsoleToggle.text[0]); + consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); + } + +// /** +// * Event handler called when closing the editor window. Kills the variable +// * inspector window. +// * +// * @param e the event object +// */ +// protected void onWindowClosing(WindowEvent e) { +// // remove var.inspector +// vi.dispose(); +// // quit running debug session +// dbg.stopDebug(); +// } + /** + * Used instead of the windowClosing event handler, since it's not called on + * mode switch. Called when closing the editor window. Stops running debug + * sessions and kills the variable inspector window. + */ + @Override + public void dispose() { + //System.out.println("window dispose"); + // quit running debug session + dbg.stopDebug(); + // remove var.inspector + vi.dispose(); + // original dispose + super.dispose(); + } + + /** + * Overrides sketch menu creation to change keyboard shortcuts from "Run". + * + * @return the sketch menu + */ + @Override + public JMenu buildSketchMenu() { + JMenuItem runItem = Toolkit.newJMenuItemShift(DebugToolbar.getTitle(DebugToolbar.RUN, false), KeyEvent.VK_R); + runItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleRun(); + } + }); + + JMenuItem presentItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.RUN, true)); + presentItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handlePresent(); + } + }); + + JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, false)); + stopItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleStop(); + } + }); + return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); + } + + /** + * Creates the debug menu. Includes ActionListeners for the menu items. + * Intended for adding to the menu bar. + * + * @return The debug menu + */ + protected JMenu buildDebugMenu() { + debugMenu = new JMenu("Debug"); + + debugMenuItem = Toolkit.newJMenuItem("Debug", KeyEvent.VK_R); + debugMenuItem.addActionListener(this); + continueMenuItem = Toolkit.newJMenuItem("Continue", KeyEvent.VK_U); + continueMenuItem.addActionListener(this); + stopMenuItem = new JMenuItem("Stop"); + stopMenuItem.addActionListener(this); + + toggleBreakpointMenuItem = Toolkit.newJMenuItem("Toggle Breakpoint", KeyEvent.VK_B); + toggleBreakpointMenuItem.addActionListener(this); + listBreakpointsMenuItem = new JMenuItem("List Breakpoints"); + listBreakpointsMenuItem.addActionListener(this); + + stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_J); + stepOverMenuItem.addActionListener(this); + stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_J); + stepIntoMenuItem.addActionListener(this); + stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_J); + stepOutMenuItem.addActionListener(this); + + printStackTraceMenuItem = new JMenuItem("Print Stack Trace"); + printStackTraceMenuItem.addActionListener(this); + printLocalsMenuItem = new JMenuItem("Print Locals"); + printLocalsMenuItem.addActionListener(this); + printThisMenuItem = new JMenuItem("Print Fields"); + printThisMenuItem.addActionListener(this); + printSourceMenuItem = new JMenuItem("Print Source Location"); + printSourceMenuItem.addActionListener(this); + printThreads = new JMenuItem("Print Threads"); + printThreads.addActionListener(this); + + toggleVariableInspectorMenuItem = Toolkit.newJMenuItem("Toggle Variable Inspector", KeyEvent.VK_I); + toggleVariableInspectorMenuItem.addActionListener(this); + + debugMenu.add(debugMenuItem); + debugMenu.add(continueMenuItem); + debugMenu.add(stopMenuItem); + debugMenu.addSeparator(); + debugMenu.add(toggleBreakpointMenuItem); + debugMenu.add(listBreakpointsMenuItem); + debugMenu.addSeparator(); + debugMenu.add(stepOverMenuItem); + debugMenu.add(stepIntoMenuItem); + debugMenu.add(stepOutMenuItem); + debugMenu.addSeparator(); + debugMenu.add(printStackTraceMenuItem); + debugMenu.add(printLocalsMenuItem); + debugMenu.add(printThisMenuItem); + debugMenu.add(printSourceMenuItem); + debugMenu.add(printThreads); + debugMenu.addSeparator(); + debugMenu.add(toggleVariableInspectorMenuItem); + debugMenu.addSeparator(); + + // XQMode menu items + + JCheckBoxMenuItem item; + final DebugEditor thisEditor = this; + item = new JCheckBoxMenuItem("Error Checker Enabled"); + item.setSelected(true); + item.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { + // unticked Menu Item + errorCheckerService.pauseThread(); + System.out.println(thisEditor.getSketch().getName() + + " - Error Checker paused."); + errorBar.errorPoints.clear(); + errorCheckerService.problemsList.clear(); + errorCheckerService.updateErrorTable(); + errorCheckerService.updateEditorStatus(); + getTextArea().repaint(); + } else { + errorCheckerService.resumeThread(); + System.out.println(thisEditor.getSketch().getName() + + " - Error Checker resumed."); + } + } + }); + debugMenu.add(item); + + problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); + // problemWindowMenuCB.setSelected(true); + problemWindowMenuCB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (errorCheckerService.errorWindow == null) + return; + errorCheckerService.errorWindow + .setVisible(((JCheckBoxMenuItem) e.getSource()) + .isSelected()); + // switch to console, now that Error Window is open + toggleView(XQConsoleToggle.text[0]); + } + }); + debugMenu.add(problemWindowMenuCB); + + showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); + showWarnings.setSelected(true); + showWarnings.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + } + }); + debugMenu.add(showWarnings); + + + return debugMenu; + } + + /** + * Show warnings menu item + */ + protected JCheckBoxMenuItem showWarnings; + + /** + * Check box menu item for show/hide Problem Window + */ + public JCheckBoxMenuItem problemWindowMenuCB; + + + public JMenu buildXQModeMenu() { + + // Enable Error Checker - CB + // Show/Hide Problem Window - CB + // Show Warnings - CB + JMenu menu = new JMenu("XQMode"); + JCheckBoxMenuItem item; + final DebugEditor thisEditor = this; + item = new JCheckBoxMenuItem("Error Checker Enabled"); + item.setSelected(true); + item.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { + // unticked Menu Item + errorCheckerService.pauseThread(); + System.out.println(thisEditor.getSketch().getName() + + " - Error Checker paused."); + errorBar.errorPoints.clear(); + errorCheckerService.problemsList.clear(); + errorCheckerService.updateErrorTable(); + errorCheckerService.updateEditorStatus(); + getTextArea().repaint(); + } else { + errorCheckerService.resumeThread(); + System.out.println(thisEditor.getSketch().getName() + + " - Error Checker resumed."); + } + } + }); + menu.add(item); + + problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); + // problemWindowMenuCB.setSelected(true); + problemWindowMenuCB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (errorCheckerService.errorWindow == null) + return; + errorCheckerService.errorWindow + .setVisible(((JCheckBoxMenuItem) e.getSource()) + .isSelected()); + // switch to console, now that Error Window is open + toggleView(XQConsoleToggle.text[0]); + } + }); + menu.add(problemWindowMenuCB); + + showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); + showWarnings.setSelected(true); + showWarnings.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + } + }); + menu.add(showWarnings); + + menu.addSeparator(); + + JMenuItem item2 = new JMenuItem("XQMode Wiki"); + item2.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Base.openURL("https://github.com/Manindra29/XQMode/wiki"); + } + }); + menu.add(item2); + + item2 = new JMenuItem("XQMode on Github"); + item2.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Base.openURL("https://github.com/Manindra29/XQMode"); + } + }); + menu.add(item2); + return menu; + } + + @Override + public JMenu buildModeMenu() { + return buildDebugMenu(); + } + + /** + * Callback for menu items. Implementation of Swing ActionListener. + * + * @param ae Action event + */ + @Override + public void actionPerformed(ActionEvent ae) { + //System.out.println("ActionEvent: " + ae.toString()); + + JMenuItem source = (JMenuItem) ae.getSource(); + if (source == debugMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item"); + //dmode.handleDebug(sketch, this); + dbg.startDebug(); + } else if (source == stopMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item"); + //dmode.handleDebug(sketch, this); + dbg.stopDebug(); + } else if (source == continueMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item"); + //dmode.handleDebug(sketch, this); + dbg.continueDebug(); + } else if (source == stepOverMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Over' menu item"); + dbg.stepOver(); + } else if (source == stepIntoMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Into' menu item"); + dbg.stepInto(); + } else if (source == stepOutMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Out' menu item"); + dbg.stepOut(); + } else if (source == printStackTraceMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item"); + dbg.printStackTrace(); + } else if (source == printLocalsMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item"); + dbg.printLocals(); + } else if (source == printThisMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item"); + dbg.printThis(); + } else if (source == printSourceMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item"); + dbg.printSource(); + } else if (source == printThreads) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item"); + dbg.printThreads(); + } else if (source == toggleBreakpointMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item"); + dbg.toggleBreakpoint(); + } else if (source == listBreakpointsMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item"); + dbg.listBreakpoints(); + } else if (source == toggleVariableInspectorMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); + toggleVariableInspector(); + } + } + +// @Override +// public void handleRun() { +// dbg.continueDebug(); +// } + /** + * Event handler called when hitting the stop button. Stops a running debug + * session or performs standard stop action if not currently debugging. + */ + @Override + public void handleStop() { + if (dbg.isStarted()) { + dbg.stopDebug(); + } else { + super.handleStop(); + } + } + + /** + * Event handler called when loading another sketch in this editor. Clears + * breakpoints of previous sketch. + * + * @param path + * @return true if a sketch was opened, false if aborted + */ + @Override + protected boolean handleOpenInternal(String path) { + boolean didOpen = super.handleOpenInternal(path); + if (didOpen && dbg != null) { + // should already been stopped (open calls handleStop) + dbg.clearBreakpoints(); + clearBreakpointedLines(); // force clear breakpoint highlights + variableInspector().reset(); // clear contents of variable inspector + } + return didOpen; + } + + /** + * Extract breakpointed lines from source code marker comments. This removes + * marker comments from the editor text. Intended to be called on loading a + * sketch, since re-setting the sketches contents after removing the markers + * will clear all breakpoints. + * + * @return the list of {@link LineID}s where breakpoint marker comments were + * removed from. + */ + protected List stripBreakpointComments() { + List bps = new ArrayList(); + // iterate over all tabs + Sketch sketch = getSketch(); + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode tab = sketch.getCode(i); + String code = tab.getProgram(); + String lines[] = code.split("\\r?\\n"); // newlines not included + //System.out.println(code); + + // scan code for breakpoint comments + int lineIdx = 0; + for (String line : lines) { + //System.out.println(line); + if (line.endsWith(breakpointMarkerComment)) { + LineID lineID = new LineID(tab.getFileName(), lineIdx); + bps.add(lineID); + //System.out.println("found breakpoint: " + lineID); + // got a breakpoint + //dbg.setBreakpoint(lineID); + int index = line.lastIndexOf(breakpointMarkerComment); + lines[lineIdx] = line.substring(0, index); + } + lineIdx++; + } + //tab.setProgram(code); + code = PApplet.join(lines, "\n"); + setTabContents(tab.getFileName(), code); + } + return bps; + } + + /** + * Add breakpoint marker comments to the source file of a specific tab. This + * acts on the source file on disk, not the editor text. Intended to be + * called just after saving the sketch. + * + * @param tabFilename the tab file name + */ + protected void addBreakpointComments(String tabFilename) { + SketchCode tab = getTab(tabFilename); + List bps = dbg.getBreakpoints(tab.getFileName()); + + // load the source file + File sourceFile = new File(sketch.getFolder(), tab.getFileName()); + //System.out.println("file: " + sourceFile); + try { + String code = Base.loadFile(sourceFile); + //System.out.println("code: " + code); + String lines[] = code.split("\\r?\\n"); // newlines not included + for (LineBreakpoint bp : bps) { + //System.out.println("adding bp: " + bp.lineID()); + lines[bp.lineID().lineIdx()] += breakpointMarkerComment; + } + code = PApplet.join(lines, "\n"); + //System.out.println("new code: " + code); + Base.saveFile(code, sourceFile); + } catch (IOException ex) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.SEVERE, null, ex); + } + } + + @Override + public boolean handleSave(boolean immediately) { + //System.out.println("handleSave " + immediately); + + // note modified tabs + final List modified = new ArrayList(); + for (int i = 0; i < getSketch().getCodeCount(); i++) { + SketchCode tab = getSketch().getCode(i); + if (tab.isModified()) { + modified.add(tab.getFileName()); + } + } + + boolean saved = super.handleSave(immediately); + if (saved) { + if (immediately) { + for (String tabFilename : modified) { + addBreakpointComments(tabFilename); + } + } else { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + for (String tabFilename : modified) { + addBreakpointComments(tabFilename); + } + } + }); + } + } + return saved; + } + + @Override + public boolean handleSaveAs() { + //System.out.println("handleSaveAs"); + String oldName = getSketch().getCode(0).getFileName(); + //System.out.println("old name: " + oldName); + boolean saved = super.handleSaveAs(); + if (saved) { + // re-set breakpoints in first tab (name has changed) + List bps = dbg.getBreakpoints(oldName); + dbg.clearBreakpoints(oldName); + String newName = getSketch().getCode(0).getFileName(); + //System.out.println("new name: " + newName); + for (LineBreakpoint bp : bps) { + LineID line = new LineID(newName, bp.lineID().lineIdx()); + //System.out.println("setting: " + line); + dbg.setBreakpoint(line); + } + // add breakpoint marker comments to source file + for (int i = 0; i < getSketch().getCodeCount(); i++) { + addBreakpointComments(getSketch().getCode(i).getFileName()); + } + + // set new name of variable inspector + vi.setTitle(getSketch().getName()); + } + return saved; + } + + /** + * Set text contents of a specific tab. Updates underlying document and text + * area. Clears Breakpoints. + * + * @param tabFilename the tab file name + * @param code the text to set + */ + protected void setTabContents(String tabFilename, String code) { + // remove all breakpoints of this tab + dbg.clearBreakpoints(tabFilename); + + SketchCode currentTab = getCurrentTab(); + + // set code of tab + SketchCode tab = getTab(tabFilename); + if (tab != null) { + tab.setProgram(code); + // this updates document and text area + // TODO: does this have any negative effects? (setting the doc to null) + tab.setDocument(null); + setCode(tab); + + // switch back to original tab + setCode(currentTab); + } + } + + /** + * Clear the console. + */ + public void clearConsole() { + console.clear(); + } + + /** + * Clear current text selection. + */ + public void clearSelection() { + setSelection(getCaretOffset(), getCaretOffset()); + } + + /** + * Select a line in the current tab. + * + * @param lineIdx 0-based line number + */ + public void selectLine(int lineIdx) { + setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx)); + } + + /** + * Set the cursor to the start of a line. + * + * @param lineIdx 0-based line number + */ + public void cursorToLineStart(int lineIdx) { + setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx)); + } + + /** + * Set the cursor to the end of a line. + * + * @param lineIdx 0-based line number + */ + public void cursorToLineEnd(int lineIdx) { + setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx)); + } + + /** + * Switch to a tab. + * + * @param tabFileName the file name identifying the tab. (as in + * {@link SketchCode#getFileName()}) + */ + public void switchToTab(String tabFileName) { + Sketch s = getSketch(); + for (int i = 0; i < s.getCodeCount(); i++) { + if (tabFileName.equals(s.getCode(i).getFileName())) { + s.setCurrentCode(i); + break; + } + } + } + + /** + * Access the debugger. + * + * @return the debugger controller object + */ + public Debugger dbg() { + return dbg; + } + + /** + * Access the mode. + * + * @return the mode object + */ + public DebugMode mode() { + return dmode; + } + + /** + * Access the custom text area object. + * + * @return the text area object + */ + public TextArea textArea() { + return ta; + } + + /** + * Access variable inspector window. + * + * @return the variable inspector object + */ + public VariableInspector variableInspector() { + return vi; + } + + public DebugToolbar toolbar() { + return (DebugToolbar) toolbar; + } + + /** + * Show the variable inspector window. + */ + public void showVariableInspector() { + vi.setVisible(true); + } + + /** + * Set visibility of the variable inspector window. + * + * @param visible true to set the variable inspector visible, false for + * invisible. + */ + public void showVariableInspector(boolean visible) { + vi.setVisible(visible); + } + + /** + * Hide the variable inspector window. + */ + public void hideVariableInspector() { + vi.setVisible(true); + } + + /** + * Toggle visibility of the variable inspector window. + */ + public void toggleVariableInspector() { + vi.setFocusableWindowState(false); // to not get focus when set visible + vi.setVisible(!vi.isVisible()); + vi.setFocusableWindowState(true); // allow to get focus again + } + + /** + * Text area factory method. Instantiates the customized TextArea. + * + * @return the customized text area object + */ + @Override + protected JEditTextArea createTextArea() { + //System.out.println("overriding creation of text area"); + return new TextArea(new PdeTextAreaDefaults(mode), this); + } + + /** + * Set the line to highlight as currently suspended at. Will override the + * breakpoint color, if set. Switches to the appropriate tab and scroll to + * the line by placing the cursor there. + * + * @param line the line to highlight as current suspended line + */ + public void setCurrentLine(LineID line) { + clearCurrentLine(); + if (line == null) { + return; // safety, e.g. when no line mapping is found and the null line is used. + } + switchToTab(line.fileName()); + // scroll to line, by setting the cursor + cursorToLineStart(line.lineIdx()); + // highlight line + currentLine = new LineHighlight(line.lineIdx(), currentLineColor, this); + currentLine.setMarker(ta.currentLineMarker, currentLineMarkerColor); + currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down + } + + /** + * Clear the highlight for the debuggers current line. + */ + public void clearCurrentLine() { + if (currentLine != null) { + currentLine.clear(); + currentLine.dispose(); + + // revert to breakpoint color if any is set on this line + for (LineHighlight hl : breakpointedLines) { + if (hl.lineID().equals(currentLine.lineID())) { + hl.paint(); + break; + } + } + currentLine = null; + } + } + + /** + * Add highlight for a breakpointed line. + * + * @param lineID the line id to highlight as breakpointed + */ + public void addBreakpointedLine(LineID lineID) { + LineHighlight hl = new LineHighlight(lineID, breakpointColor, this); + hl.setMarker(ta.breakpointMarker, breakpointMarkerColor); + breakpointedLines.add(hl); + // repaint current line if it's on this line + if (currentLine != null && currentLine.lineID().equals(lineID)) { + currentLine.paint(); + } + } + + /** + * Add highlight for a breakpointed line on the current tab. + * + * @param lineIdx the line index on the current tab to highlight as + * breakpointed + */ + //TODO: remove and replace by {@link #addBreakpointedLine(LineID lineID)} + public void addBreakpointedLine(int lineIdx) { + addBreakpointedLine(getLineIDInCurrentTab(lineIdx)); + } + + /** + * Remove a highlight for a breakpointed line. Needs to be on the current + * tab. + * + * @param lineIdx the line index on the current tab to remove a breakpoint + * highlight from + */ + public void removeBreakpointedLine(int lineIdx) { + LineID line = getLineIDInCurrentTab(lineIdx); + //System.out.println("line id: " + line.fileName() + " " + line.lineIdx()); + LineHighlight foundLine = null; + for (LineHighlight hl : breakpointedLines) { + if (hl.lineID.equals(line)) { + foundLine = hl; + break; + } + } + if (foundLine != null) { + foundLine.clear(); + breakpointedLines.remove(foundLine); + foundLine.dispose(); + // repaint current line if it's on this line + if (currentLine != null && currentLine.lineID().equals(line)) { + currentLine.paint(); + } + } + } + + /** + * Remove all highlights for breakpointed lines. + */ + public void clearBreakpointedLines() { + for (LineHighlight hl : breakpointedLines) { + hl.clear(); + hl.dispose(); + } + breakpointedLines.clear(); // remove all breakpoints + // fix highlights not being removed when tab names have changed due to opening a new sketch in same editor + ta.clearLineBgColors(); // force clear all highlights + ta.clearGutterText(); + + // repaint current line + if (currentLine != null) { + currentLine.paint(); + } + } + + /** + * Retrieve a {@link LineID} object for a line on the current tab. + * + * @param lineIdx the line index on the current tab + * @return the {@link LineID} object representing a line index on the + * current tab + */ + public LineID getLineIDInCurrentTab(int lineIdx) { + return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx); + } + + /** + * Retrieve line of sketch where the cursor currently resides. + * + * @return the current {@link LineID} + */ + protected LineID getCurrentLineID() { + String tab = getSketch().getCurrentCode().getFileName(); + int lineNo = getTextArea().getCaretLine(); + return new LineID(tab, lineNo); + } + + /** + * Check whether a {@link LineID} is on the current tab. + * + * @param line the {@link LineID} + * @return true, if the {@link LineID} is on the current tab. + */ + public boolean isInCurrentTab(LineID line) { + return line.fileName().equals(getSketch().getCurrentCode().getFileName()); + } + + /** + * Event handler called when switching between tabs. Loads all line + * background colors set for the tab. + * + * @param code tab to switch to + */ + @Override + protected void setCode(SketchCode code) { + //System.out.println("tab switch: " + code.getFileName()); + super.setCode(code); // set the new document in the textarea, etc. need to do this first + + // set line background colors for tab + if (ta != null) { // can be null when setCode is called the first time (in constructor) + // clear all line backgrounds + ta.clearLineBgColors(); + // clear all gutter text + ta.clearGutterText(); + // load appropriate line backgrounds for tab + // first paint breakpoints + for (LineHighlight hl : breakpointedLines) { + if (isInCurrentTab(hl.lineID())) { + hl.paint(); + } + } + // now paint current line (if any) + if (currentLine != null) { + if (isInCurrentTab(currentLine.lineID())) { + currentLine.paint(); + } + } + } + if (dbg() != null && dbg().isStarted()) { + dbg().startTrackingLineChanges(); + } + } + + /** + * Get a tab by its file name. + * + * @param fileName the filename to search for. + * @return the {@link SketchCode} object representing the tab, or null if + * not found + */ + public SketchCode getTab(String fileName) { + Sketch s = getSketch(); + for (SketchCode c : s.getCode()) { + if (c.getFileName().equals(fileName)) { + return c; + } + } + return null; + } + + /** + * Retrieve the current tab. + * + * @return the {@link SketchCode} representing the current tab + */ + public SketchCode getCurrentTab() { + return getSketch().getCurrentCode(); + } + + /** + * Access the currently edited document. + * + * @return the document object + */ + public Document currentDocument() { + //return ta.getDocument(); + return getCurrentTab().getDocument(); + } + + /** + * Factory method for the editor toolbar. Instantiates the customized + * toolbar. + * + * @return the toolbar + */ + @Override + public EditorToolbar createToolbar() { + return new DebugToolbar(this, base); + } + + /** + * Event Handler for double clicking in the left hand gutter area. + * + * @param lineIdx the line (0-based) that was double clicked + */ + public void gutterDblClicked(int lineIdx) { + if (dbg != null) { + dbg.toggleBreakpoint(lineIdx); + } + } + + public void statusBusy() { + statusNotice("Debugger busy..."); + } + + public void statusHalted() { + statusNotice("Debugger halted."); + } + + ErrorCheckerService errorCheckerService; + + /** + * Initializes and starts Error Checker Service + */ + private void initializeErrorChecker() { + Thread errorCheckerThread = null; + + if (errorCheckerThread == null) { + errorCheckerService = new ErrorCheckerService(this); + errorCheckerThread = new Thread(errorCheckerService); + try { + errorCheckerThread.start(); + } catch (Exception e) { + System.err + .println("Error Checker Service not initialized [XQEditor]: " + + e); + // e.printStackTrace(); + } + // System.out.println("Error Checker Service initialized."); + } + + } + + public void updateErrorBar(ArrayList problems) { + errorBar.updateErrorPoints(problems); + } + + /** + * Toggle between Console and Errors List + * + * @param buttonName + * - Button Label + */ + public void toggleView(String buttonName) { + CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); + cl.show(consoleProblemsPane, buttonName); + } + + synchronized public boolean updateTable(final TableModel tableModel) { + return errorTable.updateTable(tableModel); + } + + /** + * Checks if the sketch contains java tabs. If it does, XQMode ain't built + * for it, yet. Also, user should really start looking at Eclipse. Disable + * compilation check. + */ + private void checkForJavaTabs() { + for (int i = 0; i < this.getSketch().getCodeCount(); i++) { + if (this.getSketch().getCode(i).getExtension().equals("java")) { + compilationCheckEnabled = false; + JOptionPane.showMessageDialog(new Frame(), this + .getSketch().getName() + + " contains .java tabs. Live compilation error checking isn't " + + "supported for java tabs. Only " + + "syntax errors will be reported for .pde tabs."); + break; + } + } + } +} diff --git a/pdex/src/processing/mode/java2/DebugMode.java b/pdex/src/processing/mode/java2/DebugMode.java new file mode 100755 index 000000000..db9d71a9d --- /dev/null +++ b/pdex/src/processing/mode/java2/DebugMode.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import processing.app.Base; +import processing.app.EditorState; +import processing.app.Mode; +import processing.mode.java.JavaMode; + +/** + * Debug Mode for Processing. Built on top of JavaMode. + * + * @author Martin Leopold + */ +public class DebugMode extends JavaMode { + public static final boolean VERBOSE_LOGGING = true; + //public static final boolean VERBOSE_LOGGING = false; + public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) + + + public DebugMode(Base base, File folder) { + super(base, folder); + + // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus +// for (Mode m : base.getModeList()) { +// if (m.getClass() == JavaMode.class) { +// JavaMode jMode = (JavaMode) m; +// librariesFolder = jMode.getLibrariesFolder(); +// rebuildLibraryList(); +// break; +// } +// } + + // Fetch examples and reference from java mode + // thx to Manindra (https://github.com/martinleopold/DebugMode/issues/4) + examplesFolder = Base.getContentFile("modes/java/examples"); + // https://github.com/martinleopold/DebugMode/issues/6 + referenceFolder = Base.getContentFile("modes/java/reference"); + + // set logging level + Logger globalLogger = Logger.getLogger(""); + //Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // doesn't work on os x + if (VERBOSE_LOGGING) { + globalLogger.setLevel(Level.INFO); + } else { + globalLogger.setLevel(Level.WARNING); + } + + // enable logging to file + try { + // settings is writable for built-in modes, mode folder is not writable + File logFolder = Base.getSettingsFile("debug"); + if (!logFolder.exists()) { + logFolder.mkdir(); + } + File logFile = new File(logFolder, "DebugMode.%g.log"); + Handler handler = new FileHandler(logFile.getAbsolutePath(), LOG_SIZE, 10, false); + globalLogger.addHandler(handler); + + } catch (IOException ex) { + Logger.getLogger(DebugMode.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(DebugMode.class.getName()).log(Level.SEVERE, null, ex); + } + + // output version from manifest file + Package p = DebugMode.class.getPackage(); + String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; + //System.out.println(titleAndVersion); + Logger.getLogger(DebugMode.class.getName()).log(Level.INFO, titleAndVersion); + } + + + @Override + public String getTitle() { + return "Experimental"; + } + + + public File[] getKeywordFiles() { + return new File[] { + Base.getContentFile("modes/java/keywords.txt") + }; + } + + + /** + * Create a new editor associated with this mode. + */ + @Override + public processing.app.Editor createEditor(Base base, String path, EditorState state) { + return new DebugEditor(base, path, state, this); + } + + + /** + * Load a String value from theme.txt + * + * @param attribute the attribute key to load + * @param defaultValue the default value + * @return the attributes value, or the default value if the attribute + * couldn't be loaded + */ + public String loadThemeString(String attribute, String defaultValue) { + String newString = theme.get(attribute); + if (newString != null) { + return newString; + } + Logger.getLogger(DebugMode.class.getName()).log(Level.WARNING, "Error loading String: {0}", attribute); + return defaultValue; + } + + + /** + * Load a Color value from theme.txt + * + * @param attribute the attribute key to load + * @param defaultValue the default value + * @return the attributes value, or the default value if the attribute + * couldn't be loaded + */ + public Color getThemeColor(String attribute, Color defaultValue) { + Color newColor = theme.getColor(attribute); + if (newColor != null) { + return newColor; + } + System.out.println("error loading color: " + attribute); + Logger.getLogger(DebugMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); + return defaultValue; + } + + + public ClassLoader getJavaModeClassLoader() { + for (Mode m : base.getModeList()) { + if (m.getClass() == JavaMode.class) { + JavaMode jMode = (JavaMode) m; + return jMode.getClassLoader(); + } + } + // badness + return null; + } +} diff --git a/pdex/src/processing/mode/java2/DebugRunner.java b/pdex/src/processing/mode/java2/DebugRunner.java new file mode 100755 index 000000000..8f67b187a --- /dev/null +++ b/pdex/src/processing/mode/java2/DebugRunner.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.VirtualMachine; +import processing.app.RunnerListener; +import processing.app.SketchException; +import processing.app.exec.StreamRedirectThread; +import processing.mode.java.JavaBuild; +import processing.mode.java.runner.MessageSiphon; + +/** + * Runs a {@link JavaBuild}. Launches the build in a new debuggee VM. + * + * @author Martin Leopold + */ +public class DebugRunner extends processing.mode.java.runner.Runner { + + // important inherited fields + // protected VirtualMachine vm; + public DebugRunner(JavaBuild build, RunnerListener listener) throws SketchException { + super(build, listener); + } + + /** + * Launch the virtual machine. Simple non-blocking launch. VM starts + * suspended. + * + * @return debuggee VM or null on failure + */ + public VirtualMachine launch() { + String[] machineParamList = getMachineParams(); + String[] sketchParamList = getSketchParams(); + /* + * System.out.println("vm launch sketch params:"); for (int i=0; + * i + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.util.logging.Level; +import java.util.logging.Logger; +import processing.app.Base; +import processing.app.Editor; +import processing.mode.java.JavaToolbar; + +/** + * Custom toolbar for the editor window. Preserves original button numbers + * ({@link JavaToolbar#RUN}, {@link JavaToolbar#STOP}, {@link JavaToolbar#NEW}, + * {@link JavaToolbar#OPEN}, {@link JavaToolbar#SAVE}, {@link JavaToolbar#EXPORT}) + * which can be used e.g. in {@link #activate} and + * {@link #deactivate}. + * + * @author Martin Leopold + */ +public class DebugToolbar extends JavaToolbar { + // preserve original button id's, but re-define so they are accessible + // (they are used by DebugEditor, so they want to be public) + + static protected final int RUN = 100; // change this, to be able to get it's name via getTitle() + static protected final int DEBUG = JavaToolbar.RUN; + + static protected final int CONTINUE = 101; + static protected final int STEP = 102; + static protected final int TOGGLE_BREAKPOINT = 103; + static protected final int TOGGLE_VAR_INSPECTOR = 104; + + static protected final int STOP = JavaToolbar.STOP; + + static protected final int NEW = JavaToolbar.NEW; + static protected final int OPEN = JavaToolbar.OPEN; + static protected final int SAVE = JavaToolbar.SAVE; + static protected final int EXPORT = JavaToolbar.EXPORT; + + + // the sequence of button ids. (this maps button position = index to button ids) + static protected final int[] buttonSequence = { + DEBUG, CONTINUE, STEP, STOP, TOGGLE_BREAKPOINT, TOGGLE_VAR_INSPECTOR, + NEW, OPEN, SAVE, EXPORT + }; + + + public DebugToolbar(Editor editor, Base base) { + super(editor, base); + } + + + /** + * Initialize buttons. Loads images and adds the buttons to the toolbar. + */ + @Override + public void init() { + Image[][] images = loadImages(); + for (int idx = 0; idx < buttonSequence.length; idx++) { + int id = buttonId(idx); + addButton(getTitle(id, false), getTitle(id, true), images[idx], id == NEW || id == TOGGLE_BREAKPOINT); + } + } + + + /** + * Get the title for a toolbar button. Displayed in the toolbar when + * hovering over a button. + * @param id id of the toolbar button + * @param shift true if shift is pressed + * @return the title + */ + public static String getTitle(int id, boolean shift) { + switch (id) { + case DebugToolbar.RUN: + return JavaToolbar.getTitle(JavaToolbar.RUN, shift); + case STOP: + return JavaToolbar.getTitle(JavaToolbar.STOP, shift); + case NEW: + return JavaToolbar.getTitle(JavaToolbar.NEW, shift); + case OPEN: + return JavaToolbar.getTitle(JavaToolbar.OPEN, shift); + case SAVE: + return JavaToolbar.getTitle(JavaToolbar.SAVE, shift); + case EXPORT: + return JavaToolbar.getTitle(JavaToolbar.EXPORT, shift); + case DEBUG: + if (shift) { + return "Run"; + } else { + return "Debug"; + } + case CONTINUE: + return "Continue"; + case TOGGLE_BREAKPOINT: + return "Toggle Breakpoint"; + case STEP: + if (shift) { + return "Step Into"; + } else { + return "Step"; + } + case TOGGLE_VAR_INSPECTOR: + return "Variable Inspector"; + } + return null; + } + + + /** + * Event handler called when a toolbar button is clicked. + * @param e the mouse event + * @param idx index (i.e. position) of the toolbar button clicked + */ + @Override + public void handlePressed(MouseEvent e, int idx) { + boolean shift = e.isShiftDown(); + DebugEditor deditor = (DebugEditor) editor; + int id = buttonId(idx); // convert index/position to button id + + switch (id) { +// case DebugToolbar.RUN: +// super.handlePressed(e, JavaToolbar.RUN); +// break; + case STOP: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Stop' toolbar button"); + super.handlePressed(e, JavaToolbar.STOP); + break; + case NEW: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'New' toolbar button"); + super.handlePressed(e, JavaToolbar.NEW); + break; + case OPEN: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Open' toolbar button"); + super.handlePressed(e, JavaToolbar.OPEN); + break; + case SAVE: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Save' toolbar button"); + super.handlePressed(e, JavaToolbar.SAVE); + break; + case EXPORT: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Export' toolbar button"); + super.handlePressed(e, JavaToolbar.EXPORT); + break; + case DEBUG: + if (shift) { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button"); + deditor.handleRun(); + } else { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Debug' toolbar button"); + deditor.dbg.startDebug(); + } + break; + case CONTINUE: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Continue' toolbar button"); + deditor.dbg.continueDebug(); + break; + case TOGGLE_BREAKPOINT: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' toolbar button"); + deditor.dbg.toggleBreakpoint(); + break; + case STEP: + if (shift) { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step Into' toolbar button"); + deditor.dbg.stepInto(); + } else { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step' toolbar button"); + deditor.dbg.stepOver(); + } + break; +// case STEP_INTO: +// deditor.dbg.stepInto(); +// break; +// case STEP_OUT: +// deditor.dbg.stepOut(); +// break; + case TOGGLE_VAR_INSPECTOR: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Variable Inspector' toolbar button"); + deditor.toggleVariableInspector(); + break; + } + } + + + /** + * Activate (light up) a button. + * @param id the button id + */ + @Override + public void activate(int id) { + //System.out.println("activate button idx: " + buttonIndex(id)); + super.activate(buttonIndex(id)); + } + + + /** + * Set a button to be inactive. + * @param id the button id + */ + @Override + public void deactivate(int id) { + //System.out.println("deactivate button idx: " + buttonIndex(id)); + super.deactivate(buttonIndex(id)); + } + + + /** + * Get button position (index) from it's id. + * @param buttonId the button id + * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...) + * @return the button index + */ + protected int buttonIndex(int buttonId) { + for (int i = 0; i < buttonSequence.length; i++) { + if (buttonSequence[i] == buttonId) { + return i; + } + } + return -1; + } + + + /** + * Get the button id from its position (index). + * @param buttonIdx the button index + * @return the button id + * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...) + */ + protected int buttonId(int buttonIdx) { + return buttonSequence[buttonIdx]; + } +} diff --git a/pdex/src/processing/mode/java2/Debugger.java b/pdex/src/processing/mode/java2/Debugger.java new file mode 100755 index 000000000..e784ee305 --- /dev/null +++ b/pdex/src/processing/mode/java2/Debugger.java @@ -0,0 +1,1364 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JTree; // needed for javadocs +import javax.swing.tree.DefaultMutableTreeNode; +import processing.app.Sketch; +import processing.app.SketchCode; + +/** + * Main controller class for debugging mode. Mainly works with DebugEditor as + * the corresponding "view". Uses DebugRunner to launch a VM. + * + * @author Martin Leopold + */ +public class Debugger implements VMEventListener { + + protected DebugEditor editor; // editor window, acting as main view + protected DebugRunner runtime; // the runtime, contains debuggee VM + protected boolean started = false; // debuggee vm has started, VMStartEvent received, main class loaded + protected boolean paused = false; // currently paused at breakpoint or step + protected ThreadReference currentThread; // thread the last breakpoint or step occured in + protected String mainClassName; // name of the main class that's currently being debugged + protected ReferenceType mainClass; // the debuggee's main class + protected Set classes = new HashSet(); // holds all loaded classes in the debuggee VM + protected List classLoadListeners = new ArrayList(); // listeners for class load events + protected String srcPath; // path to the src folder of the current build + protected List breakpoints = new ArrayList(); // list of current breakpoints + protected StepRequest requestedStep; // the step request we are currently in, or null if not in a step + protected Map runtimeLineChanges = new HashMap(); // maps line number changes at runtime (orig -> changed) + protected Set runtimeTabsTracked = new HashSet(); // contains tab filenames which already have been tracked for runtime changes + + /** + * Construct a Debugger object. + * + * @param editor The Editor that will act as primary view + */ + public Debugger(DebugEditor editor) { + this.editor = editor; + } + + /** + * Access the VM. + * + * @return the virtual machine object or null if not available. + */ + public VirtualMachine vm() { + if (runtime != null) { + return runtime.vm(); + } else { + return null; + } + } + + /** + * Access the editor associated with this debugger. + * + * @return the editor object + */ + public DebugEditor editor() { + return editor; + } + + /** + * Retrieve the main class of the debuggee VM. + * + * @return the main classes {@link ReferenceType} or null if the debugger is + * not started. + */ + public ReferenceType getMainClass() { + if (isStarted()) { + return mainClass; + } else { + return null; + } + + } + + /** + * Get the {@link ReferenceType} for a class name. + * + * @param name the class name + * @return the {@link ReferenceType} or null if not found (e.g. not yet + * loaded) + */ + public ReferenceType getClass(String name) { + if (name == null) { + return null; + } + if (name.equals(mainClassName)) { + return mainClass; + } + for (ReferenceType rt : classes) { + if (rt.name().equals(name)) { + return rt; + } + } + return null; + } + + /** + * Add a class load listener. Will be notified when a class is loaded in the + * debuggee VM. + * + * @param listener the {@link ClassLoadListener} + */ + public void addClassLoadListener(ClassLoadListener listener) { + classLoadListeners.add(listener); + } + + /** + * Remove a class load listener. Cease to be notified when classes are + * loaded in the debuggee VM. + * + * @param listener {@link ClassLoadListener} + */ + public void removeClassLoadListener(ClassLoadListener listener) { + classLoadListeners.remove(listener); + } + + /** + * Start a debugging session. Builds the sketch and launches a VM to run it. + * VM starts suspended. Should produce a VMStartEvent. + */ + public synchronized void startDebug() { + //stopDebug(); // stop any running sessions + if (isStarted()) { + return; // do nothing + } + + // we are busy now + editor.statusBusy(); + + // clear console + editor.clearConsole(); + + // clear variable inspector (also resets expanded states) + editor.variableInspector().reset(); + + // load edits into sketch obj, etc... + editor.prepareRun(); + + editor.toolbar().activate(DebugToolbar.DEBUG); // after prepareRun, since this removes highlights + + try { + Sketch sketch = editor.getSketch(); + DebugBuild build = new DebugBuild(sketch); + + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "building sketch: {0}", sketch.getName()); + //LineMapping.addLineNumbers(sketch); // annotate + mainClassName = build.build(false); + //LineMapping.removeLineNumbers(sketch); // annotate + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class: {0}", mainClassName); + + // folder with assembled/preprocessed src + srcPath = build.getSrcFolder().getPath(); + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build src: {0}", srcPath); + // folder with compiled code (.class files) + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build bin: {0}", build.getBinFolder().getPath()); + + if (mainClassName != null) { + // generate the source line mapping + //lineMap = LineMapping.generateMapping(srcPath + File.separator + mainClassName + ".java"); + + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "launching debuggee runtime"); + runtime = new DebugRunner(build, editor); + VirtualMachine vm = runtime.launch(); // non-blocking + if (vm == null) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "error 37: launch failed"); + } + + // start receiving vm events + VMEventReader eventThread = new VMEventReader(vm.eventQueue(), this); + eventThread.start(); + + //return runtime; + + /* + * // launch runner in new thread new Thread(new Runnable() { + * + * @Override public void run() { runtime.launch(false); // this + * blocks until finished } }).start(); return runtime; + */ + + startTrackingLineChanges(); + editor.statusBusy(); + } + } catch (Exception e) { + editor.statusError(e); + } + } + + /** + * End debugging session. Stops and disconnects VM. Should produce + * VMDisconnectEvent. + */ + public synchronized void stopDebug() { + editor.variableInspector().lock(); + if (runtime != null) { + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "closing runtime"); + runtime.close(); + runtime = null; + //build = null; + classes.clear(); + // need to clear highlight here because, VMDisconnectedEvent seems to be unreliable. TODO: likely synchronization problem + editor.clearCurrentLine(); + } + stopTrackingLineChanges(); + started = false; + editor.toolbar().deactivate(DebugToolbar.DEBUG); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.statusEmpty(); + } + + /** + * Resume paused debugging session. Resumes VM. + */ + public synchronized void continueDebug() { + editor.toolbar().activate(DebugToolbar.CONTINUE); + editor.variableInspector().lock(); + //editor.clearSelection(); + //clearHighlight(); + editor.clearCurrentLine(); + if (!isStarted()) { + startDebug(); + } else if (isPaused()) { + runtime.vm().resume(); + paused = false; + editor.statusBusy(); + } + } + + /** + * Step through source code lines. + * + * @param stepDepth the step depth ({@link StepRequest#STEP_OVER}, + * {@link StepRequest#STEP_INTO} or {@link StepRequest#STEP_OUT}) + */ + protected void step(int stepDepth) { + if (!isStarted()) { + startDebug(); + } else if (isPaused()) { + editor.variableInspector().lock(); + editor.toolbar().activate(DebugToolbar.STEP); + + // use global to mark that there is a step request pending + requestedStep = runtime.vm().eventRequestManager().createStepRequest(currentThread, StepRequest.STEP_LINE, stepDepth); + requestedStep.addCountFilter(1); // valid for one step only + requestedStep.enable(); + paused = false; + runtime.vm().resume(); + editor.statusBusy(); + } + } + + /** + * Step over current statement. + */ + public synchronized void stepOver() { + step(StepRequest.STEP_OVER); + } + + /** + * Step into current statement. + */ + public synchronized void stepInto() { + step(StepRequest.STEP_INTO); + } + + /** + * Step out of current function. + */ + public synchronized void stepOut() { + step(StepRequest.STEP_OUT); + } + + /** + * Print the current stack trace. + */ + public synchronized void printStackTrace() { + if (isStarted()) { + printStackTrace(currentThread); + } + } + + /** + * Print local variables. Outputs type, name and value of each variable. + */ + public synchronized void printLocals() { + if (isStarted()) { + printLocalVariables(currentThread); + } + } + + /** + * Print fields of current {@code this}-object. Outputs type, name and value + * of each field. + */ + public synchronized void printThis() { + if (isStarted()) { + printThis(currentThread); + } + } + + /** + * Print a source code snippet of the current location. + */ + public synchronized void printSource() { + if (isStarted()) { + printSourceLocation(currentThread); + } + } + + /** + * Set a breakpoint on the current line. + */ + public synchronized void setBreakpoint() { + setBreakpoint(editor.getCurrentLineID()); + } + + /** + * Set a breakpoint on a line in the current tab. + * + * @param lineIdx the line index (0-based) of the current tab to set the + * breakpoint on + */ + public synchronized void setBreakpoint(int lineIdx) { + setBreakpoint(editor.getLineIDInCurrentTab(lineIdx)); + } + + /** + * Set a breakpoint. + * + * @param line the line id to set the breakpoint on + */ + public synchronized void setBreakpoint(LineID line) { + // do nothing if we are kinda busy + if (isStarted() && !isPaused()) { + return; + } + // do nothing if there already is a breakpoint on this line + if (hasBreakpoint(line)) { + return; + } + breakpoints.add(new LineBreakpoint(line, this)); + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "set breakpoint on line {0}", line); + } + + /** + * Remove a breakpoint from the current line (if set). + */ + public synchronized void removeBreakpoint() { + removeBreakpoint(editor.getCurrentLineID().lineIdx()); + } + + /** + * Remove a breakpoint from a line in the current tab. + * + * @param lineIdx the line index (0-based) in the current tab to remove the + * breakpoint from + */ + protected void removeBreakpoint(int lineIdx) { + // do nothing if we are kinda busy + if (isBusy()) { + return; + } + + LineBreakpoint bp = breakpointOnLine(editor.getLineIDInCurrentTab(lineIdx)); + if (bp != null) { + bp.remove(); + breakpoints.remove(bp); + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "removed breakpoint {0}", bp); + } + } + + /** + * Remove all breakpoints. + */ + public synchronized void clearBreakpoints() { + //TODO: handle busy-ness correctly + if (isBusy()) { + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy"); + return; + } + + for (LineBreakpoint bp : breakpoints) { + bp.remove(); + } + breakpoints.clear(); + } + + /** + * Clear breakpoints in a specific tab. + * + * @param tabFilename the tab's file name + */ + public synchronized void clearBreakpoints(String tabFilename) { + //TODO: handle busy-ness correctly + if (isBusy()) { + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy"); + return; + } + + Iterator i = breakpoints.iterator(); + while (i.hasNext()) { + LineBreakpoint bp = i.next(); + if (bp.lineID().fileName().equals(tabFilename)) { + bp.remove(); + i.remove(); + } + } + } + + /** + * Get the breakpoint on a certain line, if set. + * + * @param line the line to get the breakpoint from + * @return the breakpoint, or null if no breakpoint is set on the specified + * line. + */ + protected LineBreakpoint breakpointOnLine(LineID line) { + for (LineBreakpoint bp : breakpoints) { + if (bp.isOnLine(line)) { + return bp; + } + } + return null; + } + + /** + * Toggle a breakpoint on the current line. + */ + public synchronized void toggleBreakpoint() { + toggleBreakpoint(editor.getCurrentLineID().lineIdx()); + } + + /** + * Toggle a breakpoint on a line in the current tab. + * + * @param lineIdx the line index (0-based) in the current tab + */ + public synchronized void toggleBreakpoint(int lineIdx) { + LineID line = editor.getLineIDInCurrentTab(lineIdx); + if (!hasBreakpoint(line)) { + setBreakpoint(line.lineIdx()); + } else { + removeBreakpoint(line.lineIdx()); + } + } + + /** + * Check if there's a breakpoint on a particular line. + * + * @param line the line id + * @return true if a breakpoint is set on the given line, otherwise false + */ + protected boolean hasBreakpoint(LineID line) { + LineBreakpoint bp = breakpointOnLine(line); + return bp != null; + } + + /** + * Print a list of currently set breakpoints. + */ + public synchronized void listBreakpoints() { + if (breakpoints.isEmpty()) { + System.out.println("no breakpoints"); + } else { + System.out.println("line breakpoints:"); + for (LineBreakpoint bp : breakpoints) { + System.out.println(bp); + } + } + } + + /** + * Retrieve a list of breakpoint in a particular tab. + * + * @param tabFilename the tab's file name + * @return the list of breakpoints in the given tab + */ + public synchronized List getBreakpoints(String tabFilename) { + List list = new ArrayList(); + for (LineBreakpoint bp : breakpoints) { + if (bp.lineID().fileName().equals(tabFilename)) { + list.add(bp); + } + } + return list; + } + + /** + * Callback for VM events. Will be called from another thread. + * ({@link VMEventReader}) + * + * @param es Incoming set of events from VM + */ + @Override + public synchronized void vmEvent(EventSet es) { + for (Event e : es) { + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "*** VM Event: {0}", e.toString()); + if (e instanceof VMStartEvent) { + //initialThread = ((VMStartEvent) e).thread(); +// ThreadReference t = ((VMStartEvent) e).thread(); + //printStackTrace(t); + + // break on main class load + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on main class load: {0}", mainClassName); + ClassPrepareRequest mainClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); + mainClassPrepare.addClassFilter(mainClassName); + mainClassPrepare.enable(); + + // break on loading custom classes + for (SketchCode tab : editor.getSketch().getCode()) { + if (tab.isExtension("java")) { + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on class load: {0}", tab.getPrettyName()); + ClassPrepareRequest customClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); + customClassPrepare.addClassFilter(tab.getPrettyName()); + customClassPrepare.enable(); + } + } + + runtime.vm().resume(); + } else if (e instanceof ClassPrepareEvent) { + ClassPrepareEvent ce = (ClassPrepareEvent) e; + ReferenceType rt = ce.referenceType(); + currentThread = ce.thread(); + paused = true; // for now we're paused + + if (rt.name().equals(mainClassName)) { + //printType(rt); + mainClass = rt; + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "main class load: {0}", rt.name()); + started = true; // now that main class is loaded, we're started + } else { + classes.add(rt); // save loaded classes + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class load: {0}", rt.name()); + } + + // notify listeners + for (ClassLoadListener listener : classLoadListeners) { + if (listener != null) { + listener.classLoaded(rt); + } + } + + paused = false; // resuming now + runtime.vm().resume(); + } else if (e instanceof BreakpointEvent) { + BreakpointEvent be = (BreakpointEvent) e; + currentThread = be.thread(); // save this thread +// BreakpointRequest br = (BreakpointRequest) be.request(); + + //printSourceLocation(currentThread); + updateVariableInspector(currentThread); // this is already on the EDT + final LineID newCurrentLine = locationToLineID(be.location()); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + editor.setCurrentLine(newCurrentLine); + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + } + }); + + // hit a breakpoint during a step, need to cancel the step. + if (requestedStep != null) { + runtime.vm().eventRequestManager().deleteEventRequest(requestedStep); + requestedStep = null; + } + + // fix canvas update issue + // TODO: is this a good solution? + resumeOtherThreads(currentThread); + + paused = true; + editor.statusHalted(); + } else if (e instanceof StepEvent) { + StepEvent se = (StepEvent) e; + currentThread = se.thread(); + + //printSourceLocation(currentThread); + updateVariableInspector(currentThread); // this is already on the EDT + final LineID newCurrentLine = locationToLineID(se.location()); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + editor.setCurrentLine(newCurrentLine); + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + } + }); + + // delete the steprequest that triggered this step so new ones can be placed (only one per thread) + EventRequestManager mgr = runtime.vm().eventRequestManager(); + mgr.deleteEventRequest(se.request()); + requestedStep = null; // mark that there is no step request pending + paused = true; + editor.statusHalted(); + + // disallow stepping into invisible lines + if (!locationIsVisible(se.location())) { + stepOutIntoViewOrContinue(); // TODO: this leads to stepping, should it run on the EDT? + } + } else if (e instanceof VMDisconnectEvent) { +// started = false; +// // clear line highlight +// editor.clearCurrentLine(); + stopDebug(); + } else if (e instanceof VMDeathEvent) { + started = false; + editor.statusEmpty(); + } + } + } + + /** + * Check whether a location corresponds to a code line in the editor. + * + * @param l the location + * @return true if the location corresponds to a line in the editor + */ + protected boolean locationIsVisible(Location l) { + return locationToLineID(l) != null; + } + + /** + * Step out if this results in a visible location, otherwise continue. + */ + protected void stepOutIntoViewOrContinue() { + try { + List frames = currentThread.frames(); + if (frames.size() > 1) { + if (locationIsVisible(frames.get(1).location())) { + //System.out.println("stepping out to: " + locationToString(frames.get(1).location())); + stepOut(); + return; + } + } + continueDebug(); + +// //Step out to the next visible location on the stack frame +// if (thread.frames(i, i1)) +// for (StackFrame f : thread.frames()) { +// Location l = f.location(); +// if (locationIsVisible(l)) { +// System.out.println("need to step out to: " + locationToString(l)); +// } +// } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Check whether a debugging session is running. i.e. the debugger is + * connected to a debuggee VM, VMStartEvent has been received and main class + * is loaded. + * + * @return true if the debugger is started. + */ + public synchronized boolean isStarted() { + return started && runtime != null && runtime.vm() != null; + } + + /** + * Check whether the debugger is paused. i.e. it is currently suspended at a + * breakpoint or step. + * + * @return true if the debugger is paused, false otherwise or if not started + * ({@link #isStarted()}) + */ + public synchronized boolean isPaused() { + return isStarted() && paused && currentThread != null && currentThread.isSuspended(); + } + + /** + * Check whether the debugger is currently busy. i.e. running (not + * suspended). + * + * @return true if the debugger is currently running and not suspended. + */ + public synchronized boolean isBusy() { + return isStarted() && !isPaused(); + } + + /** + * Print call stack trace of a thread. Only works on suspended threads. + * + * @param t suspended thread to print stack trace of + */ + protected void printStackTrace(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + System.out.println("stack trace for thread " + t.name() + ":"); + int i = 0; + for (StackFrame f : t.frames()) { +// Location l = f.location(); + System.out.println(i++ + ": " + f.toString()); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Resume all other threads except the one given as parameter. Useful e.g. + * to just keep the thread suspended a breakpoint occurred in. + * + * @param t the thread not to resume + */ + protected void resumeOtherThreads(ThreadReference t) { + if (!isStarted()) { + return; + } + for (ThreadReference other : vm().allThreads()) { + if (!other.equals(t) && other.isSuspended()) { + other.resume(); + } + } + } + + /** + * Print info about all current threads. Includes name, status, isSuspended, + * isAtBreakpoint. + */ + public synchronized void printThreads() { + if (!isPaused()) { + return; + } + System.out.println("threads:"); + for (ThreadReference t : vm().allThreads()) { + printThread(t); + } + } + + /** + * Print info about a thread. Includes name, status, isSuspended, + * isAtBreakpoint. + * + * @param t the thread to print info about + */ + protected void printThread(ThreadReference t) { + System.out.println(t.name()); + System.out.println(" is suspended: " + t.isSuspended()); + System.out.println(" is at breakpoint: " + t.isAtBreakpoint()); + System.out.println(" status: " + threadStatusToString(t.status())); + } + + /** + * Convert a status code returned by {@link ThreadReference#status() } to a + * human readable form. + * + * @param status {@link ThreadReference#THREAD_STATUS_MONITOR}, + * {@link ThreadReference#THREAD_STATUS_NOT_STARTED}, + * {@link ThreadReference#THREAD_STATUS_RUNNING}, + * {@link ThreadReference#THREAD_STATUS_SLEEPING}, + * {@link ThreadReference#THREAD_STATUS_UNKNOWN}, + * {@link ThreadReference#THREAD_STATUS_WAIT} or + * {@link ThreadReference#THREAD_STATUS_ZOMBIE} + * @return String containing readable status code. + */ + protected String threadStatusToString(int status) { + switch (status) { + case ThreadReference.THREAD_STATUS_MONITOR: + return "THREAD_STATUS_MONITOR"; + case ThreadReference.THREAD_STATUS_NOT_STARTED: + return "THREAD_STATUS_NOT_STARTED"; + case ThreadReference.THREAD_STATUS_RUNNING: + return "THREAD_STATUS_RUNNING"; + case ThreadReference.THREAD_STATUS_SLEEPING: + return "THREAD_STATUS_SLEEPING"; + case ThreadReference.THREAD_STATUS_UNKNOWN: + return "THREAD_STATUS_UNKNOWN"; + case ThreadReference.THREAD_STATUS_WAIT: + return "THREAD_STATUS_WAIT"; + case ThreadReference.THREAD_STATUS_ZOMBIE: + return "THREAD_STATUS_ZOMBIE"; + default: + return ""; + } + } + + /** + * Print local variables on a suspended thread. Takes the topmost stack + * frame and lists all local variables and their values. + * + * @param t suspended thread + */ + protected void printLocalVariables(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + if (t.frameCount() == 0) { + System.out.println("call stack empty"); + } else { + StackFrame sf = t.frame(0); + List locals = sf.visibleVariables(); + if (locals.isEmpty()) { + System.out.println("no local variables"); + return; + } + for (LocalVariable lv : locals) { + System.out.println(lv.typeName() + " " + lv.name() + " = " + sf.getValue(lv)); + } + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } catch (AbsentInformationException ex) { + System.out.println("local variable information not available"); + } + } + + /** + * Update variable inspector window. Displays local variables and this + * fields. + * + * @param t suspended thread to retrieve locals and this + */ + protected void updateVariableInspector(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + if (t.frameCount() == 0) { + // TODO: needs to be handled in a better way: + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "call stack empty"); + } else { + final VariableInspector vi = editor.variableInspector(); + // first get data + final List stackTrace = getStackTrace(t); + final List locals = getLocals(t, 0); + final String currentLocation = currentLocation(t); + final List thisFields = getThisFields(t, 0, true); + final List declaredThisFields = getThisFields(t, 0, false); + final String thisName = thisName(t); + // now update asynchronously + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //System.out.println("updating vi. from EDT: " + javax.swing.SwingUtilities.isEventDispatchThread()); + vi.updateCallStack(stackTrace, "Call Stack"); + vi.updateLocals(locals, "Locals at " + currentLocation); + vi.updateThisFields(thisFields, "Class " + thisName); + vi.updateDeclaredThisFields(declaredThisFields, "Class " + thisName); + vi.unlock(); // need to do this before rebuilding, otherwise we get these ... dots in the labels + vi.rebuild(); + } + }); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Get the class name of the current this object in a suspended thread. + * + * @param t a suspended thread + * @return the class name of this + */ + protected String thisName(ThreadReference t) { + try { + if (!t.isSuspended() || t.frameCount() == 0) { + return ""; + } + return t.frame(0).thisObject().referenceType().name(); + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return ""; + } + } + + /** + * Get a description of the current location in a suspended thread. Format: + * class.method:translated_line_number + * + * @param t a suspended thread + * @return descriptive string for the given location + */ + protected String currentLocation(ThreadReference t) { + try { + if (!t.isSuspended() || t.frameCount() == 0) { + return ""; + } + return locationToString(t.frame(0).location()); + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return ""; + } + } + + /** + * Get a string describing a location. Format: + * class.method:translated_line_number + * + * @param l a location + * @return descriptive string for the given location + */ + protected String locationToString(Location l) { + LineID line = locationToLineID(l); + int lineNumber; + if (line != null) { + lineNumber = line.lineIdx() + 1; + } else { + lineNumber = l.lineNumber(); + } + return l.declaringType().name() + "." + l.method().name() + ":" + lineNumber; + } + + /** + * Compile a list of current locals usable for insertion into a + * {@link JTree}. Recursively resolves object references. + * + * @param t the suspended thread to get locals for + * @param depth how deep to resolve nested object references. 0 will not + * resolve nested objects. + * @return the list of current locals + */ + protected List getLocals(ThreadReference t, int depth) { + //System.out.println("getting locals"); + List vars = new ArrayList(); + try { + if (t.frameCount() > 0) { + StackFrame sf = t.frame(0); + for (LocalVariable lv : sf.visibleVariables()) { + //System.out.println("local var: " + lv.name()); + Value val = sf.getValue(lv); + VariableNode var = new LocalVariableNode(lv.name(), lv.typeName(), val, lv, sf); + if (depth > 0) { + var.addChildren(getFields(val, depth - 1, true)); + } + vars.add(var); + } + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "local variable information not available", ex); + } + return vars; + } + + /** + * Compile a list of fields in the current this object usable for insertion + * into a {@link JTree}. Recursively resolves object references. + * + * @param t the suspended thread to get locals for + * @param depth how deep to resolve nested object references. 0 will not + * resolve nested objects. + * @return the list of fields in the current this object + */ + protected List getThisFields(ThreadReference t, int depth, boolean includeInherited) { + //System.out.println("getting this"); + try { + if (t.frameCount() > 0) { + StackFrame sf = t.frame(0); + ObjectReference thisObj = sf.thisObject(); + return getFields(thisObj, depth, includeInherited); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + return new ArrayList(); + } + + /** + * Recursively get the fields of a {@link Value} for insertion into a + * {@link JTree}. + * + * @param value must be an instance of {@link ObjectReference} + * @param depth the current depth + * @param maxDepth the depth to stop at (inclusive) + * @return list of child fields of the given value + */ + protected List getFields(Value value, int depth, int maxDepth, boolean includeInherited) { + // remember: Value <- ObjectReference, ArrayReference + List vars = new ArrayList(); + if (depth <= maxDepth) { + if (value instanceof ArrayReference) { + return getArrayFields((ArrayReference) value); + } else if (value instanceof ObjectReference) { + ObjectReference obj = (ObjectReference) value; + // get the fields of this object + List fields = includeInherited ? obj.referenceType().visibleFields() : obj.referenceType().fields(); + for (Field field : fields) { + Value val = obj.getValue(field); // get the value, may be null + VariableNode var = new FieldNode(field.name(), field.typeName(), val, field, obj); + // recursively add children + if (val != null) { + var.addChildren(getFields(val, depth + 1, maxDepth, includeInherited)); + } + vars.add(var); + } + } + } + return vars; + } + + /** + * Recursively get the fields of a {@link Value} for insertion into a + * {@link JTree}. + * + * @param value must be an instance of {@link ObjectReference} + * @param maxDepth max recursion depth. 0 will give only direct children + * @return list of child fields of the given value + */ + protected List getFields(Value value, int maxDepth, boolean includeInherited) { + return getFields(value, 0, maxDepth, includeInherited); + } + + /** + * Get the fields of an array for insertion into a {@link JTree}. + * + * @param array the array reference + * @return list of array fields + */ + protected List getArrayFields(ArrayReference array) { + List fields = new ArrayList(); + if (array != null) { + String arrayType = array.type().name(); + if (arrayType.endsWith("[]")) { + arrayType = arrayType.substring(0, arrayType.length() - 2); + } + int i = 0; + for (Value val : array.getValues()) { + VariableNode var = new ArrayFieldNode("[" + i + "]", arrayType, val, array, i); + fields.add(var); + i++; + } + } + return fields; + } + + /** + * Get the current call stack trace usable for insertion into a + * {@link JTree}. + * + * @param t the suspended thread to retrieve the call stack from + * @return call stack as list of {@link DefaultMutableTreeNode}s + */ + protected List getStackTrace(ThreadReference t) { + List stack = new ArrayList(); + try { +// int i = 0; + for (StackFrame f : t.frames()) { + stack.add(new DefaultMutableTreeNode(locationToString(f.location()))); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + return stack; + } + + /** + * Print visible fields of current "this" object on a suspended thread. + * Prints type, name and value. + * + * @param t suspended thread + */ + protected void printThis(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + if (t.frameCount() == 0) { + // TODO: needs to be handled in a better way + System.out.println("call stack empty"); + } else { + StackFrame sf = t.frame(0); + ObjectReference thisObject = sf.thisObject(); + if (this != null) { + ReferenceType type = thisObject.referenceType(); + System.out.println("fields in this (" + type.name() + "):"); + for (Field f : type.visibleFields()) { + System.out.println(f.typeName() + " " + f.name() + " = " + thisObject.getValue(f)); + } + } else { + System.out.println("can't get this (in native or static method)"); + } + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Print source code snippet of current location in a suspended thread. + * + * @param t suspended thread + */ + protected void printSourceLocation(ThreadReference t) { + try { + if (t.frameCount() == 0) { + // TODO: needs to be handled in a better way + System.out.println("call stack empty"); + } else { + Location l = t.frame(0).location(); // current stack frame location + printSourceLocation(l); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Print source code snippet. + * + * @param l {@link Location} object to print source code for + */ + protected void printSourceLocation(Location l) { + try { + //System.out.println(l.sourceName() + ":" + l.lineNumber()); + System.out.println("in method " + l.method() + ":"); + System.out.println(getSourceLine(l.sourcePath(), l.lineNumber(), 2)); + + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Read a line from the given file in the builds src folder. 1-based i.e. + * first line has line no. 1 + * + * @param filePath + * @param lineNo + * @return the requested source line + */ + protected String getSourceLine(String filePath, int lineNo, int radius) { + if (lineNo == -1) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "invalid line number: {0}", lineNo); + return ""; + } + //System.out.println("getting line: " + lineNo); + File f = new File(srcPath + File.separator + filePath); + String output = ""; + try { + BufferedReader r = new BufferedReader(new FileReader(f)); + int i = 1; + //String line = ""; + while (i <= lineNo + radius) { + String line = r.readLine(); // line no. i + if (line == null) { + break; // end of file + } + if (i >= lineNo - radius) { + if (i > lineNo - radius) { + output += "\n"; // add newlines before all lines but the first + } + output += f.getName() + ":" + i + (i == lineNo ? " => " : " ") + line; + } + i++; + } + r.close(); + return output; + } catch (FileNotFoundException ex) { + //System.err.println(ex); + return f.getName() + ":" + lineNo; + } catch (IOException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return ""; + } + } + + /** + * Print info about a ReferenceType. Prints class name, source file name, + * lists methods. + * + * @param rt the reference type to print out + */ + protected void printType(ReferenceType rt) { + System.out.println("ref.type: " + rt); + System.out.println("name: " + rt.name()); + try { + System.out.println("sourceName: " + rt.sourceName()); + } catch (AbsentInformationException ex) { + System.out.println("sourceName: unknown"); + } + System.out.println("methods:"); + for (Method m : rt.methods()) { + System.out.println(m.toString()); + } + } + + /** + * Translate a java source location to a sketch line id. + * + * @param l the location to translate + * @return the corresponding line id, or null if not found + */ + protected LineID locationToLineID(Location l) { + try { + //return lineMap.get(LineID.create(l.sourceName(), l.lineNumber() - 1)); + return javaToSketchLine(new LineID(l.sourceName(), l.lineNumber() - 1)); + + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return null; + } + } + + /** + * Translate a line (index) from java space to sketch space. + * + * @param javaLine the java line id + * @return the corresponding sketch line id or null if failed to translate + */ + public LineID javaToSketchLine(LineID javaLine) { + Sketch sketch = editor.getSketch(); + + // it may belong to a pure java file created in the sketch + // try to find an exact filename match and check the extension + SketchCode tab = editor.getTab(javaLine.fileName()); + if (tab != null && tab.isExtension("java")) { + // can translate 1:1 + return originalToRuntimeLine(javaLine); + } + + // check if it is the preprocessed/assembled file for this sketch + // java file name needs to match the sketches filename + if (!javaLine.fileName().equals(sketch.getName() + ".java")) { + return null; + } + + // find the tab (.pde file) this line belongs to + // get the last tab that has an offset not greater than the java line number + for (int i = sketch.getCodeCount() - 1; i >= 0; i--) { + tab = sketch.getCode(i); + // ignore .java files + // the tab's offset must not be greater than the java line number + if (tab.isExtension("pde") && tab.getPreprocOffset() <= javaLine.lineIdx()) { + return originalToRuntimeLine(new LineID(tab.getFileName(), javaLine.lineIdx() - tab.getPreprocOffset())); + } + } + + return null; + } + + /** + * Get the runtime-changed line id for an original sketch line. Used to + * translate line numbers from the VM (which runs on the original line + * numbers) to their current (possibly changed) counterparts. + * + * @param line the original line id (at compile time) + * @return the changed version or the line given as parameter if not found + */ + protected LineID originalToRuntimeLine(LineID line) { + LineID transformed = runtimeLineChanges.get(line); + if (transformed == null) { + return line; + } + return transformed; + } + + /** + * Get the original line id for a sketch line that was changed at runtime. + * Used to translate line numbers from the UI at runtime (which can differ + * from the ones the VM runs on) to their original counterparts. + * + * @param line the (possibly) changed runtime line + * @return the original line or the line given as parameter if not found + */ + protected LineID runtimeToOriginalLine(LineID line) { + for (Entry entry : runtimeLineChanges.entrySet()) { + if (entry.getValue().equals(line)) { + return entry.getKey(); + } + } + return line; + } + + /** + * Translate a line (index) from sketch space to java space. + * + * @param sketchLine the sketch line id + * @return the corresponding java line id or null if failed to translate + */ + public LineID sketchToJavaLine(LineID sketchLine) { + sketchLine = runtimeToOriginalLine(sketchLine); // transform back to orig (before changes at runtime) + + // check if there is a tab for this line + SketchCode tab = editor.getTab(sketchLine.fileName()); + if (tab == null) { + return null; + } + + // check if the tab is a pure java file anyway + if (tab.isExtension("java")) { + // 1:1 translation + return sketchLine; + } + + // the java file has a name sketchname.java + // just add the tab's offset to get the java name + LineID javaLine = new LineID(editor.getSketch().getName() + ".java", sketchLine.lineIdx() + tab.getPreprocOffset()); + return javaLine; + } + + /** + * Start tracking all line changes (due to edits) in the current tab. + */ + // TODO: maybe move this to the editor? + protected void startTrackingLineChanges() { + SketchCode tab = editor.getSketch().getCurrentCode(); + if (runtimeTabsTracked.contains(tab.getFileName())) { + return; + } + + for (int i = 0; i < tab.getLineCount(); i++) { + LineID old = new LineID(tab.getFileName(), i); + LineID tracked = new LineID(tab.getFileName(), i); + tracked.startTracking(editor.currentDocument()); + runtimeLineChanges.put(old, tracked); + } + runtimeTabsTracked.add(tab.getFileName()); + //System.out.println("tracking tab: " + tab.getFileName()); + } + + /** + * Stop tracking line changes in all tabs. + */ + protected void stopTrackingLineChanges() { + //System.out.println("stop tracking line changes"); + for (LineID tracked : runtimeLineChanges.values()) { + tracked.stopTracking(); + } + runtimeLineChanges.clear(); + runtimeTabsTracked.clear(); + } +} diff --git a/pdex/src/processing/mode/java2/ErrorBar.java b/pdex/src/processing/mode/java2/ErrorBar.java new file mode 100755 index 000000000..05271f7a9 --- /dev/null +++ b/pdex/src/processing/mode/java2/ErrorBar.java @@ -0,0 +1,373 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.java2; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.util.ArrayList; + +import javax.swing.JPanel; +import javax.swing.SwingWorker; + +import processing.app.Base; +import processing.app.SketchCode; + +/** + * The bar on the left of the text area which displays all errors as rectangles.
+ *
+ * All errors and warnings of a sketch are drawn on the bar, clicking on one, + * scrolls to the tab and location. Error messages displayed on hover. Markers + * are not in sync with the error line. Similar to eclipse's right error bar + * which displays the overall errors in a document + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class ErrorBar extends JPanel { + /** + * Preferred height of the component + */ + protected int preferredHeight; + + /** + * Preferred height of the component + */ + protected int preferredWidth = 12; + + /** + * Height of marker + */ + public static final int errorMarkerHeight = 4; + + /** + * Color of Error Marker + */ + public Color errorColor = new Color(0xED2630); + + /** + * Color of Warning Marker + */ + public Color warningColor = new Color(0xFFC30E); + + /** + * Background color of the component + */ + public Color backgroundColor = new Color(0x2C343D); + + protected DebugEditor editor; + + protected ErrorCheckerService errorCheckerService; + + /** + * Stores error markers displayed PER TAB along the error bar. + */ + protected ArrayList errorPoints = new ArrayList(); + + protected ArrayList errorPointsOld = new ArrayList(); + + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setColor(backgroundColor); + g.fillRect(0, 0, getWidth(), getHeight()); + + for (ErrorMarker emarker : errorPoints) { + if (emarker.type == ErrorMarker.Error) { + g.setColor(errorColor); + } + else { + g.setColor(warningColor); + } + g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight); + } + } + + public Dimension getPreferredSize() { + return new Dimension(preferredWidth, preferredHeight); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public ErrorBar(DebugEditor editor, int height, DebugMode mode) { + this.editor = editor; + this.preferredHeight = height; + this.errorCheckerService = editor.errorCheckerService; + errorColor = mode.getThemeColor("errorbar.errorcolor", errorColor); + warningColor = mode.getThemeColor("errorbar.warningcolor", + warningColor); + backgroundColor = mode.getThemeColor("errorbar.backgroundcolor", + backgroundColor); + addListeners(); + } + + /** + * Update error markers in the error bar. + * + * @param problems + * - List of problems. + */ + synchronized public void updateErrorPoints(final ArrayList problems) { + + // NOTE TO SELF: ErrorMarkers are calculated for the present tab only + // Error Marker index in the arraylist is LOCALIZED for current tab. + + final int fheight = this.getHeight(); + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + int bigCount = 0; + int totalLines = 0; + int currentTab = 0; + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + sc.setPreprocOffset(bigCount); + + try { + if (editor.getSketch().getCurrentCode().equals(sc)) { + // Adding + 1 to len because \n gets appended for each + // sketchcode extracted during processPDECode() + totalLines = Base.countLines(sc.getDocument().getText( + 0, sc.getDocument().getLength())) + 1; + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + currentTab++; + } + // System.out.println("Total lines: " + totalLines); + + errorPointsOld.clear(); + for (ErrorMarker marker : errorPoints) { + errorPointsOld.add(marker); + } + errorPoints.clear(); + + // Each problem.getSourceLine() will have an extra line added because of + // class declaration in the beginning + for (Problem problem : problems) { + if (problem.tabIndex == currentTab) { + // Ratio of error line to total lines + float y = problem.lineNumber / ((float) totalLines); + // Ratio multiplied by height of the error bar + y *= fheight - 15; // -15 is just a vertical offset + errorPoints.add(new ErrorMarker(problem, (int) y, problem + .isError() ? ErrorMarker.Error : ErrorMarker.Warning)); + // System.out.println("Y: " + y); + } + } + + repaint(); + } + }; + + try { + worker.execute(); // I eat concurrency bugs for breakfast. + } catch (Exception exp) { + System.out.println("Errorbar update markers is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } + } + + /** + * Check if new errors have popped up in the sketch since the last check + * + * @return true - if errors have changed + */ + public boolean errorPointsChanged() { + if (errorPointsOld.size() != errorPoints.size()) { + editor.getTextArea().repaint(); + // System.out.println("2 Repaint " + System.currentTimeMillis()); + return true; + } + + else { + for (int i = 0; i < errorPoints.size(); i++) { + if (errorPoints.get(i).y != errorPointsOld.get(i).y) { + editor.getTextArea().repaint(); + // System.out.println("3 Repaint " + + // System.currentTimeMillis()); + return true; + } + } + } + return false; + } + + /** + * Add various mouse listeners. + */ + protected void addListeners() { + + this.addMouseListener(new MouseAdapter() { + + // Find out which error/warning the user has clicked + // and then scroll to that + @SuppressWarnings("rawtypes") + @Override + public void mouseClicked(final MouseEvent e) { + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + for (ErrorMarker eMarker : errorPoints) { + // -2 and +2 are extra allowance, clicks in the + // vicinity of the markers register that way + if (e.getY() >= eMarker.y - 2 + && e.getY() <= eMarker.y + 2 + + errorMarkerHeight) { + int currentTabErrorIndex = errorPoints + .indexOf(eMarker); + // System.out.println("Index: " + + // currentTabErrorIndex); + int currentTab = editor.getSketch() + .getCodeIndex( + editor.getSketch() + .getCurrentCode()); + + int totalErrorIndex = currentTabErrorIndex; + + for (int i = 0; i < errorCheckerService.problemsList + .size(); i++) { + Problem p = errorCheckerService.problemsList + .get(i); + if (p.tabIndex < currentTab) + totalErrorIndex++; + if (p.tabIndex == currentTab) + break; + } + errorCheckerService + .scrollToErrorLine(totalErrorIndex); + } + } + + } + }; + + try { + worker.execute(); + } catch (Exception exp) { + System.out.println("Errorbar mouseClicked is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } + + } + }); + + // Tooltip on hover + this.addMouseMotionListener(new MouseMotionListener() { + + @SuppressWarnings("rawtypes") + @Override + public void mouseMoved(final MouseEvent e) { + // System.out.println(e); + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + + for (ErrorMarker eMarker : errorPoints) { + if (e.getY() >= eMarker.y - 2 + && e.getY() <= eMarker.y + 2 + + errorMarkerHeight) { + // System.out.println("Index: " + + // errorPoints.indexOf(y)); + int currentTab = editor.getSketch() + .getCodeIndex( + editor.getSketch() + .getCurrentCode()); + int currentTabErrorCount = 0; + + for (int i = 0; i < errorPoints.size(); i++) { + Problem p = errorPoints.get(i).problem; + if (p.tabIndex == currentTab) { + if (currentTabErrorCount == errorPoints + .indexOf(eMarker)) { + // System.out.println("Roger that."); + String msg = (p.isError() ? "Error: " + : "Warning: ") + + p.message; + setToolTipText(msg); + setCursor(Cursor + .getPredefinedCursor(Cursor.HAND_CURSOR)); + return; + } else { + currentTabErrorCount++; + // System.out.println("Still looking.."); + } + } + + } + } + // Reset cursor and tooltip + else { + setToolTipText(""); + setCursor(Cursor + .getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + } + + } + }; + try { + worker.execute(); + } catch (Exception exp) { + System.out + .println("Errorbar mousemoved Worker is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } + } + + @Override + public void mouseDragged(MouseEvent arg0) { + + } + }); + + } + +} diff --git a/pdex/src/processing/mode/java2/ErrorCheckerService.java b/pdex/src/processing/mode/java2/ErrorCheckerService.java new file mode 100755 index 000000000..c54486d0d --- /dev/null +++ b/pdex/src/processing/mode/java2/ErrorCheckerService.java @@ -0,0 +1,1097 @@ +package processing.mode.java2; + +import java.awt.EventQueue; +import java.io.File; +import java.io.FileFilter; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.table.DefaultTableModel; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; + +import processing.app.Base; +import processing.app.Library; +import processing.app.SketchCode; +import processing.core.PApplet; + +public class ErrorCheckerService implements Runnable{ + + private DebugEditor editor; + /** + * Error check happens every sleepTime milliseconds + */ + public static final int sleepTime = 1000; + + /** + * The amazing eclipse ast parser + */ + private ASTParser parser; + + /** + * Used to indirectly stop the Error Checker Thread + */ + public boolean stopThread = false; + + /** + * If true, Error Checking is paused. Calls to checkCode() become useless. + */ + private boolean pauseThread = false; + + protected ErrorWindow errorWindow; +// protected ErrorBar errorBar; + /** + * IProblem[] returned by parser stored in here + */ + private IProblem[] problems; + + /** + * Class name of current sketch + */ + protected String className; + + /** + * Source code of current sketch + */ + protected String sourceCode; + + /** + * URLs of extra imports jar files stored here. + */ + protected URL[] classpath; + + /** + * P5 Preproc offset + */ + private int scPreProcOffset = 0; + + /** + * Stores all Problems in the sketch + */ + public ArrayList problemsList; + + /** + * How many lines are present till the initial class declaration? In static + * mode, this would include imports, class declaration and setup + * declaration. In nomral mode, this would include imports, class + * declaration only. It's fate is decided inside preprocessCode() + */ + public int mainClassOffset; + + /** + * Is the sketch running in static mode or active mode? + */ + public boolean staticMode = false; + + /** + * Compilation Unit for current sketch + */ + protected CompilationUnit cu; + + /** + * If true, compilation checker will be reloaded with updated classpath + * items. + */ + private boolean loadCompClass = true; + + /** + * Compiler Checker class. Note that methods for compilation checking are + * called from the compilationChecker object, not from this + */ + protected Class checkerClass; + + /** + * Compilation Checker object. + */ + protected Object compilationChecker; + + + /** + * List of jar files to be present in compilation checker's classpath + */ + protected ArrayList classpathJars; + + /** + * Timestamp - for measuring total overhead + */ + private long lastTimeStamp = System.currentTimeMillis(); + + /** + * Used for displaying the rotating slash on the Problem Window title bar + */ + private String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--", + "\\" }; + private int slashAnimationIndex = 0; + + /** + * Used to detect if the current tab index has changed and thus repaint the + * textarea. + */ + public int currentTab = 0, lastTab = 0; + + /** + * Stores the current import statements in the program. Used to compare for + * changed import statements and update classpath if needed. + */ + protected ArrayList programImports; + + /** + * List of imports when sketch was last checked. Used for checking for + * changed imports + */ + protected ArrayList previousImports = new ArrayList(); + + /** + * Teh Preprocessor + */ + protected XQPreprocessor xqpreproc; + + /** + * Regexp for import statements. (Used from Processing source) + */ + final public String importRegexp = "(?:^|;)\\s*(import\\s+)((?:static\\s+)?\\S+)(\\s*;)"; + + /** + * Regexp for function declarations. (Used from Processing source) + */ + final Pattern FUNCTION_DECL = Pattern + .compile("(^|;)\\s*((public|private|protected|final|static)\\s+)*" + + "(void|int|float|double|String|char|byte)" + + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(", Pattern.MULTILINE); + + public ErrorCheckerService(DebugEditor debugEditor) { + this.editor = debugEditor; + initParser(); + initializeErrorWindow(); + xqpreproc = new XQPreprocessor(); + } + + /** + * Initializes ASTParser + */ + private void initParser() { + try { + parser = ASTParser.newParser(AST.JLS4); + } catch (Exception e) { + System.err.println("XQMode initialization failed. " + + "Are you running the right version of Processing? "); + pauseThread(); + } catch (Error e) { + System.err.println("XQMode initialization failed. "); + e.printStackTrace(); + pauseThread(); + } + } + + /** + * Initialiazes the Error Window + */ + public void initializeErrorWindow() { + + if (editor == null) { + return; + } + + if (errorWindow != null) { + return; + } + + final ErrorCheckerService thisService = this; + final DebugEditor thisEditor = editor; + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + errorWindow = new ErrorWindow(thisEditor, thisService); + // errorWindow.setVisible(true); + editor.toFront(); + errorWindow.errorTable.setFocusable(false); + editor.setSelection(0, 0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + public void run() { + stopThread = false; + + while (!stopThread) { + try { + // Take a nap. + Thread.sleep(sleepTime); + } catch (Exception e) { + System.out.println("Oops! [ErrorCheckerThreaded]: " + e); + // e.printStackTrace(); + } + + if (pauseThread) + continue; + + // Check every x seconds + checkCode(); + + } + } + + private boolean checkCode() { + + lastTimeStamp = System.currentTimeMillis(); + try { + sourceCode = preprocessCode(editor.getSketch().getMainProgram()); + + syntaxCheck(); + + // No syntax errors, proceed for compilation check, Stage 2. + if (problems.length == 0 && editor.compilationCheckEnabled) { //TODO: && editor.compilationCheckEnabled condition + sourceCode = xqpreproc.doYourThing(sourceCode, programImports); + prepareCompilerClasspath(); + mainClassOffset = xqpreproc.mainClassOffset; // tiny, but + // significant + if (staticMode) + mainClassOffset++; // Extra line for setup() decl. +// System.out.println(sourceCode); +// System.out.println("--------------------------"); + compileCheck(); + } + + + updateErrorTable(); + editor.updateErrorBar(problemsList); + updateEditorStatus(); + updateTextAreaPainter(); + return true; + + } catch (Exception e) { + System.out.println("Oops! [ErrorCheckerService.checkCode]: " + e); + e.printStackTrace(); + } + return false; + } + + private void syntaxCheck() { + parser.setSource(sourceCode.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + @SuppressWarnings("unchecked") + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + cu = (CompilationUnit) parser.createAST(null); + + // Store errors returned by the ast parser + problems = cu.getProblems(); + // System.out.println("Problem Count: " + problems.length); + // Populate the probList + problemsList = new ArrayList(); + for (int i = 0; i < problems.length; i++) { + int a[] = calculateTabIndexAndLineNumber(problems[i]); + Problem p = new Problem(problems[i], a[0], a[1]); + problemsList.add(p); +// System.out.println(p.toString()); + } + } + + private void compileCheck() { + + // Currently (Sept, 2012) I'm using Java's reflection api to load the + // CompilationChecker class(from CompilationChecker.jar) that houses the + // Eclispe JDT compiler and call its getErrorsAsObj method to obtain + // errors. This way, I'm able to add the paths of contributed libraries + // to the classpath of CompilationChecker, dynamically. + + try { + + // NOTE TO SELF: If classpath contains null Strings + // URLClassLoader gets angry. Drops NPE bombs. + + // If imports have changed, reload classes with new classpath. + if (loadCompClass) { + + // if (classpathJars.size() > 0) + // System.out + // .println("XQMode: Loading contributed libraries referenced by import statements."); + + File f = new File("modes" + + File.separator + + "java2" + + File.separator + "mode"); + + FileFilter fileFilter = new FileFilter() { + public boolean accept(File file) { + return (file.getName().endsWith(".jar") && !file + .getName().startsWith("XQMode")); + } + }; + + File[] jarFiles = f.listFiles(fileFilter); + for (File jarFile : jarFiles) { + classpathJars.add(jarFile.toURI().toURL()); + } + + classpath = new URL[classpathJars.size()]; // + 1 for + // Compilation + // Checker class + for (int i = 0; i < classpathJars.size(); i++) { + classpath[i] = classpathJars.get(i); + } + + // System.out.println("CP Len -- " + classpath.length); + URLClassLoader classLoader = new URLClassLoader(classpath); + // System.out.println("1."); + checkerClass = Class.forName("CompilationChecker", true, + classLoader); + // System.out.println("2."); + compilationChecker = checkerClass.newInstance(); + loadCompClass = false; + } + + if (compilerSettings == null) { + prepareCompilerSetting(); + } + Method getErrors = checkerClass.getMethod("getErrorsAsObjArr", + new Class[] { String.class, String.class, Map.class }); + + Object[][] errorList = (Object[][]) getErrors + .invoke(compilationChecker, className, sourceCode, + compilerSettings); + + if (errorList == null) { + return; + } + + problems = new DefaultProblem[errorList.length]; + + for (int i = 0; i < errorList.length; i++) { + + // for (int j = 0; j < errorList[i].length; j++) + // System.out.print(errorList[i][j] + ", "); + + problems[i] = new DefaultProblem((char[]) errorList[i][0], + (String) errorList[i][1], + ((Integer) errorList[i][2]).intValue(), + (String[]) errorList[i][3], + ((Integer) errorList[i][4]).intValue(), + ((Integer) errorList[i][5]).intValue(), + ((Integer) errorList[i][6]).intValue(), + ((Integer) errorList[i][7]).intValue(), 0); + + // System.out + // .println("ECS: " + problems[i].getMessage() + "," + // + problems[i].isError() + "," + // + problems[i].isWarning()); + + IProblem problem = problems[i]; + + int a[] = calculateTabIndexAndLineNumber(problem); + Problem p = new Problem(problem, a[0], a[1]); + if ((Boolean) errorList[i][8]) { + p.setType(Problem.ERROR); + } + + if ((Boolean) errorList[i][9]) { + p.setType(Problem.WARNING); + } + + // If warnings are disabled, skip 'em + if (p.isWarning() && !warningsEnabled) { + continue; + } + problemsList.add(p); + } + + } catch (ClassNotFoundException e) { + System.err.println("Compiltation Checker files couldn't be found! " + + e + " compileCheck() problem."); + stopThread(); + } catch (MalformedURLException e) { + System.err.println("Compiltation Checker files couldn't be found! " + + e + " compileCheck() problem."); + stopThread(); + } catch (Exception e) { + System.err.println("compileCheck() problem." + e); + e.printStackTrace(); + stopThread(); + } catch (NoClassDefFoundError e) { + System.err + .println(e + + " compileCheck() problem. Somebody tried to mess with XQMode files."); + stopThread(); + } + // System.out.println("Compilecheck, Done."); + } + + /** + * Processes import statements to obtain classpaths of contributed + * libraries. This would be needed for compilation check. Also, adds + * stuff(jar files, class files, candy) from the code folder. And it looks + * messed up. + * + */ + private void prepareCompilerClasspath() { + if (!loadCompClass) + return; + // System.out.println("1.."); + classpathJars = new ArrayList(); + String entry = ""; + boolean codeFolderChecked = false; + for (ImportStatement impstat : programImports) { + String item = impstat.importName; + int dot = item.lastIndexOf('.'); + entry = (dot == -1) ? item : item.substring(0, dot); + + entry = entry.substring(6).trim(); + // System.out.println("Entry--" + entry); + if (ignorableImport(entry)) { + // System.out.println("Ignoring: " + entry); + continue; + } + Library library = null; + + // Try to get the library classpath and add it to the list + try { + library = editor.getMode().getLibrary(entry); + // System.out.println("lib->" + library.getClassPath() + "<-"); + String libraryPath[] = PApplet.split(library.getClassPath() + .substring(1).trim(), File.pathSeparatorChar); + for (int i = 0; i < libraryPath.length; i++) { + // System.out.println(entry + " ::" + // + new File(libraryPath[i]).toURI().toURL()); + classpathJars.add(new File(libraryPath[i]).toURI().toURL()); + } + // System.out.println("-- "); + // classpath[count] = (new File(library.getClassPath() + // .substring(1))).toURI().toURL(); + // System.out.println(" found "); + // System.out.println(library.getClassPath().substring(1)); + } catch (Exception e) { + if (library == null && !codeFolderChecked) { + // System.out.println(1); + // Look around in the code folder for jar files + if (editor.getSketch().hasCodeFolder()) { + File codeFolder = editor.getSketch().getCodeFolder(); + + // get a list of .jar files in the "code" folder + // (class files in subfolders should also be picked up) + String codeFolderClassPath = Base + .contentsToClassPath(codeFolder); + codeFolderChecked = true; + if (codeFolderClassPath.equalsIgnoreCase("")) { + System.err.println("XQMODE: Yikes! Can't find \"" + + entry + + "\" library! Line: " + + impstat.lineNumber + + " in tab: " + + editor.getSketch().getCode(impstat.tab) + .getPrettyName()); + System.out + .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); + + } + String codeFolderPath[] = PApplet.split( + codeFolderClassPath.substring(1).trim(), + File.pathSeparatorChar); + try { + for (int i = 0; i < codeFolderPath.length; i++) { + classpathJars.add(new File(codeFolderPath[i]) + .toURI().toURL()); + } + + } catch (Exception e2) { + System.out + .println("Yikes! codefolder, prepareImports(): " + + e2); + } + } else { + System.err.println("XQMODE: Yikes! Can't find \"" + + entry + + "\" library! Line: " + + impstat.lineNumber + + " in tab: " + + editor.getSketch().getCode(impstat.tab) + .getPrettyName()); + System.out + .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); + } + + } else { + System.err + .println("Yikes! There was some problem in prepareImports(): " + + e); + System.err.println("I was processing: " + entry); + + // e.printStackTrace(); + } + } + + } + + } + + /** + * Ignore processing packages, java.*.*. etc. + * + * @param packageName + * @return boolean + */ + protected boolean ignorableImport(String packageName) { + // packageName.startsWith("processing.") + // || + if (packageName.startsWith("java.") || packageName.startsWith("javax.")) { + return true; + } + return false; + } + + /** + * Various option for JDT Compiler + */ + @SuppressWarnings("rawtypes") + protected Map compilerSettings; + + /** + * Enable/Disable warnings from being shown + */ + public boolean warningsEnabled = true; + + /** + * Sets compiler options for JDT Compiler + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected void prepareCompilerSetting() { + compilerSettings = new HashMap(); + + compilerSettings.put(CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.GENERATE); + compilerSettings.put(CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.GENERATE); + compilerSettings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_6); + compilerSettings.put(CompilerOptions.OPTION_ReportUnusedImport, + CompilerOptions.IGNORE); + compilerSettings.put(CompilerOptions.OPTION_ReportMissingSerialVersion, + CompilerOptions.IGNORE); + compilerSettings.put(CompilerOptions.OPTION_ReportRawTypeReference, + CompilerOptions.IGNORE); + compilerSettings.put( + CompilerOptions.OPTION_ReportUncheckedTypeOperation, + CompilerOptions.IGNORE); + } + + + /** + * Updates the error table in the Error Window. + */ + synchronized public void updateErrorTable() { + + try { + String[][] errorData = new String[problemsList.size()][3]; + for (int i = 0; i < problemsList.size(); i++) { + errorData[i][0] = problemsList.get(i).message; + errorData[i][1] = editor.getSketch() + .getCode(problemsList.get(i).tabIndex).getPrettyName(); + errorData[i][2] = problemsList.get(i).lineNumber + ""; + } + + if (errorWindow != null) { + DefaultTableModel tm = new DefaultTableModel(errorData, + XQErrorTable.columnNames); + if (errorWindow.isVisible()) { + errorWindow.updateTable(tm); + } + + // Update error table in the editor + editor.updateTable(tm); + + // A rotating slash animation on the title bar to show + // that error checker thread is running + + slashAnimationIndex++; + if (slashAnimationIndex == slashAnimation.length) { + slashAnimationIndex = 0; + } + if (editor != null) { + String info = slashAnimation[slashAnimationIndex] + " T:" + + (System.currentTimeMillis() - lastTimeStamp) + + "ms"; + errorWindow.setTitle("Problems - " + + editor.getSketch().getName() + " " + info); + } + } + + } catch (Exception e) { + System.out.println("Exception at updateErrorTable() " + e); + e.printStackTrace(); + stopThread(); + } + + } + + /** + * Repaints the textarea if required + */ + public void updateTextAreaPainter() { + editor.getTextArea().repaint(); + currentTab = editor.getSketch().getCodeIndex( + editor.getSketch().getCurrentCode()); + if (currentTab != lastTab) { + lastTab = currentTab; + // editor.getTextArea().repaint(); + // System.out.println("1 Repaint " + System.currentTimeMillis()); + return; + } + +// TODO: if (errorBar.errorPointsChanged()) +// editor.getTextArea().repaint(); + + } + + /** + * Updates editor status bar, depending on whether the caret is on an error + * line or not + */ + public void updateEditorStatus() { + // editor.statusNotice("Position: " + + // editor.getTextArea().getCaretLine()); + boolean notFound = true; + for (ErrorMarker emarker : editor.errorBar.errorPoints) { + if (emarker.problem.lineNumber == editor.getTextArea() + .getCaretLine() + 1) { + if (emarker.type == ErrorMarker.Warning) { + editor.statusNotice(emarker.problem.message); + } + else { + editor.statusError(emarker.problem.message); + } + return; + } + } + if (notFound) { + editor.statusEmpty(); + } + } + + /** + * Calculates the tab number and line number of the error in that particular + * tab. Provides mapping between pure java and pde code. + * + * @param problem + * - IProblem + * @return int[0] - tab number, int[1] - line number + */ + public int[] calculateTabIndexAndLineNumber(IProblem problem) { + // String[] lines = {};// = PApplet.split(sourceString, '\n'); + int codeIndex = 0; + int bigCount = 0; + + int x = problem.getSourceLineNumber() - mainClassOffset; + if (x < 0) { + // System.out.println("Negative line number " + // + problem.getSourceLineNumber() + " , offset " + // + mainClassOffset); + x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index + if (x < programImports.size() && x >= 0) { + ImportStatement is = programImports.get(x); + // System.out.println(is.importName + ", " + is.tab + ", " + // + is.lineNumber); + return new int[] { is.tab, is.lineNumber }; + } else { + + // Some seriously ugly stray error, just can't find the source + // line! Simply return first line for first tab. + return new int[] { 0, 1 }; + } + + } + + try { + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + sc.setPreprocOffset(bigCount); + int len = 0; + if (editor.getSketch().getCurrentCode().equals(sc)) { + len = Base.countLines(sc.getDocument().getText(0, + sc.getDocument().getLength())) + 1; + } else { + len = Base.countLines(sc.getProgram()) + 1; + } + + // System.out.println("x,len, CI: " + x + "," + len + "," + // + codeIndex); + + if (x >= len) { + + // We're in the last tab and the line count is greater + // than the no. + // of lines in the tab, + if (codeIndex >= editor.getSketch().getCodeCount() - 1) { + // System.out.println("Exceeds lc " + x + "," + len + // + problem.toString()); + // x = len + x = editor.getSketch().getCode(codeIndex) + .getLineCount(); + // TODO: Obtain line having last non-white space + // character in the code. + break; + } else { + x -= len; + codeIndex++; + } + } else { + + if (codeIndex >= editor.getSketch().getCodeCount()) { + codeIndex = editor.getSketch().getCodeCount() - 1; + } + break; + } + + } + bigCount += sc.getLineCount(); + } + } catch (Exception e) { + System.err + .println("Things got messed up in ErrorCheckerService.calculateTabIndexAndLineNumber()"); + } + + return new int[] { codeIndex, x }; + } + + /** + * Fetches code from the editor tabs and pre-processes it into parsable pure + * java source. And there's a difference between parsable and compilable. + * XQPrerocessor.java makes this code compilable.
+ * Handles:
  • Removal of import statements
  • Conversion of int(), + * char(), etc to (int)(), (char)(), etc.
  • Replacing '#' with 0xff for + * color representation
  • Converts all 'color' datatypes to int + * (experimental)
  • Appends class declaration statement after determining + * the mode the sketch is in - ACTIVE or STATIC + * + * @return String - Pure java representation of PDE code. Note that this + * code is not yet compile ready. + */ + + private String preprocessCode(String pdeCode) { + + programImports = new ArrayList(); + + StringBuffer rawCode = new StringBuffer(); + + try { + + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + + sc.setPreprocOffset(scPreProcOffset); + + try { + + if (editor.getSketch().getCurrentCode().equals(sc)) { + + // rawCode.append(sc.getDocument().getText(0, + // sc.getDocument().getLength())); + rawCode.append(scrapImportStatements(sc.getDocument() + .getText(0, + sc.getDocument() + .getLength()), + editor.getSketch() + .getCodeIndex(sc))); + } else { + + // rawCode.append(sc.getProgram()); + rawCode.append(scrapImportStatements(sc.getProgram(), editor + .getSketch().getCodeIndex(sc))); + + } + rawCode.append('\n'); + } catch (Exception e) { + System.err.println("Exception in preprocessCode() - bigCode " + + e.toString()); + } + rawCode.append('\n'); + scPreProcOffset += sc.getLineCount(); + } + } + + } catch (Exception e) { + System.out.println("Exception in preprocessCode()"); + } + String sourceAlt = rawCode.toString(); + // Replace comments with whitespaces + // sourceAlt = scrubComments(sourceAlt); + + // Find all int(*), replace with PApplet.parseInt(*) + + // \bint\s*\(\s*\b , i.e all exclusive "int(" + + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(sourceAlt); + + // while (matcher.find()) { + // System.out.print("Start index: " + matcher.start()); + // System.out.println(" End index: " + matcher.end() + " "); + // System.out.println("-->" + matcher.group() + "<--"); + // } + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + + dataType.substring(1) + "("); + + } + + // Find all #[web color] and replace with 0xff[webcolor] + // Should be 6 digits only. + final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; + Pattern webPattern = Pattern.compile(webColorRegexp); + Matcher webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = sourceAlt.substring(webMatcher.start(), + webMatcher.end()); + // System.out.println("-> " + found); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + } + + // Replace all color data types with int + // Regex, Y U SO powerful? + final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; + Pattern colorPattern = Pattern.compile(colorTypeRegex); + Matcher colorMatcher = colorPattern.matcher(sourceAlt); + sourceAlt = colorMatcher.replaceAll("int"); + + checkForChangedImports(); + + className = (editor == null) ? "DefaultClass" : editor.getSketch() + .getName(); + + // Check whether the code is being written in STATIC mode(no function + // declarations) - append class declaration and void setup() declaration + Matcher matcher = FUNCTION_DECL.matcher(sourceAlt); + if (!matcher.find()) { + sourceAlt = "public class " + className + " extends PApplet {\n" + + "public void setup() {\n" + sourceAlt + + "\nnoLoop();\n}\n" + "\n}\n"; + staticMode = true; + mainClassOffset = 2; + + } else { + sourceAlt = "public class " + className + " extends PApplet {\n" + + sourceAlt + "\n}"; + staticMode = false; + mainClassOffset = 1; + } + + // Handle unicode characters + sourceAlt = substituteUnicode(sourceAlt); + +// System.out.println("-->\n" + sourceAlt + "\n<--"); +// System.out.println("PDE code processed - " +// + editor.getSketch().getName()); + sourceCode = sourceAlt; + return sourceAlt; + + } + + /** + * Scrolls to the error source in code. And selects the line text. Used by + * XQErrorTable and ErrorBar + * + * @param errorIndex + * - index of error + */ + public void scrollToErrorLine(int errorIndex) { + if (editor == null) + return; + if (errorIndex < problemsList.size() && errorIndex >= 0) { + Problem p = problemsList.get(errorIndex); + try { + editor.toFront(); + editor.getSketch().setCurrentCode(p.tabIndex); + editor.getTextArea().scrollTo(p.lineNumber - 1, 0); + editor.setSelection(editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) + + editor.getTextArea().getLineText(p.lineNumber - 1) + .trim().length(), editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); + editor.repaint(); + } catch (Exception e) { + System.err + .println(e + + " : Error while selecting text in scrollToErrorLine()"); + // e.printStackTrace(); + } + // System.out.println("---"); + + } + } + + /** + * Checks if import statements in the sketch have changed. If they have, + * compiler classpath needs to be updated. + */ + private void checkForChangedImports() { + // System.out.println("Imports: " + programImports.size() + + // " Prev Imp: " + // + previousImports.size()); + if (programImports.size() != previousImports.size()) { + // System.out.println(1); + loadCompClass = true; + previousImports = programImports; + } else { + for (int i = 0; i < programImports.size(); i++) { + if (!programImports.get(i).importName.equals(previousImports + .get(i).importName)) { + // System.out.println(2); + loadCompClass = true; + previousImports = programImports; + break; + } + } + } + // System.out.println("load..? " + loadCompClass); + } + + /** + * Removes import statements from tabSource, replaces each with white spaces + * and adds the import to the list of program imports + * + * @param tabProgram + * - Code in a tab + * @param tabNumber + * - index of the tab + * @return String - Tab code with imports replaced with white spaces + */ + private String scrapImportStatements(String tabProgram, int tabNumber) { + + String tabSource = new String(tabProgram); + do { + // System.out.println("-->\n" + sourceAlt + "\n<--"); + String[] pieces = PApplet.match(tabSource, importRegexp); + + // Stop the loop if we've removed all the import lines + if (pieces == null) { + break; + } + + String piece = pieces[1] + pieces[2] + pieces[3]; + int len = piece.length(); // how much to trim out + + // programImports.add(piece); // the package name + + // find index of this import in the program + int idx = tabSource.indexOf(piece); + // System.out.print("Import -> " + piece); + // System.out.println(" - " + // + Base.countLines(tabSource.substring(0, idx)) + " tab " + // + tabNumber); + programImports.add(new ImportStatement(piece, tabNumber, Base + .countLines(tabSource.substring(0, idx)))); + // Remove the import from the main program + // Substitue with white spaces + String whiteSpace = ""; + for (int j = 0; j < piece.length(); j++) { + whiteSpace += " "; + } + tabSource = tabSource.substring(0, idx) + whiteSpace + + tabSource.substring(idx + len); + + } while (true); + // System.out.println(tabSource); + return tabSource; + } + + /** + * Replaces non-ascii characters with their unicode escape sequences and + * stuff. Used as it is from + * processing.src.processing.mode.java.preproc.PdePreprocessor + * + * @param program + * - Input String containing non ascii characters + * @return String - Converted String + */ + public static String substituteUnicode(String program) { + // check for non-ascii chars (these will be/must be in unicode format) + char p[] = program.toCharArray(); + int unicodeCount = 0; + for (int i = 0; i < p.length; i++) { + if (p[i] > 127) { + unicodeCount++; + } + } + if (unicodeCount == 0) { + return program; + } + // if non-ascii chars are in there, convert to unicode escapes + // add unicodeCount * 5.. replacing each unicode char + // with six digit uXXXX sequence (xxxx is in hex) + // (except for nbsp chars which will be a replaced with a space) + int index = 0; + char p2[] = new char[p.length + unicodeCount * 5]; + for (int i = 0; i < p.length; i++) { + if (p[i] < 128) { + p2[index++] = p[i]; + } else if (p[i] == 160) { // unicode for non-breaking space + p2[index++] = ' '; + } else { + int c = p[i]; + p2[index++] = '\\'; + p2[index++] = 'u'; + char str[] = Integer.toHexString(c).toCharArray(); + // add leading zeros, so that the length is 4 + // for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0'; + for (int m = 0; m < 4 - str.length; m++) + p2[index++] = '0'; + System.arraycopy(str, 0, p2, index, str.length); + index += str.length; + } + } + return new String(p2, 0, index); + } + + /** + * Stops the Error Checker Service thread + */ + public void stopThread() { + stopThread = true; +// System.out.println(editor.getSketch().getName() +// + " - Error Checker stopped."); + } + + /** + * Pauses the Error Checker Service thread + */ + public void pauseThread() { + pauseThread = true; + } + + /** + * Resumes the Error Checker Service thread + */ + public void resumeThread() { + pauseThread = false; + } + + public DebugEditor getEditor() { + return editor; + } +} diff --git a/pdex/src/processing/mode/java2/ErrorMarker.java b/pdex/src/processing/mode/java2/ErrorMarker.java new file mode 100755 index 000000000..74736ecda --- /dev/null +++ b/pdex/src/processing/mode/java2/ErrorMarker.java @@ -0,0 +1,36 @@ +package processing.mode.java2; +/** + * Error markers displayed on the Error Bar. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ + public class ErrorMarker { + /** + * y co-ordinate of the marker + */ + public int y; + /** + * Type of marker: Error or Warning? + */ + public int type = -1; + /** + * Error Type constant + */ + public static final int Error = 1; + /** + * Warning Type constant + */ + public static final int Warning = 2; + /** + * Problem that the error marker represents + * @see Problem + */ + public Problem problem; + + public ErrorMarker(Problem problem, int y, int type) { + this.problem = problem; + this.y = y; + this.type = type; + } + } \ No newline at end of file diff --git a/pdex/src/processing/mode/java2/ErrorWindow.java b/pdex/src/processing/mode/java2/ErrorWindow.java new file mode 100755 index 000000000..4e053dbe4 --- /dev/null +++ b/pdex/src/processing/mode/java2/ErrorWindow.java @@ -0,0 +1,374 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.java2; + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.WindowConstants; +import javax.swing.border.EmptyBorder; +import javax.swing.table.TableModel; + +import processing.app.Editor; +import processing.app.Toolkit; + +/** + * Error Window that displays a tablular list of errors. Clicking on an error + * scrolls to its location in the code. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class ErrorWindow extends JFrame { + + private JPanel contentPane; + /** + * The table displaying the errors + */ + protected XQErrorTable errorTable; + /** + * Scroll pane that contains the Error Table + */ + protected JScrollPane scrollPane; + + protected DebugEditor thisEditor; + private JFrame thisErrorWindow; + + /** + * Handles the sticky Problem window + */ + private DockTool2Base Docker; + + protected ErrorCheckerService errorCheckerService; + + /** + * Preps up ErrorWindow + * + * @param editor + * - Editor + * @param ecs - ErrorCheckerService + */ + public ErrorWindow(DebugEditor editor, ErrorCheckerService ecs) { + thisErrorWindow = this; + errorCheckerService = ecs; + thisEditor = editor; + setTitle("Problems"); + prepareFrame(); + } + + /** + * Sets up ErrorWindow + */ + protected void prepareFrame() { + Toolkit.setIcon(this); + setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + // Default size: setBounds(100, 100, 458, 160); + setBounds(100, 100, 458, 160); // Yeah, I hardcode such things sometimes. Hate me. + + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(new BorderLayout(0, 0)); + + scrollPane = new JScrollPane(); + contentPane.add(scrollPane); + + errorTable = new XQErrorTable(errorCheckerService); + scrollPane.setViewportView(errorTable); + + try { + Docker = new DockTool2Base(); + addListeners(); + } catch (Exception e) { + System.out.println("addListeners() acted silly."); + e.printStackTrace(); + } + + if (thisEditor != null) { + setLocation(new Point(thisEditor.getLocation().x + + thisEditor.getWidth(), thisEditor.getLocation().y)); + } + + } + + /** + * Updates the error table with new data(Table Model). Called from Error + * Checker Service. + * + * @param tableModel + * - Table Model + * @return True - If error table was updated successfully. + */ + synchronized public boolean updateTable(final TableModel tableModel) { + // XQErrorTable handles evrything now + return errorTable.updateTable(tableModel); + } + + /** + * Adds various listeners to components of EditorWindow and to the Editor + * window + */ + protected void addListeners() { + + if (thisErrorWindow == null) + System.out.println("ERW null"); + + thisErrorWindow.addComponentListener(new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + + } + + @Override + public void componentResized(ComponentEvent e) { + Docker.tryDocking(); + } + + @Override + public void componentMoved(ComponentEvent e) { + Docker.tryDocking(); + } + + @Override + public void componentHidden(ComponentEvent e) { + + } + }); + + thisErrorWindow.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + thisEditor.problemWindowMenuCB.setSelected(false); + } + + @Override + public void windowDeiconified(WindowEvent e) { + thisEditor.setExtendedState(Frame.NORMAL); + } + + }); + + if (thisEditor == null) { + System.out.println("Editor null"); + return; + } + + thisEditor.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + + } + + @Override + public void windowClosed(WindowEvent e) { + errorCheckerService.pauseThread(); + errorCheckerService.stopThread(); // Bye bye thread. + thisErrorWindow.dispose(); + } + + @Override + public void windowIconified(WindowEvent e) { + thisErrorWindow.setExtendedState(Frame.ICONIFIED); + } + + @Override + public void windowDeiconified(WindowEvent e) { + thisErrorWindow.setExtendedState(Frame.NORMAL); + } + + }); + + thisEditor.addComponentListener(new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + + } + + @Override + public void componentResized(ComponentEvent e) { + if (Docker.isDocked()) { + Docker.dock(); + } else { + Docker.tryDocking(); + } + } + + @Override + public void componentMoved(ComponentEvent e) { + + if (Docker.isDocked()) { + Docker.dock(); + } else { + Docker.tryDocking(); + } + + } + + @Override + public void componentHidden(ComponentEvent e) { + // System.out.println("ed hidden"); + } + }); + + } + + + /** + * Implements the docking feature of the tool - The frame sticks to the + * editor and once docked, moves along with it as the editor is resized, + * moved, or closed. + * + * This class has been borrowed from Tab Manager tool by Thomas Diewald. It + * has been slightly modified and used here. + * + * @author Thomas Diewald , http://thomasdiewald.com + */ + private class DockTool2Base { + + private int docking_border = 0; + private int dock_on_editor_y_offset_ = 0; + private int dock_on_editor_x_offset_ = 0; + + // /////////////////////////////// + // ____2____ + // | | + // | | + // 0 | editor | 1 + // | | + // |_________| + // 3 + // /////////////////////////////// + + // public void reset() { + // dock_on_editor_y_offset_ = 0; + // dock_on_editor_x_offset_ = 0; + // docking_border = 0; + // } + + public boolean isDocked() { + return (docking_border >= 0); + } + + private final int MAX_GAP_ = 20; + + // + public void tryDocking() { + if (thisEditor == null) + return; + Editor editor = thisEditor; + Frame frame = thisErrorWindow; + + int ex = editor.getX(); + int ey = editor.getY(); + int ew = editor.getWidth(); + int eh = editor.getHeight(); + + int fx = frame.getX(); + int fy = frame.getY(); + int fw = frame.getWidth(); + int fh = frame.getHeight(); + + if (((fy > ey) && (fy < ey + eh)) + || ((fy + fh > ey) && (fy + fh < ey + eh))) { + int dis_border_left = Math.abs(ex - (fx + fw)); + int dis_border_right = Math.abs((ex + ew) - (fx)); + + if (dis_border_left < MAX_GAP_ || dis_border_right < MAX_GAP_) { + docking_border = (dis_border_left < dis_border_right) ? 0 + : 1; + dock_on_editor_y_offset_ = fy - ey; + dock(); + return; + } + } + + if (((fx > ex) && (fx < ex + ew)) + || ((fx + fw > ey) && (fx + fw < ex + ew))) { + int dis_border_top = Math.abs(ey - (fy + fh)); + int dis_border_bot = Math.abs((ey + eh) - (fy)); + + if (dis_border_top < MAX_GAP_ || dis_border_bot < MAX_GAP_) { + docking_border = (dis_border_top < dis_border_bot) ? 2 : 3; + dock_on_editor_x_offset_ = fx - ex; + dock(); + return; + } + } + docking_border = -1; + } + + public void dock() { + if (thisEditor == null) + return; + Editor editor = thisEditor; + Frame frame = thisErrorWindow; + + int ex = editor.getX(); + int ey = editor.getY(); + int ew = editor.getWidth(); + int eh = editor.getHeight(); + + // int fx = frame.getX(); + // int fy = frame.getY(); + int fw = frame.getWidth(); + int fh = frame.getHeight(); + + int x = 0, y = 0; + if (docking_border == -1) { + return; + } + + if (docking_border == 0) { + x = ex - fw; + y = ey + dock_on_editor_y_offset_; + } + if (docking_border == 1) { + x = ex + ew; + y = ey + dock_on_editor_y_offset_; + } + + if (docking_border == 2) { + x = ex + dock_on_editor_x_offset_; + y = ey - fh; + } + if (docking_border == 3) { + x = ex + dock_on_editor_x_offset_; + y = ey + eh; + } + frame.setLocation(x, y); + } + + } +} diff --git a/pdex/src/processing/mode/java2/FieldNode.java b/pdex/src/processing/mode/java2/FieldNode.java new file mode 100755 index 000000000..3fc6e2adb --- /dev/null +++ b/pdex/src/processing/mode/java2/FieldNode.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.Value; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Specialized {@link VariableNode} for representing fields. Overrides + * {@link #setValue} to properly change the value of the encapsulated field. + * + * @author Martin Leopold + */ +public class FieldNode extends VariableNode { + + protected Field field; + protected ObjectReference obj; + + /** + * Construct a {@link FieldNode}. + * + * @param name the name + * @param type the type + * @param value the value + * @param field the field + * @param obj a reference to the object containing the field + */ + public FieldNode(String name, String type, Value value, Field field, ObjectReference obj) { + super(name, type, value); + this.field = field; + this.obj = obj; + } + + @Override + public void setValue(Value value) { + try { + obj.setValue(field, value); + } catch (InvalidTypeException ex) { + Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotLoadedException ex) { + Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); + } + this.value = value; + } +} diff --git a/pdex/src/processing/mode/java2/ImportStatement.java b/pdex/src/processing/mode/java2/ImportStatement.java new file mode 100755 index 000000000..84277b875 --- /dev/null +++ b/pdex/src/processing/mode/java2/ImportStatement.java @@ -0,0 +1,51 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.java2; + +/** + * Wrapper for import statements + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class ImportStatement { + /** + * Ex: processing.opengl.*, java.util.* + */ + String importName; + /** + * Which tab does it belong to? + */ + int tab; + + /** + * Line number(pde code) of the import + */ + int lineNumber; + + public ImportStatement(String importName, int tab, int lineNumber) { + this.importName = importName; + this.tab = tab; + this.lineNumber = lineNumber; + } + } \ No newline at end of file diff --git a/pdex/src/processing/mode/java2/LineBreakpoint.java b/pdex/src/processing/mode/java2/LineBreakpoint.java new file mode 100755 index 000000000..84ae65d94 --- /dev/null +++ b/pdex/src/processing/mode/java2/LineBreakpoint.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Location; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.request.BreakpointRequest; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Model/Controller of a line breakpoint. Can be set before or while debugging. + * Adds a highlight using the debuggers view ({@link DebugEditor}). + * + * @author Martin Leopold + */ +public class LineBreakpoint implements ClassLoadListener { + + protected Debugger dbg; // the debugger + protected LineID line; // the line this breakpoint is set on + protected BreakpointRequest bpr; // the request on the VM's event request manager + protected ReferenceType theClass; // the class containing this breakpoint, null when not yet loaded + + /** + * Create a {@link LineBreakpoint}. If in a debug session, will try to + * immediately set the breakpoint. If not in a debug session or the + * corresponding class is not yet loaded the breakpoint will activate on + * class load. + * + * @param line the line id to create the breakpoint on + * @param dbg the {@link Debugger} + */ + public LineBreakpoint(LineID line, Debugger dbg) { + this.line = line; + line.startTracking(dbg.editor().getTab(line.fileName()).getDocument()); + this.dbg = dbg; + theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded + set(); // activate the breakpoint (show highlight, attach if debugger is running) + } + + /** + * Create a {@link LineBreakpoint} on a line in the current tab. + * + * @param lineIdx the line index of the current tab to create the breakpoint + * on + * @param dbg the {@link Debugger} + */ + // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)} + public LineBreakpoint(int lineIdx, Debugger dbg) { + this(dbg.editor().getLineIDInCurrentTab(lineIdx), dbg); + } + + /** + * Get the line id this breakpoint is on. + * + * @return the line id + */ + public LineID lineID() { + return line; + } + + /** + * Test if this breakpoint is on a certain line. + * + * @param testLine the line id to test + * @return true if this breakpoint is on the given line + */ + public boolean isOnLine(LineID testLine) { + return line.equals(testLine); + } + + /** + * Attach this breakpoint to the VM. Creates and enables a + * {@link BreakpointRequest}. VM needs to be paused. + */ + protected void attach() { + if (!dbg.isPaused()) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, debugger not paused"); + return; + } + + if (theClass == null) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, class not loaded: {0}", className()); + return; + } + + // find line in java space + LineID javaLine = dbg.sketchToJavaLine(line); + if (javaLine == null) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "couldn't find line {0} in the java code", line); + return; + } + try { + List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); + if (locations.isEmpty()) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); + return; + } + // use first found location + bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0)); + bpr.enable(); + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "attached breakpoint to {0} -> {1}", new Object[]{line, javaLine}); + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Detach this breakpoint from the VM. Deletes the + * {@link BreakpointRequest}. + */ + protected void detach() { + if (bpr != null) { + dbg.vm().eventRequestManager().deleteEventRequest(bpr); + bpr = null; + } + } + + /** + * Set this breakpoint. Adds the line highlight. If Debugger is paused also + * attaches the breakpoint by calling {@link #attach()}. + */ + protected void set() { + dbg.addClassLoadListener(this); // class may not yet be loaded + dbg.editor().addBreakpointedLine(line); + if (theClass != null && dbg.isPaused()) { // class is loaded + // immediately activate the breakpoint + attach(); + } + if (dbg.editor().isInCurrentTab(line)) { + dbg.editor().getSketch().setModified(true); + } + } + + /** + * Remove this breakpoint. Clears the highlight and detaches the breakpoint + * if the debugger is paused. + */ + public void remove() { + dbg.removeClassLoadListener(this); + //System.out.println("removing " + line.lineIdx()); + dbg.editor().removeBreakpointedLine(line.lineIdx()); + if (dbg.isPaused()) { + // immediately remove the breakpoint + detach(); + } + line.stopTracking(); + if (dbg.editor().isInCurrentTab(line)) { + dbg.editor().getSketch().setModified(true); + } + } + +// public void enable() { +// } +// +// public void disable() { +// } + @Override + public String toString() { + return line.toString(); + } + + /** + * Get the name of the class this breakpoint belongs to. Needed for fetching + * the right location to create a breakpoint request. + * + * @return the class name + */ + protected String className() { + if (line.fileName().endsWith(".pde")) { + // standard tab + ReferenceType mainClass = dbg.getMainClass(); + if (mainClass == null) { + return null; + } + return dbg.getMainClass().name(); + } + + if (line.fileName().endsWith(".java")) { + // pure java tab + return line.fileName().substring(0, line.fileName().lastIndexOf(".java")); + } + + return null; + } + + /** + * Event handler called when a class is loaded in the debugger. Causes the + * breakpoint to be attached, if its class was loaded. + * + * @param theClass the class that was just loaded. + */ + @Override + public void classLoaded(ReferenceType theClass) { + // check if our class is being loaded + if (theClass.name().equals(className())) { + this.theClass = theClass; + attach(); + } + } +} diff --git a/pdex/src/processing/mode/java2/LineHighlight.java b/pdex/src/processing/mode/java2/LineHighlight.java new file mode 100755 index 000000000..b92d3aaa5 --- /dev/null +++ b/pdex/src/processing/mode/java2/LineHighlight.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.awt.Color; +import java.util.HashSet; +import java.util.Set; + +/** + * Model/Controller for a highlighted source code line. Implements a custom + * background color and a text based marker placed in the left-hand gutter area. + * + * @author Martin Leopold + */ +public class LineHighlight implements LineListener { + + protected DebugEditor editor; // the view, used for highlighting lines by setting a background color + protected Color bgColor; // the background color for highlighting lines + protected LineID lineID; // the id of the line + protected String marker; // + protected Color markerColor; + protected int priority = 0; + protected static Set allHighlights = new HashSet(); + + protected static boolean isHighestPriority(LineHighlight hl) { + for (LineHighlight check : allHighlights) { + if (check.lineID().equals(hl.lineID()) && check.priority() > hl.priority()) { + return false; + } + } + return true; + } + + /** + * Create a {@link LineHighlight}. + * + * @param lineID the line id to highlight + * @param bgColor the background color used for highlighting + * @param editor the {@link DebugEditor} + */ + public LineHighlight(LineID lineID, Color bgColor, DebugEditor editor) { + this.lineID = lineID; + this.bgColor = bgColor; + this.editor = editor; + lineID.addListener(this); + lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc? + paint(); // already checks if on current tab + allHighlights.add(this); + } + + public void setPriority(int p) { + this.priority = p; + } + + public int priority() { + return priority; + } + + /** + * Create a {@link LineHighlight} on the current tab. + * + * @param lineIdx the line index on the current tab to highlight + * @param bgColor the background color used for highlighting + * @param editor the {@link DebugEditor} + */ + // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, DebugEditor editor)} + public LineHighlight(int lineIdx, Color bgColor, DebugEditor editor) { + this(editor.getLineIDInCurrentTab(lineIdx), bgColor, editor); + } + + /** + * Set a text based marker displayed in the left hand gutter area of this + * highlighted line. + * + * @param marker the marker text + */ + public void setMarker(String marker) { + this.marker = marker; + paint(); + } + + /** + * Set a text based marker displayed in the left hand gutter area of this + * highlighted line. Also use a custom text color. + * + * @param marker the marker text + * @param markerColor the text color + */ + public void setMarker(String marker, Color markerColor) { + this.markerColor = markerColor; + setMarker(marker); + } + + /** + * Retrieve the line id of this {@link LineHighlight}. + * + * @return the line id + */ + public LineID lineID() { + return lineID; + } + + /** + * Retrieve the color for highlighting this line. + * + * @return the highlight color. + */ + public Color getColor() { + return bgColor; + } + + /** + * Test if this highlight is on a certain line. + * + * @param testLine the line to test + * @return true if this highlight is on the given line + */ + public boolean isOnLine(LineID testLine) { + return lineID.equals(testLine); + } + + /** + * Event handler for line number changes (due to editing). Will remove the + * highlight from the old line number and repaint it at the new location. + * + * @param line the line that has changed + * @param oldLineIdx the old line index (0-based) + * @param newLineIdx the new line index (0-based) + */ + @Override + public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { + // clear old line + if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { + editor.textArea().clearLineBgColor(oldLineIdx); + editor.textArea().clearGutterText(oldLineIdx); + } + + // paint new line + // but only if it's on top -> fixes current line being hidden by breakpoint moving it down. + // lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...) + if (LineHighlight.isHighestPriority(this)) { + paint(); + } + } + + /** + * Notify this line highlight that it is no longer used. Call this for + * cleanup before the {@link LineHighlight} is discarded. + */ + public void dispose() { + lineID.removeListener(this); + lineID.stopTracking(); + allHighlights.remove(this); + } + + /** + * (Re-)paint this line highlight. + */ + public void paint() { + if (editor.isInCurrentTab(lineID)) { + editor.textArea().setLineBgColor(lineID.lineIdx(), bgColor); + if (marker != null) { + if (markerColor != null) { + editor.textArea().setGutterText(lineID.lineIdx(), marker, markerColor); + } else { + editor.textArea().setGutterText(lineID.lineIdx(), marker); + } + } + } + } + + /** + * Clear this line highlight. + */ + public void clear() { + if (editor.isInCurrentTab(lineID)) { + editor.textArea().clearLineBgColor(lineID.lineIdx()); + editor.textArea().clearGutterText(lineID.lineIdx()); + } + } +} diff --git a/pdex/src/processing/mode/java2/LineID.java b/pdex/src/processing/mode/java2/LineID.java new file mode 100755 index 000000000..52098abe2 --- /dev/null +++ b/pdex/src/processing/mode/java2/LineID.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.Position; + +/** + * Describes an ID for a code line. Comprised of a file name and a (0-based) + * line number. Can track changes to the line number due to text editing by + * attaching a {@link Document}. Registered {@link LineListener}s are notified + * of changes to the line number. + * + * @author Martin Leopold + */ +public class LineID implements DocumentListener { + + protected String fileName; // the filename + protected int lineIdx; // the line number, 0-based + protected Document doc; // the Document to use for line number tracking + protected Position pos; // the Position acquired during line number tracking + protected Set listeners = new HashSet(); // listeners for line number changes + + public LineID(String fileName, int lineIdx) { + this.fileName = fileName; + this.lineIdx = lineIdx; + } + + /** + * Get the file name of this line. + * + * @return the file name + */ + public String fileName() { + return fileName; + } + + /** + * Get the (0-based) line number of this line. + * + * @return the line index (i.e. line number, starting at 0) + */ + public synchronized int lineIdx() { + return lineIdx; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + /** + * Test whether this {@link LineID} is equal to another object. Two + * {@link LineID}'s are equal when both their fileName and lineNo are equal. + * + * @param obj the object to test for equality + * @return {@code true} if equal + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final LineID other = (LineID) obj; + if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) { + return false; + } + if (this.lineIdx != other.lineIdx) { + return false; + } + return true; + } + + /** + * Output a string representation in the form fileName:lineIdx+1. Note this + * uses a 1-based line number as is customary for human-readable line + * numbers. + * + * @return the string representation of this line ID + */ + @Override + public String toString() { + return fileName + ":" + (lineIdx + 1); + } + +// /** +// * Retrieve a copy of this line ID. +// * +// * @return the copy +// */ +// @Override +// public LineID clone() { +// return new LineID(fileName, lineIdx); +// } + + /** + * Attach a {@link Document} to enable line number tracking when editing. + * The position to track is before the first non-whitespace character on the + * line. Edits happening before that position will cause the line number to + * update accordingly. Multiple {@link #startTracking} calls will replace + * the tracked document. Whoever wants a tracked line should track it and + * add itself as listener if necessary. + * ({@link LineHighlight}, {@link LineBreakpoint}) + * + * @param doc the {@link Document} to use for line number tracking + */ + public synchronized void startTracking(Document doc) { + //System.out.println("tracking: " + this); + if (doc == null) { + return; // null arg + } + if (doc == this.doc) { + return; // already tracking that doc + } + try { + Element line = doc.getDefaultRootElement().getElement(lineIdx); + if (line == null) { + return; // line doesn't exist + } + String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset()); + // set tracking position at (=before) first non-white space character on line + pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText)); + this.doc = doc; + doc.addDocumentListener(this); + } catch (BadLocationException ex) { + Logger.getLogger(LineID.class.getName()).log(Level.SEVERE, null, ex); + pos = null; + this.doc = null; + } + } + + /** + * Notify this {@link LineID} that it is no longer in use. Will stop + * position tracking. Call this when this {@link LineID} is no longer + * needed. + */ + public synchronized void stopTracking() { + if (doc != null) { + doc.removeDocumentListener(this); + doc = null; + } + } + + /** + * Update the tracked position. Will notify listeners if line number has + * changed. + */ + protected synchronized void updatePosition() { + if (doc != null && pos != null) { + // track position + int offset = pos.getOffset(); + int oldLineIdx = lineIdx; + lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo + if (lineIdx != oldLineIdx) { + for (LineListener l : listeners) { + if (l != null) { + l.lineChanged(this, oldLineIdx, lineIdx); + } else { + listeners.remove(l); // remove null listener + } + } + } + } + } + + /** + * Add listener to be notified when the line number changes. + * + * @param l the listener to add + */ + public void addListener(LineListener l) { + listeners.add(l); + } + + /** + * Remove a listener for line number changes. + * + * @param l the listener to remove + */ + public void removeListener(LineListener l) { + listeners.remove(l); + } + + /** + * Calculate the offset of the first non-whitespace character in a string. + * + * @param str the string to examine + * @return offset of first non-whitespace character in str + */ + protected static int nonWhiteSpaceOffset(String str) { + for (int i = 0; i < str.length(); i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return i; + } + } + return str.length(); + } + + /** + * Called when the {@link Document} registered using {@link #startTracking} + * is edited. This happens when text is inserted or removed. + * + * @param de + */ + protected void editEvent(DocumentEvent de) { + //System.out.println("document edit @ " + de.getOffset()); + if (de.getOffset() <= pos.getOffset()) { + updatePosition(); + //System.out.println("updating, new line no: " + lineNo); + } + } + + /** + * {@link DocumentListener} callback. Called when text is inserted. + * + * @param de + */ + @Override + public void insertUpdate(DocumentEvent de) { + editEvent(de); + } + + /** + * {@link DocumentListener} callback. Called when text is removed. + * + * @param de + */ + @Override + public void removeUpdate(DocumentEvent de) { + editEvent(de); + } + + /** + * {@link DocumentListener} callback. Called when attributes are changed. + * Not used. + * + * @param de + */ + @Override + public void changedUpdate(DocumentEvent de) { + // not needed. + } +} diff --git a/pdex/src/processing/mode/java2/LineListener.java b/pdex/src/processing/mode/java2/LineListener.java new file mode 100755 index 000000000..05864678c --- /dev/null +++ b/pdex/src/processing/mode/java2/LineListener.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +/** + * A Listener for line number changes. + * + * @author Martin Leopold + */ +public interface LineListener { + + /** + * Event handler for line number changes (due to editing). + * + * @param line the line that has changed + * @param oldLineIdx the old line index (0-based) + * @param newLineIdx the new line index (0-based) + */ + void lineChanged(LineID line, int oldLineIdx, int newLineIdx); +} diff --git a/pdex/src/processing/mode/java2/LocalVariableNode.java b/pdex/src/processing/mode/java2/LocalVariableNode.java new file mode 100755 index 000000000..857ea697b --- /dev/null +++ b/pdex/src/processing/mode/java2/LocalVariableNode.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.StackFrame; +import com.sun.jdi.Value; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Specialized {@link VariableNode} for representing local variables. Overrides + * {@link #setValue} to properly change the value of the encapsulated local + * variable. + * + * @author Martin Leopold + */ +public class LocalVariableNode extends VariableNode { + + protected LocalVariable var; + protected StackFrame frame; + + /** + * Construct a {@link LocalVariableNode}. + * + * @param name the name + * @param type the type + * @param value the value + * @param var the local variable + * @param frame the stack frame containing the local variable + */ + public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) { + super(name, type, value); + this.var = var; + this.frame = frame; + } + + @Override + public void setValue(Value value) { + try { + frame.setValue(var, value); + } catch (InvalidTypeException ex) { + Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotLoadedException ex) { + Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); + } + this.value = value; + } +} diff --git a/pdex/src/processing/mode/java2/Problem.java b/pdex/src/processing/mode/java2/Problem.java new file mode 100755 index 000000000..1a6a59344 --- /dev/null +++ b/pdex/src/processing/mode/java2/Problem.java @@ -0,0 +1,160 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.java2; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.core.compiler.IProblem; + +/** + * Wrapper class for IProblem. + * + * Stores the tabIndex and line number according to its tab, including the + * original IProblem object + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class Problem { + /** + * The IProblem which is being wrapped + */ + private IProblem iProblem; + /** + * The tab number to which the error belongs to + */ + public int tabIndex; + /** + * Line number(pde code) of the error + */ + public int lineNumber; + + /** + * Error Message. Processed form of IProblem.getMessage() + */ + public String message; + + public int type; + + public static final int ERROR = 1, WARNING = 2; + + public Problem(IProblem iProblem, int tabIndex, int lineNumber) { + this.iProblem = iProblem; + if(iProblem.isError()) { + type = ERROR; + } + else if(iProblem.isWarning()) { + type = WARNING; + } + this.tabIndex = tabIndex; + this.lineNumber = lineNumber; + this.message = process(iProblem); + } + + public String toString() { + return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: " + + message); + } + + public boolean isError(){ + return type == ERROR; + } + + public boolean isWarning(){ + return type == WARNING; + } + + public String getMessage(){ + return message; + } + + public IProblem getIProblem(){ + return iProblem; + } + + public void setType(int ProblemType){ + if(ProblemType == ERROR) + type = ERROR; + else if(ProblemType == WARNING) + type = WARNING; + else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)"); + } + + static Pattern pattern; + static Matcher matcher; + + static final String tokenRegExp = "\\b token\\b"; + + public static String process(IProblem problem) { + return process(problem.getMessage()); + } + + /** + * Processes error messages and attempts to make them a bit more english like. + * Currently performs: + *
  • Remove all instances of token. "Syntax error on token 'blah', delete this token" + * becomes "Syntax error on 'blah', delete this" + * @param message - The message to be processed + * @return String - The processed message + */ + public static String process(String message) { + // Remove all instances of token + // "Syntax error on token 'blah', delete this token" + + pattern = Pattern.compile(tokenRegExp); + matcher = pattern.matcher(message); + message = matcher.replaceAll(""); + + // Split camel case words into separate words. + // "VaraibleDeclaration" becomes "Variable Declaration" + // But sadly "PApplet" become "P Applet" and so on. + + // StringTokenizer st = new StringTokenizer(message); + // String newMessage = ""; + // while (st.hasMoreTokens()) { + // String word = st.nextToken(); + // newMessage += splitCamelCaseWord(word) + " "; + // } + // message = new String(newMessage); + + return message; + } + + public static String splitCamelCaseWord(String word) { + String newWord = ""; + for (int i = 1; i < word.length(); i++) { + if (Character.isUpperCase(word.charAt(i))) { + // System.out.println(word.substring(0, i) + " " + // + word.substring(i)); + newWord += word.substring(0, i) + " "; + word = word.substring(i); + i = 1; + } + } + newWord += word; + // System.out.println(newWord); + return newWord.trim(); + } + +} diff --git a/pdex/src/processing/mode/java2/TextArea.java b/pdex/src/processing/mode/java2/TextArea.java new file mode 100755 index 000000000..1400623e1 --- /dev/null +++ b/pdex/src/processing/mode/java2/TextArea.java @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.FontMetrics; +import java.awt.event.ComponentListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.util.HashMap; +import java.util.Map; + +import processing.app.syntax.JEditTextArea; +import processing.app.syntax.TextAreaDefaults; + +/** + * Customized text area. Adds support for line background colors. + * + * @author Martin Leopold + */ +public class TextArea extends JEditTextArea { + + protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler + protected DebugEditor editor; // the editor + // line properties + protected Map lineColors = new HashMap(); // contains line background colors + // left-hand gutter properties + protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars + protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color + protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line + protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter + protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter + protected Map gutterText = new HashMap(); // maps line index to gutter text + protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color + protected TextAreaPainter customPainter; + + public TextArea(TextAreaDefaults defaults, DebugEditor editor) { + super(defaults); + this.editor = editor; + + // replace the painter: + // first save listeners, these are package-private in JEditTextArea, so not accessible + ComponentListener[] componentListeners = painter.getComponentListeners(); + mouseListeners = painter.getMouseListeners(); + MouseMotionListener[] mouseMotionListeners = painter.getMouseMotionListeners(); + + remove(painter); + + // set new painter + customPainter = new TextAreaPainter(this, defaults); + painter = customPainter; + + // set listeners + for (ComponentListener cl : componentListeners) { + painter.addComponentListener(cl); + } + + for (MouseMotionListener mml : mouseMotionListeners) { + painter.addMouseMotionListener(mml); + } + + // use a custom mouse handler instead of directly using mouseListeners + MouseHandler mouseHandler = new MouseHandler(); + painter.addMouseListener(mouseHandler); + painter.addMouseMotionListener(mouseHandler); + + add(CENTER, painter); + + // load settings from theme.txt + DebugMode theme = (DebugMode) editor.getMode(); + gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); + gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); + gutterPadding = theme.getInteger("gutter.padding"); + breakpointMarker = theme.loadThemeString("breakpoint.marker", breakpointMarker); + currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker); + } + + public void setECSandThemeforTextArea(ErrorCheckerService ecs, DebugMode mode) + { + customPainter.setECSandTheme(ecs, mode); + } + + /** + * Retrieve the total width of the gutter area. + * + * @return gutter width in pixels + */ + protected int getGutterWidth() { + FontMetrics fm = painter.getFontMetrics(); +// System.out.println("fm: " + (fm == null)); +// System.out.println("editor: " + (editor == null)); + //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); + + int textWidth = Math.max(fm.stringWidth(breakpointMarker), fm.stringWidth(currentLineMarker)); + return textWidth + 2 * gutterPadding; + } + + /** + * Retrieve the width of margins applied to the left and right of the gutter + * text. + * + * @return margins in pixels + */ + protected int getGutterMargins() { + return gutterPadding; + } + + /** + * Set the gutter text of a specific line. + * + * @param lineIdx the line index (0-based) + * @param text the text + */ + public void setGutterText(int lineIdx, String text) { + gutterText.put(lineIdx, text); + painter.invalidateLine(lineIdx); + } + + /** + * Set the gutter text and color of a specific line. + * + * @param lineIdx the line index (0-based) + * @param text the text + * @param textColor the text color + */ + public void setGutterText(int lineIdx, String text, Color textColor) { + gutterTextColors.put(lineIdx, textColor); + setGutterText(lineIdx, text); + } + + /** + * Clear the gutter text of a specific line. + * + * @param lineIdx the line index (0-based) + */ + public void clearGutterText(int lineIdx) { + gutterText.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all gutter text. + */ + public void clearGutterText() { + for (int lineIdx : gutterText.keySet()) { + painter.invalidateLine(lineIdx); + } + gutterText.clear(); + } + + /** + * Retrieve the gutter text of a specific line. + * + * @param lineIdx the line index (0-based) + * @return the gutter text + */ + public String getGutterText(int lineIdx) { + return gutterText.get(lineIdx); + } + + /** + * Retrieve the gutter text color for a specific line. + * + * @param lineIdx the line index + * @return the gutter text color + */ + public Color getGutterTextColor(int lineIdx) { + return gutterTextColors.get(lineIdx); + } + + /** + * Set the background color of a line. + * + * @param lineIdx 0-based line number + * @param col the background color to set + */ + public void setLineBgColor(int lineIdx, Color col) { + lineColors.put(lineIdx, col); + painter.invalidateLine(lineIdx); + } + + /** + * Clear the background color of a line. + * + * @param lineIdx 0-based line number + */ + public void clearLineBgColor(int lineIdx) { + lineColors.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all line background colors. + */ + public void clearLineBgColors() { + for (int lineIdx : lineColors.keySet()) { + painter.invalidateLine(lineIdx); + } + lineColors.clear(); + } + + /** + * Get a lines background color. + * + * @param lineIdx 0-based line number + * @return the color or null if no color was set for the specified line + */ + public Color getLineBgColor(int lineIdx) { + return lineColors.get(lineIdx); + } + + /** + * Convert a character offset to a horizontal pixel position inside the text + * area. Overridden to take gutter width into account. + * + * @param line the 0-based line number + * @param offset the character offset (0 is the first character on a line) + * @return the horizontal position + */ + @Override + public int _offsetToX(int line, int offset) { + return super._offsetToX(line, offset) + getGutterWidth(); + } + + /** + * Convert a horizontal pixel position to a character offset. Overridden to + * take gutter width into account. + * + * @param line the 0-based line number + * @param x the horizontal pixel position + * @return he character offset (0 is the first character on a line) + */ + @Override + public int xToOffset(int line, int x) { + return super.xToOffset(line, x - getGutterWidth()); + } + + /** + * Custom mouse handler. Implements double clicking in the gutter area to + * toggle breakpoints, sets default cursor (instead of text cursor) in the + * gutter area. + */ + protected class MouseHandler implements MouseListener, MouseMotionListener { + + protected int lastX; // previous horizontal positon of the mouse cursor + + @Override + public void mouseClicked(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseClicked(me); + } + } + + @Override + public void mousePressed(MouseEvent me) { + // check if this happened in the gutter area + if (me.getX() < getGutterWidth()) { + if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { + int line = me.getY() / painter.getFontMetrics().getHeight() + firstLine; + if (line >= 0 && line <= getLineCount() - 1) { + editor.gutterDblClicked(line); + } + } + } else { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mousePressed(me); + } + } + } + + @Override + public void mouseReleased(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseReleased(me); + } + } + + @Override + public void mouseEntered(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseEntered(me); + } + } + + @Override + public void mouseExited(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseExited(me); + } + } + + @Override + public void mouseDragged(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + // nop + } + + @Override + public void mouseMoved(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + if (me.getX() < getGutterWidth()) { + if (lastX >= getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } else { + if (lastX < getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + } + } + lastX = me.getX(); + } + } +} diff --git a/pdex/src/processing/mode/java2/TextAreaPainter.java b/pdex/src/processing/mode/java2/TextAreaPainter.java new file mode 100755 index 000000000..8db27a60a --- /dev/null +++ b/pdex/src/processing/mode/java2/TextAreaPainter.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Segment; +import javax.swing.text.Utilities; + +import processing.app.syntax.TextAreaDefaults; +import processing.app.syntax.TokenMarker; + +/** + * Customized line painter. Adds support for background colors, left hand gutter + * area with background color and text. + * + * @author Martin Leopold + */ +public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { + + protected TextArea ta; // we need the subclassed textarea + protected ErrorCheckerService errorCheckerService; + + /** + * Error line underline color + */ + public Color errorColor = new Color(0xED2630); + + /** + * Warning line underline color + */ + + public Color warningColor = new Color(0xFFC30E); + + /** + * Color of Error Marker + */ + public Color errorMarkerColor = new Color(0xED2630); + + /** + * Color of Warning Marker + */ + public Color warningMarkerColor = new Color(0xFFC30E); + + public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { + super(textArea, defaults); + ta = textArea; + } + + private void loadTheme(DebugMode mode){ + errorColor = mode.getThemeColor("editor.errorcolor", errorColor); + warningColor = mode.getThemeColor("editor.warningcolor", + warningColor); + errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", + errorMarkerColor); + warningMarkerColor = mode.getThemeColor( + "editor.warningmarkercolor", warningMarkerColor); + } + + /** + * Paint a line. Paints the gutter (with background color and text) then the + * line (background color and text). + * + * @param gfx the graphics context + * @param tokenMarker + * @param line 0-based line number + * @param x horizontal position + */ + @Override + protected void paintLine(Graphics gfx, TokenMarker tokenMarker, + int line, int x) { + + // paint gutter + paintGutterBg(gfx, line, x); + + paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + + paintGutterLine(gfx, line, x); + + // paint gutter symbol + paintGutterText(gfx, line, x); + + paintErrorLine(gfx, line, x); + + super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); + } + + /** + * Paint the gutter background (solid color). + * + * @param gfx the graphics context + * @param line 0-based line number + * @param x horizontal position + */ + protected void paintGutterBg(Graphics gfx, int line, int x) { + gfx.setColor(ta.gutterBgColor); + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); + } + + /** + * Paint the vertical gutter separator line. + * + * @param gfx the graphics context + * @param line 0-based line number + * @param x horizontal position + */ + protected void paintGutterLine(Graphics gfx, int line, int x) { + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.setColor(ta.gutterLineColor); + gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), y + fm.getHeight()); + } + + /** + * Paint the gutter text. + * + * @param gfx the graphics context + * @param line 0-based line number + * @param x horizontal position + */ + protected void paintGutterText(Graphics gfx, int line, int x) { + String text = ta.getGutterText(line); + if (text == null) { + return; + } + + gfx.setFont(getFont()); + Color textColor = ta.getGutterTextColor(line); + if (textColor == null) { + gfx.setColor(getForeground()); + } else { + gfx.setColor(textColor); + } + int y = ta.lineToY(line) + fm.getHeight(); + + // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. + //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y + 1, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y + 1, gfx, this, 0); + } + + /** + * Paint the background color of a line. + * + * @param gfx the graphics context + * @param line 0-based line number + * @param x + */ + protected void paintLineBgColor(Graphics gfx, int line, int x) { + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + + // get the color + Color col = ta.getLineBgColor(line); + //System.out.print("bg line " + line + ": "); + // no need to paint anything + if (col == null) { + //System.out.println("none"); + return; + } + // paint line background + gfx.setColor(col); + gfx.fillRect(0, y, getWidth(), height); + } + + /** + * Paints the underline for an error/warning line + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number: NOTE + * @param x + */ + private void paintErrorLine(Graphics gfx, int line, int x) { + + if (errorCheckerService == null) { + return; + } + + if (errorCheckerService.problemsList== null) { + return; + } + + boolean notFound = true; + boolean isWarning = false; + + // Check if current line contains an error. If it does, find if it's an + // error or warning + for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { + if (emarker.problem.lineNumber == line + 1) { + notFound = false; + if (emarker.type == ErrorMarker.Warning) { + isWarning = true; + } + break; + } + } + + if (notFound) { + return; + } + + // Determine co-ordinates + // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + + // horizontalAdjustment); + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + int start = ta.getLineStartOffset(line); + + try { + String linetext = null; + + try { + linetext = ta.getDocument().getText(start, + ta.getLineStopOffset(line) - start - 1); + } catch (BadLocationException bl) { + // Error in the import statements or end of code. + // System.out.print("BL caught. " + ta.getLineCount() + " ," + // + line + " ,"); + // System.out.println((ta.getLineStopOffset(line) - start - 1)); + return; + } + + // Take care of offsets + int aw = fm.stringWidth(trimRight(linetext)) + + ta.getHorizontalOffset(); // apparent width. Whitespaces + // to the left of line + text + // width + int rw = fm.stringWidth(linetext.trim()); // real width + int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; + // Adding offsets for the gutter + x1 += 20; + x2 += 20; + + // gfx.fillRect(x1, y, rw, height); + + // Let the painting begin! + gfx.setColor(errorMarkerColor); + if (isWarning) { + gfx.setColor(warningMarkerColor); + } + gfx.fillRect(1, y + 2, 3, height - 2); + + gfx.setColor(errorColor); + if (isWarning) { + gfx.setColor(warningColor); + } + int xx = x1; + + // Draw the jagged lines + while (xx < x2) { + gfx.drawLine(xx, y1, xx + 2, y1 + 1); + xx += 2; + gfx.drawLine(xx, y1 + 1, xx + 2, y1); + xx += 2; + } + } catch (Exception e) { + System.out + .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " + + e); + //e.printStackTrace(); + } + + // Won't highlight the line. Select the text instead. + // gfx.setColor(Color.RED); + // gfx.fillRect(2, y, 3, height); + } + + /** + * Trims out trailing whitespaces (to the right) + * + * @param string + * @return - String + */ + private String trimRight(String string) { + String newString = ""; + for (int i = 0; i < string.length(); i++) { + if (string.charAt(i) != ' ') { + newString = string.substring(0, i) + string.trim(); + break; + } + } + return newString; + } + + public void setECSandTheme(ErrorCheckerService ecs, DebugMode mode){ + this.errorCheckerService = ecs; + loadTheme(mode); + } +} diff --git a/pdex/src/processing/mode/java2/VMEventListener.java b/pdex/src/processing/mode/java2/VMEventListener.java new file mode 100755 index 000000000..1e9d33042 --- /dev/null +++ b/pdex/src/processing/mode/java2/VMEventListener.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.event.EventSet; + +/** + * Interface for VM callbacks. + * + * @author Martin Leopold + */ +public interface VMEventListener { + + /** + * Receive an event from the VM. Events are sent in batches. See + * documentation of EventSet for more information. + * + * @param es Set of events + */ + void vmEvent(EventSet es); +} diff --git a/pdex/src/processing/mode/java2/VMEventReader.java b/pdex/src/processing/mode/java2/VMEventReader.java new file mode 100755 index 000000000..ad9178bb6 --- /dev/null +++ b/pdex/src/processing/mode/java2/VMEventReader.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Reader Thread for VM Events. Constantly monitors a VMs EventQueue for new + * events and forwards them to an VMEventListener. + * + * @author Martin Leopold + */ +public class VMEventReader extends Thread { + + EventQueue eventQueue; + VMEventListener listener; + + /** + * Construct a VMEventReader. Needs to be kicked off with start() once + * constructed. + * + * @param eventQueue The queue to read events from. Can be obtained from a + * VirtualMachine via eventQueue(). + * @param listener the listener to forward events to. + */ + public VMEventReader(EventQueue eventQueue, VMEventListener listener) { + super("VM Event Thread"); + this.eventQueue = eventQueue; + this.listener = listener; + } + + @Override + public void run() { + try { + while (true) { + EventSet eventSet = eventQueue.remove(); + listener.vmEvent(eventSet); + /* + * for (Event e : eventSet) { System.out.println("VM Event: " + + * e.toString()); } + */ + } + } catch (VMDisconnectedException e) { + Logger.getLogger(VMEventReader.class.getName()).log(Level.INFO, "VMEventReader quit on VM disconnect"); + } catch (Exception e) { + Logger.getLogger(VMEventReader.class.getName()).log(Level.SEVERE, "VMEventReader quit", e); + } + } +} diff --git a/pdex/src/processing/mode/java2/VariableInspector.form b/pdex/src/processing/mode/java2/VariableInspector.form new file mode 100755 index 000000000..a5f40f1d3 --- /dev/null +++ b/pdex/src/processing/mode/java2/VariableInspector.form @@ -0,0 +1,53 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/pdex/src/processing/mode/java2/VariableInspector.java b/pdex/src/processing/mode/java2/VariableInspector.java new file mode 100755 index 000000000..220d90bbc --- /dev/null +++ b/pdex/src/processing/mode/java2/VariableInspector.java @@ -0,0 +1,929 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.Value; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.DefaultCellEditor; +import javax.swing.GrayFilter; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.table.TableColumn; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.ExpandVetoException; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import org.netbeans.swing.outline.DefaultOutlineCellRenderer; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.ExtTreeWillExpandListener; +import org.netbeans.swing.outline.OutlineModel; +import org.netbeans.swing.outline.RenderDataProvider; +import org.netbeans.swing.outline.RowModel; + +/** + * Variable Inspector window. + * + * @author Martin Leopold + */ +public class VariableInspector extends javax.swing.JFrame { + + protected DefaultMutableTreeNode rootNode; // the root node (invisible) + protected DefaultMutableTreeNode builtins; // node for Processing built-in variables + protected DefaultTreeModel treeModel; // data model for the tree column + protected OutlineModel model; // data model for the whole Outline (tree and other columns) + protected List callStack; // the call stack + protected List locals; // current local variables + protected List thisFields; // all fields of the current this-object + protected List declaredThisFields; // declared i.e. non-inherited fields of this + protected DebugEditor editor; // the editor + protected Debugger dbg; // the debugger + protected List expandedNodes = new ArrayList(); // list of expanded tree paths. (using list to maintain the order of expansion) + protected boolean p5mode = true; // processing / "advanced" mode flag (currently not used + + /** + * Creates new form VariableInspector + */ + public VariableInspector(DebugEditor editor) { + this.editor = editor; + this.dbg = editor.dbg(); + + initComponents(); + + // setup Outline + rootNode = new DefaultMutableTreeNode("root"); + builtins = new DefaultMutableTreeNode("Processing"); + treeModel = new DefaultTreeModel(rootNode); // model for the tree column + model = DefaultOutlineModel.createOutlineModel(treeModel, new VariableRowModel(), true, "Name"); // model for all columns + + ExpansionHandler expansionHandler = new ExpansionHandler(); + model.getTreePathSupport().addTreeWillExpandListener(expansionHandler); + model.getTreePathSupport().addTreeExpansionListener(expansionHandler); + tree.setModel(model); + tree.setRootVisible(false); + tree.setRenderDataProvider(new OutlineRenderer()); + tree.setColumnHidingAllowed(false); // disable visible columns button (shows by default when right scroll bar is visible) + tree.setAutoscrolls(false); + + // set custom renderer and editor for value column, since we are using a custom class for values (VariableNode) + TableColumn valueColumn = tree.getColumnModel().getColumn(1); + valueColumn.setCellRenderer(new ValueCellRenderer()); + valueColumn.setCellEditor(new ValueCellEditor()); + + //System.out.println("renderer: " + tree.getDefaultRenderer(String.class).getClass()); + //System.out.println("editor: " + tree.getDefaultEditor(String.class).getClass()); + + callStack = new ArrayList(); + locals = new ArrayList(); + thisFields = new ArrayList(); + declaredThisFields = new ArrayList(); + + this.setTitle(editor.getSketch().getName()); + +// for (Entry entry : UIManager.getDefaults().entrySet()) { +// System.out.println(entry.getKey()); +// } + } + + @Override + public void setTitle(String title) { + super.setTitle(title + " | Variable Inspector"); + } + + /** + * Model for a Outline Row (excluding the tree column). Column 0 is "Value". + * Column 1 is "Type". Handles setting and getting values. TODO: Maybe use a + * TableCellRenderer instead of this to also have a different icon based on + * expanded state. See: + * http://kickjava.com/src/org/netbeans/swing/outline/DefaultOutlineCellRenderer.java.htm + */ + protected class VariableRowModel implements RowModel { + + protected String[] columnNames = {"Value", "Type"}; + protected int[] editableTypes = {VariableNode.TYPE_BOOLEAN, VariableNode.TYPE_FLOAT, VariableNode.TYPE_INTEGER, VariableNode.TYPE_STRING, VariableNode.TYPE_FLOAT, VariableNode.TYPE_DOUBLE, VariableNode.TYPE_LONG, VariableNode.TYPE_SHORT, VariableNode.TYPE_CHAR}; + + @Override + public int getColumnCount() { + if (p5mode) { + return 1; // only show value in p5 mode + } else { + return 2; + } + } + + @Override + public Object getValueFor(Object o, int i) { + if (o instanceof VariableNode) { + VariableNode var = (VariableNode) o; + switch (i) { + case 0: + return var; // will be converted to an appropriate String by ValueCellRenderer + case 1: + return var.getTypeName(); + default: + return ""; + } + } else { + return ""; + } + } + + @Override + public Class getColumnClass(int i) { + if (i == 0) { + return VariableNode.class; + } + return String.class; + } + + @Override + public boolean isCellEditable(Object o, int i) { + if (i == 0 && o instanceof VariableNode) { + VariableNode var = (VariableNode) o; + //System.out.println("type: " + var.getTypeName()); + for (int type : editableTypes) { + if (var.getType() == type) { + return true; + } + } + } + return false; + } + + @Override + public void setValueFor(Object o, int i, Object o1) { + VariableNode var = (VariableNode) o; + String stringValue = (String) o1; + + Value value = null; + try { + switch (var.getType()) { + case VariableNode.TYPE_INTEGER: + value = dbg.vm().mirrorOf(Integer.parseInt(stringValue)); + break; + case VariableNode.TYPE_BOOLEAN: + value = dbg.vm().mirrorOf(Boolean.parseBoolean(stringValue)); + break; + case VariableNode.TYPE_FLOAT: + value = dbg.vm().mirrorOf(Float.parseFloat(stringValue)); + break; + case VariableNode.TYPE_STRING: + value = dbg.vm().mirrorOf(stringValue); + break; + case VariableNode.TYPE_LONG: + value = dbg.vm().mirrorOf(Long.parseLong(stringValue)); + break; + case VariableNode.TYPE_BYTE: + value = dbg.vm().mirrorOf(Byte.parseByte(stringValue)); + break; + case VariableNode.TYPE_DOUBLE: + value = dbg.vm().mirrorOf(Double.parseDouble(stringValue)); + break; + case VariableNode.TYPE_SHORT: + value = dbg.vm().mirrorOf(Short.parseShort(stringValue)); + break; + case VariableNode.TYPE_CHAR: + // TODO: better char support + if (stringValue.length() > 0) { + value = dbg.vm().mirrorOf(stringValue.charAt(0)); + } + break; + } + } catch (NumberFormatException ex) { + Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "invalid value entered for {0}: {1}", new Object[]{var.getName(), stringValue}); + } + if (value != null) { + var.setValue(value); + Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "new value set: {0}", var.getStringValue()); + } + } + + @Override + public String getColumnName(int i) { + return columnNames[i]; + } + } + + /** + * Renderer for the tree portion of the outline component. Handles icons, + * text color and tool tips. + */ + protected class OutlineRenderer implements RenderDataProvider { + + protected Icon[][] icons; + protected static final int ICON_SIZE = 16; // icon size (square, size=width=height) + + public OutlineRenderer() { + // load icons + icons = loadIcons("theme/var-icons.gif"); + } + + /** + * Load multiple icons (horizotal) with multiple states (vertical) from + * a single file. + * + * @param fileName file path in the mode folder. + * @return a nested array (first index: icon, second index: state) or + * null if the file wasn't found. + */ + protected ImageIcon[][] loadIcons(String fileName) { + DebugMode mode = editor.mode(); + File file = mode.getContentFile(fileName); + if (!file.exists()) { + Logger.getLogger(OutlineRenderer.class.getName()).log(Level.SEVERE, "icon file not found: {0}", file.getAbsolutePath()); + return null; + } + Image allIcons = mode.loadImage(fileName); + int cols = allIcons.getWidth(null) / ICON_SIZE; + int rows = allIcons.getHeight(null) / ICON_SIZE; + ImageIcon[][] iconImages = new ImageIcon[cols][rows]; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + //Image image = createImage(ICON_SIZE, ICON_SIZE); + Image image = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB); + Graphics g = image.getGraphics(); + g.drawImage(allIcons, -i * ICON_SIZE, -j * ICON_SIZE, null); + iconImages[i][j] = new ImageIcon(image); + } + } + return iconImages; + } + + protected Icon getIcon(int type, int state) { + if (type < 0 || type > icons.length - 1) { + return null; + } + return icons[type][state]; + } + + protected VariableNode toVariableNode(Object o) { + if (o instanceof VariableNode) { + return (VariableNode) o; + } else { + return null; + } + } + + protected Icon toGray(Icon icon) { + if (icon instanceof ImageIcon) { + Image grayImage = GrayFilter.createDisabledImage(((ImageIcon) icon).getImage()); + return new ImageIcon(grayImage); + } + // Cannot convert + return icon; + } + + @Override + public String getDisplayName(Object o) { + return o.toString(); // VariableNode.toString() returns name; (for sorting) +// VariableNode var = toVariableNode(o); +// if (var != null) { +// return var.getName(); +// } else { +// return o.toString(); +// } + } + + @Override + public boolean isHtmlDisplayName(Object o) { + return false; + } + + @Override + public Color getBackground(Object o) { + return null; + } + + @Override + public Color getForeground(Object o) { + if (tree.isEnabled()) { + return null; // default + } else { + return Color.GRAY; + } + } + + @Override + public String getTooltipText(Object o) { + VariableNode var = toVariableNode(o); + if (var != null) { + return var.getDescription(); + } else { + return ""; + } + } + + @Override + public Icon getIcon(Object o) { + VariableNode var = toVariableNode(o); + if (var != null) { + if (tree.isEnabled()) { + return getIcon(var.getType(), 0); + } else { + return getIcon(var.getType(), 1); + } + } else { + if (o instanceof TreeNode) { +// TreeNode node = (TreeNode) o; +// AbstractLayoutCache layout = tree.getLayoutCache(); + UIDefaults defaults = UIManager.getDefaults(); + + boolean isLeaf = model.isLeaf(o); + Icon icon; + if (isLeaf) { + icon = defaults.getIcon("Tree.leafIcon"); + } else { + icon = defaults.getIcon("Tree.closedIcon"); + } + + if (!tree.isEnabled()) { + return toGray(icon); + } + return icon; + } + } + return null; // use standard icon + //UIManager.getIcon(o); + } + } + + // TODO: could probably extend the simpler javax.swing.table.DefaultTableCellRenderer here + /** + * Renderer for the value column. Uses an italic font for null values and + * Object values ("instance of ..."). Uses a gray color when tree is not + * enabled. + */ + protected class ValueCellRenderer extends DefaultOutlineCellRenderer { + + public ValueCellRenderer() { + super(); + } + + protected void setItalic(boolean on) { + if (on) { + setFont(new Font(getFont().getName(), Font.ITALIC, getFont().getSize())); + } else { + setFont(new Font(getFont().getName(), Font.PLAIN, getFont().getSize())); + } + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + if (!tree.isEnabled()) { + setForeground(Color.GRAY); + } else { + setForeground(Color.BLACK); + } + + if (value instanceof VariableNode) { + VariableNode var = (VariableNode) value; + + if (var.getValue() == null || var.getType() == VariableNode.TYPE_OBJECT) { + setItalic(true); + } else { + setItalic(false); + } + value = var.getStringValue(); + } + + setValue(value); + return c; + } + } + + /** + * Editor for the value column. Will show an empty string when editing + * String values that are null. + */ + protected class ValueCellEditor extends DefaultCellEditor { + + public ValueCellEditor() { + super(new JTextField()); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + if (!(value instanceof VariableNode)) { + return super.getTableCellEditorComponent(table, value, isSelected, row, column); + } + VariableNode var = (VariableNode) value; + if (var.getType() == VariableNode.TYPE_STRING && var.getValue() == null) { + return super.getTableCellEditorComponent(table, "", isSelected, row, column); + } else { + return super.getTableCellEditorComponent(table, var.getStringValue(), isSelected, row, column); + } + } + } + + /** + * Handler for expanding and collapsing tree nodes. Implements lazy loading + * of tree data (on expand). + */ + protected class ExpansionHandler implements ExtTreeWillExpandListener, TreeExpansionListener { + + @Override + public void treeWillExpand(TreeExpansionEvent tee) throws ExpandVetoException { + //System.out.println("will expand"); + Object last = tee.getPath().getLastPathComponent(); + if (!(last instanceof VariableNode)) { + return; + } + VariableNode var = (VariableNode) last; + // load children +// if (!dbg.isPaused()) { +// System.out.println("throwing veto"); +// //throw new ExpandVetoException(tee, "Debugger busy"); +// } else { + var.removeAllChildren(); // TODO: should we only load it once? + // TODO: don't filter in advanced mode + //System.out.println("loading children for: " + var); + // true means include inherited + var.addChildren(filterNodes(dbg.getFields(var.getValue(), 0, true), new ThisFilter())); +// } + } + + @Override + public void treeWillCollapse(TreeExpansionEvent tee) throws ExpandVetoException { + //throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void treeExpanded(TreeExpansionEvent tee) { + //System.out.println("expanded: " + tee.getPath()); + if (!expandedNodes.contains(tee.getPath())) { + expandedNodes.add(tee.getPath()); + } + +// TreePath newPath = tee.getPath(); +// if (expandedLast != null) { +// // test each node of the path for equality +// for (int i = 0; i < expandedLast.getPathCount(); i++) { +// if (i < newPath.getPathCount()) { +// Object last = expandedLast.getPathComponent(i); +// Object cur = newPath.getPathComponent(i); +// System.out.println(last + " =? " + cur + ": " + last.equals(cur) + "/" + (last.hashCode() == cur.hashCode())); +// } +// } +// } +// System.out.println("path equality: " + newPath.equals(expandedLast)); +// expandedLast = newPath; + } + + @Override + public void treeCollapsed(TreeExpansionEvent tee) { + //System.out.println("collapsed: " + tee.getPath()); + + // first remove all children of collapsed path + // this makes sure children do not appear before parents in the list. + // (children can't be expanded before their parents) + List removalList = new ArrayList(); + for (TreePath path : expandedNodes) { + if (path.getParentPath().equals(tee.getPath())) { + removalList.add(path); + } + } + for (TreePath path : removalList) { + expandedNodes.remove(path); + } + // remove collapsed path + expandedNodes.remove(tee.getPath()); + } + + @Override + public void treeExpansionVetoed(TreeExpansionEvent tee, ExpandVetoException eve) { + //System.out.println("expansion vetoed"); + // nop + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + scrollPane = new javax.swing.JScrollPane(); + tree = new org.netbeans.swing.outline.Outline(); + + scrollPane.setViewportView(tree); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + +// /** +// * @param args the command line arguments +// */ +// public static void main(String args[]) { +// /* +// * Set the Nimbus look and feel +// */ +// // +// /* +// * If Nimbus (introduced in Java SE 6) is not available, stay with the +// * default look and feel. For details see +// * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html +// */ +// try { +// javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); +// } catch (ClassNotFoundException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } catch (InstantiationException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } catch (IllegalAccessException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } catch (javax.swing.UnsupportedLookAndFeelException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } +// // +// +// /* +// * Create and display the form +// */ +// run(new VariableInspector()); +// } + protected static void run(final VariableInspector vi) { + /* + * Create and display the form + */ + java.awt.EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + vi.setVisible(true); + } + }); + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane scrollPane; + protected org.netbeans.swing.outline.Outline tree; + // End of variables declaration//GEN-END:variables + + /** + * Access the root node of the tree. + * + * @return the root node + */ + public DefaultMutableTreeNode getRootNode() { + return rootNode; + } + + /** + * Unlock the inspector window. Rebuild after this to avoid ... dots in the + * trees labels + */ + public void unlock() { + tree.setEnabled(true); + } + + /** + * Lock the inspector window. Cancels open edits. + */ + public void lock() { + if (tree.getCellEditor() != null) { + //tree.getCellEditor().stopCellEditing(); // force quit open edit + tree.getCellEditor().cancelCellEditing(); // cancel an open edit + } + tree.setEnabled(false); + } + + /** + * Reset the inspector windows data. Rebuild after this to make changes + * visible. + */ + public void reset() { + rootNode.removeAllChildren(); + // clear local data for good measure (in case someone rebuilds) + callStack.clear(); + locals.clear(); + thisFields.clear(); + declaredThisFields.clear(); + expandedNodes.clear(); + // update + treeModel.nodeStructureChanged(rootNode); + } + +// public void setAdvancedMode() { +// p5mode = false; +// } +// +// public void setP5Mode() { +// p5mode = true; +// } +// +// public void toggleMode() { +// if (p5mode) { +// setAdvancedMode(); +// } else { +// setP5Mode(); +// } +// } + /** + * Update call stack data. + * + * @param nodes a list of nodes that represent the call stack. + * @param title the title to be used when labeling or otherwise grouping + * call stack data. + */ + public void updateCallStack(List nodes, String title) { + callStack = nodes; + } + + /** + * Update locals data. + * + * @param nodes a list of {@link VariableNode} to be shown as local + * variables in the inspector. + * @param title the title to be used when labeling or otherwise grouping + * locals data. + */ + public void updateLocals(List nodes, String title) { + locals = nodes; + } + + /** + * Update this-fields data. + * + * @param nodes a list of {@link VariableNode}s to be shown as this-fields + * in the inspector. + * @param title the title to be used when labeling or otherwise grouping + * this-fields data. + */ + public void updateThisFields(List nodes, String title) { + thisFields = nodes; + } + + /** + * Update declared (non-inherited) this-fields data. + * + * @param nodes a list of {@link VariableNode}s to be shown as declared + * this-fields in the inspector. + * @param title the title to be used when labeling or otherwise grouping + * declared this-fields data. + */ + public void updateDeclaredThisFields(List nodes, String title) { + declaredThisFields = nodes; + } + + /** + * Rebuild the outline tree from current data. Uses the data provided by + * {@link #updateCallStack}, {@link #updateLocals}, {@link #updateThisFields} + * and {@link #updateDeclaredThisFields} + */ + public void rebuild() { + rootNode.removeAllChildren(); + if (p5mode) { + // add all locals to root + addAllNodes(rootNode, locals); + + // add non-inherited this fields + addAllNodes(rootNode, filterNodes(declaredThisFields, new LocalHidesThisFilter(locals, LocalHidesThisFilter.MODE_PREFIX))); + + // add p5 builtins in a new folder + builtins.removeAllChildren(); + addAllNodes(builtins, filterNodes(thisFields, new P5BuiltinsFilter())); + if (builtins.getChildCount() > 0) { // skip builtins in certain situations e.g. in pure java tabs. + rootNode.add(builtins); + } + + // notify tree (using model) changed a node and its children + // http://stackoverflow.com/questions/2730851/how-to-update-jtree-elements + // needs to be done before expanding paths! + treeModel.nodeStructureChanged(rootNode); + + // handle node expansions + for (TreePath path : expandedNodes) { + //System.out.println("re-expanding: " + path); + path = synthesizePath(path); + if (path != null) { + tree.expandPath(path); + } else { + //System.out.println("couldn't synthesize path"); + } + } + + // this expansion causes problems when sorted and stepping + //tree.expandPath(new TreePath(new Object[]{rootNode, builtins})); + + } else { + // TODO: implement advanced mode here + } + } + + /** + * Re-build a {@link TreePath} from a previous path using equals-checks + * starting at the root node. This is used to use paths from previous trees + * for use on the current tree. + * + * @param path the path to synthesize. + * @return the rebuilt path, usable on the current tree. + */ + protected TreePath synthesizePath(TreePath path) { + //System.out.println("synthesizing: " + path); + if (path.getPathCount() == 0 || !rootNode.equals(path.getPathComponent(0))) { + return null; + } + Object[] newPath = new Object[path.getPathCount()]; + newPath[0] = rootNode; + TreeNode currentNode = rootNode; + for (int i = 0; i < path.getPathCount() - 1; i++) { + // get next node + for (int j = 0; j < currentNode.getChildCount(); j++) { + TreeNode nextNode = currentNode.getChildAt(j); + if (nextNode.equals(path.getPathComponent(i + 1))) { + currentNode = nextNode; + newPath[i + 1] = nextNode; + //System.out.println("found node " + (i+1) + ": " + nextNode); + break; + } + } + if (newPath[i + 1] == null) { + //System.out.println("didn't find node"); + return null; + } + } + return new TreePath(newPath); + } + + /** + * Filter a list of nodes using a {@link VariableNodeFilter}. + * + * @param nodes the list of nodes to filter. + * @param filter the filter to be used. + * @return the filtered list. + */ + protected List filterNodes(List nodes, VariableNodeFilter filter) { + List filtered = new ArrayList(); + for (VariableNode node : nodes) { + if (filter.accept(node)) { + filtered.add(node); + } + } + return filtered; + } + + /** + * Add all nodes in a list to a root node. + * + * @param root the root node to add to. + * @param nodes the list of nodes to add. + */ + protected void addAllNodes(DefaultMutableTreeNode root, List nodes) { + for (MutableTreeNode node : nodes) { + root.add(node); + } + } + + /** + * A filter for {@link VariableNode}s. + */ + public interface VariableNodeFilter { + + /** + * Check whether the filter accepts a {@link VariableNode}. + * + * @param var the input node + * @return true when the filter accepts the input node otherwise false. + */ + public boolean accept(VariableNode var); + } + + /** + * A {@link VariableNodeFilter} that accepts Processing built-in variable + * names. + */ + public class P5BuiltinsFilter implements VariableNodeFilter { + + protected String[] p5Builtins = { + "focused", + "frameCount", + "frameRate", + "height", + "online", + "screen", + "width", + "mouseX", + "mouseY", + "pmouseX", + "pmouseY", + "key", + "keyCode", + "keyPressed" + }; + + @Override + public boolean accept(VariableNode var) { + return Arrays.asList(p5Builtins).contains(var.getName()); + } + } + + /** + * A {@link VariableNodeFilter} that rejects implicit this references. + * (Names starting with "this$") + */ + public class ThisFilter implements VariableNodeFilter { + + @Override + public boolean accept(VariableNode var) { + return !var.getName().startsWith("this$"); + } + } + + /** + * A {@link VariableNodeFilter} that either rejects this-fields if hidden by + * a local, or prefixes its name with "this." + */ + public class LocalHidesThisFilter implements VariableNodeFilter { + + /** + * Reject a this-field if hidden by a local. + */ + public static final int MODE_HIDE = 0; // don't show hidden this fields + /** + * Prefix a this-fields name with "this." if hidden by a local. + */ + public static final int MODE_PREFIX = 1; // prefix hidden this fields with "this." + protected List locals; + protected int mode; + + /** + * Construct a {@link LocalHidesThisFilter}. + * + * @param locals a list of locals to check against + * @param mode either {@link #MODE_HIDE} or {@link #MODE_PREFIX} + */ + public LocalHidesThisFilter(List locals, int mode) { + this.locals = locals; + this.mode = mode; + } + + @Override + public boolean accept(VariableNode var) { + // check if the same name appears in the list of locals i.e. the local hides the field + for (VariableNode local : locals) { + if (var.getName().equals(local.getName())) { + switch (mode) { + case MODE_PREFIX: + var.setName("this." + var.getName()); + return true; + case MODE_HIDE: + return false; + } + } + } + return true; + } + } +} diff --git a/pdex/src/processing/mode/java2/VariableNode.java b/pdex/src/processing/mode/java2/VariableNode.java new file mode 100755 index 000000000..ce4813061 --- /dev/null +++ b/pdex/src/processing/mode/java2/VariableNode.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.java2; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.StringReference; +import com.sun.jdi.Value; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; + +/** + * Model for a variable in the variable inspector. Has a type and name and + * optionally a value. Can have sub-variables (as is the case for objects, and + * arrays). + * + * @author Martin Leopold + */ +public class VariableNode implements MutableTreeNode { + + public static final int TYPE_UNKNOWN = -1; + public static final int TYPE_OBJECT = 0; + public static final int TYPE_ARRAY = 1; + public static final int TYPE_INTEGER = 2; + public static final int TYPE_FLOAT = 3; + public static final int TYPE_BOOLEAN = 4; + public static final int TYPE_CHAR = 5; + public static final int TYPE_STRING = 6; + public static final int TYPE_LONG = 7; + public static final int TYPE_DOUBLE = 8; + public static final int TYPE_BYTE = 9; + public static final int TYPE_SHORT = 10; + public static final int TYPE_VOID = 11; + protected String type; + protected String name; + protected Value value; + protected List children = new ArrayList(); + protected MutableTreeNode parent; + + /** + * Construct a {@link VariableNode}. + * @param name the name + * @param type the type + * @param value the value + */ + public VariableNode(String name, String type, Value value) { + this.name = name; + this.type = type; + this.value = value; + } + + public void setValue(Value value) { + this.value = value; + } + + public Value getValue() { + return value; + } + + /** + * Get a String representation of this variable nodes value. + * + * @return a String representing the value. + */ + public String getStringValue() { + String str; + if (value != null) { + if (getType() == TYPE_OBJECT) { + str = "instance of " + type; + } else if (getType() == TYPE_ARRAY) { + //instance of int[5] (id=998) --> instance of int[5] + str = value.toString().substring(0, value.toString().lastIndexOf(" ")); + } else if (getType() == TYPE_STRING) { + str = ((StringReference) value).value(); // use original string value (without quotes) + } else { + str = value.toString(); + } + } else { + str = "null"; + } + return str; + } + + public String getTypeName() { + return type; + } + + public int getType() { + if (type == null) { + return TYPE_UNKNOWN; + } + if (type.endsWith("[]")) { + return TYPE_ARRAY; + } + if (type.equals("int")) { + return TYPE_INTEGER; + } + if (type.equals("long")) { + return TYPE_LONG; + } + if (type.equals("byte")) { + return TYPE_BYTE; + } + if (type.equals("short")) { + return TYPE_SHORT; + } + if (type.equals("float")) { + return TYPE_FLOAT; + } + if (type.equals("double")) { + return TYPE_DOUBLE; + } + if (type.equals("char")) { + return TYPE_CHAR; + } + if (type.equals("java.lang.String")) { + return TYPE_STRING; + } + if (type.equals("boolean")) { + return TYPE_BOOLEAN; + } + if (type.equals("void")) { + return TYPE_VOID; //TODO: check if this is correct + } + return TYPE_OBJECT; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * Add a {@link VariableNode} as child. + * + * @param c the {@link VariableNode} to add. + */ + public void addChild(VariableNode c) { + children.add(c); + c.setParent(this); + } + + /** + * Add multiple {@link VariableNode}s as children. + * + * @param children the list of {@link VariableNode}s to add. + */ + public void addChildren(List children) { + for (VariableNode child : children) { + addChild(child); + } + } + + @Override + public TreeNode getChildAt(int i) { + return children.get(i); + } + + @Override + public int getChildCount() { + return children.size(); + } + + @Override + public TreeNode getParent() { + return parent; + } + + @Override + public int getIndex(TreeNode tn) { + return children.indexOf(tn); + } + + @Override + public boolean getAllowsChildren() { + if (value == null) { + return false; + } + + // handle strings + if (getType() == TYPE_STRING) { + return false; + } + + // handle arrays + if (getType() == TYPE_ARRAY) { + ArrayReference array = (ArrayReference) value; + return array.length() > 0; + } + // handle objects + if (getType() == TYPE_OBJECT) { // this also rules out null + // check if this object has any fields + ObjectReference obj = (ObjectReference) value; + return !obj.referenceType().visibleFields().isEmpty(); + } + + return false; + } + + /** + * This controls the default icon and disclosure triangle. + * + * @return true, will show "folder" icon and disclosure triangle. + */ + @Override + public boolean isLeaf() { + //return children.size() == 0; + return !getAllowsChildren(); + } + + @Override + public Enumeration children() { + return Collections.enumeration(children); + } + + /** + * Get a String representation of this {@link VariableNode}. + * + * @return the name of the variable (for sorting to work). + */ + @Override + public String toString() { + return getName(); // for sorting + } + + /** + * Get a String description of this {@link VariableNode}. Contains the type, + * name and value. + * + * @return the description + */ + public String getDescription() { + String str = ""; + if (type != null) { + str += type + " "; + } + str += name; + str += " = " + getStringValue(); + return str; + } + + @Override + public void insert(MutableTreeNode mtn, int i) { + children.add(i, this); + } + + @Override + public void remove(int i) { + MutableTreeNode mtn = children.remove(i); + if (mtn != null) { + mtn.setParent(null); + } + } + + @Override + public void remove(MutableTreeNode mtn) { + children.remove(mtn); + mtn.setParent(null); + } + + /** + * Remove all children from this {@link VariableNode}. + */ + public void removeAllChildren() { + for (MutableTreeNode mtn : children) { + mtn.setParent(null); + } + children.clear(); + } + + @Override + public void setUserObject(Object o) { + if (o instanceof Value) { + value = (Value) o; + } + } + + @Override + public void removeFromParent() { + parent.remove(this); + this.parent = null; + } + + @Override + public void setParent(MutableTreeNode mtn) { + parent = mtn; + } + + /** + * Test for equality. To be equal, two {@link VariableNode}s need to have + * equal type, name and value. + * + * @param obj the object to test for equality with this {@link VariableNode} + * @return true if the given object is equal to this {@link VariableNode} + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final VariableNode other = (VariableNode) obj; + if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) { + //System.out.println("type not equal"); + return false; + } + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + //System.out.println("name not equal"); + return false; + } + if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { + //System.out.println("value not equal"); + return false; + } +// if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) { +// System.out.println("parent not equal: " + this.parent + "/" + other.parent); +// return false; +// } + return true; + } + + /** + * Returns a hash code based on type, name and value. + */ + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0); + hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); + hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0); +// hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0); + return hash; + } +} diff --git a/pdex/src/processing/mode/java2/XQConsoleToggle.java b/pdex/src/processing/mode/java2/XQConsoleToggle.java new file mode 100755 index 000000000..9042b78ae --- /dev/null +++ b/pdex/src/processing/mode/java2/XQConsoleToggle.java @@ -0,0 +1,131 @@ +package processing.mode.java2; + +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JPanel; + +/** + * Toggle Button displayed in the editor line status panel for toggling bewtween + * console and problems list. Glorified JPanel. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ + +public class XQConsoleToggle extends JPanel implements MouseListener { + public static final String[] text = { "Console", "Errors" }; + + private boolean toggleText = true; + private boolean toggleBG = true; + + /** + * Height of the component + */ + protected int height; + protected DebugEditor editor; + protected String buttonName; + + public XQConsoleToggle(DebugEditor editor, String buttonName, int height) { + this.editor = editor; + this.height = height; + this.buttonName = buttonName; + } + + public Dimension getPreferredSize() { + return new Dimension(70, height); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public Dimension getMaximumSize() { + return getPreferredSize(); + } + + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // On mouse hover, text and background color are changed. + if (toggleBG) { + g.setColor(new Color(0xff9DA7B0)); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.setColor(new Color(0xff29333D)); + g.fillRect(0, 0, 4, this.getHeight()); + g.setColor(Color.BLACK); + } else { + g.setColor(Color.DARK_GRAY); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.setColor(new Color(0xff29333D)); + g.fillRect(0, 0, 4, this.getHeight()); + g.setColor(Color.WHITE); + } + + g.drawString(buttonName, getWidth() / 2 + 2 // + 2 is a offset + - getFontMetrics(getFont()).stringWidth(buttonName) / 2, + this.getHeight() - 6); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + + this.repaint(); + try { + editor.toggleView(buttonName); + } catch (Exception e) { + System.out.println(e); + // e.printStackTrace(); + } + toggleText = !toggleText; + } + + @Override + public void mouseEntered(MouseEvent arg0) { + toggleBG = !toggleBG; + this.repaint(); + } + + @Override + public void mouseExited(MouseEvent arg0) { + toggleBG = !toggleBG; + this.repaint(); + } + + @Override + public void mousePressed(MouseEvent arg0) { + } + + @Override + public void mouseReleased(MouseEvent arg0) { + } +} \ No newline at end of file diff --git a/pdex/src/processing/mode/java2/XQErrorTable.java b/pdex/src/processing/mode/java2/XQErrorTable.java new file mode 100755 index 000000000..db3bb71da --- /dev/null +++ b/pdex/src/processing/mode/java2/XQErrorTable.java @@ -0,0 +1,161 @@ +package processing.mode.java2; + +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableModel; + +/** + * Custom JTable implementation for XQMode. Minor tweaks and addtions. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class XQErrorTable extends JTable { + + /** + * Column Names of JTable + */ + public static final String[] columnNames = { "Problem", "Tab", "Line" }; + + /** + * Column Widths of JTable. + */ + public int[] columnWidths = { 600, 100, 50 }; // Default Values + + /** + * Is the column being resized? + */ + private boolean columnResizing = false; + + protected ErrorCheckerService errorCheckerService; + + @Override + public boolean isCellEditable(int rowIndex, int colIndex) { + return false; // Disallow the editing of any cell + } + + public XQErrorTable(final ErrorCheckerService errorCheckerService) { + this.errorCheckerService = errorCheckerService; + for (int i = 0; i < this.getColumnModel().getColumnCount(); i++) { + this.getColumnModel().getColumn(i) + .setPreferredWidth(columnWidths[i]); + } + + this.getTableHeader().setReorderingAllowed(false); + + this.addMouseListener(new MouseAdapter() { + @Override + synchronized public void mouseReleased(MouseEvent e) { + try { + errorCheckerService.scrollToErrorLine(((XQErrorTable) e + .getSource()).getSelectedRow()); + // System.out.print("Row clicked: " + // + ((XQErrorTable) e.getSource()).getSelectedRow()); + } catch (Exception e1) { + System.out.println("Exception XQErrorTable mouseReleased " + + e); + } + } + }); + + // Handles the resizing of columns. When mouse press is detected on + // table header, Stop updating the table, store new values of column + // widths,and resume updating. Updating is disabled as long as + // columnResizing is true + this.getTableHeader().addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + columnResizing = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + columnResizing = false; + for (int i = 0; i < ((JTableHeader) e.getSource()) + .getColumnModel().getColumnCount(); i++) { + columnWidths[i] = ((JTableHeader) e.getSource()) + .getColumnModel().getColumn(i).getWidth(); + // System.out.println("nw " + columnWidths[i]); + } + } + }); + } + + + /** + * Updates table contents with new data + * @param tableModel - TableModel + * @return boolean - If table data was updated + */ + @SuppressWarnings("rawtypes") + synchronized public boolean updateTable(final TableModel tableModel) { + + // If problems list is not visible, no need to update + if (!this.isVisible()) + return false; + + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + + try { + setModel(tableModel); + + // Set column widths to user defined widths + for (int i = 0; i < getColumnModel().getColumnCount(); i++) { + getColumnModel().getColumn(i).setPreferredWidth( + columnWidths[i]); + } + getTableHeader().setReorderingAllowed(false); + validate(); + repaint(); + } catch (Exception e) { + System.out.println("Exception at XQErrorTable.updateTable " + e); + // e.printStackTrace(); + } + } + }; + + try { + if (!columnResizing) + worker.execute(); + } catch (Exception e) { + System.out.println("ErrorTable updateTable Worker's slacking." + + e.getMessage()); + // e.printStackTrace(); + } + return true; + } + +} diff --git a/pdex/src/processing/mode/java2/XQPreprocessor.java b/pdex/src/processing/mode/java2/XQPreprocessor.java new file mode 100755 index 000000000..3b1f6d246 --- /dev/null +++ b/pdex/src/processing/mode/java2/XQPreprocessor.java @@ -0,0 +1,245 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.java2; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.TextEdit; + +import processing.app.Preferences; +import processing.core.PApplet; + +/** + * My implementation of P5 preprocessor. Uses Eclipse JDT features instead of + * ANTLR. Performance gains mostly and full control over debug output. But needs + * lots and lots of testing. There will always an option to switch back to PDE + * preproc. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class XQPreprocessor { + + private ASTRewrite rewrite = null; + public int mainClassOffset = 0; + ArrayList imports; + ArrayList extraImports; + + /** + * The main method that performs preprocessing. Converts code into compilable java. + * @param source - String + * @param programImports - List of import statements + * @return String - Compile ready java code + */ + public String doYourThing(String source, + ArrayList programImports) { + this.extraImports = programImports; + source = prepareImports() + source; + Document doc = new Document(source); + + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setSource(doc.get().toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + @SuppressWarnings("unchecked") + Map options = JavaCore.getOptions(); + + // Ben has decided to move on to 1.6. Yay! + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + cu.recordModifications(); + rewrite = ASTRewrite.create(cu.getAST()); + cu.accept(new XQASTVisitor()); + + TextEdit edits = cu.rewrite(doc, null); + try { + edits.apply(doc); + } catch (MalformedTreeException e) { + e.printStackTrace(); + } catch (BadLocationException e) { + e.printStackTrace(); + } + // System.out.println("------------XQPreProc-----------------"); + // System.out.println(doc.get()); + // System.out.println("------------XQPreProc End-----------------"); + + // Calculate main class offset + int position = doc.get().indexOf("{") + 1; + int lines = 0; + for (int i = 0; i < position; i++) { + if (doc.get().charAt(i) == '\n') + lines++; + } + lines += 2; + // System.out.println("Lines: " + lines); + mainClassOffset = lines; + + return doc.get(); + } + + /** + * Returns all import statements as lines of code + * + * @return String - All import statements combined + */ + public String prepareImports() { + imports = new ArrayList(); + for (int i = 0; i < extraImports.size(); i++) { + imports.add(new String(extraImports.get(i).importName)); + } + imports.add(new String("// Default Imports")); + for (int i = 0; i < getCoreImports().length; i++) { + imports.add(new String("import " + getCoreImports()[i] + ";")); + } + for (int i = 0; i < getDefaultImports().length; i++) { + imports.add(new String("import " + getDefaultImports()[i] + ";")); + } + String totalImports = ""; + for (int i = 0; i < imports.size(); i++) { + totalImports += imports.get(i) + "\n"; + } + totalImports += "\n"; + return totalImports; + } + + public String[] getCoreImports() { + return new String[] { "processing.core.*", "processing.data.*", + "processing.opengl.*" }; + } + + public String[] getDefaultImports() { + // These may change in-between (if the prefs panel adds this option) + String prefsLine = Preferences.get("preproc.imports.list"); + return PApplet.splitTokens(prefsLine, ", "); + } + + /** + * Visitor implementation that does all the substitution dirty work.
    + *
  • Any function not specified as being protected or private will be made + * 'public'. This means that void setup() becomes + * public void setup(). + * + *
  • Converts doubles into floats, i.e. 12.3 becomes 12.3f so that people + * don't have to add f after their numbers all the time since it's confusing + * for beginners. Also, most functions of p5 core deal with floats only. + * + * @author Manindra Moharana + * + */ + private class XQASTVisitor extends ASTVisitor { + @SuppressWarnings({ "unchecked", "rawtypes" }) + public boolean visit(MethodDeclaration node) { + if (node.getReturnType2() != null) { + // if return type is color, make it int + // if (node.getReturnType2().toString().equals("color")) { + // System.err.println("color type detected!"); + // node.setReturnType2(rewrite.getAST().newPrimitiveType( + // PrimitiveType.INT)); + // } + + // The return type is not void, no need to make it public + // if (!node.getReturnType2().toString().equals("void")) + // return true; + } + + // Simple method, make it public + if (node.modifiers().size() == 0 && !node.isConstructor()) { + // rewrite.set(node, node.getModifiersProperty(), + // Modifier.PUBLIC, + // null); + // rewrite.getListRewrite(node, + // node.getModifiersProperty()).insertLast(Modifier., null) + List newMod = rewrite.getAST().newModifiers(Modifier.PUBLIC); + node.modifiers().add(newMod.get(0)); + } + + return true; + } + + public boolean visit(NumberLiteral node) { + if (!node.getToken().endsWith("f") + && !node.getToken().endsWith("d")) { + for (int i = 0; i < node.getToken().length(); i++) { + if (node.getToken().charAt(i) == '.') { + + String s = node.getToken() + "f"; + node.setToken(s); + break; + } + } + } + return true; + } + + // public boolean visit(FieldDeclaration node) { + // if (node.getType().toString().equals("color")){ + // System.err.println("color type detected!"); + // node.setType(rewrite.getAST().newPrimitiveType( + // PrimitiveType.INT)); + // } + // return true; + // } + // + // public boolean visit(VariableDeclarationStatement node) { + // if (node.getType().toString().equals("color")){ + // System.err.println("color type detected!"); + // node.setType(rewrite.getAST().newPrimitiveType( + // PrimitiveType.INT)); + // } + // return true; + // } + + /** + * This is added just for debugging purposes - to make sure that all + * instances of color type have been substituded as in by the regex + * search in ErrorCheckerService.preprocessCode(). + */ + public boolean visit(SimpleType node) { + if (node.toString().equals("color")) { + System.err + .println("color type detected! \nThis shouldn't be happening! Please report this as an issue on www.github.com/Manindra29/XQMode"); + } + return true; + + } + + } + +} diff --git a/pdex/theme/buttons.gif b/pdex/theme/buttons.gif new file mode 100755 index 0000000000000000000000000000000000000000..a16fa330fae97658296fa1f3c3dcb3e0d811cb40 GIT binary patch literal 6428 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 aJxlxfEJI@czTSMc&3tZZJ{ucI_dfvA0{z|q literal 0 HcmV?d00001 diff --git a/pdex/theme/tab-sel-left.gif b/pdex/theme/tab-sel-left.gif new file mode 100755 index 0000000000000000000000000000000000000000..bdee43c25cf2885042d8c024a2712d142adc4599 GIT binary patch literal 62 zcmZ?wbhEHbWMNQbn8?5|W6_$%?x_b(U14Bg&;eowkT?UAcu)UIPNBCgJVxid)^D>Z P=gGS#QJ3^ml))MRD$Nr0 literal 0 HcmV?d00001 diff --git a/pdex/theme/tab-sel-menu.gif b/pdex/theme/tab-sel-menu.gif new file mode 100755 index 0000000000000000000000000000000000000000..d926650e7f89c6848bfa20c791498fc1a27804d2 GIT binary patch literal 104 zcmZ?wbhEHb6l73jn8?6z<=PFekhuT<|2K9|Rs6}q00KH70wmACWI3mQ<>|Nli|2&g z=-zy9Pc=_Xq(E1gL)8JU1)9%~tyeq#G~&GE?M2(48*`S-pZ}rbOTe@<%RY13iZC!( F0|4Q)DtQ0^ literal 0 HcmV?d00001 diff --git a/pdex/theme/tab-sel-mid.gif b/pdex/theme/tab-sel-mid.gif new file mode 100755 index 0000000000000000000000000000000000000000..fa8ed45fca9a8d515f21f1df03cc1c5f4b03c495 GIT binary patch literal 54 zcmZ?wbhEHbWMNQbXkcJy?4Eky)D^{_EDRu^10p~&3{1Q&{VT=a@-LpV$lmI P^W@!=s7rb&%3uuu4}}s| literal 0 HcmV?d00001 diff --git a/pdex/theme/tab-unsel-menu.gif b/pdex/theme/tab-unsel-menu.gif new file mode 100755 index 0000000000000000000000000000000000000000..a1720a589caf4697f8f79da5fd1b5b270ded5633 GIT binary patch literal 104 zcmZ?wbhEHb6l73jn8?7;F=>uhNZg!d8ydT(D*j|)00A8k0g`86vYgYu^7LE&#dAV# zbZ@@5r<$iGQlKl$q3QtF0?p^g)~g+V8gX9o_M+|2jX6u^&;QWzC1Bc_WuG~1MHm>Y E0YW?|q5uE@ literal 0 HcmV?d00001 diff --git a/pdex/theme/tab-unsel-mid.gif b/pdex/theme/tab-unsel-mid.gif new file mode 100755 index 0000000000000000000000000000000000000000..a2c5497b898b4528a8095dc0cf48c6700dd179a7 GIT binary patch literal 54 zcmZ?wbhEHbWMNQbXkcJy?4CMj*#^a*EDRu^10p~&3{1Q&{VT=a@-LpV +breakpoint.marker.color = #4a545e + +# current line background color +currentline.bgcolor = #ffff96 +# marker for the current line in left hand gutter (2 ascii characters) +currentline.marker = -> +currentline.marker.color = #e27500 + +# left hand gutter background color +gutter.bgcolor = #fcfcfc +# color of vertical separation line +gutter.linecolor = #e9e9e9 +# space (in px) added to left and right of gutter markers +gutter.padding = 3 \ No newline at end of file diff --git a/pdex/theme/var-icons.gif b/pdex/theme/var-icons.gif new file mode 100755 index 0000000000000000000000000000000000000000..1d0086a38ebb728a2a44d3b4d510cf12992fc1dd GIT binary patch literal 5152 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 Date: Thu, 6 Dec 2012 22:56:27 +0000 Subject: [PATCH 002/608] changing package for this feller --- .../processing/mode/{java2 => experimental}/ArrayFieldNode.java | 2 +- .../mode/{java2 => experimental}/ClassLoadListener.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/Compiler.java | 2 +- .../src/processing/mode/{java2 => experimental}/DebugBuild.java | 2 +- .../processing/mode/{java2 => experimental}/DebugEditor.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/DebugMode.java | 2 +- .../processing/mode/{java2 => experimental}/DebugRunner.java | 2 +- .../processing/mode/{java2 => experimental}/DebugToolbar.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/Debugger.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/ErrorBar.java | 2 +- .../mode/{java2 => experimental}/ErrorCheckerService.java | 2 +- .../processing/mode/{java2 => experimental}/ErrorMarker.java | 2 +- .../processing/mode/{java2 => experimental}/ErrorWindow.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/FieldNode.java | 2 +- .../mode/{java2 => experimental}/ImportStatement.java | 2 +- .../processing/mode/{java2 => experimental}/LineBreakpoint.java | 2 +- .../processing/mode/{java2 => experimental}/LineHighlight.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/LineID.java | 2 +- .../processing/mode/{java2 => experimental}/LineListener.java | 2 +- .../mode/{java2 => experimental}/LocalVariableNode.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/Problem.java | 2 +- pdex/src/processing/mode/{java2 => experimental}/TextArea.java | 2 +- .../mode/{java2 => experimental}/TextAreaPainter.java | 2 +- .../mode/{java2 => experimental}/VMEventListener.java | 2 +- .../processing/mode/{java2 => experimental}/VMEventReader.java | 2 +- .../mode/{java2 => experimental}/VariableInspector.form | 0 .../mode/{java2 => experimental}/VariableInspector.java | 2 +- .../processing/mode/{java2 => experimental}/VariableNode.java | 2 +- .../mode/{java2 => experimental}/XQConsoleToggle.java | 2 +- .../processing/mode/{java2 => experimental}/XQErrorTable.java | 2 +- .../processing/mode/{java2 => experimental}/XQPreprocessor.java | 2 +- 31 files changed, 30 insertions(+), 30 deletions(-) rename pdex/src/processing/mode/{java2 => experimental}/ArrayFieldNode.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/ClassLoadListener.java (97%) rename pdex/src/processing/mode/{java2 => experimental}/Compiler.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/DebugBuild.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/DebugEditor.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/DebugMode.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/DebugRunner.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/DebugToolbar.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/Debugger.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/ErrorBar.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/ErrorCheckerService.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/ErrorMarker.java (94%) rename pdex/src/processing/mode/{java2 => experimental}/ErrorWindow.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/FieldNode.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/ImportStatement.java (97%) rename pdex/src/processing/mode/{java2 => experimental}/LineBreakpoint.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/LineHighlight.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/LineID.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/LineListener.java (96%) rename pdex/src/processing/mode/{java2 => experimental}/LocalVariableNode.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/Problem.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/TextArea.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/TextAreaPainter.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/VMEventListener.java (96%) rename pdex/src/processing/mode/{java2 => experimental}/VMEventReader.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/VariableInspector.form (100%) rename pdex/src/processing/mode/{java2 => experimental}/VariableInspector.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/VariableNode.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/XQConsoleToggle.java (98%) rename pdex/src/processing/mode/{java2 => experimental}/XQErrorTable.java (99%) rename pdex/src/processing/mode/{java2 => experimental}/XQPreprocessor.java (99%) diff --git a/pdex/src/processing/mode/java2/ArrayFieldNode.java b/pdex/src/processing/mode/experimental/ArrayFieldNode.java similarity index 98% rename from pdex/src/processing/mode/java2/ArrayFieldNode.java rename to pdex/src/processing/mode/experimental/ArrayFieldNode.java index 0037a84ec..04b3fb111 100755 --- a/pdex/src/processing/mode/java2/ArrayFieldNode.java +++ b/pdex/src/processing/mode/experimental/ArrayFieldNode.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.ArrayReference; import com.sun.jdi.ClassNotLoadedException; diff --git a/pdex/src/processing/mode/java2/ClassLoadListener.java b/pdex/src/processing/mode/experimental/ClassLoadListener.java similarity index 97% rename from pdex/src/processing/mode/java2/ClassLoadListener.java rename to pdex/src/processing/mode/experimental/ClassLoadListener.java index 03c474e15..64bd5516b 100755 --- a/pdex/src/processing/mode/java2/ClassLoadListener.java +++ b/pdex/src/processing/mode/experimental/ClassLoadListener.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.ReferenceType; diff --git a/pdex/src/processing/mode/java2/Compiler.java b/pdex/src/processing/mode/experimental/Compiler.java similarity index 99% rename from pdex/src/processing/mode/java2/Compiler.java rename to pdex/src/processing/mode/experimental/Compiler.java index ae1c9c09f..1a85c6a29 100755 --- a/pdex/src/processing/mode/java2/Compiler.java +++ b/pdex/src/processing/mode/experimental/Compiler.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.io.*; import java.lang.reflect.Method; diff --git a/pdex/src/processing/mode/java2/DebugBuild.java b/pdex/src/processing/mode/experimental/DebugBuild.java similarity index 98% rename from pdex/src/processing/mode/java2/DebugBuild.java rename to pdex/src/processing/mode/experimental/DebugBuild.java index 7ef1b38fa..a77dc1972 100755 --- a/pdex/src/processing/mode/java2/DebugBuild.java +++ b/pdex/src/processing/mode/experimental/DebugBuild.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.io.File; import processing.app.Sketch; diff --git a/pdex/src/processing/mode/java2/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java similarity index 99% rename from pdex/src/processing/mode/java2/DebugEditor.java rename to pdex/src/processing/mode/experimental/DebugEditor.java index eb41c5e2b..c8be53c97 100755 --- a/pdex/src/processing/mode/java2/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.BorderLayout; import java.awt.CardLayout; diff --git a/pdex/src/processing/mode/java2/DebugMode.java b/pdex/src/processing/mode/experimental/DebugMode.java similarity index 99% rename from pdex/src/processing/mode/java2/DebugMode.java rename to pdex/src/processing/mode/experimental/DebugMode.java index db9d71a9d..ba7cd5a0a 100755 --- a/pdex/src/processing/mode/java2/DebugMode.java +++ b/pdex/src/processing/mode/experimental/DebugMode.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.Color; import java.io.File; diff --git a/pdex/src/processing/mode/java2/DebugRunner.java b/pdex/src/processing/mode/experimental/DebugRunner.java similarity index 98% rename from pdex/src/processing/mode/java2/DebugRunner.java rename to pdex/src/processing/mode/experimental/DebugRunner.java index 8f67b187a..f438a7023 100755 --- a/pdex/src/processing/mode/java2/DebugRunner.java +++ b/pdex/src/processing/mode/experimental/DebugRunner.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.VirtualMachine; import processing.app.RunnerListener; diff --git a/pdex/src/processing/mode/java2/DebugToolbar.java b/pdex/src/processing/mode/experimental/DebugToolbar.java similarity index 99% rename from pdex/src/processing/mode/java2/DebugToolbar.java rename to pdex/src/processing/mode/experimental/DebugToolbar.java index 73b57b613..817627a51 100755 --- a/pdex/src/processing/mode/java2/DebugToolbar.java +++ b/pdex/src/processing/mode/experimental/DebugToolbar.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.Image; import java.awt.event.MouseEvent; diff --git a/pdex/src/processing/mode/java2/Debugger.java b/pdex/src/processing/mode/experimental/Debugger.java similarity index 99% rename from pdex/src/processing/mode/java2/Debugger.java rename to pdex/src/processing/mode/experimental/Debugger.java index e784ee305..758f6cfae 100755 --- a/pdex/src/processing/mode/java2/Debugger.java +++ b/pdex/src/processing/mode/experimental/Debugger.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.*; import com.sun.jdi.event.*; diff --git a/pdex/src/processing/mode/java2/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java similarity index 99% rename from pdex/src/processing/mode/java2/ErrorBar.java rename to pdex/src/processing/mode/experimental/ErrorBar.java index 05271f7a9..6a2d43f20 100755 --- a/pdex/src/processing/mode/java2/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -20,7 +20,7 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.Color; import java.awt.Cursor; diff --git a/pdex/src/processing/mode/java2/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java similarity index 99% rename from pdex/src/processing/mode/java2/ErrorCheckerService.java rename to pdex/src/processing/mode/experimental/ErrorCheckerService.java index c54486d0d..850613095 100755 --- a/pdex/src/processing/mode/java2/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1,4 +1,4 @@ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.EventQueue; import java.io.File; diff --git a/pdex/src/processing/mode/java2/ErrorMarker.java b/pdex/src/processing/mode/experimental/ErrorMarker.java similarity index 94% rename from pdex/src/processing/mode/java2/ErrorMarker.java rename to pdex/src/processing/mode/experimental/ErrorMarker.java index 74736ecda..0a10cff4b 100755 --- a/pdex/src/processing/mode/java2/ErrorMarker.java +++ b/pdex/src/processing/mode/experimental/ErrorMarker.java @@ -1,4 +1,4 @@ -package processing.mode.java2; +package processing.mode.experimental; /** * Error markers displayed on the Error Bar. * diff --git a/pdex/src/processing/mode/java2/ErrorWindow.java b/pdex/src/processing/mode/experimental/ErrorWindow.java similarity index 99% rename from pdex/src/processing/mode/java2/ErrorWindow.java rename to pdex/src/processing/mode/experimental/ErrorWindow.java index 4e053dbe4..6494b58ed 100755 --- a/pdex/src/processing/mode/java2/ErrorWindow.java +++ b/pdex/src/processing/mode/experimental/ErrorWindow.java @@ -20,7 +20,7 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.BorderLayout; import java.awt.Frame; diff --git a/pdex/src/processing/mode/java2/FieldNode.java b/pdex/src/processing/mode/experimental/FieldNode.java similarity index 98% rename from pdex/src/processing/mode/java2/FieldNode.java rename to pdex/src/processing/mode/experimental/FieldNode.java index 3fc6e2adb..dbe9d4fd9 100755 --- a/pdex/src/processing/mode/java2/FieldNode.java +++ b/pdex/src/processing/mode/experimental/FieldNode.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.Field; diff --git a/pdex/src/processing/mode/java2/ImportStatement.java b/pdex/src/processing/mode/experimental/ImportStatement.java similarity index 97% rename from pdex/src/processing/mode/java2/ImportStatement.java rename to pdex/src/processing/mode/experimental/ImportStatement.java index 84277b875..6e28490ef 100755 --- a/pdex/src/processing/mode/java2/ImportStatement.java +++ b/pdex/src/processing/mode/experimental/ImportStatement.java @@ -20,7 +20,7 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package processing.mode.java2; +package processing.mode.experimental; /** * Wrapper for import statements diff --git a/pdex/src/processing/mode/java2/LineBreakpoint.java b/pdex/src/processing/mode/experimental/LineBreakpoint.java similarity index 99% rename from pdex/src/processing/mode/java2/LineBreakpoint.java rename to pdex/src/processing/mode/experimental/LineBreakpoint.java index 84ae65d94..8d006fd9d 100755 --- a/pdex/src/processing/mode/java2/LineBreakpoint.java +++ b/pdex/src/processing/mode/experimental/LineBreakpoint.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.Location; diff --git a/pdex/src/processing/mode/java2/LineHighlight.java b/pdex/src/processing/mode/experimental/LineHighlight.java similarity index 99% rename from pdex/src/processing/mode/java2/LineHighlight.java rename to pdex/src/processing/mode/experimental/LineHighlight.java index b92d3aaa5..c1789cf24 100755 --- a/pdex/src/processing/mode/java2/LineHighlight.java +++ b/pdex/src/processing/mode/experimental/LineHighlight.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.Color; import java.util.HashSet; diff --git a/pdex/src/processing/mode/java2/LineID.java b/pdex/src/processing/mode/experimental/LineID.java similarity index 99% rename from pdex/src/processing/mode/java2/LineID.java rename to pdex/src/processing/mode/experimental/LineID.java index 52098abe2..a08d21296 100755 --- a/pdex/src/processing/mode/java2/LineID.java +++ b/pdex/src/processing/mode/experimental/LineID.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.util.HashSet; import java.util.Set; diff --git a/pdex/src/processing/mode/java2/LineListener.java b/pdex/src/processing/mode/experimental/LineListener.java similarity index 96% rename from pdex/src/processing/mode/java2/LineListener.java rename to pdex/src/processing/mode/experimental/LineListener.java index 05864678c..c6c3ae1b0 100755 --- a/pdex/src/processing/mode/java2/LineListener.java +++ b/pdex/src/processing/mode/experimental/LineListener.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; /** * A Listener for line number changes. diff --git a/pdex/src/processing/mode/java2/LocalVariableNode.java b/pdex/src/processing/mode/experimental/LocalVariableNode.java similarity index 98% rename from pdex/src/processing/mode/java2/LocalVariableNode.java rename to pdex/src/processing/mode/experimental/LocalVariableNode.java index 857ea697b..d1bdb2092 100755 --- a/pdex/src/processing/mode/java2/LocalVariableNode.java +++ b/pdex/src/processing/mode/experimental/LocalVariableNode.java @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.InvalidTypeException; diff --git a/pdex/src/processing/mode/java2/Problem.java b/pdex/src/processing/mode/experimental/Problem.java similarity index 99% rename from pdex/src/processing/mode/java2/Problem.java rename to pdex/src/processing/mode/experimental/Problem.java index 1a6a59344..f7348b71c 100755 --- a/pdex/src/processing/mode/java2/Problem.java +++ b/pdex/src/processing/mode/experimental/Problem.java @@ -20,7 +20,7 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package processing.mode.java2; +package processing.mode.experimental; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/pdex/src/processing/mode/java2/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java similarity index 99% rename from pdex/src/processing/mode/java2/TextArea.java rename to pdex/src/processing/mode/experimental/TextArea.java index 1400623e1..7dd0d430e 100755 --- a/pdex/src/processing/mode/java2/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.Color; import java.awt.Cursor; diff --git a/pdex/src/processing/mode/java2/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java similarity index 99% rename from pdex/src/processing/mode/java2/TextAreaPainter.java rename to pdex/src/processing/mode/experimental/TextAreaPainter.java index 8db27a60a..36706a5f0 100755 --- a/pdex/src/processing/mode/java2/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import java.awt.Color; import java.awt.Graphics; diff --git a/pdex/src/processing/mode/java2/VMEventListener.java b/pdex/src/processing/mode/experimental/VMEventListener.java similarity index 96% rename from pdex/src/processing/mode/java2/VMEventListener.java rename to pdex/src/processing/mode/experimental/VMEventListener.java index 1e9d33042..4cc648802 100755 --- a/pdex/src/processing/mode/java2/VMEventListener.java +++ b/pdex/src/processing/mode/experimental/VMEventListener.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.event.EventSet; diff --git a/pdex/src/processing/mode/java2/VMEventReader.java b/pdex/src/processing/mode/experimental/VMEventReader.java similarity index 98% rename from pdex/src/processing/mode/java2/VMEventReader.java rename to pdex/src/processing/mode/experimental/VMEventReader.java index ad9178bb6..c4d05ddf9 100755 --- a/pdex/src/processing/mode/java2/VMEventReader.java +++ b/pdex/src/processing/mode/experimental/VMEventReader.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.event.EventQueue; diff --git a/pdex/src/processing/mode/java2/VariableInspector.form b/pdex/src/processing/mode/experimental/VariableInspector.form similarity index 100% rename from pdex/src/processing/mode/java2/VariableInspector.form rename to pdex/src/processing/mode/experimental/VariableInspector.form diff --git a/pdex/src/processing/mode/java2/VariableInspector.java b/pdex/src/processing/mode/experimental/VariableInspector.java similarity index 99% rename from pdex/src/processing/mode/java2/VariableInspector.java rename to pdex/src/processing/mode/experimental/VariableInspector.java index 220d90bbc..1d3858abb 100755 --- a/pdex/src/processing/mode/java2/VariableInspector.java +++ b/pdex/src/processing/mode/experimental/VariableInspector.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.Value; import java.awt.Color; diff --git a/pdex/src/processing/mode/java2/VariableNode.java b/pdex/src/processing/mode/experimental/VariableNode.java similarity index 99% rename from pdex/src/processing/mode/java2/VariableNode.java rename to pdex/src/processing/mode/experimental/VariableNode.java index ce4813061..66b0575d7 100755 --- a/pdex/src/processing/mode/java2/VariableNode.java +++ b/pdex/src/processing/mode/experimental/VariableNode.java @@ -15,7 +15,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ -package processing.mode.java2; +package processing.mode.experimental; import com.sun.jdi.ArrayReference; import com.sun.jdi.ObjectReference; diff --git a/pdex/src/processing/mode/java2/XQConsoleToggle.java b/pdex/src/processing/mode/experimental/XQConsoleToggle.java similarity index 98% rename from pdex/src/processing/mode/java2/XQConsoleToggle.java rename to pdex/src/processing/mode/experimental/XQConsoleToggle.java index 9042b78ae..7d4ea9032 100755 --- a/pdex/src/processing/mode/java2/XQConsoleToggle.java +++ b/pdex/src/processing/mode/experimental/XQConsoleToggle.java @@ -1,4 +1,4 @@ -package processing.mode.java2; +package processing.mode.experimental; /* Part of the XQMode project - https://github.com/Manindra29/XQMode diff --git a/pdex/src/processing/mode/java2/XQErrorTable.java b/pdex/src/processing/mode/experimental/XQErrorTable.java similarity index 99% rename from pdex/src/processing/mode/java2/XQErrorTable.java rename to pdex/src/processing/mode/experimental/XQErrorTable.java index db3bb71da..9bf36afc0 100755 --- a/pdex/src/processing/mode/java2/XQErrorTable.java +++ b/pdex/src/processing/mode/experimental/XQErrorTable.java @@ -1,4 +1,4 @@ -package processing.mode.java2; +package processing.mode.experimental; /* Part of the XQMode project - https://github.com/Manindra29/XQMode diff --git a/pdex/src/processing/mode/java2/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java similarity index 99% rename from pdex/src/processing/mode/java2/XQPreprocessor.java rename to pdex/src/processing/mode/experimental/XQPreprocessor.java index 3b1f6d246..9cf3e8c2f 100755 --- a/pdex/src/processing/mode/java2/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -20,7 +20,7 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package processing.mode.java2; +package processing.mode.experimental; import java.util.ArrayList; import java.util.List; From 3724b9d1601321b226b107a31eb8b0db7e8b2c1e Mon Sep 17 00:00:00 2001 From: benfry Date: Thu, 6 Dec 2012 23:04:44 +0000 Subject: [PATCH 003/608] experimental now building from ant as its own unit --- .../mode/experimental/DebugBuild.java | 4 +- .../mode/experimental/DebugEditor.java | 8 +-- .../mode/experimental/ErrorBar.java | 2 +- .../{DebugMode.java => ExperimentalMode.java} | 58 ++++++++++--------- .../mode/experimental/TextArea.java | 4 +- .../mode/experimental/TextAreaPainter.java | 4 +- .../mode/experimental/VariableInspector.java | 2 +- pdex/theme/theme.txt | 28 +++++---- 8 files changed, 60 insertions(+), 50 deletions(-) rename pdex/src/processing/mode/experimental/{DebugMode.java => ExperimentalMode.java} (71%) diff --git a/pdex/src/processing/mode/experimental/DebugBuild.java b/pdex/src/processing/mode/experimental/DebugBuild.java index a77dc1972..fdb9b34e3 100755 --- a/pdex/src/processing/mode/experimental/DebugBuild.java +++ b/pdex/src/processing/mode/experimental/DebugBuild.java @@ -67,7 +67,7 @@ public class DebugBuild extends JavaBuild { return null; } - public DebugMode getMode() { - return (DebugMode)mode; + public ExperimentalMode getMode() { + return (ExperimentalMode)mode; } } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index c8be53c97..1ed649ceb 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -94,7 +94,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // variable inspector protected JMenuItem toggleVariableInspectorMenuItem; // references - protected DebugMode dmode; // the mode + protected ExperimentalMode dmode; // the mode protected Debugger dbg; // the debugger protected VariableInspector vi; // the variable inspector frame protected TextArea ta; // the text area @@ -133,7 +133,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { super(base, path, state, mode); // get mode - dmode = (DebugMode) mode; + dmode = (ExperimentalMode) mode; // init controller class dbg = new Debugger(this); @@ -153,7 +153,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // }); // load settings from theme.txt - DebugMode theme = dmode; + ExperimentalMode theme = dmode; breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor); breakpointMarkerColor = theme.getThemeColor("breakpoint.marker.color", breakpointMarkerColor); currentLineColor = theme.getThemeColor("currentline.bgcolor", currentLineColor); @@ -835,7 +835,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { * * @return the mode object */ - public DebugMode mode() { + public ExperimentalMode mode() { return dmode; } diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index 6a2d43f20..4934ebc70 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -118,7 +118,7 @@ public class ErrorBar extends JPanel { return getPreferredSize(); } - public ErrorBar(DebugEditor editor, int height, DebugMode mode) { + public ErrorBar(DebugEditor editor, int height, ExperimentalMode mode) { this.editor = editor; this.preferredHeight = height; this.errorCheckerService = editor.errorCheckerService; diff --git a/pdex/src/processing/mode/experimental/DebugMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java similarity index 71% rename from pdex/src/processing/mode/experimental/DebugMode.java rename to pdex/src/processing/mode/experimental/ExperimentalMode.java index ba7cd5a0a..56645fc7d 100755 --- a/pdex/src/processing/mode/experimental/DebugMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -1,20 +1,24 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + /* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ + Part of the Processing project - http://processing.org + + Copyright (c) 2012 The Processing Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + package processing.mode.experimental; import java.awt.Color; @@ -29,18 +33,18 @@ import processing.app.EditorState; import processing.app.Mode; import processing.mode.java.JavaMode; + /** - * Debug Mode for Processing. Built on top of JavaMode. - * - * @author Martin Leopold + * Experimental Mode for Processing, combines Debug Mode and XQMode and + * starts us working toward our next generation editor/debugger setup. */ -public class DebugMode extends JavaMode { +public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public DebugMode(Base base, File folder) { + public ExperimentalMode(Base base, File folder) { super(base, folder); // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus @@ -80,16 +84,16 @@ public class DebugMode extends JavaMode { globalLogger.addHandler(handler); } catch (IOException ex) { - Logger.getLogger(DebugMode.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); } catch (SecurityException ex) { - Logger.getLogger(DebugMode.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); } // output version from manifest file - Package p = DebugMode.class.getPackage(); + Package p = ExperimentalMode.class.getPackage(); String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; //System.out.println(titleAndVersion); - Logger.getLogger(DebugMode.class.getName()).log(Level.INFO, titleAndVersion); + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); } @@ -128,7 +132,7 @@ public class DebugMode extends JavaMode { if (newString != null) { return newString; } - Logger.getLogger(DebugMode.class.getName()).log(Level.WARNING, "Error loading String: {0}", attribute); + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading String: {0}", attribute); return defaultValue; } @@ -147,7 +151,7 @@ public class DebugMode extends JavaMode { return newColor; } System.out.println("error loading color: " + attribute); - Logger.getLogger(DebugMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); return defaultValue; } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 7dd0d430e..08a6b88e4 100755 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -84,7 +84,7 @@ public class TextArea extends JEditTextArea { add(CENTER, painter); // load settings from theme.txt - DebugMode theme = (DebugMode) editor.getMode(); + ExperimentalMode theme = (ExperimentalMode) editor.getMode(); gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); gutterPadding = theme.getInteger("gutter.padding"); @@ -92,7 +92,7 @@ public class TextArea extends JEditTextArea { currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker); } - public void setECSandThemeforTextArea(ErrorCheckerService ecs, DebugMode mode) + public void setECSandThemeforTextArea(ErrorCheckerService ecs, ExperimentalMode mode) { customPainter.setECSandTheme(ecs, mode); } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 36706a5f0..c2c0ae48b 100755 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -64,7 +64,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { ta = textArea; } - private void loadTheme(DebugMode mode){ + private void loadTheme(ExperimentalMode mode){ errorColor = mode.getThemeColor("editor.errorcolor", errorColor); warningColor = mode.getThemeColor("editor.warningcolor", warningColor); @@ -306,7 +306,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { return newString; } - public void setECSandTheme(ErrorCheckerService ecs, DebugMode mode){ + public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode){ this.errorCheckerService = ecs; loadTheme(mode); } diff --git a/pdex/src/processing/mode/experimental/VariableInspector.java b/pdex/src/processing/mode/experimental/VariableInspector.java index 1d3858abb..a38c19a8f 100755 --- a/pdex/src/processing/mode/experimental/VariableInspector.java +++ b/pdex/src/processing/mode/experimental/VariableInspector.java @@ -260,7 +260,7 @@ public class VariableInspector extends javax.swing.JFrame { * null if the file wasn't found. */ protected ImageIcon[][] loadIcons(String fileName) { - DebugMode mode = editor.mode(); + ExperimentalMode mode = editor.mode(); File file = mode.getContentFile(fileName); if (!file.exists()) { Logger.getLogger(OutlineRenderer.class.getName()).log(Level.SEVERE, "icon file not found: {0}", file.getAbsolutePath()); diff --git a/pdex/theme/theme.txt b/pdex/theme/theme.txt index a5d65ec7c..5f9afe1bc 100755 --- a/pdex/theme/theme.txt +++ b/pdex/theme/theme.txt @@ -74,26 +74,32 @@ editor.brackethighlight.color = #006699 # TEXT - KEYWORDS -# e.g abstract, final, private -editor.keyword1.style = #cc6600,plain +# e.g. Functions +editor.function1.style = #006699,plain -# e.g. beginShape, point, line -editor.keyword2.style = #cc6600,plain +# e.g. Methods (functions inside a class) +editor.function2.style = #006699,plain -# e.g. byte, char, short, color -editor.keyword3.style = #cc6600,bold +# e.g. Datatypes and keywords (void, int, boolean, etc.) +editor.keyword1.style = #D86736,plain + +# e.g. Processing fields [variables within a class] +editor.keyword2.style = #EE3C96,plain + +# e.g. Processing variables (width, height, focused, etc.) +editor.keyword3.style = #EE3C96,plain # TEXT - LITERALS -# constants: e.g. null, true, this, RGB, TWO_PI -editor.literal1.style = #006699,plain +# e.g. Strings (text in quotes) +editor.literal1.style = #7D4793,plain -# p5 built in variables: e.g. mouseX, width, pixels -editor.literal2.style = #006699,plain +# e.g. Constants (QUARTER_PI, CORNERS, etc.) +editor.literal2.style = #669933,plain # e.g. + - = / -editor.operator.style = #000000,plain +editor.operator.style = #006699,plain # ?? maybe this is for words followed by a colon # like in case statements or goto From dc3033bb5c401e907f237c6e15292e2f25512c84 Mon Sep 17 00:00:00 2001 From: benfry Date: Fri, 7 Dec 2012 20:20:44 +0000 Subject: [PATCH 004/608] experimental mode updates from Manindra --- .../mode/experimental/DebugEditor.java | 118 +++----------- .../mode/experimental/ErrorBar.java | 148 ++++++++++-------- .../experimental/ErrorCheckerService.java | 34 ++-- .../mode/experimental/ImportStatement.java | 44 +++--- .../processing/mode/experimental/Problem.java | 30 ++-- .../mode/experimental/TextArea.java | 5 + .../mode/experimental/TextAreaPainter.java | 7 +- .../mode/experimental/XQErrorTable.java | 9 +- .../mode/experimental/XQPreprocessor.java | 37 +++-- 9 files changed, 196 insertions(+), 236 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 1ed649ceb..b1bedbe09 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -129,6 +129,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected boolean compilationCheckEnabled = true; + /** + * Show warnings menu item + */ + protected JCheckBoxMenuItem showWarnings; + + /** + * Check box menu item for show/hide Problem Window + */ + public JCheckBoxMenuItem problemWindowMenuCB; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -383,8 +393,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - if (errorCheckerService.errorWindow == null) + if (errorCheckerService.errorWindow == null) { return; + } errorCheckerService.errorWindow .setVisible(((JCheckBoxMenuItem) e.getSource()) .isSelected()); @@ -410,102 +421,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { return debugMenu; } - /** - * Show warnings menu item - */ - protected JCheckBoxMenuItem showWarnings; - - /** - * Check box menu item for show/hide Problem Window - */ - public JCheckBoxMenuItem problemWindowMenuCB; - - - public JMenu buildXQModeMenu() { - - // Enable Error Checker - CB - // Show/Hide Problem Window - CB - // Show Warnings - CB - JMenu menu = new JMenu("XQMode"); - JCheckBoxMenuItem item; - final DebugEditor thisEditor = this; - item = new JCheckBoxMenuItem("Error Checker Enabled"); - item.setSelected(true); - item.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { - // unticked Menu Item - errorCheckerService.pauseThread(); - System.out.println(thisEditor.getSketch().getName() - + " - Error Checker paused."); - errorBar.errorPoints.clear(); - errorCheckerService.problemsList.clear(); - errorCheckerService.updateErrorTable(); - errorCheckerService.updateEditorStatus(); - getTextArea().repaint(); - } else { - errorCheckerService.resumeThread(); - System.out.println(thisEditor.getSketch().getName() - + " - Error Checker resumed."); - } - } - }); - menu.add(item); - - problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); - // problemWindowMenuCB.setSelected(true); - problemWindowMenuCB.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (errorCheckerService.errorWindow == null) - return; - errorCheckerService.errorWindow - .setVisible(((JCheckBoxMenuItem) e.getSource()) - .isSelected()); - // switch to console, now that Error Window is open - toggleView(XQConsoleToggle.text[0]); - } - }); - menu.add(problemWindowMenuCB); - - showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); - showWarnings.setSelected(true); - showWarnings.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e - .getSource()).isSelected(); - } - }); - menu.add(showWarnings); - - menu.addSeparator(); - - JMenuItem item2 = new JMenuItem("XQMode Wiki"); - item2.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Base.openURL("https://github.com/Manindra29/XQMode/wiki"); - } - }); - menu.add(item2); - - item2 = new JMenuItem("XQMode on Github"); - item2.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Base.openURL("https://github.com/Manindra29/XQMode"); - } - }); - menu.add(item2); - return menu; - } - @Override public JMenu buildModeMenu() { return buildDebugMenu(); @@ -1176,6 +1091,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { } + /** + * Updates the error bar + * @param problems + */ public void updateErrorBar(ArrayList problems) { errorBar.updateErrorPoints(problems); } @@ -1191,6 +1110,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { cl.show(consoleProblemsPane, buttonName); } + /** + * Updates the error table + * @param tableModel + * @return + */ synchronized public boolean updateTable(final TableModel tableModel) { return errorTable.updateTable(tableModel); } diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index 4934ebc70..b66c34543 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -1,11 +1,11 @@ /* Part of the XQMode project - https://github.com/Manindra29/XQMode - + Under Google Summer of Code 2012 - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - + Copyright (C) 2012 Manindra Moharana - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. @@ -81,8 +81,14 @@ public class ErrorBar extends JPanel { */ public Color backgroundColor = new Color(0x2C343D); + /** + * DebugEditor instance + */ protected DebugEditor editor; + /** + * ErrorCheckerService instance + */ protected ErrorCheckerService errorCheckerService; /** @@ -90,6 +96,9 @@ public class ErrorBar extends JPanel { */ protected ArrayList errorPoints = new ArrayList(); + /** + * Stores previous list of error markers. + */ protected ArrayList errorPointsOld = new ArrayList(); public void paintComponent(Graphics g) { @@ -102,8 +111,7 @@ public class ErrorBar extends JPanel { for (ErrorMarker emarker : errorPoints) { if (emarker.type == ErrorMarker.Error) { g.setColor(errorColor); - } - else { + } else { g.setColor(warningColor); } g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight); @@ -123,8 +131,8 @@ public class ErrorBar extends JPanel { this.preferredHeight = height; this.errorCheckerService = editor.errorCheckerService; errorColor = mode.getThemeColor("errorbar.errorcolor", errorColor); - warningColor = mode.getThemeColor("errorbar.warningcolor", - warningColor); + warningColor = mode + .getThemeColor("errorbar.warningcolor", warningColor); backgroundColor = mode.getThemeColor("errorbar.backgroundcolor", backgroundColor); addListeners(); @@ -140,69 +148,73 @@ public class ErrorBar extends JPanel { // NOTE TO SELF: ErrorMarkers are calculated for the present tab only // Error Marker index in the arraylist is LOCALIZED for current tab. - - final int fheight = this.getHeight(); - SwingWorker worker = new SwingWorker() { - - protected Object doInBackground() throws Exception { - return null; - } + // Also, need to do the update in the UI thread to prevent concurrency issues. + final int fheight = this.getHeight(); + SwingWorker worker = new SwingWorker() { - protected void done() { - int bigCount = 0; - int totalLines = 0; - int currentTab = 0; - for (SketchCode sc : editor.getSketch().getCode()) { - if (sc.isExtension("pde")) { - sc.setPreprocOffset(bigCount); + protected Object doInBackground() throws Exception { + return null; + } - try { - if (editor.getSketch().getCurrentCode().equals(sc)) { - // Adding + 1 to len because \n gets appended for each - // sketchcode extracted during processPDECode() - totalLines = Base.countLines(sc.getDocument().getText( - 0, sc.getDocument().getLength())) + 1; - break; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - currentTab++; - } - // System.out.println("Total lines: " + totalLines); + protected void done() { + int bigCount = 0; + int totalLines = 0; + int currentTab = 0; + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + sc.setPreprocOffset(bigCount); - errorPointsOld.clear(); - for (ErrorMarker marker : errorPoints) { - errorPointsOld.add(marker); - } - errorPoints.clear(); + try { + if (editor.getSketch().getCurrentCode().equals(sc)) { + // Adding + 1 to len because \n gets appended + // for each + // sketchcode extracted during processPDECode() + totalLines = Base.countLines(sc.getDocument() + .getText(0, + sc.getDocument().getLength())) + 1; + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + currentTab++; + } + // System.out.println("Total lines: " + totalLines); - // Each problem.getSourceLine() will have an extra line added because of - // class declaration in the beginning - for (Problem problem : problems) { - if (problem.tabIndex == currentTab) { - // Ratio of error line to total lines - float y = problem.lineNumber / ((float) totalLines); - // Ratio multiplied by height of the error bar - y *= fheight - 15; // -15 is just a vertical offset - errorPoints.add(new ErrorMarker(problem, (int) y, problem - .isError() ? ErrorMarker.Error : ErrorMarker.Warning)); - // System.out.println("Y: " + y); - } - } + errorPointsOld.clear(); + for (ErrorMarker marker : errorPoints) { + errorPointsOld.add(marker); + } + errorPoints.clear(); - repaint(); - } - }; + // Each problem.getSourceLine() will have an extra line added + // because of + // class declaration in the beginning + for (Problem problem : problems) { + if (problem.tabIndex == currentTab) { + // Ratio of error line to total lines + float y = problem.lineNumber / ((float) totalLines); + // Ratio multiplied by height of the error bar + y *= fheight - 15; // -15 is just a vertical offset + errorPoints.add(new ErrorMarker(problem, (int) y, + problem.isError() ? ErrorMarker.Error + : ErrorMarker.Warning)); + // System.out.println("Y: " + y); + } + } - try { - worker.execute(); // I eat concurrency bugs for breakfast. - } catch (Exception exp) { - System.out.println("Errorbar update markers is slacking." - + exp.getMessage()); - // e.printStackTrace(); - } + repaint(); + } + }; + + try { + worker.execute(); // I eat concurrency bugs for breakfast. + } catch (Exception exp) { + System.out.println("Errorbar update markers is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } } /** @@ -270,10 +282,12 @@ public class ErrorBar extends JPanel { .size(); i++) { Problem p = errorCheckerService.problemsList .get(i); - if (p.tabIndex < currentTab) + if (p.tabIndex < currentTab) { totalErrorIndex++; - if (p.tabIndex == currentTab) + } + if (p.tabIndex == currentTab) { break; + } } errorCheckerService .scrollToErrorLine(totalErrorIndex); @@ -364,7 +378,7 @@ public class ErrorBar extends JPanel { @Override public void mouseDragged(MouseEvent arg0) { - + } }); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 850613095..97730a271 100755 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -52,7 +52,7 @@ public class ErrorCheckerService implements Runnable{ private boolean pauseThread = false; protected ErrorWindow errorWindow; -// protected ErrorBar errorBar; + /** * IProblem[] returned by parser stored in here */ @@ -256,15 +256,16 @@ public class ErrorCheckerService implements Runnable{ syntaxCheck(); // No syntax errors, proceed for compilation check, Stage 2. - if (problems.length == 0 && editor.compilationCheckEnabled) { //TODO: && editor.compilationCheckEnabled condition + if (problems.length == 0 && editor.compilationCheckEnabled) { sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); mainClassOffset = xqpreproc.mainClassOffset; // tiny, but // significant - if (staticMode) - mainClassOffset++; // Extra line for setup() decl. -// System.out.println(sourceCode); -// System.out.println("--------------------------"); + if (staticMode) { + mainClassOffset++; // Extra line for setup() decl. + } + // System.out.println(sourceCode); + // System.out.println("--------------------------"); compileCheck(); } @@ -303,7 +304,7 @@ public class ErrorCheckerService implements Runnable{ int a[] = calculateTabIndexAndLineNumber(problems[i]); Problem p = new Problem(problems[i], a[0], a[1]); problemsList.add(p); -// System.out.println(p.toString()); + // System.out.println(p.toString()); } } @@ -329,17 +330,18 @@ public class ErrorCheckerService implements Runnable{ File f = new File("modes" + File.separator - + "java2" + + "experimental" + File.separator + "mode"); FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return (file.getName().endsWith(".jar") && !file - .getName().startsWith("XQMode")); + .getName().startsWith("experimental")); } }; File[] jarFiles = f.listFiles(fileFilter); + // System.out.println( "Jar files found? " + (jarFiles != null)); for (File jarFile : jarFiles) { classpathJars.add(jarFile.toURI().toURL()); } @@ -444,8 +446,10 @@ public class ErrorCheckerService implements Runnable{ * */ private void prepareCompilerClasspath() { - if (!loadCompClass) + if (!loadCompClass) { return; + } + // System.out.println("1.."); classpathJars = new ArrayList(); String entry = ""; @@ -648,6 +652,7 @@ public class ErrorCheckerService implements Runnable{ * Repaints the textarea if required */ public void updateTextAreaPainter() { + // TODO: Make this fucntion of some use editor.getTextArea().repaint(); currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); @@ -658,9 +663,6 @@ public class ErrorCheckerService implements Runnable{ return; } -// TODO: if (errorBar.errorPointsChanged()) -// editor.getTextArea().repaint(); - } /** @@ -920,8 +922,10 @@ public class ErrorCheckerService implements Runnable{ * - index of error */ public void scrollToErrorLine(int errorIndex) { - if (editor == null) + if (editor == null) { return; + } + if (errorIndex < problemsList.size() && errorIndex >= 0) { Problem p = problemsList.get(errorIndex); try { @@ -1073,8 +1077,6 @@ public class ErrorCheckerService implements Runnable{ */ public void stopThread() { stopThread = true; -// System.out.println(editor.getSketch().getName() -// + " - Error Checker stopped."); } /** diff --git a/pdex/src/processing/mode/experimental/ImportStatement.java b/pdex/src/processing/mode/experimental/ImportStatement.java index 6e28490ef..26d2db7d1 100755 --- a/pdex/src/processing/mode/experimental/ImportStatement.java +++ b/pdex/src/processing/mode/experimental/ImportStatement.java @@ -29,23 +29,29 @@ package processing.mode.experimental; * */ public class ImportStatement { - /** - * Ex: processing.opengl.*, java.util.* - */ - String importName; - /** - * Which tab does it belong to? - */ - int tab; - - /** - * Line number(pde code) of the import - */ - int lineNumber; + /** + * Ex: processing.opengl.*, java.util.* + */ + String importName; + /** + * Which tab does it belong to? + */ + int tab; - public ImportStatement(String importName, int tab, int lineNumber) { - this.importName = importName; - this.tab = tab; - this.lineNumber = lineNumber; - } - } \ No newline at end of file + /** + * Line number(pde code) of the import + */ + int lineNumber; + + /** + * + * @param importName - Ex: processing.opengl.*, java.util.* + * @param tab - Which tab does it belong to? + * @param lineNumber - Line number(pde code) of the import + */ + public ImportStatement(String importName, int tab, int lineNumber) { + this.importName = importName; + this.tab = tab; + this.lineNumber = lineNumber; + } +} \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/Problem.java b/pdex/src/processing/mode/experimental/Problem.java index f7348b71c..6b5b95ff4 100755 --- a/pdex/src/processing/mode/experimental/Problem.java +++ b/pdex/src/processing/mode/experimental/Problem.java @@ -55,10 +55,19 @@ public class Problem { */ public String message; + /** + * The type of error - WARNING or ERROR. + */ public int type; public static final int ERROR = 1, WARNING = 2; + /** + * + * @param iProblem - The IProblem which is being wrapped + * @param tabIndex - The tab number to which the error belongs to + * @param lineNumber - Line number(pde code) of the error + */ public Problem(IProblem iProblem, int tabIndex, int lineNumber) { this.iProblem = iProblem; if(iProblem.isError()) { @@ -101,10 +110,10 @@ public class Problem { else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)"); } - static Pattern pattern; - static Matcher matcher; + private static Pattern pattern; + private static Matcher matcher; - static final String tokenRegExp = "\\b token\\b"; + private static final String tokenRegExp = "\\b token\\b"; public static String process(IProblem problem) { return process(problem.getMessage()); @@ -126,21 +135,12 @@ public class Problem { matcher = pattern.matcher(message); message = matcher.replaceAll(""); - // Split camel case words into separate words. - // "VaraibleDeclaration" becomes "Variable Declaration" - // But sadly "PApplet" become "P Applet" and so on. - - // StringTokenizer st = new StringTokenizer(message); - // String newMessage = ""; - // while (st.hasMoreTokens()) { - // String word = st.nextToken(); - // newMessage += splitCamelCaseWord(word) + " "; - // } - // message = new String(newMessage); - return message; } + // Split camel case words into separate words. + // "VaraibleDeclaration" becomes "Variable Declaration" + // But sadly "PApplet" become "P Applet" and so on. public static String splitCamelCaseWord(String word) { String newWord = ""; for (int i = 1; i < word.length(); i++) { diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 08a6b88e4..e8bb82991 100755 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -92,6 +92,11 @@ public class TextArea extends JEditTextArea { currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker); } + /** + * Sets ErrorCheckerService and loads theme for TextArea(XQMode) + * @param ecs + * @param mode + */ public void setECSandThemeforTextArea(ErrorCheckerService ecs, ExperimentalMode mode) { customPainter.setECSandTheme(ecs, mode); diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index c2c0ae48b..8c93978f2 100755 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -193,7 +193,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { * 0-based line number: NOTE * @param x */ - private void paintErrorLine(Graphics gfx, int line, int x) { + protected void paintErrorLine(Graphics gfx, int line, int x) { if (errorCheckerService == null) { return; @@ -306,6 +306,11 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { return newString; } + /** + * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) + * @param ecs + * @param mode + */ public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode){ this.errorCheckerService = ecs; loadTheme(mode); diff --git a/pdex/src/processing/mode/experimental/XQErrorTable.java b/pdex/src/processing/mode/experimental/XQErrorTable.java index 9bf36afc0..e64cf2c4b 100755 --- a/pdex/src/processing/mode/experimental/XQErrorTable.java +++ b/pdex/src/processing/mode/experimental/XQErrorTable.java @@ -53,6 +53,9 @@ public class XQErrorTable extends JTable { */ private boolean columnResizing = false; + /** + * ErrorCheckerService instance + */ protected ErrorCheckerService errorCheckerService; @Override @@ -118,8 +121,9 @@ public class XQErrorTable extends JTable { synchronized public boolean updateTable(final TableModel tableModel) { // If problems list is not visible, no need to update - if (!this.isVisible()) + if (!this.isVisible()) { return false; + } SwingWorker worker = new SwingWorker() { @@ -148,8 +152,9 @@ public class XQErrorTable extends JTable { }; try { - if (!columnResizing) + if (!columnResizing) { worker.execute(); + } } catch (Exception e) { System.out.println("ErrorTable updateTable Worker's slacking." + e.getMessage()); diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index 9cf3e8c2f..7835c7c02 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -43,6 +43,7 @@ import org.eclipse.text.edits.TextEdit; import processing.app.Preferences; import processing.core.PApplet; +import processing.mode.java.preproc.PdePreprocessor; /** * My implementation of P5 preprocessor. Uses Eclipse JDT features instead of @@ -57,8 +58,16 @@ public class XQPreprocessor { private ASTRewrite rewrite = null; public int mainClassOffset = 0; - ArrayList imports; - ArrayList extraImports; + private ArrayList imports; + private ArrayList extraImports; + + private String[] coreImports, defaultImports; + + public XQPreprocessor() { + PdePreprocessor p = new PdePreprocessor(null); + defaultImports = p.getDefaultImports(); + coreImports = p.getCoreImports(); + } /** * The main method that performs preprocessing. Converts code into compilable java. @@ -104,8 +113,9 @@ public class XQPreprocessor { int position = doc.get().indexOf("{") + 1; int lines = 0; for (int i = 0; i < position; i++) { - if (doc.get().charAt(i) == '\n') + if (doc.get().charAt(i) == '\n') { lines++; + } } lines += 2; // System.out.println("Lines: " + lines); @@ -117,7 +127,7 @@ public class XQPreprocessor { /** * Returns all import statements as lines of code * - * @return String - All import statements combined + * @return String - All import statements combined. Each import in a separate line. */ public String prepareImports() { imports = new ArrayList(); @@ -125,11 +135,11 @@ public class XQPreprocessor { imports.add(new String(extraImports.get(i).importName)); } imports.add(new String("// Default Imports")); - for (int i = 0; i < getCoreImports().length; i++) { - imports.add(new String("import " + getCoreImports()[i] + ";")); + for (int i = 0; i < coreImports.length; i++) { + imports.add(new String("import " + coreImports[i] + ";")); } - for (int i = 0; i < getDefaultImports().length; i++) { - imports.add(new String("import " + getDefaultImports()[i] + ";")); + for (int i = 0; i < defaultImports.length; i++) { + imports.add(new String("import " + defaultImports[i] + ";")); } String totalImports = ""; for (int i = 0; i < imports.size(); i++) { @@ -139,17 +149,6 @@ public class XQPreprocessor { return totalImports; } - public String[] getCoreImports() { - return new String[] { "processing.core.*", "processing.data.*", - "processing.opengl.*" }; - } - - public String[] getDefaultImports() { - // These may change in-between (if the prefs panel adds this option) - String prefsLine = Preferences.get("preproc.imports.list"); - return PApplet.splitTokens(prefsLine, ", "); - } - /** * Visitor implementation that does all the substitution dirty work.
    *
  • Any function not specified as being protected or private will be made From c3e8641219562385c808e5aa7005e379ff7f090b Mon Sep 17 00:00:00 2001 From: benfry Date: Fri, 7 Dec 2012 20:26:32 +0000 Subject: [PATCH 005/608] adding colors for experimental mode --- pdex/theme/theme.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pdex/theme/theme.txt b/pdex/theme/theme.txt index 5f9afe1bc..c6c561e1d 100755 --- a/pdex/theme/theme.txt +++ b/pdex/theme/theme.txt @@ -136,4 +136,18 @@ gutter.bgcolor = #fcfcfc # color of vertical separation line gutter.linecolor = #e9e9e9 # space (in px) added to left and right of gutter markers -gutter.padding = 3 \ No newline at end of file +gutter.padding = 3 + + +# XQMODE + +# underline colors +editor.errorcolor = #ed2630 +editor.warningcolor = #ffc30e +editor.errormarkercolor = #ed2630 +editor.warningmarkercolor = #ffc30e + +# ERROR BAR - error bar on the right that shows the markers +errorbar.errorcolor = #ed2630 +errorbar.warningcolor = #ffc30e +errorbar.backgroundcolor = #2c343d From bb18fc230ca3b67e3a1ac7e14d203667d2ed27d8 Mon Sep 17 00:00:00 2001 From: benfry Date: Sat, 8 Dec 2012 19:35:26 +0000 Subject: [PATCH 006/608] fixes from Manindra (issue #1449) --- .../mode/experimental/DebugEditor.java | 1 + .../experimental/ErrorCheckerService.java | 24 +++++++++++-------- .../mode/experimental/ExperimentalMode.java | 18 +++++++------- .../mode/experimental/XQPreprocessor.java | 2 +- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index b1bedbe09..91bf862b9 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -378,6 +378,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { errorCheckerService.updateErrorTable(); errorCheckerService.updateEditorStatus(); getTextArea().repaint(); + errorBar.repaint(); } else { errorCheckerService.resumeThread(); System.out.println(thisEditor.getSketch().getName() diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 97730a271..85a8b84a5 100755 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -186,11 +186,11 @@ public class ErrorCheckerService implements Runnable{ try { parser = ASTParser.newParser(AST.JLS4); } catch (Exception e) { - System.err.println("XQMode initialization failed. " + System.err.println("Experimental Mode initialization failed. " + "Are you running the right version of Processing? "); pauseThread(); } catch (Error e) { - System.err.println("XQMode initialization failed. "); + System.err.println("Experimental Mode initialization failed. "); e.printStackTrace(); pauseThread(); } @@ -228,7 +228,8 @@ public class ErrorCheckerService implements Runnable{ public void run() { stopThread = false; - + + checkCode(); while (!stopThread) { try { // Take a nap. @@ -326,13 +327,16 @@ public class ErrorCheckerService implements Runnable{ // if (classpathJars.size() > 0) // System.out - // .println("XQMode: Loading contributed libraries referenced by import statements."); + // .println("Experimental Mode: Loading contributed libraries referenced by import statements."); - File f = new File("modes" - + File.separator - + "experimental" + File f = Base.getContentFile("modes" + File.separator + "experimental" + File.separator + "mode"); + if(!f.exists()) { + System.err.println("Could not locate the files required for on-the-fly error checking. Bummer."); + return; + } + FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return (file.getName().endsWith(".jar") && !file @@ -432,7 +436,7 @@ public class ErrorCheckerService implements Runnable{ } catch (NoClassDefFoundError e) { System.err .println(e - + " compileCheck() problem. Somebody tried to mess with XQMode files."); + + " compileCheck() problem. Somebody tried to mess with Experimental Mode files."); stopThread(); } // System.out.println("Compilecheck, Done."); @@ -496,7 +500,7 @@ public class ErrorCheckerService implements Runnable{ .contentsToClassPath(codeFolder); codeFolderChecked = true; if (codeFolderClassPath.equalsIgnoreCase("")) { - System.err.println("XQMODE: Yikes! Can't find \"" + System.err.println("Experimental Mode: Yikes! Can't find \"" + entry + "\" library! Line: " + impstat.lineNumber @@ -523,7 +527,7 @@ public class ErrorCheckerService implements Runnable{ + e2); } } else { - System.err.println("XQMODE: Yikes! Can't find \"" + System.err.println("Experimental Mode: Yikes! Can't find \"" + entry + "\" library! Line: " + impstat.lineNumber diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 56645fc7d..581258a79 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -47,15 +47,15 @@ public class ExperimentalMode extends JavaMode { public ExperimentalMode(Base base, File folder) { super(base, folder); - // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus -// for (Mode m : base.getModeList()) { -// if (m.getClass() == JavaMode.class) { -// JavaMode jMode = (JavaMode) m; -// librariesFolder = jMode.getLibrariesFolder(); -// rebuildLibraryList(); -// break; -// } -// } + // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus + for (Mode m : base.getModeList()) { + if (m.getClass() == JavaMode.class) { + JavaMode jMode = (JavaMode) m; + librariesFolder = jMode.getLibrariesFolder(); + rebuildLibraryList(); + break; + } + } // Fetch examples and reference from java mode // thx to Manindra (https://github.com/martinleopold/DebugMode/issues/4) diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index 7835c7c02..5388e04e5 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -233,7 +233,7 @@ public class XQPreprocessor { public boolean visit(SimpleType node) { if (node.toString().equals("color")) { System.err - .println("color type detected! \nThis shouldn't be happening! Please report this as an issue on www.github.com/Manindra29/XQMode"); + .println("color type detected! \nThis shouldn't be happening! Please report this as an issue."); } return true; From 115ca2104d9102904e76d488b342f6b66f86446d Mon Sep 17 00:00:00 2001 From: benfry Date: Mon, 10 Dec 2012 17:22:48 +0000 Subject: [PATCH 007/608] starting to move syntax coloring out of theme.txt and back into Preferences --- pdex/theme/theme.txt | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/pdex/theme/theme.txt b/pdex/theme/theme.txt index c6c561e1d..838d43666 100755 --- a/pdex/theme/theme.txt +++ b/pdex/theme/theme.txt @@ -72,45 +72,6 @@ editor.brackethighlight = true editor.brackethighlight.color = #006699 -# TEXT - KEYWORDS - -# e.g. Functions -editor.function1.style = #006699,plain - -# e.g. Methods (functions inside a class) -editor.function2.style = #006699,plain - -# e.g. Datatypes and keywords (void, int, boolean, etc.) -editor.keyword1.style = #D86736,plain - -# e.g. Processing fields [variables within a class] -editor.keyword2.style = #EE3C96,plain - -# e.g. Processing variables (width, height, focused, etc.) -editor.keyword3.style = #EE3C96,plain - - -# TEXT - LITERALS - -# e.g. Strings (text in quotes) -editor.literal1.style = #7D4793,plain - -# e.g. Constants (QUARTER_PI, CORNERS, etc.) -editor.literal2.style = #669933,plain - -# e.g. + - = / -editor.operator.style = #006699,plain - -# ?? maybe this is for words followed by a colon -# like in case statements or goto -editor.label.style = #7e7e7e,bold - - -# TEXT - COMMENTS -editor.comment1.style = #7e7e7e,plain -editor.comment2.style = #7e7e7e,plain - - # LINE STATUS - editor line number status bar at the bottom of the screen linestatus.font = SansSerif,plain,10 #linestatus.font.macosx = Helvetica,plain,10 From 069476bb494ab8e02a732a7121d119b9d7a9c131 Mon Sep 17 00:00:00 2001 From: benfry Date: Sat, 15 Dec 2012 23:07:06 +0000 Subject: [PATCH 008/608] remove warning, and initial startup noise --- .../mode/experimental/ExperimentalMode.java | 11 ++++++----- .../processing/mode/experimental/XQPreprocessor.java | 2 -- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 581258a79..6e2f85fd0 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -89,11 +89,12 @@ public class ExperimentalMode extends JavaMode { Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); } - // output version from manifest file - Package p = ExperimentalMode.class.getPackage(); - String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; - //System.out.println(titleAndVersion); - Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); + // disable initial chattiness for now +// // output version from manifest file +// Package p = ExperimentalMode.class.getPackage(); +// String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; +// //System.out.println(titleAndVersion); +// Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); } diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index 5388e04e5..cc263072f 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -41,8 +41,6 @@ import org.eclipse.jface.text.Document; import org.eclipse.text.edits.MalformedTreeException; import org.eclipse.text.edits.TextEdit; -import processing.app.Preferences; -import processing.core.PApplet; import processing.mode.java.preproc.PdePreprocessor; /** From 54403bd4de3854e08c5465a632dd39a850db165e Mon Sep 17 00:00:00 2001 From: benfry Date: Fri, 21 Dec 2012 16:55:31 +0000 Subject: [PATCH 009/608] This patch fixes a serious bug that was causing the Debugger to point to wrong (break point) line numbers. --- .../processing/mode/experimental/ErrorBar.java | 2 -- .../mode/experimental/ErrorCheckerService.java | 16 +--------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index b66c34543..ece0cb5d1 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -162,8 +162,6 @@ public class ErrorBar extends JPanel { int currentTab = 0; for (SketchCode sc : editor.getSketch().getCode()) { if (sc.isExtension("pde")) { - sc.setPreprocOffset(bigCount); - try { if (editor.getSketch().getCurrentCode().equals(sc)) { // Adding + 1 to len because \n gets appended diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 85a8b84a5..e07791ebc 100755 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -73,11 +73,6 @@ public class ErrorCheckerService implements Runnable{ */ protected URL[] classpath; - /** - * P5 Preproc offset - */ - private int scPreProcOffset = 0; - /** * Stores all Problems in the sketch */ @@ -656,7 +651,7 @@ public class ErrorCheckerService implements Runnable{ * Repaints the textarea if required */ public void updateTextAreaPainter() { - // TODO: Make this fucntion of some use + // TODO: Make this function of some use editor.getTextArea().repaint(); currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); @@ -705,7 +700,6 @@ public class ErrorCheckerService implements Runnable{ public int[] calculateTabIndexAndLineNumber(IProblem problem) { // String[] lines = {};// = PApplet.split(sourceString, '\n'); int codeIndex = 0; - int bigCount = 0; int x = problem.getSourceLineNumber() - mainClassOffset; if (x < 0) { @@ -730,7 +724,6 @@ public class ErrorCheckerService implements Runnable{ try { for (SketchCode sc : editor.getSketch().getCode()) { if (sc.isExtension("pde")) { - sc.setPreprocOffset(bigCount); int len = 0; if (editor.getSketch().getCurrentCode().equals(sc)) { len = Base.countLines(sc.getDocument().getText(0, @@ -769,7 +762,6 @@ public class ErrorCheckerService implements Runnable{ } } - bigCount += sc.getLineCount(); } } catch (Exception e) { System.err @@ -804,14 +796,10 @@ public class ErrorCheckerService implements Runnable{ for (SketchCode sc : editor.getSketch().getCode()) { if (sc.isExtension("pde")) { - sc.setPreprocOffset(scPreProcOffset); - try { if (editor.getSketch().getCurrentCode().equals(sc)) { - // rawCode.append(sc.getDocument().getText(0, - // sc.getDocument().getLength())); rawCode.append(scrapImportStatements(sc.getDocument() .getText(0, sc.getDocument() @@ -820,7 +808,6 @@ public class ErrorCheckerService implements Runnable{ .getCodeIndex(sc))); } else { - // rawCode.append(sc.getProgram()); rawCode.append(scrapImportStatements(sc.getProgram(), editor .getSketch().getCodeIndex(sc))); @@ -831,7 +818,6 @@ public class ErrorCheckerService implements Runnable{ + e.toString()); } rawCode.append('\n'); - scPreProcOffset += sc.getLineCount(); } } From b2729b4654e5a2563187828eeb7b8ddc468efcfa Mon Sep 17 00:00:00 2001 From: benfry Date: Sat, 22 Dec 2012 00:29:21 +0000 Subject: [PATCH 010/608] more fixes from Manindra (issue #1504) --- pdex/src/processing/mode/experimental/DebugToolbar.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdex/src/processing/mode/experimental/DebugToolbar.java b/pdex/src/processing/mode/experimental/DebugToolbar.java index 817627a51..e094176ad 100755 --- a/pdex/src/processing/mode/experimental/DebugToolbar.java +++ b/pdex/src/processing/mode/experimental/DebugToolbar.java @@ -159,6 +159,7 @@ public class DebugToolbar extends JavaToolbar { super.handlePressed(e, JavaToolbar.EXPORT); break; case DEBUG: + deditor.handleStop(); // Close any running sketches if (shift) { Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button"); deditor.handleRun(); From 41fb67d3bdb9c10a09896f97161c4dd0cb256f82 Mon Sep 17 00:00:00 2001 From: benfry Date: Thu, 10 Jan 2013 15:59:05 +0000 Subject: [PATCH 011/608] removing unused var --- pdex/src/processing/mode/experimental/ErrorBar.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index ece0cb5d1..b21aaac40 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -157,7 +157,6 @@ public class ErrorBar extends JPanel { } protected void done() { - int bigCount = 0; int totalLines = 0; int currentTab = 0; for (SketchCode sc : editor.getSketch().getCode()) { From d2171857974e7e387ed887d7a4b7a68587c07e74 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 27 Jan 2013 20:57:21 +0530 Subject: [PATCH 012/608] 3rd attempt. Error Check now happens only on text update. --- .../experimental/ErrorCheckerService.java | 23 +++++++++++++++++++ .../mode/experimental/TextArea.java | 12 +++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index e07791ebc..3cb40b69a 100755 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -10,6 +10,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -221,6 +222,11 @@ public class ErrorCheckerService implements Runnable{ }); } + /** + * checkCode() only on text area update + */ + protected AtomicInteger textModified = new AtomicInteger(0); + public void run() { stopThread = false; @@ -237,12 +243,18 @@ public class ErrorCheckerService implements Runnable{ if (pauseThread) continue; + if(textModified.get() == 0) + continue; + // Check every x seconds checkCode(); } } + + + private boolean checkCode() { lastTimeStamp = System.currentTimeMillis(); @@ -270,6 +282,17 @@ public class ErrorCheckerService implements Runnable{ editor.updateErrorBar(problemsList); updateEditorStatus(); updateTextAreaPainter(); + int x = textModified.get(); + //System.out.println("TM " + x); + if(x>=3){ + textModified.set(3); + x = 3; + } + + if(x>0) + textModified.set(x - 1); + else + textModified.set(0); return true; } catch (Exception e) { diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index e8bb82991..87722498a 100755 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -21,6 +21,7 @@ import java.awt.Color; import java.awt.Cursor; import java.awt.FontMetrics; import java.awt.event.ComponentListener; +import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; @@ -50,6 +51,7 @@ public class TextArea extends JEditTextArea { protected Map gutterText = new HashMap(); // maps line index to gutter text protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color protected TextAreaPainter customPainter; + protected ErrorCheckerService errorCheckerService; public TextArea(TextAreaDefaults defaults, DebugEditor editor) { super(defaults); @@ -99,7 +101,15 @@ public class TextArea extends JEditTextArea { */ public void setECSandThemeforTextArea(ErrorCheckerService ecs, ExperimentalMode mode) { - customPainter.setECSandTheme(ecs, mode); + errorCheckerService = ecs; + customPainter.setECSandTheme(ecs, mode); + } + + public void processKeyEvent(KeyEvent evt) { + super.processKeyEvent(evt); + if(evt.getID() == KeyEvent.KEY_TYPED){ + errorCheckerService.textModified.incrementAndGet(); + } } /** From e52a49301c3c9b94ca63847d42ef828ad56d756f Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 27 Jan 2013 10:52:36 -0500 Subject: [PATCH 013/608] adding ignore files --- pdex/.gitignore | 1 + pdex/mode/.gitignore | 1 + 2 files changed, 2 insertions(+) create mode 100644 pdex/.gitignore create mode 100644 pdex/mode/.gitignore diff --git a/pdex/.gitignore b/pdex/.gitignore new file mode 100644 index 000000000..ba077a403 --- /dev/null +++ b/pdex/.gitignore @@ -0,0 +1 @@ +bin diff --git a/pdex/mode/.gitignore b/pdex/mode/.gitignore new file mode 100644 index 000000000..9acf0e7e9 --- /dev/null +++ b/pdex/mode/.gitignore @@ -0,0 +1 @@ +experimental.jar From ac81b0a78434e3fa1a35de46777662db91e7efb0 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 1 Feb 2013 20:04:50 +0530 Subject: [PATCH 014/608] textarea painter bug fix. --- .../mode/experimental/ErrorCheckerService.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 3cb40b69a..d10796f52 100755 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -243,6 +243,8 @@ public class ErrorCheckerService implements Runnable{ if (pauseThread) continue; + updatePaintedThingy(); + if(textModified.get() == 0) continue; @@ -281,7 +283,7 @@ public class ErrorCheckerService implements Runnable{ updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); - updateTextAreaPainter(); + // updatePaintedThingy(); int x = textModified.get(); //System.out.println("TM " + x); if(x>=3){ @@ -673,15 +675,14 @@ public class ErrorCheckerService implements Runnable{ /** * Repaints the textarea if required */ - public void updateTextAreaPainter() { - // TODO: Make this function of some use + public void updatePaintedThingy() { editor.getTextArea().repaint(); currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); if (currentTab != lastTab) { lastTab = currentTab; - // editor.getTextArea().repaint(); - // System.out.println("1 Repaint " + System.currentTimeMillis()); + editor.updateErrorBar(problemsList); + updateEditorStatus(); return; } From 922077f36c059a49ed34ed94eeb930406a91ac5f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 1 Feb 2013 20:11:15 +0530 Subject: [PATCH 015/608] editor status repaint --- .../src/processing/mode/experimental/ErrorCheckerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index d10796f52..435d54903 100755 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -677,12 +677,12 @@ public class ErrorCheckerService implements Runnable{ */ public void updatePaintedThingy() { editor.getTextArea().repaint(); + updateEditorStatus(); currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); if (currentTab != lastTab) { lastTab = currentTab; - editor.updateErrorBar(problemsList); - updateEditorStatus(); + editor.updateErrorBar(problemsList); return; } From 9f0e4b72760d5d4576b87d88e5d2e78bb7739f79 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 5 Feb 2013 14:19:28 -0500 Subject: [PATCH 016/608] quick project name change, add ignore file for lwjgl --- pdex/.project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/.project b/pdex/.project index c754d21c8..1be6ebc0c 100644 --- a/pdex/.project +++ b/pdex/.project @@ -1,6 +1,6 @@ - processing-java2 + processing-experimental From cb3f60ed7fac583d03487802c851796452fe9d6d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 30 Mar 2013 02:23:46 +0530 Subject: [PATCH 017/608] adding experiment result --- pdex/.project | 10 + pdex/build.xml | 6 + .../mode/experimental/ASTGenerator.java | 1509 +++++++++++++++++ .../mode/experimental/DebugEditor.java | 4 +- .../mode/experimental/ErrorBar.java | 5 +- .../experimental/ErrorCheckerService.java | 117 +- .../processing/mode/experimental/Problem.java | 2 +- .../mode/experimental/TextArea.java | 706 +++++--- .../mode/experimental/TextAreaPainter.java | 685 +++++--- .../mode/experimental/XQPreprocessor.java | 9 +- 10 files changed, 2471 insertions(+), 582 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/ASTGenerator.java mode change 100755 => 100644 pdex/src/processing/mode/experimental/ErrorCheckerService.java mode change 100755 => 100644 pdex/src/processing/mode/experimental/Problem.java mode change 100755 => 100644 pdex/src/processing/mode/experimental/TextArea.java mode change 100755 => 100644 pdex/src/processing/mode/experimental/TextAreaPainter.java diff --git a/pdex/.project b/pdex/.project index 1be6ebc0c..dd2d29121 100644 --- a/pdex/.project +++ b/pdex/.project @@ -10,6 +10,16 @@ + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/processing-experimental build.xml [Builder] (1).launch + + + org.eclipse.jdt.core.javanature diff --git a/pdex/build.xml b/pdex/build.xml index 2e0f18baa..489c3f93d 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -56,4 +56,10 @@ + + + + + + diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java new file mode 100644 index 000000000..03841481e --- /dev/null +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -0,0 +1,1509 @@ +package processing.mode.experimental; + +import java.awt.Rectangle; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.table.DefaultTableModel; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.ArrayAccess; +import org.eclipse.jdt.core.dom.ArrayCreation; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.CastExpression; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.CharacterLiteral; +import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ConditionalExpression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.InstanceofExpression; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.LineComment; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.ParenthesizedExpression; +import org.eclipse.jdt.core.dom.PostfixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SwitchCase; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; + + +import processing.app.Base; +import processing.app.SketchCode; +import processing.app.syntax.InputHandler.clipboard_copy; + +public class ASTGenerator { + + protected ErrorCheckerService errorCheckerService; + + protected DebugEditor editor; + + public DefaultMutableTreeNode codeTree = new DefaultMutableTreeNode(); + + private DefaultMutableTreeNode currentParent = null; + + private JFrame frame2, frameAutoComp; + + private JTree jtree; + + private CompilationUnit compilationUnit; + + private JTable tableAuto; + + public ASTGenerator(ErrorCheckerService ecs) { + this.errorCheckerService = ecs; + this.editor = ecs.getEditor(); + frame2 = new JFrame(); + + jtree = new JTree(); + frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame2.setBounds(new Rectangle(100, 100, 460, 620)); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(jtree); + frame2.add(sp); + + frameAutoComp = new JFrame(); + frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); + tableAuto = new JTable(); + JScrollPane sp2 = new JScrollPane(); + sp2.setViewportView(tableAuto); + frameAutoComp.add(sp2); + + } + + public class ASTNodeWrapper { + private ASTNode node; + + private String label; + + private int lineNumber; + + private int apiLevel; + + public ASTNodeWrapper(ASTNode node) { + if (node == null) + return; + this.node = node; + label = getNodeAsString(node); + if (label == null) + label = node.toString(); + lineNumber = compilationUnit.getLineNumber(node.getStartPosition()); + label += " | Line " + lineNumber; + apiLevel = 0; + } + + public String toString() { + return label; + } + + public ASTNode getNode() { + return node; + } + + public String getLabel() { + return label; + } + + public int getNodeType() { + return node.getNodeType(); + } + + public int getLineNumber() { + return lineNumber; + } + } + + private DefaultMutableTreeNode buildAST2(String source) { + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + compilationUnit = (CompilationUnit) parser.createAST(null); +// OutlineVisitor visitor = new OutlineVisitor(); +// compilationUnit.accept(visitor); + codeTree = new DefaultMutableTreeNode( + getNodeAsString((ASTNode) compilationUnit + .types().get(0))); + visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (codeTree != null) { +// if (jtree.hasFocus() || frame2.hasFocus()) +// return; + jtree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) jtree.getModel()).reload(); + if (!frame2.isVisible()) + frame2.setVisible(true); + if (!frameAutoComp.isVisible()) + frameAutoComp.setVisible(true); + jtree.validate(); + } + } + }; + worker.execute(); + + return codeTree; + } + + public DefaultMutableTreeNode buildAST() { + return buildAST2(errorCheckerService.sourceCode); + } + + public String[] checkForTypes2(ASTNode node) { + + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return new String[] { ((TypeDeclaration) node).getName().toString() }; + + case ASTNode.METHOD_DECLARATION: + String[] ret1 = new String[] { ((MethodDeclaration) node).getName() + .toString() }; + return ret1; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return new String[] { ((SingleVariableDeclaration) node).getName() + .toString() }; + + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + String ret[] = new String[vdfs.size()]; + int i = 0; + for (VariableDeclarationFragment vdf : vdfs) { + ret[i++] = vdf.getName().toString(); + } + return ret; + } + + return null; + } + + public static String[] checkForTypes(ASTNode node) { + + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return new String[] { getNodeAsString(node) }; + + case ASTNode.METHOD_DECLARATION: + String[] ret1 = new String[] { getNodeAsString(node) }; + return ret1; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return new String[] { getNodeAsString(node) }; + + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + String ret[] = new String[vdfs.size()]; + int i = 0; + for (VariableDeclarationFragment vdf : vdfs) { + ret[i++] = getNodeAsString(vdf); + } + return ret; + } + + return null; + } + + @SuppressWarnings("unchecked") + public ArrayList getNameIfType(ASTNode astnode) { + + ArrayList names = new ArrayList(); + List sprops = astnode + .structuralPropertiesForType(); + for (StructuralPropertyDescriptor sprop : sprops) { + ASTNode cnode = null; + if (!sprop.isChildListProperty()) { + if (astnode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) astnode.getStructuralProperty(sprop); + //if(cnode) + } + } else { + // Childlist prop + List nodelist = (List) astnode + .getStructuralProperty(sprop); + for (ASTNode clnode : nodelist) { + + } + } + } + + return names; + } + + public static ASTNode resolveExpression(ASTNode nearestNode, + ASTNode expression) { +// ASTNode anode = null; + if (expression instanceof SimpleName) { + return findDeclaration2(((SimpleName) expression), nearestNode); + } else if (expression instanceof MethodInvocation) { + return findDeclaration2(((MethodInvocation) expression).getName(), + nearestNode); + } else if (expression instanceof FieldAccess) { + return findDeclaration2(((FieldAccess) expression).getName(), nearestNode); + } else if (expression instanceof QualifiedName) { + return findDeclaration2(((QualifiedName) expression).getName(), + nearestNode); + } + +// if (anode != null) { +// System.out.println("Expression: " + anode); +// anode = resolveExpression(nearestNode, anode); +// } +// String word = anode.toString(); +// // Here expression should be a SN type hopefully. +// System.out.println("Final Expression: " + word); +//// anode = expression.getParent(); +// +// anode = nearestNode.getParent(); +// ASTNode matchinNode = null; +// while (anode != null) { +// +// List sprops = anode +// .structuralPropertiesForType(); +// for (StructuralPropertyDescriptor sprop : sprops) { +// ASTNode cnode = null; +// if (!sprop.isChildListProperty()) { +// if (anode.getStructuralProperty(sprop) instanceof ASTNode) { +// cnode = (ASTNode) anode.getStructuralProperty(sprop); +// String[] types = checkForTypes(cnode); +// if (types != null) { +// for (int i = 0; i < types.length; i++) { +// if (types[i].startsWith(word)) +// { +// System.out.println("match: "+types[i]); +// } +// } +// } +// } +// } else { +// // Childlist prop +// List nodelist = (List) anode +// .getStructuralProperty(sprop); +// for (ASTNode clnode : nodelist) { +// String[] types = checkForTypes(clnode); +// if (types != null) { +// for (int i = 0; i < types.length; i++) { +// if (types[i].startsWith(word)) +// System.out.println("match: "+types[i]);; +// } +// } +// } +// } +// } +// anode = anode.getParent(); +// } + + return null; + } + + public static TypeDeclaration getDefiningNode(ASTNode node) { + ASTNode parent = node.getParent(); + while (!(parent instanceof TypeDeclaration)) { + parent = parent.getParent(); + if (parent instanceof CompilationUnit) + return null; + } + return (TypeDeclaration) parent; + } + + public void updatePredictions(final String word, final int line) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { +// ArrayList candidates = new ArrayList(); + + //ASTNodeWrapper[][] candi = new ASTNodeWrapper[80][1]; + int lineNumber = line; + // Adjust line number for tabbed sketches + if (errorCheckerService != null) { + editor = errorCheckerService.getEditor(); + int codeIndex = editor.getSketch().getCodeIndex(editor + .getCurrentTab()); + if (codeIndex > 0) + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + + } + + ASTNode anode = null; + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setKind(ASTParser.K_EXPRESSION); + parser.setSource(word.toCharArray()); + ASTNode testnode = parser.createAST(null); + System.out.print("Typed: " + word + "|"); + anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + .get(0)); + System.out.println(lineNumber + " Nearest ASTNode to PRED " + + getNodeAsString(anode)); + + ArrayList candidates = new ArrayList(); + + if (testnode instanceof SimpleName) { + anode = anode.getParent(); + while (anode != null) { + + List sprops = anode + .structuralPropertiesForType(); + for (StructuralPropertyDescriptor sprop : sprops) { + ASTNode cnode = null; + if (!sprop.isChildListProperty()) { + if (anode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) anode.getStructuralProperty(sprop); + String[] types = checkForTypes(cnode); + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (types[i].startsWith(word)) + candidates.add(types[i]); + } + } + } + } else { + // Childlist prop + List nodelist = (List) anode + .getStructuralProperty(sprop); + for (ASTNode clnode : nodelist) { + String[] types = checkForTypes(clnode); + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (types[i].startsWith(word)) + candidates.add(types[i]); + } + } + } + } + } + anode = anode.getParent(); + } + } else { + + // Complicated completion + System.out.println("Not a SN " + getNodeAsString(testnode)); + ASTNode det = resolveExpression(anode, testnode); + if (det != null) { + TypeDeclaration td = null; + if (det instanceof MethodDeclaration) { + if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { + SimpleType stp = (SimpleType) (((MethodDeclaration) det) + .getReturnType2()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + } else if (det instanceof FieldDeclaration) { + if (((FieldDeclaration) det).getType() instanceof SimpleType) { + SimpleType stp = (SimpleType) (((FieldDeclaration) det) + .getType()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + } + + System.out.println(getNodeAsString(det) + " defined in " + + getNodeAsString(td)); + if (td != null) { + for (int i = 0; i < td.getFields().length; i++) { + candidates.add(getNodeAsString(td.getFields()[i])); + } + for (int i = 0; i < td.getMethods().length; i++) { + candidates.add(getNodeAsString(td.getMethods()[i])); + } + } + + } + + } + + String[][] candi = new String[candidates.size()][1]; + for (int i = 0; i < candi.length; i++) { + candi[i][0] = candidates.get(i); + } + System.out.println("K = " + candidates.size()); + DefaultTableModel tm = new DefaultTableModel( + candi, + new String[] { "Suggestions" }); + tableAuto.setModel(tm); + tableAuto.validate(); + tableAuto.repaint(); + } + }; + + worker.execute(); + + } + + @SuppressWarnings("unchecked") + private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + System.out.println("Looking at " + getNodeAsString(cnode)); + int cLineNum = ((CompilationUnit) cnode.getRoot()) + .getLineNumber(cnode.getStartPosition() + cnode.getLength()); + if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { + return findClosestParentNode(lineNumber, cnode); + } + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + int cLineNum = ((CompilationUnit) cnode.getRoot()) + .getLineNumber(cnode.getStartPosition() + cnode.getLength()); + System.out.println("Looking at " + getNodeAsString(cnode)); + if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { + return findClosestParentNode(lineNumber, cnode); + } + } + } + } + return node; + } + + @SuppressWarnings("unchecked") + private static ASTNode findClosestNode(int lineNumber, ASTNode node) { + ASTNode parent = findClosestParentNode(lineNumber, node); + if (parent == null) + return null; + if (getLineNumber(parent) == lineNumber) + return parent; + List nodes = null; + if (parent instanceof TypeDeclaration) { + nodes = (List) ((TypeDeclaration) parent) + .getStructuralProperty(TypeDeclaration.BODY_DECLARATIONS_PROPERTY); + } else if (parent instanceof Block) { + nodes = (List) ((Block) parent) + .getStructuralProperty(Block.STATEMENTS_PROPERTY); + } else { + System.err.println("THIS CONDITION SHOULD NOT OCCUR - findClosestNode " + + getNodeAsString(parent)); + return null; + } + + ASTNode retNode = nodes.get(0); + for (ASTNode cNode : nodes) { + if (getLineNumber(cNode) <= lineNumber) + retNode = cNode; + else + break; + } + + return retNode; + } + +// static DefaultMutableTreeNode findNodeBS(DefaultMutableTreeNode tree, +// int lineNumber, String name, +// int elementOffset) { +// if (tree.getUserObject() == null) +// return null; +// +// ASTNodeWrapper node = ((ASTNodeWrapper) tree.getUserObject()); +// +// if (node.getLineNumber() == lineNumber) { +// System.out.println("Located line " + lineNumber + " , " + tree); +// if (name == null) +// return tree; +// else +// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() +// .getStartPosition()); +// } +// +// int low = 0, high = tree.getChildCount() - 1, mid = (high + low) / 2; +// DefaultMutableTreeNode tnode = null; +// while (low <= high) { +// mid = (high + low) / 2; +// tnode = (DefaultMutableTreeNode) tree.getChildAt(mid); +// node = ((ASTNodeWrapper) tnode.getUserObject()); +// if (node.getLineNumber() == lineNumber) { +// System.out.println("Located line " + lineNumber + " , " + tnode); +// if (name == null) +// return tnode; +// else +// return findOnLine(tnode, lineNumber, name, elementOffset, node +// .getNode().getStartPosition()); +// } else if (lineNumber < node.getLineNumber()) { +// high = mid - 1; +// } else { +// if (high - mid <= 1) { +// if (lineNumber > ((ASTNodeWrapper) ((DefaultMutableTreeNode) tree +// .getChildAt(high)).getUserObject()).getLineNumber()) //high l no. +// low = mid + 1; +// else +// +// high = mid - 1; +// } +// low = mid + 1; +// } +// +// } +// +// if (!tnode.isLeaf()) +// return findNodeBS(tnode, lineNumber, name, elementOffset); +// else +// return tnode; +// +// //System.out.println("visiting: " + getNodeAsString(node.getNode()) + " on line "+node.getLineNumber()); +// if (node.getLineNumber() == lineNumber) { +// System.err.println("Located line: " + node.toString()); +// if (name == null) // name ==null, finds any node equal to line +// // number +// { +// System.out.println("Closest node at line: " + lineNumber); +// return tree; +// } else +// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() +// .getStartPosition()); +// +// } else if (!tree.isLeaf()) { +// for (int i = 0; i < tree.getChildCount(); i++) { +// .getChildAt(i), +// lineNumber, name, elementOffset); +// if (node2 != null) +// return node2; +// } +// } +// +// return null; +// } + + public DefaultMutableTreeNode getAST() { + return codeTree; + } + + public String getLabelForASTNode(int lineNumber, String name, int offset) { + retLabelString = ""; + getASTNodeAt(lineNumber, name, offset, false); + return retLabelString; + } + + public void scrollToDeclaration(int lineNumber, String name, int offset) { + getASTNodeAt(lineNumber, name, offset, true); + } + + String retLabelString; + + public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, + boolean scrollOnly) { + System.out.println("--------"); + if (errorCheckerService != null) { + editor = errorCheckerService.getEditor(); + int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); + if (codeIndex > 0) { + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + } + + } + System.out.println("FLON: " + lineNumber); + ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); + System.out.println("+> " + lineNode); + ASTNode decl = null; + if (lineNode != null) { + System.out.println("FLON2: " + lineNumber + " LN O " + + lineNode.getStartPosition()); + ASTNode simpName = pinpointOnLine(lineNode, offset, + lineNode.getStartPosition(), name); + System.out.println("+++> " + simpName); + if (simpName instanceof SimpleName) { + System.out.println(getNodeAsString(simpName)); + decl = findDeclaration((SimpleName) simpName); + if (decl != null) { + System.err.println("DECLA: " + decl.getClass().getName()); + retLabelString = getNodeAsString(decl); + } else + System.err.println("null"); + + System.out.println(getNodeAsString(decl)); + } + } + +// +// retStr = ""; + if (decl != null && scrollOnly) { + System.err.println("FINAL String label: " + getNodeAsString(decl)); + + DefaultProblem dpr = new DefaultProblem(null, null, -1, null, -1, + decl.getStartPosition(), + decl.getStartPosition(), + getLineNumber(decl) + 1, 0); + int[] position = errorCheckerService.calculateTabIndexAndLineNumber(dpr); + System.out.println("Tab " + position[0] + ", Line: " + (position[1])); + Problem p = new Problem(dpr, position[0], position[1]); + //errorCheckerService.scrollToErrorLine(p); + } // uncomment this one, it works + + return null; + } + + private static int getLineNumber(ASTNode node) { + return ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + } + + public static void main(String[] args) { + traversal2(); +// ASTParserd + } + + public static void traversal2() { + ASTParser parser = ASTParser.newParser(AST.JLS4); + String source = readFile("/media/quarkninja/Work/TestStuff/low.java"); +// String source = "package decl; \npublic class ABC{\n int ret(){\n}\n}"; + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + System.out.println(CompilationUnit.propertyDescriptors(AST.JLS4).size()); + + DefaultMutableTreeNode astTree = new DefaultMutableTreeNode( + "CompilationUnit"); + System.err.println("Errors: " + cu.getProblems().length); + visitRecur(cu, astTree); + System.out.println(astTree.getChildCount()); + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + JFrame frame2 = new JFrame(); + JTree jtree = new JTree(astTree); + frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame2.setBounds(new Rectangle(100, 100, 460, 620)); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(jtree); + frame2.add(sp); + frame2.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + + ASTNode found = NodeFinder.perform(cu, 468, 5); + if (found != null) { + System.out.println(found); + } + } + + @SuppressWarnings({ "unchecked" }) + public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + DefaultMutableTreeNode ctnode = null; + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + if (isAddableASTNode(cnode)) { + ctnode = new DefaultMutableTreeNode( + getNodeAsString((ASTNode) node + .getStructuralProperty(prop))); + tnode.add(ctnode); + visitRecur(cnode, ctnode); + } + } else { + tnode.add(new DefaultMutableTreeNode(node + .getStructuralProperty(prop))); + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (isAddableASTNode(cnode)) { + ctnode = new DefaultMutableTreeNode(getNodeAsString(cnode)); + tnode.add(ctnode); + visitRecur(cnode, ctnode); + } else + visitRecur(cnode, tnode); + } + } + } + } + + public static void printRecur(ASTNode node) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + System.out.println(getNodeAsString(cnode)); + printRecur(cnode); + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + System.out.println(getNodeAsString(cnode)); + printRecur(cnode); + } + } + } + } + + @SuppressWarnings("unchecked") + private static ASTNode findLineOfNode(ASTNode node, int lineNumber, + int offset, String name) { + + CompilationUnit root = (CompilationUnit) node.getRoot(); +// System.out.println("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); + if (root.getLineNumber(node.getStartPosition()) == lineNumber) { + System.err + .println(3 + getNodeAsString(node) + " len " + node.getLength()); + + if (offset < node.getLength()) + return node; + else { + System.err.println(-11); + return null; + } + } + for (Object oprop : node.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode retNode = findLineOfNode((ASTNode) node + .getStructuralProperty(prop), + lineNumber, offset, name); + if (retNode != null) { +// System.err.println(11 + getNodeAsString(retNode)); + return retNode; + } + } + } + } else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + + ASTNode rr = findLineOfNode(retNode, lineNumber, offset, name); + if (rr != null) { +// System.err.println(12 + getNodeAsString(rr)); + return rr; + } + } + } + } +// System.err.println("-1"); + return null; + } + + /** + * + * @param node + * @param offset + * - from textarea painter + * @param lineStartOffset + * - obtained from findLineOfNode + * @param name + * @param root + * @return + */ + @SuppressWarnings("unchecked") + public static ASTNode pinpointOnLine(ASTNode node, int offset, + int lineStartOffset, String name) { + + if (node instanceof SimpleName) { + SimpleName sn = (SimpleName) node; + if ((lineStartOffset + offset) >= sn.getStartPosition() + && (lineStartOffset + offset) <= sn.getStartPosition() + + sn.getLength()) { + if (sn.toString().equals(name)) + return sn; + else + return null; + } else + return null; + } + for (Object oprop : node.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode retNode = pinpointOnLine((ASTNode) node + .getStructuralProperty(prop), + offset, lineStartOffset, name); + if (retNode != null) { +// System.err.println(11 + getNodeAsString(retNode)); + return retNode; + } + } + } + } else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + + ASTNode rr = pinpointOnLine(retNode, offset, lineStartOffset, name); + if (rr != null) { +// System.err.println(12 + getNodeAsString(rr)); + return rr; + } + } + } + } +// System.err.println("-1"); + return null; + } + + @SuppressWarnings("unchecked") + private static ASTNode findDeclaration(Name findMe) { + ASTNode declaringClass = null; + ASTNode parent = findMe.getParent(); + ASTNode ret = null; + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration((stp.getName())); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration((stp.getName())); + constrains.add(ASTNode.TYPE_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); + declaringClass = findDeclaration(stp.getName()); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qn.getName().toString(), constrains, + null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { + constrains.add(ASTNode.TYPE_DECLARATION); + if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) + constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + } else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } + while (parent != null) { + System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); + for (Object oprop : parent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (parent.getStructuralProperty(prop) instanceof ASTNode) { + System.out.println(prop + " C/S Prop of -> " + + getNodeAsString(parent)); + ret = definedIn((ASTNode) parent.getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { + System.out.println((prop) + " ChildList props of " + + getNodeAsString(parent)); + List nodelist = (List) parent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + parent = parent.getParent(); + } + return null; + } + + private static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { + ASTNode declaringClass = null; + ASTNode parent = findMe.getParent(); + ASTNode ret = null; + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2((stp.getName()), alternateParent); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + alternateParent = alternateParent.getParent(); + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2((stp.getName()), alternateParent); + constrains.add(ASTNode.TYPE_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + alternateParent = alternateParent.getParent(); + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration2((qn.getQualifier()), + alternateParent)); + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qn.getName().toString(), constrains, + null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { + constrains.add(ASTNode.TYPE_DECLARATION); + if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) + constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + } else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } + System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); + while (alternateParent != null) { + System.out.println("findDeclaration2 -> " + + getNodeAsString(alternateParent)); + for (Object oprop : alternateParent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) { + System.out.println(prop + " C/S Prop of -> " + + getNodeAsString(alternateParent)); + ret = definedIn((ASTNode) alternateParent + .getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { + System.out.println((prop) + " ChildList props of " + + getNodeAsString(alternateParent)); + List nodelist = (List) alternateParent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + alternateParent = alternateParent.getParent(); + } + return null; + } + + /** + * Find the SimpleType from FD, SVD, VDS, etc + * + * @param node + * @return + */ + private static SimpleType extracTypeInfo(ASTNode node) { + if (node == null) + return null; + switch (node.getNodeType()) { + case ASTNode.METHOD_DECLARATION: + return (SimpleType) ((MethodDeclaration) node) + .getStructuralProperty(MethodDeclaration.RETURN_TYPE2_PROPERTY); + case ASTNode.FIELD_DECLARATION: + return (SimpleType) ((FieldDeclaration) node) + .getStructuralProperty(FieldDeclaration.TYPE_PROPERTY); + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + return (SimpleType) ((VariableDeclarationExpression) node) + .getStructuralProperty(VariableDeclarationExpression.TYPE_PROPERTY); + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + return (SimpleType) ((VariableDeclarationStatement) node) + .getStructuralProperty(VariableDeclarationStatement.TYPE_PROPERTY); + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return (SimpleType) ((SingleVariableDeclaration) node) + .getStructuralProperty(SingleVariableDeclaration.TYPE_PROPERTY); + } + return null; + } + + @SuppressWarnings("unchecked") + private static ASTNode definedIn(ASTNode node, String name, + ArrayList constrains, + ASTNode declaringClass) { + if (node == null) + return null; + if (constrains != null) { + System.out.println("Looking at " + getNodeAsString(node) + " for " + name + + " in definedIn"); + if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) { + System.err.print("definedIn -1 " + " But constrain was "); + for (Integer integer : constrains) { + System.out.print(ASTNode.nodeClassForType(integer) + ","); + } + System.out.println(); + return null; + } + } + + List vdfList = null; + switch (node.getNodeType()) { + + case ASTNode.TYPE_DECLARATION: + System.err.println(getNodeAsString(node)); + TypeDeclaration td = (TypeDeclaration) node; + if (td.getName().toString().equals(name)) { + if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) { + // look for constructor; + MethodDeclaration[] methods = td.getMethods(); + for (MethodDeclaration md : methods) { + if (md.getName().toString().equals(name)) { + return md; + } + } + } else { + // it's just the TD we're lookin for + return node; + } + } else { + if (constrains.contains(ASTNode.FIELD_DECLARATION)) { + // look for fields + FieldDeclaration[] fields = td.getFields(); + for (FieldDeclaration fd : fields) { + List fragments = fd.fragments(); + for (VariableDeclarationFragment vdf : fragments) { + if (vdf.getName().toString().equals(name)) + return fd; + } + } + } else if (constrains.contains(ASTNode.METHOD_DECLARATION)) { + // look for methods + MethodDeclaration[] methods = td.getMethods(); + for (MethodDeclaration md : methods) { + if (md.getName().toString().equals(name)) { + return md; + } + } + } + } + break; + case ASTNode.METHOD_DECLARATION: + System.err.println(getNodeAsString(node)); + if (((MethodDeclaration) node).getName().toString().equals(name)) + return node; + break; + case ASTNode.SINGLE_VARIABLE_DECLARATION: + System.err.println(getNodeAsString(node)); + if (((SingleVariableDeclaration) node).getName().toString().equals(name)) + return node; + break; + case ASTNode.FIELD_DECLARATION: + System.err.println("FD" + node); + vdfList = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + System.err.println("VDE" + node); + vdfList = ((VariableDeclarationExpression) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + System.err.println("VDS" + node); + vdfList = ((VariableDeclarationStatement) node).fragments(); + break; + + default: + + } + if (vdfList != null) { + for (VariableDeclarationFragment vdf : vdfList) { + if (vdf.getName().toString().equals(name)) + return node; + } + } + return null; + } + + public static boolean isAddableASTNode(ASTNode node) { + return true; + } + + static private String getNodeAsString(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString() + " | " + className; + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString() + " | " + + className; + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString() + " FldDecl| "; + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName() + " - " + + ((SingleVariableDeclaration) node).getType() + " | SVD "; + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (className.startsWith("Variable")) + value = node.toString() + " | " + className; + else if (className.endsWith("Type")) + value = node.toString() + " |" + className; + value += " [" + node.getStartPosition() + "," + + (node.getStartPosition() + node.getLength()) + "]"; + value += " Line: " + + ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + return value; + } + + public static String readFile(String path) { + BufferedReader reader = null; + try { + reader = new BufferedReader( + new InputStreamReader( + new FileInputStream( + new File( + path)))); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + try { + StringBuilder ret = new StringBuilder(); + // ret.append("package " + className + ";\n"); + String line; + while ((line = reader.readLine()) != null) { + ret.append(line); + ret.append("\n"); + } + return ret.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + +} diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 91bf862b9..b8f44a05b 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -179,7 +179,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { checkForJavaTabs(); initializeErrorChecker(); ta.setECSandThemeforTextArea(errorCheckerService, dmode); - addXQModeUI(); + addXQModeUI(); + //TODO: Remove this later + setBounds(160, 400, getWidth(), getHeight()); } private void addXQModeUI(){ diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index b21aaac40..24d552ae5 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -187,11 +187,12 @@ public class ErrorBar extends JPanel { // Each problem.getSourceLine() will have an extra line added // because of - // class declaration in the beginning + // class declaration in the beginning as well as default imports for (Problem problem : problems) { if (problem.tabIndex == currentTab) { // Ratio of error line to total lines - float y = problem.lineNumber / ((float) totalLines); + float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset) + / ((float) totalLines); // Ratio multiplied by height of the error bar y *= fheight - 15; // -15 is just a vertical offset errorPoints.add(new ErrorMarker(problem, (int) y, diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java old mode 100755 new mode 100644 index 435d54903..e0ce2a646 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -28,6 +28,7 @@ import processing.app.Base; import processing.app.Library; import processing.app.SketchCode; import processing.core.PApplet; +import processing.mode.java.preproc.PdePreprocessor; public class ErrorCheckerService implements Runnable{ @@ -87,6 +88,11 @@ public class ErrorCheckerService implements Runnable{ */ public int mainClassOffset; + /** + * Fixed p5 offsets for all sketches + */ + public int defaultImportsOffset; + /** * Is the sketch running in static mode or active mode? */ @@ -173,6 +179,9 @@ public class ErrorCheckerService implements Runnable{ initParser(); initializeErrorWindow(); xqpreproc = new XQPreprocessor(); + PdePreprocessor pdePrepoc = new PdePreprocessor(null); + defaultImportsOffset = pdePrepoc.getCoreImports().length + + pdePrepoc.getDefaultImports().length + 1; } /** @@ -222,11 +231,6 @@ public class ErrorCheckerService implements Runnable{ }); } - /** - * checkCode() only on text area update - */ - protected AtomicInteger textModified = new AtomicInteger(0); - public void run() { stopThread = false; @@ -239,62 +243,62 @@ public class ErrorCheckerService implements Runnable{ System.out.println("Oops! [ErrorCheckerThreaded]: " + e); // e.printStackTrace(); } - + + updatePaintedThingys(); + if (pauseThread) continue; - - updatePaintedThingy(); - if(textModified.get() == 0) continue; - // Check every x seconds checkCode(); } } - - - + ASTGenerator astGenerator = new ASTGenerator(this); + AtomicInteger textModified = new AtomicInteger(); private boolean checkCode() { - + System.out.println("checkCode() " + textModified.get() ); lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); syntaxCheck(); - + System.err.println(editor.getSketch().getName()+ " MCO " + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. + if (problems.length == 0 && editor.compilationCheckEnabled) { + astGenerator.buildAST(); sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); - mainClassOffset = xqpreproc.mainClassOffset; // tiny, but - // significant - if (staticMode) { - mainClassOffset++; // Extra line for setup() decl. - } +// mainClassOffset = xqpreproc.mainClassOffset; // tiny, but +// // significant +// if (staticMode) { +// mainClassOffset++; // Extra line for setup() decl. +// } // System.out.println(sourceCode); // System.out.println("--------------------------"); compileCheck(); + } updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); - // updatePaintedThingy(); + updatePaintedThingys(); int x = textModified.get(); //System.out.println("TM " + x); if(x>=3){ - textModified.set(3); - x = 3; + textModified.set(3); + x = 3; } if(x>0) - textModified.set(x - 1); + textModified.set(x - 1); else - textModified.set(0); + textModified.set(0); return true; } catch (Exception e) { @@ -675,14 +679,15 @@ public class ErrorCheckerService implements Runnable{ /** * Repaints the textarea if required */ - public void updatePaintedThingy() { + public void updatePaintedThingys() { editor.getTextArea().repaint(); updateEditorStatus(); currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); + //System.out.println("awesome! " + currentTab + " LT " + lastTab); if (currentTab != lastTab) { + textModified.incrementAndGet(); lastTab = currentTab; - editor.updateErrorBar(problemsList); return; } @@ -725,7 +730,7 @@ public class ErrorCheckerService implements Runnable{ // String[] lines = {};// = PApplet.split(sourceString, '\n'); int codeIndex = 0; - int x = problem.getSourceLineNumber() - mainClassOffset; + int x = problem.getSourceLineNumber() - mainClassOffset + 1; if (x < 0) { // System.out.println("Negative line number " // + problem.getSourceLineNumber() + " , offset " @@ -900,23 +905,31 @@ public class ErrorCheckerService implements Runnable{ className = (editor == null) ? "DefaultClass" : editor.getSketch() .getName(); + // Check whether the code is being written in STATIC mode(no function // declarations) - append class declaration and void setup() declaration Matcher matcher = FUNCTION_DECL.matcher(sourceAlt); if (!matcher.find()) { - sourceAlt = "public class " + className + " extends PApplet {\n" + sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" + "public void setup() {\n" + sourceAlt + "\nnoLoop();\n}\n" + "\n}\n"; - staticMode = true; - mainClassOffset = 2; + staticMode = true; } else { - sourceAlt = "public class " + className + " extends PApplet {\n" + sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" + sourceAlt + "\n}"; - staticMode = false; - mainClassOffset = 1; + staticMode = false; } - + + int position = sourceAlt.indexOf("{") + 1; + mainClassOffset = 1; + for (int i = 0; i <= position; i++) { + if (sourceAlt.charAt(i) == '\n') { + mainClassOffset++; + } + } + if(staticMode) mainClassOffset++; + //mainClassOffset += 2; // Handle unicode characters sourceAlt = substituteUnicode(sourceAlt); @@ -963,6 +976,36 @@ public class ErrorCheckerService implements Runnable{ } } + public void scrollToErrorLine(Problem p) { + if (editor == null) { + return; + } + if(p==null) + return; + try { + editor.toFront(); + editor.getSketch().setCurrentCode(p.tabIndex); + + editor.setSelection(editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) + + editor.getTextArea().getLineText(p.lineNumber - 1) + .trim().length(), editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); + editor.getTextArea().scrollTo(p.lineNumber - 1, 0); + editor.repaint(); + } catch (Exception e) { + System.err + .println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + } + // System.out.println("---"); + + + } + + + /** * Checks if import statements in the sketch have changed. If they have, * compiler classpath needs to be updated. @@ -1000,7 +1043,7 @@ public class ErrorCheckerService implements Runnable{ * @return String - Tab code with imports replaced with white spaces */ private String scrapImportStatements(String tabProgram, int tabNumber) { - + //TODO: Commented out imports are still detected as main imports. String tabSource = new String(tabProgram); do { // System.out.println("-->\n" + sourceAlt + "\n<--"); @@ -1025,7 +1068,7 @@ public class ErrorCheckerService implements Runnable{ programImports.add(new ImportStatement(piece, tabNumber, Base .countLines(tabSource.substring(0, idx)))); // Remove the import from the main program - // Substitue with white spaces + // Substitute with white spaces String whiteSpace = ""; for (int j = 0; j < piece.length(); j++) { whiteSpace += " "; diff --git a/pdex/src/processing/mode/experimental/Problem.java b/pdex/src/processing/mode/experimental/Problem.java old mode 100755 new mode 100644 index 6b5b95ff4..56cc0e833 --- a/pdex/src/processing/mode/experimental/Problem.java +++ b/pdex/src/processing/mode/experimental/Problem.java @@ -130,7 +130,7 @@ public class Problem { public static String process(String message) { // Remove all instances of token // "Syntax error on token 'blah', delete this token" - + if(message == null) return null; pattern = Pattern.compile(tokenRegExp); matcher = pattern.matcher(message); message = matcher.replaceAll(""); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java old mode 100755 new mode 100644 index 87722498a..a90d9c6b6 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -33,318 +33,462 @@ import processing.app.syntax.TextAreaDefaults; /** * Customized text area. Adds support for line background colors. - * + * * @author Martin Leopold */ public class TextArea extends JEditTextArea { - protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler - protected DebugEditor editor; // the editor - // line properties - protected Map lineColors = new HashMap(); // contains line background colors - // left-hand gutter properties - protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars - protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color - protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line - protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter - protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter - protected Map gutterText = new HashMap(); // maps line index to gutter text - protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color - protected TextAreaPainter customPainter; - protected ErrorCheckerService errorCheckerService; - - public TextArea(TextAreaDefaults defaults, DebugEditor editor) { - super(defaults); - this.editor = editor; + protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler - // replace the painter: - // first save listeners, these are package-private in JEditTextArea, so not accessible - ComponentListener[] componentListeners = painter.getComponentListeners(); - mouseListeners = painter.getMouseListeners(); - MouseMotionListener[] mouseMotionListeners = painter.getMouseMotionListeners(); + protected DebugEditor editor; // the editor - remove(painter); + // line properties + protected Map lineColors = new HashMap(); // contains line background colors - // set new painter - customPainter = new TextAreaPainter(this, defaults); - painter = customPainter; - - // set listeners - for (ComponentListener cl : componentListeners) { - painter.addComponentListener(cl); - } + // left-hand gutter properties + protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars - for (MouseMotionListener mml : mouseMotionListeners) { - painter.addMouseMotionListener(mml); - } + protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color - // use a custom mouse handler instead of directly using mouseListeners - MouseHandler mouseHandler = new MouseHandler(); - painter.addMouseListener(mouseHandler); - painter.addMouseMotionListener(mouseHandler); + protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line - add(CENTER, painter); + protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter - // load settings from theme.txt - ExperimentalMode theme = (ExperimentalMode) editor.getMode(); - gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); - gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); - gutterPadding = theme.getInteger("gutter.padding"); - breakpointMarker = theme.loadThemeString("breakpoint.marker", breakpointMarker); - currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker); + protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter + + protected Map gutterText = new HashMap(); // maps line index to gutter text + + protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color + + protected TextAreaPainter customPainter; + + protected ErrorCheckerService errorCheckerService; + + public TextArea(TextAreaDefaults defaults, DebugEditor editor) { + super(defaults); + this.editor = editor; + + // replace the painter: + // first save listeners, these are package-private in JEditTextArea, so not accessible + ComponentListener[] componentListeners = painter.getComponentListeners(); + mouseListeners = painter.getMouseListeners(); + MouseMotionListener[] mouseMotionListeners = painter + .getMouseMotionListeners(); + + remove(painter); + + // set new painter + customPainter = new TextAreaPainter(this, defaults); + painter = customPainter; + + // set listeners + for (ComponentListener cl : componentListeners) { + painter.addComponentListener(cl); } - - /** - * Sets ErrorCheckerService and loads theme for TextArea(XQMode) - * @param ecs - * @param mode + + for (MouseMotionListener mml : mouseMotionListeners) { + painter.addMouseMotionListener(mml); + } + + // use a custom mouse handler instead of directly using mouseListeners + MouseHandler mouseHandler = new MouseHandler(); + painter.addMouseListener(mouseHandler); + painter.addMouseMotionListener(mouseHandler); + + add(CENTER, painter); + + // load settings from theme.txt + ExperimentalMode theme = (ExperimentalMode) editor.getMode(); + gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); + gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); + gutterPadding = theme.getInteger("gutter.padding"); + breakpointMarker = theme.loadThemeString("breakpoint.marker", + breakpointMarker); + currentLineMarker = theme.loadThemeString("currentline.marker", + currentLineMarker); + } + + /** + * Sets ErrorCheckerService and loads theme for TextArea(XQMode) + * + * @param ecs + * @param mode + */ + public void setECSandThemeforTextArea(ErrorCheckerService ecs, + ExperimentalMode mode) { + errorCheckerService = ecs; + customPainter.setECSandTheme(ecs, mode); + } + + public void processKeyEvent(KeyEvent evt) { + super.processKeyEvent(evt); + if (evt.getID() == KeyEvent.KEY_TYPED) { + errorCheckerService.textModified.incrementAndGet(); + System.out.println(" Typing: " + fetchPhrase(evt) + " " + + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); + + } + + } + + private String fetchPhrase(KeyEvent evt) { + int off = getCaretPosition(); + System.out.print("off " + off); + if (off < 0) + return null; + int line = getCaretLine(); + if (line < 0) + return null; + String s = getLineText(line); + System.out.print("lin " + line); + /* + * if (s == null) return null; else if (s.length() == 0) return null; */ - public void setECSandThemeforTextArea(ErrorCheckerService ecs, ExperimentalMode mode) - { - errorCheckerService = ecs; - customPainter.setECSandTheme(ecs, mode); - } - - public void processKeyEvent(KeyEvent evt) { - super.processKeyEvent(evt); - if(evt.getID() == KeyEvent.KEY_TYPED){ - errorCheckerService.textModified.incrementAndGet(); - } - } +// else { + //System.out.print(s + " len " + s.length()); - /** - * Retrieve the total width of the gutter area. - * - * @return gutter width in pixels - */ - protected int getGutterWidth() { - FontMetrics fm = painter.getFontMetrics(); + int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + System.out.print(" x char: " + s.charAt(x)); + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) + ; // accepted these keys + else if (keyChar == KeyEvent.CHAR_UNDEFINED) + + return null; + + String word = (x < s.length() ? s.charAt(x) : "") + ""; + if (s.trim().length() == 1) { +// word = "" +// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + errorCheckerService.astGenerator.updatePredictions(word, line + + errorCheckerService.mainClassOffset); + return word; + } +// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) +// ; // accepted these keys +// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) +// return null; + int i = 0; + int closeB = 0; + + while (true) { + i++; + //TODO: currently works on single line only. "a. b()" won't be detected + if (x1 >= 0) { +// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' + || s.charAt(x1) == '.' || s.charAt(x1) == ')') + { + + if (s.charAt(x1) == ')') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '(') + closeB--; + if (s.charAt(x1) == ')') + closeB++; + x1--; + } + } else { + word = s.charAt(x1--) + word; + } + } else { + break; + } + } else { + break; + } + +// if (x2 >= 0 && x2 < s.length()) { +// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' +// || s.charAt(x2) == '$') +// word = word + s.charAt(x2++); +// else +// x2 = -1; +// } else +// x2 = -1; + +// if (x1 < 0 )//&& x2 < 0 +// break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); + break; + } + } +// if (keyChar != KeyEvent.CHAR_UNDEFINED) + + if (Character.isDigit(word.charAt(0))) + return null; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + errorCheckerService.astGenerator.updatePredictions(word, line + + errorCheckerService.mainClassOffset); + return word; + + //} + } + + /** + * Retrieve the total width of the gutter area. + * + * @return gutter width in pixels + */ + protected int getGutterWidth() { + FontMetrics fm = painter.getFontMetrics(); // System.out.println("fm: " + (fm == null)); // System.out.println("editor: " + (editor == null)); - //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); + //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); - int textWidth = Math.max(fm.stringWidth(breakpointMarker), fm.stringWidth(currentLineMarker)); - return textWidth + 2 * gutterPadding; + int textWidth = Math.max(fm.stringWidth(breakpointMarker), + fm.stringWidth(currentLineMarker)); + return textWidth + 2 * gutterPadding; + } + + /** + * Retrieve the width of margins applied to the left and right of the gutter + * text. + * + * @return margins in pixels + */ + protected int getGutterMargins() { + return gutterPadding; + } + + /** + * Set the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @param text + * the text + */ + public void setGutterText(int lineIdx, String text) { + gutterText.put(lineIdx, text); + painter.invalidateLine(lineIdx); + } + + /** + * Set the gutter text and color of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @param text + * the text + * @param textColor + * the text color + */ + public void setGutterText(int lineIdx, String text, Color textColor) { + gutterTextColors.put(lineIdx, textColor); + setGutterText(lineIdx, text); + } + + /** + * Clear the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + */ + public void clearGutterText(int lineIdx) { + gutterText.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all gutter text. + */ + public void clearGutterText() { + for (int lineIdx : gutterText.keySet()) { + painter.invalidateLine(lineIdx); } + gutterText.clear(); + } - /** - * Retrieve the width of margins applied to the left and right of the gutter - * text. - * - * @return margins in pixels - */ - protected int getGutterMargins() { - return gutterPadding; + /** + * Retrieve the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @return the gutter text + */ + public String getGutterText(int lineIdx) { + return gutterText.get(lineIdx); + } + + /** + * Retrieve the gutter text color for a specific line. + * + * @param lineIdx + * the line index + * @return the gutter text color + */ + public Color getGutterTextColor(int lineIdx) { + return gutterTextColors.get(lineIdx); + } + + /** + * Set the background color of a line. + * + * @param lineIdx + * 0-based line number + * @param col + * the background color to set + */ + public void setLineBgColor(int lineIdx, Color col) { + lineColors.put(lineIdx, col); + painter.invalidateLine(lineIdx); + } + + /** + * Clear the background color of a line. + * + * @param lineIdx + * 0-based line number + */ + public void clearLineBgColor(int lineIdx) { + lineColors.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all line background colors. + */ + public void clearLineBgColors() { + for (int lineIdx : lineColors.keySet()) { + painter.invalidateLine(lineIdx); } + lineColors.clear(); + } - /** - * Set the gutter text of a specific line. - * - * @param lineIdx the line index (0-based) - * @param text the text - */ - public void setGutterText(int lineIdx, String text) { - gutterText.put(lineIdx, text); - painter.invalidateLine(lineIdx); - } + /** + * Get a lines background color. + * + * @param lineIdx + * 0-based line number + * @return the color or null if no color was set for the specified line + */ + public Color getLineBgColor(int lineIdx) { + return lineColors.get(lineIdx); + } - /** - * Set the gutter text and color of a specific line. - * - * @param lineIdx the line index (0-based) - * @param text the text - * @param textColor the text color - */ - public void setGutterText(int lineIdx, String text, Color textColor) { - gutterTextColors.put(lineIdx, textColor); - setGutterText(lineIdx, text); - } + /** + * Convert a character offset to a horizontal pixel position inside the text + * area. Overridden to take gutter width into account. + * + * @param line + * the 0-based line number + * @param offset + * the character offset (0 is the first character on a line) + * @return the horizontal position + */ + @Override + public int _offsetToX(int line, int offset) { + return super._offsetToX(line, offset) + getGutterWidth(); + } - /** - * Clear the gutter text of a specific line. - * - * @param lineIdx the line index (0-based) - */ - public void clearGutterText(int lineIdx) { - gutterText.remove(lineIdx); - painter.invalidateLine(lineIdx); - } + /** + * Convert a horizontal pixel position to a character offset. Overridden to + * take gutter width into account. + * + * @param line + * the 0-based line number + * @param x + * the horizontal pixel position + * @return he character offset (0 is the first character on a line) + */ + @Override + public int xToOffset(int line, int x) { + return super.xToOffset(line, x - getGutterWidth()); + } - /** - * Clear all gutter text. - */ - public void clearGutterText() { - for (int lineIdx : gutterText.keySet()) { - painter.invalidateLine(lineIdx); - } - gutterText.clear(); - } + /** + * Custom mouse handler. Implements double clicking in the gutter area to + * toggle breakpoints, sets default cursor (instead of text cursor) in the + * gutter area. + */ + protected class MouseHandler implements MouseListener, MouseMotionListener { - /** - * Retrieve the gutter text of a specific line. - * - * @param lineIdx the line index (0-based) - * @return the gutter text - */ - public String getGutterText(int lineIdx) { - return gutterText.get(lineIdx); - } + protected int lastX; // previous horizontal positon of the mouse cursor - /** - * Retrieve the gutter text color for a specific line. - * - * @param lineIdx the line index - * @return the gutter text color - */ - public Color getGutterTextColor(int lineIdx) { - return gutterTextColors.get(lineIdx); - } - - /** - * Set the background color of a line. - * - * @param lineIdx 0-based line number - * @param col the background color to set - */ - public void setLineBgColor(int lineIdx, Color col) { - lineColors.put(lineIdx, col); - painter.invalidateLine(lineIdx); - } - - /** - * Clear the background color of a line. - * - * @param lineIdx 0-based line number - */ - public void clearLineBgColor(int lineIdx) { - lineColors.remove(lineIdx); - painter.invalidateLine(lineIdx); - } - - /** - * Clear all line background colors. - */ - public void clearLineBgColors() { - for (int lineIdx : lineColors.keySet()) { - painter.invalidateLine(lineIdx); - } - lineColors.clear(); - } - - /** - * Get a lines background color. - * - * @param lineIdx 0-based line number - * @return the color or null if no color was set for the specified line - */ - public Color getLineBgColor(int lineIdx) { - return lineColors.get(lineIdx); - } - - /** - * Convert a character offset to a horizontal pixel position inside the text - * area. Overridden to take gutter width into account. - * - * @param line the 0-based line number - * @param offset the character offset (0 is the first character on a line) - * @return the horizontal position - */ @Override - public int _offsetToX(int line, int offset) { - return super._offsetToX(line, offset) + getGutterWidth(); + public void mouseClicked(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseClicked(me); + } } - /** - * Convert a horizontal pixel position to a character offset. Overridden to - * take gutter width into account. - * - * @param line the 0-based line number - * @param x the horizontal pixel position - * @return he character offset (0 is the first character on a line) - */ @Override - public int xToOffset(int line, int x) { - return super.xToOffset(line, x - getGutterWidth()); + public void mousePressed(MouseEvent me) { + // check if this happened in the gutter area + if (me.getX() < getGutterWidth()) { + if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { + int line = me.getY() / painter.getFontMetrics().getHeight() + + firstLine; + if (line >= 0 && line <= getLineCount() - 1) { + editor.gutterDblClicked(line); + } + } + } else { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mousePressed(me); + } + } } - /** - * Custom mouse handler. Implements double clicking in the gutter area to - * toggle breakpoints, sets default cursor (instead of text cursor) in the - * gutter area. - */ - protected class MouseHandler implements MouseListener, MouseMotionListener { - - protected int lastX; // previous horizontal positon of the mouse cursor - - @Override - public void mouseClicked(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseClicked(me); - } - } - - @Override - public void mousePressed(MouseEvent me) { - // check if this happened in the gutter area - if (me.getX() < getGutterWidth()) { - if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { - int line = me.getY() / painter.getFontMetrics().getHeight() + firstLine; - if (line >= 0 && line <= getLineCount() - 1) { - editor.gutterDblClicked(line); - } - } - } else { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mousePressed(me); - } - } - } - - @Override - public void mouseReleased(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseReleased(me); - } - } - - @Override - public void mouseEntered(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseEntered(me); - } - } - - @Override - public void mouseExited(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseExited(me); - } - } - - @Override - public void mouseDragged(MouseEvent me) { - // No need to forward since the standard MouseMotionListeners are called anyway - // nop - } - - @Override - public void mouseMoved(MouseEvent me) { - // No need to forward since the standard MouseMotionListeners are called anyway - if (me.getX() < getGutterWidth()) { - if (lastX >= getGutterWidth()) { - painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } else { - if (lastX < getGutterWidth()) { - painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); - } - } - lastX = me.getX(); - } + @Override + public void mouseReleased(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseReleased(me); + } } + + @Override + public void mouseEntered(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseEntered(me); + } + } + + @Override + public void mouseExited(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseExited(me); + } + } + + @Override + public void mouseDragged(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + // nop + } + + @Override + public void mouseMoved(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + if (me.getX() < getGutterWidth()) { + if (lastX >= getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } else { + if (lastX < getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + } + } + lastX = me.getX(); + } + } + } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java old mode 100755 new mode 100644 index 8c93978f2..76dd2b3c6 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -19,6 +19,13 @@ package processing.mode.experimental; import java.awt.Color; import java.awt.Graphics; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import javax.swing.text.BadLocationException; import javax.swing.text.Segment; @@ -26,293 +33,457 @@ import javax.swing.text.Utilities; import processing.app.syntax.TextAreaDefaults; import processing.app.syntax.TokenMarker; +import processing.mode.experimental.ASTGenerator.ASTNodeWrapper; /** * Customized line painter. Adds support for background colors, left hand gutter * area with background color and text. - * + * * @author Martin Leopold */ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { - protected TextArea ta; // we need the subclassed textarea - protected ErrorCheckerService errorCheckerService; - - /** - * Error line underline color - */ - public Color errorColor = new Color(0xED2630); + protected TextArea ta; // we need the subclassed textarea - /** - * Warning line underline color - */ + protected ErrorCheckerService errorCheckerService; - public Color warningColor = new Color(0xFFC30E); + /** + * Error line underline color + */ + public Color errorColor = new Color(0xED2630); - /** - * Color of Error Marker - */ - public Color errorMarkerColor = new Color(0xED2630); + /** + * Warning line underline color + */ - /** - * Color of Warning Marker - */ - public Color warningMarkerColor = new Color(0xFFC30E); - - public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { - super(textArea, defaults); - ta = textArea; - } - - private void loadTheme(ExperimentalMode mode){ - errorColor = mode.getThemeColor("editor.errorcolor", errorColor); - warningColor = mode.getThemeColor("editor.warningcolor", - warningColor); - errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", - errorMarkerColor); - warningMarkerColor = mode.getThemeColor( - "editor.warningmarkercolor", warningMarkerColor); - } + public Color warningColor = new Color(0xFFC30E); - /** - * Paint a line. Paints the gutter (with background color and text) then the - * line (background color and text). - * - * @param gfx the graphics context - * @param tokenMarker - * @param line 0-based line number - * @param x horizontal position - */ - @Override - protected void paintLine(Graphics gfx, TokenMarker tokenMarker, - int line, int x) { + /** + * Color of Error Marker + */ + public Color errorMarkerColor = new Color(0xED2630); - // paint gutter - paintGutterBg(gfx, line, x); + /** + * Color of Warning Marker + */ + public Color warningMarkerColor = new Color(0xFFC30E); - paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + static int ctrlMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - paintGutterLine(gfx, line, x); - - // paint gutter symbol - paintGutterText(gfx, line, x); - - paintErrorLine(gfx, line, x); - - super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); - } - - /** - * Paint the gutter background (solid color). - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x horizontal position - */ - protected void paintGutterBg(Graphics gfx, int line, int x) { - gfx.setColor(ta.gutterBgColor); - int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); - gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); - } - - /** - * Paint the vertical gutter separator line. - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x horizontal position - */ - protected void paintGutterLine(Graphics gfx, int line, int x) { - int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); - gfx.setColor(ta.gutterLineColor); - gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), y + fm.getHeight()); - } - - /** - * Paint the gutter text. - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x horizontal position - */ - protected void paintGutterText(Graphics gfx, int line, int x) { - String text = ta.getGutterText(line); - if (text == null) { - return; - } - - gfx.setFont(getFont()); - Color textColor = ta.getGutterTextColor(line); - if (textColor == null) { - gfx.setColor(getForeground()); - } else { - gfx.setColor(textColor); - } - int y = ta.lineToY(line) + fm.getHeight(); - - // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. - //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins(), y + 1, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), ta.getGutterMargins() + 1, y + 1, gfx, this, 0); - } - - /** - * Paint the background color of a line. - * - * @param gfx the graphics context - * @param line 0-based line number - * @param x - */ - protected void paintLineBgColor(Graphics gfx, int line, int x) { - int y = ta.lineToY(line); - y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); - - // get the color - Color col = ta.getLineBgColor(line); - //System.out.print("bg line " + line + ": "); - // no need to paint anything - if (col == null) { - //System.out.println("none"); - return; - } - // paint line background - gfx.setColor(col); - gfx.fillRect(0, y, getWidth(), height); - } - - /** - * Paints the underline for an error/warning line - * - * @param gfx - * the graphics context - * @param tokenMarker - * @param line - * 0-based line number: NOTE - * @param x - */ - protected void paintErrorLine(Graphics gfx, int line, int x) { - - if (errorCheckerService == null) { - return; + public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { + super(textArea, defaults); + ta = textArea; + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { +// System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); + if (evt.isControlDown()) + handleCtrlClick(evt); } - - if (errorCheckerService.problemsList== null) { - return; - } - - boolean notFound = true; - boolean isWarning = false; + }); - // Check if current line contains an error. If it does, find if it's an - // error or warning - for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { - if (emarker.problem.lineNumber == line + 1) { - notFound = false; - if (emarker.type == ErrorMarker.Warning) { - isWarning = true; - } + } + +// public void processKeyEvent(KeyEvent evt) { +// System.out.println(evt); +// } + + void handleCtrlClick(MouseEvent evt) { + System.out.println("--handleCtrlClick--"); + int off = ta.xyToOffset(evt.getX(), evt.getY()); + if (off < 0) + return; + int line = ta.getLineOfOffset(off); + if (line < 0) + return; + String s = ta.getLineText(line); + if (s == null) + return; + else if (s.length() == 0) + return; + else { + int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + if (x < 0 || x >= s.length()) + return; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); break; } } - - if (notFound) { + if (Character.isDigit(word.charAt(0))) return; + + System.out.print(errorCheckerService.mainClassOffset + line); + System.out.print("|" + line + "| offset " + xLS + word + " <= \n"); + errorCheckerService.astGenerator.scrollToDeclaration(line + + errorCheckerService.mainClassOffset, word, xLS); + } + } + + private void loadTheme(ExperimentalMode mode) { + errorColor = mode.getThemeColor("editor.errorcolor", errorColor); + warningColor = mode.getThemeColor("editor.warningcolor", warningColor); + errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", + errorMarkerColor); + warningMarkerColor = mode.getThemeColor("editor.warningmarkercolor", + warningMarkerColor); + } + + /** + * Paint a line. Paints the gutter (with background color and text) then the + * line (background color and text). + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number + * @param x + * horizontal position + */ + @Override + protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, + int x) { + + // paint gutter + paintGutterBg(gfx, line, x); + + paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + + paintGutterLine(gfx, line, x); + + // paint gutter symbol + paintGutterText(gfx, line, x); + + paintErrorLine(gfx, line, x); + + super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); + } + + /** + * Paint the gutter background (solid color). + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterBg(Graphics gfx, int line, int x) { + gfx.setColor(ta.gutterBgColor); + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); + } + + /** + * Paint the vertical gutter separator line. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterLine(Graphics gfx, int line, int x) { + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.setColor(ta.gutterLineColor); + gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), + y + fm.getHeight()); + } + + /** + * Paint the gutter text. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterText(Graphics gfx, int line, int x) { + String text = ta.getGutterText(line); + if (text == null) { + return; + } + + gfx.setFont(getFont()); + Color textColor = ta.getGutterTextColor(line); + if (textColor == null) { + gfx.setColor(getForeground()); + } else { + gfx.setColor(textColor); + } + int y = ta.lineToY(line) + fm.getHeight(); + + // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. + //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins(), y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins() + 1, y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins(), y + 1, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins() + 1, y + 1, gfx, this, 0); + } + + /** + * Paint the background color of a line. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + */ + protected void paintLineBgColor(Graphics gfx, int line, int x) { + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + + // get the color + Color col = ta.getLineBgColor(line); + //System.out.print("bg line " + line + ": "); + // no need to paint anything + if (col == null) { + //System.out.println("none"); + return; + } + // paint line background + gfx.setColor(col); + gfx.fillRect(0, y, getWidth(), height); + } + + /** + * Paints the underline for an error/warning line + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number: NOTE + * @param x + */ + protected void paintErrorLine(Graphics gfx, int line, int x) { + + if (errorCheckerService == null) { + return; + } + + if (errorCheckerService.problemsList == null) { + return; + } + + boolean notFound = true; + boolean isWarning = false; + + // Check if current line contains an error. If it does, find if it's an + // error or warning + for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { + if (emarker.problem.lineNumber == line + 1) { + notFound = false; + if (emarker.type == ErrorMarker.Warning) { + isWarning = true; + } + break; } - - // Determine co-ordinates - // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + - // horizontalAdjustment); - int y = ta.lineToY(line); - y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); - int start = ta.getLineStartOffset(line); + } + + if (notFound) { + return; + } + + // Determine co-ordinates + // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + + // horizontalAdjustment); + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + int start = ta.getLineStartOffset(line); + + try { + String linetext = null; try { - String linetext = null; - - try { - linetext = ta.getDocument().getText(start, - ta.getLineStopOffset(line) - start - 1); - } catch (BadLocationException bl) { - // Error in the import statements or end of code. - // System.out.print("BL caught. " + ta.getLineCount() + " ," - // + line + " ,"); - // System.out.println((ta.getLineStopOffset(line) - start - 1)); - return; - } - - // Take care of offsets - int aw = fm.stringWidth(trimRight(linetext)) - + ta.getHorizontalOffset(); // apparent width. Whitespaces - // to the left of line + text - // width - int rw = fm.stringWidth(linetext.trim()); // real width - int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; - // Adding offsets for the gutter - x1 += 20; - x2 += 20; - - // gfx.fillRect(x1, y, rw, height); - - // Let the painting begin! - gfx.setColor(errorMarkerColor); - if (isWarning) { - gfx.setColor(warningMarkerColor); - } - gfx.fillRect(1, y + 2, 3, height - 2); - - gfx.setColor(errorColor); - if (isWarning) { - gfx.setColor(warningColor); - } - int xx = x1; - - // Draw the jagged lines - while (xx < x2) { - gfx.drawLine(xx, y1, xx + 2, y1 + 1); - xx += 2; - gfx.drawLine(xx, y1 + 1, xx + 2, y1); - xx += 2; - } - } catch (Exception e) { - System.out - .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " - + e); - //e.printStackTrace(); + linetext = ta.getDocument().getText(start, + ta.getLineStopOffset(line) - start + - 1); + } catch (BadLocationException bl) { + // Error in the import statements or end of code. + // System.out.print("BL caught. " + ta.getLineCount() + " ," + // + line + " ,"); + // System.out.println((ta.getLineStopOffset(line) - start - 1)); + return; } - // Won't highlight the line. Select the text instead. - // gfx.setColor(Color.RED); - // gfx.fillRect(2, y, 3, height); + // Take care of offsets + int aw = fm.stringWidth(trimRight(linetext)) + ta.getHorizontalOffset(); // apparent width. Whitespaces + // to the left of line + text + // width + int rw = fm.stringWidth(linetext.trim()); // real width + int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; + // Adding offsets for the gutter + x1 += 20; + x2 += 20; + + // gfx.fillRect(x1, y, rw, height); + + // Let the painting begin! + gfx.setColor(errorMarkerColor); + if (isWarning) { + gfx.setColor(warningMarkerColor); + } + gfx.fillRect(1, y + 2, 3, height - 2); + + gfx.setColor(errorColor); + if (isWarning) { + gfx.setColor(warningColor); + } + int xx = x1; + + // Draw the jagged lines + while (xx < x2) { + gfx.drawLine(xx, y1, xx + 2, y1 + 1); + xx += 2; + gfx.drawLine(xx, y1 + 1, xx + 2, y1); + xx += 2; + } + } catch (Exception e) { + System.out + .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " + + e); + //e.printStackTrace(); } - - /** - * Trims out trailing whitespaces (to the right) - * - * @param string - * @return - String - */ - private String trimRight(String string) { - String newString = ""; - for (int i = 0; i < string.length(); i++) { - if (string.charAt(i) != ' ') { - newString = string.substring(0, i) + string.trim(); + + // Won't highlight the line. Select the text instead. + // gfx.setColor(Color.RED); + // gfx.fillRect(2, y, 3, height); + } + + /** + * Trims out trailing whitespaces (to the right) + * + * @param string + * @return - String + */ + private String trimRight(String string) { + String newString = ""; + for (int i = 0; i < string.length(); i++) { + if (string.charAt(i) != ' ') { + newString = string.substring(0, i) + string.trim(); + break; + } + } + return newString; + } + + /** + * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) + * + * @param ecs + * @param mode + */ + public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode) { + this.errorCheckerService = ecs; + loadTheme(mode); + } + + public String getToolTipText(java.awt.event.MouseEvent evt) {System.err.println("GET"); + int off = ta.xyToOffset(evt.getX(), evt.getY()); + if (off < 0) + return null; + int line = ta.getLineOfOffset(off); + if (line < 0) + return null; + String s = ta.getLineText(line); + if (s == null) + return evt.toString(); + else if (s.length() == 0) + return null; + else { + int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + if (x < 0 || x >= s.length()) + return null; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return null; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return null; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); break; } } - return newString; - } - - /** - * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) - * @param ecs - * @param mode - */ - public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode){ - this.errorCheckerService = ecs; - loadTheme(mode); + if (Character.isDigit(word.charAt(0))) + return null; + String tooltipText = errorCheckerService.astGenerator + .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, + xLS); + + System.out.print(errorCheckerService.mainClassOffset + " MCO "); + System.out.print("|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); + if (tooltipText != null) + return tooltipText; + return word; } + + } + } diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index cc263072f..34ee2a9a2 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -55,7 +55,6 @@ import processing.mode.java.preproc.PdePreprocessor; public class XQPreprocessor { private ASTRewrite rewrite = null; - public int mainClassOffset = 0; private ArrayList imports; private ArrayList extraImports; @@ -76,7 +75,7 @@ public class XQPreprocessor { public String doYourThing(String source, ArrayList programImports) { this.extraImports = programImports; - source = prepareImports() + source; + //source = prepareImports() + source; Document doc = new Document(source); ASTParser parser = ASTParser.newParser(AST.JLS4); @@ -117,7 +116,6 @@ public class XQPreprocessor { } lines += 2; // System.out.println("Lines: " + lines); - mainClassOffset = lines; return doc.get(); } @@ -146,6 +144,11 @@ public class XQPreprocessor { totalImports += "\n"; return totalImports; } + + public String prepareImports(ArrayList programImports) { + this.extraImports = programImports; + return prepareImports(); + } /** * Visitor implementation that does all the substitution dirty work.
    From 910b371f9ebc27ca36fa695df2550f41583e8db6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 30 Mar 2013 22:01:27 +0530 Subject: [PATCH 018/608] Now complex field access getting resolved --- .../mode/experimental/ASTGenerator.java | 156 +++++++++--------- .../mode/experimental/TextAreaPainter.java | 2 +- 2 files changed, 81 insertions(+), 77 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 03841481e..c64793227 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -96,7 +96,6 @@ import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.core.dom.WhileStatement; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; - import processing.app.Base; import processing.app.SketchCode; import processing.app.syntax.InputHandler.clipboard_copy; @@ -347,58 +346,31 @@ public class ASTGenerator { } else if (expression instanceof FieldAccess) { return findDeclaration2(((FieldAccess) expression).getName(), nearestNode); } else if (expression instanceof QualifiedName) { - return findDeclaration2(((QualifiedName) expression).getName(), + System.out.println("1. Resolving " + + ((QualifiedName) expression).getQualifier() + " ||| " + + ((QualifiedName) expression).getName()); + return findDeclaration2(((QualifiedName) expression).getQualifier(), nearestNode); } -// if (anode != null) { -// System.out.println("Expression: " + anode); -// anode = resolveExpression(nearestNode, anode); -// } -// String word = anode.toString(); -// // Here expression should be a SN type hopefully. -// System.out.println("Final Expression: " + word); -//// anode = expression.getParent(); -// -// anode = nearestNode.getParent(); -// ASTNode matchinNode = null; -// while (anode != null) { -// -// List sprops = anode -// .structuralPropertiesForType(); -// for (StructuralPropertyDescriptor sprop : sprops) { -// ASTNode cnode = null; -// if (!sprop.isChildListProperty()) { -// if (anode.getStructuralProperty(sprop) instanceof ASTNode) { -// cnode = (ASTNode) anode.getStructuralProperty(sprop); -// String[] types = checkForTypes(cnode); -// if (types != null) { -// for (int i = 0; i < types.length; i++) { -// if (types[i].startsWith(word)) -// { -// System.out.println("match: "+types[i]); -// } -// } -// } -// } -// } else { -// // Childlist prop -// List nodelist = (List) anode -// .getStructuralProperty(sprop); -// for (ASTNode clnode : nodelist) { -// String[] types = checkForTypes(clnode); -// if (types != null) { -// for (int i = 0; i < types.length; i++) { -// if (types[i].startsWith(word)) -// System.out.println("match: "+types[i]);; -// } -// } -// } -// } -// } -// anode = anode.getParent(); -// } + return null; + } + /** + * For a().abc.a123 this would return a123 + * + * @param expression + * @return + */ + public static ASTNode resolveChildExpression(ASTNode expression) { +// ASTNode anode = null; + if (expression instanceof SimpleName) { + return expression; + } else if (expression instanceof FieldAccess) { + return ((FieldAccess) expression).getExpression(); + } else if (expression instanceof QualifiedName) { + return ((QualifiedName) expression).getName(); + } return null; } @@ -439,20 +411,27 @@ public class ASTGenerator { } + // Now parse the expression into an ASTNode object ASTNode anode = null; ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setKind(ASTParser.K_EXPRESSION); parser.setSource(word.toCharArray()); ASTNode testnode = parser.createAST(null); - System.out.print("Typed: " + word + "|"); + + // Find closest ASTNode of the document to this word + System.err.print("Typed: " + word + "|"); anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); - System.out.println(lineNumber + " Nearest ASTNode to PRED " + System.err.println(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(anode)); ArrayList candidates = new ArrayList(); + // Determine the expression typed + if (testnode instanceof SimpleName) { + + // Simple one word exprssion - so is just an identifier anode = anode.getParent(); while (anode != null) { @@ -490,9 +469,15 @@ public class ASTGenerator { } } else { - // Complicated completion - System.out.println("Not a SN " + getNodeAsString(testnode)); + // Complex expression of type blah.blah2().doIt,etc + // Have to resolve it by carefully traversing AST of testNode + System.err.println("Complex expression " + getNodeAsString(testnode)); + ASTNode det = resolveExpression(anode, testnode); + // Find the parent of the expression + // in a().b, this would give me the return type of a(), so that we can + // find all children of a() begininng with b + System.err.println("DET " + getNodeAsString(det)); if (det != null) { TypeDeclaration td = null; if (det instanceof MethodDeclaration) { @@ -507,16 +492,33 @@ public class ASTGenerator { .getType()); td = (TypeDeclaration) findDeclaration(stp.getName()); } + } else if (det instanceof VariableDeclarationStatement) { + SimpleType stp = (SimpleType) (((VariableDeclarationStatement) det) + .getType()); + td = (TypeDeclaration) findDeclaration(stp.getName()); } - System.out.println(getNodeAsString(det) + " defined in " + // Now td contains the type returned by a() + System.err.println(getNodeAsString(det) + " defined in " + getNodeAsString(td)); + if (td != null) { + ASTNode child = resolveChildExpression(testnode); + System.out.println("Completion candidate: " + + getNodeAsString(child)); for (int i = 0; i < td.getFields().length; i++) { - candidates.add(getNodeAsString(td.getFields()[i])); + List vdfs = td.getFields()[i] + .fragments(); + for (VariableDeclarationFragment vdf : vdfs) { + if (vdf.getName().toString().startsWith(child.toString())) + candidates.add(getNodeAsString(vdf)); + } + } for (int i = 0; i < td.getMethods().length; i++) { - candidates.add(getNodeAsString(td.getMethods()[i])); + if (td.getMethods()[i].getName().toString() + .startsWith(child.toString())) + candidates.add(getNodeAsString(td.getMethods()[i])); } } @@ -557,7 +559,7 @@ public class ASTGenerator { // .println(node.getStructuralProperty(prop) + " -> " + (prop)); if (node.getStructuralProperty(prop) instanceof ASTNode) { ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); - System.out.println("Looking at " + getNodeAsString(cnode)); +// System.out.println("Looking at " + getNodeAsString(cnode)); int cLineNum = ((CompilationUnit) cnode.getRoot()) .getLineNumber(cnode.getStartPosition() + cnode.getLength()); if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { @@ -573,7 +575,7 @@ public class ASTGenerator { for (ASTNode cnode : nodelist) { int cLineNum = ((CompilationUnit) cnode.getRoot()) .getLineNumber(cnode.getStartPosition() + cnode.getLength()); - System.out.println("Looking at " + getNodeAsString(cnode)); +// System.out.println("Looking at " + getNodeAsString(cnode)); if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { return findClosestParentNode(lineNumber, cnode); } @@ -755,7 +757,7 @@ public class ASTGenerator { int[] position = errorCheckerService.calculateTabIndexAndLineNumber(dpr); System.out.println("Tab " + position[0] + ", Line: " + (position[1])); Problem p = new Problem(dpr, position[0], position[1]); - //errorCheckerService.scrollToErrorLine(p); + errorCheckerService.scrollToErrorLine(p); } // uncomment this one, it works return null; @@ -1119,16 +1121,16 @@ public class ASTGenerator { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; if (prop.isChildProperty() || prop.isSimpleProperty()) { if (parent.getStructuralProperty(prop) instanceof ASTNode) { - System.out.println(prop + " C/S Prop of -> " - + getNodeAsString(parent)); +// System.out.println(prop + " C/S Prop of -> " +// + getNodeAsString(parent)); ret = definedIn((ASTNode) parent.getStructuralProperty(prop), findMe.toString(), constrains, declaringClass); if (ret != null) return ret; } } else if (prop.isChildListProperty()) { - System.out.println((prop) + " ChildList props of " - + getNodeAsString(parent)); +// System.out.println((prop) + " ChildList props of " +// + getNodeAsString(parent)); List nodelist = (List) parent .getStructuralProperty(prop); for (ASTNode retNode : nodelist) { @@ -1272,14 +1274,14 @@ public class ASTGenerator { } System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); while (alternateParent != null) { - System.out.println("findDeclaration2 -> " - + getNodeAsString(alternateParent)); +// System.out.println("findDeclaration2 -> " +// + getNodeAsString(alternateParent)); for (Object oprop : alternateParent.structuralPropertiesForType()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; if (prop.isChildProperty() || prop.isSimpleProperty()) { if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) { - System.out.println(prop + " C/S Prop of -> " - + getNodeAsString(alternateParent)); +// System.out.println(prop + " C/S Prop of -> " +// + getNodeAsString(alternateParent)); ret = definedIn((ASTNode) alternateParent .getStructuralProperty(prop), findMe.toString(), constrains, declaringClass); @@ -1287,8 +1289,8 @@ public class ASTGenerator { return ret; } } else if (prop.isChildListProperty()) { - System.out.println((prop) + " ChildList props of " - + getNodeAsString(alternateParent)); +// System.out.println((prop) + " ChildList props of " +// + getNodeAsString(alternateParent)); List nodelist = (List) alternateParent .getStructuralProperty(prop); for (ASTNode retNode : nodelist) { @@ -1340,14 +1342,14 @@ public class ASTGenerator { if (node == null) return null; if (constrains != null) { - System.out.println("Looking at " + getNodeAsString(node) + " for " + name - + " in definedIn"); +// System.out.println("Looking at " + getNodeAsString(node) + " for " + name +// + " in definedIn"); if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) { - System.err.print("definedIn -1 " + " But constrain was "); - for (Integer integer : constrains) { - System.out.print(ASTNode.nodeClassForType(integer) + ","); - } - System.out.println(); +// System.err.print("definedIn -1 " + " But constrain was "); +// for (Integer integer : constrains) { +// System.out.print(ASTNode.nodeClassForType(integer) + ","); +// } +// System.out.println(); return null; } } @@ -1462,6 +1464,8 @@ public class ASTGenerator { value = node.toString() + className; else if (node instanceof SimpleName) value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (node instanceof QualifiedName) + value = node.toString() + " | " + className; else if (className.startsWith("Variable")) value = node.toString() + " | " + className; else if (className.endsWith("Type")) diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 76dd2b3c6..dd20d67e6 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -420,7 +420,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { loadTheme(mode); } - public String getToolTipText(java.awt.event.MouseEvent evt) {System.err.println("GET"); + public String getToolTipText(java.awt.event.MouseEvent evt) { int off = ta.xyToOffset(evt.getX(), evt.getY()); if (off < 0) return null; From 1b3d7acf88d751d1373820b097f1a35ceeb2ed53 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 3 Apr 2013 21:04:38 +0530 Subject: [PATCH 019/608] Moar stuff working, including predictions for a().b and a().b() =D --- pdex/.project | 2 +- .../mode/experimental/ASTGenerator.java | 40 ++++++++++++++----- .../mode/experimental/TextArea.java | 4 +- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/pdex/.project b/pdex/.project index dd2d29121..70f10f617 100644 --- a/pdex/.project +++ b/pdex/.project @@ -12,7 +12,7 @@ org.eclipse.ui.externaltools.ExternalToolBuilder - full,incremental, + auto,full,incremental, LaunchConfigHandle diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index c64793227..b904b5e33 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -338,13 +338,16 @@ public class ASTGenerator { public static ASTNode resolveExpression(ASTNode nearestNode, ASTNode expression) { // ASTNode anode = null; + System.out.println("Resolving " + getNodeAsString(expression)); if (expression instanceof SimpleName) { return findDeclaration2(((SimpleName) expression), nearestNode); } else if (expression instanceof MethodInvocation) { return findDeclaration2(((MethodInvocation) expression).getName(), nearestNode); } else if (expression instanceof FieldAccess) { - return findDeclaration2(((FieldAccess) expression).getName(), nearestNode); + System.out.println("2. Field access " + getNodeAsString(((FieldAccess)expression).getExpression())); + return resolveExpression(nearestNode, ((FieldAccess)expression).getExpression()); + //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); } else if (expression instanceof QualifiedName) { System.out.println("1. Resolving " + ((QualifiedName) expression).getQualifier() + " ||| " @@ -367,10 +370,12 @@ public class ASTGenerator { if (expression instanceof SimpleName) { return expression; } else if (expression instanceof FieldAccess) { - return ((FieldAccess) expression).getExpression(); + return ((FieldAccess) expression).getName(); } else if (expression instanceof QualifiedName) { return ((QualifiedName) expression).getName(); } + System.out.println(" resolveChildExpression returning NULL for " + + getNodeAsString(expression)); return null; } @@ -393,9 +398,15 @@ public class ASTGenerator { } protected void done() { -// ArrayList candidates = new ArrayList(); - //ASTNodeWrapper[][] candi = new ASTNodeWrapper[80][1]; + String word2 = word; + boolean noCompare = false; + if (word2.endsWith(".")) { + // return all matches + word2 = word2.substring(0, word.length() - 1); + noCompare = true; + } + int lineNumber = line; // Adjust line number for tabbed sketches if (errorCheckerService != null) { @@ -415,11 +426,11 @@ public class ASTGenerator { ASTNode anode = null; ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setKind(ASTParser.K_EXPRESSION); - parser.setSource(word.toCharArray()); + parser.setSource(word2.toCharArray()); ASTNode testnode = parser.createAST(null); // Find closest ASTNode of the document to this word - System.err.print("Typed: " + word + "|"); + System.err.print("Typed: " + word2 + "|"); anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); System.err.println(lineNumber + " Nearest ASTNode to PRED " @@ -429,8 +440,10 @@ public class ASTGenerator { // Determine the expression typed - if (testnode instanceof SimpleName) { + if (testnode instanceof SimpleName && !noCompare) { + System.err + .println("One word expression " + getNodeAsString(testnode)); // Simple one word exprssion - so is just an identifier anode = anode.getParent(); while (anode != null) { @@ -445,7 +458,7 @@ public class ASTGenerator { String[] types = checkForTypes(cnode); if (types != null) { for (int i = 0; i < types.length; i++) { - if (types[i].startsWith(word)) + if (types[i].startsWith(word2)) candidates.add(types[i]); } } @@ -458,7 +471,7 @@ public class ASTGenerator { String[] types = checkForTypes(clnode); if (types != null) { for (int i = 0; i < types.length; i++) { - if (types[i].startsWith(word)) + if (types[i].startsWith(word2)) candidates.add(types[i]); } } @@ -510,13 +523,18 @@ public class ASTGenerator { List vdfs = td.getFields()[i] .fragments(); for (VariableDeclarationFragment vdf : vdfs) { - if (vdf.getName().toString().startsWith(child.toString())) + if (noCompare) { + candidates.add(getNodeAsString(vdf)); + } else if (vdf.getName().toString() + .startsWith(child.toString())) candidates.add(getNodeAsString(vdf)); } } for (int i = 0; i < td.getMethods().length; i++) { - if (td.getMethods()[i].getName().toString() + if (noCompare) { + candidates.add(getNodeAsString(td.getMethods()[i])); + } else if (td.getMethods()[i].getName().toString() .startsWith(child.toString())) candidates.add(getNodeAsString(td.getMethods()[i])); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index a90d9c6b6..0e18de79b 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -228,8 +228,8 @@ public class TextArea extends JEditTextArea { if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); - if (word.endsWith(".")) - word = word.substring(0, word.length() - 1); +// if (word.endsWith(".")) +// word = word.substring(0, word.length() - 1); errorCheckerService.astGenerator.updatePredictions(word, line + errorCheckerService.mainClassOffset); return word; From 3862164c670fe149f5281e3e510aa13128b12708 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 12 Apr 2013 20:38:43 +0530 Subject: [PATCH 020/608] trimming imports --- .../mode/experimental/ASTGenerator.java | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b904b5e33..ebc586396 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -18,87 +18,37 @@ import javax.swing.JTable; import javax.swing.JTree; import javax.swing.SwingWorker; import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeNode; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.ASTVisitor; -import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; -import org.eclipse.jdt.core.dom.ArrayAccess; -import org.eclipse.jdt.core.dom.ArrayCreation; -import org.eclipse.jdt.core.dom.ArrayInitializer; -import org.eclipse.jdt.core.dom.ArrayType; -import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.Block; -import org.eclipse.jdt.core.dom.BodyDeclaration; -import org.eclipse.jdt.core.dom.BooleanLiteral; -import org.eclipse.jdt.core.dom.BreakStatement; -import org.eclipse.jdt.core.dom.CastExpression; -import org.eclipse.jdt.core.dom.CatchClause; -import org.eclipse.jdt.core.dom.CharacterLiteral; -import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; -import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.ConditionalExpression; -import org.eclipse.jdt.core.dom.ConstructorInvocation; -import org.eclipse.jdt.core.dom.ContinueStatement; -import org.eclipse.jdt.core.dom.DoStatement; -import org.eclipse.jdt.core.dom.EnhancedForStatement; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ExpressionStatement; import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.FieldDeclaration; -import org.eclipse.jdt.core.dom.ForStatement; -import org.eclipse.jdt.core.dom.IfStatement; -import org.eclipse.jdt.core.dom.InfixExpression; -import org.eclipse.jdt.core.dom.Initializer; -import org.eclipse.jdt.core.dom.InstanceofExpression; -import org.eclipse.jdt.core.dom.Javadoc; -import org.eclipse.jdt.core.dom.LineComment; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NodeFinder; -import org.eclipse.jdt.core.dom.NumberLiteral; -import org.eclipse.jdt.core.dom.ParameterizedType; -import org.eclipse.jdt.core.dom.ParenthesizedExpression; -import org.eclipse.jdt.core.dom.PostfixExpression; -import org.eclipse.jdt.core.dom.PrefixExpression; -import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; -import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; -import org.eclipse.jdt.core.dom.Statement; -import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; -import org.eclipse.jdt.core.dom.SuperConstructorInvocation; -import org.eclipse.jdt.core.dom.SuperFieldAccess; -import org.eclipse.jdt.core.dom.SuperMethodInvocation; -import org.eclipse.jdt.core.dom.SwitchCase; -import org.eclipse.jdt.core.dom.SwitchStatement; -import org.eclipse.jdt.core.dom.SynchronizedStatement; -import org.eclipse.jdt.core.dom.ThrowStatement; -import org.eclipse.jdt.core.dom.TryStatement; -import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.dom.TypeDeclarationStatement; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.core.dom.WhileStatement; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; import processing.app.SketchCode; -import processing.app.syntax.InputHandler.clipboard_copy; public class ASTGenerator { From 4d6ac4993e775e7bdfc8cd6ee82cbfbf0c276aa6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 15 Apr 2013 17:58:21 +0530 Subject: [PATCH 021/608] prediction from 3rd party libraries --- pdex/build.xml | 2 +- .../mode/experimental/ASTGenerator.java | 123 ++++++++++++++++-- .../experimental/ErrorCheckerService.java | 27 ++-- 3 files changed, 128 insertions(+), 24 deletions(-) diff --git a/pdex/build.xml b/pdex/build.xml index 489c3f93d..a3a206dff 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -47,7 +47,7 @@ destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar" + classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar; mode/classpath-explorer-1.0.jar" debug="on"> diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ebc586396..8f6ce8d23 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -7,6 +7,10 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -47,6 +51,12 @@ import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; +import com.google.classpath.ClassPath; +import com.google.classpath.ClassPathFactory; +import com.google.classpath.RegExpResourceFilter; +import com.ibm.icu.util.StringTokenizer; +import com.sun.jdi.Type; + import processing.app.Base; import processing.app.SketchCode; @@ -87,7 +97,7 @@ public class ASTGenerator { JScrollPane sp2 = new JScrollPane(); sp2.setViewportView(tableAuto); frameAutoComp.add(sp2); - + //loadJars(); } public class ASTNodeWrapper { @@ -162,8 +172,11 @@ public class ASTGenerator { // return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) + if (!frame2.isVisible()) { frame2.setVisible(true); + loadJars(); + //System.out.println(System.getProperty("java.home")); + } if (!frameAutoComp.isVisible()) frameAutoComp.setVisible(true); jtree.validate(); @@ -171,10 +184,55 @@ public class ASTGenerator { } }; worker.execute(); - + System.err.println("++>" + System.getProperty("java.class.path")); +// System.out.println(System.getProperty("java.class.path")); +// System.out.println("-------------------------------"); return codeTree; } + private ClassPathFactory factory; + + private ClassPath classPath; + + private void loadJars() { + try { + factory = new ClassPathFactory(); + + String tehPaths = System.getProperty("java.class.path") + + File.pathSeparatorChar + System.getProperty("java.home") + + "/lib/rt.jar"; + StringBuffer tehPath = new StringBuffer(System.getProperty("java.class.path") + + File.pathSeparatorChar + System.getProperty("java.home") + + "/lib/rt.jar"); + if(errorCheckerService.classpathJars != null){ + for (URL jarPath : errorCheckerService.classpathJars) { + tehPath.append(jarPath.getPath() + File.pathSeparatorChar); + } + } + + //String paths[] = tehPaths.split(File.separatorChar +""); + StringTokenizer st = new StringTokenizer(tehPath.toString(), File.pathSeparatorChar + + ""); + while (st.hasMoreElements()) { + System.out.println("- " + st.nextToken()); + } + classPath = factory.createFromPath(tehPath.toString()); + for (String packageName : classPath.listPackages("")) { + System.out.println(packageName); + } + RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( + ".*", + "Vec3D.class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + public DefaultMutableTreeNode buildAST() { return buildAST2(errorCheckerService.sourceCode); } @@ -295,8 +353,10 @@ public class ASTGenerator { return findDeclaration2(((MethodInvocation) expression).getName(), nearestNode); } else if (expression instanceof FieldAccess) { - System.out.println("2. Field access " + getNodeAsString(((FieldAccess)expression).getExpression())); - return resolveExpression(nearestNode, ((FieldAccess)expression).getExpression()); + System.out.println("2. Field access " + + getNodeAsString(((FieldAccess) expression).getExpression())); + return resolveExpression(nearestNode, + ((FieldAccess) expression).getExpression()); //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); } else if (expression instanceof QualifiedName) { System.out.println("1. Resolving " @@ -430,6 +490,9 @@ public class ASTGenerator { } anode = anode.getParent(); } + + + } else { // Complex expression of type blah.blah2().doIt,etc @@ -443,24 +506,23 @@ public class ASTGenerator { System.err.println("DET " + getNodeAsString(det)); if (det != null) { TypeDeclaration td = null; + SimpleType stp = null; if (det instanceof MethodDeclaration) { if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { - SimpleType stp = (SimpleType) (((MethodDeclaration) det) - .getReturnType2()); + stp = (SimpleType) (((MethodDeclaration) det).getReturnType2()); td = (TypeDeclaration) findDeclaration(stp.getName()); } } else if (det instanceof FieldDeclaration) { if (((FieldDeclaration) det).getType() instanceof SimpleType) { - SimpleType stp = (SimpleType) (((FieldDeclaration) det) - .getType()); + stp = (SimpleType) (((FieldDeclaration) det).getType()); td = (TypeDeclaration) findDeclaration(stp.getName()); } } else if (det instanceof VariableDeclarationStatement) { - SimpleType stp = (SimpleType) (((VariableDeclarationStatement) det) + stp = (SimpleType) (((VariableDeclarationStatement) det) .getType()); td = (TypeDeclaration) findDeclaration(stp.getName()); } - + System.out.println("ST is " + stp.getName()); // Now td contains the type returned by a() System.err.println(getNodeAsString(det) + " defined in " + getNodeAsString(td)); @@ -488,6 +550,45 @@ public class ASTGenerator { .startsWith(child.toString())) candidates.add(getNodeAsString(td.getMethods()[i])); } + } else { + if (stp != null) { + System.out.println("Couldn't determine type! " + + stp.getName().toString()); + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", stp + .getName().toString() + ".class"); + String[] resources = classPath + .findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } + if(resources.length > 0){ + String matchedClass = resources[0]; + matchedClass = matchedClass.substring(0,matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + System.out.println("Matched class: " + matchedClass); + try { + Class probableClass = Class.forName(matchedClass, false, errorCheckerService.classLoader); + for (Method method : probableClass.getMethods()) { + StringBuffer label = new StringBuffer(method.getName() + "("); + for (Class type : method.getParameterTypes()) { + label.append(type.getSimpleName() + ","); + } + label.append(")"); + candidates.add(label.toString()); + } + for (Field field : probableClass.getFields()) { + candidates.add(field.getName()); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.out.println("Couldn't load " + matchedClass); + } + + //processing/core/PVector.class + // + } + } } } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index e0ce2a646..d09faf5c9 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -265,10 +265,11 @@ public class ErrorCheckerService implements Runnable{ sourceCode = preprocessCode(editor.getSketch().getMainProgram()); syntaxCheck(); - System.err.println(editor.getSketch().getName()+ " MCO " + mainClassOffset); + System.err.println(editor.getSketch().getName()+ "1 MCO " + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. if (problems.length == 0 && editor.compilationCheckEnabled) { + mainClassOffset++; // just a hack. astGenerator.buildAST(); sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); @@ -280,7 +281,7 @@ public class ErrorCheckerService implements Runnable{ // System.out.println(sourceCode); // System.out.println("--------------------------"); compileCheck(); - + System.err.println(editor.getSketch().getName()+ "2 MCO " + mainClassOffset); } @@ -332,7 +333,7 @@ public class ErrorCheckerService implements Runnable{ // System.out.println(p.toString()); } } - + protected URLClassLoader classLoader; private void compileCheck() { // Currently (Sept, 2012) I'm using Java's reflection api to load the @@ -370,19 +371,21 @@ public class ErrorCheckerService implements Runnable{ File[] jarFiles = f.listFiles(fileFilter); // System.out.println( "Jar files found? " + (jarFiles != null)); - for (File jarFile : jarFiles) { - classpathJars.add(jarFile.toURI().toURL()); - } + //for (File jarFile : jarFiles) { + //classpathJars.add(jarFile.toURI().toURL()); + //} - classpath = new URL[classpathJars.size()]; // + 1 for - // Compilation - // Checker class - for (int i = 0; i < classpathJars.size(); i++) { - classpath[i] = classpathJars.get(i); + classpath = new URL[classpathJars.size() + jarFiles.length]; + int ii = 0; + for (; ii < classpathJars.size(); ii++) { + classpath[ii] = classpathJars.get(ii); + } + for (int i = 0; i < jarFiles.length; i++) { + classpath[ii++] = jarFiles[i].toURI().toURL(); } // System.out.println("CP Len -- " + classpath.length); - URLClassLoader classLoader = new URLClassLoader(classpath); + classLoader = new URLClassLoader(classpath); // System.out.println("1."); checkerClass = Class.forName("CompilationChecker", true, classLoader); From 6bd36efa3ab823cab9a50dd5d25de1f120cb7817 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 17 Apr 2013 23:25:24 +0530 Subject: [PATCH 022/608] javadoc loading tests --- pdex/build.xml | 4 +- .../mode/experimental/ASTGenerator.java | 290 ++++++++++++++---- .../mode/experimental/DebugEditor.java | 2 +- .../experimental/ErrorCheckerService.java | 2 +- 4 files changed, 241 insertions(+), 57 deletions(-) diff --git a/pdex/build.xml b/pdex/build.xml index a3a206dff..309946ae0 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -47,8 +47,8 @@ destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar; mode/classpath-explorer-1.0.jar" - debug="on"> + classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar;mode/classpath-explorer-1.0.jar; mode/jsoup-1.7.1.jar;" + debug="off"> diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 8f6ce8d23..431fb4cfb 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -10,13 +10,14 @@ import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; -import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.TreeMap; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTree; @@ -50,15 +51,18 @@ import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import processing.app.Base; +import processing.app.SketchCode; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; import com.google.classpath.RegExpResourceFilter; import com.ibm.icu.util.StringTokenizer; -import com.sun.jdi.Type; - -import processing.app.Base; -import processing.app.SketchCode; public class ASTGenerator { @@ -78,6 +82,8 @@ public class ASTGenerator { private JTable tableAuto; + private JLabel jdocLabel; + public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; this.editor = ecs.getEditor(); @@ -97,6 +103,13 @@ public class ASTGenerator { JScrollPane sp2 = new JScrollPane(); sp2.setViewportView(tableAuto); frameAutoComp.add(sp2); + + jdocWindow = new JFrame(); + jdocWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + jdocWindow.setBounds(new Rectangle(280, 100, 460, 460)); + jdocLabel = new JLabel(); + jdocWindow.add(jdocLabel); + jdocMap = new TreeMap(); //loadJars(); } @@ -175,10 +188,13 @@ public class ASTGenerator { if (!frame2.isVisible()) { frame2.setVisible(true); loadJars(); + loadJavaDoc(); //System.out.println(System.getProperty("java.home")); } if (!frameAutoComp.isVisible()) frameAutoComp.setVisible(true); + if(!jdocWindow.isVisible()) + jdocWindow.setVisible(true); jtree.validate(); } } @@ -194,6 +210,8 @@ public class ASTGenerator { private ClassPath classPath; + private JFrame jdocWindow; + private void loadJars() { try { factory = new ClassPathFactory(); @@ -201,18 +219,22 @@ public class ASTGenerator { String tehPaths = System.getProperty("java.class.path") + File.pathSeparatorChar + System.getProperty("java.home") + "/lib/rt.jar"; - StringBuffer tehPath = new StringBuffer(System.getProperty("java.class.path") - + File.pathSeparatorChar + System.getProperty("java.home") - + "/lib/rt.jar"); - if(errorCheckerService.classpathJars != null){ + StringBuffer tehPath = new StringBuffer( + System + .getProperty("java.class.path") + + File.pathSeparatorChar + + System + .getProperty("java.home") + + "/lib/rt.jar"); + if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { tehPath.append(jarPath.getPath() + File.pathSeparatorChar); } } - + //String paths[] = tehPaths.split(File.separatorChar +""); - StringTokenizer st = new StringTokenizer(tehPath.toString(), File.pathSeparatorChar - + ""); + StringTokenizer st = new StringTokenizer(tehPath.toString(), + File.pathSeparatorChar + ""); while (st.hasMoreElements()) { System.out.println("- " + st.nextToken()); } @@ -231,6 +253,70 @@ public class ASTGenerator { // TODO Auto-generated catch block e.printStackTrace(); } + + } + private TreeMap jdocMap; + private void loadJavaDoc() { + Document doc; + + String primTypes[] = { + "void", "int", "short", "byte", "boolean", "char", "float", "double", + "long" }; + try { + File javaDocFile = new File( + "/home/quarkninja/Documents/Processing/libraries/SimpleOpenNI/documentation/SimpleOpenNI/SimpleOpenNI.html"); + //SimpleOpenNI.SimpleOpenNI + doc = Jsoup.parse(javaDocFile, null); + + String msg = ""; + Elements elm = doc.getElementsByTag("pre"); + Elements desc = doc.getElementsByTag("dl"); + //System.out.println(elm.toString()); + + + for (Iterator iterator = elm.iterator(); iterator.hasNext();) { + Element element = (Element) iterator.next(); + + //System.out.println(element.text()); +// if (element.nextElementSibling() != null) +// System.out.println(element.nextElementSibling().text()); + System.out.println("-------------------"); + msg = "
    " + + element.html() + + element.nextElementSibling() + + "
    "; + + String parts[] = element.text().split("\\s|\\(|,|\\)"); + int i = 0; + if (parts[i].equals("public")) + i++; + if (parts[i].equals("static") || parts[i].equals("final")) + i++; + if (parts[i].equals("static") || parts[i].equals("final")) + i++; +// System.out.println("Ret Type " + parts[i]); + + i++; // return type + + // System.out.println("Name " + parts[i]); + jdocMap.put(parts[i], msg); +// if (parts[i].startsWith("draw")) { +// match = element.text(); +// msg = "
    " +// + element.html() +// + element.nextElementSibling() +// + "
    "; +// System.out.println(match + " " + msg); +// } + } + System.out.println("JDoc loaded"); + for (String key : jdocMap.keySet()) { + System.out.println("Method: " + key); + System.out.println("Method: " + jdocMap.get(key)); + } + } catch (Exception e) { + e.printStackTrace(); + } } public DefaultMutableTreeNode buildAST() { @@ -451,13 +537,27 @@ public class ASTGenerator { // Determine the expression typed if (testnode instanceof SimpleName && !noCompare) { - System.err .println("One word expression " + getNodeAsString(testnode)); // Simple one word exprssion - so is just an identifier anode = anode.getParent(); while (anode != null) { + if (anode instanceof TypeDeclaration) { + TypeDeclaration td = (TypeDeclaration) anode; + if (td + .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) { + SimpleType st = (SimpleType) td + .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); + System.out.println("Superclass " + st.getName()); + for (String can : getMembersForType(st.getName().toString(), + word2, noCompare)) { + candidates.add(can); + } + //findDeclaration(st.getName()) + + } + } List sprops = anode .structuralPropertiesForType(); for (StructuralPropertyDescriptor sprop : sprops) { @@ -490,8 +590,6 @@ public class ASTGenerator { } anode = anode.getParent(); } - - } else { @@ -526,9 +624,9 @@ public class ASTGenerator { // Now td contains the type returned by a() System.err.println(getNodeAsString(det) + " defined in " + getNodeAsString(td)); - + ASTNode child = resolveChildExpression(testnode); if (td != null) { - ASTNode child = resolveChildExpression(testnode); + System.out.println("Completion candidate: " + getNodeAsString(child)); for (int i = 0; i < td.getFields().length; i++) { @@ -552,42 +650,56 @@ public class ASTGenerator { } } else { if (stp != null) { - System.out.println("Couldn't determine type! " - + stp.getName().toString()); - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", stp - .getName().toString() + ".class"); - String[] resources = classPath - .findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } - if(resources.length > 0){ - String matchedClass = resources[0]; - matchedClass = matchedClass.substring(0,matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - System.out.println("Matched class: " + matchedClass); - try { - Class probableClass = Class.forName(matchedClass, false, errorCheckerService.classLoader); - for (Method method : probableClass.getMethods()) { - StringBuffer label = new StringBuffer(method.getName() + "("); - for (Class type : method.getParameterTypes()) { - label.append(type.getSimpleName() + ","); - } - label.append(")"); - candidates.add(label.toString()); - } - for (Field field : probableClass.getFields()) { - candidates.add(field.getName()); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - System.out.println("Couldn't load " + matchedClass); - } - - //processing/core/PVector.class - // - } +// System.out.println("Couldn't determine type! " +// + stp.getName().toString()); +// RegExpResourceFilter regExpResourceFilter; +// regExpResourceFilter = new RegExpResourceFilter(".*", stp +// .getName().toString() + ".class"); +// String[] resources = classPath +// .findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } +// if (resources.length > 0) { +// String matchedClass = resources[0]; +// matchedClass = matchedClass +// .substring(0, matchedClass.length() - 6); +// matchedClass = matchedClass.replace('/', '.'); +// System.out.println("Matched class: " + matchedClass); +// System.out.println("Looking for match " + child.toString()); +// try { +// Class probableClass = Class +// .forName(matchedClass, false, +// errorCheckerService.classLoader); +// for (Method method : probableClass.getMethods()) { +// StringBuffer label = new StringBuffer(method.getName() +// + "("); +// for (Class type : method.getParameterTypes()) { +// label.append(type.getSimpleName() + ","); +// } +// label.append(")"); +// if (noCompare) +// candidates.add(label.toString()); +// else if (label.toString().startsWith(child.toString())) +// candidates.add(label.toString()); +// } +// for (Field field : probableClass.getFields()) { +// if (noCompare) +// +// candidates.add(field.getName()); +// else if (field.getName().startsWith(child.toString())) +// candidates.add(field.getName()); +// } +// } catch (ClassNotFoundException e) { +// e.printStackTrace(); +// System.out.println("Couldn't load " + matchedClass); +// } +// +// //processing/core/PVector.class +// // +// } + candidates = getMembersForType(stp.getName().toString(), + child.toString(), noCompare); } } @@ -613,6 +725,78 @@ public class ASTGenerator { } + public ArrayList getMembersForType(String typeName, String child, + boolean noCompare) { + ArrayList candidates = new ArrayList(); + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } + if (resources.length > 0) { + String matchedClass = resources[0]; + matchedClass = matchedClass.substring(0, matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + System.out.println("Matched class: " + matchedClass); + System.out.println("Looking for match " + child.toString()); + try { + Class probableClass = Class.forName(matchedClass, false, + errorCheckerService.classLoader); + + for (Method method : probableClass.getMethods()) { + StringBuffer label = new StringBuffer(method.getName() + "("); + for (Class type : method.getParameterTypes()) { + label.append(type.getSimpleName() + ","); + } + label.append(")"); + if (noCompare) + candidates.add(label.toString()); + else if (label.toString().startsWith(child.toString())) + candidates.add(label.toString()); + } + for (Field field : probableClass.getFields()) { + if (noCompare) + + candidates.add(field.getName()); + else if (field.getName().startsWith(child.toString())) + candidates.add(field.getName()); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.out.println("Couldn't load " + matchedClass); + } + } + if(candidates.size() > 0){ + String methodmatch = candidates.get(0); + System.out.println("jdoc match " + methodmatch); + for (final String key : jdocMap.keySet()) { + if(methodmatch.startsWith(key) && key.length() > 4) + { + System.out.println("Matched jdoc" +key); + jdocLabel.setText(jdocMap.get(key)); + visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + System.out.println(jdocMap.get(key)); + jdocLabel.repaint(); + } + }; + worker.execute(); + + break; + } + } + } + return candidates; + } + @SuppressWarnings("unchecked") private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { Iterator it = node diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index b8f44a05b..268720017 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -181,7 +181,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); //TODO: Remove this later - setBounds(160, 400, getWidth(), getHeight()); + setBounds(160, 300, getWidth(), getHeight()); } private void addXQModeUI(){ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index d09faf5c9..74d90c915 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -269,7 +269,7 @@ public class ErrorCheckerService implements Runnable{ // No syntax errors, proceed for compilation check, Stage 2. if (problems.length == 0 && editor.compilationCheckEnabled) { - mainClassOffset++; // just a hack. + //mainClassOffset++; // just a hack. astGenerator.buildAST(); sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); From d8f50815b76fa8b83259435b7688d3b0856ea210 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 19 Apr 2013 01:46:01 +0530 Subject: [PATCH 023/608] a barebones completion window implementaion --- .../mode/experimental/ASTGenerator.java | 167 +++++++++++++++--- .../mode/experimental/SuggestionPanel.java | 111 ++++++++++++ 2 files changed, 255 insertions(+), 23 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/SuggestionPanel.java diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 431fb4cfb..a3bca76fc 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,6 +1,9 @@ package processing.mode.experimental; +import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -21,9 +24,11 @@ import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTree; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.table.DefaultTableModel; +import javax.swing.text.BadLocationException; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -58,6 +63,7 @@ import org.jsoup.select.Elements; import processing.app.Base; import processing.app.SketchCode; +import processing.app.syntax.JEditTextArea; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; @@ -109,8 +115,125 @@ public class ASTGenerator { jdocWindow.setBounds(new Rectangle(280, 100, 460, 460)); jdocLabel = new JLabel(); jdocWindow.add(jdocLabel); - jdocMap = new TreeMap(); + jdocMap = new TreeMap(); //loadJars(); + + //addCompletionPopupListner(); + } + + private SuggestionPanel suggestion; + + JEditTextArea textarea; + + private void addCompletionPopupListner() { + textarea = errorCheckerService.getEditor().textArea(); + textarea.addKeyListener(new KeyListener() { + + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == KeyEvent.VK_ENTER) { + if (suggestion != null) { + if (suggestion.insertSelection()) { + e.consume(); + final int position = textarea.getCaretPosition(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + textarea.getDocument().remove(position - 1, 1); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + }); + } + } + } else if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE) { + System.out.println("BK Key"); + } + } + + @Override + public void keyReleased(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { + suggestion.moveDown(); + } else if (e.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { + suggestion.moveUp(); + } else if (Character.isLetterOrDigit(e.getKeyChar()) + || e.getKeyChar() == KeyEvent.VK_BACK_SPACE + || e.getKeyChar() == KeyEvent.VK_DELETE) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showSuggestion(); + } + + }); + } else if (Character.isWhitespace(e.getKeyChar())) { + hideSuggestion(); + } + } + + @Override + public void keyPressed(KeyEvent e) { + + } + }); + } + + protected void showSuggestionLater() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showSuggestion(); + } + + }); + } + + protected void showSuggestion() { + hideSuggestion(); + final int position = textarea.getCaretPosition(); + Point location = new Point(); + try { + location.x = textarea.offsetToX(textarea.getCaretLine(), position + - textarea.getLineStartOffset(textarea.getCaretLine())); + location.y = textarea.lineToY(textarea.getCaretLine()) + + textarea.getPainter().getFontMetrics().getHeight(); + } catch (Exception e2) { + e2.printStackTrace(); + return; + } + String text = textarea.getText(); + int start = Math.max(0, position - 1); + while (start > 0) { + if (!Character.isWhitespace(text.charAt(start))) { + start--; + } else { + start++; + break; + } + } + if (start > position) { + return; + } + final String subWord = text.substring(start, position); + if (subWord.length() < 2) { + return; + } + suggestion = new SuggestionPanel(textarea, position, subWord, location); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + textarea.requestFocusInWindow(); + } + }); + } + + private void hideSuggestion() { + if (suggestion != null) { + suggestion.hide(); + } } public class ASTNodeWrapper { @@ -189,11 +312,12 @@ public class ASTGenerator { frame2.setVisible(true); loadJars(); loadJavaDoc(); + addCompletionPopupListner(); //System.out.println(System.getProperty("java.home")); } if (!frameAutoComp.isVisible()) frameAutoComp.setVisible(true); - if(!jdocWindow.isVisible()) + if (!jdocWindow.isVisible()) jdocWindow.setVisible(true); jtree.validate(); } @@ -216,9 +340,6 @@ public class ASTGenerator { try { factory = new ClassPathFactory(); - String tehPaths = System.getProperty("java.class.path") - + File.pathSeparatorChar + System.getProperty("java.home") - + "/lib/rt.jar"; StringBuffer tehPath = new StringBuffer( System .getProperty("java.class.path") @@ -255,25 +376,26 @@ public class ASTGenerator { } } + private TreeMap jdocMap; + private void loadJavaDoc() { Document doc; - String primTypes[] = { - "void", "int", "short", "byte", "boolean", "char", "float", "double", - "long" }; +// String primTypes[] = { +// "void", "int", "short", "byte", "boolean", "char", "float", "double", +// "long" }; try { File javaDocFile = new File( "/home/quarkninja/Documents/Processing/libraries/SimpleOpenNI/documentation/SimpleOpenNI/SimpleOpenNI.html"); //SimpleOpenNI.SimpleOpenNI doc = Jsoup.parse(javaDocFile, null); - + String msg = ""; Elements elm = doc.getElementsByTag("pre"); - Elements desc = doc.getElementsByTag("dl"); +// Elements desc = doc.getElementsByTag("dl"); //System.out.println(elm.toString()); - for (Iterator iterator = elm.iterator(); iterator.hasNext();) { Element element = (Element) iterator.next(); @@ -281,10 +403,10 @@ public class ASTGenerator { // if (element.nextElementSibling() != null) // System.out.println(element.nextElementSibling().text()); System.out.println("-------------------"); - msg = "
    " - + element.html() - + element.nextElementSibling() - + "
    "; + msg = "
    " + + element.html() + + element.nextElementSibling() + + "
    "; String parts[] = element.text().split("\\s|\\(|,|\\)"); int i = 0; @@ -295,7 +417,7 @@ public class ASTGenerator { if (parts[i].equals("static") || parts[i].equals("final")) i++; // System.out.println("Ret Type " + parts[i]); - + i++; // return type // System.out.println("Name " + parts[i]); @@ -743,7 +865,7 @@ public class ASTGenerator { try { Class probableClass = Class.forName(matchedClass, false, errorCheckerService.classLoader); - + for (Method method : probableClass.getMethods()) { StringBuffer label = new StringBuffer(method.getName() + "("); for (Class type : method.getParameterTypes()) { @@ -767,13 +889,12 @@ public class ASTGenerator { System.out.println("Couldn't load " + matchedClass); } } - if(candidates.size() > 0){ + if (candidates.size() > 0) { String methodmatch = candidates.get(0); System.out.println("jdoc match " + methodmatch); for (final String key : jdocMap.keySet()) { - if(methodmatch.startsWith(key) && key.length() > 4) - { - System.out.println("Matched jdoc" +key); + if (methodmatch.startsWith(key) && key.length() > 4) { + System.out.println("Matched jdoc" + key); jdocLabel.setText(jdocMap.get(key)); visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); SwingWorker worker = new SwingWorker() { @@ -785,11 +906,11 @@ public class ASTGenerator { protected void done() { System.out.println(jdocMap.get(key)); - jdocLabel.repaint(); + jdocLabel.repaint(); } }; worker.execute(); - + break; } } diff --git a/pdex/src/processing/mode/experimental/SuggestionPanel.java b/pdex/src/processing/mode/experimental/SuggestionPanel.java new file mode 100644 index 000000000..671e63d18 --- /dev/null +++ b/pdex/src/processing/mode/experimental/SuggestionPanel.java @@ -0,0 +1,111 @@ +package processing.mode.experimental; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.JTextArea; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + +import processing.app.syntax.JEditTextArea; + +public class SuggestionPanel { + private JList list; + + private JPopupMenu popupMenu; + + private String subWord; + + private final int insertionPosition; + private JTextArea textarea; + + public SuggestionPanel(JEditTextArea textarea, int position, String subWord, + Point location) { + this.insertionPosition = position; + this.subWord = subWord; + popupMenu = new JPopupMenu(); + popupMenu.removeAll(); + popupMenu.setOpaque(false); + popupMenu.setBorder(null); + popupMenu.add(list = createSuggestionList(position, subWord), + BorderLayout.CENTER); + popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + + location.y); + } + + public void hide() { + popupMenu.setVisible(false); +// if (suggestion == this) { +// suggestion = null; +// } + } + + private JList createSuggestionList(final int position, final String subWord) { + Object[] data = new Object[10]; + for (int i = 0; i < data.length; i++) { + data[i] = subWord + i * 10; + } + JList list = new JList(data); + list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.setSelectedIndex(0); + list.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + insertSelection(); + } + } + }); + return list; + } + + public boolean insertSelection() { + if (list.getSelectedValue() != null) { + try { + final String selectedSuggestion = ((String) list.getSelectedValue()) + .substring(subWord.length()); + textarea.getDocument().insertString(insertionPosition, + selectedSuggestion, null); + return true; + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + hideSuggestion(); + } + return false; + } + + public void hideSuggestion() { + hide(); + } + + public void moveUp() { + int index = Math.min(list.getSelectedIndex() - 1, 0); + selectIndex(index); + } + + public void moveDown() { + int index = Math.min(list.getSelectedIndex() + 1, list.getModel() + .getSize() - 1); + selectIndex(index); + } + + private void selectIndex(int index) { + final int position = textarea.getCaretPosition(); + list.setSelectedIndex(index); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + textarea.setCaretPosition(position); + }; + }); + } + } \ No newline at end of file From cdbcee6b68c789b9e0c4f2a2bb2b922799a4cb87 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Apr 2013 10:39:29 +0530 Subject: [PATCH 024/608] further work on completion panel --- .../mode/experimental/ASTGenerator.java | 271 +++++++----------- .../mode/experimental/CompletionPanel.java | 144 ++++++++++ .../experimental/ErrorCheckerService.java | 2 +- .../mode/experimental/SuggestionPanel.java | 111 ------- .../mode/experimental/TextArea.java | 142 ++++++++- 5 files changed, 390 insertions(+), 280 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/CompletionPanel.java delete mode 100644 pdex/src/processing/mode/experimental/SuggestionPanel.java diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index a3bca76fc..9851ff66e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -121,121 +121,6 @@ public class ASTGenerator { //addCompletionPopupListner(); } - private SuggestionPanel suggestion; - - JEditTextArea textarea; - - private void addCompletionPopupListner() { - textarea = errorCheckerService.getEditor().textArea(); - textarea.addKeyListener(new KeyListener() { - - @Override - public void keyTyped(KeyEvent e) { - if (e.getKeyChar() == KeyEvent.VK_ENTER) { - if (suggestion != null) { - if (suggestion.insertSelection()) { - e.consume(); - final int position = textarea.getCaretPosition(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - textarea.getDocument().remove(position - 1, 1); - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - }); - } - } - } else if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE) { - System.out.println("BK Key"); - } - } - - @Override - public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { - suggestion.moveDown(); - } else if (e.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { - suggestion.moveUp(); - } else if (Character.isLetterOrDigit(e.getKeyChar()) - || e.getKeyChar() == KeyEvent.VK_BACK_SPACE - || e.getKeyChar() == KeyEvent.VK_DELETE) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - showSuggestion(); - } - - }); - } else if (Character.isWhitespace(e.getKeyChar())) { - hideSuggestion(); - } - } - - @Override - public void keyPressed(KeyEvent e) { - - } - }); - } - - protected void showSuggestionLater() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - showSuggestion(); - } - - }); - } - - protected void showSuggestion() { - hideSuggestion(); - final int position = textarea.getCaretPosition(); - Point location = new Point(); - try { - location.x = textarea.offsetToX(textarea.getCaretLine(), position - - textarea.getLineStartOffset(textarea.getCaretLine())); - location.y = textarea.lineToY(textarea.getCaretLine()) - + textarea.getPainter().getFontMetrics().getHeight(); - } catch (Exception e2) { - e2.printStackTrace(); - return; - } - String text = textarea.getText(); - int start = Math.max(0, position - 1); - while (start > 0) { - if (!Character.isWhitespace(text.charAt(start))) { - start--; - } else { - start++; - break; - } - } - if (start > position) { - return; - } - final String subWord = text.substring(start, position); - if (subWord.length() < 2) { - return; - } - suggestion = new SuggestionPanel(textarea, position, subWord, location); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - textarea.requestFocusInWindow(); - } - }); - } - - private void hideSuggestion() { - if (suggestion != null) { - suggestion.hide(); - } - } - public class ASTNodeWrapper { private ASTNode node; @@ -308,15 +193,17 @@ public class ASTGenerator { // return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) { - frame2.setVisible(true); +// if (!frame2.isVisible()) { +// frame2.setVisible(true); +// } + if (!frameAutoComp.isVisible()){ + frameAutoComp.setVisible(true); + long t = System.currentTimeMillis(); loadJars(); loadJavaDoc(); - addCompletionPopupListner(); - //System.out.println(System.getProperty("java.home")); + System.out.println("Time taken: " + + (System.currentTimeMillis() - t)); } - if (!frameAutoComp.isVisible()) - frameAutoComp.setVisible(true); if (!jdocWindow.isVisible()) jdocWindow.setVisible(true); jtree.validate(); @@ -324,7 +211,7 @@ public class ASTGenerator { } }; worker.execute(); - System.err.println("++>" + System.getProperty("java.class.path")); +// System.err.println("++>" + System.getProperty("java.class.path")); // System.out.println(System.getProperty("java.class.path")); // System.out.println("-------------------------------"); return codeTree; @@ -354,22 +241,20 @@ public class ASTGenerator { } //String paths[] = tehPaths.split(File.separatorChar +""); - StringTokenizer st = new StringTokenizer(tehPath.toString(), - File.pathSeparatorChar + ""); - while (st.hasMoreElements()) { - System.out.println("- " + st.nextToken()); - } +// StringTokenizer st = new StringTokenizer(tehPath.toString(), +// File.pathSeparatorChar + ""); + classPath = factory.createFromPath(tehPath.toString()); - for (String packageName : classPath.listPackages("")) { - System.out.println(packageName); - } +// for (String packageName : classPath.listPackages("")) { +// System.out.println(packageName); +// } RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( ".*", "Vec3D.class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -402,7 +287,7 @@ public class ASTGenerator { //System.out.println(element.text()); // if (element.nextElementSibling() != null) // System.out.println(element.nextElementSibling().text()); - System.out.println("-------------------"); + //System.out.println("-------------------"); msg = "
    " + element.html() + element.nextElementSibling() @@ -432,10 +317,10 @@ public class ASTGenerator { // } } System.out.println("JDoc loaded"); - for (String key : jdocMap.keySet()) { - System.out.println("Method: " + key); - System.out.println("Method: " + jdocMap.get(key)); - } +// for (String key : jdocMap.keySet()) { +// System.out.println("Method: " + key); +// System.out.println("Method: " + jdocMap.get(key)); +// } } catch (Exception e) { e.printStackTrace(); } @@ -491,14 +376,14 @@ public class ASTGenerator { List vdfs = null; switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: - return new String[] { getNodeAsString(node) }; + return new String[] { getNodeAsString2(node) }; case ASTNode.METHOD_DECLARATION: - String[] ret1 = new String[] { getNodeAsString(node) }; + String[] ret1 = new String[] { getNodeAsString2(node) }; return ret1; case ASTNode.SINGLE_VARIABLE_DECLARATION: - return new String[] { getNodeAsString(node) }; + return new String[] { getNodeAsString2(node) }; case ASTNode.FIELD_DECLARATION: vdfs = ((FieldDeclaration) node).fragments(); @@ -517,7 +402,7 @@ public class ASTGenerator { String ret[] = new String[vdfs.size()]; int i = 0; for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = getNodeAsString(vdf); + ret[i++] = getNodeAsString2(vdf); } return ret; } @@ -756,19 +641,19 @@ public class ASTGenerator { .fragments(); for (VariableDeclarationFragment vdf : vdfs) { if (noCompare) { - candidates.add(getNodeAsString(vdf)); + candidates.add(getNodeAsString2(vdf)); } else if (vdf.getName().toString() .startsWith(child.toString())) - candidates.add(getNodeAsString(vdf)); + candidates.add(getNodeAsString2(vdf)); } } for (int i = 0; i < td.getMethods().length; i++) { if (noCompare) { - candidates.add(getNodeAsString(td.getMethods()[i])); + candidates.add(getNodeAsString2(td.getMethods()[i])); } else if (td.getMethods()[i].getName().toString() .startsWith(child.toString())) - candidates.add(getNodeAsString(td.getMethods()[i])); + candidates.add(getNodeAsString2(td.getMethods()[i])); } } else { if (stp != null) { @@ -830,6 +715,7 @@ public class ASTGenerator { } String[][] candi = new String[candidates.size()][1]; + for (int i = 0; i < candi.length; i++) { candi[i][0] = candidates.get(i); } @@ -840,6 +726,13 @@ public class ASTGenerator { tableAuto.setModel(tm); tableAuto.validate(); tableAuto.repaint(); + //String[] items = + String[] candi2 = candidates.toArray(new String[candidates + .size()]); + errorCheckerService + .getEditor() + .textArea() + .showSuggestion(candi2); } }; @@ -868,9 +761,11 @@ public class ASTGenerator { for (Method method : probableClass.getMethods()) { StringBuffer label = new StringBuffer(method.getName() + "("); - for (Class type : method.getParameterTypes()) { - label.append(type.getSimpleName() + ","); + for (int i = 0; i < method.getParameterTypes().length; i++) { + if(i < method.getParameterTypes().length - 1) + label.append(method.getParameterTypes()[i].getSimpleName() + ","); } + label.append(")"); if (noCompare) candidates.add(label.toString()); @@ -891,26 +786,22 @@ public class ASTGenerator { } if (candidates.size() > 0) { String methodmatch = candidates.get(0); + if(methodmatch.indexOf('(') != -1){ + methodmatch = methodmatch.substring(0, methodmatch.indexOf('(') - 1); + } System.out.println("jdoc match " + methodmatch); for (final String key : jdocMap.keySet()) { - if (methodmatch.startsWith(key) && key.length() > 4) { + if (key.startsWith(methodmatch) && key.length() > 3) { System.out.println("Matched jdoc" + key); - jdocLabel.setText(jdocMap.get(key)); - visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); - SwingWorker worker = new SwingWorker() { - + + //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingUtilities.invokeLater(new Runnable() { + @Override - protected Object doInBackground() throws Exception { - return null; + public void run() { + jdocLabel.setText(jdocMap.get(key)); } - - protected void done() { - System.out.println(jdocMap.get(key)); - jdocLabel.repaint(); - } - }; - worker.execute(); - + }); break; } } @@ -1851,6 +1742,58 @@ public class ASTGenerator { .getStartPosition()); return value; } + + /** + * CompletionPanel name + * @param node + * @return + */ + static private String getNodeAsString2(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString(); + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString(); + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString(); + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName().toString() ; + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (node instanceof QualifiedName) + value = node.toString(); + else if (node instanceof VariableDeclarationFragment) + value = ((VariableDeclarationFragment)node).getName().toString(); + else if (className.startsWith("Variable")) + value = node.toString() ; + else if (node instanceof VariableDeclarationStatement) + value = ((VariableDeclarationStatement)node).toString(); + else if (className.endsWith("Type")) + value = node.toString() ; +// value += " [" + node.getStartPosition() + "," +// + (node.getStartPosition() + node.getLength()) + "]"; +// value += " Line: " +// + ((CompilationUnit) node.getRoot()).getLineNumber(node +// .getStartPosition()); + return value; + } + public static String readFile(String path) { BufferedReader reader = null; diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java new file mode 100644 index 000000000..86209cbc6 --- /dev/null +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -0,0 +1,144 @@ +package processing.mode.experimental; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.JTextArea; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + +import processing.app.syntax.JEditTextArea; + +public class CompletionPanel { + private JList list; + + private JPopupMenu popupMenu; + + private String subWord; + + private final int insertionPosition; + + private JEditTextArea textarea; + + public CompletionPanel(JEditTextArea textarea, int position, String subWord, + String[] items, Point location) { + this.textarea = textarea; + this.insertionPosition = position; + if (subWord.indexOf('.') != -1) + this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); + else + this.subWord = subWord; + popupMenu = new JPopupMenu(); + popupMenu.removeAll(); + popupMenu.setOpaque(false); + popupMenu.setBorder(null); + popupMenu.add(list = createSuggestionList(position, items), + BorderLayout.CENTER); + popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + + location.y); + } + + public void hide() { + popupMenu.setVisible(false); + } + + public boolean isVisible() { + return popupMenu.isVisible(); + } + +// private JList createSuggestionList(final int position, final String subWord) { +// Object[] data = new Object[10]; +// for (int i = 0; i < data.length; i++) { +// data[i] = subWord + i * 10; +// } +// JList list = new JList(data); +// list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); +// list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); +// list.setSelectedIndex(0); +// list.addMouseListener(new MouseAdapter() { +// @Override +// public void mouseClicked(MouseEvent e) { +// if (e.getClickCount() == 2) { +// insertSelection(); +// } +// } +// }); +// return list; +// } + + public JList createSuggestionList(final int position, final String[] items) { + + JList list = new JList(items); + list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.setSelectedIndex(0); + list.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + insertSelection(); + } + } + }); + return list; + } + + public boolean insertSelection() { + if (list.getSelectedValue() != null) { + try { + final String selectedSuggestion = ((String) list.getSelectedValue()) + .substring(subWord.length()); + textarea.getDocument().insertString(insertionPosition, + selectedSuggestion, null); + textarea.setCaretPosition(insertionPosition + + selectedSuggestion.length()); + return true; + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + hideSuggestion(); + } + return false; + } + + public void hideSuggestion() { + hide(); + } + + public void moveUp() { + if (list.getSelectedIndex() == 0) { + selectIndex(list.getModel().getSize() - 1); + } else { + int index = Math.max(list.getSelectedIndex() - 1, 0); + selectIndex(index); + } + } + + public void moveDown() { + if (list.getSelectedIndex() == list.getModel().getSize() - 1) { + selectIndex(0); + } else { + int index = Math.min(list.getSelectedIndex() + 1, list.getModel() + .getSize() - 1); + selectIndex(index); + } + } + + private void selectIndex(int index) { + list.setSelectedIndex(index); +// final int position = textarea.getCaretPosition(); +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// textarea.setCaretPosition(position); +// }; +// }); + } +} \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 74d90c915..57d6ab3dd 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -733,7 +733,7 @@ public class ErrorCheckerService implements Runnable{ // String[] lines = {};// = PApplet.split(sourceString, '\n'); int codeIndex = 0; - int x = problem.getSourceLineNumber() - mainClassOffset + 1; + int x = problem.getSourceLineNumber() - mainClassOffset; if (x < 0) { // System.out.println("Negative line number " // + problem.getSourceLineNumber() + " , offset " diff --git a/pdex/src/processing/mode/experimental/SuggestionPanel.java b/pdex/src/processing/mode/experimental/SuggestionPanel.java deleted file mode 100644 index 671e63d18..000000000 --- a/pdex/src/processing/mode/experimental/SuggestionPanel.java +++ /dev/null @@ -1,111 +0,0 @@ -package processing.mode.experimental; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.BorderFactory; -import javax.swing.JList; -import javax.swing.JPopupMenu; -import javax.swing.JTextArea; -import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; -import javax.swing.text.BadLocationException; - -import processing.app.syntax.JEditTextArea; - -public class SuggestionPanel { - private JList list; - - private JPopupMenu popupMenu; - - private String subWord; - - private final int insertionPosition; - private JTextArea textarea; - - public SuggestionPanel(JEditTextArea textarea, int position, String subWord, - Point location) { - this.insertionPosition = position; - this.subWord = subWord; - popupMenu = new JPopupMenu(); - popupMenu.removeAll(); - popupMenu.setOpaque(false); - popupMenu.setBorder(null); - popupMenu.add(list = createSuggestionList(position, subWord), - BorderLayout.CENTER); - popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) - + location.y); - } - - public void hide() { - popupMenu.setVisible(false); -// if (suggestion == this) { -// suggestion = null; -// } - } - - private JList createSuggestionList(final int position, final String subWord) { - Object[] data = new Object[10]; - for (int i = 0; i < data.length; i++) { - data[i] = subWord + i * 10; - } - JList list = new JList(data); - list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); - list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.setSelectedIndex(0); - list.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - insertSelection(); - } - } - }); - return list; - } - - public boolean insertSelection() { - if (list.getSelectedValue() != null) { - try { - final String selectedSuggestion = ((String) list.getSelectedValue()) - .substring(subWord.length()); - textarea.getDocument().insertString(insertionPosition, - selectedSuggestion, null); - return true; - } catch (BadLocationException e1) { - e1.printStackTrace(); - } - hideSuggestion(); - } - return false; - } - - public void hideSuggestion() { - hide(); - } - - public void moveUp() { - int index = Math.min(list.getSelectedIndex() - 1, 0); - selectIndex(index); - } - - public void moveDown() { - int index = Math.min(list.getSelectedIndex() + 1, list.getModel() - .getSize() - 1); - selectIndex(index); - } - - private void selectIndex(int index) { - final int position = textarea.getCaretPosition(); - list.setSelectedIndex(index); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - textarea.setCaretPosition(position); - }; - }); - } - } \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 0e18de79b..a2c7782a7 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -20,14 +20,19 @@ package processing.mode.experimental; import java.awt.Color; import java.awt.Cursor; import java.awt.FontMetrics; +import java.awt.Point; import java.awt.event.ComponentListener; import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.HashMap; import java.util.Map; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + import processing.app.syntax.JEditTextArea; import processing.app.syntax.TextAreaDefaults; @@ -94,7 +99,7 @@ public class TextArea extends JEditTextArea { MouseHandler mouseHandler = new MouseHandler(); painter.addMouseListener(mouseHandler); painter.addMouseMotionListener(mouseHandler); - + addCompletionPopupListner(); add(CENTER, painter); // load settings from theme.txt @@ -121,6 +126,44 @@ public class TextArea extends JEditTextArea { } public void processKeyEvent(KeyEvent evt) { + if (evt.getID() == KeyEvent.KEY_PRESSED) { + if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { + if (suggestion.isVisible()) { + //System.out.println("KeyDown"); + suggestion.moveDown(); + return; + } + } else if (evt.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { + if (suggestion.isVisible()) { + //System.out.println("KeyUp"); + suggestion.moveUp(); + return; + } + } + if (evt.getKeyChar() == KeyEvent.VK_ENTER) { + if (suggestion != null) { + if (suggestion.isVisible()){ + if (suggestion.insertSelection()) { + final int position = getCaretPosition(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + //getDocument().remove(position - 1, 1); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + return; + } + } + } + } else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) { + System.out.println("BK Key"); + } + } + super.processKeyEvent(evt); if (evt.getID() == KeyEvent.KEY_TYPED) { errorCheckerService.textModified.incrementAndGet(); @@ -181,9 +224,8 @@ public class TextArea extends JEditTextArea { //TODO: currently works on single line only. "a. b()" won't be detected if (x1 >= 0) { // if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') - if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' - || s.charAt(x1) == '.' || s.charAt(x1) == ')') - { + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' + || s.charAt(x1) == '.' || s.charAt(x1) == ')') { if (s.charAt(x1) == ')') { word = s.charAt(x1--) + word; @@ -232,6 +274,7 @@ public class TextArea extends JEditTextArea { // word = word.substring(0, word.length() - 1); errorCheckerService.astGenerator.updatePredictions(word, line + errorCheckerService.mainClassOffset); + //showSuggestionLater(); return word; //} @@ -491,4 +534,95 @@ public class TextArea extends JEditTextArea { } } + private CompletionPanel suggestion; + + //JEditTextArea textarea; + + private void addCompletionPopupListner() { + this.addKeyListener(new KeyListener() { + + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void keyReleased(KeyEvent e) { + if (Character.isLetterOrDigit(e.getKeyChar()) + || e.getKeyChar() == KeyEvent.VK_BACK_SPACE + || e.getKeyChar() == KeyEvent.VK_DELETE) { +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// showSuggestion(); +// } +// +// }); + } else if (Character.isWhitespace(e.getKeyChar())) { + hideSuggestion(); + } + } + + @Override + public void keyPressed(KeyEvent e) { + } + }); + } + + public void showSuggestionLater(final String[] items) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showSuggestion(items); + } + + }); + } + + protected void showSuggestion(String[] items) { + hideSuggestion(); + final int position = getCaretPosition(); + Point location = new Point(); + try { + location.x = offsetToX(getCaretLine(), position + - getLineStartOffset(getCaretLine())); + location.y = lineToY(getCaretLine()) + + getPainter().getFontMetrics().getHeight(); + } catch (Exception e2) { + e2.printStackTrace(); + return; + } + String text = getText(); + int start = Math.max(0, position - 1); + while (start > 0) { + if (!Character.isWhitespace(text.charAt(start))) { + start--; + } else { + start++; + break; + } + } + if (start > position) { + return; + } + final String subWord = text.substring(start, position); + if (subWord.length() < 2) { + return; + } + suggestion = new CompletionPanel(this, position, subWord, items, location); + requestFocusInWindow(); +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// requestFocusInWindow(); +// } +// }); + } + + private void hideSuggestion() { + if (suggestion != null) { + suggestion.hide(); + } + } + } From e519f1711aaa412ce66a3f5d963e1ad1d4885602 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Apr 2013 19:06:28 +0530 Subject: [PATCH 025/608] further work on cc --- .../mode/experimental/ASTGenerator.java | 336 +++++++++--------- .../experimental/CompletionCandidate.java | 39 ++ .../mode/experimental/CompletionPanel.java | 40 +-- .../mode/experimental/TextArea.java | 6 +- 4 files changed, 227 insertions(+), 194 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/CompletionCandidate.java diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9851ff66e..f20872177 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -18,6 +18,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.JFrame; import javax.swing.JLabel; @@ -112,7 +114,6 @@ public class ASTGenerator { jdocWindow = new JFrame(); jdocWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - jdocWindow.setBounds(new Rectangle(280, 100, 460, 460)); jdocLabel = new JLabel(); jdocWindow.add(jdocLabel); jdocMap = new TreeMap(); @@ -196,7 +197,8 @@ public class ASTGenerator { // if (!frame2.isVisible()) { // frame2.setVisible(true); // } - if (!frameAutoComp.isVisible()){ + if (!frameAutoComp.isVisible()) { + frameAutoComp.setVisible(true); long t = System.currentTimeMillis(); loadJars(); @@ -204,8 +206,13 @@ public class ASTGenerator { System.out.println("Time taken: " + (System.currentTimeMillis() - t)); } - if (!jdocWindow.isVisible()) + if (!jdocWindow.isVisible()) { + jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() + .getX() + errorCheckerService.getEditor().getWidth(), + errorCheckerService.getEditor() + .getY(), 400, 400)); jdocWindow.setVisible(true); + } jtree.validate(); } } @@ -265,65 +272,80 @@ public class ASTGenerator { private TreeMap jdocMap; private void loadJavaDoc() { - Document doc; + + // presently loading only p5 reference for PApplet + Thread t = new Thread(new Runnable() { -// String primTypes[] = { -// "void", "int", "short", "byte", "boolean", "char", "float", "double", -// "long" }; - try { - File javaDocFile = new File( - "/home/quarkninja/Documents/Processing/libraries/SimpleOpenNI/documentation/SimpleOpenNI/SimpleOpenNI.html"); - //SimpleOpenNI.SimpleOpenNI - doc = Jsoup.parse(javaDocFile, null); + @Override + public void run() { + Document doc; - String msg = ""; - Elements elm = doc.getElementsByTag("pre"); -// Elements desc = doc.getElementsByTag("dl"); - //System.out.println(elm.toString()); + Pattern pat = Pattern.compile("\\w+"); + try { + File javaDocFile = new File( + "/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html"); + //SimpleOpenNI.SimpleOpenNI + doc = Jsoup.parse(javaDocFile, null); - for (Iterator iterator = elm.iterator(); iterator.hasNext();) { - Element element = (Element) iterator.next(); + String msg = ""; + Elements elm = doc.getElementsByTag("pre"); +// Elements desc = doc.getElementsByTag("dl"); + //System.out.println(elm.toString()); - //System.out.println(element.text()); -// if (element.nextElementSibling() != null) -// System.out.println(element.nextElementSibling().text()); - //System.out.println("-------------------"); - msg = "
    " - + element.html() - + element.nextElementSibling() - + "
    "; + for (Iterator iterator = elm.iterator(); iterator.hasNext();) { + Element element = (Element) iterator.next(); - String parts[] = element.text().split("\\s|\\(|,|\\)"); - int i = 0; - if (parts[i].equals("public")) - i++; - if (parts[i].equals("static") || parts[i].equals("final")) - i++; - if (parts[i].equals("static") || parts[i].equals("final")) - i++; -// System.out.println("Ret Type " + parts[i]); + //System.out.println(element.text()); +// if (element.nextElementSibling() != null) +// System.out.println(element.nextElementSibling().text()); + //System.out.println("-------------------"); + msg = "
    " + + element.html() + + element.nextElementSibling() + + "
    "; + int k = 0; + Matcher matcher = pat.matcher(element.text()); + ArrayList parts = new ArrayList(); + while (matcher.find()) { +// System.out.print("Start index: " + matcher.start()); +// System.out.print(" End index: " + matcher.end() + " "); + if (k == 0 && !matcher.group().equals("public")) { + k = -1; + break; + } + // System.out.print(matcher.group() + " "); + parts.add(matcher.group()); + k++; + } + if (k <= 0 || parts.size() < 3) + continue; + int i = 0; + if (parts.get(i).equals("public")) + i++; + if (parts.get(i).equals("static") || parts.get(i).equals("final") + || parts.get(i).equals("class")) + i++; + if (parts.get(i).equals("static") || parts.get(i).equals("final")) + i++; +// System.out.println("Ret Type " + parts.get(i)); - i++; // return type + i++; // return type - // System.out.println("Name " + parts[i]); - jdocMap.put(parts[i], msg); -// if (parts[i].startsWith("draw")) { -// match = element.text(); -// msg = "
    " -// + element.html() -// + element.nextElementSibling() -// + "
    "; -// System.out.println(match + " " + msg); -// } + //System.out.println("Name " + parts.get(i)); + jdocMap.put(parts.get(i), msg); + } + System.out.println("JDoc loaded"); +// for (String key : jdocMap.keySet()) { +// System.out.println("Method: " + key); +// System.out.println("Method: " + jdocMap.get(key)); +// } + } catch (Exception e) { + e.printStackTrace(); + } } - System.out.println("JDoc loaded"); -// for (String key : jdocMap.keySet()) { -// System.out.println("Method: " + key); -// System.out.println("Method: " + jdocMap.get(key)); -// } - } catch (Exception e) { - e.printStackTrace(); - } + }); + t.start(); + } public DefaultMutableTreeNode buildAST() { @@ -371,19 +393,31 @@ public class ASTGenerator { return null; } - public static String[] checkForTypes(ASTNode node) { + public static CompletionCandidate[] checkForTypes(ASTNode node) { List vdfs = null; switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: - return new String[] { getNodeAsString2(node) }; + return new CompletionCandidate[] { new CompletionCandidate( + getNodeAsString2(node), + ((TypeDeclaration) node) + .getName() + .toString()) }; case ASTNode.METHOD_DECLARATION: - String[] ret1 = new String[] { getNodeAsString2(node) }; - return ret1; + MethodDeclaration md = (MethodDeclaration) node; + List params = (List) md + .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); + CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1]; + cand[0] = new CompletionCandidate(md.getName().toString()); + for (int i = 0; i < params.size(); i++) { + cand[i + 1] = new CompletionCandidate(params.get(i).toString()); + } + return cand; case ASTNode.SINGLE_VARIABLE_DECLARATION: - return new String[] { getNodeAsString2(node) }; + return new CompletionCandidate[] { new CompletionCandidate( + getNodeAsString2(node)) }; case ASTNode.FIELD_DECLARATION: vdfs = ((FieldDeclaration) node).fragments(); @@ -399,10 +433,10 @@ public class ASTGenerator { } if (vdfs != null) { - String ret[] = new String[vdfs.size()]; + CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()]; int i = 0; for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = getNodeAsString2(vdf); + ret[i++] = new CompletionCandidate(getNodeAsString2(vdf)); } return ret; } @@ -539,7 +573,7 @@ public class ASTGenerator { System.err.println(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(anode)); - ArrayList candidates = new ArrayList(); + ArrayList candidates = new ArrayList(); // Determine the expression typed @@ -557,8 +591,8 @@ public class ASTGenerator { SimpleType st = (SimpleType) td .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); System.out.println("Superclass " + st.getName()); - for (String can : getMembersForType(st.getName().toString(), - word2, noCompare)) { + for (CompletionCandidate can : getMembersForType(st.getName() + .toString(), word2, noCompare)) { candidates.add(can); } //findDeclaration(st.getName()) @@ -572,10 +606,10 @@ public class ASTGenerator { if (!sprop.isChildListProperty()) { if (anode.getStructuralProperty(sprop) instanceof ASTNode) { cnode = (ASTNode) anode.getStructuralProperty(sprop); - String[] types = checkForTypes(cnode); + CompletionCandidate[] types = checkForTypes(cnode); if (types != null) { for (int i = 0; i < types.length; i++) { - if (types[i].startsWith(word2)) + if (types[i].getElementName().startsWith(word2)) candidates.add(types[i]); } } @@ -585,10 +619,10 @@ public class ASTGenerator { List nodelist = (List) anode .getStructuralProperty(sprop); for (ASTNode clnode : nodelist) { - String[] types = checkForTypes(clnode); + CompletionCandidate[] types = checkForTypes(clnode); if (types != null) { for (int i = 0; i < types.length; i++) { - if (types[i].startsWith(word2)) + if (types[i].getElementName().startsWith(word2)) candidates.add(types[i]); } } @@ -641,70 +675,26 @@ public class ASTGenerator { .fragments(); for (VariableDeclarationFragment vdf : vdfs) { if (noCompare) { - candidates.add(getNodeAsString2(vdf)); + candidates + .add(new CompletionCandidate(getNodeAsString2(vdf))); } else if (vdf.getName().toString() .startsWith(child.toString())) - candidates.add(getNodeAsString2(vdf)); + candidates + .add(new CompletionCandidate(getNodeAsString2(vdf))); } } for (int i = 0; i < td.getMethods().length; i++) { if (noCompare) { - candidates.add(getNodeAsString2(td.getMethods()[i])); + candidates.add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString())); } else if (td.getMethods()[i].getName().toString() .startsWith(child.toString())) - candidates.add(getNodeAsString2(td.getMethods()[i])); + candidates.add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString())); } } else { if (stp != null) { -// System.out.println("Couldn't determine type! " -// + stp.getName().toString()); -// RegExpResourceFilter regExpResourceFilter; -// regExpResourceFilter = new RegExpResourceFilter(".*", stp -// .getName().toString() + ".class"); -// String[] resources = classPath -// .findResources("", regExpResourceFilter); -// for (String className : resources) { -// System.out.println("-> " + className); -// } -// if (resources.length > 0) { -// String matchedClass = resources[0]; -// matchedClass = matchedClass -// .substring(0, matchedClass.length() - 6); -// matchedClass = matchedClass.replace('/', '.'); -// System.out.println("Matched class: " + matchedClass); -// System.out.println("Looking for match " + child.toString()); -// try { -// Class probableClass = Class -// .forName(matchedClass, false, -// errorCheckerService.classLoader); -// for (Method method : probableClass.getMethods()) { -// StringBuffer label = new StringBuffer(method.getName() -// + "("); -// for (Class type : method.getParameterTypes()) { -// label.append(type.getSimpleName() + ","); -// } -// label.append(")"); -// if (noCompare) -// candidates.add(label.toString()); -// else if (label.toString().startsWith(child.toString())) -// candidates.add(label.toString()); -// } -// for (Field field : probableClass.getFields()) { -// if (noCompare) -// -// candidates.add(field.getName()); -// else if (field.getName().startsWith(child.toString())) -// candidates.add(field.getName()); -// } -// } catch (ClassNotFoundException e) { -// e.printStackTrace(); -// System.out.println("Couldn't load " + matchedClass); -// } -// -// //processing/core/PVector.class -// // -// } candidates = getMembersForType(stp.getName().toString(), child.toString(), noCompare); } @@ -714,7 +704,8 @@ public class ASTGenerator { } - String[][] candi = new String[candidates.size()][1]; + CompletionCandidate[][] candi = new CompletionCandidate[candidates + .size()][1]; for (int i = 0; i < candi.length; i++) { candi[i][0] = candidates.get(i); @@ -727,12 +718,10 @@ public class ASTGenerator { tableAuto.validate(); tableAuto.repaint(); //String[] items = - String[] candi2 = candidates.toArray(new String[candidates - .size()]); - errorCheckerService - .getEditor() - .textArea() - .showSuggestion(candi2); + CompletionCandidate[] candi2 = candidates + .toArray(new CompletionCandidate[candidates.size()]); + if (candidates.size() > 0) + errorCheckerService.getEditor().textArea().showSuggestion(candi2); } }; @@ -740,9 +729,10 @@ public class ASTGenerator { } - public ArrayList getMembersForType(String typeName, String child, - boolean noCompare) { - ArrayList candidates = new ArrayList(); + public ArrayList getMembersForType(String typeName, + String child, + boolean noCompare) { + ArrayList candidates = new ArrayList(); RegExpResourceFilter regExpResourceFilter; regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); String[] resources = classPath.findResources("", regExpResourceFilter); @@ -762,51 +752,67 @@ public class ASTGenerator { for (Method method : probableClass.getMethods()) { StringBuffer label = new StringBuffer(method.getName() + "("); for (int i = 0; i < method.getParameterTypes().length; i++) { - if(i < method.getParameterTypes().length - 1) - label.append(method.getParameterTypes()[i].getSimpleName() + ","); + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); } - + label.append(")"); if (noCompare) - candidates.add(label.toString()); + candidates.add(new CompletionCandidate(method.getName(), + matchedClass, label + .toString())); else if (label.toString().startsWith(child.toString())) - candidates.add(label.toString()); + candidates.add(new CompletionCandidate(method.getName(), + matchedClass, label + .toString())); } for (Field field : probableClass.getFields()) { if (noCompare) - candidates.add(field.getName()); + candidates.add(new CompletionCandidate(field.getName(), + matchedClass)); else if (field.getName().startsWith(child.toString())) - candidates.add(field.getName()); + candidates.add(new CompletionCandidate(field.getName(), + matchedClass)); } } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("Couldn't load " + matchedClass); } } - if (candidates.size() > 0) { - String methodmatch = candidates.get(0); - if(methodmatch.indexOf('(') != -1){ - methodmatch = methodmatch.substring(0, methodmatch.indexOf('(') - 1); - } - System.out.println("jdoc match " + methodmatch); - for (final String key : jdocMap.keySet()) { - if (key.startsWith(methodmatch) && key.length() > 3) { - System.out.println("Matched jdoc" + key); - - //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { + //updateJavaDoc(methodmatch) + + return candidates; + } + + public void updateJavaDoc(final CompletionCandidate candidate) { + String methodmatch = candidate.toString(); + if (methodmatch.indexOf('(') != -1) { + methodmatch = methodmatch.substring(0, methodmatch.indexOf('(')); + } + + //System.out.println("jdoc match " + methodmatch); + for (final String key : jdocMap.keySet()) { + if (key.startsWith(methodmatch) && key.length() > 3) { + System.out.println("Matched jdoc " + key); + + //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + System.out.println("Class: " + candidate.getDefiningClass()); + if (candidate.getDefiningClass().equals("processing.core.PApplet")) jdocLabel.setText(jdocMap.get(key)); - } - }); - break; - } + else + jdocLabel.setText(""); + } + }); + break; } } - return candidates; + } @SuppressWarnings("unchecked") @@ -1742,9 +1748,10 @@ public class ASTGenerator { .getStartPosition()); return value; } - + /** - * CompletionPanel name + * CompletionPanel name + * * @param node * @return */ @@ -1771,7 +1778,7 @@ public class ASTGenerator { else if (node instanceof FieldDeclaration) value = ((FieldDeclaration) node).toString(); else if (node instanceof SingleVariableDeclaration) - value = ((SingleVariableDeclaration) node).getName().toString() ; + value = ((SingleVariableDeclaration) node).getName().toString(); else if (node instanceof ExpressionStatement) value = node.toString() + className; else if (node instanceof SimpleName) @@ -1779,13 +1786,13 @@ public class ASTGenerator { else if (node instanceof QualifiedName) value = node.toString(); else if (node instanceof VariableDeclarationFragment) - value = ((VariableDeclarationFragment)node).getName().toString(); + value = ((VariableDeclarationFragment) node).getName().toString(); else if (className.startsWith("Variable")) - value = node.toString() ; + value = node.toString(); else if (node instanceof VariableDeclarationStatement) - value = ((VariableDeclarationStatement)node).toString(); + value = ((VariableDeclarationStatement) node).toString(); else if (className.endsWith("Type")) - value = node.toString() ; + value = node.toString(); // value += " [" + node.getStartPosition() + "," // + (node.getStartPosition() + node.getLength()) + "]"; // value += " Line: " @@ -1793,7 +1800,6 @@ public class ASTGenerator { // .getStartPosition()); return value; } - public static String readFile(String path) { BufferedReader reader = null; diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java new file mode 100644 index 000000000..e18c17463 --- /dev/null +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -0,0 +1,39 @@ +package processing.mode.experimental; + +public class CompletionCandidate { + + private String definingClass; + private String elementName; + private String label; + + public CompletionCandidate(String name, String className, String label){ + definingClass = className; + elementName = name; + this.label = label; + } + + public CompletionCandidate(String name, String className){ + definingClass = className; + elementName = name; + label = name; + } + + public CompletionCandidate(String name){ + definingClass = ""; + elementName = name; + label = name; + } + + public String getDefiningClass() { + return definingClass; + } + + public String getElementName() { + return elementName; + } + + public String toString(){ + return label; + } + +} diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 86209cbc6..03f0450dc 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -9,9 +9,7 @@ import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.JList; import javax.swing.JPopupMenu; -import javax.swing.JTextArea; import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import processing.app.syntax.JEditTextArea; @@ -25,11 +23,11 @@ public class CompletionPanel { private final int insertionPosition; - private JEditTextArea textarea; + private TextArea textarea; public CompletionPanel(JEditTextArea textarea, int position, String subWord, - String[] items, Point location) { - this.textarea = textarea; + CompletionCandidate[] items, Point location) { + this.textarea = (TextArea) textarea; this.insertionPosition = position; if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); @@ -43,6 +41,8 @@ public class CompletionPanel { BorderLayout.CENTER); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); + this.textarea.errorCheckerService.astGenerator.updateJavaDoc((CompletionCandidate) list + .getSelectedValue()); } public void hide() { @@ -53,27 +53,7 @@ public class CompletionPanel { return popupMenu.isVisible(); } -// private JList createSuggestionList(final int position, final String subWord) { -// Object[] data = new Object[10]; -// for (int i = 0; i < data.length; i++) { -// data[i] = subWord + i * 10; -// } -// JList list = new JList(data); -// list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); -// list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); -// list.setSelectedIndex(0); -// list.addMouseListener(new MouseAdapter() { -// @Override -// public void mouseClicked(MouseEvent e) { -// if (e.getClickCount() == 2) { -// insertSelection(); -// } -// } -// }); -// return list; -// } - - public JList createSuggestionList(final int position, final String[] items) { + public JList createSuggestionList(final int position, final CompletionCandidate[] items) { JList list = new JList(items); list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); @@ -84,6 +64,7 @@ public class CompletionPanel { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { insertSelection(); + hideSuggestion(); } } }); @@ -93,7 +74,7 @@ public class CompletionPanel { public boolean insertSelection() { if (list.getSelectedValue() != null) { try { - final String selectedSuggestion = ((String) list.getSelectedValue()) + final String selectedSuggestion = ((CompletionCandidate) list.getSelectedValue()).toString() .substring(subWord.length()); textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null); @@ -119,6 +100,9 @@ public class CompletionPanel { int index = Math.max(list.getSelectedIndex() - 1, 0); selectIndex(index); } + textarea.errorCheckerService.astGenerator.updateJavaDoc((CompletionCandidate) list + .getSelectedValue()); + } public void moveDown() { @@ -129,6 +113,8 @@ public class CompletionPanel { .getSize() - 1); selectIndex(index); } + textarea.errorCheckerService.astGenerator.updateJavaDoc((CompletionCandidate) list + .getSelectedValue()); } private void selectIndex(int index) { diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index a2c7782a7..0092ed36d 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -191,6 +191,8 @@ public class TextArea extends JEditTextArea { //System.out.print(s + " len " + s.length()); int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + if(x >= s.length() || x < 0) + return null; //TODO: Does this check cause problems? Verify. System.out.print(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); char keyChar = evt.getKeyChar(); @@ -569,7 +571,7 @@ public class TextArea extends JEditTextArea { }); } - public void showSuggestionLater(final String[] items) { + public void showSuggestionLater(final CompletionCandidate[] items) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { @@ -579,7 +581,7 @@ public class TextArea extends JEditTextArea { }); } - protected void showSuggestion(String[] items) { + protected void showSuggestion(CompletionCandidate[] items) { hideSuggestion(); final int position = getCaretPosition(); Point location = new Point(); From 7ce2291b64f3cb6f9513baf22655db2bcffbcd17 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 21 Apr 2013 01:40:41 +0530 Subject: [PATCH 026/608] better everythang \m/ --- .../mode/experimental/ASTGenerator.java | 215 +++++++++--------- .../mode/experimental/CompletionPanel.java | 45 +++- .../experimental/ErrorCheckerService.java | 2 +- .../mode/experimental/JavadocHelper.java | 122 ++++++++++ .../mode/experimental/TextArea.java | 14 +- 5 files changed, 269 insertions(+), 129 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/JavadocHelper.java diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index f20872177..f42c7b8ff 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -6,12 +6,14 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.BufferedReader; import java.io.File; +import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; @@ -21,6 +23,7 @@ import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; @@ -69,6 +72,7 @@ import processing.app.syntax.JEditTextArea; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; +import com.google.classpath.DirectoryClassPath.FileFileFilter; import com.google.classpath.RegExpResourceFilter; import com.ibm.icu.util.StringTokenizer; @@ -90,7 +94,9 @@ public class ASTGenerator { private JTable tableAuto; - private JLabel jdocLabel; + private JEditorPane javadocPane; + + private JScrollPane scrollPane; public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; @@ -113,9 +119,15 @@ public class ASTGenerator { frameAutoComp.add(sp2); jdocWindow = new JFrame(); - jdocWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - jdocLabel = new JLabel(); - jdocWindow.add(jdocLabel); + jdocWindow.setTitle("P5 InstaHelp"); + //jdocWindow.setUndecorated(true); + jdocWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + javadocPane = new JEditorPane(); + javadocPane.setContentType("text/html"); + javadocPane.setEditable(false); + scrollPane = new JScrollPane(); + scrollPane.setViewportView(javadocPane); + jdocWindow.add(scrollPane); jdocMap = new TreeMap(); //loadJars(); @@ -164,23 +176,28 @@ public class ASTGenerator { } } - private DefaultMutableTreeNode buildAST2(String source) { - ASTParser parser = ASTParser.newParser(AST.JLS4); - parser.setSource(source.toCharArray()); - parser.setKind(ASTParser.K_COMPILATION_UNIT); + private DefaultMutableTreeNode buildAST2(String source, CompilationUnit cu) { + if (cu == null) { + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); - Map options = JavaCore.getOptions(); + Map options = JavaCore.getOptions(); - JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); - options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - parser.setCompilerOptions(options); - compilationUnit = (CompilationUnit) parser.createAST(null); + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + compilationUnit = (CompilationUnit) parser.createAST(null); + } else { + compilationUnit = cu; + System.out.println("Other cu"); + } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); - codeTree = new DefaultMutableTreeNode( - getNodeAsString((ASTNode) compilationUnit - .types().get(0))); - visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); +// codeTree = new DefaultMutableTreeNode( +// getNodeAsString((ASTNode) compilationUnit +// .types().get(0))); +// visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); SwingWorker worker = new SwingWorker() { @Override @@ -210,7 +227,7 @@ public class ASTGenerator { jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() .getX() + errorCheckerService.getEditor().getWidth(), errorCheckerService.getEditor() - .getY(), 400, 400)); + .getY(), 450, 600)); jdocWindow.setVisible(true); } jtree.validate(); @@ -240,28 +257,32 @@ public class ASTGenerator { + File.pathSeparatorChar + System .getProperty("java.home") - + "/lib/rt.jar"); + + "/lib/rt.jar"+ File.pathSeparatorChar); if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { tehPath.append(jarPath.getPath() + File.pathSeparatorChar); } } - //String paths[] = tehPaths.split(File.separatorChar +""); -// StringTokenizer st = new StringTokenizer(tehPath.toString(), -// File.pathSeparatorChar + ""); +// String paths[] = tehPath.toString().split(File.separatorChar +""); + StringTokenizer st = new StringTokenizer(tehPath.toString(), + File.pathSeparatorChar + ""); + while (st.hasMoreElements()) { + String sstr = (String) st.nextElement(); + System.out.println(sstr); + } classPath = factory.createFromPath(tehPath.toString()); -// for (String packageName : classPath.listPackages("")) { -// System.out.println(packageName); -// } + for (String packageName : classPath.listPackages("")) { + System.out.println(packageName); + } RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( ".*", - "Vec3D.class"); -// String[] resources = classPath.findResources("", regExpResourceFilter); -// for (String className : resources) { -// System.out.println("-> " + className); -// } + "ArrayList.class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -272,84 +293,21 @@ public class ASTGenerator { private TreeMap jdocMap; private void loadJavaDoc() { - + // presently loading only p5 reference for PApplet Thread t = new Thread(new Runnable() { @Override public void run() { - Document doc; - - Pattern pat = Pattern.compile("\\w+"); - try { - File javaDocFile = new File( - "/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html"); - //SimpleOpenNI.SimpleOpenNI - doc = Jsoup.parse(javaDocFile, null); - - String msg = ""; - Elements elm = doc.getElementsByTag("pre"); -// Elements desc = doc.getElementsByTag("dl"); - //System.out.println(elm.toString()); - - for (Iterator iterator = elm.iterator(); iterator.hasNext();) { - Element element = (Element) iterator.next(); - - //System.out.println(element.text()); -// if (element.nextElementSibling() != null) -// System.out.println(element.nextElementSibling().text()); - //System.out.println("-------------------"); - msg = "
    " - + element.html() - + element.nextElementSibling() - + "
    "; - int k = 0; - Matcher matcher = pat.matcher(element.text()); - ArrayList parts = new ArrayList(); - while (matcher.find()) { -// System.out.print("Start index: " + matcher.start()); -// System.out.print(" End index: " + matcher.end() + " "); - if (k == 0 && !matcher.group().equals("public")) { - k = -1; - break; - } - // System.out.print(matcher.group() + " "); - parts.add(matcher.group()); - k++; - } - if (k <= 0 || parts.size() < 3) - continue; - int i = 0; - if (parts.get(i).equals("public")) - i++; - if (parts.get(i).equals("static") || parts.get(i).equals("final") - || parts.get(i).equals("class")) - i++; - if (parts.get(i).equals("static") || parts.get(i).equals("final")) - i++; -// System.out.println("Ret Type " + parts.get(i)); - - i++; // return type - - //System.out.println("Name " + parts.get(i)); - jdocMap.put(parts.get(i), msg); - } - System.out.println("JDoc loaded"); -// for (String key : jdocMap.keySet()) { -// System.out.println("Method: " + key); -// System.out.println("Method: " + jdocMap.get(key)); -// } - } catch (Exception e) { - e.printStackTrace(); - } + JavadocHelper.loadJavaDoc(jdocMap); } }); t.start(); } - public DefaultMutableTreeNode buildAST() { - return buildAST2(errorCheckerService.sourceCode); + public DefaultMutableTreeNode buildAST(CompilationUnit cu) { + return buildAST2(errorCheckerService.sourceCode,cu); } public String[] checkForTypes2(ASTNode node) { @@ -570,6 +528,9 @@ public class ASTGenerator { System.err.print("Typed: " + word2 + "|"); anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); + if(anode == null) + //Make sure anode is not NULL if couldn't find a closeset node + anode = (ASTNode)compilationUnit.types().get(0); System.err.println(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(anode)); @@ -592,7 +553,7 @@ public class ASTGenerator { .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); System.out.println("Superclass " + st.getName()); for (CompletionCandidate can : getMembersForType(st.getName() - .toString(), word2, noCompare)) { + .toString(), word2, noCompare,false)) { candidates.add(can); } //findDeclaration(st.getName()) @@ -696,11 +657,22 @@ public class ASTGenerator { } else { if (stp != null) { candidates = getMembersForType(stp.getName().toString(), - child.toString(), noCompare); + child.toString(), noCompare,false); } } } + else if(word.length() - word2.length() == 1){ +// int dC = 0; +// for (int i = 0; i < word.length(); i++) { +// if(word.charAt(i) == '.') +// dC++; +// } +// if(dC == 1 && word.charAt(word.length() - 1) == '.'){ + System.out.println("All members of " + word2); + candidates = getMembersForType(word2, "", true,true); +// } + } } @@ -729,9 +701,16 @@ public class ASTGenerator { } + /** + * Loads classes from .jar files in sketch classpath + * @param typeName + * @param child + * @param noCompare + * @return + */ public ArrayList getMembersForType(String typeName, String child, - boolean noCompare) { + boolean noCompare,boolean staticOnly) { ArrayList candidates = new ArrayList(); RegExpResourceFilter regExpResourceFilter; regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); @@ -750,6 +729,8 @@ public class ASTGenerator { errorCheckerService.classLoader); for (Method method : probableClass.getMethods()) { + if(!Modifier.isStatic(method.getModifiers()) && staticOnly) + continue; StringBuffer label = new StringBuffer(method.getName() + "("); for (int i = 0; i < method.getParameterTypes().length; i++) { label.append(method.getParameterTypes()[i].getSimpleName()); @@ -768,6 +749,8 @@ public class ASTGenerator { .toString())); } for (Field field : probableClass.getFields()) { + if(!Modifier.isStatic(field.getModifiers()) && staticOnly) + continue; if (noCompare) candidates.add(new CompletionCandidate(field.getName(), @@ -804,14 +787,19 @@ public class ASTGenerator { System.out.println("Class: " + candidate.getDefiningClass()); if (candidate.getDefiningClass().equals("processing.core.PApplet")) - jdocLabel.setText(jdocMap.get(key)); + { javadocPane.setText(jdocMap.get(key)); + //jdocWindow.setVisible(true); + //editor.textArea().requestFocus() + } else - jdocLabel.setText(""); + javadocPane.setText(""); + javadocPane.setCaretPosition(0); } }); break; } } + //jdocWindow.setVisible(false); } @@ -876,15 +864,18 @@ public class ASTGenerator { return null; } - ASTNode retNode = nodes.get(0); - for (ASTNode cNode : nodes) { - if (getLineNumber(cNode) <= lineNumber) - retNode = cNode; - else - break; - } + if (nodes.size() > 0) { + ASTNode retNode = nodes.get(0); + for (ASTNode cNode : nodes) { + if (getLineNumber(cNode) <= lineNumber) + retNode = cNode; + else + break; + } - return retNode; + return retNode; + } + return null; } // static DefaultMutableTreeNode findNodeBS(DefaultMutableTreeNode tree, @@ -1800,6 +1791,10 @@ public class ASTGenerator { // .getStartPosition()); return value; } + + public void jdocWindowVisible(boolean visible){ + jdocWindow.setVisible(visible); + } public static String readFile(String path) { BufferedReader reader = null; diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 03f0450dc..6d5eeb130 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -9,6 +9,7 @@ import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.JList; import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.text.BadLocationException; @@ -25,6 +26,8 @@ public class CompletionPanel { private TextArea textarea; + private JScrollPane scrollPane; + public CompletionPanel(JEditTextArea textarea, int position, String subWord, CompletionCandidate[] items, Point location) { this.textarea = (TextArea) textarea; @@ -37,12 +40,14 @@ public class CompletionPanel { popupMenu.removeAll(); popupMenu.setOpaque(false); popupMenu.setBorder(null); - popupMenu.add(list = createSuggestionList(position, items), - BorderLayout.CENTER); + scrollPane = new JScrollPane(); + scrollPane.setViewportView(list = createSuggestionList(position, items)); + popupMenu.add(scrollPane, BorderLayout.CENTER); + this.textarea.errorCheckerService.astGenerator + .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - this.textarea.errorCheckerService.astGenerator.updateJavaDoc((CompletionCandidate) list - .getSelectedValue()); + } public void hide() { @@ -53,7 +58,8 @@ public class CompletionPanel { return popupMenu.isVisible(); } - public JList createSuggestionList(final int position, final CompletionCandidate[] items) { + public JList createSuggestionList(final int position, + final CompletionCandidate[] items) { JList list = new JList(items); list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); @@ -74,8 +80,8 @@ public class CompletionPanel { public boolean insertSelection() { if (list.getSelectedValue() != null) { try { - final String selectedSuggestion = ((CompletionCandidate) list.getSelectedValue()).toString() - .substring(subWord.length()); + final String selectedSuggestion = ((CompletionCandidate) list + .getSelectedValue()).toString().substring(subWord.length()); textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null); textarea.setCaretPosition(insertionPosition @@ -91,30 +97,47 @@ public class CompletionPanel { public void hideSuggestion() { hide(); + //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); } public void moveUp() { if (list.getSelectedIndex() == 0) { + scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); selectIndex(list.getModel().getSize() - 1); + return; } else { int index = Math.max(list.getSelectedIndex() - 1, 0); selectIndex(index); } - textarea.errorCheckerService.astGenerator.updateJavaDoc((CompletionCandidate) list - .getSelectedValue()); + int step = scrollPane.getVerticalScrollBar().getMaximum() + / list.getModel().getSize(); + scrollPane.getVerticalScrollBar().setValue(scrollPane + .getVerticalScrollBar() + .getValue() + - step); + textarea.errorCheckerService.astGenerator + .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); } public void moveDown() { if (list.getSelectedIndex() == list.getModel().getSize() - 1) { + scrollPane.getVerticalScrollBar().setValue(0); selectIndex(0); + return; } else { int index = Math.min(list.getSelectedIndex() + 1, list.getModel() .getSize() - 1); selectIndex(index); } - textarea.errorCheckerService.astGenerator.updateJavaDoc((CompletionCandidate) list - .getSelectedValue()); + textarea.errorCheckerService.astGenerator + .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + int step = scrollPane.getVerticalScrollBar().getMaximum() + / list.getModel().getSize(); + scrollPane.getVerticalScrollBar().setValue(scrollPane + .getVerticalScrollBar() + .getValue() + + step); } private void selectIndex(int index) { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 57d6ab3dd..fbdfbb953 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -270,7 +270,7 @@ public class ErrorCheckerService implements Runnable{ if (problems.length == 0 && editor.compilationCheckEnabled) { //mainClassOffset++; // just a hack. - astGenerator.buildAST(); + astGenerator.buildAST(cu); sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); // mainClassOffset = xqpreproc.mainClassOffset; // tiny, but diff --git a/pdex/src/processing/mode/experimental/JavadocHelper.java b/pdex/src/processing/mode/experimental/JavadocHelper.java new file mode 100644 index 000000000..7f59da5ab --- /dev/null +++ b/pdex/src/processing/mode/experimental/JavadocHelper.java @@ -0,0 +1,122 @@ +package processing.mode.experimental; + +import java.io.File; +import java.io.FileFilter; +import java.util.Iterator; +import java.util.TreeMap; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +public class JavadocHelper { + + public static void loadJavaDoc(TreeMap jdocMap){ + Document doc; + + //Pattern pat = Pattern.compile("\\w+"); + try { + File p5Ref = new File( + "/home/quarkninja/Workspaces/processing-workspace/processing/build/linux/work/modes/java/reference"); + FileFilter fileFilter = new FileFilter() { + public boolean accept(File file) { + if(!file.getName().endsWith("_.html")) + return false; + int k = 0; + for (int i = 0; i < file.getName().length(); i++) { + if(file.getName().charAt(i)== '_') + k++; + if(k > 1) + return false; + } + return true; + } + }; + + for (File docFile : p5Ref.listFiles(fileFilter)) { + + doc = Jsoup.parse(docFile, null); + Elements elm = doc.getElementsByClass("ref-item"); + String msg = ""; + String methodName = docFile.getName().substring(0, docFile.getName().indexOf('_')); + //System.out.println(methodName); + for (Iterator it = elm.iterator(); it.hasNext();) { + Element ele = (Element) it.next(); + msg = "
    " + + ele.html() + "
    "; + //mat.replaceAll(""); + msg = msg.replaceAll("img src=\"", "img src=\"" + + p5Ref.toURI().toURL().toString() + "/"); + //System.out.println(ele.text()); + } + jdocMap.put(methodName, msg); + } + + /* File javaDocFile = new File( + "/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html"); + //SimpleOpenNI.SimpleOpenNI + doc = Jsoup.parse(javaDocFile, null); + + String msg = ""; + Elements elm = doc.getElementsByTag("pre"); +// Elements desc = doc.getElementsByTag("dl"); + //System.out.println(elm.toString()); + + for (Iterator iterator = elm.iterator(); iterator.hasNext();) { + Element element = (Element) iterator.next(); + + //System.out.println(element.text()); +// if (element.nextElementSibling() != null) +// System.out.println(element.nextElementSibling().text()); + //System.out.println("-------------------"); + msg = "
    " + + element.html() + + element.nextElementSibling() + + "
    "; + int k = 0; + Matcher matcher = pat.matcher(element.text()); + ArrayList parts = new ArrayList(); + while (matcher.find()) { +// System.out.print("Start index: " + matcher.start()); +// System.out.print(" End index: " + matcher.end() + " "); + if (k == 0 && !matcher.group().equals("public")) { + k = -1; + break; + } + // System.out.print(matcher.group() + " "); + parts.add(matcher.group()); + k++; + } + if (k <= 0 || parts.size() < 3) + continue; + int i = 0; + if (parts.get(i).equals("public")) + i++; + if (parts.get(i).equals("static") || parts.get(i).equals("final") + || parts.get(i).equals("class")) + i++; + if (parts.get(i).equals("static") || parts.get(i).equals("final")) + i++; +// System.out.println("Ret Type " + parts.get(i)); + + i++; // return type + + //System.out.println("Name " + parts.get(i)); + jdocMap.put(parts.get(i), msg); + } + System.out.println("JDoc loaded"); +// for (String key : jdocMap.keySet()) { +// System.out.println("Method: " + key); +// System.out.println("Method: " + jdocMap.get(key)); +// } + * + */ + } catch (Exception e) { + e.printStackTrace(); + } + + + } + +} diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 0092ed36d..e07cda0b3 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -612,13 +612,13 @@ public class TextArea extends JEditTextArea { return; } suggestion = new CompletionPanel(this, position, subWord, items, location); - requestFocusInWindow(); -// SwingUtilities.invokeLater(new Runnable() { -// @Override -// public void run() { -// requestFocusInWindow(); -// } -// }); +// requestFocusInWindow(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + requestFocusInWindow(); + } + }); } private void hideSuggestion() { From 1a174ed4d5811eae0b2fde3e08db59a8dfc49f64 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 21 Apr 2013 15:17:58 +0530 Subject: [PATCH 027/608] refining stuff --- .../mode/experimental/ASTGenerator.java | 86 +++++++++---------- .../experimental/CompletionCandidate.java | 73 +++++++++++++++- 2 files changed, 111 insertions(+), 48 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index f42c7b8ff..1db31a42c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -253,11 +253,9 @@ public class ASTGenerator { StringBuffer tehPath = new StringBuffer( System - .getProperty("java.class.path") - + File.pathSeparatorChar - + System - .getProperty("java.home") - + "/lib/rt.jar"+ File.pathSeparatorChar); + .getProperty("java.class.path")); + tehPath.append(+File.pathSeparatorChar + System.getProperty("java.home") + + "/lib/rt.jar" + File.pathSeparatorChar); if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { tehPath.append(jarPath.getPath() + File.pathSeparatorChar); @@ -307,7 +305,7 @@ public class ASTGenerator { } public DefaultMutableTreeNode buildAST(CompilationUnit cu) { - return buildAST2(errorCheckerService.sourceCode,cu); + return buildAST2(errorCheckerService.sourceCode, cu); } public String[] checkForTypes2(ASTNode node) { @@ -364,18 +362,20 @@ public class ASTGenerator { case ASTNode.METHOD_DECLARATION: MethodDeclaration md = (MethodDeclaration) node; + System.out.println(getNodeAsString(md)); List params = (List) md .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1]; - cand[0] = new CompletionCandidate(md.getName().toString()); + cand[0] = new CompletionCandidate(md); for (int i = 0; i < params.size(); i++) { - cand[i + 1] = new CompletionCandidate(params.get(i).toString()); + cand[i + 1] = new CompletionCandidate(params.get(i).toString(), "", "", + CompletionCandidate.LOCAL_VAR); } return cand; case ASTNode.SINGLE_VARIABLE_DECLARATION: return new CompletionCandidate[] { new CompletionCandidate( - getNodeAsString2(node)) }; + getNodeAsString2(node),"","",CompletionCandidate.LOCAL_VAR) }; case ASTNode.FIELD_DECLARATION: vdfs = ((FieldDeclaration) node).fragments(); @@ -394,7 +394,7 @@ public class ASTGenerator { CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()]; int i = 0; for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = new CompletionCandidate(getNodeAsString2(vdf)); + ret[i++] = new CompletionCandidate(getNodeAsString2(vdf),"","",CompletionCandidate.LOCAL_VAR); } return ret; } @@ -528,9 +528,9 @@ public class ASTGenerator { System.err.print("Typed: " + word2 + "|"); anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); - if(anode == null) - //Make sure anode is not NULL if couldn't find a closeset node - anode = (ASTNode)compilationUnit.types().get(0); + if (anode == null) + //Make sure anode is not NULL if couldn't find a closeset node + anode = (ASTNode) compilationUnit.types().get(0); System.err.println(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(anode)); @@ -553,7 +553,7 @@ public class ASTGenerator { .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); System.out.println("Superclass " + st.getName()); for (CompletionCandidate can : getMembersForType(st.getName() - .toString(), word2, noCompare,false)) { + .toString(), word2, noCompare, false)) { candidates.add(can); } //findDeclaration(st.getName()) @@ -647,22 +647,26 @@ public class ASTGenerator { } for (int i = 0; i < td.getMethods().length; i++) { if (noCompare) { - candidates.add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString())); + candidates + .add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString(), "", + CompletionCandidate.METHOD)); } else if (td.getMethods()[i].getName().toString() .startsWith(child.toString())) - candidates.add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString())); + candidates + .add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString(), "", + CompletionCandidate.METHOD)); } } else { if (stp != null) { candidates = getMembersForType(stp.getName().toString(), - child.toString(), noCompare,false); + child.toString(), noCompare, + false); } } - } - else if(word.length() - word2.length() == 1){ + } else if (word.length() - word2.length() == 1) { // int dC = 0; // for (int i = 0; i < word.length(); i++) { // if(word.charAt(i) == '.') @@ -670,7 +674,7 @@ public class ASTGenerator { // } // if(dC == 1 && word.charAt(word.length() - 1) == '.'){ System.out.println("All members of " + word2); - candidates = getMembersForType(word2, "", true,true); + candidates = getMembersForType(word2, "", true, true); // } } @@ -703,6 +707,7 @@ public class ASTGenerator { /** * Loads classes from .jar files in sketch classpath + * * @param typeName * @param child * @param noCompare @@ -710,7 +715,8 @@ public class ASTGenerator { */ public ArrayList getMembersForType(String typeName, String child, - boolean noCompare,boolean staticOnly) { + boolean noCompare, + boolean staticOnly) { ArrayList candidates = new ArrayList(); RegExpResourceFilter regExpResourceFilter; regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); @@ -729,7 +735,7 @@ public class ASTGenerator { errorCheckerService.classLoader); for (Method method : probableClass.getMethods()) { - if(!Modifier.isStatic(method.getModifiers()) && staticOnly) + if (!Modifier.isStatic(method.getModifiers()) && staticOnly) continue; StringBuffer label = new StringBuffer(method.getName() + "("); for (int i = 0; i < method.getParameterTypes().length; i++) { @@ -740,24 +746,17 @@ public class ASTGenerator { label.append(")"); if (noCompare) - candidates.add(new CompletionCandidate(method.getName(), - matchedClass, label - .toString())); + candidates.add(new CompletionCandidate(method)); else if (label.toString().startsWith(child.toString())) - candidates.add(new CompletionCandidate(method.getName(), - matchedClass, label - .toString())); + candidates.add(new CompletionCandidate(method)); } for (Field field : probableClass.getFields()) { - if(!Modifier.isStatic(field.getModifiers()) && staticOnly) + if (!Modifier.isStatic(field.getModifiers()) && staticOnly) continue; if (noCompare) - - candidates.add(new CompletionCandidate(field.getName(), - matchedClass)); + candidates.add(new CompletionCandidate(field)); else if (field.getName().startsWith(child.toString())) - candidates.add(new CompletionCandidate(field.getName(), - matchedClass)); + candidates.add(new CompletionCandidate(field)); } } catch (ClassNotFoundException e) { e.printStackTrace(); @@ -786,12 +785,11 @@ public class ASTGenerator { public void run() { System.out.println("Class: " + candidate.getDefiningClass()); - if (candidate.getDefiningClass().equals("processing.core.PApplet")) - { javadocPane.setText(jdocMap.get(key)); - //jdocWindow.setVisible(true); - //editor.textArea().requestFocus() - } - else + if (candidate.getDefiningClass().equals("processing.core.PApplet")) { + javadocPane.setText(jdocMap.get(key)); + //jdocWindow.setVisible(true); + //editor.textArea().requestFocus() + } else javadocPane.setText(""); javadocPane.setCaretPosition(0); } @@ -1791,8 +1789,8 @@ public class ASTGenerator { // .getStartPosition()); return value; } - - public void jdocWindowVisible(boolean visible){ + + public void jdocWindowVisible(boolean visible) { jdocWindow.setVisible(visible); } diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index e18c17463..ebf8bddf3 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -1,15 +1,72 @@ package processing.mode.experimental; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.MethodDeclaration; + public class CompletionCandidate { private String definingClass; - private String elementName; - private String label; + private String elementName; // + private String label; // the toString value + private String completionString; + private int type; + public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3; - public CompletionCandidate(String name, String className, String label){ + public CompletionCandidate(String name, String className, String label, int TYPE){ definingClass = className; elementName = name; - this.label = label; + if(label.length() > 0) + this.label = label; + else + this.label = name; + this.type = TYPE; + if(type == METHOD){ + this.label += "()"; + } + + } + + public CompletionCandidate(Method method){ + definingClass = method.getDeclaringClass().getName(); + elementName = method.getName(); + type = METHOD; + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); + } + + label.append(")"); + this.label = label.toString(); + } + + public CompletionCandidate(MethodDeclaration method){ + definingClass = ""; + elementName = method.getName().toString(); + type = METHOD; + List params = (List) method + .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); + StringBuffer label = new StringBuffer(elementName + "("); + for (int i = 0; i < params.size(); i++) { + label.append(params.get(i).toString()); + if (i < params.size() - 1) + label.append(","); + } + label.append(")"); + this.label = label.toString(); + } + + + public CompletionCandidate(Field f){ + definingClass = f.getDeclaringClass().getName(); + elementName = f.getName(); + type = FIELD; + label = f.getName(); } public CompletionCandidate(String name, String className){ @@ -31,9 +88,17 @@ public class CompletionCandidate { public String getElementName() { return elementName; } + + public String getCompletionString(){ + return completionString; + } public String toString(){ return label; } + + public int getType(){ + return type; + } } From 8469bf795c3faed97428bfd46d782f99c55b325c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 21 Apr 2013 20:45:43 +0530 Subject: [PATCH 028/608] Ready for demo --- .../mode/experimental/ASTGenerator.java | 34 ++++++---- .../experimental/CompletionCandidate.java | 68 ++++++++++++------- .../mode/experimental/CompletionPanel.java | 2 +- .../experimental/ErrorCheckerService.java | 3 +- .../mode/experimental/JavadocHelper.java | 14 ++-- 5 files changed, 76 insertions(+), 45 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1db31a42c..5b887b35b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -254,7 +254,7 @@ public class ASTGenerator { StringBuffer tehPath = new StringBuffer( System .getProperty("java.class.path")); - tehPath.append(+File.pathSeparatorChar + System.getProperty("java.home") + tehPath.append(File.pathSeparatorChar + System.getProperty("java.home") + "/lib/rt.jar" + File.pathSeparatorChar); if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { @@ -271,18 +271,18 @@ public class ASTGenerator { } classPath = factory.createFromPath(tehPath.toString()); - for (String packageName : classPath.listPackages("")) { - System.out.println(packageName); - } - RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( - ".*", - "ArrayList.class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } +// for (String packageName : classPath.listPackages("")) { +// System.out.println(packageName); +// } +// RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( +// ".*", +// "ArrayList.class"); +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } + System.out.println("jars loaded."); } catch (Exception e) { - // TODO Auto-generated catch block e.printStackTrace(); } @@ -297,7 +297,7 @@ public class ASTGenerator { @Override public void run() { - JavadocHelper.loadJavaDoc(jdocMap); + JavadocHelper.loadJavaDoc(jdocMap,editor.mode().getReferenceFolder()); } }); t.start(); @@ -667,6 +667,7 @@ public class ASTGenerator { } } else if (word.length() - word2.length() == 1) { + System.out.println(word +" w2 " + word2); // int dC = 0; // for (int i = 0; i < word.length(); i++) { // if(word.charAt(i) == '.') @@ -677,6 +678,13 @@ public class ASTGenerator { candidates = getMembersForType(word2, "", true, true); // } } + else{ + System.out.println("Some members of " + word2); + int x = word2.indexOf('.'); + if(x != -1){ + candidates = getMembersForType(word2.substring(0, x), word2.substring(x+1), false, true); + } + } } diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index ebf8bddf3..5f3f0d740 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -10,75 +10,93 @@ import org.eclipse.jdt.core.dom.MethodDeclaration; public class CompletionCandidate { private String definingClass; + private String elementName; // + private String label; // the toString value + private String completionString; + private int type; - public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3; - - public CompletionCandidate(String name, String className, String label, int TYPE){ + + public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3; + + public CompletionCandidate(String name, String className, String label, + int TYPE) { definingClass = className; elementName = name; - if(label.length() > 0) + if (label.length() > 0) this.label = label; else this.label = name; this.type = TYPE; - if(type == METHOD){ + if (type == METHOD) { this.label += "()"; } - + completionString = this.label; } - - public CompletionCandidate(Method method){ + + public CompletionCandidate(Method method) { definingClass = method.getDeclaringClass().getName(); elementName = method.getName(); type = METHOD; StringBuffer label = new StringBuffer(method.getName() + "("); + StringBuffer cstr = new StringBuffer(method.getName() + "("); for (int i = 0; i < method.getParameterTypes().length; i++) { label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) + if (i < method.getParameterTypes().length - 1) { label.append(","); + cstr.append(","); + } } label.append(")"); + cstr.append(")"); this.label = label.toString(); + this.completionString = cstr.toString(); } - - public CompletionCandidate(MethodDeclaration method){ + + public CompletionCandidate(MethodDeclaration method) { definingClass = ""; elementName = method.getName().toString(); type = METHOD; List params = (List) method .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); StringBuffer label = new StringBuffer(elementName + "("); + StringBuffer cstr = new StringBuffer(method.getName() + "("); for (int i = 0; i < params.size(); i++) { label.append(params.get(i).toString()); - if (i < params.size() - 1) + if (i < params.size() - 1){ label.append(","); + cstr.append(","); + } } label.append(")"); + cstr.append(")"); this.label = label.toString(); + this.completionString = cstr.toString(); } - - - public CompletionCandidate(Field f){ + + public CompletionCandidate(Field f) { definingClass = f.getDeclaringClass().getName(); elementName = f.getName(); type = FIELD; label = f.getName(); + completionString = elementName; } - - public CompletionCandidate(String name, String className){ + + public CompletionCandidate(String name, String className) { definingClass = className; elementName = name; label = name; + completionString = name; } - - public CompletionCandidate(String name){ + + public CompletionCandidate(String name) { definingClass = ""; elementName = name; label = name; + completionString = name; } public String getDefiningClass() { @@ -88,16 +106,16 @@ public class CompletionCandidate { public String getElementName() { return elementName; } - - public String getCompletionString(){ + + public String getCompletionString() { return completionString; } - - public String toString(){ + + public String toString() { return label; } - - public int getType(){ + + public int getType() { return type; } diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 6d5eeb130..3e0f7678d 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -81,7 +81,7 @@ public class CompletionPanel { if (list.getSelectedValue() != null) { try { final String selectedSuggestion = ((CompletionCandidate) list - .getSelectedValue()).toString().substring(subWord.length()); + .getSelectedValue()).getCompletionString().substring(subWord.length()); textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null); textarea.setCaretPosition(insertionPosition diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index fbdfbb953..cd1c181d4 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -182,6 +182,7 @@ public class ErrorCheckerService implements Runnable{ PdePreprocessor pdePrepoc = new PdePreprocessor(null); defaultImportsOffset = pdePrepoc.getCoreImports().length + pdePrepoc.getDefaultImports().length + 1; + astGenerator = new ASTGenerator(this); } /** @@ -256,7 +257,7 @@ public class ErrorCheckerService implements Runnable{ } } - ASTGenerator astGenerator = new ASTGenerator(this); + protected ASTGenerator astGenerator; AtomicInteger textModified = new AtomicInteger(); private boolean checkCode() { System.out.println("checkCode() " + textModified.get() ); diff --git a/pdex/src/processing/mode/experimental/JavadocHelper.java b/pdex/src/processing/mode/experimental/JavadocHelper.java index 7f59da5ab..7cc582072 100644 --- a/pdex/src/processing/mode/experimental/JavadocHelper.java +++ b/pdex/src/processing/mode/experimental/JavadocHelper.java @@ -12,13 +12,17 @@ import org.jsoup.select.Elements; public class JavadocHelper { - public static void loadJavaDoc(TreeMap jdocMap){ + public static void loadJavaDoc(TreeMap jdocMap, File p5Ref){ Document doc; //Pattern pat = Pattern.compile("\\w+"); try { - File p5Ref = new File( - "/home/quarkninja/Workspaces/processing-workspace/processing/build/linux/work/modes/java/reference"); + if (p5Ref == null) { + System.out.println("P5 Ref location null"); + p5Ref = new File( + "/home/quarkninja/Workspaces/processing-workspace/processing/build/linux/work/modes/java/reference"); + } + FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { if(!file.getName().endsWith("_.html")) @@ -52,7 +56,7 @@ public class JavadocHelper { } jdocMap.put(methodName, msg); } - + System.out.println("JDoc loaded "+jdocMap.size()); /* File javaDocFile = new File( "/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html"); //SimpleOpenNI.SimpleOpenNI @@ -105,7 +109,7 @@ public class JavadocHelper { //System.out.println("Name " + parts.get(i)); jdocMap.put(parts.get(i), msg); } - System.out.println("JDoc loaded"); + // for (String key : jdocMap.keySet()) { // System.out.println("Method: " + key); // System.out.println("Method: " + jdocMap.get(key)); From 3b1a6babc1c0604968eb7d2ccd3b1d1f141efe30 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 25 Apr 2013 11:53:45 +0530 Subject: [PATCH 029/608] minor edits --- .../processing/mode/experimental/ASTGenerator.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 5b887b35b..6d7b8096e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -214,16 +214,17 @@ public class ASTGenerator { // if (!frame2.isVisible()) { // frame2.setVisible(true); // } - if (!frameAutoComp.isVisible()) { - - frameAutoComp.setVisible(true); +// if (!frameAutoComp.isVisible()) { +// +// frameAutoComp.setVisible(true); +// +// } + if (!jdocWindow.isVisible()) { long t = System.currentTimeMillis(); loadJars(); loadJavaDoc(); System.out.println("Time taken: " + (System.currentTimeMillis() - t)); - } - if (!jdocWindow.isVisible()) { jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() .getX() + errorCheckerService.getEditor().getWidth(), errorCheckerService.getEditor() From b4248d587629200cbde2cc48964d28c053411d15 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 27 Apr 2013 15:38:17 -0400 Subject: [PATCH 030/608] switch to socket attach connector, fix error msg for bitness of libs, fighting with Eclipse JDI --- .../mode/experimental/DebugRunner.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugRunner.java b/pdex/src/processing/mode/experimental/DebugRunner.java index f438a7023..1f810d964 100755 --- a/pdex/src/processing/mode/experimental/DebugRunner.java +++ b/pdex/src/processing/mode/experimental/DebugRunner.java @@ -44,18 +44,18 @@ public class DebugRunner extends processing.mode.java.runner.Runner { * @return debuggee VM or null on failure */ public VirtualMachine launch() { - String[] machineParamList = getMachineParams(); - String[] sketchParamList = getSketchParams(); - /* - * System.out.println("vm launch sketch params:"); for (int i=0; - * i Date: Sat, 27 Apr 2013 18:55:51 -0400 Subject: [PATCH 031/608] add notes about JDI --- pdex/mode/readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pdex/mode/readme.txt b/pdex/mode/readme.txt index 3ec74a7e8..2152b63de 100644 --- a/pdex/mode/readme.txt +++ b/pdex/mode/readme.txt @@ -1,3 +1,5 @@ Packages from Eclipse 4.2.1: http://download.eclipse.org/eclipse/downloads/ +The jdi.jar and jdimodel.jar files are unpacked +from the org.eclipse.jdt.debug JAR file. From 6a34f74190af6fe3e30553c91645f527db8581f2 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 30 Apr 2013 12:42:46 -0400 Subject: [PATCH 032/608] checking on experimental mode --- .../mode/experimental/ExperimentalMode.java | 5 +- pdex/theme/tab-sel-left.gif | Bin 62 -> 0 bytes pdex/theme/tab-sel-menu.gif | Bin 104 -> 0 bytes pdex/theme/tab-sel-mid.gif | Bin 54 -> 0 bytes pdex/theme/tab-sel-right.gif | Bin 839 -> 0 bytes pdex/theme/tab-unsel-left.gif | Bin 62 -> 0 bytes pdex/theme/tab-unsel-menu.gif | Bin 104 -> 0 bytes pdex/theme/tab-unsel-mid.gif | Bin 54 -> 0 bytes pdex/theme/tab-unsel-right.gif | Bin 63 -> 0 bytes pdex/theme/theme.txt | 80 ------------------ 10 files changed, 3 insertions(+), 82 deletions(-) delete mode 100755 pdex/theme/tab-sel-left.gif delete mode 100755 pdex/theme/tab-sel-menu.gif delete mode 100755 pdex/theme/tab-sel-mid.gif delete mode 100755 pdex/theme/tab-sel-right.gif delete mode 100755 pdex/theme/tab-unsel-left.gif delete mode 100755 pdex/theme/tab-unsel-menu.gif delete mode 100755 pdex/theme/tab-unsel-mid.gif delete mode 100755 pdex/theme/tab-unsel-right.gif diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 6e2f85fd0..50d7ce4b3 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -29,6 +29,7 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import processing.app.Base; +import processing.app.Editor; import processing.app.EditorState; import processing.app.Mode; import processing.mode.java.JavaMode; @@ -115,7 +116,7 @@ public class ExperimentalMode extends JavaMode { * Create a new editor associated with this mode. */ @Override - public processing.app.Editor createEditor(Base base, String path, EditorState state) { + public Editor createEditor(Base base, String path, EditorState state) { return new DebugEditor(base, path, state, this); } @@ -133,7 +134,7 @@ public class ExperimentalMode extends JavaMode { if (newString != null) { return newString; } - Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading String: {0}", attribute); + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Error loading String: {0}", attribute); return defaultValue; } diff --git a/pdex/theme/tab-sel-left.gif b/pdex/theme/tab-sel-left.gif deleted file mode 100755 index bdee43c25cf2885042d8c024a2712d142adc4599..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62 zcmZ?wbhEHbWMNQbn8?5|W6_$%?x_b(U14Bg&;eowkT?UAcu)UIPNBCgJVxid)^D>Z P=gGS#QJ3^ml))MRD$Nr0 diff --git a/pdex/theme/tab-sel-menu.gif b/pdex/theme/tab-sel-menu.gif deleted file mode 100755 index d926650e7f89c6848bfa20c791498fc1a27804d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmZ?wbhEHb6l73jn8?6z<=PFekhuT<|2K9|Rs6}q00KH70wmACWI3mQ<>|Nli|2&g z=-zy9Pc=_Xq(E1gL)8JU1)9%~tyeq#G~&GE?M2(48*`S-pZ}rbOTe@<%RY13iZC!( F0|4Q)DtQ0^ diff --git a/pdex/theme/tab-sel-mid.gif b/pdex/theme/tab-sel-mid.gif deleted file mode 100755 index fa8ed45fca9a8d515f21f1df03cc1c5f4b03c495..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54 zcmZ?wbhEHbWMNQbXkcJy?4Eky)D^{_EDRu^10p~&3{1Q&{VT=a@-LpV$lmI P^W@!=s7rb&%3uuu4}}s| diff --git a/pdex/theme/tab-unsel-menu.gif b/pdex/theme/tab-unsel-menu.gif deleted file mode 100755 index a1720a589caf4697f8f79da5fd1b5b270ded5633..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmZ?wbhEHb6l73jn8?7;F=>uhNZg!d8ydT(D*j|)00A8k0g`86vYgYu^7LE&#dAV# zbZ@@5r<$iGQlKl$q3QtF0?p^g)~g+V8gX9o_M+|2jX6u^&;QWzC1Bc_WuG~1MHm>Y E0YW?|q5uE@ diff --git a/pdex/theme/tab-unsel-mid.gif b/pdex/theme/tab-unsel-mid.gif deleted file mode 100755 index a2c5497b898b4528a8095dc0cf48c6700dd179a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54 zcmZ?wbhEHbWMNQbXkcJy?4CMj*#^a*EDRu^10p~&3{1Q&{VT=a@-LpV Date: Mon, 6 May 2013 15:43:14 -0400 Subject: [PATCH 036/608] new mode images and sizes from Casey --- pdex/theme/buttons.gif | Bin 6428 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 pdex/theme/buttons.gif diff --git a/pdex/theme/buttons.gif b/pdex/theme/buttons.gif deleted file mode 100755 index a16fa330fae97658296fa1f3c3dcb3e0d811cb40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6428 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 aJxlxfEJI@czTSMc&3tZZJ{ucI_dfvA0{z|q From 1b20eafd91fafa9349fa5db77a33b90c458dc2d3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 9 Jun 2013 00:11:43 +0530 Subject: [PATCH 040/608] jar loading for completions now dynamic --- pdex/.project | 10 ++ .../mode/experimental/ASTGenerator.java | 143 ++++++++++-------- .../experimental/ErrorCheckerService.java | 7 +- 3 files changed, 99 insertions(+), 61 deletions(-) diff --git a/pdex/.project b/pdex/.project index 1be6ebc0c..85716855e 100644 --- a/pdex/.project +++ b/pdex/.project @@ -10,6 +10,16 @@ + + org.eclipse.ui.externaltools.ExternalToolBuilder + auto,full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/Auto_Builder.launch + + + org.eclipse.jdt.core.javanature diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 6d7b8096e..6cfeb56b5 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -176,7 +176,7 @@ public class ASTGenerator { } } - private DefaultMutableTreeNode buildAST2(String source, CompilationUnit cu) { + private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setSource(source.toCharArray()); @@ -219,18 +219,18 @@ public class ASTGenerator { // frameAutoComp.setVisible(true); // // } - if (!jdocWindow.isVisible()) { - long t = System.currentTimeMillis(); - loadJars(); - loadJavaDoc(); - System.out.println("Time taken: " - + (System.currentTimeMillis() - t)); - jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() - .getX() + errorCheckerService.getEditor().getWidth(), - errorCheckerService.getEditor() - .getY(), 450, 600)); - jdocWindow.setVisible(true); - } +// if (!jdocWindow.isVisible()) { +// long t = System.currentTimeMillis(); +// loadJars(); +// loadJavaDoc(); +// System.out.println("Time taken: " +// + (System.currentTimeMillis() - t)); +// jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() +// .getX() + errorCheckerService.getEditor().getWidth(), +// errorCheckerService.getEditor() +// .getY(), 450, 600)); +// jdocWindow.setVisible(true); +// } jtree.validate(); } } @@ -248,45 +248,63 @@ public class ASTGenerator { private JFrame jdocWindow; - private void loadJars() { - try { - factory = new ClassPathFactory(); + /** + * Loads up .jar files and classes defined in it for completion lookup + */ + protected void loadJars() { +// SwingWorker worker = new SwingWorker() { +// protected void done(){ +// } +// protected Object doInBackground() throws Exception { +// return null; +// } +// }; +// worker.execute(); + + Thread t = new Thread(new Runnable() { - StringBuffer tehPath = new StringBuffer( - System - .getProperty("java.class.path")); - tehPath.append(File.pathSeparatorChar + System.getProperty("java.home") - + "/lib/rt.jar" + File.pathSeparatorChar); - if (errorCheckerService.classpathJars != null) { - for (URL jarPath : errorCheckerService.classpathJars) { - tehPath.append(jarPath.getPath() + File.pathSeparatorChar); + public void run() { + try { + factory = new ClassPathFactory(); + + StringBuffer tehPath = new StringBuffer(System + .getProperty("java.class.path")); + tehPath.append(File.pathSeparatorChar + + System.getProperty("java.home") + "/lib/rt.jar" + + File.pathSeparatorChar); + if (errorCheckerService.classpathJars != null) { + for (URL jarPath : errorCheckerService.classpathJars) { + System.out.println(jarPath.getPath()); + tehPath.append(jarPath.getPath() + File.pathSeparatorChar); + } + } + +// String paths[] = tehPath.toString().split(File.separatorChar +""); + StringTokenizer st = new StringTokenizer(tehPath.toString(), + File.pathSeparatorChar + ""); + while (st.hasMoreElements()) { + String sstr = (String) st.nextElement(); + System.out.println(sstr); + } + + classPath = factory.createFromPath(tehPath.toString()); +// for (String packageName : classPath.listPackages("")) { +// System.out.println(packageName); +// } +// RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( +// ".*", +// "ArrayList.class"); +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } + System.out.println("jars loaded."); + } catch (Exception e) { + e.printStackTrace(); } } - -// String paths[] = tehPath.toString().split(File.separatorChar +""); - StringTokenizer st = new StringTokenizer(tehPath.toString(), - File.pathSeparatorChar + ""); - while (st.hasMoreElements()) { - String sstr = (String) st.nextElement(); - System.out.println(sstr); - } - - classPath = factory.createFromPath(tehPath.toString()); -// for (String packageName : classPath.listPackages("")) { -// System.out.println(packageName); -// } -// RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( -// ".*", -// "ArrayList.class"); -// String[] resources = classPath.findResources("", regExpResourceFilter); -// for (String className : resources) { -// System.out.println("-> " + className); -// } - System.out.println("jars loaded."); - } catch (Exception e) { - e.printStackTrace(); - } - + }); + t.start(); } private TreeMap jdocMap; @@ -298,7 +316,7 @@ public class ASTGenerator { @Override public void run() { - JavadocHelper.loadJavaDoc(jdocMap,editor.mode().getReferenceFolder()); + JavadocHelper.loadJavaDoc(jdocMap, editor.mode().getReferenceFolder()); } }); t.start(); @@ -306,7 +324,7 @@ public class ASTGenerator { } public DefaultMutableTreeNode buildAST(CompilationUnit cu) { - return buildAST2(errorCheckerService.sourceCode, cu); + return buildAST(errorCheckerService.sourceCode, cu); } public String[] checkForTypes2(ASTNode node) { @@ -376,7 +394,10 @@ public class ASTGenerator { case ASTNode.SINGLE_VARIABLE_DECLARATION: return new CompletionCandidate[] { new CompletionCandidate( - getNodeAsString2(node),"","",CompletionCandidate.LOCAL_VAR) }; + getNodeAsString2(node), + "", + "", + CompletionCandidate.LOCAL_VAR) }; case ASTNode.FIELD_DECLARATION: vdfs = ((FieldDeclaration) node).fragments(); @@ -395,7 +416,8 @@ public class ASTGenerator { CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()]; int i = 0; for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = new CompletionCandidate(getNodeAsString2(vdf),"","",CompletionCandidate.LOCAL_VAR); + ret[i++] = new CompletionCandidate(getNodeAsString2(vdf), "", "", + CompletionCandidate.LOCAL_VAR); } return ret; } @@ -496,6 +518,8 @@ public class ASTGenerator { protected void done() { String word2 = word; + + //After typing 'arg.' all members of arg type are to be listed. This one is a flag for it boolean noCompare = false; if (word2.endsWith(".")) { // return all matches @@ -668,7 +692,7 @@ public class ASTGenerator { } } else if (word.length() - word2.length() == 1) { - System.out.println(word +" w2 " + word2); + System.out.println(word + " w2 " + word2); // int dC = 0; // for (int i = 0; i < word.length(); i++) { // if(word.charAt(i) == '.') @@ -678,12 +702,13 @@ public class ASTGenerator { System.out.println("All members of " + word2); candidates = getMembersForType(word2, "", true, true); // } - } - else{ + } else { System.out.println("Some members of " + word2); int x = word2.indexOf('.'); - if(x != -1){ - candidates = getMembersForType(word2.substring(0, x), word2.substring(x+1), false, true); + if (x != -1) { + candidates = getMembersForType(word2.substring(0, x), + word2.substring(x + 1), false, + true); } } @@ -763,7 +788,7 @@ public class ASTGenerator { if (!Modifier.isStatic(field.getModifiers()) && staticOnly) continue; if (noCompare) - candidates.add(new CompletionCandidate(field)); + candidates.add(new CompletionCandidate(field)); else if (field.getName().startsWith(child.toString())) candidates.add(new CompletionCandidate(field)); } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index cd1c181d4..a03965ada 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -341,7 +341,8 @@ public class ErrorCheckerService implements Runnable{ // CompilationChecker class(from CompilationChecker.jar) that houses the // Eclispe JDT compiler and call its getErrorsAsObj method to obtain // errors. This way, I'm able to add the paths of contributed libraries - // to the classpath of CompilationChecker, dynamically. + // to the classpath of CompilationChecker, dynamically. The eclipse compiler + // needs all referenced libraries in the classpath. try { @@ -375,7 +376,7 @@ public class ErrorCheckerService implements Runnable{ //for (File jarFile : jarFiles) { //classpathJars.add(jarFile.toURI().toURL()); //} - + classpath = new URL[classpathJars.size() + jarFiles.length]; int ii = 0; for (; ii < classpathJars.size(); ii++) { @@ -392,6 +393,8 @@ public class ErrorCheckerService implements Runnable{ classLoader); // System.out.println("2."); compilationChecker = checkerClass.newInstance(); + + astGenerator.loadJars(); // Update jar files for completition list loadCompClass = false; } From b853fe94bc73be2225e032c7830c7cfeb3567cce Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 10 Jun 2013 08:15:16 +0530 Subject: [PATCH 041/608] Sorted completion list --- .../src/processing/mode/experimental/ASTGenerator.java | 2 ++ .../mode/experimental/CompletionCandidate.java | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 6cfeb56b5..3fbd2d58f 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -16,6 +16,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -714,6 +715,7 @@ public class ASTGenerator { } + Collections.sort(candidates); CompletionCandidate[][] candi = new CompletionCandidate[candidates .size()][1]; diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 5f3f0d740..4ff73400f 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -7,7 +7,7 @@ import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.MethodDeclaration; -public class CompletionCandidate { +public class CompletionCandidate implements Comparable{ private String definingClass; @@ -119,4 +119,12 @@ public class CompletionCandidate { return type; } + public int compareTo(CompletionCandidate cc) { + if(type != cc.getType()){ + return cc.getType() - type; + } + + return (elementName.compareTo(cc.getElementName())); + } + } From f1abd96787b41aa6dc7470cc2ee2912ca895a0b7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 10 Jun 2013 18:29:08 +0530 Subject: [PATCH 042/608] Completion for external classes --- .../mode/experimental/ASTGenerator.java | 105 ++++++++++-------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 3fbd2d58f..b18e20c87 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,12 +1,8 @@ package processing.mode.experimental; -import java.awt.Point; import java.awt.Rectangle; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; import java.io.BufferedReader; import java.io.File; -import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -21,12 +17,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.swing.JEditorPane; import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTree; @@ -34,7 +27,6 @@ import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.table.DefaultTableModel; -import javax.swing.text.BadLocationException; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -62,18 +54,12 @@ import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import processing.app.Base; import processing.app.SketchCode; -import processing.app.syntax.JEditTextArea; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; -import com.google.classpath.DirectoryClassPath.FileFileFilter; import com.google.classpath.RegExpResourceFilter; import com.ibm.icu.util.StringTokenizer; @@ -275,30 +261,30 @@ public class ASTGenerator { + File.pathSeparatorChar); if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { - System.out.println(jarPath.getPath()); + //System.out.println(jarPath.getPath()); tehPath.append(jarPath.getPath() + File.pathSeparatorChar); } } // String paths[] = tehPath.toString().split(File.separatorChar +""); - StringTokenizer st = new StringTokenizer(tehPath.toString(), - File.pathSeparatorChar + ""); - while (st.hasMoreElements()) { - String sstr = (String) st.nextElement(); - System.out.println(sstr); - } +// StringTokenizer st = new StringTokenizer(tehPath.toString(), +// File.pathSeparatorChar + ""); +// while (st.hasMoreElements()) { +// String sstr = (String) st.nextElement(); +// System.out.println(sstr); +// } classPath = factory.createFromPath(tehPath.toString()); // for (String packageName : classPath.listPackages("")) { // System.out.println(packageName); // } -// RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( -// ".*", -// "ArrayList.class"); -// String[] resources = classPath.findResources("", regExpResourceFilter); -// for (String className : resources) { -// System.out.println("-> " + className); -// } + RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( + ".*", + "ArrayList.class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } System.out.println("jars loaded."); } catch (Exception e) { e.printStackTrace(); @@ -544,7 +530,7 @@ public class ASTGenerator { } // Now parse the expression into an ASTNode object - ASTNode anode = null; + ASTNode nearestNode = null; ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setKind(ASTParser.K_EXPRESSION); parser.setSource(word2.toCharArray()); @@ -552,13 +538,13 @@ public class ASTGenerator { // Find closest ASTNode of the document to this word System.err.print("Typed: " + word2 + "|"); - anode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); - if (anode == null) - //Make sure anode is not NULL if couldn't find a closeset node - anode = (ASTNode) compilationUnit.types().get(0); + if (nearestNode == null) + //Make sure nearestNode is not NULL if couldn't find a closeset node + nearestNode = (ASTNode) compilationUnit.types().get(0); System.err.println(lineNumber + " Nearest ASTNode to PRED " - + getNodeAsString(anode)); + + getNodeAsString(nearestNode)); ArrayList candidates = new ArrayList(); @@ -567,12 +553,16 @@ public class ASTGenerator { if (testnode instanceof SimpleName && !noCompare) { System.err .println("One word expression " + getNodeAsString(testnode)); - // Simple one word exprssion - so is just an identifier - anode = anode.getParent(); - while (anode != null) { - - if (anode instanceof TypeDeclaration) { - TypeDeclaration td = (TypeDeclaration) anode; + //==> Simple one word exprssion - so is just an identifier + + // Bottom up traversal of the AST to look for possible definitions at + // higher levels. + nearestNode = nearestNode.getParent(); + while (nearestNode != null) { + // If the current class has a super class, look inside it for + // definitions. + if (nearestNode instanceof TypeDeclaration) { + TypeDeclaration td = (TypeDeclaration) nearestNode; if (td .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) { SimpleType st = (SimpleType) td @@ -586,13 +576,13 @@ public class ASTGenerator { } } - List sprops = anode + List sprops = nearestNode .structuralPropertiesForType(); for (StructuralPropertyDescriptor sprop : sprops) { ASTNode cnode = null; if (!sprop.isChildListProperty()) { - if (anode.getStructuralProperty(sprop) instanceof ASTNode) { - cnode = (ASTNode) anode.getStructuralProperty(sprop); + if (nearestNode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) nearestNode.getStructuralProperty(sprop); CompletionCandidate[] types = checkForTypes(cnode); if (types != null) { for (int i = 0; i < types.length; i++) { @@ -603,7 +593,7 @@ public class ASTGenerator { } } else { // Childlist prop - List nodelist = (List) anode + List nodelist = (List) nearestNode .getStructuralProperty(sprop); for (ASTNode clnode : nodelist) { CompletionCandidate[] types = checkForTypes(clnode); @@ -616,16 +606,33 @@ public class ASTGenerator { } } } - anode = anode.getParent(); + nearestNode = nearestNode.getParent(); + } + if(candidates.isEmpty()){ + // We're seeing a simple name that's not defined locally or in + // the parent class. So most probably a pre-defined type. + System.out.println("Empty can. " + word2); + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", word2 + "[a-zA-Z_0-9]*.class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String matchedClass : resources) { + matchedClass = matchedClass.substring(0, + matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + int d = matchedClass.lastIndexOf('.'); + matchedClass = matchedClass.substring(d + 1); + candidates.add(new CompletionCandidate(matchedClass)); + //System.out.println("-> " + className); + } } } else { - // Complex expression of type blah.blah2().doIt,etc + // ==> Complex expression of type blah.blah2().doIt,etc // Have to resolve it by carefully traversing AST of testNode System.err.println("Complex expression " + getNodeAsString(testnode)); - ASTNode det = resolveExpression(anode, testnode); + ASTNode det = resolveExpression(nearestNode, testnode); // Find the parent of the expression // in a().b, this would give me the return type of a(), so that we can // find all children of a() begininng with b @@ -760,11 +767,11 @@ public class ASTGenerator { for (String className : resources) { System.out.println("-> " + className); } - if (resources.length > 0) { + if (resources.length > 0) { //TODO: Multiple matched classes? What about 'em? String matchedClass = resources[0]; matchedClass = matchedClass.substring(0, matchedClass.length() - 6); matchedClass = matchedClass.replace('/', '.'); - System.out.println("Matched class: " + matchedClass); + System.out.println("In GMFT(), Matched class: " + matchedClass); System.out.println("Looking for match " + child.toString()); try { Class probableClass = Class.forName(matchedClass, false, From 3d1602f929f00c17991bc6f432b1ba191910086f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 18 Jun 2013 00:33:28 +0530 Subject: [PATCH 043/608] work on pde<-> java code offset mapping --- .../mode/experimental/ASTGenerator.java | 154 ++++++++++++------ .../mode/experimental/ASTNodeWrapper.java | 142 ++++++++++++++++ .../experimental/ErrorCheckerService.java | 83 ++++++++++ .../mode/experimental/TextAreaPainter.java | 1 - 4 files changed, 325 insertions(+), 55 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/ASTNodeWrapper.java diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b18e20c87..8f22b45bf 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,6 +1,8 @@ package processing.mode.experimental; import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -26,6 +28,8 @@ import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -73,8 +77,16 @@ public class ASTGenerator { private DefaultMutableTreeNode currentParent = null; - private JFrame frame2, frameAutoComp; + /** + * AST Window + */ + private JFrame frame2; + + private JFrame frameAutoComp; + /** + * Swing component wrapper for AST, used for internal testing + */ private JTree jtree; private CompilationUnit compilationUnit; @@ -121,48 +133,6 @@ public class ASTGenerator { //addCompletionPopupListner(); } - public class ASTNodeWrapper { - private ASTNode node; - - private String label; - - private int lineNumber; - - private int apiLevel; - - public ASTNodeWrapper(ASTNode node) { - if (node == null) - return; - this.node = node; - label = getNodeAsString(node); - if (label == null) - label = node.toString(); - lineNumber = compilationUnit.getLineNumber(node.getStartPosition()); - label += " | Line " + lineNumber; - apiLevel = 0; - } - - public String toString() { - return label; - } - - public ASTNode getNode() { - return node; - } - - public String getLabel() { - return label; - } - - public int getNodeType() { - return node.getNodeType(); - } - - public int getLineNumber() { - return lineNumber; - } - } - private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { ASTParser parser = ASTParser.newParser(AST.JLS4); @@ -181,10 +151,10 @@ public class ASTGenerator { } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); -// codeTree = new DefaultMutableTreeNode( -// getNodeAsString((ASTNode) compilationUnit -// .types().get(0))); -// visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + codeTree = new DefaultMutableTreeNode( + getNodeAsString((ASTNode) compilationUnit + .types().get(0))); + visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); SwingWorker worker = new SwingWorker() { @Override @@ -194,13 +164,13 @@ public class ASTGenerator { protected void done() { if (codeTree != null) { -// if (jtree.hasFocus() || frame2.hasFocus()) -// return; + if (jtree.hasFocus() || frame2.hasFocus()) + return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if (!frame2.isVisible()) { + frame2.setVisible(true); + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -438,6 +408,14 @@ public class ASTGenerator { return names; } + /** + * Find the parent of the expression in a().b, this would give me the return + * type of a(), so that we can find all children of a() begininng with b + * + * @param nearestNode + * @param expression + * @return + */ public static ASTNode resolveExpression(ASTNode nearestNode, ASTNode expression) { // ASTNode anode = null; @@ -1117,8 +1095,37 @@ public class ASTGenerator { System.out.println(found); } } + + private void addTreeListner(){ + jtree.addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) jtree + .getLastSelectedPathComponent(); + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + + } + }; + worker.execute(); + } + }); + } @SuppressWarnings({ "unchecked" }) + /** + * Generates AST Swing component + * @param node + * @param tnode + */ public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { Iterator it = node .structuralPropertiesForType().iterator(); @@ -1136,7 +1143,7 @@ public class ASTGenerator { ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); if (isAddableASTNode(cnode)) { ctnode = new DefaultMutableTreeNode( - getNodeAsString((ASTNode) node + new ASTNodeWrapper((ASTNode) node .getStructuralProperty(prop))); tnode.add(ctnode); visitRecur(cnode, ctnode); @@ -1153,7 +1160,7 @@ public class ASTGenerator { .getStructuralProperty(prop); for (ASTNode cnode : nodelist) { if (isAddableASTNode(cnode)) { - ctnode = new DefaultMutableTreeNode(getNodeAsString(cnode)); + ctnode = new DefaultMutableTreeNode(new ASTNodeWrapper(cnode)); tnode.add(ctnode); visitRecur(cnode, ctnode); } else @@ -1736,6 +1743,45 @@ public class ASTGenerator { public static boolean isAddableASTNode(ASTNode node) { return true; } + + /** + * For any line or expression, finds the line start offset(java code). + * @param node + * @return + */ + public int getASTNodeLineStartOffset(ASTNode node){ + int nodeLineNo = getLineNumber(node); + while(node.getParent() != null){ + if (getLineNumber(node.getParent()) == nodeLineNo) { + node = node.getParent(); + } else { + break; + } + } + return node.getStartPosition(); + } + + /** + * For any node, finds various offsets (java code). + * + * @param node + * @return int[]{line number, line number start offset, node start offset, + * node length} + */ + public int[] getASTNodeAllOffsets(ASTNode node){ + int nodeLineNo = getLineNumber(node), nodeOffset = node.getStartPosition(), nodeLength = node + .getLength(); + while(node.getParent() != null){ + if (getLineNumber(node.getParent()) == nodeLineNo) { + node = node.getParent(); + } else { + break; + } + } + return new int[]{nodeLineNo, node.getStartPosition(), nodeOffset,nodeLength}; + } + + static private String getNodeAsString(ASTNode node) { if (node == null) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java new file mode 100644 index 000000000..d2c3bdcf1 --- /dev/null +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -0,0 +1,142 @@ +package processing.mode.experimental; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclaration; + +public class ASTNodeWrapper { + private ASTNode node; + + private String label; + + private int lineNumber; + + //private int apiLevel; + + /* + * TODO: Every ASTNode object in ASTGenerator.codetree is stored as a + * ASTNodeWrapper instance. So how resource heavy would it be to store a + * pointer to ECS in every instance of ASTNodeWrapper? Currently I will rather + * pass an ECS pointer in the argument when I need to access a method which + * requires a method defined in ECS, i.e, only on demand. + * Bad design choice for ECS methods? IDK, yet. + */ + + public ASTNodeWrapper(ASTNode node) { + if (node == null) + return; + this.node = node; + label = getNodeAsString(node); + if (label == null) + label = node.toString(); + lineNumber = getLineNumber(node); + label += " | Line " + lineNumber; + //apiLevel = 0; + } + + /** + * For this node, finds various offsets (java code). + * + * @return int[]{line number, line number start offset, node start offset, + * node length} + */ + public int[] getJavaCodeOffsets() { + int nodeLineNo = getLineNumber(node), nodeOffset = node.getStartPosition(), nodeLength = node + .getLength(); + ASTNode thisNode = node; + while (thisNode.getParent() != null) { + if (getLineNumber(node.getParent()) == nodeLineNo) { + node = node.getParent(); + } else { + break; + } + } + return new int[] { + nodeLineNo, node.getStartPosition(), nodeOffset, nodeLength }; + } + + /** + * + * @param ecs + * - ErrorCheckerService instance + */ + public void getPDECodeOffsets(ErrorCheckerService ecs) { + + } + + public String toString() { + return label; + } + + public ASTNode getNode() { + return node; + } + + public String getLabel() { + return label; + } + + public int getNodeType() { + return node.getNodeType(); + } + + public int getLineNumber() { + return lineNumber; + } + + private static int getLineNumber(ASTNode node) { + return ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + } + + static private String getNodeAsString(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString() + " | " + className; + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString() + " | " + + className; + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString() + " FldDecl| "; + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName() + " - " + + ((SingleVariableDeclaration) node).getType() + " | SVD "; + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (node instanceof QualifiedName) + value = node.toString() + " | " + className; + else if (className.startsWith("Variable")) + value = node.toString() + " | " + className; + else if (className.endsWith("Type")) + value = node.toString() + " |" + className; + value += " [" + node.getStartPosition() + "," + + (node.getStartPosition() + node.getLength()) + "]"; + value += " Line: " + + ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + return value; + } +} \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index a03965ada..0c4e9bbe1 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -725,6 +725,89 @@ public class ErrorCheckerService implements Runnable{ } } + /** + * Maps offset from java code to pde code. Returns a bunch of offsets as array + * + * @param line + * - line number in java code + * @param offset + * - offset from the start of the 'line' + * @return int[0] - tab number, int[1] - line number, int[2] - line start + * offset, int[3] - offset from line start int[2] and int[3] are on + * TODO + */ + public int[] JavaToPdeOffsets(int line, int offset){ + int codeIndex = 0; + + int x = line - mainClassOffset; + if (x < 0) { + // System.out.println("Negative line number " + // + problem.getSourceLineNumber() + " , offset " + // + mainClassOffset); + x = line - 2; // Another -1 for 0 index + if (x < programImports.size() && x >= 0) { + ImportStatement is = programImports.get(x); + // System.out.println(is.importName + ", " + is.tab + ", " + // + is.lineNumber); + return new int[] { is.tab, is.lineNumber }; + } else { + + // Some seriously ugly stray error, just can't find the source + // line! Simply return first line for first tab. + return new int[] { 0, 1 }; + } + + } + + try { + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + int len = 0; + if (editor.getSketch().getCurrentCode().equals(sc)) { + len = Base.countLines(sc.getDocument().getText(0, + sc.getDocument().getLength())) + 1; + } else { + len = Base.countLines(sc.getProgram()) + 1; + } + + // System.out.println("x,len, CI: " + x + "," + len + "," + // + codeIndex); + + if (x >= len) { + + // We're in the last tab and the line count is greater + // than the no. + // of lines in the tab, + if (codeIndex >= editor.getSketch().getCodeCount() - 1) { + // System.out.println("Exceeds lc " + x + "," + len + // + problem.toString()); + // x = len + x = editor.getSketch().getCode(codeIndex) + .getLineCount(); + // TODO: Obtain line having last non-white space + // character in the code. + break; + } else { + x -= len; + codeIndex++; + } + } else { + + if (codeIndex >= editor.getSketch().getCodeCount()) { + codeIndex = editor.getSketch().getCodeCount() - 1; + } + break; + } + + } + } + } catch (Exception e) { + System.err + .println("Things got messed up in ErrorCheckerService.JavaToPdeOffset()"); + } + return new int[] { codeIndex, x }; + } + /** * Calculates the tab number and line number of the error in that particular * tab. Provides mapping between pure java and pde code. diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index dd20d67e6..9ee6b9539 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -33,7 +33,6 @@ import javax.swing.text.Utilities; import processing.app.syntax.TextAreaDefaults; import processing.app.syntax.TokenMarker; -import processing.mode.experimental.ASTGenerator.ASTNodeWrapper; /** * Customized line painter. Adds support for background colors, left hand gutter From 1abaea188f38db5dde9694915db6e4c3ff15d3f8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 18 Jun 2013 00:45:00 +0530 Subject: [PATCH 044/608] redundant code. meh. --- .../mode/experimental/ASTNodeWrapper.java | 10 ++++---- .../experimental/ErrorCheckerService.java | 25 +++---------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index d2c3bdcf1..7b2b161a3 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -48,18 +48,18 @@ public class ASTNodeWrapper { * node length} */ public int[] getJavaCodeOffsets() { - int nodeLineNo = getLineNumber(node), nodeOffset = node.getStartPosition(), nodeLength = node + int nodeOffset = node.getStartPosition(), nodeLength = node .getLength(); ASTNode thisNode = node; while (thisNode.getParent() != null) { - if (getLineNumber(node.getParent()) == nodeLineNo) { + if (getLineNumber(node.getParent()) == lineNumber) { node = node.getParent(); } else { break; } } return new int[] { - nodeLineNo, node.getStartPosition(), nodeOffset, nodeLength }; + lineNumber, node.getStartPosition(), nodeOffset, nodeLength }; } /** @@ -67,8 +67,8 @@ public class ASTNodeWrapper { * @param ecs * - ErrorCheckerService instance */ - public void getPDECodeOffsets(ErrorCheckerService ecs) { - + public int[] getPDECodeOffsets(ErrorCheckerService ecs) { + return ecs.JavaToPdeOffsets(lineNumber, node.getStartPosition()); } public String toString() { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 0c4e9bbe1..3ea9e4968 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -732,9 +732,9 @@ public class ErrorCheckerService implements Runnable{ * - line number in java code * @param offset * - offset from the start of the 'line' - * @return int[0] - tab number, int[1] - line number, int[2] - line start - * offset, int[3] - offset from line start int[2] and int[3] are on - * TODO + * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] + * - line start offset, int[3] - offset from line start int[2] and + * int[3] are on TODO */ public int[] JavaToPdeOffsets(int line, int offset){ int codeIndex = 0; @@ -1045,24 +1045,7 @@ public class ErrorCheckerService implements Runnable{ if (errorIndex < problemsList.size() && errorIndex >= 0) { Problem p = problemsList.get(errorIndex); - try { - editor.toFront(); - editor.getSketch().setCurrentCode(p.tabIndex); - editor.getTextArea().scrollTo(p.lineNumber - 1, 0); - editor.setSelection(editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) - + editor.getTextArea().getLineText(p.lineNumber - 1) - .trim().length(), editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); - editor.repaint(); - } catch (Exception e) { - System.err - .println(e - + " : Error while selecting text in scrollToErrorLine()"); - // e.printStackTrace(); - } - // System.out.println("---"); - + scrollToErrorLine(p); } } From a988b74785c43f516d66a6d0f738ffff67a0e855 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 18 Jun 2013 00:52:24 +0530 Subject: [PATCH 045/608] About time this went static. --- .../experimental/ErrorCheckerService.java | 82 +++++++++++++------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 3ea9e4968..4335da973 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; +import processing.app.Editor; import processing.app.Library; import processing.app.SketchCode; import processing.core.PApplet; @@ -1050,34 +1051,63 @@ public class ErrorCheckerService implements Runnable{ } public void scrollToErrorLine(Problem p) { - if (editor == null) { - return; - } - if(p==null) - return; - try { - editor.toFront(); - editor.getSketch().setCurrentCode(p.tabIndex); - - editor.setSelection(editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) - + editor.getTextArea().getLineText(p.lineNumber - 1) - .trim().length(), editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); - editor.getTextArea().scrollTo(p.lineNumber - 1, 0); - editor.repaint(); - } catch (Exception e) { - System.err - .println(e - + " : Error while selecting text in scrollToErrorLine()"); - e.printStackTrace(); - } - // System.out.println("---"); + if (editor == null) { + return; + } + if (p == null) + return; + try { + editor.toFront(); + editor.getSketch().setCurrentCode(p.tabIndex); - - } - + editor + .setSelection(editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) + + editor.getTextArea() + .getLineText(p.lineNumber - 1).trim().length(), + editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); + editor.getTextArea().scrollTo(p.lineNumber - 1, 0); + editor.repaint(); + } catch (Exception e) { + System.err.println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + } + // System.out.println("---"); + } + /** + * Static method for scroll to a particular line in the PDE. Requires + * the editor instance as arguement. About time this went static. + * @param edt + * @param tabIndex + * @param lineNoInTab - line number in the corresponding tab + * @return - true, if scroll was successful + */ + public static boolean scrollToErrorLine(Editor edt, int tabIndex, int lineNoInTab) { + if (edt == null) { + return false; + } + try { + edt.toFront(); + edt.getSketch().setCurrentCode(tabIndex); + + edt.setSelection(edt.getTextArea() + .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1) + + edt.getTextArea().getLineText(lineNoInTab - 1) + .trim().length(), edt.getTextArea() + .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1)); + edt.getTextArea().scrollTo(lineNoInTab - 1, 0); + edt.repaint(); + } catch (Exception e) { + System.err.println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + return false; + } + return true; + } /** * Checks if import statements in the sketch have changed. If they have, From a2cf09f7fe26d7107030788fa480c81a6a439dde Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 18 Jun 2013 02:03:45 +0530 Subject: [PATCH 046/608] Sketch Outline Tool like thing implemented temporarily. Should help me see things clearly. --- .../mode/experimental/ASTGenerator.java | 19 +++++++++++++++++-- .../mode/experimental/ASTNodeWrapper.java | 5 ++++- .../experimental/ErrorCheckerService.java | 17 ++++++++++------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 8f22b45bf..6afc450d4 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -131,6 +131,7 @@ public class ASTGenerator { //loadJars(); //addCompletionPopupListner(); + addTreeListner(); } private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { @@ -1101,6 +1102,7 @@ public class ASTGenerator { @Override public void valueChanged(TreeSelectionEvent e) { + System.out.println(e); SwingWorker worker = new SwingWorker() { @Override @@ -1109,10 +1111,23 @@ public class ASTGenerator { } protected void done() { + if(jtree + .getLastSelectedPathComponent() == null){ + return; + } DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) jtree - .getLastSelectedPathComponent(); - ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + .getLastSelectedPathComponent(); + if(tnode.getUserObject() == null){ + return; + } + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + // 3 friggin casts. Javaaargh. + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + int offsets[] = awrap.getPDECodeOffsets(errorCheckerService); + ErrorCheckerService.scrollToErrorLine(editor, offsets[0], + offsets[1]); + } } }; worker.execute(); diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 7b2b161a3..26bfaeaca 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -66,9 +66,12 @@ public class ASTNodeWrapper { * * @param ecs * - ErrorCheckerService instance + * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] + * - line start offset, int[3] - offset from line start int[2] and + * int[3] are on TODO */ public int[] getPDECodeOffsets(ErrorCheckerService ecs) { - return ecs.JavaToPdeOffsets(lineNumber, node.getStartPosition()); + return ecs.JavaToPdeOffsets(lineNumber + 1, node.getStartPosition()); } public String toString() { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 4335da973..6e0f8d494 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -265,11 +265,12 @@ public class ErrorCheckerService implements Runnable{ lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); - + syntaxCheck(); - System.err.println(editor.getSketch().getName()+ "1 MCO " + mainClassOffset); + System.out.println(editor.getSketch().getName() + "1 MCO " + + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. - + if (problems.length == 0 && editor.compilationCheckEnabled) { //mainClassOffset++; // just a hack. astGenerator.buildAST(cu); @@ -283,10 +284,10 @@ public class ErrorCheckerService implements Runnable{ // System.out.println(sourceCode); // System.out.println("--------------------------"); compileCheck(); - System.err.println(editor.getSketch().getName()+ "2 MCO " + mainClassOffset); + System.out.println(editor.getSketch().getName() + "2 MCO " + + mainClassOffset); } - updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); @@ -734,7 +735,7 @@ public class ErrorCheckerService implements Runnable{ * @param offset * - offset from the start of the 'line' * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] - * - line start offset, int[3] - offset from line start int[2] and + * - line start offset, int[3] - offset from line start. int[2] and * int[3] are on TODO */ public int[] JavaToPdeOffsets(int line, int offset){ @@ -1019,7 +1020,9 @@ public class ErrorCheckerService implements Runnable{ mainClassOffset++; } } - if(staticMode) mainClassOffset++; + if(staticMode) { + mainClassOffset++; + } //mainClassOffset += 2; // Handle unicode characters sourceAlt = substituteUnicode(sourceAlt); From fbafd8e07ce8f1f2051f9ddfa9f7badadc82db5d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 18 Jun 2013 17:40:04 +0530 Subject: [PATCH 047/608] Selection thingy works like a charm --- .../mode/experimental/ASTGenerator.java | 10 ++++--- .../mode/experimental/ASTNodeWrapper.java | 8 +++--- .../experimental/ErrorCheckerService.java | 26 +++++++++++-------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 6afc450d4..7c512ae14 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1124,9 +1124,13 @@ public class ASTGenerator { if (tnode.getUserObject() instanceof ASTNodeWrapper) { // 3 friggin casts. Javaaargh. ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - int offsets[] = awrap.getPDECodeOffsets(errorCheckerService); - ErrorCheckerService.scrollToErrorLine(editor, offsets[0], - offsets[1]); + int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); + int javaoffsets[] = awrap.getJavaCodeOffsets(); + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1], + javaoffsets[2] + - javaoffsets[1], + javaoffsets[3]); } } }; diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 26bfaeaca..313f27400 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -43,7 +43,7 @@ public class ASTNodeWrapper { /** * For this node, finds various offsets (java code). - * + * Note that line start offset for this node is int[2] - int[1] * @return int[]{line number, line number start offset, node start offset, * node length} */ @@ -52,14 +52,14 @@ public class ASTNodeWrapper { .getLength(); ASTNode thisNode = node; while (thisNode.getParent() != null) { - if (getLineNumber(node.getParent()) == lineNumber) { - node = node.getParent(); + if (getLineNumber(thisNode.getParent()) == lineNumber) { + thisNode = thisNode.getParent(); } else { break; } } return new int[] { - lineNumber, node.getStartPosition(), nodeOffset, nodeLength }; + lineNumber, thisNode.getStartPosition(), nodeOffset, nodeLength }; } /** diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 6e0f8d494..5b931eb70 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1081,31 +1081,35 @@ public class ErrorCheckerService implements Runnable{ } /** - * Static method for scroll to a particular line in the PDE. Requires - * the editor instance as arguement. About time this went static. + * /** Static method for scroll to a particular line in the PDE. Requires the + * editor instance as arguement. + * * @param edt * @param tabIndex - * @param lineNoInTab - line number in the corresponding tab + * @param lineNoInTab + * - line number in the corresponding tab + * @param lineStartOffset + * - selection start offset(from line start non-whitespace offset) + * @param length + * - length of selection * @return - true, if scroll was successful */ - public static boolean scrollToErrorLine(Editor edt, int tabIndex, int lineNoInTab) { + public static boolean scrollToErrorLine(Editor edt, int tabIndex, int lineNoInTab, int lineStartOffset, int length) { if (edt == null) { return false; } try { edt.toFront(); edt.getSketch().setCurrentCode(tabIndex); - - edt.setSelection(edt.getTextArea() - .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1) - + edt.getTextArea().getLineText(lineNoInTab - 1) - .trim().length(), edt.getTextArea() - .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1)); + int lsno = edt.getTextArea() + .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1) + lineStartOffset; + edt.setSelection(lsno, lsno + length); edt.getTextArea().scrollTo(lineNoInTab - 1, 0); edt.repaint(); + System.out.println(lineStartOffset + " LSO,len " + length); } catch (Exception e) { System.err.println(e - + " : Error while selecting text in scrollToErrorLine()"); + + " : Error while selecting text in static scrollToErrorLine()"); e.printStackTrace(); return false; } From 41ee9382af130c6b517fe0c1470e18e73eb8e52d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 18 Jun 2013 21:53:47 +0530 Subject: [PATCH 048/608] Added todo list. --- pdex/Todo, GSoC 2013.txt | 51 +++++++++++++++++++ .../experimental/ErrorCheckerService.java | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 pdex/Todo, GSoC 2013.txt diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt new file mode 100644 index 000000000..c4c9b267e --- /dev/null +++ b/pdex/Todo, GSoC 2013.txt @@ -0,0 +1,51 @@ +TODO List for Experimental Mode Plus- GSOC 2013 + +This would also be a break down of my thought process and ideas as I tackle various tasks. + +Manindra Moharana (me@mkmoharana.com) + +* : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo + +Code Completion +============== +The big stuff: +x! Code competition for local code is working with recursive look up. +x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. +x Completion for external classes - ArrayList, HashMap, etc. +*! Recursive lookup for compiled(library) code! +*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned +ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. +*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. +*! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. +* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. +*+ Differentiating between multiple statements on the same line. How to? + +Finer details +* Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. +* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? +* Sorted list of completion candidates - fields, then methods. It's unsorted presently. +*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. +* Reflection API - getMethods vs getDeclaredMethods. + +Refactoring +=========== +First major hurdle is offset mapping +* pde<->java code offset : precise conversion needed +x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. +* This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. +* PDE specific enhancements will also have to be tackled like int(), # literals. + +Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. +1. First identify the declaration of the variable in the AST. +2. Now for each instance of the word in code inside the declaration scope(i.e further down the child nodes in the AST), find if the matched word is the same one whose declaration I know of. +3. If it is so, replace it with the new name. +4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. + +Quick Navigation +============== +x Ctrl + Click on an element to scroll to its definition in code +x Local Vars +x Local Methods +x Local Classes +x Recursive lookup, a.b().c() + diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 5b931eb70..0f97281a1 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1081,7 +1081,7 @@ public class ErrorCheckerService implements Runnable{ } /** - * /** Static method for scroll to a particular line in the PDE. Requires the + * Static method for scroll to a particular line in the PDE. Requires the * editor instance as arguement. * * @param edt From 8a00d5a774c7d1fcce0155be2e8759cdbbcfd220 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 19 Jun 2013 00:51:46 +0530 Subject: [PATCH 049/608] ironing out edge cases --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 11 ++++- .../mode/experimental/ASTNodeWrapper.java | 40 ++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index c4c9b267e..e105e352d 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -33,6 +33,7 @@ First major hurdle is offset mapping * pde<->java code offset : precise conversion needed x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. * This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. +x Edge case - multiple staetments in a single line * PDE specific enhancements will also have to be tackled like int(), # literals. Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 7c512ae14..becb60450 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -52,6 +52,7 @@ import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; @@ -1760,7 +1761,15 @@ public class ASTGenerator { } public static boolean isAddableASTNode(ASTNode node) { - return true; + switch (node.getNodeType()) { +// case ASTNode.STRING_LITERAL: +// case ASTNode.NUMBER_LITERAL: +// case ASTNode.BOOLEAN_LITERAL: +// case ASTNode.NULL_LITERAL: +// return false; + default: + return true; + } } /** diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 313f27400..620d2ca78 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -1,5 +1,8 @@ package processing.mode.experimental; +import java.util.Iterator; +import java.util.List; + import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ExpressionStatement; @@ -9,6 +12,7 @@ import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.TypeDeclaration; public class ASTNodeWrapper { @@ -58,8 +62,40 @@ public class ASTNodeWrapper { break; } } - return new int[] { - lineNumber, thisNode.getStartPosition(), nodeOffset, nodeLength }; + /* + * There's an edge case here - multiple staetments in a single line. + * After identifying the statement with the line number, I'll have to + * look at previous tree nodes in the same level for same line number. + * The correct line start offset would be the line start offset of + * the first node with this line number. + * + * Using linear search for now. P.S: Eclipse AST iterators are messy. + * TODO: binary search might improve speed by 0.001%? + */ + + int altStartPos = thisNode.getStartPosition(); + thisNode = thisNode.getParent(); + + Iterator it = thisNode + .structuralPropertiesForType().iterator(); + + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) thisNode + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (getLineNumber(cnode) == lineNumber) { + altStartPos = cnode.getStartPosition(); + // System.out.println("multi..."); + break; + } + } + } + } + // System.out.println("Altspos " + altStartPos); + return new int[] { lineNumber,altStartPos , nodeOffset, nodeLength }; } /** From dec4c58633aa9af9040c5f120a4593370ea35eed Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 19 Jun 2013 00:55:31 +0530 Subject: [PATCH 050/608] a friendly reminder --- pdex/Todo, GSoC 2013.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index e105e352d..14526ce18 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -1,6 +1,6 @@ TODO List for Experimental Mode Plus- GSOC 2013 -This would also be a break down of my thought process and ideas as I tackle various tasks. +This would also be a break down of my thought process and ideas as I tackle various tasks. Also lines are fairly long. Make sure you turn on word wrap. ;) Manindra Moharana (me@mkmoharana.com) @@ -34,7 +34,7 @@ First major hurdle is offset mapping x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. * This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. x Edge case - multiple staetments in a single line -* PDE specific enhancements will also have to be tackled like int(), # literals. +* PDE specific enhancements will also have to be tackled like int(), # literals. Although after being able to precisely locate ast nodes in a single line(with multiple statements per line), it seems this problem might not occur at all! Need to examine test cases further. Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. From 7cac0a0d0dff85948c820a9d4525e81fb005fa99 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 20 Jun 2013 21:35:43 +0530 Subject: [PATCH 051/608] Forst shot at pde specific offset mapping. Not there yet. --- pdex/Todo, GSoC 2013.txt | 5 +- .../mode/experimental/ASTNodeWrapper.java | 93 ++++++++++++++++--- .../experimental/ErrorCheckerService.java | 2 +- 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 14526ce18..a690e2dec 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -16,7 +16,7 @@ x Completion for external classes - ArrayList, HashMap, etc. *! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. *! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. -*! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. +x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. *+ Differentiating between multiple statements on the same line. How to? @@ -34,7 +34,8 @@ First major hurdle is offset mapping x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. * This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. x Edge case - multiple staetments in a single line -* PDE specific enhancements will also have to be tackled like int(), # literals. Although after being able to precisely locate ast nodes in a single line(with multiple statements per line), it seems this problem might not occur at all! Need to examine test cases further. +* PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. + Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 620d2ca78..b8ad65c16 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -2,6 +2,8 @@ package processing.mode.experimental; import java.util.Iterator; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; @@ -16,7 +18,7 @@ import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.TypeDeclaration; public class ASTNodeWrapper { - private ASTNode node; + private ASTNode Node; private String label; @@ -36,7 +38,7 @@ public class ASTNodeWrapper { public ASTNodeWrapper(ASTNode node) { if (node == null) return; - this.node = node; + this.Node = node; label = getNodeAsString(node); if (label == null) label = node.toString(); @@ -52,9 +54,9 @@ public class ASTNodeWrapper { * node length} */ public int[] getJavaCodeOffsets() { - int nodeOffset = node.getStartPosition(), nodeLength = node + int nodeOffset = Node.getStartPosition(), nodeLength = Node .getLength(); - ASTNode thisNode = node; + ASTNode thisNode = Node; while (thisNode.getParent() != null) { if (getLineNumber(thisNode.getParent()) == lineNumber) { thisNode = thisNode.getParent(); @@ -63,7 +65,7 @@ public class ASTNodeWrapper { } } /* - * There's an edge case here - multiple staetments in a single line. + * There's an edge case here - multiple statements in a single line. * After identifying the statement with the line number, I'll have to * look at previous tree nodes in the same level for same line number. * The correct line start offset would be the line start offset of @@ -78,7 +80,7 @@ public class ASTNodeWrapper { Iterator it = thisNode .structuralPropertiesForType().iterator(); - + boolean flag = true; while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -87,15 +89,80 @@ public class ASTNodeWrapper { .getStructuralProperty(prop); for (ASTNode cnode : nodelist) { if (getLineNumber(cnode) == lineNumber) { - altStartPos = cnode.getStartPosition(); - // System.out.println("multi..."); - break; + if (flag) { + altStartPos = cnode.getStartPosition(); + // System.out.println("multi..."); + + flag = false; + } else { + if(cnode == Node){ + // loop only till the current node. + break; + } + // We've located the first node in the line. + // Now normalize offsets till Node + //altStartPos += normalizeOffsets(cnode); + + } + } } } } // System.out.println("Altspos " + altStartPos); - return new int[] { lineNumber,altStartPos , nodeOffset, nodeLength }; + return new int[] { lineNumber,altStartPos , nodeOffset, nodeLength + normalizeOffsets(Node) }; + } + + /** + * Returns the difference in offsets between pde and java versions of the ast + * node + * + * @param anode + * @return offset adjustment + */ + private int normalizeOffsets(ASTNode anode){ + String source = anode.toString().trim(); + System.out.println("Src: " + source); + int offset = 0; + String dataTypeFunc[] = { "Int", "Char", "Float", "Boolean", "Byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\bPApplet.parse" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(source); + + while (matcher.find()) { + System.out.print("Start index: " + matcher.start()); + System.out.println(" End index: " + matcher.end() + " "); + System.out.println("-->" + matcher.group() + "<--"); + offset = offset - ("PApplet.parse(").length(); + } + + + } + + // Find all #[web color] and replace with 0xff[webcolor] + // Should be 6 digits only. + final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; + Pattern webPattern = Pattern.compile(webColorRegexp); + Matcher webMatcher = webPattern.matcher(source); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = source.substring(webMatcher.start(), webMatcher.end()); + // System.out.println("-> " + found); + source = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(source); + offset += 3; + } + + // Replace all color data types with int + // Regex, Y U SO powerful? + final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; + Pattern colorPattern = Pattern.compile(colorTypeRegex); + Matcher colorMatcher = colorPattern.matcher(source); + source = colorMatcher.replaceAll("int"); + System.out.println(source + "-Norm offset " + offset); + return offset; } /** @@ -107,7 +174,7 @@ public class ASTNodeWrapper { * int[3] are on TODO */ public int[] getPDECodeOffsets(ErrorCheckerService ecs) { - return ecs.JavaToPdeOffsets(lineNumber + 1, node.getStartPosition()); + return ecs.JavaToPdeOffsets(lineNumber + 1, Node.getStartPosition()); } public String toString() { @@ -115,7 +182,7 @@ public class ASTNodeWrapper { } public ASTNode getNode() { - return node; + return Node; } public String getLabel() { @@ -123,7 +190,7 @@ public class ASTNodeWrapper { } public int getNodeType() { - return node.getNodeType(); + return Node.getNodeType(); } public int getLineNumber() { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 0f97281a1..0a84df988 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -897,7 +897,7 @@ public class ErrorCheckerService implements Runnable{ * java source. And there's a difference between parsable and compilable. * XQPrerocessor.java makes this code compilable.
    * Handles:
  • Removal of import statements
  • Conversion of int(), - * char(), etc to (int)(), (char)(), etc.
  • Replacing '#' with 0xff for + * char(), etc to PApplet.parseInt(), etc.
  • Replacing '#' with 0xff for * color representation
  • Converts all 'color' datatypes to int * (experimental)
  • Appends class declaration statement after determining * the mode the sketch is in - ACTIVE or STATIC From f418e7750d9d708e7a88de85f4fa7b1f3d6538f8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 21 Jun 2013 00:45:57 +0530 Subject: [PATCH 052/608] The fight continues for pde specific offset mapping. --- .../mode/experimental/ASTGenerator.java | 2 +- .../mode/experimental/ASTNodeWrapper.java | 78 ++++++++++++------- .../experimental/ErrorCheckerService.java | 4 + 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index becb60450..23750c7ab 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1126,7 +1126,7 @@ public class ASTGenerator { // 3 friggin casts. Javaaargh. ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); - int javaoffsets[] = awrap.getJavaCodeOffsets(); + int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], pdeoffsets[1], javaoffsets[2] diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index b8ad65c16..c17c22dce 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -2,6 +2,7 @@ package processing.mode.experimental; import java.util.Iterator; import java.util.List; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -53,7 +54,7 @@ public class ASTNodeWrapper { * @return int[]{line number, line number start offset, node start offset, * node length} */ - public int[] getJavaCodeOffsets() { + public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { int nodeOffset = Node.getStartPosition(), nodeLength = Node .getLength(); ASTNode thisNode = Node; @@ -110,59 +111,82 @@ public class ASTNodeWrapper { } } // System.out.println("Altspos " + altStartPos); - return new int[] { lineNumber,altStartPos , nodeOffset, nodeLength + normalizeOffsets(Node) }; + int pdeoffsets[] = getPDECodeOffsets(ecs); +// System.out.println("Line: "+ ecs.getPDECode(pdeoffsets[1] - 1)); + int x = normalizeOffsets(ecs.getPDECode(pdeoffsets[1] - 1), nodeOffset + - altStartPos); + int xlen = normalizeOffsets(Node.toString(),nodeLength); + System.out.println("X="+x + " xlen=" + xlen); + + return new int[] { lineNumber,altStartPos, nodeOffset+x, nodeLength+xlen}; } - /** - * Returns the difference in offsets between pde and java versions of the ast - * node - * - * @param anode - * @return offset adjustment - */ - private int normalizeOffsets(ASTNode anode){ - String source = anode.toString().trim(); + private int normalizeOffsets(String source, int inpOffset){ System.out.println("Src: " + source); + String sourceAlt = new String(source); int offset = 0; - String dataTypeFunc[] = { "Int", "Char", "Float", "Boolean", "Byte" }; + TreeMap offsetmap = new TreeMap(); + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; for (String dataType : dataTypeFunc) { - String dataTypeRegexp = "\\bPApplet.parse" + dataType + "\\s*\\("; + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; Pattern pattern = Pattern.compile(dataTypeRegexp); - Matcher matcher = pattern.matcher(source); + Matcher matcher = pattern.matcher(sourceAlt); while (matcher.find()) { System.out.print("Start index: " + matcher.start()); System.out.println(" End index: " + matcher.end() + " "); System.out.println("-->" + matcher.group() + "<--"); - offset = offset - ("PApplet.parse(").length(); + offsetmap.put(matcher.end(), ("PApplet.parse").length()); } - - + matcher.reset(); + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + + dataType.substring(1) + "("); + } - + // Find all #[web color] and replace with 0xff[webcolor] // Should be 6 digits only. final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; Pattern webPattern = Pattern.compile(webColorRegexp); - Matcher webMatcher = webPattern.matcher(source); + Matcher webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { // System.out.println("Found at: " + webMatcher.start()); - String found = source.substring(webMatcher.start(), webMatcher.end()); + String found = sourceAlt.substring(webMatcher.start(), + webMatcher.end()); // System.out.println("-> " + found); - source = webMatcher.replaceFirst("0xff" + found.substring(1)); - webMatcher = webPattern.matcher(source); - offset += 3; + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + offsetmap.put(webMatcher.end(), 3); } // Replace all color data types with int // Regex, Y U SO powerful? final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; Pattern colorPattern = Pattern.compile(colorTypeRegex); - Matcher colorMatcher = colorPattern.matcher(source); - source = colorMatcher.replaceAll("int"); - System.out.println(source + "-Norm offset " + offset); - return offset; + Matcher colorMatcher = colorPattern.matcher(sourceAlt); + sourceAlt = colorMatcher.replaceAll("int"); + while (colorMatcher.find()) { + System.out.print("Start index: " + colorMatcher.start()); + System.out.println(" End index: " + colorMatcher.end() + " "); + System.out.println("-->" + colorMatcher.group() + "<--"); + offsetmap.put(colorMatcher.end(), -2); + } + colorMatcher.reset(); + sourceAlt = colorMatcher.replaceAll("int"); + for (Integer key : offsetmap.keySet()) { + if(key < inpOffset){ + offset -= offsetmap.get(key); + } + else{ + break; + } + System.out.println(key + ":" + offsetmap.get(key)); + } + System.out.println(source); + System.out.println(sourceAlt); + return offset; } /** diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 0a84df988..5f90a2bea 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -810,6 +810,10 @@ public class ErrorCheckerService implements Runnable{ return new int[] { codeIndex, x }; } + public String getPDECode(int linenumber){ + return editor.ta.getLineText(linenumber); + } + /** * Calculates the tab number and line number of the error in that particular * tab. Provides mapping between pure java and pde code. From a5450455f639038d263abde9adda8f01f76da690 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 21 Jun 2013 01:20:38 +0530 Subject: [PATCH 053/608] Nearly there.. --- .../mode/experimental/ASTNodeWrapper.java | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index c17c22dce..50f2f90b3 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -113,16 +113,31 @@ public class ASTNodeWrapper { // System.out.println("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); // System.out.println("Line: "+ ecs.getPDECode(pdeoffsets[1] - 1)); - int x = normalizeOffsets(ecs.getPDECode(pdeoffsets[1] - 1), nodeOffset - - altStartPos); - int xlen = normalizeOffsets(Node.toString(),nodeLength); - System.out.println("X="+x + " xlen=" + xlen); - - return new int[] { lineNumber,altStartPos, nodeOffset+x, nodeLength+xlen}; + + TreeMap offsetmap = createOffsetMapping(ecs.getPDECode(pdeoffsets[1] - 1), + nodeOffset + - altStartPos); + int x = 0, xlen = 0; + for (Integer key : offsetmap.keySet()) { + System.out.println(key + ":" + offsetmap.get(key)); + } + for (Integer key : offsetmap.keySet()) { + if (key < nodeOffset - altStartPos) { + x -= offsetmap.get(key); + } + if (key >= nodeOffset - altStartPos && key <= nodeOffset - altStartPos + nodeLength) { + xlen -= offsetmap.get(key); + } + System.out.println(key + ":" + offsetmap.get(key)); + } + System.out.println("X=" + x + " xlen=" + xlen); + + return new int[] { + lineNumber, altStartPos, nodeOffset + x, nodeLength + xlen }; } - private int normalizeOffsets(String source, int inpOffset){ - System.out.println("Src: " + source); + private TreeMap createOffsetMapping(String source, int inpOffset){ + System.out.println("Src: " + source + " inpoff" + inpOffset); String sourceAlt = new String(source); int offset = 0; TreeMap offsetmap = new TreeMap(); @@ -156,8 +171,7 @@ public class ASTNodeWrapper { String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); // System.out.println("-> " + found); - sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); - webMatcher = webPattern.matcher(sourceAlt); + offsetmap.put(webMatcher.end(), 3); } @@ -166,7 +180,6 @@ public class ASTNodeWrapper { final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; Pattern colorPattern = Pattern.compile(colorTypeRegex); Matcher colorMatcher = colorPattern.matcher(sourceAlt); - sourceAlt = colorMatcher.replaceAll("int"); while (colorMatcher.find()) { System.out.print("Start index: " + colorMatcher.start()); System.out.println(" End index: " + colorMatcher.end() + " "); @@ -175,18 +188,9 @@ public class ASTNodeWrapper { } colorMatcher.reset(); sourceAlt = colorMatcher.replaceAll("int"); - for (Integer key : offsetmap.keySet()) { - if(key < inpOffset){ - offset -= offsetmap.get(key); - } - else{ - break; - } - System.out.println(key + ":" + offsetmap.get(key)); - } - System.out.println(source); + System.out.println(sourceAlt); - return offset; + return offsetmap; } /** From 717b26793a592edfaf882f1c4ea3fdfc35c44f9e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 21 Jun 2013 17:47:00 +0530 Subject: [PATCH 054/608] When sh*t gets real. Damn. --- .../mode/experimental/ASTNodeWrapper.java | 142 ++++++++++++++++-- 1 file changed, 133 insertions(+), 9 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 50f2f90b3..b039729ee 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -113,19 +113,68 @@ public class ASTNodeWrapper { // System.out.println("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); // System.out.println("Line: "+ ecs.getPDECode(pdeoffsets[1] - 1)); - - TreeMap offsetmap = createOffsetMapping(ecs.getPDECode(pdeoffsets[1] - 1), + String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1); + int ws = 0;//leftWS(pdeCode); + TreeMap offsetmap = createOffsetMapping(pdeCode, nodeOffset - altStartPos); int x = 0, xlen = 0; + System.out.println("Map:"); for (Integer key : offsetmap.keySet()) { System.out.println(key + ":" + offsetmap.get(key)); } + System.out.println((nodeOffset - altStartPos) + ",range, " +(nodeOffset - altStartPos + nodeLength)); + + int pdeCodeMap[] = new int[pdeCode.length()*2]; + int javaCodeMap[] = new int[pdeCode.length()*2]; + int pi = 1,pj = 1; + + for (Integer key : offsetmap.keySet()) { + for (; pi < key; pi++) { + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + } + for (; pj < key; pj++) { + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + } + + System.out.println(key + ":" + offsetmap.get(key)); + int kval =offsetmap.get(key); + if(kval > 0){ + // repeat pde offsets + pi--; + pj--; + for (int i = 0; i < kval; i++,pi++,pj++) { + pdeCodeMap[pi] = pdeCodeMap[pi-1]; + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + } + } + else + { + // repeat java offsets + pi--; + pj--; + for (int i = 0; i < -kval; i++,pi++,pj++) { + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + javaCodeMap[pj] = javaCodeMap[pj-1] ; + } + } + } + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; +// for (int i = 0; i < javaCodeMap.length; i++) { +// if(javaCodeMap[i] > 0 || pdeCodeMap[i] > 0 || i==0) +// System.out.println(javaCodeMap[i] + " - " + pdeCodeMap[i]); +// } +// System.out.println(); +// for (int i = 0; i < javaCodeMap.length; i++) { +// System.out.println(pdeCodeMap[i] + " "); +// } + for (Integer key : offsetmap.keySet()) { if (key < nodeOffset - altStartPos) { x -= offsetmap.get(key); } - if (key >= nodeOffset - altStartPos && key <= nodeOffset - altStartPos + nodeLength) { + if (key >= nodeOffset - altStartPos + ws && key <= nodeOffset - altStartPos + nodeLength+ws) { xlen -= offsetmap.get(key); } System.out.println(key + ":" + offsetmap.get(key)); @@ -136,13 +185,14 @@ public class ASTNodeWrapper { lineNumber, altStartPos, nodeOffset + x, nodeLength + xlen }; } - private TreeMap createOffsetMapping(String source, int inpOffset){ + @SuppressWarnings("unused") +private TreeMap createOffsetMapping(String source, int inpOffset){ System.out.println("Src: " + source + " inpoff" + inpOffset); String sourceAlt = new String(source); int offset = 0; TreeMap offsetmap = new TreeMap(); String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; - + for (String dataType : dataTypeFunc) { String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; Pattern pattern = Pattern.compile(dataTypeRegexp); @@ -152,7 +202,7 @@ public class ASTNodeWrapper { System.out.print("Start index: " + matcher.start()); System.out.println(" End index: " + matcher.end() + " "); System.out.println("-->" + matcher.group() + "<--"); - offsetmap.put(matcher.end(), ("PApplet.parse").length()); + offsetmap.put(matcher.end()-1, ("PApplet.parse").length()); } matcher.reset(); sourceAlt = matcher.replaceAll("PApplet.parse" @@ -171,8 +221,9 @@ public class ASTNodeWrapper { String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); // System.out.println("-> " + found); - - offsetmap.put(webMatcher.end(), 3); + offsetmap.put(webMatcher.end()-1, 3); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); } // Replace all color data types with int @@ -184,14 +235,87 @@ public class ASTNodeWrapper { System.out.print("Start index: " + colorMatcher.start()); System.out.println(" End index: " + colorMatcher.end() + " "); System.out.println("-->" + colorMatcher.group() + "<--"); - offsetmap.put(colorMatcher.end(), -2); + offsetmap.put(colorMatcher.end()-1, -2); } colorMatcher.reset(); sourceAlt = colorMatcher.replaceAll("int"); + + System.out.println(sourceAlt); + + int pdeCodeMap[] = new int[source.length()*2]; + int javaCodeMap[] = new int[source.length()*2]; + int pi = 1,pj = 1; + + for (Integer key : offsetmap.keySet()) { + for (; pi < key; pi++) { + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + } + for (; pj < key; pj++) { + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + } + + System.out.println(key + ":" + offsetmap.get(key)); + int kval =offsetmap.get(key); + if(kval > 0){ + // repeat pde offsets + pi--; + pj-=2; + for (int i = 0; i < kval; i++,pi++,pj++) { + pdeCodeMap[pi] = pdeCodeMap[pi-1]; + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + } + } + else + { + // repeat java offsets + pi--; + pj--; + for (int i = 0; i < -kval; i++,pi++,pj++) { + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + javaCodeMap[pj] = javaCodeMap[pj-1] ; + } + } + } + + + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + + + while (pi < sourceAlt.length()) { + pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + pi++; + } + while (pj < source.length()) { + javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + pj++; + } + + for (int i = 0; i < javaCodeMap.length; i++) { + if(javaCodeMap[i] > 0 || pdeCodeMap[i] > 0 || i==0) + if(i < source.length()) + System.out.print(source.charAt(i)); + System.out.print(javaCodeMap[i] + " - " + pdeCodeMap[i]); + if(i < sourceAlt.length()) + System.out.print(sourceAlt.charAt(i)); + System.out.println(); + } + System.out.println(); return offsetmap; } + + private int leftWS(String s) { + int i = 0; + for (; i < s.length(); i++) { + if (s.charAt(i) == ' ') + continue; + else + break; + } + return i; + } /** * From 8fab89452f002f416e2b66c43ce71675eec90f5c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 21 Jun 2013 21:20:18 +0530 Subject: [PATCH 055/608] Boom, it works \m/ --- .../mode/experimental/ASTNodeWrapper.java | 175 ++++++++---------- 1 file changed, 75 insertions(+), 100 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index b039729ee..53ba9e07f 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -113,81 +113,35 @@ public class ASTNodeWrapper { // System.out.println("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); // System.out.println("Line: "+ ecs.getPDECode(pdeoffsets[1] - 1)); - String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1); - int ws = 0;//leftWS(pdeCode); - TreeMap offsetmap = createOffsetMapping(pdeCode, - nodeOffset - - altStartPos); - int x = 0, xlen = 0; - System.out.println("Map:"); - for (Integer key : offsetmap.keySet()) { - System.out.println(key + ":" + offsetmap.get(key)); - } - System.out.println((nodeOffset - altStartPos) + ",range, " +(nodeOffset - altStartPos + nodeLength)); - - int pdeCodeMap[] = new int[pdeCode.length()*2]; - int javaCodeMap[] = new int[pdeCode.length()*2]; - int pi = 1,pj = 1; - - for (Integer key : offsetmap.keySet()) { - for (; pi < key; pi++) { - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; - } - for (; pj < key; pj++) { - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; - } - - System.out.println(key + ":" + offsetmap.get(key)); - int kval =offsetmap.get(key); - if(kval > 0){ - // repeat pde offsets - pi--; - pj--; - for (int i = 0; i < kval; i++,pi++,pj++) { - pdeCodeMap[pi] = pdeCodeMap[pi-1]; - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; - } - } - else - { - // repeat java offsets - pi--; - pj--; - for (int i = 0; i < -kval; i++,pi++,pj++) { - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; - javaCodeMap[pj] = javaCodeMap[pj-1] ; - } - } - } - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; -// for (int i = 0; i < javaCodeMap.length; i++) { -// if(javaCodeMap[i] > 0 || pdeCodeMap[i] > 0 || i==0) -// System.out.println(javaCodeMap[i] + " - " + pdeCodeMap[i]); + String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); +// int ws = 0;//leftWS(pdeCode); + int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); +// int x = 0, xlen = 0; +// System.out.println("Map:"); +// for (Integer key : offsetmap.keySet()) { +// System.out.println(key + ":" + offsetmap.get(key)); // } -// System.out.println(); -// for (int i = 0; i < javaCodeMap.length; i++) { -// System.out.println(pdeCodeMap[i] + " "); +// System.out.println((nodeOffset - altStartPos) + ",range, " +(nodeOffset - altStartPos + nodeLength)); +// +// +// for (Integer key : offsetmap.keySet()) { +// if (key < nodeOffset - altStartPos) { +// x -= offsetmap.get(key); +// } +// if (key >= nodeOffset - altStartPos + ws && key <= nodeOffset - altStartPos + nodeLength+ws) { +// xlen -= offsetmap.get(key); +// } +// System.out.println(key + ":" + offsetmap.get(key)); // } - - for (Integer key : offsetmap.keySet()) { - if (key < nodeOffset - altStartPos) { - x -= offsetmap.get(key); - } - if (key >= nodeOffset - altStartPos + ws && key <= nodeOffset - altStartPos + nodeLength+ws) { - xlen -= offsetmap.get(key); - } - System.out.println(key + ":" + offsetmap.get(key)); - } - System.out.println("X=" + x + " xlen=" + xlen); +// System.out.println("X=" + x + " xlen=" + xlen); return new int[] { - lineNumber, altStartPos, nodeOffset + x, nodeLength + xlen }; + lineNumber, altStartPos, nodeOffset + vals[0], vals[1]}; } @SuppressWarnings("unused") -private TreeMap createOffsetMapping(String source, int inpOffset){ - System.out.println("Src: " + source + " inpoff" + inpOffset); +private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ + System.out.println("Src:" + source + "\ninpoff" + inpOffset + " nodelen " + nodeLen); String sourceAlt = new String(source); int offset = 0; TreeMap offsetmap = new TreeMap(); @@ -202,7 +156,7 @@ private TreeMap createOffsetMapping(String source, int inpOffs System.out.print("Start index: " + matcher.start()); System.out.println(" End index: " + matcher.end() + " "); System.out.println("-->" + matcher.group() + "<--"); - offsetmap.put(matcher.end()-1, ("PApplet.parse").length()); + offsetmap.put(matcher.end()+1, ("PApplet.parse").length()); } matcher.reset(); sourceAlt = matcher.replaceAll("PApplet.parse" @@ -244,16 +198,16 @@ private TreeMap createOffsetMapping(String source, int inpOffs System.out.println(sourceAlt); - int pdeCodeMap[] = new int[source.length()*2]; int javaCodeMap[] = new int[source.length()*2]; + int pdeeCodeMap[] = new int[source.length()*2]; int pi = 1,pj = 1; for (Integer key : offsetmap.keySet()) { for (; pi < key; pi++) { - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + javaCodeMap[pi] = javaCodeMap[pi-1] + 1; } for (; pj < key; pj++) { - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; } System.out.println(key + ":" + offsetmap.get(key)); @@ -263,8 +217,8 @@ private TreeMap createOffsetMapping(String source, int inpOffs pi--; pj-=2; for (int i = 0; i < kval; i++,pi++,pj++) { - pdeCodeMap[pi] = pdeCodeMap[pi-1]; - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + javaCodeMap[pi] = javaCodeMap[pi-1]; + pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; } } else @@ -273,50 +227,71 @@ private TreeMap createOffsetMapping(String source, int inpOffs pi--; pj--; for (int i = 0; i < -kval; i++,pi++,pj++) { - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; - javaCodeMap[pj] = javaCodeMap[pj-1] ; + javaCodeMap[pi] = javaCodeMap[pi-1] + 1; + pdeeCodeMap[pj] = pdeeCodeMap[pj-1] ; } } } - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + javaCodeMap[pi] = javaCodeMap[pi-1] + 1; + pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; while (pi < sourceAlt.length()) { - pdeCodeMap[pi] = pdeCodeMap[pi-1] + 1; + javaCodeMap[pi] = javaCodeMap[pi-1] + 1; pi++; } while (pj < source.length()) { - javaCodeMap[pj] = javaCodeMap[pj-1] + 1; + pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; pj++; } - for (int i = 0; i < javaCodeMap.length; i++) { - if(javaCodeMap[i] > 0 || pdeCodeMap[i] > 0 || i==0) - if(i < source.length()) - System.out.print(source.charAt(i)); - System.out.print(javaCodeMap[i] + " - " + pdeCodeMap[i]); - if(i < sourceAlt.length()) - System.out.print(sourceAlt.charAt(i)); - System.out.println(); + for (int i = 0; i < pdeeCodeMap.length; i++) { + if (pdeeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { + if (i < source.length()) + System.out.print(source.charAt(i)); + System.out.print(pdeeCodeMap[i] + " - " + javaCodeMap[i] + " <-["+i+"]"); + if (i < sourceAlt.length()) + System.out.print(sourceAlt.charAt(i)); + System.out.println(); + } } System.out.println(); - return offsetmap; + pj = 0; + pi = 0; + int count = 0; + // first find the java code index +// while(javaCodeMap[pj] != inpOffset && pj < javaCodeMap.length) +// pj++; + pj=inpOffset; + + int startIndex = javaCodeMap[pj]; + + // find beginning + while(pdeeCodeMap[pi] != startIndex && pi < pdeeCodeMap.length) + pi++; + int startoffDif = pi - pj; +// while((javaCodeMap[pj] != inpOffset + nodeLen) && pj < javaCodeMap.length) +// pj++; + int stopindex = javaCodeMap[pj+nodeLen]; + System.out.println(startIndex+"SI,St"+stopindex + "sod " +startoffDif); + // Use this index in the pdemap + + + + // count till stopindex + while(pdeeCodeMap[pi] < stopindex && pi < pdeeCodeMap.length){ + pi++; + count++; + } + +// System.out.println("PDE maps from " + pdeeCodeMap[pi]); + + System.out.println("pde len " + count); + return new int[] { startoffDif,count }; } - private int leftWS(String s) { - int i = 0; - for (; i < s.length(); i++) { - if (s.charAt(i) == ' ') - continue; - else - break; - } - return i; - } - /** * * @param ecs From 60c0d03a2b92d967cade5acb51d784ba8a1399f8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 22 Jun 2013 01:00:47 +0530 Subject: [PATCH 056/608] Dear lord. Gimme the strength. To destroy this bug for eternity. --- pdex/Todo, GSoC 2013.txt | 5 +- .../mode/experimental/ASTNodeWrapper.java | 74 +++++++++++-------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index a690e2dec..10591ffb8 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -33,8 +33,9 @@ First major hurdle is offset mapping * pde<->java code offset : precise conversion needed x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. * This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. -x Edge case - multiple staetments in a single line -* PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. +x Edge case - multiple statements in a single line +x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. +* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will look into later. Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 53ba9e07f..396d71c8b 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -145,27 +145,9 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ String sourceAlt = new String(source); int offset = 0; TreeMap offsetmap = new TreeMap(); - String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; - for (String dataType : dataTypeFunc) { - String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; - Pattern pattern = Pattern.compile(dataTypeRegexp); - Matcher matcher = pattern.matcher(sourceAlt); - while (matcher.find()) { - System.out.print("Start index: " + matcher.start()); - System.out.println(" End index: " + matcher.end() + " "); - System.out.println("-->" + matcher.group() + "<--"); - offsetmap.put(matcher.end()+1, ("PApplet.parse").length()); - } - matcher.reset(); - sourceAlt = matcher.replaceAll("PApplet.parse" - + Character.toUpperCase(dataType.charAt(0)) - + dataType.substring(1) + "("); - - } - - // Find all #[web color] and replace with 0xff[webcolor] + // Find all #[web color] // Should be 6 digits only. final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; Pattern webPattern = Pattern.compile(webColorRegexp); @@ -176,9 +158,8 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ webMatcher.end()); // System.out.println("-> " + found); offsetmap.put(webMatcher.end()-1, 3); - sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); - webMatcher = webPattern.matcher(sourceAlt); } + // Replace all color data types with int // Regex, Y U SO powerful? @@ -191,17 +172,48 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ System.out.println("-->" + colorMatcher.group() + "<--"); offsetmap.put(colorMatcher.end()-1, -2); } - colorMatcher.reset(); + + + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(sourceAlt); + + while (matcher.find()) { + System.out.print("Start index: " + matcher.start()); + System.out.println(" End index: " + matcher.end() + " "); + System.out.println("-->" + matcher.group() + "<--"); + offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); + } + matcher.reset(); + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) + + "("); + + } + + // replace with 0xff[webcolor] + webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = sourceAlt.substring(webMatcher.start(), + webMatcher.end()); + // System.out.println("-> " + found); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + } + + colorMatcher = colorPattern.matcher(sourceAlt); sourceAlt = colorMatcher.replaceAll("int"); - - System.out.println(sourceAlt); int javaCodeMap[] = new int[source.length()*2]; int pdeeCodeMap[] = new int[source.length()*2]; int pi = 1,pj = 1; - + int keySum = 0; for (Integer key : offsetmap.keySet()) { for (; pi < key; pi++) { javaCodeMap[pi] = javaCodeMap[pi-1] + 1; @@ -211,11 +223,12 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ } System.out.println(key + ":" + offsetmap.get(key)); + int kval =offsetmap.get(key); if(kval > 0){ - // repeat pde offsets + // repeat java offsets pi--; - pj-=2; + pj--; for (int i = 0; i < kval; i++,pi++,pj++) { javaCodeMap[pi] = javaCodeMap[pi-1]; pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; @@ -223,7 +236,7 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ } else { - // repeat java offsets + // repeat pde offsets pi--; pj--; for (int i = 0; i < -kval; i++,pi++,pj++) { @@ -231,6 +244,8 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ pdeeCodeMap[pj] = pdeeCodeMap[pj-1] ; } } + keySum+=offsetmap.get(key); + System.out.println("=="); } @@ -251,9 +266,10 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ if (pdeeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { if (i < source.length()) System.out.print(source.charAt(i)); - System.out.print(pdeeCodeMap[i] + " - " + javaCodeMap[i] + " <-["+i+"]"); + System.out.print(pdeeCodeMap[i] + " - " + javaCodeMap[i]); if (i < sourceAlt.length()) System.out.print(sourceAlt.charAt(i)); + System.out.print(" <-["+i+"]"); System.out.println(); } } From 3af21043529df10150b86b768edc1a5a586b62d7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 22 Jun 2013 01:17:50 +0530 Subject: [PATCH 057/608] A deft touch to finish it off. Pheww. --- pdex/src/processing/mode/experimental/ASTNodeWrapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 396d71c8b..de3fb300e 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -276,7 +276,7 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ System.out.println(); pj = 0; pi = 0; - int count = 0; + int count = 1; // first find the java code index // while(javaCodeMap[pj] != inpOffset && pj < javaCodeMap.length) // pj++; @@ -290,7 +290,7 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ int startoffDif = pi - pj; // while((javaCodeMap[pj] != inpOffset + nodeLen) && pj < javaCodeMap.length) // pj++; - int stopindex = javaCodeMap[pj+nodeLen]; + int stopindex = javaCodeMap[pj+nodeLen-1]; System.out.println(startIndex+"SI,St"+stopindex + "sod " +startoffDif); // Use this index in the pdemap From 54e08667b480ea59a99abdebf920fb0cba2b1112 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 22 Jun 2013 01:45:36 +0530 Subject: [PATCH 058/608] Some comments and thoughts. --- .../mode/experimental/ASTNodeWrapper.java | 198 +++++++++--------- 1 file changed, 94 insertions(+), 104 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index de3fb300e..04e84db84 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -112,40 +112,48 @@ public class ASTNodeWrapper { } // System.out.println("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); -// System.out.println("Line: "+ ecs.getPDECode(pdeoffsets[1] - 1)); String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); -// int ws = 0;//leftWS(pdeCode); int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); -// int x = 0, xlen = 0; -// System.out.println("Map:"); -// for (Integer key : offsetmap.keySet()) { -// System.out.println(key + ":" + offsetmap.get(key)); -// } -// System.out.println((nodeOffset - altStartPos) + ",range, " +(nodeOffset - altStartPos + nodeLength)); -// -// -// for (Integer key : offsetmap.keySet()) { -// if (key < nodeOffset - altStartPos) { -// x -= offsetmap.get(key); -// } -// if (key >= nodeOffset - altStartPos + ws && key <= nodeOffset - altStartPos + nodeLength+ws) { -// xlen -= offsetmap.get(key); -// } -// System.out.println(key + ":" + offsetmap.get(key)); -// } -// System.out.println("X=" + x + " xlen=" + xlen); - return new int[] { lineNumber, altStartPos, nodeOffset + vals[0], vals[1]}; } - @SuppressWarnings("unused") -private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ - System.out.println("Src:" + source + "\ninpoff" + inpOffset + " nodelen " + nodeLen); - String sourceAlt = new String(source); - int offset = 0; - TreeMap offsetmap = new TreeMap(); + + private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { + /* + * This is some tricky shiz. So detailed explanation follows: + * + * The main issue here is that pde enhancements like color vars, # literals + * and int() type casting deviate from standard java. But I need to exact + * index matching for pde and java versions of snippets.For ex: + * "color col = #ffaadd;" <-PDE version "int col = 0xffffaadd;" <-Converted + * to Java + * + * For exact index mapping, I need to know at what indices either is + * deviating from the other and by what amount. Turns out, it isn't quite + * easy.(1) First I take the pde version of the code as an argument(pde + * version fetched from the editor directly). I then find all instances + * which need to be converted to pure java, marking those indices and the + * index correction needed. (2) Now all java conversions are applied after + * marking the offsets. This ensures that the index order isn't disturbed by + * one at a time conversions as done in preprocessCode() in ECS. Took me + * sometime to figure out this was a bug. (3) Next I create a tables(two + * separate arrays) which allows me to look it up for matching any index + * between pde or java version of the snippet. This also lets me find out + * any difference in length between both versions. + * + * Keep in mind though, dark magic was involved in creating the final lookup + * table. + * + * TODO: This is a work in progress. There may be more bugs here in hiding. + */ + + + System.out.println("Src:" + source + "\ninpoff" + inpOffset + " nodelen " + + nodeLen); + String sourceAlt = new String(source); + TreeMap offsetmap = new TreeMap(); // Find all #[web color] // Should be 6 digits only. @@ -154,26 +162,22 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ Matcher webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { // System.out.println("Found at: " + webMatcher.start()); - String found = sourceAlt.substring(webMatcher.start(), - webMatcher.end()); // System.out.println("-> " + found); - offsetmap.put(webMatcher.end()-1, 3); + offsetmap.put(webMatcher.end() - 1, 3); } - - // Replace all color data types with int - // Regex, Y U SO powerful? + // Find all color data types final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; Pattern colorPattern = Pattern.compile(colorTypeRegex); Matcher colorMatcher = colorPattern.matcher(sourceAlt); while (colorMatcher.find()) { - System.out.print("Start index: " + colorMatcher.start()); - System.out.println(" End index: " + colorMatcher.end() + " "); - System.out.println("-->" + colorMatcher.group() + "<--"); - offsetmap.put(colorMatcher.end()-1, -2); +// System.out.print("Start index: " + colorMatcher.start()); +// System.out.println(" End index: " + colorMatcher.end() + " "); +// System.out.println("-->" + colorMatcher.group() + "<--"); + offsetmap.put(colorMatcher.end() - 1, -2); } - - + + // Find all int(), char() String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; for (String dataType : dataTypeFunc) { @@ -182,9 +186,9 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ Matcher matcher = pattern.matcher(sourceAlt); while (matcher.find()) { - System.out.print("Start index: " + matcher.start()); - System.out.println(" End index: " + matcher.end() + " "); - System.out.println("-->" + matcher.group() + "<--"); +// System.out.print("Start index: " + matcher.start()); +// System.out.println(" End index: " + matcher.end() + " "); +// System.out.println("-->" + matcher.group() + "<--"); offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); } matcher.reset(); @@ -193,83 +197,76 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ + "("); } - - // replace with 0xff[webcolor] + + // replace with 0xff[webcolor] and others webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { // System.out.println("Found at: " + webMatcher.start()); - String found = sourceAlt.substring(webMatcher.start(), - webMatcher.end()); + String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); // System.out.println("-> " + found); sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); webMatcher = webPattern.matcher(sourceAlt); } - + colorMatcher = colorPattern.matcher(sourceAlt); sourceAlt = colorMatcher.replaceAll("int"); - + System.out.println(sourceAlt); - - int javaCodeMap[] = new int[source.length()*2]; - int pdeeCodeMap[] = new int[source.length()*2]; - int pi = 1,pj = 1; - int keySum = 0; + + // Create code map. Beware! Dark magic ahead. + int javaCodeMap[] = new int[source.length() * 2]; + int pdeCodeMap[] = new int[source.length() * 2]; + int pi = 1, pj = 1; for (Integer key : offsetmap.keySet()) { - for (; pi < key; pi++) { - javaCodeMap[pi] = javaCodeMap[pi-1] + 1; + for (; pi < key; pi++) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; } - for (; pj < key; pj++) { - pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; + for (; pj < key; pj++) { + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; } - + System.out.println(key + ":" + offsetmap.get(key)); - - int kval =offsetmap.get(key); - if(kval > 0){ + + int kval = offsetmap.get(key); + if (kval > 0) { // repeat java offsets pi--; pj--; - for (int i = 0; i < kval; i++,pi++,pj++) { - javaCodeMap[pi] = javaCodeMap[pi-1]; - pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; + for (int i = 0; i < kval; i++, pi++, pj++) { + javaCodeMap[pi] = javaCodeMap[pi - 1]; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; } - } - else - { + } else { // repeat pde offsets pi--; pj--; - for (int i = 0; i < -kval; i++,pi++,pj++) { - javaCodeMap[pi] = javaCodeMap[pi-1] + 1; - pdeeCodeMap[pj] = pdeeCodeMap[pj-1] ; + for (int i = 0; i < -kval; i++, pi++, pj++) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1]; } } - keySum+=offsetmap.get(key); - System.out.println("=="); } - - - javaCodeMap[pi] = javaCodeMap[pi-1] + 1; - pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; - - + + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + while (pi < sourceAlt.length()) { - javaCodeMap[pi] = javaCodeMap[pi-1] + 1; + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; pi++; } while (pj < source.length()) { - pdeeCodeMap[pj] = pdeeCodeMap[pj-1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; pj++; } - - for (int i = 0; i < pdeeCodeMap.length; i++) { - if (pdeeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { + + for (int i = 0; i < pdeCodeMap.length; i++) { + if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { if (i < source.length()) System.out.print(source.charAt(i)); - System.out.print(pdeeCodeMap[i] + " - " + javaCodeMap[i]); + System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]); if (i < sourceAlt.length()) System.out.print(sourceAlt.charAt(i)); - System.out.print(" <-["+i+"]"); + System.out.print(" <-[" + i + "]"); System.out.println(); } } @@ -278,34 +275,27 @@ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen){ pi = 0; int count = 1; // first find the java code index -// while(javaCodeMap[pj] != inpOffset && pj < javaCodeMap.length) -// pj++; - pj=inpOffset; - + pj = inpOffset; + int startIndex = javaCodeMap[pj]; - - // find beginning - while(pdeeCodeMap[pi] != startIndex && pi < pdeeCodeMap.length) + + // find beginning + while (pdeCodeMap[pi] != startIndex && pi < pdeCodeMap.length) pi++; int startoffDif = pi - pj; -// while((javaCodeMap[pj] != inpOffset + nodeLen) && pj < javaCodeMap.length) -// pj++; - int stopindex = javaCodeMap[pj+nodeLen-1]; - System.out.println(startIndex+"SI,St"+stopindex + "sod " +startoffDif); - // Use this index in the pdemap - - - + int stopindex = javaCodeMap[pj + nodeLen - 1]; + System.out.println(startIndex + "SI,St" + stopindex + "sod " + startoffDif); + // count till stopindex - while(pdeeCodeMap[pi] < stopindex && pi < pdeeCodeMap.length){ + while (pdeCodeMap[pi] < stopindex && pi < pdeCodeMap.length) { pi++; count++; } - + // System.out.println("PDE maps from " + pdeeCodeMap[pi]); - + System.out.println("pde len " + count); - return new int[] { startoffDif,count }; + return new int[] { startoffDif, count }; } /** From fed19cf712b69f10ae4783f9779d60a43465e447 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Jun 2013 12:02:00 +0530 Subject: [PATCH 059/608] Offset mapping bug fix. Definitely getting better. --- pdex/Todo, GSoC 2013.txt | 10 +++++----- .../processing/mode/experimental/ASTGenerator.java | 11 +++++------ .../mode/experimental/ASTNodeWrapper.java | 14 ++++++++------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 10591ffb8..1a0187c76 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -26,17 +26,17 @@ Finer details * Sorted list of completion candidates - fields, then methods. It's unsorted presently. *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. * Reflection API - getMethods vs getDeclaredMethods. +* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? -Refactoring +Offset Mapping & Refactoring =========== First major hurdle is offset mapping -* pde<->java code offset : precise conversion needed +*! pde<->java code offset : precise conversion needed x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. * This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. x Edge case - multiple statements in a single line x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. -* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will look into later. - +* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. @@ -45,7 +45,7 @@ Refactoring would work only when code is compiler error free. I plan to do a fin 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. Quick Navigation -============== +================ x Ctrl + Click on an element to scroll to its definition in code x Local Vars x Local Methods diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 23750c7ab..bf3f153db 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1010,8 +1010,9 @@ public class ASTGenerator { System.out.println("+> " + lineNode); ASTNode decl = null; if (lineNode != null) { - System.out.println("FLON2: " + lineNumber + " LN O " - + lineNode.getStartPosition()); + ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); + System.out.println("FLON2: " + lineNumber + " LN spos " + + lineNode.getStartPosition() + " off " + offset); ASTNode simpName = pinpointOnLine(lineNode, offset, lineNode.getStartPosition(), name); System.out.println("+++> " + simpName); @@ -1128,10 +1129,8 @@ public class ASTGenerator { int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1], - javaoffsets[2] - - javaoffsets[1], - javaoffsets[3]); + pdeoffsets[1],javaoffsets[1], + javaoffsets[2]); } } }; diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 04e84db84..e22b328ba 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -115,7 +115,7 @@ public class ASTNodeWrapper { String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); return new int[] { - lineNumber, altStartPos, nodeOffset + vals[0], vals[1]}; + lineNumber, nodeOffset + vals[0] - altStartPos, vals[1]}; } @@ -127,10 +127,10 @@ public class ASTNodeWrapper { * The main issue here is that pde enhancements like color vars, # literals * and int() type casting deviate from standard java. But I need to exact * index matching for pde and java versions of snippets.For ex: - * "color col = #ffaadd;" <-PDE version "int col = 0xffffaadd;" <-Converted - * to Java + * "color col = #ffaadd;" <-PDE version + * "int col = 0xffffaadd;" <-Converted to Java * - * For exact index mapping, I need to know at what indices either is + * For exact index mapping, I need to know at which indices either is * deviating from the other and by what amount. Turns out, it isn't quite * easy.(1) First I take the pde version of the code as an argument(pde * version fetched from the editor directly). I then find all instances @@ -217,11 +217,12 @@ public class ASTNodeWrapper { int javaCodeMap[] = new int[source.length() * 2]; int pdeCodeMap[] = new int[source.length() * 2]; int pi = 1, pj = 1; + int keySum = 0; for (Integer key : offsetmap.keySet()) { - for (; pi < key; pi++) { + for (; pi < key +keySum; pi++) { javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; } - for (; pj < key; pj++) { + for (; pj < key+keySum; pj++) { pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; } @@ -245,6 +246,7 @@ public class ASTNodeWrapper { pdeCodeMap[pj] = pdeCodeMap[pj - 1]; } } + keySum += kval; } javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; From fc7c5f938d29334400bb820c8b446b17005f1322 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Jun 2013 12:45:31 +0530 Subject: [PATCH 060/608] Offset mapping bug fixes --- .../mode/experimental/ASTNodeWrapper.java | 147 +++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index e22b328ba..a6d10f965 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -149,7 +149,7 @@ public class ASTNodeWrapper { * TODO: This is a work in progress. There may be more bugs here in hiding. */ - + /* System.out.println("Src:" + source + "\ninpoff" + inpOffset + " nodelen " + nodeLen); String sourceAlt = new String(source); @@ -246,6 +246,9 @@ public class ASTNodeWrapper { pdeCodeMap[pj] = pdeCodeMap[pj - 1]; } } + + // after each adjustment, the key values need to keep + // up with changed offset keySum += kval; } @@ -273,6 +276,11 @@ public class ASTNodeWrapper { } } System.out.println(); + */ + int ret[][] = getOffsetMapping(source); + int javaCodeMap[] = ret[0]; + int pdeCodeMap[] = ret[1]; + int pi = 1, pj = 1; pj = 0; pi = 0; int count = 1; @@ -299,6 +307,143 @@ public class ASTNodeWrapper { System.out.println("pde len " + count); return new int[] { startoffDif, count }; } + + /** + * Generates offset mapping between java and pde code + * + * @param source + * @return int[0] - java code offsets, int[1] = pde code offsets + */ + public int[][] getOffsetMapping(String source){ + System.out.println("Src:" + source); + String sourceAlt = new String(source); + TreeMap offsetmap = new TreeMap(); + + // Find all #[web color] + // Should be 6 digits only. + final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; + Pattern webPattern = Pattern.compile(webColorRegexp); + Matcher webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + // System.out.println("-> " + found); + offsetmap.put(webMatcher.end() - 1, 3); + } + + // Find all color data types + final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; + Pattern colorPattern = Pattern.compile(colorTypeRegex); + Matcher colorMatcher = colorPattern.matcher(sourceAlt); + while (colorMatcher.find()) { +// System.out.print("Start index: " + colorMatcher.start()); +// System.out.println(" End index: " + colorMatcher.end() + " "); +// System.out.println("-->" + colorMatcher.group() + "<--"); + offsetmap.put(colorMatcher.end() - 1, -2); + } + + // Find all int(), char() + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(sourceAlt); + + while (matcher.find()) { +// System.out.print("Start index: " + matcher.start()); +// System.out.println(" End index: " + matcher.end() + " "); +// System.out.println("-->" + matcher.group() + "<--"); + offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); + } + matcher.reset(); + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) + + "("); + + } + + // replace with 0xff[webcolor] and others + webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); + // System.out.println("-> " + found); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + } + + colorMatcher = colorPattern.matcher(sourceAlt); + sourceAlt = colorMatcher.replaceAll("int"); + + System.out.println(sourceAlt); + + // Create code map. Beware! Dark magic ahead. + int javaCodeMap[] = new int[source.length() * 2]; + int pdeCodeMap[] = new int[source.length() * 2]; + int pi = 1, pj = 1; + int keySum = 0; + for (Integer key : offsetmap.keySet()) { + for (; pi < key +keySum; pi++) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + } + for (; pj < key; pj++) { + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + } + + System.out.println(key + ":" + offsetmap.get(key)); + + int kval = offsetmap.get(key); + if (kval > 0) { + // repeat java offsets + pi--; + pj--; + for (int i = 0; i < kval; i++, pi++, pj++) { + javaCodeMap[pi] = javaCodeMap[pi - 1]; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + } + } else { + // repeat pde offsets + pi--; + pj--; + for (int i = 0; i < -kval; i++, pi++, pj++) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1]; + } + } + + // after each adjustment, the key values need to keep + // up with changed offset + keySum += kval; + } + + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + + while (pi < sourceAlt.length()) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pi++; + } + while (pj < source.length()) { + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + pj++; + } + + // deubg o/p + for (int i = 0; i < pdeCodeMap.length; i++) { + if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { + if (i < source.length()) + System.out.print(source.charAt(i)); + System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]); + if (i < sourceAlt.length()) + System.out.print(sourceAlt.charAt(i)); + System.out.print(" <-[" + i + "]"); + System.out.println(); + } + } + System.out.println(); + + return new int[][]{javaCodeMap,pdeCodeMap}; + } /** * From 457a219db410a533c361ce48d0b652cf2dbe31ea Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Jun 2013 13:00:55 +0530 Subject: [PATCH 061/608] Ctrl+Click with offset handling. Also moved stuff around. --- .../mode/experimental/ASTGenerator.java | 11 +- .../mode/experimental/ASTNodeWrapper.java | 193 ++++-------------- 2 files changed, 45 insertions(+), 159 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index bf3f153db..d19305ba5 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1011,9 +1011,16 @@ public class ASTGenerator { ASTNode decl = null; if (lineNode != null) { ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); + int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); + int javaCodeMap[] = ret[0]; + int altOff = 0; + for (; altOff < javaCodeMap.length; altOff++) { + if(javaCodeMap[altOff] == offset) + break; + } System.out.println("FLON2: " + lineNumber + " LN spos " - + lineNode.getStartPosition() + " off " + offset); - ASTNode simpName = pinpointOnLine(lineNode, offset, + + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); System.out.println("+++> " + simpName); if (simpName instanceof SimpleName) { diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index a6d10f965..66affac5c 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -120,163 +120,7 @@ public class ASTNodeWrapper { private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { - - /* - * This is some tricky shiz. So detailed explanation follows: - * - * The main issue here is that pde enhancements like color vars, # literals - * and int() type casting deviate from standard java. But I need to exact - * index matching for pde and java versions of snippets.For ex: - * "color col = #ffaadd;" <-PDE version - * "int col = 0xffffaadd;" <-Converted to Java - * - * For exact index mapping, I need to know at which indices either is - * deviating from the other and by what amount. Turns out, it isn't quite - * easy.(1) First I take the pde version of the code as an argument(pde - * version fetched from the editor directly). I then find all instances - * which need to be converted to pure java, marking those indices and the - * index correction needed. (2) Now all java conversions are applied after - * marking the offsets. This ensures that the index order isn't disturbed by - * one at a time conversions as done in preprocessCode() in ECS. Took me - * sometime to figure out this was a bug. (3) Next I create a tables(two - * separate arrays) which allows me to look it up for matching any index - * between pde or java version of the snippet. This also lets me find out - * any difference in length between both versions. - * - * Keep in mind though, dark magic was involved in creating the final lookup - * table. - * - * TODO: This is a work in progress. There may be more bugs here in hiding. - */ - - /* - System.out.println("Src:" + source + "\ninpoff" + inpOffset + " nodelen " - + nodeLen); - String sourceAlt = new String(source); - TreeMap offsetmap = new TreeMap(); - - // Find all #[web color] - // Should be 6 digits only. - final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; - Pattern webPattern = Pattern.compile(webColorRegexp); - Matcher webMatcher = webPattern.matcher(sourceAlt); - while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - // System.out.println("-> " + found); - offsetmap.put(webMatcher.end() - 1, 3); - } - - // Find all color data types - final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; - Pattern colorPattern = Pattern.compile(colorTypeRegex); - Matcher colorMatcher = colorPattern.matcher(sourceAlt); - while (colorMatcher.find()) { -// System.out.print("Start index: " + colorMatcher.start()); -// System.out.println(" End index: " + colorMatcher.end() + " "); -// System.out.println("-->" + colorMatcher.group() + "<--"); - offsetmap.put(colorMatcher.end() - 1, -2); - } - - // Find all int(), char() - String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; - - for (String dataType : dataTypeFunc) { - String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; - Pattern pattern = Pattern.compile(dataTypeRegexp); - Matcher matcher = pattern.matcher(sourceAlt); - - while (matcher.find()) { -// System.out.print("Start index: " + matcher.start()); -// System.out.println(" End index: " + matcher.end() + " "); -// System.out.println("-->" + matcher.group() + "<--"); - offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); - } - matcher.reset(); - sourceAlt = matcher.replaceAll("PApplet.parse" - + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) - + "("); - - } - - // replace with 0xff[webcolor] and others - webMatcher = webPattern.matcher(sourceAlt); - while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); - // System.out.println("-> " + found); - sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); - webMatcher = webPattern.matcher(sourceAlt); - } - - colorMatcher = colorPattern.matcher(sourceAlt); - sourceAlt = colorMatcher.replaceAll("int"); - - System.out.println(sourceAlt); - - // Create code map. Beware! Dark magic ahead. - int javaCodeMap[] = new int[source.length() * 2]; - int pdeCodeMap[] = new int[source.length() * 2]; - int pi = 1, pj = 1; - int keySum = 0; - for (Integer key : offsetmap.keySet()) { - for (; pi < key +keySum; pi++) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - } - for (; pj < key+keySum; pj++) { - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - } - - System.out.println(key + ":" + offsetmap.get(key)); - - int kval = offsetmap.get(key); - if (kval > 0) { - // repeat java offsets - pi--; - pj--; - for (int i = 0; i < kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1]; - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - } - } else { - // repeat pde offsets - pi--; - pj--; - for (int i = 0; i < -kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pdeCodeMap[pj] = pdeCodeMap[pj - 1]; - } - } - - // after each adjustment, the key values need to keep - // up with changed offset - keySum += kval; - } - - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - - while (pi < sourceAlt.length()) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pi++; - } - while (pj < source.length()) { - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - pj++; - } - - for (int i = 0; i < pdeCodeMap.length; i++) { - if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { - if (i < source.length()) - System.out.print(source.charAt(i)); - System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]); - if (i < sourceAlt.length()) - System.out.print(sourceAlt.charAt(i)); - System.out.print(" <-[" + i + "]"); - System.out.println(); - } - } - System.out.println(); - */ + int ret[][] = getOffsetMapping(source); int javaCodeMap[] = ret[0]; int pdeCodeMap[] = ret[1]; @@ -315,6 +159,35 @@ public class ASTNodeWrapper { * @return int[0] - java code offsets, int[1] = pde code offsets */ public int[][] getOffsetMapping(String source){ + + /* + * This is some tricky shiz. So detailed explanation follows: + * + * The main issue here is that pde enhancements like color vars, # literals + * and int() type casting deviate from standard java. But I need to exact + * index matching for pde and java versions of snippets.For ex: + * "color col = #ffaadd;" <-PDE version + * "int col = 0xffffaadd;" <-Converted to Java + * + * For exact index mapping, I need to know at which indices either is + * deviating from the other and by what amount. Turns out, it isn't quite + * easy.(1) First I take the pde version of the code as an argument(pde + * version fetched from the editor directly). I then find all instances + * which need to be converted to pure java, marking those indices and the + * index correction needed. (2) Now all java conversions are applied after + * marking the offsets. This ensures that the index order isn't disturbed by + * one at a time conversions as done in preprocessCode() in ECS. Took me + * sometime to figure out this was a bug. (3) Next I create a tables(two + * separate arrays) which allows me to look it up for matching any index + * between pde or java version of the snippet. This also lets me find out + * any difference in length between both versions. + * + * Keep in mind though, dark magic was involved in creating the final lookup + * table. + * + * TODO: This is a work in progress. There may be more bugs here in hiding. + */ + System.out.println("Src:" + source); String sourceAlt = new String(source); TreeMap offsetmap = new TreeMap(); @@ -444,6 +317,12 @@ public class ASTNodeWrapper { return new int[][]{javaCodeMap,pdeCodeMap}; } + + public int[][] getOffsetMapping(ErrorCheckerService ecs){ + int pdeoffsets[] = getPDECodeOffsets(ecs); + String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); + return getOffsetMapping(pdeCode); + } /** * From b29f91ed62d344d676196fc5b11d78f52fd18b59 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Jun 2013 21:23:20 +0530 Subject: [PATCH 062/608] Ctrl+Click further fixes. Now works with multiple statements on a line. --- .../mode/experimental/ASTGenerator.java | 58 +++++++++++++++---- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index d19305ba5..e19ab9f58 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1007,19 +1007,57 @@ public class ASTGenerator { } System.out.println("FLON: " + lineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); + System.out.println("+> " + lineNode); ASTNode decl = null; if (lineNode != null) { ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); - int javaCodeMap[] = ret[0]; + int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; int altOff = 0; for (; altOff < javaCodeMap.length; altOff++) { - if(javaCodeMap[altOff] == offset) + if(javaCodeMap[altOff] == pdeCodeMap[offset]){ + //altOff = javaCodeMap[altOff]; break; + } } System.out.println("FLON2: " + lineNumber + " LN spos " + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + /* + * Now I need to see if multiple statements exist with this same line number + * If that's the case, I need to ensure the offset is right. + */ + ASTNode parLineNode = lineNode.getParent(); + + Iterator it = parLineNode + .structuralPropertiesForType().iterator(); + boolean flag = true; + int lineStartPos = lineNode.getStartPosition(), offAdjust = 0; + while (it.hasNext() && flag) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) parLineNode + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (getLineNumber(cnode) == lineNumber) { + if (cnode.getStartPosition() <= lineNode.getStartPosition() + + altOff + && cnode.getStartPosition() + cnode.getLength() > lineNode + .getStartPosition() + altOff) { + System.out.println(cnode); + offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); + lineNode = cnode; + altOff -= offAdjust; + flag = false; + break; + } + + } + } + } + } + System.out.println("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); System.out.println("+++> " + simpName); @@ -1235,14 +1273,14 @@ public class ASTGenerator { // System.out.println("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); if (root.getLineNumber(node.getStartPosition()) == lineNumber) { System.err - .println(3 + getNodeAsString(node) + " len " + node.getLength()); - - if (offset < node.getLength()) - return node; - else { - System.err.println(-11); - return null; - } + .println(3 + getNodeAsString(node) + " len " + node.getLength()); + return node; +// if (offset < node.getLength()) +// return node; +// else { +// System.err.println(-11); +// return null; +// } } for (Object oprop : node.structuralPropertiesForType()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; From e74b7d575cf994a7f183c0715d1cf9f5cf06fca5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Jun 2013 22:34:06 +0530 Subject: [PATCH 063/608] Further work on ASTGen --- pdex/Todo, GSoC 2013.txt | 2 + .../mode/experimental/ASTGenerator.java | 95 +++++++++++++++---- .../mode/experimental/ASTNodeWrapper.java | 25 ++++- 3 files changed, 97 insertions(+), 25 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 1a0187c76..0abbb121f 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -51,4 +51,6 @@ x Local Vars x Local Methods x Local Classes x Recursive lookup, a.b().c() +x Now highlihgting the declaration name, rather than the whole declaration. +*+ A silly bug where the name of the first field declaration isn't highlighted correctly. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index e19ab9f58..b8cc56a2e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1010,16 +1010,20 @@ public class ASTGenerator { System.out.println("+> " + lineNode); ASTNode decl = null; + String nameOfNode = null; // The node name which is to be scrolled to if (lineNode != null) { ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); + int altOff = offset; int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); - int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; - int altOff = 0; - for (; altOff < javaCodeMap.length; altOff++) { - if(javaCodeMap[altOff] == pdeCodeMap[offset]){ - //altOff = javaCodeMap[altOff]; - break; - } + if(ret != null){ + altOff = 0; + int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; + + for (; altOff < javaCodeMap.length; altOff++) { + if (javaCodeMap[altOff] == pdeCodeMap[offset]) { + break; + } + } } System.out.println("FLON2: " + lineNumber + " LN spos " + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); @@ -1032,7 +1036,7 @@ public class ASTGenerator { Iterator it = parLineNode .structuralPropertiesForType().iterator(); boolean flag = true; - int lineStartPos = lineNode.getStartPosition(), offAdjust = 0; + int offAdjust = 0; while (it.hasNext() && flag) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -1062,6 +1066,7 @@ public class ASTGenerator { lineNode.getStartPosition(), name); System.out.println("+++> " + simpName); if (simpName instanceof SimpleName) { + nameOfNode = simpName.toString(); System.out.println(getNodeAsString(simpName)); decl = findDeclaration((SimpleName) simpName); if (decl != null) { @@ -1077,20 +1082,64 @@ public class ASTGenerator { // // retStr = ""; if (decl != null && scrollOnly) { - System.err.println("FINAL String label: " + getNodeAsString(decl)); - - DefaultProblem dpr = new DefaultProblem(null, null, -1, null, -1, - decl.getStartPosition(), - decl.getStartPosition(), - getLineNumber(decl) + 1, 0); - int[] position = errorCheckerService.calculateTabIndexAndLineNumber(dpr); - System.out.println("Tab " + position[0] + ", Line: " + (position[1])); - Problem p = new Problem(dpr, position[0], position[1]); - errorCheckerService.scrollToErrorLine(p); + ASTNode simpName2 = getNodeName(decl,nameOfNode); + System.err.println("FINAL String decl: " + getNodeAsString(decl)); + System.err.println("FINAL String label: " + getNodeAsString(simpName2)); + ASTNodeWrapper awrap = new ASTNodeWrapper(simpName2); + int pdeoffsets[] = awrap .getPDECodeOffsets(errorCheckerService); + int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1],javaoffsets[1], + javaoffsets[2]); + // Now highlight the SimpleName + + + +// DefaultProblem dpr = new DefaultProblem(null, null, -1, null, -1, +// decl.getStartPosition(), +// decl.getStartPosition(), +// getLineNumber(decl) + 1, 0); +// int[] position = errorCheckerService.calculateTabIndexAndLineNumber(dpr); +// System.out.println("Tab " + position[0] + ", Line: " + (position[1])); +// Problem p = new Problem(dpr, position[0], position[1]); +// errorCheckerService.scrollToErrorLine(p); } // uncomment this one, it works return null; } + + private ASTNode getNodeName(ASTNode node, String name){ + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return ((TypeDeclaration) node).getName(); + case ASTNode.METHOD_DECLARATION: + return ((MethodDeclaration) node).getName(); + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return ((SingleVariableDeclaration) node).getName(); + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + for (VariableDeclarationFragment vdf : vdfs) { + if (vdf.getName().toString().equals(name)) { + return vdf.getName(); + } + } + + } + return null; + } private static int getLineNumber(ASTNode node) { return ((CompilationUnit) node.getRoot()).getLineNumber(node @@ -1330,15 +1379,19 @@ public class ASTGenerator { if (node instanceof SimpleName) { SimpleName sn = (SimpleName) node; + System.out.println(offset+ "off,pol " + getNodeAsString(sn)); if ((lineStartOffset + offset) >= sn.getStartPosition() && (lineStartOffset + offset) <= sn.getStartPosition() + sn.getLength()) { - if (sn.toString().equals(name)) + if (sn.toString().equals(name)) { return sn; - else + } + else { return null; - } else + } + } else { return null; + } } for (Object oprop : node.structuralPropertiesForType()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 66affac5c..7f9779421 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -110,18 +110,32 @@ public class ASTNodeWrapper { } } } - // System.out.println("Altspos " + altStartPos); + System.out.println("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); - return new int[] { - lineNumber, nodeOffset + vals[0] - altStartPos, vals[1]}; + if(vals != null) + return new int[] { + lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; + else + return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; } + /** + * + * @param source + * @param inpOffset + * @param nodeLen + * @return int[0] - difference in start offset, int[1] - node length + */ private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { int ret[][] = getOffsetMapping(source); + if(ret == null){ + // no offset mapping needed + return null; + } int javaCodeMap[] = ret[0]; int pdeCodeMap[] = ret[1]; int pi = 1, pj = 1; @@ -234,7 +248,10 @@ public class ASTNodeWrapper { + "("); } - + if(offsetmap.isEmpty()){ + System.out.println("No offset matching needed."); + return null; + } // replace with 0xff[webcolor] and others webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { From 575ae579d3af110a555db7728c71c6b35fdd64c9 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Jun 2013 22:52:11 +0530 Subject: [PATCH 064/608] Bad location exception while scrolling bug fix --- pdex/src/processing/mode/experimental/ASTNodeWrapper.java | 6 +++--- .../processing/mode/experimental/ErrorCheckerService.java | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 7f9779421..700c7c7d5 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -112,9 +112,9 @@ public class ASTNodeWrapper { } System.out.println("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); - String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); + String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); - if(vals != null) + if (vals != null) return new int[] { lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; else @@ -337,7 +337,7 @@ public class ASTNodeWrapper { public int[][] getOffsetMapping(ErrorCheckerService ecs){ int pdeoffsets[] = getPDECodeOffsets(ecs); - String pdeCode = ecs.getPDECode(pdeoffsets[1] - 1).trim(); + String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); return getOffsetMapping(pdeCode); } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 5f90a2bea..949f0eba6 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -810,7 +810,8 @@ public class ErrorCheckerService implements Runnable{ return new int[] { codeIndex, x }; } - public String getPDECode(int linenumber){ + public String getPDECodeAtLine(int tab, int linenumber){ + editor.getSketch().setCurrentCode(tab); return editor.ta.getLineText(linenumber); } From e2c1266f1005b0c90f39f69ed7797d3d94b5c620 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 24 Jun 2013 02:29:21 +0530 Subject: [PATCH 065/608] Cleanup, notes, and some jdoc. --- pdex/Todo, GSoC 2013.txt | 2 +- .../mode/experimental/ASTGenerator.java | 53 +++++++++---------- .../experimental/ErrorCheckerService.java | 30 ++++++++++- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 0abbb121f..4acc4988d 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -52,5 +52,5 @@ x Local Methods x Local Classes x Recursive lookup, a.b().c() x Now highlihgting the declaration name, rather than the whole declaration. -*+ A silly bug where the name of the first field declaration isn't highlighted correctly. +*+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b8cc56a2e..dc62b8e42 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1012,6 +1012,8 @@ public class ASTGenerator { ASTNode decl = null; String nameOfNode = null; // The node name which is to be scrolled to if (lineNode != null) { + + // Some delicate offset handling follows. ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); int altOff = offset; int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); @@ -1079,36 +1081,30 @@ public class ASTGenerator { } } -// -// retStr = ""; if (decl != null && scrollOnly) { + /* + * For scrolling, we highlight just the name of the node, + * i.e., a SimpleName instance. But the declared node always + * points to the declared node itself, like TypeDecl, MethodDecl, etc. + * This is important since it contains all the properties. + */ ASTNode simpName2 = getNodeName(decl,nameOfNode); System.err.println("FINAL String decl: " + getNodeAsString(decl)); System.err.println("FINAL String label: " + getNodeAsString(simpName2)); - ASTNodeWrapper awrap = new ASTNodeWrapper(simpName2); - int pdeoffsets[] = awrap .getPDECodeOffsets(errorCheckerService); - int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1],javaoffsets[1], - javaoffsets[2]); - // Now highlight the SimpleName - - - -// DefaultProblem dpr = new DefaultProblem(null, null, -1, null, -1, -// decl.getStartPosition(), -// decl.getStartPosition(), -// getLineNumber(decl) + 1, 0); -// int[] position = errorCheckerService.calculateTabIndexAndLineNumber(dpr); -// System.out.println("Tab " + position[0] + ", Line: " + (position[1])); -// Problem p = new Problem(dpr, position[0], position[1]); -// errorCheckerService.scrollToErrorLine(p); - } // uncomment this one, it works + errorCheckerService.highlightNode(simpName2); + } return null; } - private ASTNode getNodeName(ASTNode node, String name){ + /** + * Given a declaration type astnode, returns the SimpleName peroperty + * of that node. + * @param node + * @param name - The name we're looking for. + * @return SimpleName + */ + private static ASTNode getNodeName(ASTNode node, String name){ List vdfs = null; switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: @@ -1141,6 +1137,11 @@ public class ASTGenerator { return null; } + /** + * Fetches line number of the node in its CompilationUnit. + * @param node + * @return + */ private static int getLineNumber(ASTNode node) { return ((CompilationUnit) node.getRoot()).getLineNumber(node .getStartPosition()); @@ -1148,7 +1149,6 @@ public class ASTGenerator { public static void main(String[] args) { traversal2(); -// ASTParserd } public static void traversal2() { @@ -1218,13 +1218,8 @@ public class ASTGenerator { } if (tnode.getUserObject() instanceof ASTNodeWrapper) { - // 3 friggin casts. Javaaargh. ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); - int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1],javaoffsets[1], - javaoffsets[2]); + errorCheckerService.highlightNode(awrap); } } }; diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 949f0eba6..395def5e2 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -19,6 +19,7 @@ import javax.swing.table.DefaultTableModel; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; @@ -1040,6 +1041,31 @@ public class ErrorCheckerService implements Runnable{ } + /** + * The super method that highlights any ASTNode in the pde editor =D + * @param node + * @return true - if highlighting happened correctly. + */ + public boolean highlightNode(ASTNodeWrapper awrap){ + int pdeoffsets[] = awrap.getPDECodeOffsets(this); + int javaoffsets[] = awrap.getJavaCodeOffsets(this); + try { + scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1],javaoffsets[1], + javaoffsets[2]); + return true; + } catch (Exception e) { + + e.printStackTrace(); + } + return false; + } + + public boolean highlightNode(ASTNode node){ + ASTNodeWrapper awrap = new ASTNodeWrapper(node); + return highlightNode(awrap); + } + /** * Scrolls to the error source in code. And selects the line text. Used by * XQErrorTable and ErrorBar @@ -1086,8 +1112,8 @@ public class ErrorCheckerService implements Runnable{ } /** - * Static method for scroll to a particular line in the PDE. Requires the - * editor instance as arguement. + * Static method for scroll to a particular line in the PDE. Also highlights + * the length of the text. Requires the editor instance as arguement. * * @param edt * @param tabIndex From 6f471781b8facfb74b935e58b88d0b072d6c2179 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 24 Jun 2013 14:26:13 +0530 Subject: [PATCH 066/608] Starting work on refactoring. --- pdex/Todo, GSoC 2013.txt | 7 +- .../mode/experimental/ASTGenerator.java | 189 +++++++++++++++--- 2 files changed, 170 insertions(+), 26 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 4acc4988d..889dfb842 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -39,9 +39,10 @@ x PDE specific enhancements will also have to be tackled like int(), # literals. * The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. -1. First identify the declaration of the variable in the AST. -2. Now for each instance of the word in code inside the declaration scope(i.e further down the child nodes in the AST), find if the matched word is the same one whose declaration I know of. -3. If it is so, replace it with the new name. +1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. +2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. +x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. +3. Find corresponding PDE offsets of the SimpleNames, rename in each line taking displaced offsets into consideration. 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. Quick Navigation diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index dc62b8e42..a8d3f0818 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,6 +1,10 @@ package processing.mode.experimental; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.BufferedReader; @@ -18,8 +22,10 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Stack; import java.util.TreeMap; +import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JScrollPane; @@ -67,6 +73,7 @@ import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; import com.google.classpath.RegExpResourceFilter; import com.ibm.icu.util.StringTokenizer; +import com.sun.org.apache.bcel.internal.generic.GETSTATIC; public class ASTGenerator { @@ -89,6 +96,11 @@ public class ASTGenerator { * Swing component wrapper for AST, used for internal testing */ private JTree jtree; + + /** + * JTree used for testing refactoring operations + */ + private JTree renameTree; private CompilationUnit compilationUnit; @@ -98,6 +110,8 @@ public class ASTGenerator { private JScrollPane scrollPane; + private JButton renameButton; + public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; this.editor = ecs.getEditor(); @@ -105,34 +119,50 @@ public class ASTGenerator { jtree = new JTree(); frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame2.setBounds(new Rectangle(100, 100, 460, 620)); + frame2.setBounds(new Rectangle(680, 100, 460, 620)); JScrollPane sp = new JScrollPane(); sp.setViewportView(jtree); frame2.add(sp); - frameAutoComp = new JFrame(); - frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); - tableAuto = new JTable(); + renameButton = new JButton("Rename"); + JFrame frame3 = new JFrame(); + frame3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame3.setBounds(new Rectangle(680, 50, 100, 50)); + frame3.add(renameButton); + frame3.setVisible(true); + + JFrame frame4 = new JFrame(); + frame4.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame4.setBounds(new Rectangle(1100, 50, 350, 500)); JScrollPane sp2 = new JScrollPane(); - sp2.setViewportView(tableAuto); - frameAutoComp.add(sp2); + renameTree = new JTree(); + sp2.setViewportView(renameTree); + frame4.add(sp2); + frame4.setVisible(true); + +// frameAutoComp = new JFrame(); +// frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); +// frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); +// tableAuto = new JTable(); +// JScrollPane sp2 = new JScrollPane(); +// sp2.setViewportView(tableAuto); +// frameAutoComp.add(sp2); - jdocWindow = new JFrame(); - jdocWindow.setTitle("P5 InstaHelp"); - //jdocWindow.setUndecorated(true); - jdocWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - javadocPane = new JEditorPane(); - javadocPane.setContentType("text/html"); - javadocPane.setEditable(false); - scrollPane = new JScrollPane(); - scrollPane.setViewportView(javadocPane); - jdocWindow.add(scrollPane); - jdocMap = new TreeMap(); - //loadJars(); +// jdocWindow = new JFrame(); +// jdocWindow.setTitle("P5 InstaHelp"); +// //jdocWindow.setUndecorated(true); +// jdocWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); +// javadocPane = new JEditorPane(); +// javadocPane.setContentType("text/html"); +// javadocPane.setEditable(false); +// scrollPane = new JScrollPane(); +// scrollPane.setViewportView(javadocPane); +// jdocWindow.add(scrollPane); +// jdocMap = new TreeMap(); +//// loadJars(); //addCompletionPopupListner(); - addTreeListner(); + addListners(); } private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { @@ -992,7 +1022,8 @@ public class ASTGenerator { public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - System.out.println("--------"); + + System.out.println("----getASTNodeAt----"); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -1094,7 +1125,7 @@ public class ASTGenerator { errorCheckerService.highlightNode(simpName2); } - return null; + return new ASTNodeWrapper(decl); } /** @@ -1193,7 +1224,7 @@ public class ASTGenerator { } } - private void addTreeListner(){ + private void addListners(){ jtree.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -1226,6 +1257,83 @@ public class ASTGenerator { worker.execute(); } }); + + renameButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (editor.ta.getSelectedText() == null) + return; + String selText = editor.ta.getSelectedText(); + int line = editor.ta.getSelectionStartLine(); + System.out.println(editor.ta.getSelectedText() + + "<- offsets " + + (line) + + ", " + + (editor.ta.getSelectionStart() - editor.ta + .getLineStartOffset(line)) + + ", " + + (editor.ta.getSelectionStop() - editor.ta + .getLineStartOffset(line))); + ASTNodeWrapper wnode = getASTNodeAt(line + + errorCheckerService.mainClassOffset, + selText, + editor.ta.getSelectionStart() + - editor.ta + .getLineStartOffset(line), + false); + + DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); + visitRecurNameOnly(defCU, wnode.getNode(), selText); + System.out.println(wnode); + renameTree.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) renameTree.getModel()).reload(); + } + }; + worker.execute(); + } + }); + + renameTree.addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + System.out.println(e); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if(renameTree + .getLastSelectedPathComponent() == null){ + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) renameTree + .getLastSelectedPathComponent(); + if(tnode.getUserObject() == null){ + return; + } + + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + errorCheckerService.highlightNode(awrap); + } + } + }; + worker.execute(); + } + }); } @SuppressWarnings({ "unchecked" }) @@ -1277,6 +1385,41 @@ public class ASTGenerator { } } } + + public void visitRecurNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) { + Stack temp = new Stack(); + temp.push(codeTree); + + while(!temp.isEmpty()){ + DefaultMutableTreeNode cnode = (DefaultMutableTreeNode) temp.pop(); + for (int i = 0; i < cnode.getChildCount(); i++) { + temp.push(cnode.getChildAt(i)); + } + + if(!(cnode.getUserObject() instanceof ASTNodeWrapper)) + continue; + ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); +// System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); + if(isInstanceOfType(awnode.getNode(), decl, name)){ + tnode.add(new DefaultMutableTreeNode(awnode)); + } + + } + } + + private boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ + if(node instanceof SimpleName){ + SimpleName sn = (SimpleName) node; + System.out.println("Visiting: " + getNodeAsString(node)); + if (sn.toString().equals(name)) { + if (findDeclaration(sn).equals(decl)) + return true; + } + } + return false; + } + + public static void printRecur(ASTNode node) { Iterator it = node From 1ca21c903628adb2f31503d530213a930ba7f92d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 24 Jun 2013 19:22:21 +0530 Subject: [PATCH 067/608] Basic refactoring works. =D --- .../mode/experimental/ASTGenerator.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index a8d3f0818..f47025ac3 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -2,6 +2,7 @@ package processing.mode.experimental; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.GridLayout; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -25,11 +26,14 @@ import java.util.Map; import java.util.Stack; import java.util.TreeMap; +import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; +import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -112,6 +116,8 @@ public class ASTGenerator { private JButton renameButton; + private JTextField renameTextField; + public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; this.editor = ecs.getEditor(); @@ -127,17 +133,22 @@ public class ASTGenerator { renameButton = new JButton("Rename"); JFrame frame3 = new JFrame(); frame3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame3.setBounds(new Rectangle(680, 50, 100, 50)); + frame3.setBounds(new Rectangle(680, 50, 150, 100)); + frame3.setLayout(new GridLayout(2, 1)); frame3.add(renameButton); + renameTextField = new JTextField(); + renameTextField.setPreferredSize(new Dimension(150, 60)); + frame3.add(renameTextField); frame3.setVisible(true); JFrame frame4 = new JFrame(); frame4.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame4.setBounds(new Rectangle(1100, 50, 350, 500)); + JScrollPane sp2 = new JScrollPane(); renameTree = new JTree(); - sp2.setViewportView(renameTree); - frame4.add(sp2); + sp2.setViewportView(renameTree); + frame4.add(sp2); frame4.setVisible(true); // frameAutoComp = new JFrame(); @@ -1272,6 +1283,9 @@ public class ASTGenerator { protected void done() { if (editor.ta.getSelectedText() == null) return; + if(renameTextField.getText().length() == 0) + return; + String newName = renameTextField.getText(); String selText = editor.ta.getSelectedText(); int line = editor.ta.getSelectionStartLine(); System.out.println(editor.ta.getSelectedText() @@ -1296,6 +1310,18 @@ public class ASTGenerator { System.out.println(wnode); renameTree.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) renameTree.getModel()).reload(); + for (int i = 0; i < defCU.getChildCount(); i++) { + ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU + .getChildAt(i))).getUserObject(); + int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); + int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); + + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1], + javaoffsets[1], + javaoffsets[2]); + editor.ta.setSelectedText(newName); + } } }; worker.execute(); From dba3444a70abe145bc7f03affbaeeb7026488d28 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 28 Jun 2013 22:05:40 +0530 Subject: [PATCH 068/608] tricky findDec bugfix --- pdex/Todo, GSoC 2013.txt | 2 +- .../mode/experimental/ASTGenerator.java | 136 +++++++++++++----- .../mode/experimental/ASTNodeWrapper.java | 3 +- 3 files changed, 107 insertions(+), 34 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 889dfb842..2d8b268c5 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -29,7 +29,7 @@ Finer details * Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? Offset Mapping & Refactoring -=========== +============================ First major hurdle is offset mapping *! pde<->java code offset : precise conversion needed x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index f47025ac3..4a91fcd7d 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -78,6 +78,7 @@ import com.google.classpath.ClassPathFactory; import com.google.classpath.RegExpResourceFilter; import com.ibm.icu.util.StringTokenizer; import com.sun.org.apache.bcel.internal.generic.GETSTATIC; +import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs; public class ASTGenerator { @@ -116,6 +117,8 @@ public class ASTGenerator { private JButton renameButton; + private JButton listOccurrence; + private JTextField renameTextField; public ASTGenerator(ErrorCheckerService ecs) { @@ -131,11 +134,13 @@ public class ASTGenerator { frame2.add(sp); renameButton = new JButton("Rename"); + listOccurrence = new JButton("Find All"); JFrame frame3 = new JFrame(); frame3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame3.setBounds(new Rectangle(680, 50, 150, 100)); - frame3.setLayout(new GridLayout(2, 1)); + frame3.setBounds(new Rectangle(680, 50, 150, 150)); + frame3.setLayout(new GridLayout(3, 1)); frame3.add(renameButton); + frame3.add(listOccurrence); renameTextField = new JTextField(); renameTextField.setPreferredSize(new Dimension(150, 60)); frame3.add(renameTextField); @@ -173,7 +178,7 @@ public class ASTGenerator { //// loadJars(); //addCompletionPopupListner(); - addListners(); + addListenrs(); } private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { @@ -1031,6 +1036,14 @@ public class ASTGenerator { String retLabelString; + /** + * + * @param lineNumber + * @param name + * @param offset - line start nonwhitespace offset + * @param scrollOnly + * @return + */ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { @@ -1235,7 +1248,7 @@ public class ASTGenerator { } } - private void addListners(){ + private void addListenrs(){ jtree.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -1286,28 +1299,7 @@ public class ASTGenerator { if(renameTextField.getText().length() == 0) return; String newName = renameTextField.getText(); - String selText = editor.ta.getSelectedText(); - int line = editor.ta.getSelectionStartLine(); - System.out.println(editor.ta.getSelectedText() - + "<- offsets " - + (line) - + ", " - + (editor.ta.getSelectionStart() - editor.ta - .getLineStartOffset(line)) - + ", " - + (editor.ta.getSelectionStop() - editor.ta - .getLineStartOffset(line))); - ASTNodeWrapper wnode = getASTNodeAt(line - + errorCheckerService.mainClassOffset, - selText, - editor.ta.getSelectionStart() - - editor.ta - .getLineStartOffset(line), - false); - - DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); - visitRecurNameOnly(defCU, wnode.getNode(), selText); - System.out.println(wnode); + DefaultMutableTreeNode defCU = findAllOccurrences(); renameTree.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) renameTree.getModel()).reload(); for (int i = 0; i < defCU.getChildCount(); i++) { @@ -1322,12 +1314,36 @@ public class ASTGenerator { javaoffsets[2]); editor.ta.setSelectedText(newName); } + editor.getSketch().setModified(true); } }; worker.execute(); } }); - + // TODO: Diable this listner at deployment + listOccurrence.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (editor.ta.getSelectedText() == null) + return; + DefaultMutableTreeNode defCU = findAllOccurrences(); + renameTree.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) renameTree.getModel()).reload(); + } + }; + worker.execute(); + } + }); + renameTree.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -1361,6 +1377,34 @@ public class ASTGenerator { } }); } + + private DefaultMutableTreeNode findAllOccurrences(){ + String selText = editor.ta.getSelectedText(); + int line = editor.ta.getSelectionStartLine(); + System.out.println(editor.ta.getSelectedText() + + "<- offsets " + + (line) + + ", " + + (editor.ta.getSelectionStart() - editor.ta + .getLineStartOffset(line)) + + ", " + + (editor.ta.getSelectionStop() - editor.ta + .getLineStartOffset(line))); + int offwhitespace = editor.ta + .getLineStartNonWhiteSpaceOffset(line); + ASTNodeWrapper wnode = getASTNodeAt(line + + errorCheckerService.mainClassOffset, + selText, + editor.ta.getSelectionStart() + - offwhitespace, false); + System.err.println("Gonna find all occurrences of " + + getNodeAsString(wnode.getNode())); + + DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); + dfsNameOnly(defCU, wnode.getNode(), selText); + System.out.println(wnode); + return defCU; + } @SuppressWarnings({ "unchecked" }) /** @@ -1412,7 +1456,7 @@ public class ASTGenerator { } } - public void visitRecurNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) { + public void dfsNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) { Stack temp = new Stack(); temp.push(codeTree); @@ -1436,10 +1480,29 @@ public class ASTGenerator { private boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ if(node instanceof SimpleName){ SimpleName sn = (SimpleName) node; - System.out.println("Visiting: " + getNodeAsString(node)); + if (sn.toString().equals(name)) { - if (findDeclaration(sn).equals(decl)) - return true; + ArrayList nodesToBeMatched = new ArrayList(); + nodesToBeMatched.add(decl); + if(decl instanceof TypeDeclaration){ + System.out.println("decl is a TD"); + TypeDeclaration td = (TypeDeclaration)decl; + MethodDeclaration[] mlist = td.getMethods(); + for (MethodDeclaration md : mlist) { + if(md.getName().toString().equals(name)){ + nodesToBeMatched.add(md); + } + } + } + System.out.println("Visiting: " + getNodeAsString(node)); + ASTNode decl2 = findDeclaration(sn); + System.err.println("It's decl: " + getNodeAsString(decl2)); + System.out.println("But we need: "+getNodeAsString(decl)); + for (ASTNode astNode : nodesToBeMatched) { + if(astNode.equals(decl2)){ + return true; + } + } } } return false; @@ -1701,7 +1764,15 @@ public class ASTGenerator { constrains.add(ASTNode.TYPE_DECLARATION); if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) constrains.add(ASTNode.CLASS_INSTANCE_CREATION); - } else if (parent instanceof Expression) { + } else if(parent.getNodeType() == ASTNode.TYPE_DECLARATION){ + // The condition where we look up the name of a class decl + TypeDeclaration td = (TypeDeclaration) parent; + if(findMe.equals(td.getName())) + { + return parent; + } + } + else if (parent instanceof Expression) { // constrains.add(ASTNode.TYPE_DECLARATION); // constrains.add(ASTNode.METHOD_DECLARATION); // constrains.add(ASTNode.FIELD_DECLARATION); @@ -1957,6 +2028,7 @@ public class ASTGenerator { MethodDeclaration[] methods = td.getMethods(); for (MethodDeclaration md : methods) { if (md.getName().toString().equals(name)) { + System.out.println("Found a constructor."); return md; } } diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 700c7c7d5..359d3d4e2 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -37,8 +37,9 @@ public class ASTNodeWrapper { */ public ASTNodeWrapper(ASTNode node) { - if (node == null) + if (node == null){ return; + } this.Node = node; label = getNodeAsString(node); if (label == null) From f85682e73416807dc0e22eb273df677eb43e5912 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 28 Jun 2013 23:37:30 +0530 Subject: [PATCH 069/608] constructor refactoring support --- pdex/Todo, GSoC 2013.txt | 12 +++-- .../mode/experimental/ASTGenerator.java | 45 +++++++++++++++++-- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2d8b268c5..0663bd840 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -28,8 +28,8 @@ Finer details * Reflection API - getMethods vs getDeclaredMethods. * Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? -Offset Mapping & Refactoring -============================ +Offset Mapping +============== First major hurdle is offset mapping *! pde<->java code offset : precise conversion needed x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. @@ -38,12 +38,18 @@ x Edge case - multiple statements in a single line x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. * The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. +Refactoring +=========== Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. 2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. -3. Find corresponding PDE offsets of the SimpleNames, rename in each line taking displaced offsets into consideration. +x Renaming any constructor is equivalent to renaming the TD +3. Find corresponding PDE offsets of the SimpleNames, rename in each line. +* Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. +* Undo misbehaves here, handle carefully. +* Handle saving. If sketch closed after renaming w/o saving find bugs. Quick Navigation ================ diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 4a91fcd7d..749571692 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -20,6 +20,7 @@ import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -178,7 +179,7 @@ public class ASTGenerator { //// loadJars(); //addCompletionPopupListner(); - addListenrs(); + addListeners(); } private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { @@ -1248,7 +1249,7 @@ public class ASTGenerator { } } - private void addListenrs(){ + private void addListeners(){ jtree.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -1302,6 +1303,10 @@ public class ASTGenerator { DefaultMutableTreeNode defCU = findAllOccurrences(); renameTree.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) renameTree.getModel()).reload(); + int lineOffsetDisplacementConst = newName.length() + - editor.ta.getSelectedText().length(); + HashMap lineOffsetDisplacement = new HashMap(); + for (int i = 0; i < defCU.getChildCount(); i++) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); @@ -1313,6 +1318,19 @@ public class ASTGenerator { javaoffsets[1], javaoffsets[2]); editor.ta.setSelectedText(newName); + if(lineOffsetDisplacement.get(javaoffsets[0]) != null){ + int off = lineOffsetDisplacement.get(javaoffsets[0]); + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst + off); + } + else{ + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst); + } + } + for (Integer lineNum : lineOffsetDisplacement.keySet()) { + System.out.println(lineNum + "line, disp" + + lineOffsetDisplacement.get(lineNum)); } editor.getSketch().setModified(true); } @@ -1400,6 +1418,26 @@ public class ASTGenerator { System.err.println("Gonna find all occurrences of " + getNodeAsString(wnode.getNode())); + //If wnode is a constructor, find the TD instead. + if (wnode.getNodeType() == ASTNode.METHOD_DECLARATION) { + MethodDeclaration md = (MethodDeclaration) wnode.getNode(); + ASTNode node = md.getParent(); + while (node != null) { + if (node instanceof TypeDeclaration) { + // System.out.println("Parent class " + getNodeAsString(node)); + break; + } + node = node.getParent(); + } + if(node != null && node instanceof TypeDeclaration){ + TypeDeclaration td = (TypeDeclaration) node; + if(td.getName().toString().equals(md.getName().toString())){ + System.err.println("Renaming constructor of " + getNodeAsString(td)); + wnode = new ASTNodeWrapper(td); + } + } + } + DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); dfsNameOnly(defCU, wnode.getNode(), selText); System.out.println(wnode); @@ -1933,7 +1971,8 @@ public class ASTGenerator { // constrains.add(ASTNode.TYPE_DECLARATION); // constrains.add(ASTNode.METHOD_DECLARATION); // constrains.add(ASTNode.FIELD_DECLARATION); - } + } // TODO: in findDec, we also have a case where parent of type TD is handled. + // Figure out if needed here as well. System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); while (alternateParent != null) { // System.out.println("findDeclaration2 -> " From 1bddc05dd9a2e1c0294bf728b2898d46447816c3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 00:41:51 +0530 Subject: [PATCH 070/608] line offset displacements now handled --- pdex/Todo, GSoC 2013.txt | 2 +- .../mode/experimental/ASTGenerator.java | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 0663bd840..a156e43cb 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -46,7 +46,7 @@ Refactoring would work only when code is compiler error free. I plan to do a fin x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. x Renaming any constructor is equivalent to renaming the TD 3. Find corresponding PDE offsets of the SimpleNames, rename in each line. -* Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. +x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. * Undo misbehaves here, handle carefully. * Handle saving. If sketch closed after renaming w/o saving find bugs. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 749571692..cd79906e7 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1307,19 +1307,17 @@ public class ASTGenerator { - editor.ta.getSelectedText().length(); HashMap lineOffsetDisplacement = new HashMap(); - for (int i = 0; i < defCU.getChildCount(); i++) { + for (int i = defCU.getChildCount() - 1; i >= 0; i--) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1], - javaoffsets[1], - javaoffsets[2]); - editor.ta.setSelectedText(newName); + // correction for pde enhancements related displacement on a line + int off = 0; if(lineOffsetDisplacement.get(javaoffsets[0]) != null){ - int off = lineOffsetDisplacement.get(javaoffsets[0]); + off = lineOffsetDisplacement.get(javaoffsets[0]); + lineOffsetDisplacement.put(javaoffsets[0], lineOffsetDisplacementConst + off); } @@ -1327,6 +1325,12 @@ public class ASTGenerator { lineOffsetDisplacement.put(javaoffsets[0], lineOffsetDisplacementConst); } + + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1], + javaoffsets[1] + off, + javaoffsets[2]); + editor.ta.setSelectedText(newName); } for (Integer lineNum : lineOffsetDisplacement.keySet()) { System.out.println(lineNum + "line, disp" From af6b128793b6c3f82d3d4d7b2edc375e6b892545 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 11:27:25 +0530 Subject: [PATCH 071/608] beginning work on refactoring ui --- pdex/Todo, GSoC 2013.txt | 2 ++ .../mode/experimental/ASTGenerator.java | 23 +++++++++++------- .../mode/experimental/DebugEditor.java | 24 ++++++++++++++++++- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index a156e43cb..754eb4b3a 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -50,6 +50,8 @@ x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. * Undo misbehaves here, handle carefully. * Handle saving. If sketch closed after renaming w/o saving find bugs. +* Refactoring ui +* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully Quick Navigation ================ diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index cd79906e7..b4ebb3413 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -115,6 +115,8 @@ public class ASTGenerator { private JEditorPane javadocPane; private JScrollPane scrollPane; + + private JFrame renameWindow; private JButton renameButton; @@ -136,16 +138,16 @@ public class ASTGenerator { renameButton = new JButton("Rename"); listOccurrence = new JButton("Find All"); - JFrame frame3 = new JFrame(); - frame3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame3.setBounds(new Rectangle(680, 50, 150, 150)); - frame3.setLayout(new GridLayout(3, 1)); - frame3.add(renameButton); - frame3.add(listOccurrence); + renameWindow = new JFrame(); + renameWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + renameWindow.setBounds(new Rectangle(680, 50, 150, 150)); + renameWindow.setLayout(new GridLayout(3, 1)); + renameWindow.add(renameButton); + renameWindow.add(listOccurrence); renameTextField = new JTextField(); renameTextField.setPreferredSize(new Dimension(150, 60)); - frame3.add(renameTextField); - frame3.setVisible(true); + renameWindow.add(renameTextField); + renameWindow.setVisible(true); JFrame frame4 = new JFrame(); frame4.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); @@ -1550,6 +1552,11 @@ public class ASTGenerator { return false; } + public void handleRefactor(){ + if (!renameWindow.isVisible()) + renameWindow.setVisible(true); + renameWindow.toFront(); + } public static void printRecur(ASTNode node) { diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 268720017..099e90d1a 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -25,6 +25,8 @@ import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -153,7 +155,21 @@ public class DebugEditor extends JavaEditor implements ActionListener { // access to customized (i.e. subclassed) text area ta = (TextArea) textarea; - + + // add refactor option + JMenuItem renameItem = new JMenuItem("Rename.."); + renameItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleRefactor(); + } + }); + // TODO: Add support for word select on right click and rename. +// ta.customPainter.addMouseListener(new MouseAdapter() { +// public void mouseClicked(MouseEvent evt) { +// System.out.println(evt); +// } +// }); + ta.getRightClickPopup().add(renameItem); // set action on frame close // addWindowListener(new WindowAdapter() { // @Override @@ -1122,6 +1138,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { return errorTable.updateTable(tableModel); } + private void handleRefactor() { + System.out.println("Caret at:"); + System.out.println(ta.getLineText(ta.getCaretLine())); + errorCheckerService.astGenerator.handleRefactor(); + } + /** * Checks if the sketch contains java tabs. If it does, XQMode ain't built * for it, yet. Also, user should really start looking at Eclipse. Disable From fbef84e153fe25cb62e404c7e65f651eb5da48e2 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 13:35:11 +0530 Subject: [PATCH 072/608] Create README.md --- pdex/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 pdex/README.md diff --git a/pdex/README.md b/pdex/README.md new file mode 100644 index 000000000..4b7b12b6c --- /dev/null +++ b/pdex/README.md @@ -0,0 +1,4 @@ +processing-experimental +======================= + +Experimental Mode for the PDE From c6c233969cf59a39ce5e1e7ad6071c349fafd351 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 13:40:40 +0530 Subject: [PATCH 073/608] moving stuff into its new home --- pdex/experimental/.classpath | 23 + .../.externalToolBuilders/Auto_Builder.launch | 17 + pdex/experimental/.gitignore | 1 + pdex/experimental/.project | 27 + .../.settings/org.eclipse.jdt.core.prefs | 11 + pdex/experimental/Todo, GSoC 2013.txt | 65 + pdex/experimental/build.xml | 65 + pdex/experimental/mode/.gitignore | 1 + pdex/experimental/mode/readme.txt | 5 + .../mode/experimental/ASTGenerator.java | 2329 +++++++++++++++++ .../mode/experimental/ASTNodeWrapper.java | 425 +++ .../mode/experimental/ArrayFieldNode.java | 65 + .../mode/experimental/ClassLoadListener.java | 37 + .../mode/experimental/Compiler.java | 367 +++ .../experimental/CompletionCandidate.java | 130 + .../mode/experimental/CompletionPanel.java | 153 ++ .../mode/experimental/DebugBuild.java | 73 + .../mode/experimental/DebugEditor.java | 1165 +++++++++ .../mode/experimental/DebugRunner.java | 85 + .../mode/experimental/DebugToolbar.java | 249 ++ .../mode/experimental/Debugger.java | 1364 ++++++++++ .../mode/experimental/ErrorBar.java | 385 +++ .../experimental/ErrorCheckerService.java | 1297 +++++++++ .../mode/experimental/ErrorMarker.java | 36 + .../mode/experimental/ErrorWindow.java | 374 +++ .../mode/experimental/ExperimentalMode.java | 171 ++ .../mode/experimental/FieldNode.java | 65 + .../mode/experimental/ImportStatement.java | 57 + .../mode/experimental/JavadocHelper.java | 126 + .../mode/experimental/LineBreakpoint.java | 218 ++ .../mode/experimental/LineHighlight.java | 196 ++ .../processing/mode/experimental/LineID.java | 269 ++ .../mode/experimental/LineListener.java | 35 + .../mode/experimental/LocalVariableNode.java | 66 + .../processing/mode/experimental/Problem.java | 160 ++ .../mode/experimental/TextArea.java | 630 +++++ .../mode/experimental/TextAreaPainter.java | 488 ++++ .../mode/experimental/VMEventListener.java | 36 + .../mode/experimental/VMEventReader.java | 68 + .../mode/experimental/VariableInspector.form | 53 + .../mode/experimental/VariableInspector.java | 929 +++++++ .../mode/experimental/VariableNode.java | 358 +++ .../mode/experimental/XQConsoleToggle.java | 131 + .../mode/experimental/XQErrorTable.java | 166 ++ .../mode/experimental/XQPreprocessor.java | 245 ++ pdex/experimental/theme/theme.txt | 34 + pdex/experimental/theme/var-icons.gif | Bin 0 -> 5152 bytes 47 files changed, 13250 insertions(+) create mode 100644 pdex/experimental/.classpath create mode 100644 pdex/experimental/.externalToolBuilders/Auto_Builder.launch create mode 100644 pdex/experimental/.gitignore create mode 100644 pdex/experimental/.project create mode 100644 pdex/experimental/.settings/org.eclipse.jdt.core.prefs create mode 100644 pdex/experimental/Todo, GSoC 2013.txt create mode 100644 pdex/experimental/build.xml create mode 100644 pdex/experimental/mode/.gitignore create mode 100644 pdex/experimental/mode/readme.txt create mode 100644 pdex/experimental/src/processing/mode/experimental/ASTGenerator.java create mode 100644 pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java create mode 100755 pdex/experimental/src/processing/mode/experimental/Compiler.java create mode 100644 pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java create mode 100644 pdex/experimental/src/processing/mode/experimental/CompletionPanel.java create mode 100755 pdex/experimental/src/processing/mode/experimental/DebugBuild.java create mode 100755 pdex/experimental/src/processing/mode/experimental/DebugEditor.java create mode 100755 pdex/experimental/src/processing/mode/experimental/DebugRunner.java create mode 100755 pdex/experimental/src/processing/mode/experimental/DebugToolbar.java create mode 100755 pdex/experimental/src/processing/mode/experimental/Debugger.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ErrorBar.java create mode 100644 pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ErrorMarker.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ErrorWindow.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java create mode 100755 pdex/experimental/src/processing/mode/experimental/FieldNode.java create mode 100755 pdex/experimental/src/processing/mode/experimental/ImportStatement.java create mode 100644 pdex/experimental/src/processing/mode/experimental/JavadocHelper.java create mode 100755 pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java create mode 100755 pdex/experimental/src/processing/mode/experimental/LineHighlight.java create mode 100755 pdex/experimental/src/processing/mode/experimental/LineID.java create mode 100755 pdex/experimental/src/processing/mode/experimental/LineListener.java create mode 100755 pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java create mode 100644 pdex/experimental/src/processing/mode/experimental/Problem.java create mode 100644 pdex/experimental/src/processing/mode/experimental/TextArea.java create mode 100644 pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java create mode 100755 pdex/experimental/src/processing/mode/experimental/VMEventListener.java create mode 100755 pdex/experimental/src/processing/mode/experimental/VMEventReader.java create mode 100755 pdex/experimental/src/processing/mode/experimental/VariableInspector.form create mode 100755 pdex/experimental/src/processing/mode/experimental/VariableInspector.java create mode 100755 pdex/experimental/src/processing/mode/experimental/VariableNode.java create mode 100755 pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java create mode 100755 pdex/experimental/src/processing/mode/experimental/XQErrorTable.java create mode 100755 pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java create mode 100755 pdex/experimental/theme/theme.txt create mode 100755 pdex/experimental/theme/var-icons.gif diff --git a/pdex/experimental/.classpath b/pdex/experimental/.classpath new file mode 100644 index 000000000..5bb5a9eb3 --- /dev/null +++ b/pdex/experimental/.classpath @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pdex/experimental/.externalToolBuilders/Auto_Builder.launch b/pdex/experimental/.externalToolBuilders/Auto_Builder.launch new file mode 100644 index 000000000..dc7825b02 --- /dev/null +++ b/pdex/experimental/.externalToolBuilders/Auto_Builder.launch @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/pdex/experimental/.gitignore b/pdex/experimental/.gitignore new file mode 100644 index 000000000..ba077a403 --- /dev/null +++ b/pdex/experimental/.gitignore @@ -0,0 +1 @@ +bin diff --git a/pdex/experimental/.project b/pdex/experimental/.project new file mode 100644 index 000000000..85716855e --- /dev/null +++ b/pdex/experimental/.project @@ -0,0 +1,27 @@ + + + processing-experimental + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + auto,full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/Auto_Builder.launch + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/pdex/experimental/.settings/org.eclipse.jdt.core.prefs b/pdex/experimental/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..8000cd6ca --- /dev/null +++ b/pdex/experimental/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/pdex/experimental/Todo, GSoC 2013.txt b/pdex/experimental/Todo, GSoC 2013.txt new file mode 100644 index 000000000..754eb4b3a --- /dev/null +++ b/pdex/experimental/Todo, GSoC 2013.txt @@ -0,0 +1,65 @@ +TODO List for Experimental Mode Plus- GSOC 2013 + +This would also be a break down of my thought process and ideas as I tackle various tasks. Also lines are fairly long. Make sure you turn on word wrap. ;) + +Manindra Moharana (me@mkmoharana.com) + +* : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo + +Code Completion +============== +The big stuff: +x! Code competition for local code is working with recursive look up. +x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. +x Completion for external classes - ArrayList, HashMap, etc. +*! Recursive lookup for compiled(library) code! +*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned +ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. +*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. +x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. +* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. +*+ Differentiating between multiple statements on the same line. How to? + +Finer details +* Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. +* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? +* Sorted list of completion candidates - fields, then methods. It's unsorted presently. +*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. +* Reflection API - getMethods vs getDeclaredMethods. +* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? + +Offset Mapping +============== +First major hurdle is offset mapping +*! pde<->java code offset : precise conversion needed +x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. +* This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. +x Edge case - multiple statements in a single line +x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. +* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. + +Refactoring +=========== +Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. +1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. +2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. +x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. +x Renaming any constructor is equivalent to renaming the TD +3. Find corresponding PDE offsets of the SimpleNames, rename in each line. +x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. +4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. +* Undo misbehaves here, handle carefully. +* Handle saving. If sketch closed after renaming w/o saving find bugs. +* Refactoring ui +* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully + +Quick Navigation +================ +x Ctrl + Click on an element to scroll to its definition in code +x Local Vars +x Local Methods +x Local Classes +x Recursive lookup, a.b().c() +x Now highlihgting the declaration name, rather than the whole declaration. +*+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. + diff --git a/pdex/experimental/build.xml b/pdex/experimental/build.xml new file mode 100644 index 000000000..309946ae0 --- /dev/null +++ b/pdex/experimental/build.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pdex/experimental/mode/.gitignore b/pdex/experimental/mode/.gitignore new file mode 100644 index 000000000..9acf0e7e9 --- /dev/null +++ b/pdex/experimental/mode/.gitignore @@ -0,0 +1 @@ +experimental.jar diff --git a/pdex/experimental/mode/readme.txt b/pdex/experimental/mode/readme.txt new file mode 100644 index 000000000..2152b63de --- /dev/null +++ b/pdex/experimental/mode/readme.txt @@ -0,0 +1,5 @@ +Packages from Eclipse 4.2.1: +http://download.eclipse.org/eclipse/downloads/ + +The jdi.jar and jdimodel.jar files are unpacked +from the org.eclipse.jdt.debug JAR file. diff --git a/pdex/experimental/src/processing/mode/experimental/ASTGenerator.java b/pdex/experimental/src/processing/mode/experimental/ASTGenerator.java new file mode 100644 index 000000000..b4ebb3413 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ASTGenerator.java @@ -0,0 +1,2329 @@ +package processing.mode.experimental; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; +import java.util.TreeMap; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.table.DefaultTableModel; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; + +import processing.app.Base; +import processing.app.SketchCode; + +import com.google.classpath.ClassPath; +import com.google.classpath.ClassPathFactory; +import com.google.classpath.RegExpResourceFilter; +import com.ibm.icu.util.StringTokenizer; +import com.sun.org.apache.bcel.internal.generic.GETSTATIC; +import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs; + +public class ASTGenerator { + + protected ErrorCheckerService errorCheckerService; + + protected DebugEditor editor; + + public DefaultMutableTreeNode codeTree = new DefaultMutableTreeNode(); + + private DefaultMutableTreeNode currentParent = null; + + /** + * AST Window + */ + private JFrame frame2; + + private JFrame frameAutoComp; + + /** + * Swing component wrapper for AST, used for internal testing + */ + private JTree jtree; + + /** + * JTree used for testing refactoring operations + */ + private JTree renameTree; + + private CompilationUnit compilationUnit; + + private JTable tableAuto; + + private JEditorPane javadocPane; + + private JScrollPane scrollPane; + + private JFrame renameWindow; + + private JButton renameButton; + + private JButton listOccurrence; + + private JTextField renameTextField; + + public ASTGenerator(ErrorCheckerService ecs) { + this.errorCheckerService = ecs; + this.editor = ecs.getEditor(); + frame2 = new JFrame(); + + jtree = new JTree(); + frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame2.setBounds(new Rectangle(680, 100, 460, 620)); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(jtree); + frame2.add(sp); + + renameButton = new JButton("Rename"); + listOccurrence = new JButton("Find All"); + renameWindow = new JFrame(); + renameWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + renameWindow.setBounds(new Rectangle(680, 50, 150, 150)); + renameWindow.setLayout(new GridLayout(3, 1)); + renameWindow.add(renameButton); + renameWindow.add(listOccurrence); + renameTextField = new JTextField(); + renameTextField.setPreferredSize(new Dimension(150, 60)); + renameWindow.add(renameTextField); + renameWindow.setVisible(true); + + JFrame frame4 = new JFrame(); + frame4.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame4.setBounds(new Rectangle(1100, 50, 350, 500)); + + JScrollPane sp2 = new JScrollPane(); + renameTree = new JTree(); + sp2.setViewportView(renameTree); + frame4.add(sp2); + frame4.setVisible(true); + +// frameAutoComp = new JFrame(); +// frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); +// frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); +// tableAuto = new JTable(); +// JScrollPane sp2 = new JScrollPane(); +// sp2.setViewportView(tableAuto); +// frameAutoComp.add(sp2); + +// jdocWindow = new JFrame(); +// jdocWindow.setTitle("P5 InstaHelp"); +// //jdocWindow.setUndecorated(true); +// jdocWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); +// javadocPane = new JEditorPane(); +// javadocPane.setContentType("text/html"); +// javadocPane.setEditable(false); +// scrollPane = new JScrollPane(); +// scrollPane.setViewportView(javadocPane); +// jdocWindow.add(scrollPane); +// jdocMap = new TreeMap(); +//// loadJars(); + + //addCompletionPopupListner(); + addListeners(); + } + + private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { + if (cu == null) { + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + compilationUnit = (CompilationUnit) parser.createAST(null); + } else { + compilationUnit = cu; + System.out.println("Other cu"); + } +// OutlineVisitor visitor = new OutlineVisitor(); +// compilationUnit.accept(visitor); + codeTree = new DefaultMutableTreeNode( + getNodeAsString((ASTNode) compilationUnit + .types().get(0))); + visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (codeTree != null) { + if (jtree.hasFocus() || frame2.hasFocus()) + return; + jtree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) jtree.getModel()).reload(); + if (!frame2.isVisible()) { + frame2.setVisible(true); + } +// if (!frameAutoComp.isVisible()) { +// +// frameAutoComp.setVisible(true); +// +// } +// if (!jdocWindow.isVisible()) { +// long t = System.currentTimeMillis(); +// loadJars(); +// loadJavaDoc(); +// System.out.println("Time taken: " +// + (System.currentTimeMillis() - t)); +// jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() +// .getX() + errorCheckerService.getEditor().getWidth(), +// errorCheckerService.getEditor() +// .getY(), 450, 600)); +// jdocWindow.setVisible(true); +// } + jtree.validate(); + } + } + }; + worker.execute(); +// System.err.println("++>" + System.getProperty("java.class.path")); +// System.out.println(System.getProperty("java.class.path")); +// System.out.println("-------------------------------"); + return codeTree; + } + + private ClassPathFactory factory; + + private ClassPath classPath; + + private JFrame jdocWindow; + + /** + * Loads up .jar files and classes defined in it for completion lookup + */ + protected void loadJars() { +// SwingWorker worker = new SwingWorker() { +// protected void done(){ +// } +// protected Object doInBackground() throws Exception { +// return null; +// } +// }; +// worker.execute(); + + Thread t = new Thread(new Runnable() { + + public void run() { + try { + factory = new ClassPathFactory(); + + StringBuffer tehPath = new StringBuffer(System + .getProperty("java.class.path")); + tehPath.append(File.pathSeparatorChar + + System.getProperty("java.home") + "/lib/rt.jar" + + File.pathSeparatorChar); + if (errorCheckerService.classpathJars != null) { + for (URL jarPath : errorCheckerService.classpathJars) { + //System.out.println(jarPath.getPath()); + tehPath.append(jarPath.getPath() + File.pathSeparatorChar); + } + } + +// String paths[] = tehPath.toString().split(File.separatorChar +""); +// StringTokenizer st = new StringTokenizer(tehPath.toString(), +// File.pathSeparatorChar + ""); +// while (st.hasMoreElements()) { +// String sstr = (String) st.nextElement(); +// System.out.println(sstr); +// } + + classPath = factory.createFromPath(tehPath.toString()); +// for (String packageName : classPath.listPackages("")) { +// System.out.println(packageName); +// } + RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( + ".*", + "ArrayList.class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } + System.out.println("jars loaded."); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + t.start(); + } + + private TreeMap jdocMap; + + private void loadJavaDoc() { + + // presently loading only p5 reference for PApplet + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + JavadocHelper.loadJavaDoc(jdocMap, editor.mode().getReferenceFolder()); + } + }); + t.start(); + + } + + public DefaultMutableTreeNode buildAST(CompilationUnit cu) { + return buildAST(errorCheckerService.sourceCode, cu); + } + + public String[] checkForTypes2(ASTNode node) { + + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return new String[] { ((TypeDeclaration) node).getName().toString() }; + + case ASTNode.METHOD_DECLARATION: + String[] ret1 = new String[] { ((MethodDeclaration) node).getName() + .toString() }; + return ret1; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return new String[] { ((SingleVariableDeclaration) node).getName() + .toString() }; + + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + String ret[] = new String[vdfs.size()]; + int i = 0; + for (VariableDeclarationFragment vdf : vdfs) { + ret[i++] = vdf.getName().toString(); + } + return ret; + } + + return null; + } + + public static CompletionCandidate[] checkForTypes(ASTNode node) { + + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return new CompletionCandidate[] { new CompletionCandidate( + getNodeAsString2(node), + ((TypeDeclaration) node) + .getName() + .toString()) }; + + case ASTNode.METHOD_DECLARATION: + MethodDeclaration md = (MethodDeclaration) node; + System.out.println(getNodeAsString(md)); + List params = (List) md + .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); + CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1]; + cand[0] = new CompletionCandidate(md); + for (int i = 0; i < params.size(); i++) { + cand[i + 1] = new CompletionCandidate(params.get(i).toString(), "", "", + CompletionCandidate.LOCAL_VAR); + } + return cand; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return new CompletionCandidate[] { new CompletionCandidate( + getNodeAsString2(node), + "", + "", + CompletionCandidate.LOCAL_VAR) }; + + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()]; + int i = 0; + for (VariableDeclarationFragment vdf : vdfs) { + ret[i++] = new CompletionCandidate(getNodeAsString2(vdf), "", "", + CompletionCandidate.LOCAL_VAR); + } + return ret; + } + + return null; + } + + @SuppressWarnings("unchecked") + public ArrayList getNameIfType(ASTNode astnode) { + + ArrayList names = new ArrayList(); + List sprops = astnode + .structuralPropertiesForType(); + for (StructuralPropertyDescriptor sprop : sprops) { + ASTNode cnode = null; + if (!sprop.isChildListProperty()) { + if (astnode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) astnode.getStructuralProperty(sprop); + //if(cnode) + } + } else { + // Childlist prop + List nodelist = (List) astnode + .getStructuralProperty(sprop); + for (ASTNode clnode : nodelist) { + + } + } + } + + return names; + } + + /** + * Find the parent of the expression in a().b, this would give me the return + * type of a(), so that we can find all children of a() begininng with b + * + * @param nearestNode + * @param expression + * @return + */ + public static ASTNode resolveExpression(ASTNode nearestNode, + ASTNode expression) { +// ASTNode anode = null; + System.out.println("Resolving " + getNodeAsString(expression)); + if (expression instanceof SimpleName) { + return findDeclaration2(((SimpleName) expression), nearestNode); + } else if (expression instanceof MethodInvocation) { + return findDeclaration2(((MethodInvocation) expression).getName(), + nearestNode); + } else if (expression instanceof FieldAccess) { + System.out.println("2. Field access " + + getNodeAsString(((FieldAccess) expression).getExpression())); + return resolveExpression(nearestNode, + ((FieldAccess) expression).getExpression()); + //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); + } else if (expression instanceof QualifiedName) { + System.out.println("1. Resolving " + + ((QualifiedName) expression).getQualifier() + " ||| " + + ((QualifiedName) expression).getName()); + return findDeclaration2(((QualifiedName) expression).getQualifier(), + nearestNode); + } + + return null; + } + + /** + * For a().abc.a123 this would return a123 + * + * @param expression + * @return + */ + public static ASTNode resolveChildExpression(ASTNode expression) { +// ASTNode anode = null; + if (expression instanceof SimpleName) { + return expression; + } else if (expression instanceof FieldAccess) { + return ((FieldAccess) expression).getName(); + } else if (expression instanceof QualifiedName) { + return ((QualifiedName) expression).getName(); + } + System.out.println(" resolveChildExpression returning NULL for " + + getNodeAsString(expression)); + return null; + } + + public static TypeDeclaration getDefiningNode(ASTNode node) { + ASTNode parent = node.getParent(); + while (!(parent instanceof TypeDeclaration)) { + parent = parent.getParent(); + if (parent instanceof CompilationUnit) + return null; + } + return (TypeDeclaration) parent; + } + + public void updatePredictions(final String word, final int line) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + + String word2 = word; + + //After typing 'arg.' all members of arg type are to be listed. This one is a flag for it + boolean noCompare = false; + if (word2.endsWith(".")) { + // return all matches + word2 = word2.substring(0, word.length() - 1); + noCompare = true; + } + + int lineNumber = line; + // Adjust line number for tabbed sketches + if (errorCheckerService != null) { + editor = errorCheckerService.getEditor(); + int codeIndex = editor.getSketch().getCodeIndex(editor + .getCurrentTab()); + if (codeIndex > 0) + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + + } + + // Now parse the expression into an ASTNode object + ASTNode nearestNode = null; + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setKind(ASTParser.K_EXPRESSION); + parser.setSource(word2.toCharArray()); + ASTNode testnode = parser.createAST(null); + + // Find closest ASTNode of the document to this word + System.err.print("Typed: " + word2 + "|"); + nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + .get(0)); + if (nearestNode == null) + //Make sure nearestNode is not NULL if couldn't find a closeset node + nearestNode = (ASTNode) compilationUnit.types().get(0); + System.err.println(lineNumber + " Nearest ASTNode to PRED " + + getNodeAsString(nearestNode)); + + ArrayList candidates = new ArrayList(); + + // Determine the expression typed + + if (testnode instanceof SimpleName && !noCompare) { + System.err + .println("One word expression " + getNodeAsString(testnode)); + //==> Simple one word exprssion - so is just an identifier + + // Bottom up traversal of the AST to look for possible definitions at + // higher levels. + nearestNode = nearestNode.getParent(); + while (nearestNode != null) { + // If the current class has a super class, look inside it for + // definitions. + if (nearestNode instanceof TypeDeclaration) { + TypeDeclaration td = (TypeDeclaration) nearestNode; + if (td + .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) { + SimpleType st = (SimpleType) td + .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); + System.out.println("Superclass " + st.getName()); + for (CompletionCandidate can : getMembersForType(st.getName() + .toString(), word2, noCompare, false)) { + candidates.add(can); + } + //findDeclaration(st.getName()) + + } + } + List sprops = nearestNode + .structuralPropertiesForType(); + for (StructuralPropertyDescriptor sprop : sprops) { + ASTNode cnode = null; + if (!sprop.isChildListProperty()) { + if (nearestNode.getStructuralProperty(sprop) instanceof ASTNode) { + cnode = (ASTNode) nearestNode.getStructuralProperty(sprop); + CompletionCandidate[] types = checkForTypes(cnode); + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (types[i].getElementName().startsWith(word2)) + candidates.add(types[i]); + } + } + } + } else { + // Childlist prop + List nodelist = (List) nearestNode + .getStructuralProperty(sprop); + for (ASTNode clnode : nodelist) { + CompletionCandidate[] types = checkForTypes(clnode); + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (types[i].getElementName().startsWith(word2)) + candidates.add(types[i]); + } + } + } + } + } + nearestNode = nearestNode.getParent(); + } + if(candidates.isEmpty()){ + // We're seeing a simple name that's not defined locally or in + // the parent class. So most probably a pre-defined type. + System.out.println("Empty can. " + word2); + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", word2 + "[a-zA-Z_0-9]*.class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String matchedClass : resources) { + matchedClass = matchedClass.substring(0, + matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + int d = matchedClass.lastIndexOf('.'); + matchedClass = matchedClass.substring(d + 1); + candidates.add(new CompletionCandidate(matchedClass)); + //System.out.println("-> " + className); + } + } + + } else { + + // ==> Complex expression of type blah.blah2().doIt,etc + // Have to resolve it by carefully traversing AST of testNode + System.err.println("Complex expression " + getNodeAsString(testnode)); + + ASTNode det = resolveExpression(nearestNode, testnode); + // Find the parent of the expression + // in a().b, this would give me the return type of a(), so that we can + // find all children of a() begininng with b + System.err.println("DET " + getNodeAsString(det)); + if (det != null) { + TypeDeclaration td = null; + SimpleType stp = null; + if (det instanceof MethodDeclaration) { + if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { + stp = (SimpleType) (((MethodDeclaration) det).getReturnType2()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + } else if (det instanceof FieldDeclaration) { + if (((FieldDeclaration) det).getType() instanceof SimpleType) { + stp = (SimpleType) (((FieldDeclaration) det).getType()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + } else if (det instanceof VariableDeclarationStatement) { + stp = (SimpleType) (((VariableDeclarationStatement) det) + .getType()); + td = (TypeDeclaration) findDeclaration(stp.getName()); + } + System.out.println("ST is " + stp.getName()); + // Now td contains the type returned by a() + System.err.println(getNodeAsString(det) + " defined in " + + getNodeAsString(td)); + ASTNode child = resolveChildExpression(testnode); + if (td != null) { + + System.out.println("Completion candidate: " + + getNodeAsString(child)); + for (int i = 0; i < td.getFields().length; i++) { + List vdfs = td.getFields()[i] + .fragments(); + for (VariableDeclarationFragment vdf : vdfs) { + if (noCompare) { + candidates + .add(new CompletionCandidate(getNodeAsString2(vdf))); + } else if (vdf.getName().toString() + .startsWith(child.toString())) + candidates + .add(new CompletionCandidate(getNodeAsString2(vdf))); + } + + } + for (int i = 0; i < td.getMethods().length; i++) { + if (noCompare) { + candidates + .add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString(), "", + CompletionCandidate.METHOD)); + } else if (td.getMethods()[i].getName().toString() + .startsWith(child.toString())) + candidates + .add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString(), "", + CompletionCandidate.METHOD)); + } + } else { + if (stp != null) { + candidates = getMembersForType(stp.getName().toString(), + child.toString(), noCompare, + false); + } + } + + } else if (word.length() - word2.length() == 1) { + System.out.println(word + " w2 " + word2); +// int dC = 0; +// for (int i = 0; i < word.length(); i++) { +// if(word.charAt(i) == '.') +// dC++; +// } +// if(dC == 1 && word.charAt(word.length() - 1) == '.'){ + System.out.println("All members of " + word2); + candidates = getMembersForType(word2, "", true, true); +// } + } else { + System.out.println("Some members of " + word2); + int x = word2.indexOf('.'); + if (x != -1) { + candidates = getMembersForType(word2.substring(0, x), + word2.substring(x + 1), false, + true); + } + } + + } + + Collections.sort(candidates); + CompletionCandidate[][] candi = new CompletionCandidate[candidates + .size()][1]; + + for (int i = 0; i < candi.length; i++) { + candi[i][0] = candidates.get(i); + } + System.out.println("K = " + candidates.size()); + DefaultTableModel tm = new DefaultTableModel( + candi, + new String[] { "Suggestions" }); + tableAuto.setModel(tm); + tableAuto.validate(); + tableAuto.repaint(); + //String[] items = + CompletionCandidate[] candi2 = candidates + .toArray(new CompletionCandidate[candidates.size()]); + if (candidates.size() > 0) + errorCheckerService.getEditor().textArea().showSuggestion(candi2); + } + }; + + worker.execute(); + + } + + /** + * Loads classes from .jar files in sketch classpath + * + * @param typeName + * @param child + * @param noCompare + * @return + */ + public ArrayList getMembersForType(String typeName, + String child, + boolean noCompare, + boolean staticOnly) { + ArrayList candidates = new ArrayList(); + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } + if (resources.length > 0) { //TODO: Multiple matched classes? What about 'em? + String matchedClass = resources[0]; + matchedClass = matchedClass.substring(0, matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + System.out.println("In GMFT(), Matched class: " + matchedClass); + System.out.println("Looking for match " + child.toString()); + try { + Class probableClass = Class.forName(matchedClass, false, + errorCheckerService.classLoader); + + for (Method method : probableClass.getMethods()) { + if (!Modifier.isStatic(method.getModifiers()) && staticOnly) + continue; + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); + } + + label.append(")"); + if (noCompare) + candidates.add(new CompletionCandidate(method)); + else if (label.toString().startsWith(child.toString())) + candidates.add(new CompletionCandidate(method)); + } + for (Field field : probableClass.getFields()) { + if (!Modifier.isStatic(field.getModifiers()) && staticOnly) + continue; + if (noCompare) + candidates.add(new CompletionCandidate(field)); + else if (field.getName().startsWith(child.toString())) + candidates.add(new CompletionCandidate(field)); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.out.println("Couldn't load " + matchedClass); + } + } + //updateJavaDoc(methodmatch) + + return candidates; + } + + public void updateJavaDoc(final CompletionCandidate candidate) { + String methodmatch = candidate.toString(); + if (methodmatch.indexOf('(') != -1) { + methodmatch = methodmatch.substring(0, methodmatch.indexOf('(')); + } + + //System.out.println("jdoc match " + methodmatch); + for (final String key : jdocMap.keySet()) { + if (key.startsWith(methodmatch) && key.length() > 3) { + System.out.println("Matched jdoc " + key); + + //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + System.out.println("Class: " + candidate.getDefiningClass()); + if (candidate.getDefiningClass().equals("processing.core.PApplet")) { + javadocPane.setText(jdocMap.get(key)); + //jdocWindow.setVisible(true); + //editor.textArea().requestFocus() + } else + javadocPane.setText(""); + javadocPane.setCaretPosition(0); + } + }); + break; + } + } + //jdocWindow.setVisible(false); + + } + + @SuppressWarnings("unchecked") + private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); +// System.out.println("Looking at " + getNodeAsString(cnode)); + int cLineNum = ((CompilationUnit) cnode.getRoot()) + .getLineNumber(cnode.getStartPosition() + cnode.getLength()); + if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { + return findClosestParentNode(lineNumber, cnode); + } + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + int cLineNum = ((CompilationUnit) cnode.getRoot()) + .getLineNumber(cnode.getStartPosition() + cnode.getLength()); +// System.out.println("Looking at " + getNodeAsString(cnode)); + if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { + return findClosestParentNode(lineNumber, cnode); + } + } + } + } + return node; + } + + @SuppressWarnings("unchecked") + private static ASTNode findClosestNode(int lineNumber, ASTNode node) { + ASTNode parent = findClosestParentNode(lineNumber, node); + if (parent == null) + return null; + if (getLineNumber(parent) == lineNumber) + return parent; + List nodes = null; + if (parent instanceof TypeDeclaration) { + nodes = (List) ((TypeDeclaration) parent) + .getStructuralProperty(TypeDeclaration.BODY_DECLARATIONS_PROPERTY); + } else if (parent instanceof Block) { + nodes = (List) ((Block) parent) + .getStructuralProperty(Block.STATEMENTS_PROPERTY); + } else { + System.err.println("THIS CONDITION SHOULD NOT OCCUR - findClosestNode " + + getNodeAsString(parent)); + return null; + } + + if (nodes.size() > 0) { + ASTNode retNode = nodes.get(0); + for (ASTNode cNode : nodes) { + if (getLineNumber(cNode) <= lineNumber) + retNode = cNode; + else + break; + } + + return retNode; + } + return null; + } + +// static DefaultMutableTreeNode findNodeBS(DefaultMutableTreeNode tree, +// int lineNumber, String name, +// int elementOffset) { +// if (tree.getUserObject() == null) +// return null; +// +// ASTNodeWrapper node = ((ASTNodeWrapper) tree.getUserObject()); +// +// if (node.getLineNumber() == lineNumber) { +// System.out.println("Located line " + lineNumber + " , " + tree); +// if (name == null) +// return tree; +// else +// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() +// .getStartPosition()); +// } +// +// int low = 0, high = tree.getChildCount() - 1, mid = (high + low) / 2; +// DefaultMutableTreeNode tnode = null; +// while (low <= high) { +// mid = (high + low) / 2; +// tnode = (DefaultMutableTreeNode) tree.getChildAt(mid); +// node = ((ASTNodeWrapper) tnode.getUserObject()); +// if (node.getLineNumber() == lineNumber) { +// System.out.println("Located line " + lineNumber + " , " + tnode); +// if (name == null) +// return tnode; +// else +// return findOnLine(tnode, lineNumber, name, elementOffset, node +// .getNode().getStartPosition()); +// } else if (lineNumber < node.getLineNumber()) { +// high = mid - 1; +// } else { +// if (high - mid <= 1) { +// if (lineNumber > ((ASTNodeWrapper) ((DefaultMutableTreeNode) tree +// .getChildAt(high)).getUserObject()).getLineNumber()) //high l no. +// low = mid + 1; +// else +// +// high = mid - 1; +// } +// low = mid + 1; +// } +// +// } +// +// if (!tnode.isLeaf()) +// return findNodeBS(tnode, lineNumber, name, elementOffset); +// else +// return tnode; +// +// //System.out.println("visiting: " + getNodeAsString(node.getNode()) + " on line "+node.getLineNumber()); +// if (node.getLineNumber() == lineNumber) { +// System.err.println("Located line: " + node.toString()); +// if (name == null) // name ==null, finds any node equal to line +// // number +// { +// System.out.println("Closest node at line: " + lineNumber); +// return tree; +// } else +// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() +// .getStartPosition()); +// +// } else if (!tree.isLeaf()) { +// for (int i = 0; i < tree.getChildCount(); i++) { +// .getChildAt(i), +// lineNumber, name, elementOffset); +// if (node2 != null) +// return node2; +// } +// } +// +// return null; +// } + + public DefaultMutableTreeNode getAST() { + return codeTree; + } + + public String getLabelForASTNode(int lineNumber, String name, int offset) { + retLabelString = ""; + getASTNodeAt(lineNumber, name, offset, false); + return retLabelString; + } + + public void scrollToDeclaration(int lineNumber, String name, int offset) { + getASTNodeAt(lineNumber, name, offset, true); + } + + String retLabelString; + + /** + * + * @param lineNumber + * @param name + * @param offset - line start nonwhitespace offset + * @param scrollOnly + * @return + */ + public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, + boolean scrollOnly) { + + System.out.println("----getASTNodeAt----"); + if (errorCheckerService != null) { + editor = errorCheckerService.getEditor(); + int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); + if (codeIndex > 0) { + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + } + + } + System.out.println("FLON: " + lineNumber); + ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); + + System.out.println("+> " + lineNode); + ASTNode decl = null; + String nameOfNode = null; // The node name which is to be scrolled to + if (lineNode != null) { + + // Some delicate offset handling follows. + ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); + int altOff = offset; + int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); + if(ret != null){ + altOff = 0; + int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; + + for (; altOff < javaCodeMap.length; altOff++) { + if (javaCodeMap[altOff] == pdeCodeMap[offset]) { + break; + } + } + } + System.out.println("FLON2: " + lineNumber + " LN spos " + + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + /* + * Now I need to see if multiple statements exist with this same line number + * If that's the case, I need to ensure the offset is right. + */ + ASTNode parLineNode = lineNode.getParent(); + + Iterator it = parLineNode + .structuralPropertiesForType().iterator(); + boolean flag = true; + int offAdjust = 0; + while (it.hasNext() && flag) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) parLineNode + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (getLineNumber(cnode) == lineNumber) { + if (cnode.getStartPosition() <= lineNode.getStartPosition() + + altOff + && cnode.getStartPosition() + cnode.getLength() > lineNode + .getStartPosition() + altOff) { + System.out.println(cnode); + offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); + lineNode = cnode; + altOff -= offAdjust; + flag = false; + break; + } + + } + } + } + } + System.out.println("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + ASTNode simpName = pinpointOnLine(lineNode, altOff, + lineNode.getStartPosition(), name); + System.out.println("+++> " + simpName); + if (simpName instanceof SimpleName) { + nameOfNode = simpName.toString(); + System.out.println(getNodeAsString(simpName)); + decl = findDeclaration((SimpleName) simpName); + if (decl != null) { + System.err.println("DECLA: " + decl.getClass().getName()); + retLabelString = getNodeAsString(decl); + } else + System.err.println("null"); + + System.out.println(getNodeAsString(decl)); + } + } + + if (decl != null && scrollOnly) { + /* + * For scrolling, we highlight just the name of the node, + * i.e., a SimpleName instance. But the declared node always + * points to the declared node itself, like TypeDecl, MethodDecl, etc. + * This is important since it contains all the properties. + */ + ASTNode simpName2 = getNodeName(decl,nameOfNode); + System.err.println("FINAL String decl: " + getNodeAsString(decl)); + System.err.println("FINAL String label: " + getNodeAsString(simpName2)); + errorCheckerService.highlightNode(simpName2); + } + + return new ASTNodeWrapper(decl); + } + + /** + * Given a declaration type astnode, returns the SimpleName peroperty + * of that node. + * @param node + * @param name - The name we're looking for. + * @return SimpleName + */ + private static ASTNode getNodeName(ASTNode node, String name){ + List vdfs = null; + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + return ((TypeDeclaration) node).getName(); + case ASTNode.METHOD_DECLARATION: + return ((MethodDeclaration) node).getName(); + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return ((SingleVariableDeclaration) node).getName(); + case ASTNode.FIELD_DECLARATION: + vdfs = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + vdfs = ((VariableDeclarationStatement) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + vdfs = ((VariableDeclarationExpression) node).fragments(); + break; + default: + break; + } + + if (vdfs != null) { + for (VariableDeclarationFragment vdf : vdfs) { + if (vdf.getName().toString().equals(name)) { + return vdf.getName(); + } + } + + } + return null; + } + + /** + * Fetches line number of the node in its CompilationUnit. + * @param node + * @return + */ + private static int getLineNumber(ASTNode node) { + return ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + } + + public static void main(String[] args) { + traversal2(); + } + + public static void traversal2() { + ASTParser parser = ASTParser.newParser(AST.JLS4); + String source = readFile("/media/quarkninja/Work/TestStuff/low.java"); +// String source = "package decl; \npublic class ABC{\n int ret(){\n}\n}"; + parser.setSource(source.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + System.out.println(CompilationUnit.propertyDescriptors(AST.JLS4).size()); + + DefaultMutableTreeNode astTree = new DefaultMutableTreeNode( + "CompilationUnit"); + System.err.println("Errors: " + cu.getProblems().length); + visitRecur(cu, astTree); + System.out.println(astTree.getChildCount()); + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + JFrame frame2 = new JFrame(); + JTree jtree = new JTree(astTree); + frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame2.setBounds(new Rectangle(100, 100, 460, 620)); + JScrollPane sp = new JScrollPane(); + sp.setViewportView(jtree); + frame2.add(sp); + frame2.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + + ASTNode found = NodeFinder.perform(cu, 468, 5); + if (found != null) { + System.out.println(found); + } + } + + private void addListeners(){ + jtree.addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + System.out.println(e); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if(jtree + .getLastSelectedPathComponent() == null){ + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) jtree + .getLastSelectedPathComponent(); + if(tnode.getUserObject() == null){ + return; + } + + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + errorCheckerService.highlightNode(awrap); + } + } + }; + worker.execute(); + } + }); + + renameButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (editor.ta.getSelectedText() == null) + return; + if(renameTextField.getText().length() == 0) + return; + String newName = renameTextField.getText(); + DefaultMutableTreeNode defCU = findAllOccurrences(); + renameTree.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) renameTree.getModel()).reload(); + int lineOffsetDisplacementConst = newName.length() + - editor.ta.getSelectedText().length(); + HashMap lineOffsetDisplacement = new HashMap(); + + for (int i = defCU.getChildCount() - 1; i >= 0; i--) { + ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU + .getChildAt(i))).getUserObject(); + int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); + int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); + + // correction for pde enhancements related displacement on a line + int off = 0; + if(lineOffsetDisplacement.get(javaoffsets[0]) != null){ + off = lineOffsetDisplacement.get(javaoffsets[0]); + + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst + off); + } + else{ + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst); + } + + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1], + javaoffsets[1] + off, + javaoffsets[2]); + editor.ta.setSelectedText(newName); + } + for (Integer lineNum : lineOffsetDisplacement.keySet()) { + System.out.println(lineNum + "line, disp" + + lineOffsetDisplacement.get(lineNum)); + } + editor.getSketch().setModified(true); + } + }; + worker.execute(); + } + }); + // TODO: Diable this listner at deployment + listOccurrence.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (editor.ta.getSelectedText() == null) + return; + DefaultMutableTreeNode defCU = findAllOccurrences(); + renameTree.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) renameTree.getModel()).reload(); + } + }; + worker.execute(); + } + }); + + renameTree.addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + System.out.println(e); + SwingWorker worker = new SwingWorker() { + + @Override + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if(renameTree + .getLastSelectedPathComponent() == null){ + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) renameTree + .getLastSelectedPathComponent(); + if(tnode.getUserObject() == null){ + return; + } + + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + errorCheckerService.highlightNode(awrap); + } + } + }; + worker.execute(); + } + }); + } + + private DefaultMutableTreeNode findAllOccurrences(){ + String selText = editor.ta.getSelectedText(); + int line = editor.ta.getSelectionStartLine(); + System.out.println(editor.ta.getSelectedText() + + "<- offsets " + + (line) + + ", " + + (editor.ta.getSelectionStart() - editor.ta + .getLineStartOffset(line)) + + ", " + + (editor.ta.getSelectionStop() - editor.ta + .getLineStartOffset(line))); + int offwhitespace = editor.ta + .getLineStartNonWhiteSpaceOffset(line); + ASTNodeWrapper wnode = getASTNodeAt(line + + errorCheckerService.mainClassOffset, + selText, + editor.ta.getSelectionStart() + - offwhitespace, false); + System.err.println("Gonna find all occurrences of " + + getNodeAsString(wnode.getNode())); + + //If wnode is a constructor, find the TD instead. + if (wnode.getNodeType() == ASTNode.METHOD_DECLARATION) { + MethodDeclaration md = (MethodDeclaration) wnode.getNode(); + ASTNode node = md.getParent(); + while (node != null) { + if (node instanceof TypeDeclaration) { + // System.out.println("Parent class " + getNodeAsString(node)); + break; + } + node = node.getParent(); + } + if(node != null && node instanceof TypeDeclaration){ + TypeDeclaration td = (TypeDeclaration) node; + if(td.getName().toString().equals(md.getName().toString())){ + System.err.println("Renaming constructor of " + getNodeAsString(td)); + wnode = new ASTNodeWrapper(td); + } + } + } + + DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); + dfsNameOnly(defCU, wnode.getNode(), selText); + System.out.println(wnode); + return defCU; + } + + @SuppressWarnings({ "unchecked" }) + /** + * Generates AST Swing component + * @param node + * @param tnode + */ + public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + DefaultMutableTreeNode ctnode = null; + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + if (isAddableASTNode(cnode)) { + ctnode = new DefaultMutableTreeNode( + new ASTNodeWrapper((ASTNode) node + .getStructuralProperty(prop))); + tnode.add(ctnode); + visitRecur(cnode, ctnode); + } + } else { + tnode.add(new DefaultMutableTreeNode(node + .getStructuralProperty(prop))); + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (isAddableASTNode(cnode)) { + ctnode = new DefaultMutableTreeNode(new ASTNodeWrapper(cnode)); + tnode.add(ctnode); + visitRecur(cnode, ctnode); + } else + visitRecur(cnode, tnode); + } + } + } + } + + public void dfsNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) { + Stack temp = new Stack(); + temp.push(codeTree); + + while(!temp.isEmpty()){ + DefaultMutableTreeNode cnode = (DefaultMutableTreeNode) temp.pop(); + for (int i = 0; i < cnode.getChildCount(); i++) { + temp.push(cnode.getChildAt(i)); + } + + if(!(cnode.getUserObject() instanceof ASTNodeWrapper)) + continue; + ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); +// System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); + if(isInstanceOfType(awnode.getNode(), decl, name)){ + tnode.add(new DefaultMutableTreeNode(awnode)); + } + + } + } + + private boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ + if(node instanceof SimpleName){ + SimpleName sn = (SimpleName) node; + + if (sn.toString().equals(name)) { + ArrayList nodesToBeMatched = new ArrayList(); + nodesToBeMatched.add(decl); + if(decl instanceof TypeDeclaration){ + System.out.println("decl is a TD"); + TypeDeclaration td = (TypeDeclaration)decl; + MethodDeclaration[] mlist = td.getMethods(); + for (MethodDeclaration md : mlist) { + if(md.getName().toString().equals(name)){ + nodesToBeMatched.add(md); + } + } + } + System.out.println("Visiting: " + getNodeAsString(node)); + ASTNode decl2 = findDeclaration(sn); + System.err.println("It's decl: " + getNodeAsString(decl2)); + System.out.println("But we need: "+getNodeAsString(decl)); + for (ASTNode astNode : nodesToBeMatched) { + if(astNode.equals(decl2)){ + return true; + } + } + } + } + return false; + } + + public void handleRefactor(){ + if (!renameWindow.isVisible()) + renameWindow.setVisible(true); + renameWindow.toFront(); + } + + + public static void printRecur(ASTNode node) { + Iterator it = node + .structuralPropertiesForType().iterator(); + //System.err.println("Props of " + node.getClass().getName()); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { +// System.out +// .println(node.getStructuralProperty(prop) + " -> " + (prop)); + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); + System.out.println(getNodeAsString(cnode)); + printRecur(cnode); + } + } + } + + else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + System.out.println(getNodeAsString(cnode)); + printRecur(cnode); + } + } + } + } + + @SuppressWarnings("unchecked") + private static ASTNode findLineOfNode(ASTNode node, int lineNumber, + int offset, String name) { + + CompilationUnit root = (CompilationUnit) node.getRoot(); +// System.out.println("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); + if (root.getLineNumber(node.getStartPosition()) == lineNumber) { + System.err + .println(3 + getNodeAsString(node) + " len " + node.getLength()); + return node; +// if (offset < node.getLength()) +// return node; +// else { +// System.err.println(-11); +// return null; +// } + } + for (Object oprop : node.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode retNode = findLineOfNode((ASTNode) node + .getStructuralProperty(prop), + lineNumber, offset, name); + if (retNode != null) { +// System.err.println(11 + getNodeAsString(retNode)); + return retNode; + } + } + } + } else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + + ASTNode rr = findLineOfNode(retNode, lineNumber, offset, name); + if (rr != null) { +// System.err.println(12 + getNodeAsString(rr)); + return rr; + } + } + } + } +// System.err.println("-1"); + return null; + } + + /** + * + * @param node + * @param offset + * - from textarea painter + * @param lineStartOffset + * - obtained from findLineOfNode + * @param name + * @param root + * @return + */ + @SuppressWarnings("unchecked") + public static ASTNode pinpointOnLine(ASTNode node, int offset, + int lineStartOffset, String name) { + + if (node instanceof SimpleName) { + SimpleName sn = (SimpleName) node; + System.out.println(offset+ "off,pol " + getNodeAsString(sn)); + if ((lineStartOffset + offset) >= sn.getStartPosition() + && (lineStartOffset + offset) <= sn.getStartPosition() + + sn.getLength()) { + if (sn.toString().equals(name)) { + return sn; + } + else { + return null; + } + } else { + return null; + } + } + for (Object oprop : node.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (node.getStructuralProperty(prop) != null) { + if (node.getStructuralProperty(prop) instanceof ASTNode) { + ASTNode retNode = pinpointOnLine((ASTNode) node + .getStructuralProperty(prop), + offset, lineStartOffset, name); + if (retNode != null) { +// System.err.println(11 + getNodeAsString(retNode)); + return retNode; + } + } + } + } else if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + + ASTNode rr = pinpointOnLine(retNode, offset, lineStartOffset, name); + if (rr != null) { +// System.err.println(12 + getNodeAsString(rr)); + return rr; + } + } + } + } +// System.err.println("-1"); + return null; + } + + @SuppressWarnings("unchecked") + private static ASTNode findDeclaration(Name findMe) { + ASTNode declaringClass = null; + ASTNode parent = findMe.getParent(); + ASTNode ret = null; + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration((stp.getName())); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + declaringClass = findDeclaration((stp.getName())); + constrains.add(ASTNode.TYPE_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + declaringClass = findDeclaration(stp.getName()); + System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); + declaringClass = findDeclaration(stp.getName()); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qn.getName().toString(), constrains, + null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { + constrains.add(ASTNode.TYPE_DECLARATION); + if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) + constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + } else if(parent.getNodeType() == ASTNode.TYPE_DECLARATION){ + // The condition where we look up the name of a class decl + TypeDeclaration td = (TypeDeclaration) parent; + if(findMe.equals(td.getName())) + { + return parent; + } + } + else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } + while (parent != null) { + System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); + for (Object oprop : parent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (parent.getStructuralProperty(prop) instanceof ASTNode) { +// System.out.println(prop + " C/S Prop of -> " +// + getNodeAsString(parent)); + ret = definedIn((ASTNode) parent.getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { +// System.out.println((prop) + " ChildList props of " +// + getNodeAsString(parent)); + List nodelist = (List) parent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + parent = parent.getParent(); + } + return null; + } + + private static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { + ASTNode declaringClass = null; + ASTNode parent = findMe.getParent(); + ASTNode ret = null; + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2((stp.getName()), alternateParent); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, ((MethodInvocation) parent) + .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + alternateParent = alternateParent.getParent(); + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) + .getName(), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2((stp.getName()), alternateParent); + constrains.add(ASTNode.TYPE_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), + alternateParent)); + if (stp == null) + return null; + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn(declaringClass, fa.getName().toString(), + constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + alternateParent = alternateParent.getParent(); + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration2((qn.getQualifier()), + alternateParent)); + declaringClass = findDeclaration2(stp.getName(), alternateParent); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qn.getName().toString(), constrains, + null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { + constrains.add(ASTNode.TYPE_DECLARATION); + if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) + constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + } else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } // TODO: in findDec, we also have a case where parent of type TD is handled. + // Figure out if needed here as well. + System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); + while (alternateParent != null) { +// System.out.println("findDeclaration2 -> " +// + getNodeAsString(alternateParent)); + for (Object oprop : alternateParent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) { +// System.out.println(prop + " C/S Prop of -> " +// + getNodeAsString(alternateParent)); + ret = definedIn((ASTNode) alternateParent + .getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { +// System.out.println((prop) + " ChildList props of " +// + getNodeAsString(alternateParent)); + List nodelist = (List) alternateParent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + alternateParent = alternateParent.getParent(); + } + return null; + } + + /** + * Find the SimpleType from FD, SVD, VDS, etc + * + * @param node + * @return + */ + private static SimpleType extracTypeInfo(ASTNode node) { + if (node == null) + return null; + switch (node.getNodeType()) { + case ASTNode.METHOD_DECLARATION: + return (SimpleType) ((MethodDeclaration) node) + .getStructuralProperty(MethodDeclaration.RETURN_TYPE2_PROPERTY); + case ASTNode.FIELD_DECLARATION: + return (SimpleType) ((FieldDeclaration) node) + .getStructuralProperty(FieldDeclaration.TYPE_PROPERTY); + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + return (SimpleType) ((VariableDeclarationExpression) node) + .getStructuralProperty(VariableDeclarationExpression.TYPE_PROPERTY); + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + return (SimpleType) ((VariableDeclarationStatement) node) + .getStructuralProperty(VariableDeclarationStatement.TYPE_PROPERTY); + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return (SimpleType) ((SingleVariableDeclaration) node) + .getStructuralProperty(SingleVariableDeclaration.TYPE_PROPERTY); + } + return null; + } + + @SuppressWarnings("unchecked") + private static ASTNode definedIn(ASTNode node, String name, + ArrayList constrains, + ASTNode declaringClass) { + if (node == null) + return null; + if (constrains != null) { +// System.out.println("Looking at " + getNodeAsString(node) + " for " + name +// + " in definedIn"); + if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) { +// System.err.print("definedIn -1 " + " But constrain was "); +// for (Integer integer : constrains) { +// System.out.print(ASTNode.nodeClassForType(integer) + ","); +// } +// System.out.println(); + return null; + } + } + + List vdfList = null; + switch (node.getNodeType()) { + + case ASTNode.TYPE_DECLARATION: + System.err.println(getNodeAsString(node)); + TypeDeclaration td = (TypeDeclaration) node; + if (td.getName().toString().equals(name)) { + if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) { + // look for constructor; + MethodDeclaration[] methods = td.getMethods(); + for (MethodDeclaration md : methods) { + if (md.getName().toString().equals(name)) { + System.out.println("Found a constructor."); + return md; + } + } + } else { + // it's just the TD we're lookin for + return node; + } + } else { + if (constrains.contains(ASTNode.FIELD_DECLARATION)) { + // look for fields + FieldDeclaration[] fields = td.getFields(); + for (FieldDeclaration fd : fields) { + List fragments = fd.fragments(); + for (VariableDeclarationFragment vdf : fragments) { + if (vdf.getName().toString().equals(name)) + return fd; + } + } + } else if (constrains.contains(ASTNode.METHOD_DECLARATION)) { + // look for methods + MethodDeclaration[] methods = td.getMethods(); + for (MethodDeclaration md : methods) { + if (md.getName().toString().equals(name)) { + return md; + } + } + } + } + break; + case ASTNode.METHOD_DECLARATION: + System.err.println(getNodeAsString(node)); + if (((MethodDeclaration) node).getName().toString().equals(name)) + return node; + break; + case ASTNode.SINGLE_VARIABLE_DECLARATION: + System.err.println(getNodeAsString(node)); + if (((SingleVariableDeclaration) node).getName().toString().equals(name)) + return node; + break; + case ASTNode.FIELD_DECLARATION: + System.err.println("FD" + node); + vdfList = ((FieldDeclaration) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + System.err.println("VDE" + node); + vdfList = ((VariableDeclarationExpression) node).fragments(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + System.err.println("VDS" + node); + vdfList = ((VariableDeclarationStatement) node).fragments(); + break; + + default: + + } + if (vdfList != null) { + for (VariableDeclarationFragment vdf : vdfList) { + if (vdf.getName().toString().equals(name)) + return node; + } + } + return null; + } + + public static boolean isAddableASTNode(ASTNode node) { + switch (node.getNodeType()) { +// case ASTNode.STRING_LITERAL: +// case ASTNode.NUMBER_LITERAL: +// case ASTNode.BOOLEAN_LITERAL: +// case ASTNode.NULL_LITERAL: +// return false; + default: + return true; + } + } + + /** + * For any line or expression, finds the line start offset(java code). + * @param node + * @return + */ + public int getASTNodeLineStartOffset(ASTNode node){ + int nodeLineNo = getLineNumber(node); + while(node.getParent() != null){ + if (getLineNumber(node.getParent()) == nodeLineNo) { + node = node.getParent(); + } else { + break; + } + } + return node.getStartPosition(); + } + + /** + * For any node, finds various offsets (java code). + * + * @param node + * @return int[]{line number, line number start offset, node start offset, + * node length} + */ + public int[] getASTNodeAllOffsets(ASTNode node){ + int nodeLineNo = getLineNumber(node), nodeOffset = node.getStartPosition(), nodeLength = node + .getLength(); + while(node.getParent() != null){ + if (getLineNumber(node.getParent()) == nodeLineNo) { + node = node.getParent(); + } else { + break; + } + } + return new int[]{nodeLineNo, node.getStartPosition(), nodeOffset,nodeLength}; + } + + + + static private String getNodeAsString(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString() + " | " + className; + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString() + " | " + + className; + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString() + " FldDecl| "; + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName() + " - " + + ((SingleVariableDeclaration) node).getType() + " | SVD "; + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (node instanceof QualifiedName) + value = node.toString() + " | " + className; + else if (className.startsWith("Variable")) + value = node.toString() + " | " + className; + else if (className.endsWith("Type")) + value = node.toString() + " |" + className; + value += " [" + node.getStartPosition() + "," + + (node.getStartPosition() + node.getLength()) + "]"; + value += " Line: " + + ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + return value; + } + + /** + * CompletionPanel name + * + * @param node + * @return + */ + static private String getNodeAsString2(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString(); + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString(); + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString(); + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName().toString(); + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (node instanceof QualifiedName) + value = node.toString(); + else if (node instanceof VariableDeclarationFragment) + value = ((VariableDeclarationFragment) node).getName().toString(); + else if (className.startsWith("Variable")) + value = node.toString(); + else if (node instanceof VariableDeclarationStatement) + value = ((VariableDeclarationStatement) node).toString(); + else if (className.endsWith("Type")) + value = node.toString(); +// value += " [" + node.getStartPosition() + "," +// + (node.getStartPosition() + node.getLength()) + "]"; +// value += " Line: " +// + ((CompilationUnit) node.getRoot()).getLineNumber(node +// .getStartPosition()); + return value; + } + + public void jdocWindowVisible(boolean visible) { + jdocWindow.setVisible(visible); + } + + public static String readFile(String path) { + BufferedReader reader = null; + try { + reader = new BufferedReader( + new InputStreamReader( + new FileInputStream( + new File( + path)))); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + try { + StringBuilder ret = new StringBuilder(); + // ret.append("package " + className + ";\n"); + String line; + while ((line = reader.readLine()) != null) { + ret.append(line); + ret.append("\n"); + } + return ret.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return null; + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java new file mode 100644 index 000000000..359d3d4e2 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java @@ -0,0 +1,425 @@ +package processing.mode.experimental; + +import java.util.Iterator; +import java.util.List; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.TypeDeclaration; + +public class ASTNodeWrapper { + private ASTNode Node; + + private String label; + + private int lineNumber; + + //private int apiLevel; + + /* + * TODO: Every ASTNode object in ASTGenerator.codetree is stored as a + * ASTNodeWrapper instance. So how resource heavy would it be to store a + * pointer to ECS in every instance of ASTNodeWrapper? Currently I will rather + * pass an ECS pointer in the argument when I need to access a method which + * requires a method defined in ECS, i.e, only on demand. + * Bad design choice for ECS methods? IDK, yet. + */ + + public ASTNodeWrapper(ASTNode node) { + if (node == null){ + return; + } + this.Node = node; + label = getNodeAsString(node); + if (label == null) + label = node.toString(); + lineNumber = getLineNumber(node); + label += " | Line " + lineNumber; + //apiLevel = 0; + } + + /** + * For this node, finds various offsets (java code). + * Note that line start offset for this node is int[2] - int[1] + * @return int[]{line number, line number start offset, node start offset, + * node length} + */ + public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { + int nodeOffset = Node.getStartPosition(), nodeLength = Node + .getLength(); + ASTNode thisNode = Node; + while (thisNode.getParent() != null) { + if (getLineNumber(thisNode.getParent()) == lineNumber) { + thisNode = thisNode.getParent(); + } else { + break; + } + } + /* + * There's an edge case here - multiple statements in a single line. + * After identifying the statement with the line number, I'll have to + * look at previous tree nodes in the same level for same line number. + * The correct line start offset would be the line start offset of + * the first node with this line number. + * + * Using linear search for now. P.S: Eclipse AST iterators are messy. + * TODO: binary search might improve speed by 0.001%? + */ + + int altStartPos = thisNode.getStartPosition(); + thisNode = thisNode.getParent(); + + Iterator it = thisNode + .structuralPropertiesForType().iterator(); + boolean flag = true; + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) thisNode + .getStructuralProperty(prop); + for (ASTNode cnode : nodelist) { + if (getLineNumber(cnode) == lineNumber) { + if (flag) { + altStartPos = cnode.getStartPosition(); + // System.out.println("multi..."); + + flag = false; + } else { + if(cnode == Node){ + // loop only till the current node. + break; + } + // We've located the first node in the line. + // Now normalize offsets till Node + //altStartPos += normalizeOffsets(cnode); + + } + + } + } + } + } + System.out.println("Altspos " + altStartPos); + int pdeoffsets[] = getPDECodeOffsets(ecs); + String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); + int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); + if (vals != null) + return new int[] { + lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; + else + return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; + } + + + /** + * + * @param source + * @param inpOffset + * @param nodeLen + * @return int[0] - difference in start offset, int[1] - node length + */ + private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { + + int ret[][] = getOffsetMapping(source); + if(ret == null){ + // no offset mapping needed + return null; + } + int javaCodeMap[] = ret[0]; + int pdeCodeMap[] = ret[1]; + int pi = 1, pj = 1; + pj = 0; + pi = 0; + int count = 1; + // first find the java code index + pj = inpOffset; + + int startIndex = javaCodeMap[pj]; + + // find beginning + while (pdeCodeMap[pi] != startIndex && pi < pdeCodeMap.length) + pi++; + int startoffDif = pi - pj; + int stopindex = javaCodeMap[pj + nodeLen - 1]; + System.out.println(startIndex + "SI,St" + stopindex + "sod " + startoffDif); + + // count till stopindex + while (pdeCodeMap[pi] < stopindex && pi < pdeCodeMap.length) { + pi++; + count++; + } + +// System.out.println("PDE maps from " + pdeeCodeMap[pi]); + + System.out.println("pde len " + count); + return new int[] { startoffDif, count }; + } + + /** + * Generates offset mapping between java and pde code + * + * @param source + * @return int[0] - java code offsets, int[1] = pde code offsets + */ + public int[][] getOffsetMapping(String source){ + + /* + * This is some tricky shiz. So detailed explanation follows: + * + * The main issue here is that pde enhancements like color vars, # literals + * and int() type casting deviate from standard java. But I need to exact + * index matching for pde and java versions of snippets.For ex: + * "color col = #ffaadd;" <-PDE version + * "int col = 0xffffaadd;" <-Converted to Java + * + * For exact index mapping, I need to know at which indices either is + * deviating from the other and by what amount. Turns out, it isn't quite + * easy.(1) First I take the pde version of the code as an argument(pde + * version fetched from the editor directly). I then find all instances + * which need to be converted to pure java, marking those indices and the + * index correction needed. (2) Now all java conversions are applied after + * marking the offsets. This ensures that the index order isn't disturbed by + * one at a time conversions as done in preprocessCode() in ECS. Took me + * sometime to figure out this was a bug. (3) Next I create a tables(two + * separate arrays) which allows me to look it up for matching any index + * between pde or java version of the snippet. This also lets me find out + * any difference in length between both versions. + * + * Keep in mind though, dark magic was involved in creating the final lookup + * table. + * + * TODO: This is a work in progress. There may be more bugs here in hiding. + */ + + System.out.println("Src:" + source); + String sourceAlt = new String(source); + TreeMap offsetmap = new TreeMap(); + + // Find all #[web color] + // Should be 6 digits only. + final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; + Pattern webPattern = Pattern.compile(webColorRegexp); + Matcher webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + // System.out.println("-> " + found); + offsetmap.put(webMatcher.end() - 1, 3); + } + + // Find all color data types + final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; + Pattern colorPattern = Pattern.compile(colorTypeRegex); + Matcher colorMatcher = colorPattern.matcher(sourceAlt); + while (colorMatcher.find()) { +// System.out.print("Start index: " + colorMatcher.start()); +// System.out.println(" End index: " + colorMatcher.end() + " "); +// System.out.println("-->" + colorMatcher.group() + "<--"); + offsetmap.put(colorMatcher.end() - 1, -2); + } + + // Find all int(), char() + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(sourceAlt); + + while (matcher.find()) { +// System.out.print("Start index: " + matcher.start()); +// System.out.println(" End index: " + matcher.end() + " "); +// System.out.println("-->" + matcher.group() + "<--"); + offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); + } + matcher.reset(); + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) + + "("); + + } + if(offsetmap.isEmpty()){ + System.out.println("No offset matching needed."); + return null; + } + // replace with 0xff[webcolor] and others + webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); + // System.out.println("-> " + found); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + } + + colorMatcher = colorPattern.matcher(sourceAlt); + sourceAlt = colorMatcher.replaceAll("int"); + + System.out.println(sourceAlt); + + // Create code map. Beware! Dark magic ahead. + int javaCodeMap[] = new int[source.length() * 2]; + int pdeCodeMap[] = new int[source.length() * 2]; + int pi = 1, pj = 1; + int keySum = 0; + for (Integer key : offsetmap.keySet()) { + for (; pi < key +keySum; pi++) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + } + for (; pj < key; pj++) { + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + } + + System.out.println(key + ":" + offsetmap.get(key)); + + int kval = offsetmap.get(key); + if (kval > 0) { + // repeat java offsets + pi--; + pj--; + for (int i = 0; i < kval; i++, pi++, pj++) { + javaCodeMap[pi] = javaCodeMap[pi - 1]; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + } + } else { + // repeat pde offsets + pi--; + pj--; + for (int i = 0; i < -kval; i++, pi++, pj++) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1]; + } + } + + // after each adjustment, the key values need to keep + // up with changed offset + keySum += kval; + } + + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + + while (pi < sourceAlt.length()) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pi++; + } + while (pj < source.length()) { + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + pj++; + } + + // deubg o/p + for (int i = 0; i < pdeCodeMap.length; i++) { + if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { + if (i < source.length()) + System.out.print(source.charAt(i)); + System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]); + if (i < sourceAlt.length()) + System.out.print(sourceAlt.charAt(i)); + System.out.print(" <-[" + i + "]"); + System.out.println(); + } + } + System.out.println(); + + return new int[][]{javaCodeMap,pdeCodeMap}; + } + + public int[][] getOffsetMapping(ErrorCheckerService ecs){ + int pdeoffsets[] = getPDECodeOffsets(ecs); + String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); + return getOffsetMapping(pdeCode); + } + + /** + * + * @param ecs + * - ErrorCheckerService instance + * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] + * - line start offset, int[3] - offset from line start int[2] and + * int[3] are on TODO + */ + public int[] getPDECodeOffsets(ErrorCheckerService ecs) { + return ecs.JavaToPdeOffsets(lineNumber + 1, Node.getStartPosition()); + } + + public String toString() { + return label; + } + + public ASTNode getNode() { + return Node; + } + + public String getLabel() { + return label; + } + + public int getNodeType() { + return Node.getNodeType(); + } + + public int getLineNumber() { + return lineNumber; + } + + private static int getLineNumber(ASTNode node) { + return ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + } + + static private String getNodeAsString(ASTNode node) { + if (node == null) + return "NULL"; + String className = node.getClass().getName(); + int index = className.lastIndexOf("."); + if (index > 0) + className = className.substring(index + 1); + + // if(node instanceof BodyDeclaration) + // return className; + + String value = className; + + if (node instanceof TypeDeclaration) + value = ((TypeDeclaration) node).getName().toString() + " | " + className; + else if (node instanceof MethodDeclaration) + value = ((MethodDeclaration) node).getName().toString() + " | " + + className; + else if (node instanceof MethodInvocation) + value = ((MethodInvocation) node).getName().toString() + " | " + + className; + else if (node instanceof FieldDeclaration) + value = ((FieldDeclaration) node).toString() + " FldDecl| "; + else if (node instanceof SingleVariableDeclaration) + value = ((SingleVariableDeclaration) node).getName() + " - " + + ((SingleVariableDeclaration) node).getType() + " | SVD "; + else if (node instanceof ExpressionStatement) + value = node.toString() + className; + else if (node instanceof SimpleName) + value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; + else if (node instanceof QualifiedName) + value = node.toString() + " | " + className; + else if (className.startsWith("Variable")) + value = node.toString() + " | " + className; + else if (className.endsWith("Type")) + value = node.toString() + " |" + className; + value += " [" + node.getStartPosition() + "," + + (node.getStartPosition() + node.getLength()) + "]"; + value += " Line: " + + ((CompilationUnit) node.getRoot()).getLineNumber(node + .getStartPosition()); + return value; + } +} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java b/pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java new file mode 100755 index 000000000..04b3fb111 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.Value; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Specialized {@link VariableNode} for representing single fields in an array. + * Overrides {@link #setValue} to properly change the value of the encapsulated + * array field. + * + * @author Martin Leopold + */ +public class ArrayFieldNode extends VariableNode { + + protected ArrayReference array; + protected int index; + + /** + * Construct an {@link ArrayFieldNode}. + * + * @param name the name + * @param type the type + * @param value the value + * @param array a reference to the array + * @param index the index inside the array + */ + public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) { + super(name, type, value); + this.array = array; + this.index = index; + } + + @Override + public void setValue(Value value) { + try { + array.setValue(index, value); + } catch (InvalidTypeException ex) { + Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotLoadedException ex) { + Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); + } + this.value = value; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java b/pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java new file mode 100755 index 000000000..64bd5516b --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.ReferenceType; + +/** + * Listener to be notified when a class is loaded in the debugger. Used by + * {@link LineBreakpoint}s to activate themselves as soon as the respective + * class is loaded. + * + * @author Martin Leopold + */ +public interface ClassLoadListener { + + /** + * Event handler called when a class is loaded. + * + * @param theClass the class + */ + public void classLoaded(ReferenceType theClass); +} diff --git a/pdex/experimental/src/processing/mode/experimental/Compiler.java b/pdex/experimental/src/processing/mode/experimental/Compiler.java new file mode 100755 index 000000000..1a85c6a29 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/Compiler.java @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.io.*; +import java.lang.reflect.Method; +import processing.app.Base; +import processing.app.SketchException; +import processing.core.PApplet; + +/** + * Copied from processing.mode.java.Compiler, just added -g switch to generate + * debugging info. + * + * @author Martin Leopold + */ +public class Compiler extends processing.mode.java.Compiler { + /** + * Compile with ECJ. See http://j.mp/8paifz for documentation. + * + * @return true if successful. + * @throws RunnerException Only if there's a problem. Only then. + */ +// public boolean compile(Sketch sketch, +// File srcFolder, +// File binFolder, +// String primaryClassName, +// String sketchClassPath, +// String bootClassPath) throws RunnerException { + static public boolean compile(DebugBuild build) throws SketchException { + + // This will be filled in if anyone gets angry + SketchException exception = null; + boolean success = false; + + String baseCommand[] = new String[] { + "-g", + "-Xemacs", + //"-noExit", // not necessary for ecj + "-source", "1.6", + "-target", "1.6", + "-classpath", build.getClassPath(), + "-nowarn", // we're not currently interested in warnings (works in ecj) + "-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath + }; + //PApplet.println(baseCommand); + + // make list of code files that need to be compiled +// String[] sourceFiles = new String[sketch.getCodeCount()]; +// int sourceCount = 0; +// sourceFiles[sourceCount++] = +// new File(buildPath, primaryClassName + ".java").getAbsolutePath(); +// +// for (SketchCode code : sketch.getCode()) { +// if (code.isExtension("java")) { +// String path = new File(buildPath, code.getFileName()).getAbsolutePath(); +// sourceFiles[sourceCount++] = path; +// } +// } + String[] sourceFiles = Base.listFiles(build.getSrcFolder(), false, ".java"); + +// String[] command = new String[baseCommand.length + sourceFiles.length]; +// System.arraycopy(baseCommand, 0, command, 0, baseCommand.length); +// // append each of the files to the command string +// System.arraycopy(sourceFiles, 0, command, baseCommand.length, sourceCount); + String[] command = PApplet.concat(baseCommand, sourceFiles); + + //PApplet.println(command); + + try { + // Load errors into a local StringBuffer + final StringBuffer errorBuffer = new StringBuffer(); + + // Create single method dummy writer class to slurp errors from ecj + Writer internalWriter = new Writer() { + public void write(char[] buf, int off, int len) { + errorBuffer.append(buf, off, len); + } + + public void flush() { } + + public void close() { } + }; + // Wrap as a PrintWriter since that's what compile() wants + PrintWriter writer = new PrintWriter(internalWriter); + + //result = com.sun.tools.javac.Main.compile(command, writer); + + PrintWriter outWriter = new PrintWriter(System.out); + + // Version that's not dynamically loaded + //CompilationProgress progress = null; + //success = BatchCompiler.compile(command, outWriter, writer, progress); + + // Version that *is* dynamically loaded. First gets the mode class loader + // so that it can grab the compiler JAR files from it. + ClassLoader loader = build.getMode().getJavaModeClassLoader(); + //ClassLoader loader = build.getMode().getClassLoader(); + try { + Class batchClass = + Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader); + Class progressClass = + Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader); + Class[] compileArgs = + new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass }; + Method compileMethod = batchClass.getMethod("compile", compileArgs); + success = (Boolean) + compileMethod.invoke(null, new Object[] { command, outWriter, writer, null }); + } catch (Exception e) { + e.printStackTrace(); + throw new SketchException("Unknown error inside the compiler."); + } + + // Close out the stream for good measure + writer.flush(); + writer.close(); + + BufferedReader reader = + new BufferedReader(new StringReader(errorBuffer.toString())); + //System.err.println(errorBuffer.toString()); + + String line = null; + while ((line = reader.readLine()) != null) { + //System.out.println("got line " + line); // debug + + // get first line, which contains file name, line number, + // and at least the first line of the error message + String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*"; + String[] pieces = PApplet.match(line, errorFormat); + //PApplet.println(pieces); + + // if it's something unexpected, die and print the mess to the console + if (pieces == null) { + exception = new SketchException("Cannot parse error text: " + line); + exception.hideStackTrace(); + // Send out the rest of the error message to the console. + System.err.println(line); + while ((line = reader.readLine()) != null) { + System.err.println(line); + } + break; + } + + // translate the java filename and line number into a un-preprocessed + // location inside a source file or tab in the environment. + String dotJavaFilename = pieces[1]; + // Line numbers are 1-indexed from javac + int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1; + String errorMessage = pieces[4]; + + exception = build.placeException(errorMessage, + dotJavaFilename, + dotJavaLineIndex); + /* + int codeIndex = 0; //-1; + int codeLine = -1; + + // first check to see if it's a .java file + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode code = sketch.getCode(i); + if (code.isExtension("java")) { + if (dotJavaFilename.equals(code.getFileName())) { + codeIndex = i; + codeLine = dotJavaLineIndex; + } + } + } + + // if it's not a .java file, codeIndex will still be 0 + if (codeIndex == 0) { // main class, figure out which tab + //for (int i = 1; i < sketch.getCodeCount(); i++) { + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode code = sketch.getCode(i); + + if (code.isExtension("pde")) { + if (code.getPreprocOffset() <= dotJavaLineIndex) { + codeIndex = i; + //System.out.println("i'm thinkin file " + i); + codeLine = dotJavaLineIndex - code.getPreprocOffset(); + } + } + } + } + //System.out.println("code line now " + codeLine); + exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false); + */ + + if (exception == null) { + exception = new SketchException(errorMessage); + } + + // for a test case once message parsing is implemented, + // use new Font(...) since that wasn't getting picked up properly. + + /* + if (errorMessage.equals("cannot find symbol")) { + handleCannotFindSymbol(reader, exception); + + } else if (errorMessage.indexOf("is already defined") != -1) { + reader.readLine(); // repeats the line of code w/ error + int codeColumn = caretColumn(reader.readLine()); + exception = new RunnerException(errorMessage, + codeIndex, codeLine, codeColumn); + + } else if (errorMessage.startsWith("package") && + errorMessage.endsWith("does not exist")) { + // Because imports are stripped out and re-added to the 0th line of + // the preprocessed code, codeLine will always be wrong for imports. + exception = new RunnerException("P" + errorMessage.substring(1) + + ". You might be missing a library."); + } else { + exception = new RunnerException(errorMessage); + } + */ + if (errorMessage.startsWith("The import ") && + errorMessage.endsWith("cannot be resolved")) { + // The import poo cannot be resolved + //import poo.shoe.blah.*; + //String what = errorMessage.substring("The import ".length()); + String[] m = PApplet.match(errorMessage, "The import (.*) cannot be resolved"); + //what = what.substring(0, what.indexOf(' ')); + if (m != null) { +// System.out.println("'" + m[1] + "'"); + if (m[1].equals("processing.xml")) { + exception.setMessage("processing.xml no longer exists, this code needs to be updated for 2.0."); + System.err.println("The processing.xml library has been replaced " + + "with a new 'XML' class that's built-in."); + handleCrustyCode(); + + } else { + exception.setMessage("The package " + + "\u201C" + m[1] + "\u201D" + + " does not exist. " + + "You might be missing a library."); + System.err.println("Libraries must be " + + "installed in a folder named 'libraries' " + + "inside the 'sketchbook' folder."); + } + } + +// // Actually create the folder and open it for the user +// File sketchbookLibraries = Base.getSketchbookLibrariesFolder(); +// if (!sketchbookLibraries.exists()) { +// if (sketchbookLibraries.mkdirs()) { +// Base.openFolder(sketchbookLibraries); +// } +// } + + } else if (errorMessage.endsWith("cannot be resolved to a type")) { + // xxx cannot be resolved to a type + //xxx c; + + String what = errorMessage.substring(0, errorMessage.indexOf(' ')); + + if (what.equals("BFont") || + what.equals("BGraphics") || + what.equals("BImage")) { + exception.setMessage(what + " has been replaced with P" + what.substring(1)); + handleCrustyCode(); + + } else { + exception.setMessage("Cannot find a class or type " + + "named \u201C" + what + "\u201D"); + } + + } else if (errorMessage.endsWith("cannot be resolved")) { + // xxx cannot be resolved + //println(xxx); + + String what = errorMessage.substring(0, errorMessage.indexOf(' ')); + + if (what.equals("LINE_LOOP") || + what.equals("LINE_STRIP")) { + exception.setMessage("LINE_LOOP and LINE_STRIP are not available, " + + "please update your code."); + handleCrustyCode(); + + } else if (what.equals("framerate")) { + exception.setMessage("framerate should be changed to frameRate."); + handleCrustyCode(); + + } else if (what.equals("screen")) { + exception.setMessage("Change screen.width and screen.height to " + + "displayWidth and displayHeight."); + handleCrustyCode(); + + } else if (what.equals("screenWidth") || + what.equals("screenHeight")) { + exception.setMessage("Change screenWidth and screenHeight to " + + "displayWidth and displayHeight."); + handleCrustyCode(); + + } else { + exception.setMessage("Cannot find anything " + + "named \u201C" + what + "\u201D"); + } + + } else if (errorMessage.startsWith("Duplicate")) { + // "Duplicate nested type xxx" + // "Duplicate local variable xxx" + + } else { + String[] parts = null; + + // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX + //xxx("blah"); + // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX + //xxx("blah", 34); + // The method xxx(String, int) is undefined for the type PApplet + //PApplet.sub("ding"); + String undefined = + "The method (\\S+\\(.*\\)) is undefined for the type (.*)"; + parts = PApplet.match(errorMessage, undefined); + if (parts != null) { + if (parts[1].equals("framerate(int)")) { + exception.setMessage("framerate() no longer exists, use frameRate() instead."); + handleCrustyCode(); + + } else if (parts[1].equals("push()")) { + exception.setMessage("push() no longer exists, use pushMatrix() instead."); + handleCrustyCode(); + + } else if (parts[1].equals("pop()")) { + exception.setMessage("pop() no longer exists, use popMatrix() instead."); + handleCrustyCode(); + + } else { + String mess = "The function " + parts[1] + " does not exist."; + exception.setMessage(mess); + } + break; + } + } + if (exception != null) { + // The stack trace just shows that this happened inside the compiler, + // which is a red herring. Don't ever show it for compiler stuff. + exception.hideStackTrace(); + break; + } + } + } catch (IOException e) { + String bigSigh = "Error while compiling. (" + e.getMessage() + ")"; + exception = new SketchException(bigSigh); + e.printStackTrace(); + success = false; + } + // In case there was something else. + if (exception != null) throw exception; + + return success; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java b/pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java new file mode 100644 index 000000000..4ff73400f --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java @@ -0,0 +1,130 @@ +package processing.mode.experimental; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.MethodDeclaration; + +public class CompletionCandidate implements Comparable{ + + private String definingClass; + + private String elementName; // + + private String label; // the toString value + + private String completionString; + + private int type; + + public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3; + + public CompletionCandidate(String name, String className, String label, + int TYPE) { + definingClass = className; + elementName = name; + if (label.length() > 0) + this.label = label; + else + this.label = name; + this.type = TYPE; + if (type == METHOD) { + this.label += "()"; + } + completionString = this.label; + } + + public CompletionCandidate(Method method) { + definingClass = method.getDeclaringClass().getName(); + elementName = method.getName(); + type = METHOD; + StringBuffer label = new StringBuffer(method.getName() + "("); + StringBuffer cstr = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) { + label.append(","); + cstr.append(","); + } + } + + label.append(")"); + cstr.append(")"); + this.label = label.toString(); + this.completionString = cstr.toString(); + } + + public CompletionCandidate(MethodDeclaration method) { + definingClass = ""; + elementName = method.getName().toString(); + type = METHOD; + List params = (List) method + .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); + StringBuffer label = new StringBuffer(elementName + "("); + StringBuffer cstr = new StringBuffer(method.getName() + "("); + for (int i = 0; i < params.size(); i++) { + label.append(params.get(i).toString()); + if (i < params.size() - 1){ + label.append(","); + cstr.append(","); + } + } + label.append(")"); + cstr.append(")"); + this.label = label.toString(); + this.completionString = cstr.toString(); + } + + public CompletionCandidate(Field f) { + definingClass = f.getDeclaringClass().getName(); + elementName = f.getName(); + type = FIELD; + label = f.getName(); + completionString = elementName; + } + + public CompletionCandidate(String name, String className) { + definingClass = className; + elementName = name; + label = name; + completionString = name; + } + + public CompletionCandidate(String name) { + definingClass = ""; + elementName = name; + label = name; + completionString = name; + } + + public String getDefiningClass() { + return definingClass; + } + + public String getElementName() { + return elementName; + } + + public String getCompletionString() { + return completionString; + } + + public String toString() { + return label; + } + + public int getType() { + return type; + } + + public int compareTo(CompletionCandidate cc) { + if(type != cc.getType()){ + return cc.getType() - type; + } + + return (elementName.compareTo(cc.getElementName())); + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/CompletionPanel.java b/pdex/experimental/src/processing/mode/experimental/CompletionPanel.java new file mode 100644 index 000000000..3e0f7678d --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/CompletionPanel.java @@ -0,0 +1,153 @@ +package processing.mode.experimental; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; +import javax.swing.text.BadLocationException; + +import processing.app.syntax.JEditTextArea; + +public class CompletionPanel { + private JList list; + + private JPopupMenu popupMenu; + + private String subWord; + + private final int insertionPosition; + + private TextArea textarea; + + private JScrollPane scrollPane; + + public CompletionPanel(JEditTextArea textarea, int position, String subWord, + CompletionCandidate[] items, Point location) { + this.textarea = (TextArea) textarea; + this.insertionPosition = position; + if (subWord.indexOf('.') != -1) + this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); + else + this.subWord = subWord; + popupMenu = new JPopupMenu(); + popupMenu.removeAll(); + popupMenu.setOpaque(false); + popupMenu.setBorder(null); + scrollPane = new JScrollPane(); + scrollPane.setViewportView(list = createSuggestionList(position, items)); + popupMenu.add(scrollPane, BorderLayout.CENTER); + this.textarea.errorCheckerService.astGenerator + .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + + location.y); + + } + + public void hide() { + popupMenu.setVisible(false); + } + + public boolean isVisible() { + return popupMenu.isVisible(); + } + + public JList createSuggestionList(final int position, + final CompletionCandidate[] items) { + + JList list = new JList(items); + list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + list.setSelectedIndex(0); + list.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + insertSelection(); + hideSuggestion(); + } + } + }); + return list; + } + + public boolean insertSelection() { + if (list.getSelectedValue() != null) { + try { + final String selectedSuggestion = ((CompletionCandidate) list + .getSelectedValue()).getCompletionString().substring(subWord.length()); + textarea.getDocument().insertString(insertionPosition, + selectedSuggestion, null); + textarea.setCaretPosition(insertionPosition + + selectedSuggestion.length()); + return true; + } catch (BadLocationException e1) { + e1.printStackTrace(); + } + hideSuggestion(); + } + return false; + } + + public void hideSuggestion() { + hide(); + //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); + } + + public void moveUp() { + if (list.getSelectedIndex() == 0) { + scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); + selectIndex(list.getModel().getSize() - 1); + return; + } else { + int index = Math.max(list.getSelectedIndex() - 1, 0); + selectIndex(index); + } + int step = scrollPane.getVerticalScrollBar().getMaximum() + / list.getModel().getSize(); + scrollPane.getVerticalScrollBar().setValue(scrollPane + .getVerticalScrollBar() + .getValue() + - step); + textarea.errorCheckerService.astGenerator + .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + + } + + public void moveDown() { + if (list.getSelectedIndex() == list.getModel().getSize() - 1) { + scrollPane.getVerticalScrollBar().setValue(0); + selectIndex(0); + return; + } else { + int index = Math.min(list.getSelectedIndex() + 1, list.getModel() + .getSize() - 1); + selectIndex(index); + } + textarea.errorCheckerService.astGenerator + .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + int step = scrollPane.getVerticalScrollBar().getMaximum() + / list.getModel().getSize(); + scrollPane.getVerticalScrollBar().setValue(scrollPane + .getVerticalScrollBar() + .getValue() + + step); + } + + private void selectIndex(int index) { + list.setSelectedIndex(index); +// final int position = textarea.getCaretPosition(); +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// textarea.setCaretPosition(position); +// }; +// }); + } +} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/DebugBuild.java b/pdex/experimental/src/processing/mode/experimental/DebugBuild.java new file mode 100755 index 000000000..fdb9b34e3 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/DebugBuild.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.io.File; +import processing.app.Sketch; +import processing.app.SketchException; +import processing.mode.java.JavaBuild; + +/** + * Copied from processing.mode.java.JavaBuild, just changed compiler. + * + * @author Martin Leopold + */ +public class DebugBuild extends JavaBuild { + + public DebugBuild(Sketch sketch) { + super(sketch); + } + + /** + * Preprocess and compile sketch. Copied from + * processing.mode.java.JavaBuild, just changed compiler. + * + * @param srcFolder + * @param binFolder + * @param sizeWarning + * @return main class name or null on compile failure + * @throws SketchException + */ + @Override + public String build(File srcFolder, File binFolder, boolean sizeWarning) throws SketchException { + this.srcFolder = srcFolder; + this.binFolder = binFolder; + +// Base.openFolder(srcFolder); +// Base.openFolder(binFolder); + + // run the preprocessor + String classNameFound = preprocess(srcFolder, sizeWarning); + + // compile the program. errors will happen as a RunnerException + // that will bubble up to whomever called build(). +// Compiler compiler = new Compiler(this); +// String bootClasses = System.getProperty("sun.boot.class.path"); +// if (compiler.compile(this, srcFolder, binFolder, primaryClassName, getClassPath(), bootClasses)) { + + if (Compiler.compile(this)) { // use compiler with debug info enabled (-g switch flicked) + sketchClassName = classNameFound; + return classNameFound; + } + return null; + } + + public ExperimentalMode getMode() { + return (ExperimentalMode)mode; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/DebugEditor.java b/pdex/experimental/src/processing/mode/experimental/DebugEditor.java new file mode 100755 index 000000000..099e90d1a --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/DebugEditor.java @@ -0,0 +1,1165 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.Box; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.border.EtchedBorder; +import javax.swing.table.TableModel; +import javax.swing.text.Document; +import processing.app.*; +import processing.app.syntax.JEditTextArea; +import processing.app.syntax.PdeTextAreaDefaults; +import processing.core.PApplet; +import processing.mode.java.JavaEditor; + +/** + * Main View Class. Handles the editor window including tool bar and menu. Has + * access to the Sketch. Provides line highlighting (for breakpoints and the + * debuggers current line). + * + * @author Martin Leopold + * @author Manindra Moharana <me@mkmoharana.com> + * + * + */ +public class DebugEditor extends JavaEditor implements ActionListener { + // important fields from superclass + //protected Sketch sketch; + //private JMenu fileMenu; + //protected EditorToolbar toolbar; + + // highlighting + protected Color breakpointColor = new Color(240, 240, 240); // the background color for highlighting lines + protected Color currentLineColor = new Color(255, 255, 150); // the background color for highlighting lines + protected Color breakpointMarkerColor = new Color(74, 84, 94); // the color of breakpoint gutter markers + protected Color currentLineMarkerColor = new Color(226, 117, 0); // the color of current line gutter markers + protected List breakpointedLines = new ArrayList(); // breakpointed lines + protected LineHighlight currentLine; // line the debugger is currently suspended at + protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment + // menus + protected JMenu debugMenu; // the debug menu + // debugger control + protected JMenuItem debugMenuItem; + protected JMenuItem continueMenuItem; + protected JMenuItem stopMenuItem; + // breakpoints + protected JMenuItem toggleBreakpointMenuItem; + protected JMenuItem listBreakpointsMenuItem; + // stepping + protected JMenuItem stepOverMenuItem; + protected JMenuItem stepIntoMenuItem; + protected JMenuItem stepOutMenuItem; + // info + protected JMenuItem printStackTraceMenuItem; + protected JMenuItem printLocalsMenuItem; + protected JMenuItem printThisMenuItem; + protected JMenuItem printSourceMenuItem; + protected JMenuItem printThreads; + // variable inspector + protected JMenuItem toggleVariableInspectorMenuItem; + // references + protected ExperimentalMode dmode; // the mode + protected Debugger dbg; // the debugger + protected VariableInspector vi; // the variable inspector frame + protected TextArea ta; // the text area + + + protected ErrorBar errorBar; + /** + * Show Console button + */ + protected XQConsoleToggle btnShowConsole; + + /** + * Show Problems button + */ + protected XQConsoleToggle btnShowErrors; + + /** + * Scroll pane for Error Table + */ + protected JScrollPane errorTableScrollPane; + + /** + * Panel with card layout which contains the p5 console and Error Table + * panes + */ + protected JPanel consoleProblemsPane; + + protected XQErrorTable errorTable; + + /** + * Enable/Disable compilation checking + */ + protected boolean compilationCheckEnabled = true; + + /** + * Show warnings menu item + */ + protected JCheckBoxMenuItem showWarnings; + + /** + * Check box menu item for show/hide Problem Window + */ + public JCheckBoxMenuItem problemWindowMenuCB; + + public DebugEditor(Base base, String path, EditorState state, Mode mode) { + super(base, path, state, mode); + + // get mode + dmode = (ExperimentalMode) mode; + + // init controller class + dbg = new Debugger(this); + + // variable inspector window + vi = new VariableInspector(this); + + // access to customized (i.e. subclassed) text area + ta = (TextArea) textarea; + + // add refactor option + JMenuItem renameItem = new JMenuItem("Rename.."); + renameItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleRefactor(); + } + }); + // TODO: Add support for word select on right click and rename. +// ta.customPainter.addMouseListener(new MouseAdapter() { +// public void mouseClicked(MouseEvent evt) { +// System.out.println(evt); +// } +// }); + ta.getRightClickPopup().add(renameItem); + // set action on frame close +// addWindowListener(new WindowAdapter() { +// @Override +// public void windowClosing(WindowEvent e) { +// onWindowClosing(e); +// } +// }); + + // load settings from theme.txt + ExperimentalMode theme = dmode; + breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor); + breakpointMarkerColor = theme.getThemeColor("breakpoint.marker.color", breakpointMarkerColor); + currentLineColor = theme.getThemeColor("currentline.bgcolor", currentLineColor); + currentLineMarkerColor = theme.getThemeColor("currentline.marker.color", currentLineMarkerColor); + + // set breakpoints from marker comments + for (LineID lineID : stripBreakpointComments()) { + //System.out.println("setting: " + lineID); + dbg.setBreakpoint(lineID); + } + getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here + + checkForJavaTabs(); + initializeErrorChecker(); + ta.setECSandThemeforTextArea(errorCheckerService, dmode); + addXQModeUI(); + //TODO: Remove this later + setBounds(160, 300, getWidth(), getHeight()); + } + + private void addXQModeUI(){ + + // Adding ErrorBar + JPanel textAndError = new JPanel(); + Box box = (Box) textarea.getParent(); + box.remove(2); // Remove textArea from it's container, i.e Box + textAndError.setLayout(new BorderLayout()); + errorBar = new ErrorBar(this, textarea.getMinimumSize().height, dmode); + textAndError.add(errorBar, BorderLayout.EAST); + textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight()); + textAndError.add(textarea); + box.add(textAndError); + + // Adding Error Table in a scroll pane + errorTableScrollPane = new JScrollPane(); + errorTable = new XQErrorTable(errorCheckerService); + // errorTableScrollPane.setBorder(new EmptyBorder(2, 2, 2, 2)); + errorTableScrollPane.setBorder(new EtchedBorder()); + errorTableScrollPane.setViewportView(errorTable); + + // Adding toggle console button + consolePanel.remove(2); + JPanel lineStatusPanel = new JPanel(); + lineStatusPanel.setLayout(new BorderLayout()); + btnShowConsole = new XQConsoleToggle(this, + XQConsoleToggle.text[0], lineStatus.getHeight()); + btnShowErrors = new XQConsoleToggle(this, + XQConsoleToggle.text[1], lineStatus.getHeight()); + btnShowConsole.addMouseListener(btnShowConsole); + + // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST); + // lineStatusPanel.add(btnShowErrors); + btnShowErrors.addMouseListener(btnShowErrors); + + JPanel toggleButtonPanel = new JPanel(new BorderLayout()); + toggleButtonPanel.add(btnShowConsole, BorderLayout.EAST); + toggleButtonPanel.add(btnShowErrors, BorderLayout.WEST); + lineStatusPanel.add(toggleButtonPanel, BorderLayout.EAST); + lineStatus.setBounds(0, 0, toggleButtonPanel.getX() - 1, + toggleButtonPanel.getHeight()); + lineStatusPanel.add(lineStatus); + consolePanel.add(lineStatusPanel, BorderLayout.SOUTH); + lineStatusPanel.repaint(); + + // Adding JPanel with CardLayout for Console/Problems Toggle + consolePanel.remove(1); + consoleProblemsPane = new JPanel(new CardLayout()); + consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.text[1]); + consoleProblemsPane.add(console, XQConsoleToggle.text[0]); + consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); + } + +// /** +// * Event handler called when closing the editor window. Kills the variable +// * inspector window. +// * +// * @param e the event object +// */ +// protected void onWindowClosing(WindowEvent e) { +// // remove var.inspector +// vi.dispose(); +// // quit running debug session +// dbg.stopDebug(); +// } + /** + * Used instead of the windowClosing event handler, since it's not called on + * mode switch. Called when closing the editor window. Stops running debug + * sessions and kills the variable inspector window. + */ + @Override + public void dispose() { + //System.out.println("window dispose"); + // quit running debug session + dbg.stopDebug(); + // remove var.inspector + vi.dispose(); + // original dispose + super.dispose(); + } + + /** + * Overrides sketch menu creation to change keyboard shortcuts from "Run". + * + * @return the sketch menu + */ + @Override + public JMenu buildSketchMenu() { + JMenuItem runItem = Toolkit.newJMenuItemShift(DebugToolbar.getTitle(DebugToolbar.RUN, false), KeyEvent.VK_R); + runItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleRun(); + } + }); + + JMenuItem presentItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.RUN, true)); + presentItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handlePresent(); + } + }); + + JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, false)); + stopItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleStop(); + } + }); + return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); + } + + /** + * Creates the debug menu. Includes ActionListeners for the menu items. + * Intended for adding to the menu bar. + * + * @return The debug menu + */ + protected JMenu buildDebugMenu() { + debugMenu = new JMenu("Debug"); + + debugMenuItem = Toolkit.newJMenuItem("Debug", KeyEvent.VK_R); + debugMenuItem.addActionListener(this); + continueMenuItem = Toolkit.newJMenuItem("Continue", KeyEvent.VK_U); + continueMenuItem.addActionListener(this); + stopMenuItem = new JMenuItem("Stop"); + stopMenuItem.addActionListener(this); + + toggleBreakpointMenuItem = Toolkit.newJMenuItem("Toggle Breakpoint", KeyEvent.VK_B); + toggleBreakpointMenuItem.addActionListener(this); + listBreakpointsMenuItem = new JMenuItem("List Breakpoints"); + listBreakpointsMenuItem.addActionListener(this); + + stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_J); + stepOverMenuItem.addActionListener(this); + stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_J); + stepIntoMenuItem.addActionListener(this); + stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_J); + stepOutMenuItem.addActionListener(this); + + printStackTraceMenuItem = new JMenuItem("Print Stack Trace"); + printStackTraceMenuItem.addActionListener(this); + printLocalsMenuItem = new JMenuItem("Print Locals"); + printLocalsMenuItem.addActionListener(this); + printThisMenuItem = new JMenuItem("Print Fields"); + printThisMenuItem.addActionListener(this); + printSourceMenuItem = new JMenuItem("Print Source Location"); + printSourceMenuItem.addActionListener(this); + printThreads = new JMenuItem("Print Threads"); + printThreads.addActionListener(this); + + toggleVariableInspectorMenuItem = Toolkit.newJMenuItem("Toggle Variable Inspector", KeyEvent.VK_I); + toggleVariableInspectorMenuItem.addActionListener(this); + + debugMenu.add(debugMenuItem); + debugMenu.add(continueMenuItem); + debugMenu.add(stopMenuItem); + debugMenu.addSeparator(); + debugMenu.add(toggleBreakpointMenuItem); + debugMenu.add(listBreakpointsMenuItem); + debugMenu.addSeparator(); + debugMenu.add(stepOverMenuItem); + debugMenu.add(stepIntoMenuItem); + debugMenu.add(stepOutMenuItem); + debugMenu.addSeparator(); + debugMenu.add(printStackTraceMenuItem); + debugMenu.add(printLocalsMenuItem); + debugMenu.add(printThisMenuItem); + debugMenu.add(printSourceMenuItem); + debugMenu.add(printThreads); + debugMenu.addSeparator(); + debugMenu.add(toggleVariableInspectorMenuItem); + debugMenu.addSeparator(); + + // XQMode menu items + + JCheckBoxMenuItem item; + final DebugEditor thisEditor = this; + item = new JCheckBoxMenuItem("Error Checker Enabled"); + item.setSelected(true); + item.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { + // unticked Menu Item + errorCheckerService.pauseThread(); + System.out.println(thisEditor.getSketch().getName() + + " - Error Checker paused."); + errorBar.errorPoints.clear(); + errorCheckerService.problemsList.clear(); + errorCheckerService.updateErrorTable(); + errorCheckerService.updateEditorStatus(); + getTextArea().repaint(); + errorBar.repaint(); + } else { + errorCheckerService.resumeThread(); + System.out.println(thisEditor.getSketch().getName() + + " - Error Checker resumed."); + } + } + }); + debugMenu.add(item); + + problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); + // problemWindowMenuCB.setSelected(true); + problemWindowMenuCB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (errorCheckerService.errorWindow == null) { + return; + } + errorCheckerService.errorWindow + .setVisible(((JCheckBoxMenuItem) e.getSource()) + .isSelected()); + // switch to console, now that Error Window is open + toggleView(XQConsoleToggle.text[0]); + } + }); + debugMenu.add(problemWindowMenuCB); + + showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); + showWarnings.setSelected(true); + showWarnings.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + } + }); + debugMenu.add(showWarnings); + + + return debugMenu; + } + + @Override + public JMenu buildModeMenu() { + return buildDebugMenu(); + } + + /** + * Callback for menu items. Implementation of Swing ActionListener. + * + * @param ae Action event + */ + @Override + public void actionPerformed(ActionEvent ae) { + //System.out.println("ActionEvent: " + ae.toString()); + + JMenuItem source = (JMenuItem) ae.getSource(); + if (source == debugMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item"); + //dmode.handleDebug(sketch, this); + dbg.startDebug(); + } else if (source == stopMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item"); + //dmode.handleDebug(sketch, this); + dbg.stopDebug(); + } else if (source == continueMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item"); + //dmode.handleDebug(sketch, this); + dbg.continueDebug(); + } else if (source == stepOverMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Over' menu item"); + dbg.stepOver(); + } else if (source == stepIntoMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Into' menu item"); + dbg.stepInto(); + } else if (source == stepOutMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Out' menu item"); + dbg.stepOut(); + } else if (source == printStackTraceMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item"); + dbg.printStackTrace(); + } else if (source == printLocalsMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item"); + dbg.printLocals(); + } else if (source == printThisMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item"); + dbg.printThis(); + } else if (source == printSourceMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item"); + dbg.printSource(); + } else if (source == printThreads) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item"); + dbg.printThreads(); + } else if (source == toggleBreakpointMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item"); + dbg.toggleBreakpoint(); + } else if (source == listBreakpointsMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item"); + dbg.listBreakpoints(); + } else if (source == toggleVariableInspectorMenuItem) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); + toggleVariableInspector(); + } + } + +// @Override +// public void handleRun() { +// dbg.continueDebug(); +// } + /** + * Event handler called when hitting the stop button. Stops a running debug + * session or performs standard stop action if not currently debugging. + */ + @Override + public void handleStop() { + if (dbg.isStarted()) { + dbg.stopDebug(); + } else { + super.handleStop(); + } + } + + /** + * Event handler called when loading another sketch in this editor. Clears + * breakpoints of previous sketch. + * + * @param path + * @return true if a sketch was opened, false if aborted + */ + @Override + protected boolean handleOpenInternal(String path) { + boolean didOpen = super.handleOpenInternal(path); + if (didOpen && dbg != null) { + // should already been stopped (open calls handleStop) + dbg.clearBreakpoints(); + clearBreakpointedLines(); // force clear breakpoint highlights + variableInspector().reset(); // clear contents of variable inspector + } + return didOpen; + } + + /** + * Extract breakpointed lines from source code marker comments. This removes + * marker comments from the editor text. Intended to be called on loading a + * sketch, since re-setting the sketches contents after removing the markers + * will clear all breakpoints. + * + * @return the list of {@link LineID}s where breakpoint marker comments were + * removed from. + */ + protected List stripBreakpointComments() { + List bps = new ArrayList(); + // iterate over all tabs + Sketch sketch = getSketch(); + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode tab = sketch.getCode(i); + String code = tab.getProgram(); + String lines[] = code.split("\\r?\\n"); // newlines not included + //System.out.println(code); + + // scan code for breakpoint comments + int lineIdx = 0; + for (String line : lines) { + //System.out.println(line); + if (line.endsWith(breakpointMarkerComment)) { + LineID lineID = new LineID(tab.getFileName(), lineIdx); + bps.add(lineID); + //System.out.println("found breakpoint: " + lineID); + // got a breakpoint + //dbg.setBreakpoint(lineID); + int index = line.lastIndexOf(breakpointMarkerComment); + lines[lineIdx] = line.substring(0, index); + } + lineIdx++; + } + //tab.setProgram(code); + code = PApplet.join(lines, "\n"); + setTabContents(tab.getFileName(), code); + } + return bps; + } + + /** + * Add breakpoint marker comments to the source file of a specific tab. This + * acts on the source file on disk, not the editor text. Intended to be + * called just after saving the sketch. + * + * @param tabFilename the tab file name + */ + protected void addBreakpointComments(String tabFilename) { + SketchCode tab = getTab(tabFilename); + List bps = dbg.getBreakpoints(tab.getFileName()); + + // load the source file + File sourceFile = new File(sketch.getFolder(), tab.getFileName()); + //System.out.println("file: " + sourceFile); + try { + String code = Base.loadFile(sourceFile); + //System.out.println("code: " + code); + String lines[] = code.split("\\r?\\n"); // newlines not included + for (LineBreakpoint bp : bps) { + //System.out.println("adding bp: " + bp.lineID()); + lines[bp.lineID().lineIdx()] += breakpointMarkerComment; + } + code = PApplet.join(lines, "\n"); + //System.out.println("new code: " + code); + Base.saveFile(code, sourceFile); + } catch (IOException ex) { + Logger.getLogger(DebugEditor.class.getName()).log(Level.SEVERE, null, ex); + } + } + + @Override + public boolean handleSave(boolean immediately) { + //System.out.println("handleSave " + immediately); + + // note modified tabs + final List modified = new ArrayList(); + for (int i = 0; i < getSketch().getCodeCount(); i++) { + SketchCode tab = getSketch().getCode(i); + if (tab.isModified()) { + modified.add(tab.getFileName()); + } + } + + boolean saved = super.handleSave(immediately); + if (saved) { + if (immediately) { + for (String tabFilename : modified) { + addBreakpointComments(tabFilename); + } + } else { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + for (String tabFilename : modified) { + addBreakpointComments(tabFilename); + } + } + }); + } + } + return saved; + } + + @Override + public boolean handleSaveAs() { + //System.out.println("handleSaveAs"); + String oldName = getSketch().getCode(0).getFileName(); + //System.out.println("old name: " + oldName); + boolean saved = super.handleSaveAs(); + if (saved) { + // re-set breakpoints in first tab (name has changed) + List bps = dbg.getBreakpoints(oldName); + dbg.clearBreakpoints(oldName); + String newName = getSketch().getCode(0).getFileName(); + //System.out.println("new name: " + newName); + for (LineBreakpoint bp : bps) { + LineID line = new LineID(newName, bp.lineID().lineIdx()); + //System.out.println("setting: " + line); + dbg.setBreakpoint(line); + } + // add breakpoint marker comments to source file + for (int i = 0; i < getSketch().getCodeCount(); i++) { + addBreakpointComments(getSketch().getCode(i).getFileName()); + } + + // set new name of variable inspector + vi.setTitle(getSketch().getName()); + } + return saved; + } + + /** + * Set text contents of a specific tab. Updates underlying document and text + * area. Clears Breakpoints. + * + * @param tabFilename the tab file name + * @param code the text to set + */ + protected void setTabContents(String tabFilename, String code) { + // remove all breakpoints of this tab + dbg.clearBreakpoints(tabFilename); + + SketchCode currentTab = getCurrentTab(); + + // set code of tab + SketchCode tab = getTab(tabFilename); + if (tab != null) { + tab.setProgram(code); + // this updates document and text area + // TODO: does this have any negative effects? (setting the doc to null) + tab.setDocument(null); + setCode(tab); + + // switch back to original tab + setCode(currentTab); + } + } + + /** + * Clear the console. + */ + public void clearConsole() { + console.clear(); + } + + /** + * Clear current text selection. + */ + public void clearSelection() { + setSelection(getCaretOffset(), getCaretOffset()); + } + + /** + * Select a line in the current tab. + * + * @param lineIdx 0-based line number + */ + public void selectLine(int lineIdx) { + setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx)); + } + + /** + * Set the cursor to the start of a line. + * + * @param lineIdx 0-based line number + */ + public void cursorToLineStart(int lineIdx) { + setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx)); + } + + /** + * Set the cursor to the end of a line. + * + * @param lineIdx 0-based line number + */ + public void cursorToLineEnd(int lineIdx) { + setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx)); + } + + /** + * Switch to a tab. + * + * @param tabFileName the file name identifying the tab. (as in + * {@link SketchCode#getFileName()}) + */ + public void switchToTab(String tabFileName) { + Sketch s = getSketch(); + for (int i = 0; i < s.getCodeCount(); i++) { + if (tabFileName.equals(s.getCode(i).getFileName())) { + s.setCurrentCode(i); + break; + } + } + } + + /** + * Access the debugger. + * + * @return the debugger controller object + */ + public Debugger dbg() { + return dbg; + } + + /** + * Access the mode. + * + * @return the mode object + */ + public ExperimentalMode mode() { + return dmode; + } + + /** + * Access the custom text area object. + * + * @return the text area object + */ + public TextArea textArea() { + return ta; + } + + /** + * Access variable inspector window. + * + * @return the variable inspector object + */ + public VariableInspector variableInspector() { + return vi; + } + + public DebugToolbar toolbar() { + return (DebugToolbar) toolbar; + } + + /** + * Show the variable inspector window. + */ + public void showVariableInspector() { + vi.setVisible(true); + } + + /** + * Set visibility of the variable inspector window. + * + * @param visible true to set the variable inspector visible, false for + * invisible. + */ + public void showVariableInspector(boolean visible) { + vi.setVisible(visible); + } + + /** + * Hide the variable inspector window. + */ + public void hideVariableInspector() { + vi.setVisible(true); + } + + /** + * Toggle visibility of the variable inspector window. + */ + public void toggleVariableInspector() { + vi.setFocusableWindowState(false); // to not get focus when set visible + vi.setVisible(!vi.isVisible()); + vi.setFocusableWindowState(true); // allow to get focus again + } + + /** + * Text area factory method. Instantiates the customized TextArea. + * + * @return the customized text area object + */ + @Override + protected JEditTextArea createTextArea() { + //System.out.println("overriding creation of text area"); + return new TextArea(new PdeTextAreaDefaults(mode), this); + } + + /** + * Set the line to highlight as currently suspended at. Will override the + * breakpoint color, if set. Switches to the appropriate tab and scroll to + * the line by placing the cursor there. + * + * @param line the line to highlight as current suspended line + */ + public void setCurrentLine(LineID line) { + clearCurrentLine(); + if (line == null) { + return; // safety, e.g. when no line mapping is found and the null line is used. + } + switchToTab(line.fileName()); + // scroll to line, by setting the cursor + cursorToLineStart(line.lineIdx()); + // highlight line + currentLine = new LineHighlight(line.lineIdx(), currentLineColor, this); + currentLine.setMarker(ta.currentLineMarker, currentLineMarkerColor); + currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down + } + + /** + * Clear the highlight for the debuggers current line. + */ + public void clearCurrentLine() { + if (currentLine != null) { + currentLine.clear(); + currentLine.dispose(); + + // revert to breakpoint color if any is set on this line + for (LineHighlight hl : breakpointedLines) { + if (hl.lineID().equals(currentLine.lineID())) { + hl.paint(); + break; + } + } + currentLine = null; + } + } + + /** + * Add highlight for a breakpointed line. + * + * @param lineID the line id to highlight as breakpointed + */ + public void addBreakpointedLine(LineID lineID) { + LineHighlight hl = new LineHighlight(lineID, breakpointColor, this); + hl.setMarker(ta.breakpointMarker, breakpointMarkerColor); + breakpointedLines.add(hl); + // repaint current line if it's on this line + if (currentLine != null && currentLine.lineID().equals(lineID)) { + currentLine.paint(); + } + } + + /** + * Add highlight for a breakpointed line on the current tab. + * + * @param lineIdx the line index on the current tab to highlight as + * breakpointed + */ + //TODO: remove and replace by {@link #addBreakpointedLine(LineID lineID)} + public void addBreakpointedLine(int lineIdx) { + addBreakpointedLine(getLineIDInCurrentTab(lineIdx)); + } + + /** + * Remove a highlight for a breakpointed line. Needs to be on the current + * tab. + * + * @param lineIdx the line index on the current tab to remove a breakpoint + * highlight from + */ + public void removeBreakpointedLine(int lineIdx) { + LineID line = getLineIDInCurrentTab(lineIdx); + //System.out.println("line id: " + line.fileName() + " " + line.lineIdx()); + LineHighlight foundLine = null; + for (LineHighlight hl : breakpointedLines) { + if (hl.lineID.equals(line)) { + foundLine = hl; + break; + } + } + if (foundLine != null) { + foundLine.clear(); + breakpointedLines.remove(foundLine); + foundLine.dispose(); + // repaint current line if it's on this line + if (currentLine != null && currentLine.lineID().equals(line)) { + currentLine.paint(); + } + } + } + + /** + * Remove all highlights for breakpointed lines. + */ + public void clearBreakpointedLines() { + for (LineHighlight hl : breakpointedLines) { + hl.clear(); + hl.dispose(); + } + breakpointedLines.clear(); // remove all breakpoints + // fix highlights not being removed when tab names have changed due to opening a new sketch in same editor + ta.clearLineBgColors(); // force clear all highlights + ta.clearGutterText(); + + // repaint current line + if (currentLine != null) { + currentLine.paint(); + } + } + + /** + * Retrieve a {@link LineID} object for a line on the current tab. + * + * @param lineIdx the line index on the current tab + * @return the {@link LineID} object representing a line index on the + * current tab + */ + public LineID getLineIDInCurrentTab(int lineIdx) { + return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx); + } + + /** + * Retrieve line of sketch where the cursor currently resides. + * + * @return the current {@link LineID} + */ + protected LineID getCurrentLineID() { + String tab = getSketch().getCurrentCode().getFileName(); + int lineNo = getTextArea().getCaretLine(); + return new LineID(tab, lineNo); + } + + /** + * Check whether a {@link LineID} is on the current tab. + * + * @param line the {@link LineID} + * @return true, if the {@link LineID} is on the current tab. + */ + public boolean isInCurrentTab(LineID line) { + return line.fileName().equals(getSketch().getCurrentCode().getFileName()); + } + + /** + * Event handler called when switching between tabs. Loads all line + * background colors set for the tab. + * + * @param code tab to switch to + */ + @Override + protected void setCode(SketchCode code) { + //System.out.println("tab switch: " + code.getFileName()); + super.setCode(code); // set the new document in the textarea, etc. need to do this first + + // set line background colors for tab + if (ta != null) { // can be null when setCode is called the first time (in constructor) + // clear all line backgrounds + ta.clearLineBgColors(); + // clear all gutter text + ta.clearGutterText(); + // load appropriate line backgrounds for tab + // first paint breakpoints + for (LineHighlight hl : breakpointedLines) { + if (isInCurrentTab(hl.lineID())) { + hl.paint(); + } + } + // now paint current line (if any) + if (currentLine != null) { + if (isInCurrentTab(currentLine.lineID())) { + currentLine.paint(); + } + } + } + if (dbg() != null && dbg().isStarted()) { + dbg().startTrackingLineChanges(); + } + } + + /** + * Get a tab by its file name. + * + * @param fileName the filename to search for. + * @return the {@link SketchCode} object representing the tab, or null if + * not found + */ + public SketchCode getTab(String fileName) { + Sketch s = getSketch(); + for (SketchCode c : s.getCode()) { + if (c.getFileName().equals(fileName)) { + return c; + } + } + return null; + } + + /** + * Retrieve the current tab. + * + * @return the {@link SketchCode} representing the current tab + */ + public SketchCode getCurrentTab() { + return getSketch().getCurrentCode(); + } + + /** + * Access the currently edited document. + * + * @return the document object + */ + public Document currentDocument() { + //return ta.getDocument(); + return getCurrentTab().getDocument(); + } + + /** + * Factory method for the editor toolbar. Instantiates the customized + * toolbar. + * + * @return the toolbar + */ + @Override + public EditorToolbar createToolbar() { + return new DebugToolbar(this, base); + } + + /** + * Event Handler for double clicking in the left hand gutter area. + * + * @param lineIdx the line (0-based) that was double clicked + */ + public void gutterDblClicked(int lineIdx) { + if (dbg != null) { + dbg.toggleBreakpoint(lineIdx); + } + } + + public void statusBusy() { + statusNotice("Debugger busy..."); + } + + public void statusHalted() { + statusNotice("Debugger halted."); + } + + ErrorCheckerService errorCheckerService; + + /** + * Initializes and starts Error Checker Service + */ + private void initializeErrorChecker() { + Thread errorCheckerThread = null; + + if (errorCheckerThread == null) { + errorCheckerService = new ErrorCheckerService(this); + errorCheckerThread = new Thread(errorCheckerService); + try { + errorCheckerThread.start(); + } catch (Exception e) { + System.err + .println("Error Checker Service not initialized [XQEditor]: " + + e); + // e.printStackTrace(); + } + // System.out.println("Error Checker Service initialized."); + } + + } + + /** + * Updates the error bar + * @param problems + */ + public void updateErrorBar(ArrayList problems) { + errorBar.updateErrorPoints(problems); + } + + /** + * Toggle between Console and Errors List + * + * @param buttonName + * - Button Label + */ + public void toggleView(String buttonName) { + CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); + cl.show(consoleProblemsPane, buttonName); + } + + /** + * Updates the error table + * @param tableModel + * @return + */ + synchronized public boolean updateTable(final TableModel tableModel) { + return errorTable.updateTable(tableModel); + } + + private void handleRefactor() { + System.out.println("Caret at:"); + System.out.println(ta.getLineText(ta.getCaretLine())); + errorCheckerService.astGenerator.handleRefactor(); + } + + /** + * Checks if the sketch contains java tabs. If it does, XQMode ain't built + * for it, yet. Also, user should really start looking at Eclipse. Disable + * compilation check. + */ + private void checkForJavaTabs() { + for (int i = 0; i < this.getSketch().getCodeCount(); i++) { + if (this.getSketch().getCode(i).getExtension().equals("java")) { + compilationCheckEnabled = false; + JOptionPane.showMessageDialog(new Frame(), this + .getSketch().getName() + + " contains .java tabs. Live compilation error checking isn't " + + "supported for java tabs. Only " + + "syntax errors will be reported for .pde tabs."); + break; + } + } + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/DebugRunner.java b/pdex/experimental/src/processing/mode/experimental/DebugRunner.java new file mode 100755 index 000000000..1f810d964 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/DebugRunner.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.VirtualMachine; +import processing.app.RunnerListener; +import processing.app.SketchException; +import processing.app.exec.StreamRedirectThread; +import processing.mode.java.JavaBuild; +import processing.mode.java.runner.MessageSiphon; + +/** + * Runs a {@link JavaBuild}. Launches the build in a new debuggee VM. + * + * @author Martin Leopold + */ +public class DebugRunner extends processing.mode.java.runner.Runner { + + // important inherited fields + // protected VirtualMachine vm; + public DebugRunner(JavaBuild build, RunnerListener listener) throws SketchException { + super(build, listener); + } + + /** + * Launch the virtual machine. Simple non-blocking launch. VM starts + * suspended. + * + * @return debuggee VM or null on failure + */ + public VirtualMachine launch() { +// String[] machineParamList = getMachineParams(); +// String[] sketchParamList = getSketchParams(false); +// /* +// * System.out.println("vm launch sketch params:"); for (int i=0; +// * i + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.util.logging.Level; +import java.util.logging.Logger; +import processing.app.Base; +import processing.app.Editor; +import processing.mode.java.JavaToolbar; + +/** + * Custom toolbar for the editor window. Preserves original button numbers + * ({@link JavaToolbar#RUN}, {@link JavaToolbar#STOP}, {@link JavaToolbar#NEW}, + * {@link JavaToolbar#OPEN}, {@link JavaToolbar#SAVE}, {@link JavaToolbar#EXPORT}) + * which can be used e.g. in {@link #activate} and + * {@link #deactivate}. + * + * @author Martin Leopold + */ +public class DebugToolbar extends JavaToolbar { + // preserve original button id's, but re-define so they are accessible + // (they are used by DebugEditor, so they want to be public) + + static protected final int RUN = 100; // change this, to be able to get it's name via getTitle() + static protected final int DEBUG = JavaToolbar.RUN; + + static protected final int CONTINUE = 101; + static protected final int STEP = 102; + static protected final int TOGGLE_BREAKPOINT = 103; + static protected final int TOGGLE_VAR_INSPECTOR = 104; + + static protected final int STOP = JavaToolbar.STOP; + + static protected final int NEW = JavaToolbar.NEW; + static protected final int OPEN = JavaToolbar.OPEN; + static protected final int SAVE = JavaToolbar.SAVE; + static protected final int EXPORT = JavaToolbar.EXPORT; + + + // the sequence of button ids. (this maps button position = index to button ids) + static protected final int[] buttonSequence = { + DEBUG, CONTINUE, STEP, STOP, TOGGLE_BREAKPOINT, TOGGLE_VAR_INSPECTOR, + NEW, OPEN, SAVE, EXPORT + }; + + + public DebugToolbar(Editor editor, Base base) { + super(editor, base); + } + + + /** + * Initialize buttons. Loads images and adds the buttons to the toolbar. + */ + @Override + public void init() { + Image[][] images = loadImages(); + for (int idx = 0; idx < buttonSequence.length; idx++) { + int id = buttonId(idx); + addButton(getTitle(id, false), getTitle(id, true), images[idx], id == NEW || id == TOGGLE_BREAKPOINT); + } + } + + + /** + * Get the title for a toolbar button. Displayed in the toolbar when + * hovering over a button. + * @param id id of the toolbar button + * @param shift true if shift is pressed + * @return the title + */ + public static String getTitle(int id, boolean shift) { + switch (id) { + case DebugToolbar.RUN: + return JavaToolbar.getTitle(JavaToolbar.RUN, shift); + case STOP: + return JavaToolbar.getTitle(JavaToolbar.STOP, shift); + case NEW: + return JavaToolbar.getTitle(JavaToolbar.NEW, shift); + case OPEN: + return JavaToolbar.getTitle(JavaToolbar.OPEN, shift); + case SAVE: + return JavaToolbar.getTitle(JavaToolbar.SAVE, shift); + case EXPORT: + return JavaToolbar.getTitle(JavaToolbar.EXPORT, shift); + case DEBUG: + if (shift) { + return "Run"; + } else { + return "Debug"; + } + case CONTINUE: + return "Continue"; + case TOGGLE_BREAKPOINT: + return "Toggle Breakpoint"; + case STEP: + if (shift) { + return "Step Into"; + } else { + return "Step"; + } + case TOGGLE_VAR_INSPECTOR: + return "Variable Inspector"; + } + return null; + } + + + /** + * Event handler called when a toolbar button is clicked. + * @param e the mouse event + * @param idx index (i.e. position) of the toolbar button clicked + */ + @Override + public void handlePressed(MouseEvent e, int idx) { + boolean shift = e.isShiftDown(); + DebugEditor deditor = (DebugEditor) editor; + int id = buttonId(idx); // convert index/position to button id + + switch (id) { +// case DebugToolbar.RUN: +// super.handlePressed(e, JavaToolbar.RUN); +// break; + case STOP: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Stop' toolbar button"); + super.handlePressed(e, JavaToolbar.STOP); + break; + case NEW: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'New' toolbar button"); + super.handlePressed(e, JavaToolbar.NEW); + break; + case OPEN: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Open' toolbar button"); + super.handlePressed(e, JavaToolbar.OPEN); + break; + case SAVE: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Save' toolbar button"); + super.handlePressed(e, JavaToolbar.SAVE); + break; + case EXPORT: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Export' toolbar button"); + super.handlePressed(e, JavaToolbar.EXPORT); + break; + case DEBUG: + deditor.handleStop(); // Close any running sketches + if (shift) { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button"); + deditor.handleRun(); + } else { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Debug' toolbar button"); + deditor.dbg.startDebug(); + } + break; + case CONTINUE: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Continue' toolbar button"); + deditor.dbg.continueDebug(); + break; + case TOGGLE_BREAKPOINT: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' toolbar button"); + deditor.dbg.toggleBreakpoint(); + break; + case STEP: + if (shift) { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step Into' toolbar button"); + deditor.dbg.stepInto(); + } else { + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step' toolbar button"); + deditor.dbg.stepOver(); + } + break; +// case STEP_INTO: +// deditor.dbg.stepInto(); +// break; +// case STEP_OUT: +// deditor.dbg.stepOut(); +// break; + case TOGGLE_VAR_INSPECTOR: + Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Variable Inspector' toolbar button"); + deditor.toggleVariableInspector(); + break; + } + } + + + /** + * Activate (light up) a button. + * @param id the button id + */ + @Override + public void activate(int id) { + //System.out.println("activate button idx: " + buttonIndex(id)); + super.activate(buttonIndex(id)); + } + + + /** + * Set a button to be inactive. + * @param id the button id + */ + @Override + public void deactivate(int id) { + //System.out.println("deactivate button idx: " + buttonIndex(id)); + super.deactivate(buttonIndex(id)); + } + + + /** + * Get button position (index) from it's id. + * @param buttonId the button id + * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...) + * @return the button index + */ + protected int buttonIndex(int buttonId) { + for (int i = 0; i < buttonSequence.length; i++) { + if (buttonSequence[i] == buttonId) { + return i; + } + } + return -1; + } + + + /** + * Get the button id from its position (index). + * @param buttonIdx the button index + * @return the button id + * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...) + */ + protected int buttonId(int buttonIdx) { + return buttonSequence[buttonIdx]; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/Debugger.java b/pdex/experimental/src/processing/mode/experimental/Debugger.java new file mode 100755 index 000000000..758f6cfae --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/Debugger.java @@ -0,0 +1,1364 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.*; +import com.sun.jdi.event.*; +import com.sun.jdi.request.*; +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JTree; // needed for javadocs +import javax.swing.tree.DefaultMutableTreeNode; +import processing.app.Sketch; +import processing.app.SketchCode; + +/** + * Main controller class for debugging mode. Mainly works with DebugEditor as + * the corresponding "view". Uses DebugRunner to launch a VM. + * + * @author Martin Leopold + */ +public class Debugger implements VMEventListener { + + protected DebugEditor editor; // editor window, acting as main view + protected DebugRunner runtime; // the runtime, contains debuggee VM + protected boolean started = false; // debuggee vm has started, VMStartEvent received, main class loaded + protected boolean paused = false; // currently paused at breakpoint or step + protected ThreadReference currentThread; // thread the last breakpoint or step occured in + protected String mainClassName; // name of the main class that's currently being debugged + protected ReferenceType mainClass; // the debuggee's main class + protected Set classes = new HashSet(); // holds all loaded classes in the debuggee VM + protected List classLoadListeners = new ArrayList(); // listeners for class load events + protected String srcPath; // path to the src folder of the current build + protected List breakpoints = new ArrayList(); // list of current breakpoints + protected StepRequest requestedStep; // the step request we are currently in, or null if not in a step + protected Map runtimeLineChanges = new HashMap(); // maps line number changes at runtime (orig -> changed) + protected Set runtimeTabsTracked = new HashSet(); // contains tab filenames which already have been tracked for runtime changes + + /** + * Construct a Debugger object. + * + * @param editor The Editor that will act as primary view + */ + public Debugger(DebugEditor editor) { + this.editor = editor; + } + + /** + * Access the VM. + * + * @return the virtual machine object or null if not available. + */ + public VirtualMachine vm() { + if (runtime != null) { + return runtime.vm(); + } else { + return null; + } + } + + /** + * Access the editor associated with this debugger. + * + * @return the editor object + */ + public DebugEditor editor() { + return editor; + } + + /** + * Retrieve the main class of the debuggee VM. + * + * @return the main classes {@link ReferenceType} or null if the debugger is + * not started. + */ + public ReferenceType getMainClass() { + if (isStarted()) { + return mainClass; + } else { + return null; + } + + } + + /** + * Get the {@link ReferenceType} for a class name. + * + * @param name the class name + * @return the {@link ReferenceType} or null if not found (e.g. not yet + * loaded) + */ + public ReferenceType getClass(String name) { + if (name == null) { + return null; + } + if (name.equals(mainClassName)) { + return mainClass; + } + for (ReferenceType rt : classes) { + if (rt.name().equals(name)) { + return rt; + } + } + return null; + } + + /** + * Add a class load listener. Will be notified when a class is loaded in the + * debuggee VM. + * + * @param listener the {@link ClassLoadListener} + */ + public void addClassLoadListener(ClassLoadListener listener) { + classLoadListeners.add(listener); + } + + /** + * Remove a class load listener. Cease to be notified when classes are + * loaded in the debuggee VM. + * + * @param listener {@link ClassLoadListener} + */ + public void removeClassLoadListener(ClassLoadListener listener) { + classLoadListeners.remove(listener); + } + + /** + * Start a debugging session. Builds the sketch and launches a VM to run it. + * VM starts suspended. Should produce a VMStartEvent. + */ + public synchronized void startDebug() { + //stopDebug(); // stop any running sessions + if (isStarted()) { + return; // do nothing + } + + // we are busy now + editor.statusBusy(); + + // clear console + editor.clearConsole(); + + // clear variable inspector (also resets expanded states) + editor.variableInspector().reset(); + + // load edits into sketch obj, etc... + editor.prepareRun(); + + editor.toolbar().activate(DebugToolbar.DEBUG); // after prepareRun, since this removes highlights + + try { + Sketch sketch = editor.getSketch(); + DebugBuild build = new DebugBuild(sketch); + + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "building sketch: {0}", sketch.getName()); + //LineMapping.addLineNumbers(sketch); // annotate + mainClassName = build.build(false); + //LineMapping.removeLineNumbers(sketch); // annotate + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class: {0}", mainClassName); + + // folder with assembled/preprocessed src + srcPath = build.getSrcFolder().getPath(); + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build src: {0}", srcPath); + // folder with compiled code (.class files) + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build bin: {0}", build.getBinFolder().getPath()); + + if (mainClassName != null) { + // generate the source line mapping + //lineMap = LineMapping.generateMapping(srcPath + File.separator + mainClassName + ".java"); + + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "launching debuggee runtime"); + runtime = new DebugRunner(build, editor); + VirtualMachine vm = runtime.launch(); // non-blocking + if (vm == null) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "error 37: launch failed"); + } + + // start receiving vm events + VMEventReader eventThread = new VMEventReader(vm.eventQueue(), this); + eventThread.start(); + + //return runtime; + + /* + * // launch runner in new thread new Thread(new Runnable() { + * + * @Override public void run() { runtime.launch(false); // this + * blocks until finished } }).start(); return runtime; + */ + + startTrackingLineChanges(); + editor.statusBusy(); + } + } catch (Exception e) { + editor.statusError(e); + } + } + + /** + * End debugging session. Stops and disconnects VM. Should produce + * VMDisconnectEvent. + */ + public synchronized void stopDebug() { + editor.variableInspector().lock(); + if (runtime != null) { + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "closing runtime"); + runtime.close(); + runtime = null; + //build = null; + classes.clear(); + // need to clear highlight here because, VMDisconnectedEvent seems to be unreliable. TODO: likely synchronization problem + editor.clearCurrentLine(); + } + stopTrackingLineChanges(); + started = false; + editor.toolbar().deactivate(DebugToolbar.DEBUG); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.statusEmpty(); + } + + /** + * Resume paused debugging session. Resumes VM. + */ + public synchronized void continueDebug() { + editor.toolbar().activate(DebugToolbar.CONTINUE); + editor.variableInspector().lock(); + //editor.clearSelection(); + //clearHighlight(); + editor.clearCurrentLine(); + if (!isStarted()) { + startDebug(); + } else if (isPaused()) { + runtime.vm().resume(); + paused = false; + editor.statusBusy(); + } + } + + /** + * Step through source code lines. + * + * @param stepDepth the step depth ({@link StepRequest#STEP_OVER}, + * {@link StepRequest#STEP_INTO} or {@link StepRequest#STEP_OUT}) + */ + protected void step(int stepDepth) { + if (!isStarted()) { + startDebug(); + } else if (isPaused()) { + editor.variableInspector().lock(); + editor.toolbar().activate(DebugToolbar.STEP); + + // use global to mark that there is a step request pending + requestedStep = runtime.vm().eventRequestManager().createStepRequest(currentThread, StepRequest.STEP_LINE, stepDepth); + requestedStep.addCountFilter(1); // valid for one step only + requestedStep.enable(); + paused = false; + runtime.vm().resume(); + editor.statusBusy(); + } + } + + /** + * Step over current statement. + */ + public synchronized void stepOver() { + step(StepRequest.STEP_OVER); + } + + /** + * Step into current statement. + */ + public synchronized void stepInto() { + step(StepRequest.STEP_INTO); + } + + /** + * Step out of current function. + */ + public synchronized void stepOut() { + step(StepRequest.STEP_OUT); + } + + /** + * Print the current stack trace. + */ + public synchronized void printStackTrace() { + if (isStarted()) { + printStackTrace(currentThread); + } + } + + /** + * Print local variables. Outputs type, name and value of each variable. + */ + public synchronized void printLocals() { + if (isStarted()) { + printLocalVariables(currentThread); + } + } + + /** + * Print fields of current {@code this}-object. Outputs type, name and value + * of each field. + */ + public synchronized void printThis() { + if (isStarted()) { + printThis(currentThread); + } + } + + /** + * Print a source code snippet of the current location. + */ + public synchronized void printSource() { + if (isStarted()) { + printSourceLocation(currentThread); + } + } + + /** + * Set a breakpoint on the current line. + */ + public synchronized void setBreakpoint() { + setBreakpoint(editor.getCurrentLineID()); + } + + /** + * Set a breakpoint on a line in the current tab. + * + * @param lineIdx the line index (0-based) of the current tab to set the + * breakpoint on + */ + public synchronized void setBreakpoint(int lineIdx) { + setBreakpoint(editor.getLineIDInCurrentTab(lineIdx)); + } + + /** + * Set a breakpoint. + * + * @param line the line id to set the breakpoint on + */ + public synchronized void setBreakpoint(LineID line) { + // do nothing if we are kinda busy + if (isStarted() && !isPaused()) { + return; + } + // do nothing if there already is a breakpoint on this line + if (hasBreakpoint(line)) { + return; + } + breakpoints.add(new LineBreakpoint(line, this)); + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "set breakpoint on line {0}", line); + } + + /** + * Remove a breakpoint from the current line (if set). + */ + public synchronized void removeBreakpoint() { + removeBreakpoint(editor.getCurrentLineID().lineIdx()); + } + + /** + * Remove a breakpoint from a line in the current tab. + * + * @param lineIdx the line index (0-based) in the current tab to remove the + * breakpoint from + */ + protected void removeBreakpoint(int lineIdx) { + // do nothing if we are kinda busy + if (isBusy()) { + return; + } + + LineBreakpoint bp = breakpointOnLine(editor.getLineIDInCurrentTab(lineIdx)); + if (bp != null) { + bp.remove(); + breakpoints.remove(bp); + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "removed breakpoint {0}", bp); + } + } + + /** + * Remove all breakpoints. + */ + public synchronized void clearBreakpoints() { + //TODO: handle busy-ness correctly + if (isBusy()) { + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy"); + return; + } + + for (LineBreakpoint bp : breakpoints) { + bp.remove(); + } + breakpoints.clear(); + } + + /** + * Clear breakpoints in a specific tab. + * + * @param tabFilename the tab's file name + */ + public synchronized void clearBreakpoints(String tabFilename) { + //TODO: handle busy-ness correctly + if (isBusy()) { + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy"); + return; + } + + Iterator i = breakpoints.iterator(); + while (i.hasNext()) { + LineBreakpoint bp = i.next(); + if (bp.lineID().fileName().equals(tabFilename)) { + bp.remove(); + i.remove(); + } + } + } + + /** + * Get the breakpoint on a certain line, if set. + * + * @param line the line to get the breakpoint from + * @return the breakpoint, or null if no breakpoint is set on the specified + * line. + */ + protected LineBreakpoint breakpointOnLine(LineID line) { + for (LineBreakpoint bp : breakpoints) { + if (bp.isOnLine(line)) { + return bp; + } + } + return null; + } + + /** + * Toggle a breakpoint on the current line. + */ + public synchronized void toggleBreakpoint() { + toggleBreakpoint(editor.getCurrentLineID().lineIdx()); + } + + /** + * Toggle a breakpoint on a line in the current tab. + * + * @param lineIdx the line index (0-based) in the current tab + */ + public synchronized void toggleBreakpoint(int lineIdx) { + LineID line = editor.getLineIDInCurrentTab(lineIdx); + if (!hasBreakpoint(line)) { + setBreakpoint(line.lineIdx()); + } else { + removeBreakpoint(line.lineIdx()); + } + } + + /** + * Check if there's a breakpoint on a particular line. + * + * @param line the line id + * @return true if a breakpoint is set on the given line, otherwise false + */ + protected boolean hasBreakpoint(LineID line) { + LineBreakpoint bp = breakpointOnLine(line); + return bp != null; + } + + /** + * Print a list of currently set breakpoints. + */ + public synchronized void listBreakpoints() { + if (breakpoints.isEmpty()) { + System.out.println("no breakpoints"); + } else { + System.out.println("line breakpoints:"); + for (LineBreakpoint bp : breakpoints) { + System.out.println(bp); + } + } + } + + /** + * Retrieve a list of breakpoint in a particular tab. + * + * @param tabFilename the tab's file name + * @return the list of breakpoints in the given tab + */ + public synchronized List getBreakpoints(String tabFilename) { + List list = new ArrayList(); + for (LineBreakpoint bp : breakpoints) { + if (bp.lineID().fileName().equals(tabFilename)) { + list.add(bp); + } + } + return list; + } + + /** + * Callback for VM events. Will be called from another thread. + * ({@link VMEventReader}) + * + * @param es Incoming set of events from VM + */ + @Override + public synchronized void vmEvent(EventSet es) { + for (Event e : es) { + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "*** VM Event: {0}", e.toString()); + if (e instanceof VMStartEvent) { + //initialThread = ((VMStartEvent) e).thread(); +// ThreadReference t = ((VMStartEvent) e).thread(); + //printStackTrace(t); + + // break on main class load + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on main class load: {0}", mainClassName); + ClassPrepareRequest mainClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); + mainClassPrepare.addClassFilter(mainClassName); + mainClassPrepare.enable(); + + // break on loading custom classes + for (SketchCode tab : editor.getSketch().getCode()) { + if (tab.isExtension("java")) { + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on class load: {0}", tab.getPrettyName()); + ClassPrepareRequest customClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); + customClassPrepare.addClassFilter(tab.getPrettyName()); + customClassPrepare.enable(); + } + } + + runtime.vm().resume(); + } else if (e instanceof ClassPrepareEvent) { + ClassPrepareEvent ce = (ClassPrepareEvent) e; + ReferenceType rt = ce.referenceType(); + currentThread = ce.thread(); + paused = true; // for now we're paused + + if (rt.name().equals(mainClassName)) { + //printType(rt); + mainClass = rt; + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "main class load: {0}", rt.name()); + started = true; // now that main class is loaded, we're started + } else { + classes.add(rt); // save loaded classes + Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class load: {0}", rt.name()); + } + + // notify listeners + for (ClassLoadListener listener : classLoadListeners) { + if (listener != null) { + listener.classLoaded(rt); + } + } + + paused = false; // resuming now + runtime.vm().resume(); + } else if (e instanceof BreakpointEvent) { + BreakpointEvent be = (BreakpointEvent) e; + currentThread = be.thread(); // save this thread +// BreakpointRequest br = (BreakpointRequest) be.request(); + + //printSourceLocation(currentThread); + updateVariableInspector(currentThread); // this is already on the EDT + final LineID newCurrentLine = locationToLineID(be.location()); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + editor.setCurrentLine(newCurrentLine); + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + } + }); + + // hit a breakpoint during a step, need to cancel the step. + if (requestedStep != null) { + runtime.vm().eventRequestManager().deleteEventRequest(requestedStep); + requestedStep = null; + } + + // fix canvas update issue + // TODO: is this a good solution? + resumeOtherThreads(currentThread); + + paused = true; + editor.statusHalted(); + } else if (e instanceof StepEvent) { + StepEvent se = (StepEvent) e; + currentThread = se.thread(); + + //printSourceLocation(currentThread); + updateVariableInspector(currentThread); // this is already on the EDT + final LineID newCurrentLine = locationToLineID(se.location()); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + editor.setCurrentLine(newCurrentLine); + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + } + }); + + // delete the steprequest that triggered this step so new ones can be placed (only one per thread) + EventRequestManager mgr = runtime.vm().eventRequestManager(); + mgr.deleteEventRequest(se.request()); + requestedStep = null; // mark that there is no step request pending + paused = true; + editor.statusHalted(); + + // disallow stepping into invisible lines + if (!locationIsVisible(se.location())) { + stepOutIntoViewOrContinue(); // TODO: this leads to stepping, should it run on the EDT? + } + } else if (e instanceof VMDisconnectEvent) { +// started = false; +// // clear line highlight +// editor.clearCurrentLine(); + stopDebug(); + } else if (e instanceof VMDeathEvent) { + started = false; + editor.statusEmpty(); + } + } + } + + /** + * Check whether a location corresponds to a code line in the editor. + * + * @param l the location + * @return true if the location corresponds to a line in the editor + */ + protected boolean locationIsVisible(Location l) { + return locationToLineID(l) != null; + } + + /** + * Step out if this results in a visible location, otherwise continue. + */ + protected void stepOutIntoViewOrContinue() { + try { + List frames = currentThread.frames(); + if (frames.size() > 1) { + if (locationIsVisible(frames.get(1).location())) { + //System.out.println("stepping out to: " + locationToString(frames.get(1).location())); + stepOut(); + return; + } + } + continueDebug(); + +// //Step out to the next visible location on the stack frame +// if (thread.frames(i, i1)) +// for (StackFrame f : thread.frames()) { +// Location l = f.location(); +// if (locationIsVisible(l)) { +// System.out.println("need to step out to: " + locationToString(l)); +// } +// } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Check whether a debugging session is running. i.e. the debugger is + * connected to a debuggee VM, VMStartEvent has been received and main class + * is loaded. + * + * @return true if the debugger is started. + */ + public synchronized boolean isStarted() { + return started && runtime != null && runtime.vm() != null; + } + + /** + * Check whether the debugger is paused. i.e. it is currently suspended at a + * breakpoint or step. + * + * @return true if the debugger is paused, false otherwise or if not started + * ({@link #isStarted()}) + */ + public synchronized boolean isPaused() { + return isStarted() && paused && currentThread != null && currentThread.isSuspended(); + } + + /** + * Check whether the debugger is currently busy. i.e. running (not + * suspended). + * + * @return true if the debugger is currently running and not suspended. + */ + public synchronized boolean isBusy() { + return isStarted() && !isPaused(); + } + + /** + * Print call stack trace of a thread. Only works on suspended threads. + * + * @param t suspended thread to print stack trace of + */ + protected void printStackTrace(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + System.out.println("stack trace for thread " + t.name() + ":"); + int i = 0; + for (StackFrame f : t.frames()) { +// Location l = f.location(); + System.out.println(i++ + ": " + f.toString()); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Resume all other threads except the one given as parameter. Useful e.g. + * to just keep the thread suspended a breakpoint occurred in. + * + * @param t the thread not to resume + */ + protected void resumeOtherThreads(ThreadReference t) { + if (!isStarted()) { + return; + } + for (ThreadReference other : vm().allThreads()) { + if (!other.equals(t) && other.isSuspended()) { + other.resume(); + } + } + } + + /** + * Print info about all current threads. Includes name, status, isSuspended, + * isAtBreakpoint. + */ + public synchronized void printThreads() { + if (!isPaused()) { + return; + } + System.out.println("threads:"); + for (ThreadReference t : vm().allThreads()) { + printThread(t); + } + } + + /** + * Print info about a thread. Includes name, status, isSuspended, + * isAtBreakpoint. + * + * @param t the thread to print info about + */ + protected void printThread(ThreadReference t) { + System.out.println(t.name()); + System.out.println(" is suspended: " + t.isSuspended()); + System.out.println(" is at breakpoint: " + t.isAtBreakpoint()); + System.out.println(" status: " + threadStatusToString(t.status())); + } + + /** + * Convert a status code returned by {@link ThreadReference#status() } to a + * human readable form. + * + * @param status {@link ThreadReference#THREAD_STATUS_MONITOR}, + * {@link ThreadReference#THREAD_STATUS_NOT_STARTED}, + * {@link ThreadReference#THREAD_STATUS_RUNNING}, + * {@link ThreadReference#THREAD_STATUS_SLEEPING}, + * {@link ThreadReference#THREAD_STATUS_UNKNOWN}, + * {@link ThreadReference#THREAD_STATUS_WAIT} or + * {@link ThreadReference#THREAD_STATUS_ZOMBIE} + * @return String containing readable status code. + */ + protected String threadStatusToString(int status) { + switch (status) { + case ThreadReference.THREAD_STATUS_MONITOR: + return "THREAD_STATUS_MONITOR"; + case ThreadReference.THREAD_STATUS_NOT_STARTED: + return "THREAD_STATUS_NOT_STARTED"; + case ThreadReference.THREAD_STATUS_RUNNING: + return "THREAD_STATUS_RUNNING"; + case ThreadReference.THREAD_STATUS_SLEEPING: + return "THREAD_STATUS_SLEEPING"; + case ThreadReference.THREAD_STATUS_UNKNOWN: + return "THREAD_STATUS_UNKNOWN"; + case ThreadReference.THREAD_STATUS_WAIT: + return "THREAD_STATUS_WAIT"; + case ThreadReference.THREAD_STATUS_ZOMBIE: + return "THREAD_STATUS_ZOMBIE"; + default: + return ""; + } + } + + /** + * Print local variables on a suspended thread. Takes the topmost stack + * frame and lists all local variables and their values. + * + * @param t suspended thread + */ + protected void printLocalVariables(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + if (t.frameCount() == 0) { + System.out.println("call stack empty"); + } else { + StackFrame sf = t.frame(0); + List locals = sf.visibleVariables(); + if (locals.isEmpty()) { + System.out.println("no local variables"); + return; + } + for (LocalVariable lv : locals) { + System.out.println(lv.typeName() + " " + lv.name() + " = " + sf.getValue(lv)); + } + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } catch (AbsentInformationException ex) { + System.out.println("local variable information not available"); + } + } + + /** + * Update variable inspector window. Displays local variables and this + * fields. + * + * @param t suspended thread to retrieve locals and this + */ + protected void updateVariableInspector(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + if (t.frameCount() == 0) { + // TODO: needs to be handled in a better way: + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "call stack empty"); + } else { + final VariableInspector vi = editor.variableInspector(); + // first get data + final List stackTrace = getStackTrace(t); + final List locals = getLocals(t, 0); + final String currentLocation = currentLocation(t); + final List thisFields = getThisFields(t, 0, true); + final List declaredThisFields = getThisFields(t, 0, false); + final String thisName = thisName(t); + // now update asynchronously + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + //System.out.println("updating vi. from EDT: " + javax.swing.SwingUtilities.isEventDispatchThread()); + vi.updateCallStack(stackTrace, "Call Stack"); + vi.updateLocals(locals, "Locals at " + currentLocation); + vi.updateThisFields(thisFields, "Class " + thisName); + vi.updateDeclaredThisFields(declaredThisFields, "Class " + thisName); + vi.unlock(); // need to do this before rebuilding, otherwise we get these ... dots in the labels + vi.rebuild(); + } + }); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Get the class name of the current this object in a suspended thread. + * + * @param t a suspended thread + * @return the class name of this + */ + protected String thisName(ThreadReference t) { + try { + if (!t.isSuspended() || t.frameCount() == 0) { + return ""; + } + return t.frame(0).thisObject().referenceType().name(); + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return ""; + } + } + + /** + * Get a description of the current location in a suspended thread. Format: + * class.method:translated_line_number + * + * @param t a suspended thread + * @return descriptive string for the given location + */ + protected String currentLocation(ThreadReference t) { + try { + if (!t.isSuspended() || t.frameCount() == 0) { + return ""; + } + return locationToString(t.frame(0).location()); + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return ""; + } + } + + /** + * Get a string describing a location. Format: + * class.method:translated_line_number + * + * @param l a location + * @return descriptive string for the given location + */ + protected String locationToString(Location l) { + LineID line = locationToLineID(l); + int lineNumber; + if (line != null) { + lineNumber = line.lineIdx() + 1; + } else { + lineNumber = l.lineNumber(); + } + return l.declaringType().name() + "." + l.method().name() + ":" + lineNumber; + } + + /** + * Compile a list of current locals usable for insertion into a + * {@link JTree}. Recursively resolves object references. + * + * @param t the suspended thread to get locals for + * @param depth how deep to resolve nested object references. 0 will not + * resolve nested objects. + * @return the list of current locals + */ + protected List getLocals(ThreadReference t, int depth) { + //System.out.println("getting locals"); + List vars = new ArrayList(); + try { + if (t.frameCount() > 0) { + StackFrame sf = t.frame(0); + for (LocalVariable lv : sf.visibleVariables()) { + //System.out.println("local var: " + lv.name()); + Value val = sf.getValue(lv); + VariableNode var = new LocalVariableNode(lv.name(), lv.typeName(), val, lv, sf); + if (depth > 0) { + var.addChildren(getFields(val, depth - 1, true)); + } + vars.add(var); + } + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "local variable information not available", ex); + } + return vars; + } + + /** + * Compile a list of fields in the current this object usable for insertion + * into a {@link JTree}. Recursively resolves object references. + * + * @param t the suspended thread to get locals for + * @param depth how deep to resolve nested object references. 0 will not + * resolve nested objects. + * @return the list of fields in the current this object + */ + protected List getThisFields(ThreadReference t, int depth, boolean includeInherited) { + //System.out.println("getting this"); + try { + if (t.frameCount() > 0) { + StackFrame sf = t.frame(0); + ObjectReference thisObj = sf.thisObject(); + return getFields(thisObj, depth, includeInherited); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + return new ArrayList(); + } + + /** + * Recursively get the fields of a {@link Value} for insertion into a + * {@link JTree}. + * + * @param value must be an instance of {@link ObjectReference} + * @param depth the current depth + * @param maxDepth the depth to stop at (inclusive) + * @return list of child fields of the given value + */ + protected List getFields(Value value, int depth, int maxDepth, boolean includeInherited) { + // remember: Value <- ObjectReference, ArrayReference + List vars = new ArrayList(); + if (depth <= maxDepth) { + if (value instanceof ArrayReference) { + return getArrayFields((ArrayReference) value); + } else if (value instanceof ObjectReference) { + ObjectReference obj = (ObjectReference) value; + // get the fields of this object + List fields = includeInherited ? obj.referenceType().visibleFields() : obj.referenceType().fields(); + for (Field field : fields) { + Value val = obj.getValue(field); // get the value, may be null + VariableNode var = new FieldNode(field.name(), field.typeName(), val, field, obj); + // recursively add children + if (val != null) { + var.addChildren(getFields(val, depth + 1, maxDepth, includeInherited)); + } + vars.add(var); + } + } + } + return vars; + } + + /** + * Recursively get the fields of a {@link Value} for insertion into a + * {@link JTree}. + * + * @param value must be an instance of {@link ObjectReference} + * @param maxDepth max recursion depth. 0 will give only direct children + * @return list of child fields of the given value + */ + protected List getFields(Value value, int maxDepth, boolean includeInherited) { + return getFields(value, 0, maxDepth, includeInherited); + } + + /** + * Get the fields of an array for insertion into a {@link JTree}. + * + * @param array the array reference + * @return list of array fields + */ + protected List getArrayFields(ArrayReference array) { + List fields = new ArrayList(); + if (array != null) { + String arrayType = array.type().name(); + if (arrayType.endsWith("[]")) { + arrayType = arrayType.substring(0, arrayType.length() - 2); + } + int i = 0; + for (Value val : array.getValues()) { + VariableNode var = new ArrayFieldNode("[" + i + "]", arrayType, val, array, i); + fields.add(var); + i++; + } + } + return fields; + } + + /** + * Get the current call stack trace usable for insertion into a + * {@link JTree}. + * + * @param t the suspended thread to retrieve the call stack from + * @return call stack as list of {@link DefaultMutableTreeNode}s + */ + protected List getStackTrace(ThreadReference t) { + List stack = new ArrayList(); + try { +// int i = 0; + for (StackFrame f : t.frames()) { + stack.add(new DefaultMutableTreeNode(locationToString(f.location()))); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + return stack; + } + + /** + * Print visible fields of current "this" object on a suspended thread. + * Prints type, name and value. + * + * @param t suspended thread + */ + protected void printThis(ThreadReference t) { + if (!t.isSuspended()) { + return; + } + try { + if (t.frameCount() == 0) { + // TODO: needs to be handled in a better way + System.out.println("call stack empty"); + } else { + StackFrame sf = t.frame(0); + ObjectReference thisObject = sf.thisObject(); + if (this != null) { + ReferenceType type = thisObject.referenceType(); + System.out.println("fields in this (" + type.name() + "):"); + for (Field f : type.visibleFields()) { + System.out.println(f.typeName() + " " + f.name() + " = " + thisObject.getValue(f)); + } + } else { + System.out.println("can't get this (in native or static method)"); + } + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Print source code snippet of current location in a suspended thread. + * + * @param t suspended thread + */ + protected void printSourceLocation(ThreadReference t) { + try { + if (t.frameCount() == 0) { + // TODO: needs to be handled in a better way + System.out.println("call stack empty"); + } else { + Location l = t.frame(0).location(); // current stack frame location + printSourceLocation(l); + } + } catch (IncompatibleThreadStateException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Print source code snippet. + * + * @param l {@link Location} object to print source code for + */ + protected void printSourceLocation(Location l) { + try { + //System.out.println(l.sourceName() + ":" + l.lineNumber()); + System.out.println("in method " + l.method() + ":"); + System.out.println(getSourceLine(l.sourcePath(), l.lineNumber(), 2)); + + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Read a line from the given file in the builds src folder. 1-based i.e. + * first line has line no. 1 + * + * @param filePath + * @param lineNo + * @return the requested source line + */ + protected String getSourceLine(String filePath, int lineNo, int radius) { + if (lineNo == -1) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "invalid line number: {0}", lineNo); + return ""; + } + //System.out.println("getting line: " + lineNo); + File f = new File(srcPath + File.separator + filePath); + String output = ""; + try { + BufferedReader r = new BufferedReader(new FileReader(f)); + int i = 1; + //String line = ""; + while (i <= lineNo + radius) { + String line = r.readLine(); // line no. i + if (line == null) { + break; // end of file + } + if (i >= lineNo - radius) { + if (i > lineNo - radius) { + output += "\n"; // add newlines before all lines but the first + } + output += f.getName() + ":" + i + (i == lineNo ? " => " : " ") + line; + } + i++; + } + r.close(); + return output; + } catch (FileNotFoundException ex) { + //System.err.println(ex); + return f.getName() + ":" + lineNo; + } catch (IOException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return ""; + } + } + + /** + * Print info about a ReferenceType. Prints class name, source file name, + * lists methods. + * + * @param rt the reference type to print out + */ + protected void printType(ReferenceType rt) { + System.out.println("ref.type: " + rt); + System.out.println("name: " + rt.name()); + try { + System.out.println("sourceName: " + rt.sourceName()); + } catch (AbsentInformationException ex) { + System.out.println("sourceName: unknown"); + } + System.out.println("methods:"); + for (Method m : rt.methods()) { + System.out.println(m.toString()); + } + } + + /** + * Translate a java source location to a sketch line id. + * + * @param l the location to translate + * @return the corresponding line id, or null if not found + */ + protected LineID locationToLineID(Location l) { + try { + //return lineMap.get(LineID.create(l.sourceName(), l.lineNumber() - 1)); + return javaToSketchLine(new LineID(l.sourceName(), l.lineNumber() - 1)); + + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + return null; + } + } + + /** + * Translate a line (index) from java space to sketch space. + * + * @param javaLine the java line id + * @return the corresponding sketch line id or null if failed to translate + */ + public LineID javaToSketchLine(LineID javaLine) { + Sketch sketch = editor.getSketch(); + + // it may belong to a pure java file created in the sketch + // try to find an exact filename match and check the extension + SketchCode tab = editor.getTab(javaLine.fileName()); + if (tab != null && tab.isExtension("java")) { + // can translate 1:1 + return originalToRuntimeLine(javaLine); + } + + // check if it is the preprocessed/assembled file for this sketch + // java file name needs to match the sketches filename + if (!javaLine.fileName().equals(sketch.getName() + ".java")) { + return null; + } + + // find the tab (.pde file) this line belongs to + // get the last tab that has an offset not greater than the java line number + for (int i = sketch.getCodeCount() - 1; i >= 0; i--) { + tab = sketch.getCode(i); + // ignore .java files + // the tab's offset must not be greater than the java line number + if (tab.isExtension("pde") && tab.getPreprocOffset() <= javaLine.lineIdx()) { + return originalToRuntimeLine(new LineID(tab.getFileName(), javaLine.lineIdx() - tab.getPreprocOffset())); + } + } + + return null; + } + + /** + * Get the runtime-changed line id for an original sketch line. Used to + * translate line numbers from the VM (which runs on the original line + * numbers) to their current (possibly changed) counterparts. + * + * @param line the original line id (at compile time) + * @return the changed version or the line given as parameter if not found + */ + protected LineID originalToRuntimeLine(LineID line) { + LineID transformed = runtimeLineChanges.get(line); + if (transformed == null) { + return line; + } + return transformed; + } + + /** + * Get the original line id for a sketch line that was changed at runtime. + * Used to translate line numbers from the UI at runtime (which can differ + * from the ones the VM runs on) to their original counterparts. + * + * @param line the (possibly) changed runtime line + * @return the original line or the line given as parameter if not found + */ + protected LineID runtimeToOriginalLine(LineID line) { + for (Entry entry : runtimeLineChanges.entrySet()) { + if (entry.getValue().equals(line)) { + return entry.getKey(); + } + } + return line; + } + + /** + * Translate a line (index) from sketch space to java space. + * + * @param sketchLine the sketch line id + * @return the corresponding java line id or null if failed to translate + */ + public LineID sketchToJavaLine(LineID sketchLine) { + sketchLine = runtimeToOriginalLine(sketchLine); // transform back to orig (before changes at runtime) + + // check if there is a tab for this line + SketchCode tab = editor.getTab(sketchLine.fileName()); + if (tab == null) { + return null; + } + + // check if the tab is a pure java file anyway + if (tab.isExtension("java")) { + // 1:1 translation + return sketchLine; + } + + // the java file has a name sketchname.java + // just add the tab's offset to get the java name + LineID javaLine = new LineID(editor.getSketch().getName() + ".java", sketchLine.lineIdx() + tab.getPreprocOffset()); + return javaLine; + } + + /** + * Start tracking all line changes (due to edits) in the current tab. + */ + // TODO: maybe move this to the editor? + protected void startTrackingLineChanges() { + SketchCode tab = editor.getSketch().getCurrentCode(); + if (runtimeTabsTracked.contains(tab.getFileName())) { + return; + } + + for (int i = 0; i < tab.getLineCount(); i++) { + LineID old = new LineID(tab.getFileName(), i); + LineID tracked = new LineID(tab.getFileName(), i); + tracked.startTracking(editor.currentDocument()); + runtimeLineChanges.put(old, tracked); + } + runtimeTabsTracked.add(tab.getFileName()); + //System.out.println("tracking tab: " + tab.getFileName()); + } + + /** + * Stop tracking line changes in all tabs. + */ + protected void stopTrackingLineChanges() { + //System.out.println("stop tracking line changes"); + for (LineID tracked : runtimeLineChanges.values()) { + tracked.stopTracking(); + } + runtimeLineChanges.clear(); + runtimeTabsTracked.clear(); + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorBar.java b/pdex/experimental/src/processing/mode/experimental/ErrorBar.java new file mode 100755 index 000000000..24d552ae5 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ErrorBar.java @@ -0,0 +1,385 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.experimental; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.util.ArrayList; + +import javax.swing.JPanel; +import javax.swing.SwingWorker; + +import processing.app.Base; +import processing.app.SketchCode; + +/** + * The bar on the left of the text area which displays all errors as rectangles.
    + *
    + * All errors and warnings of a sketch are drawn on the bar, clicking on one, + * scrolls to the tab and location. Error messages displayed on hover. Markers + * are not in sync with the error line. Similar to eclipse's right error bar + * which displays the overall errors in a document + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class ErrorBar extends JPanel { + /** + * Preferred height of the component + */ + protected int preferredHeight; + + /** + * Preferred height of the component + */ + protected int preferredWidth = 12; + + /** + * Height of marker + */ + public static final int errorMarkerHeight = 4; + + /** + * Color of Error Marker + */ + public Color errorColor = new Color(0xED2630); + + /** + * Color of Warning Marker + */ + public Color warningColor = new Color(0xFFC30E); + + /** + * Background color of the component + */ + public Color backgroundColor = new Color(0x2C343D); + + /** + * DebugEditor instance + */ + protected DebugEditor editor; + + /** + * ErrorCheckerService instance + */ + protected ErrorCheckerService errorCheckerService; + + /** + * Stores error markers displayed PER TAB along the error bar. + */ + protected ArrayList errorPoints = new ArrayList(); + + /** + * Stores previous list of error markers. + */ + protected ArrayList errorPointsOld = new ArrayList(); + + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setColor(backgroundColor); + g.fillRect(0, 0, getWidth(), getHeight()); + + for (ErrorMarker emarker : errorPoints) { + if (emarker.type == ErrorMarker.Error) { + g.setColor(errorColor); + } else { + g.setColor(warningColor); + } + g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight); + } + } + + public Dimension getPreferredSize() { + return new Dimension(preferredWidth, preferredHeight); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public ErrorBar(DebugEditor editor, int height, ExperimentalMode mode) { + this.editor = editor; + this.preferredHeight = height; + this.errorCheckerService = editor.errorCheckerService; + errorColor = mode.getThemeColor("errorbar.errorcolor", errorColor); + warningColor = mode + .getThemeColor("errorbar.warningcolor", warningColor); + backgroundColor = mode.getThemeColor("errorbar.backgroundcolor", + backgroundColor); + addListeners(); + } + + /** + * Update error markers in the error bar. + * + * @param problems + * - List of problems. + */ + synchronized public void updateErrorPoints(final ArrayList problems) { + + // NOTE TO SELF: ErrorMarkers are calculated for the present tab only + // Error Marker index in the arraylist is LOCALIZED for current tab. + // Also, need to do the update in the UI thread to prevent concurrency issues. + final int fheight = this.getHeight(); + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + int totalLines = 0; + int currentTab = 0; + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + try { + if (editor.getSketch().getCurrentCode().equals(sc)) { + // Adding + 1 to len because \n gets appended + // for each + // sketchcode extracted during processPDECode() + totalLines = Base.countLines(sc.getDocument() + .getText(0, + sc.getDocument().getLength())) + 1; + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + currentTab++; + } + // System.out.println("Total lines: " + totalLines); + + errorPointsOld.clear(); + for (ErrorMarker marker : errorPoints) { + errorPointsOld.add(marker); + } + errorPoints.clear(); + + // Each problem.getSourceLine() will have an extra line added + // because of + // class declaration in the beginning as well as default imports + for (Problem problem : problems) { + if (problem.tabIndex == currentTab) { + // Ratio of error line to total lines + float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset) + / ((float) totalLines); + // Ratio multiplied by height of the error bar + y *= fheight - 15; // -15 is just a vertical offset + errorPoints.add(new ErrorMarker(problem, (int) y, + problem.isError() ? ErrorMarker.Error + : ErrorMarker.Warning)); + // System.out.println("Y: " + y); + } + } + + repaint(); + } + }; + + try { + worker.execute(); // I eat concurrency bugs for breakfast. + } catch (Exception exp) { + System.out.println("Errorbar update markers is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } + } + + /** + * Check if new errors have popped up in the sketch since the last check + * + * @return true - if errors have changed + */ + public boolean errorPointsChanged() { + if (errorPointsOld.size() != errorPoints.size()) { + editor.getTextArea().repaint(); + // System.out.println("2 Repaint " + System.currentTimeMillis()); + return true; + } + + else { + for (int i = 0; i < errorPoints.size(); i++) { + if (errorPoints.get(i).y != errorPointsOld.get(i).y) { + editor.getTextArea().repaint(); + // System.out.println("3 Repaint " + + // System.currentTimeMillis()); + return true; + } + } + } + return false; + } + + /** + * Add various mouse listeners. + */ + protected void addListeners() { + + this.addMouseListener(new MouseAdapter() { + + // Find out which error/warning the user has clicked + // and then scroll to that + @SuppressWarnings("rawtypes") + @Override + public void mouseClicked(final MouseEvent e) { + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + for (ErrorMarker eMarker : errorPoints) { + // -2 and +2 are extra allowance, clicks in the + // vicinity of the markers register that way + if (e.getY() >= eMarker.y - 2 + && e.getY() <= eMarker.y + 2 + + errorMarkerHeight) { + int currentTabErrorIndex = errorPoints + .indexOf(eMarker); + // System.out.println("Index: " + + // currentTabErrorIndex); + int currentTab = editor.getSketch() + .getCodeIndex( + editor.getSketch() + .getCurrentCode()); + + int totalErrorIndex = currentTabErrorIndex; + + for (int i = 0; i < errorCheckerService.problemsList + .size(); i++) { + Problem p = errorCheckerService.problemsList + .get(i); + if (p.tabIndex < currentTab) { + totalErrorIndex++; + } + if (p.tabIndex == currentTab) { + break; + } + } + errorCheckerService + .scrollToErrorLine(totalErrorIndex); + } + } + + } + }; + + try { + worker.execute(); + } catch (Exception exp) { + System.out.println("Errorbar mouseClicked is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } + + } + }); + + // Tooltip on hover + this.addMouseMotionListener(new MouseMotionListener() { + + @SuppressWarnings("rawtypes") + @Override + public void mouseMoved(final MouseEvent e) { + // System.out.println(e); + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + + for (ErrorMarker eMarker : errorPoints) { + if (e.getY() >= eMarker.y - 2 + && e.getY() <= eMarker.y + 2 + + errorMarkerHeight) { + // System.out.println("Index: " + + // errorPoints.indexOf(y)); + int currentTab = editor.getSketch() + .getCodeIndex( + editor.getSketch() + .getCurrentCode()); + int currentTabErrorCount = 0; + + for (int i = 0; i < errorPoints.size(); i++) { + Problem p = errorPoints.get(i).problem; + if (p.tabIndex == currentTab) { + if (currentTabErrorCount == errorPoints + .indexOf(eMarker)) { + // System.out.println("Roger that."); + String msg = (p.isError() ? "Error: " + : "Warning: ") + + p.message; + setToolTipText(msg); + setCursor(Cursor + .getPredefinedCursor(Cursor.HAND_CURSOR)); + return; + } else { + currentTabErrorCount++; + // System.out.println("Still looking.."); + } + } + + } + } + // Reset cursor and tooltip + else { + setToolTipText(""); + setCursor(Cursor + .getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + } + + } + }; + try { + worker.execute(); + } catch (Exception exp) { + System.out + .println("Errorbar mousemoved Worker is slacking." + + exp.getMessage()); + // e.printStackTrace(); + } + } + + @Override + public void mouseDragged(MouseEvent arg0) { + + } + }); + + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java new file mode 100644 index 000000000..395def5e2 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java @@ -0,0 +1,1297 @@ +package processing.mode.experimental; + +import java.awt.EventQueue; +import java.io.File; +import java.io.FileFilter; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.table.DefaultTableModel; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; + +import processing.app.Base; +import processing.app.Editor; +import processing.app.Library; +import processing.app.SketchCode; +import processing.core.PApplet; +import processing.mode.java.preproc.PdePreprocessor; + +public class ErrorCheckerService implements Runnable{ + + private DebugEditor editor; + /** + * Error check happens every sleepTime milliseconds + */ + public static final int sleepTime = 1000; + + /** + * The amazing eclipse ast parser + */ + private ASTParser parser; + + /** + * Used to indirectly stop the Error Checker Thread + */ + public boolean stopThread = false; + + /** + * If true, Error Checking is paused. Calls to checkCode() become useless. + */ + private boolean pauseThread = false; + + protected ErrorWindow errorWindow; + + /** + * IProblem[] returned by parser stored in here + */ + private IProblem[] problems; + + /** + * Class name of current sketch + */ + protected String className; + + /** + * Source code of current sketch + */ + protected String sourceCode; + + /** + * URLs of extra imports jar files stored here. + */ + protected URL[] classpath; + + /** + * Stores all Problems in the sketch + */ + public ArrayList problemsList; + + /** + * How many lines are present till the initial class declaration? In static + * mode, this would include imports, class declaration and setup + * declaration. In nomral mode, this would include imports, class + * declaration only. It's fate is decided inside preprocessCode() + */ + public int mainClassOffset; + + /** + * Fixed p5 offsets for all sketches + */ + public int defaultImportsOffset; + + /** + * Is the sketch running in static mode or active mode? + */ + public boolean staticMode = false; + + /** + * Compilation Unit for current sketch + */ + protected CompilationUnit cu; + + /** + * If true, compilation checker will be reloaded with updated classpath + * items. + */ + private boolean loadCompClass = true; + + /** + * Compiler Checker class. Note that methods for compilation checking are + * called from the compilationChecker object, not from this + */ + protected Class checkerClass; + + /** + * Compilation Checker object. + */ + protected Object compilationChecker; + + + /** + * List of jar files to be present in compilation checker's classpath + */ + protected ArrayList classpathJars; + + /** + * Timestamp - for measuring total overhead + */ + private long lastTimeStamp = System.currentTimeMillis(); + + /** + * Used for displaying the rotating slash on the Problem Window title bar + */ + private String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--", + "\\" }; + private int slashAnimationIndex = 0; + + /** + * Used to detect if the current tab index has changed and thus repaint the + * textarea. + */ + public int currentTab = 0, lastTab = 0; + + /** + * Stores the current import statements in the program. Used to compare for + * changed import statements and update classpath if needed. + */ + protected ArrayList programImports; + + /** + * List of imports when sketch was last checked. Used for checking for + * changed imports + */ + protected ArrayList previousImports = new ArrayList(); + + /** + * Teh Preprocessor + */ + protected XQPreprocessor xqpreproc; + + /** + * Regexp for import statements. (Used from Processing source) + */ + final public String importRegexp = "(?:^|;)\\s*(import\\s+)((?:static\\s+)?\\S+)(\\s*;)"; + + /** + * Regexp for function declarations. (Used from Processing source) + */ + final Pattern FUNCTION_DECL = Pattern + .compile("(^|;)\\s*((public|private|protected|final|static)\\s+)*" + + "(void|int|float|double|String|char|byte)" + + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(", Pattern.MULTILINE); + + public ErrorCheckerService(DebugEditor debugEditor) { + this.editor = debugEditor; + initParser(); + initializeErrorWindow(); + xqpreproc = new XQPreprocessor(); + PdePreprocessor pdePrepoc = new PdePreprocessor(null); + defaultImportsOffset = pdePrepoc.getCoreImports().length + + pdePrepoc.getDefaultImports().length + 1; + astGenerator = new ASTGenerator(this); + } + + /** + * Initializes ASTParser + */ + private void initParser() { + try { + parser = ASTParser.newParser(AST.JLS4); + } catch (Exception e) { + System.err.println("Experimental Mode initialization failed. " + + "Are you running the right version of Processing? "); + pauseThread(); + } catch (Error e) { + System.err.println("Experimental Mode initialization failed. "); + e.printStackTrace(); + pauseThread(); + } + } + + /** + * Initialiazes the Error Window + */ + public void initializeErrorWindow() { + + if (editor == null) { + return; + } + + if (errorWindow != null) { + return; + } + + final ErrorCheckerService thisService = this; + final DebugEditor thisEditor = editor; + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + errorWindow = new ErrorWindow(thisEditor, thisService); + // errorWindow.setVisible(true); + editor.toFront(); + errorWindow.errorTable.setFocusable(false); + editor.setSelection(0, 0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + public void run() { + stopThread = false; + + checkCode(); + while (!stopThread) { + try { + // Take a nap. + Thread.sleep(sleepTime); + } catch (Exception e) { + System.out.println("Oops! [ErrorCheckerThreaded]: " + e); + // e.printStackTrace(); + } + + updatePaintedThingys(); + + if (pauseThread) + continue; + if(textModified.get() == 0) + continue; + // Check every x seconds + checkCode(); + + } + } + + protected ASTGenerator astGenerator; + AtomicInteger textModified = new AtomicInteger(); + private boolean checkCode() { + System.out.println("checkCode() " + textModified.get() ); + lastTimeStamp = System.currentTimeMillis(); + try { + sourceCode = preprocessCode(editor.getSketch().getMainProgram()); + + syntaxCheck(); + System.out.println(editor.getSketch().getName() + "1 MCO " + + mainClassOffset); + // No syntax errors, proceed for compilation check, Stage 2. + + if (problems.length == 0 && editor.compilationCheckEnabled) { + //mainClassOffset++; // just a hack. + astGenerator.buildAST(cu); + sourceCode = xqpreproc.doYourThing(sourceCode, programImports); + prepareCompilerClasspath(); +// mainClassOffset = xqpreproc.mainClassOffset; // tiny, but +// // significant +// if (staticMode) { +// mainClassOffset++; // Extra line for setup() decl. +// } + // System.out.println(sourceCode); + // System.out.println("--------------------------"); + compileCheck(); + System.out.println(editor.getSketch().getName() + "2 MCO " + + mainClassOffset); + } + + updateErrorTable(); + editor.updateErrorBar(problemsList); + updateEditorStatus(); + updatePaintedThingys(); + int x = textModified.get(); + //System.out.println("TM " + x); + if(x>=3){ + textModified.set(3); + x = 3; + } + + if(x>0) + textModified.set(x - 1); + else + textModified.set(0); + return true; + + } catch (Exception e) { + System.out.println("Oops! [ErrorCheckerService.checkCode]: " + e); + e.printStackTrace(); + } + return false; + } + + private void syntaxCheck() { + parser.setSource(sourceCode.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + @SuppressWarnings("unchecked") + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + cu = (CompilationUnit) parser.createAST(null); + + // Store errors returned by the ast parser + problems = cu.getProblems(); + // System.out.println("Problem Count: " + problems.length); + // Populate the probList + problemsList = new ArrayList(); + for (int i = 0; i < problems.length; i++) { + int a[] = calculateTabIndexAndLineNumber(problems[i]); + Problem p = new Problem(problems[i], a[0], a[1]); + problemsList.add(p); + // System.out.println(p.toString()); + } + } + protected URLClassLoader classLoader; + private void compileCheck() { + + // Currently (Sept, 2012) I'm using Java's reflection api to load the + // CompilationChecker class(from CompilationChecker.jar) that houses the + // Eclispe JDT compiler and call its getErrorsAsObj method to obtain + // errors. This way, I'm able to add the paths of contributed libraries + // to the classpath of CompilationChecker, dynamically. The eclipse compiler + // needs all referenced libraries in the classpath. + + try { + + // NOTE TO SELF: If classpath contains null Strings + // URLClassLoader gets angry. Drops NPE bombs. + + // If imports have changed, reload classes with new classpath. + if (loadCompClass) { + + // if (classpathJars.size() > 0) + // System.out + // .println("Experimental Mode: Loading contributed libraries referenced by import statements."); + + File f = Base.getContentFile("modes" + File.separator + "experimental" + + File.separator + "mode"); + + if(!f.exists()) { + System.err.println("Could not locate the files required for on-the-fly error checking. Bummer."); + return; + } + + FileFilter fileFilter = new FileFilter() { + public boolean accept(File file) { + return (file.getName().endsWith(".jar") && !file + .getName().startsWith("experimental")); + } + }; + + File[] jarFiles = f.listFiles(fileFilter); + // System.out.println( "Jar files found? " + (jarFiles != null)); + //for (File jarFile : jarFiles) { + //classpathJars.add(jarFile.toURI().toURL()); + //} + + classpath = new URL[classpathJars.size() + jarFiles.length]; + int ii = 0; + for (; ii < classpathJars.size(); ii++) { + classpath[ii] = classpathJars.get(ii); + } + for (int i = 0; i < jarFiles.length; i++) { + classpath[ii++] = jarFiles[i].toURI().toURL(); + } + + // System.out.println("CP Len -- " + classpath.length); + classLoader = new URLClassLoader(classpath); + // System.out.println("1."); + checkerClass = Class.forName("CompilationChecker", true, + classLoader); + // System.out.println("2."); + compilationChecker = checkerClass.newInstance(); + + astGenerator.loadJars(); // Update jar files for completition list + loadCompClass = false; + } + + if (compilerSettings == null) { + prepareCompilerSetting(); + } + Method getErrors = checkerClass.getMethod("getErrorsAsObjArr", + new Class[] { String.class, String.class, Map.class }); + + Object[][] errorList = (Object[][]) getErrors + .invoke(compilationChecker, className, sourceCode, + compilerSettings); + + if (errorList == null) { + return; + } + + problems = new DefaultProblem[errorList.length]; + + for (int i = 0; i < errorList.length; i++) { + + // for (int j = 0; j < errorList[i].length; j++) + // System.out.print(errorList[i][j] + ", "); + + problems[i] = new DefaultProblem((char[]) errorList[i][0], + (String) errorList[i][1], + ((Integer) errorList[i][2]).intValue(), + (String[]) errorList[i][3], + ((Integer) errorList[i][4]).intValue(), + ((Integer) errorList[i][5]).intValue(), + ((Integer) errorList[i][6]).intValue(), + ((Integer) errorList[i][7]).intValue(), 0); + + // System.out + // .println("ECS: " + problems[i].getMessage() + "," + // + problems[i].isError() + "," + // + problems[i].isWarning()); + + IProblem problem = problems[i]; + + int a[] = calculateTabIndexAndLineNumber(problem); + Problem p = new Problem(problem, a[0], a[1]); + if ((Boolean) errorList[i][8]) { + p.setType(Problem.ERROR); + } + + if ((Boolean) errorList[i][9]) { + p.setType(Problem.WARNING); + } + + // If warnings are disabled, skip 'em + if (p.isWarning() && !warningsEnabled) { + continue; + } + problemsList.add(p); + } + + } catch (ClassNotFoundException e) { + System.err.println("Compiltation Checker files couldn't be found! " + + e + " compileCheck() problem."); + stopThread(); + } catch (MalformedURLException e) { + System.err.println("Compiltation Checker files couldn't be found! " + + e + " compileCheck() problem."); + stopThread(); + } catch (Exception e) { + System.err.println("compileCheck() problem." + e); + e.printStackTrace(); + stopThread(); + } catch (NoClassDefFoundError e) { + System.err + .println(e + + " compileCheck() problem. Somebody tried to mess with Experimental Mode files."); + stopThread(); + } + // System.out.println("Compilecheck, Done."); + } + + /** + * Processes import statements to obtain classpaths of contributed + * libraries. This would be needed for compilation check. Also, adds + * stuff(jar files, class files, candy) from the code folder. And it looks + * messed up. + * + */ + private void prepareCompilerClasspath() { + if (!loadCompClass) { + return; + } + + // System.out.println("1.."); + classpathJars = new ArrayList(); + String entry = ""; + boolean codeFolderChecked = false; + for (ImportStatement impstat : programImports) { + String item = impstat.importName; + int dot = item.lastIndexOf('.'); + entry = (dot == -1) ? item : item.substring(0, dot); + + entry = entry.substring(6).trim(); + // System.out.println("Entry--" + entry); + if (ignorableImport(entry)) { + // System.out.println("Ignoring: " + entry); + continue; + } + Library library = null; + + // Try to get the library classpath and add it to the list + try { + library = editor.getMode().getLibrary(entry); + // System.out.println("lib->" + library.getClassPath() + "<-"); + String libraryPath[] = PApplet.split(library.getClassPath() + .substring(1).trim(), File.pathSeparatorChar); + for (int i = 0; i < libraryPath.length; i++) { + // System.out.println(entry + " ::" + // + new File(libraryPath[i]).toURI().toURL()); + classpathJars.add(new File(libraryPath[i]).toURI().toURL()); + } + // System.out.println("-- "); + // classpath[count] = (new File(library.getClassPath() + // .substring(1))).toURI().toURL(); + // System.out.println(" found "); + // System.out.println(library.getClassPath().substring(1)); + } catch (Exception e) { + if (library == null && !codeFolderChecked) { + // System.out.println(1); + // Look around in the code folder for jar files + if (editor.getSketch().hasCodeFolder()) { + File codeFolder = editor.getSketch().getCodeFolder(); + + // get a list of .jar files in the "code" folder + // (class files in subfolders should also be picked up) + String codeFolderClassPath = Base + .contentsToClassPath(codeFolder); + codeFolderChecked = true; + if (codeFolderClassPath.equalsIgnoreCase("")) { + System.err.println("Experimental Mode: Yikes! Can't find \"" + + entry + + "\" library! Line: " + + impstat.lineNumber + + " in tab: " + + editor.getSketch().getCode(impstat.tab) + .getPrettyName()); + System.out + .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); + + } + String codeFolderPath[] = PApplet.split( + codeFolderClassPath.substring(1).trim(), + File.pathSeparatorChar); + try { + for (int i = 0; i < codeFolderPath.length; i++) { + classpathJars.add(new File(codeFolderPath[i]) + .toURI().toURL()); + } + + } catch (Exception e2) { + System.out + .println("Yikes! codefolder, prepareImports(): " + + e2); + } + } else { + System.err.println("Experimental Mode: Yikes! Can't find \"" + + entry + + "\" library! Line: " + + impstat.lineNumber + + " in tab: " + + editor.getSketch().getCode(impstat.tab) + .getPrettyName()); + System.out + .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); + } + + } else { + System.err + .println("Yikes! There was some problem in prepareImports(): " + + e); + System.err.println("I was processing: " + entry); + + // e.printStackTrace(); + } + } + + } + + } + + /** + * Ignore processing packages, java.*.*. etc. + * + * @param packageName + * @return boolean + */ + protected boolean ignorableImport(String packageName) { + // packageName.startsWith("processing.") + // || + if (packageName.startsWith("java.") || packageName.startsWith("javax.")) { + return true; + } + return false; + } + + /** + * Various option for JDT Compiler + */ + @SuppressWarnings("rawtypes") + protected Map compilerSettings; + + /** + * Enable/Disable warnings from being shown + */ + public boolean warningsEnabled = true; + + /** + * Sets compiler options for JDT Compiler + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected void prepareCompilerSetting() { + compilerSettings = new HashMap(); + + compilerSettings.put(CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.GENERATE); + compilerSettings.put(CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.GENERATE); + compilerSettings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_6); + compilerSettings.put(CompilerOptions.OPTION_ReportUnusedImport, + CompilerOptions.IGNORE); + compilerSettings.put(CompilerOptions.OPTION_ReportMissingSerialVersion, + CompilerOptions.IGNORE); + compilerSettings.put(CompilerOptions.OPTION_ReportRawTypeReference, + CompilerOptions.IGNORE); + compilerSettings.put( + CompilerOptions.OPTION_ReportUncheckedTypeOperation, + CompilerOptions.IGNORE); + } + + + /** + * Updates the error table in the Error Window. + */ + synchronized public void updateErrorTable() { + + try { + String[][] errorData = new String[problemsList.size()][3]; + for (int i = 0; i < problemsList.size(); i++) { + errorData[i][0] = problemsList.get(i).message; + errorData[i][1] = editor.getSketch() + .getCode(problemsList.get(i).tabIndex).getPrettyName(); + errorData[i][2] = problemsList.get(i).lineNumber + ""; + } + + if (errorWindow != null) { + DefaultTableModel tm = new DefaultTableModel(errorData, + XQErrorTable.columnNames); + if (errorWindow.isVisible()) { + errorWindow.updateTable(tm); + } + + // Update error table in the editor + editor.updateTable(tm); + + // A rotating slash animation on the title bar to show + // that error checker thread is running + + slashAnimationIndex++; + if (slashAnimationIndex == slashAnimation.length) { + slashAnimationIndex = 0; + } + if (editor != null) { + String info = slashAnimation[slashAnimationIndex] + " T:" + + (System.currentTimeMillis() - lastTimeStamp) + + "ms"; + errorWindow.setTitle("Problems - " + + editor.getSketch().getName() + " " + info); + } + } + + } catch (Exception e) { + System.out.println("Exception at updateErrorTable() " + e); + e.printStackTrace(); + stopThread(); + } + + } + + /** + * Repaints the textarea if required + */ + public void updatePaintedThingys() { + editor.getTextArea().repaint(); + updateEditorStatus(); + currentTab = editor.getSketch().getCodeIndex( + editor.getSketch().getCurrentCode()); + //System.out.println("awesome! " + currentTab + " LT " + lastTab); + if (currentTab != lastTab) { + textModified.incrementAndGet(); + lastTab = currentTab; + return; + } + + } + + /** + * Updates editor status bar, depending on whether the caret is on an error + * line or not + */ + public void updateEditorStatus() { + // editor.statusNotice("Position: " + + // editor.getTextArea().getCaretLine()); + boolean notFound = true; + for (ErrorMarker emarker : editor.errorBar.errorPoints) { + if (emarker.problem.lineNumber == editor.getTextArea() + .getCaretLine() + 1) { + if (emarker.type == ErrorMarker.Warning) { + editor.statusNotice(emarker.problem.message); + } + else { + editor.statusError(emarker.problem.message); + } + return; + } + } + if (notFound) { + editor.statusEmpty(); + } + } + + /** + * Maps offset from java code to pde code. Returns a bunch of offsets as array + * + * @param line + * - line number in java code + * @param offset + * - offset from the start of the 'line' + * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] + * - line start offset, int[3] - offset from line start. int[2] and + * int[3] are on TODO + */ + public int[] JavaToPdeOffsets(int line, int offset){ + int codeIndex = 0; + + int x = line - mainClassOffset; + if (x < 0) { + // System.out.println("Negative line number " + // + problem.getSourceLineNumber() + " , offset " + // + mainClassOffset); + x = line - 2; // Another -1 for 0 index + if (x < programImports.size() && x >= 0) { + ImportStatement is = programImports.get(x); + // System.out.println(is.importName + ", " + is.tab + ", " + // + is.lineNumber); + return new int[] { is.tab, is.lineNumber }; + } else { + + // Some seriously ugly stray error, just can't find the source + // line! Simply return first line for first tab. + return new int[] { 0, 1 }; + } + + } + + try { + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + int len = 0; + if (editor.getSketch().getCurrentCode().equals(sc)) { + len = Base.countLines(sc.getDocument().getText(0, + sc.getDocument().getLength())) + 1; + } else { + len = Base.countLines(sc.getProgram()) + 1; + } + + // System.out.println("x,len, CI: " + x + "," + len + "," + // + codeIndex); + + if (x >= len) { + + // We're in the last tab and the line count is greater + // than the no. + // of lines in the tab, + if (codeIndex >= editor.getSketch().getCodeCount() - 1) { + // System.out.println("Exceeds lc " + x + "," + len + // + problem.toString()); + // x = len + x = editor.getSketch().getCode(codeIndex) + .getLineCount(); + // TODO: Obtain line having last non-white space + // character in the code. + break; + } else { + x -= len; + codeIndex++; + } + } else { + + if (codeIndex >= editor.getSketch().getCodeCount()) { + codeIndex = editor.getSketch().getCodeCount() - 1; + } + break; + } + + } + } + } catch (Exception e) { + System.err + .println("Things got messed up in ErrorCheckerService.JavaToPdeOffset()"); + } + return new int[] { codeIndex, x }; + } + + public String getPDECodeAtLine(int tab, int linenumber){ + editor.getSketch().setCurrentCode(tab); + return editor.ta.getLineText(linenumber); + } + + /** + * Calculates the tab number and line number of the error in that particular + * tab. Provides mapping between pure java and pde code. + * + * @param problem + * - IProblem + * @return int[0] - tab number, int[1] - line number + */ + public int[] calculateTabIndexAndLineNumber(IProblem problem) { + // String[] lines = {};// = PApplet.split(sourceString, '\n'); + int codeIndex = 0; + + int x = problem.getSourceLineNumber() - mainClassOffset; + if (x < 0) { + // System.out.println("Negative line number " + // + problem.getSourceLineNumber() + " , offset " + // + mainClassOffset); + x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index + if (x < programImports.size() && x >= 0) { + ImportStatement is = programImports.get(x); + // System.out.println(is.importName + ", " + is.tab + ", " + // + is.lineNumber); + return new int[] { is.tab, is.lineNumber }; + } else { + + // Some seriously ugly stray error, just can't find the source + // line! Simply return first line for first tab. + return new int[] { 0, 1 }; + } + + } + + try { + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + int len = 0; + if (editor.getSketch().getCurrentCode().equals(sc)) { + len = Base.countLines(sc.getDocument().getText(0, + sc.getDocument().getLength())) + 1; + } else { + len = Base.countLines(sc.getProgram()) + 1; + } + + // System.out.println("x,len, CI: " + x + "," + len + "," + // + codeIndex); + + if (x >= len) { + + // We're in the last tab and the line count is greater + // than the no. + // of lines in the tab, + if (codeIndex >= editor.getSketch().getCodeCount() - 1) { + // System.out.println("Exceeds lc " + x + "," + len + // + problem.toString()); + // x = len + x = editor.getSketch().getCode(codeIndex) + .getLineCount(); + // TODO: Obtain line having last non-white space + // character in the code. + break; + } else { + x -= len; + codeIndex++; + } + } else { + + if (codeIndex >= editor.getSketch().getCodeCount()) { + codeIndex = editor.getSketch().getCodeCount() - 1; + } + break; + } + + } + } + } catch (Exception e) { + System.err + .println("Things got messed up in ErrorCheckerService.calculateTabIndexAndLineNumber()"); + } + + return new int[] { codeIndex, x }; + } + + /** + * Fetches code from the editor tabs and pre-processes it into parsable pure + * java source. And there's a difference between parsable and compilable. + * XQPrerocessor.java makes this code compilable.
    + * Handles:
  • Removal of import statements
  • Conversion of int(), + * char(), etc to PApplet.parseInt(), etc.
  • Replacing '#' with 0xff for + * color representation
  • Converts all 'color' datatypes to int + * (experimental)
  • Appends class declaration statement after determining + * the mode the sketch is in - ACTIVE or STATIC + * + * @return String - Pure java representation of PDE code. Note that this + * code is not yet compile ready. + */ + + private String preprocessCode(String pdeCode) { + + programImports = new ArrayList(); + + StringBuffer rawCode = new StringBuffer(); + + try { + + for (SketchCode sc : editor.getSketch().getCode()) { + if (sc.isExtension("pde")) { + + try { + + if (editor.getSketch().getCurrentCode().equals(sc)) { + + rawCode.append(scrapImportStatements(sc.getDocument() + .getText(0, + sc.getDocument() + .getLength()), + editor.getSketch() + .getCodeIndex(sc))); + } else { + + rawCode.append(scrapImportStatements(sc.getProgram(), editor + .getSketch().getCodeIndex(sc))); + + } + rawCode.append('\n'); + } catch (Exception e) { + System.err.println("Exception in preprocessCode() - bigCode " + + e.toString()); + } + rawCode.append('\n'); + } + } + + } catch (Exception e) { + System.out.println("Exception in preprocessCode()"); + } + String sourceAlt = rawCode.toString(); + // Replace comments with whitespaces + // sourceAlt = scrubComments(sourceAlt); + + // Find all int(*), replace with PApplet.parseInt(*) + + // \bint\s*\(\s*\b , i.e all exclusive "int(" + + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(sourceAlt); + + // while (matcher.find()) { + // System.out.print("Start index: " + matcher.start()); + // System.out.println(" End index: " + matcher.end() + " "); + // System.out.println("-->" + matcher.group() + "<--"); + // } + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + + dataType.substring(1) + "("); + + } + + // Find all #[web color] and replace with 0xff[webcolor] + // Should be 6 digits only. + final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; + Pattern webPattern = Pattern.compile(webColorRegexp); + Matcher webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = sourceAlt.substring(webMatcher.start(), + webMatcher.end()); + // System.out.println("-> " + found); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + } + + // Replace all color data types with int + // Regex, Y U SO powerful? + final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; + Pattern colorPattern = Pattern.compile(colorTypeRegex); + Matcher colorMatcher = colorPattern.matcher(sourceAlt); + sourceAlt = colorMatcher.replaceAll("int"); + + checkForChangedImports(); + + className = (editor == null) ? "DefaultClass" : editor.getSketch() + .getName(); + + + // Check whether the code is being written in STATIC mode(no function + // declarations) - append class declaration and void setup() declaration + Matcher matcher = FUNCTION_DECL.matcher(sourceAlt); + if (!matcher.find()) { + sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" + + "public void setup() {\n" + sourceAlt + + "\nnoLoop();\n}\n" + "\n}\n"; + staticMode = true; + + } else { + sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" + + sourceAlt + "\n}"; + staticMode = false; + } + + int position = sourceAlt.indexOf("{") + 1; + mainClassOffset = 1; + for (int i = 0; i <= position; i++) { + if (sourceAlt.charAt(i) == '\n') { + mainClassOffset++; + } + } + if(staticMode) { + mainClassOffset++; + } + //mainClassOffset += 2; + // Handle unicode characters + sourceAlt = substituteUnicode(sourceAlt); + +// System.out.println("-->\n" + sourceAlt + "\n<--"); +// System.out.println("PDE code processed - " +// + editor.getSketch().getName()); + sourceCode = sourceAlt; + return sourceAlt; + + } + + /** + * The super method that highlights any ASTNode in the pde editor =D + * @param node + * @return true - if highlighting happened correctly. + */ + public boolean highlightNode(ASTNodeWrapper awrap){ + int pdeoffsets[] = awrap.getPDECodeOffsets(this); + int javaoffsets[] = awrap.getJavaCodeOffsets(this); + try { + scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1],javaoffsets[1], + javaoffsets[2]); + return true; + } catch (Exception e) { + + e.printStackTrace(); + } + return false; + } + + public boolean highlightNode(ASTNode node){ + ASTNodeWrapper awrap = new ASTNodeWrapper(node); + return highlightNode(awrap); + } + + /** + * Scrolls to the error source in code. And selects the line text. Used by + * XQErrorTable and ErrorBar + * + * @param errorIndex + * - index of error + */ + public void scrollToErrorLine(int errorIndex) { + if (editor == null) { + return; + } + + if (errorIndex < problemsList.size() && errorIndex >= 0) { + Problem p = problemsList.get(errorIndex); + scrollToErrorLine(p); + } + } + + public void scrollToErrorLine(Problem p) { + if (editor == null) { + return; + } + if (p == null) + return; + try { + editor.toFront(); + editor.getSketch().setCurrentCode(p.tabIndex); + + editor + .setSelection(editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) + + editor.getTextArea() + .getLineText(p.lineNumber - 1).trim().length(), + editor.getTextArea() + .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); + editor.getTextArea().scrollTo(p.lineNumber - 1, 0); + editor.repaint(); + } catch (Exception e) { + System.err.println(e + + " : Error while selecting text in scrollToErrorLine()"); + e.printStackTrace(); + } + // System.out.println("---"); + } + + /** + * Static method for scroll to a particular line in the PDE. Also highlights + * the length of the text. Requires the editor instance as arguement. + * + * @param edt + * @param tabIndex + * @param lineNoInTab + * - line number in the corresponding tab + * @param lineStartOffset + * - selection start offset(from line start non-whitespace offset) + * @param length + * - length of selection + * @return - true, if scroll was successful + */ + public static boolean scrollToErrorLine(Editor edt, int tabIndex, int lineNoInTab, int lineStartOffset, int length) { + if (edt == null) { + return false; + } + try { + edt.toFront(); + edt.getSketch().setCurrentCode(tabIndex); + int lsno = edt.getTextArea() + .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1) + lineStartOffset; + edt.setSelection(lsno, lsno + length); + edt.getTextArea().scrollTo(lineNoInTab - 1, 0); + edt.repaint(); + System.out.println(lineStartOffset + " LSO,len " + length); + } catch (Exception e) { + System.err.println(e + + " : Error while selecting text in static scrollToErrorLine()"); + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Checks if import statements in the sketch have changed. If they have, + * compiler classpath needs to be updated. + */ + private void checkForChangedImports() { + // System.out.println("Imports: " + programImports.size() + + // " Prev Imp: " + // + previousImports.size()); + if (programImports.size() != previousImports.size()) { + // System.out.println(1); + loadCompClass = true; + previousImports = programImports; + } else { + for (int i = 0; i < programImports.size(); i++) { + if (!programImports.get(i).importName.equals(previousImports + .get(i).importName)) { + // System.out.println(2); + loadCompClass = true; + previousImports = programImports; + break; + } + } + } + // System.out.println("load..? " + loadCompClass); + } + + /** + * Removes import statements from tabSource, replaces each with white spaces + * and adds the import to the list of program imports + * + * @param tabProgram + * - Code in a tab + * @param tabNumber + * - index of the tab + * @return String - Tab code with imports replaced with white spaces + */ + private String scrapImportStatements(String tabProgram, int tabNumber) { + //TODO: Commented out imports are still detected as main imports. + String tabSource = new String(tabProgram); + do { + // System.out.println("-->\n" + sourceAlt + "\n<--"); + String[] pieces = PApplet.match(tabSource, importRegexp); + + // Stop the loop if we've removed all the import lines + if (pieces == null) { + break; + } + + String piece = pieces[1] + pieces[2] + pieces[3]; + int len = piece.length(); // how much to trim out + + // programImports.add(piece); // the package name + + // find index of this import in the program + int idx = tabSource.indexOf(piece); + // System.out.print("Import -> " + piece); + // System.out.println(" - " + // + Base.countLines(tabSource.substring(0, idx)) + " tab " + // + tabNumber); + programImports.add(new ImportStatement(piece, tabNumber, Base + .countLines(tabSource.substring(0, idx)))); + // Remove the import from the main program + // Substitute with white spaces + String whiteSpace = ""; + for (int j = 0; j < piece.length(); j++) { + whiteSpace += " "; + } + tabSource = tabSource.substring(0, idx) + whiteSpace + + tabSource.substring(idx + len); + + } while (true); + // System.out.println(tabSource); + return tabSource; + } + + /** + * Replaces non-ascii characters with their unicode escape sequences and + * stuff. Used as it is from + * processing.src.processing.mode.java.preproc.PdePreprocessor + * + * @param program + * - Input String containing non ascii characters + * @return String - Converted String + */ + public static String substituteUnicode(String program) { + // check for non-ascii chars (these will be/must be in unicode format) + char p[] = program.toCharArray(); + int unicodeCount = 0; + for (int i = 0; i < p.length; i++) { + if (p[i] > 127) { + unicodeCount++; + } + } + if (unicodeCount == 0) { + return program; + } + // if non-ascii chars are in there, convert to unicode escapes + // add unicodeCount * 5.. replacing each unicode char + // with six digit uXXXX sequence (xxxx is in hex) + // (except for nbsp chars which will be a replaced with a space) + int index = 0; + char p2[] = new char[p.length + unicodeCount * 5]; + for (int i = 0; i < p.length; i++) { + if (p[i] < 128) { + p2[index++] = p[i]; + } else if (p[i] == 160) { // unicode for non-breaking space + p2[index++] = ' '; + } else { + int c = p[i]; + p2[index++] = '\\'; + p2[index++] = 'u'; + char str[] = Integer.toHexString(c).toCharArray(); + // add leading zeros, so that the length is 4 + // for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0'; + for (int m = 0; m < 4 - str.length; m++) + p2[index++] = '0'; + System.arraycopy(str, 0, p2, index, str.length); + index += str.length; + } + } + return new String(p2, 0, index); + } + + /** + * Stops the Error Checker Service thread + */ + public void stopThread() { + stopThread = true; + } + + /** + * Pauses the Error Checker Service thread + */ + public void pauseThread() { + pauseThread = true; + } + + /** + * Resumes the Error Checker Service thread + */ + public void resumeThread() { + pauseThread = false; + } + + public DebugEditor getEditor() { + return editor; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorMarker.java b/pdex/experimental/src/processing/mode/experimental/ErrorMarker.java new file mode 100755 index 000000000..0a10cff4b --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ErrorMarker.java @@ -0,0 +1,36 @@ +package processing.mode.experimental; +/** + * Error markers displayed on the Error Bar. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ + public class ErrorMarker { + /** + * y co-ordinate of the marker + */ + public int y; + /** + * Type of marker: Error or Warning? + */ + public int type = -1; + /** + * Error Type constant + */ + public static final int Error = 1; + /** + * Warning Type constant + */ + public static final int Warning = 2; + /** + * Problem that the error marker represents + * @see Problem + */ + public Problem problem; + + public ErrorMarker(Problem problem, int y, int type) { + this.problem = problem; + this.y = y; + this.type = type; + } + } \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorWindow.java b/pdex/experimental/src/processing/mode/experimental/ErrorWindow.java new file mode 100755 index 000000000..6494b58ed --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ErrorWindow.java @@ -0,0 +1,374 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.experimental; + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.WindowConstants; +import javax.swing.border.EmptyBorder; +import javax.swing.table.TableModel; + +import processing.app.Editor; +import processing.app.Toolkit; + +/** + * Error Window that displays a tablular list of errors. Clicking on an error + * scrolls to its location in the code. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class ErrorWindow extends JFrame { + + private JPanel contentPane; + /** + * The table displaying the errors + */ + protected XQErrorTable errorTable; + /** + * Scroll pane that contains the Error Table + */ + protected JScrollPane scrollPane; + + protected DebugEditor thisEditor; + private JFrame thisErrorWindow; + + /** + * Handles the sticky Problem window + */ + private DockTool2Base Docker; + + protected ErrorCheckerService errorCheckerService; + + /** + * Preps up ErrorWindow + * + * @param editor + * - Editor + * @param ecs - ErrorCheckerService + */ + public ErrorWindow(DebugEditor editor, ErrorCheckerService ecs) { + thisErrorWindow = this; + errorCheckerService = ecs; + thisEditor = editor; + setTitle("Problems"); + prepareFrame(); + } + + /** + * Sets up ErrorWindow + */ + protected void prepareFrame() { + Toolkit.setIcon(this); + setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + // Default size: setBounds(100, 100, 458, 160); + setBounds(100, 100, 458, 160); // Yeah, I hardcode such things sometimes. Hate me. + + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(new BorderLayout(0, 0)); + + scrollPane = new JScrollPane(); + contentPane.add(scrollPane); + + errorTable = new XQErrorTable(errorCheckerService); + scrollPane.setViewportView(errorTable); + + try { + Docker = new DockTool2Base(); + addListeners(); + } catch (Exception e) { + System.out.println("addListeners() acted silly."); + e.printStackTrace(); + } + + if (thisEditor != null) { + setLocation(new Point(thisEditor.getLocation().x + + thisEditor.getWidth(), thisEditor.getLocation().y)); + } + + } + + /** + * Updates the error table with new data(Table Model). Called from Error + * Checker Service. + * + * @param tableModel + * - Table Model + * @return True - If error table was updated successfully. + */ + synchronized public boolean updateTable(final TableModel tableModel) { + // XQErrorTable handles evrything now + return errorTable.updateTable(tableModel); + } + + /** + * Adds various listeners to components of EditorWindow and to the Editor + * window + */ + protected void addListeners() { + + if (thisErrorWindow == null) + System.out.println("ERW null"); + + thisErrorWindow.addComponentListener(new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + + } + + @Override + public void componentResized(ComponentEvent e) { + Docker.tryDocking(); + } + + @Override + public void componentMoved(ComponentEvent e) { + Docker.tryDocking(); + } + + @Override + public void componentHidden(ComponentEvent e) { + + } + }); + + thisErrorWindow.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + thisEditor.problemWindowMenuCB.setSelected(false); + } + + @Override + public void windowDeiconified(WindowEvent e) { + thisEditor.setExtendedState(Frame.NORMAL); + } + + }); + + if (thisEditor == null) { + System.out.println("Editor null"); + return; + } + + thisEditor.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + + } + + @Override + public void windowClosed(WindowEvent e) { + errorCheckerService.pauseThread(); + errorCheckerService.stopThread(); // Bye bye thread. + thisErrorWindow.dispose(); + } + + @Override + public void windowIconified(WindowEvent e) { + thisErrorWindow.setExtendedState(Frame.ICONIFIED); + } + + @Override + public void windowDeiconified(WindowEvent e) { + thisErrorWindow.setExtendedState(Frame.NORMAL); + } + + }); + + thisEditor.addComponentListener(new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + + } + + @Override + public void componentResized(ComponentEvent e) { + if (Docker.isDocked()) { + Docker.dock(); + } else { + Docker.tryDocking(); + } + } + + @Override + public void componentMoved(ComponentEvent e) { + + if (Docker.isDocked()) { + Docker.dock(); + } else { + Docker.tryDocking(); + } + + } + + @Override + public void componentHidden(ComponentEvent e) { + // System.out.println("ed hidden"); + } + }); + + } + + + /** + * Implements the docking feature of the tool - The frame sticks to the + * editor and once docked, moves along with it as the editor is resized, + * moved, or closed. + * + * This class has been borrowed from Tab Manager tool by Thomas Diewald. It + * has been slightly modified and used here. + * + * @author Thomas Diewald , http://thomasdiewald.com + */ + private class DockTool2Base { + + private int docking_border = 0; + private int dock_on_editor_y_offset_ = 0; + private int dock_on_editor_x_offset_ = 0; + + // /////////////////////////////// + // ____2____ + // | | + // | | + // 0 | editor | 1 + // | | + // |_________| + // 3 + // /////////////////////////////// + + // public void reset() { + // dock_on_editor_y_offset_ = 0; + // dock_on_editor_x_offset_ = 0; + // docking_border = 0; + // } + + public boolean isDocked() { + return (docking_border >= 0); + } + + private final int MAX_GAP_ = 20; + + // + public void tryDocking() { + if (thisEditor == null) + return; + Editor editor = thisEditor; + Frame frame = thisErrorWindow; + + int ex = editor.getX(); + int ey = editor.getY(); + int ew = editor.getWidth(); + int eh = editor.getHeight(); + + int fx = frame.getX(); + int fy = frame.getY(); + int fw = frame.getWidth(); + int fh = frame.getHeight(); + + if (((fy > ey) && (fy < ey + eh)) + || ((fy + fh > ey) && (fy + fh < ey + eh))) { + int dis_border_left = Math.abs(ex - (fx + fw)); + int dis_border_right = Math.abs((ex + ew) - (fx)); + + if (dis_border_left < MAX_GAP_ || dis_border_right < MAX_GAP_) { + docking_border = (dis_border_left < dis_border_right) ? 0 + : 1; + dock_on_editor_y_offset_ = fy - ey; + dock(); + return; + } + } + + if (((fx > ex) && (fx < ex + ew)) + || ((fx + fw > ey) && (fx + fw < ex + ew))) { + int dis_border_top = Math.abs(ey - (fy + fh)); + int dis_border_bot = Math.abs((ey + eh) - (fy)); + + if (dis_border_top < MAX_GAP_ || dis_border_bot < MAX_GAP_) { + docking_border = (dis_border_top < dis_border_bot) ? 2 : 3; + dock_on_editor_x_offset_ = fx - ex; + dock(); + return; + } + } + docking_border = -1; + } + + public void dock() { + if (thisEditor == null) + return; + Editor editor = thisEditor; + Frame frame = thisErrorWindow; + + int ex = editor.getX(); + int ey = editor.getY(); + int ew = editor.getWidth(); + int eh = editor.getHeight(); + + // int fx = frame.getX(); + // int fy = frame.getY(); + int fw = frame.getWidth(); + int fh = frame.getHeight(); + + int x = 0, y = 0; + if (docking_border == -1) { + return; + } + + if (docking_border == 0) { + x = ex - fw; + y = ey + dock_on_editor_y_offset_; + } + if (docking_border == 1) { + x = ex + ew; + y = ey + dock_on_editor_y_offset_; + } + + if (docking_border == 2) { + x = ex + dock_on_editor_x_offset_; + y = ey - fh; + } + if (docking_border == 3) { + x = ex + dock_on_editor_x_offset_; + y = ey + eh; + } + frame.setLocation(x, y); + } + + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java b/pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java new file mode 100755 index 000000000..50d7ce4b3 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java @@ -0,0 +1,171 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2012 The Processing Foundation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.mode.experimental; + +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import processing.app.Base; +import processing.app.Editor; +import processing.app.EditorState; +import processing.app.Mode; +import processing.mode.java.JavaMode; + + +/** + * Experimental Mode for Processing, combines Debug Mode and XQMode and + * starts us working toward our next generation editor/debugger setup. + */ +public class ExperimentalMode extends JavaMode { + public static final boolean VERBOSE_LOGGING = true; + //public static final boolean VERBOSE_LOGGING = false; + public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) + + + public ExperimentalMode(Base base, File folder) { + super(base, folder); + + // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus + for (Mode m : base.getModeList()) { + if (m.getClass() == JavaMode.class) { + JavaMode jMode = (JavaMode) m; + librariesFolder = jMode.getLibrariesFolder(); + rebuildLibraryList(); + break; + } + } + + // Fetch examples and reference from java mode + // thx to Manindra (https://github.com/martinleopold/DebugMode/issues/4) + examplesFolder = Base.getContentFile("modes/java/examples"); + // https://github.com/martinleopold/DebugMode/issues/6 + referenceFolder = Base.getContentFile("modes/java/reference"); + + // set logging level + Logger globalLogger = Logger.getLogger(""); + //Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // doesn't work on os x + if (VERBOSE_LOGGING) { + globalLogger.setLevel(Level.INFO); + } else { + globalLogger.setLevel(Level.WARNING); + } + + // enable logging to file + try { + // settings is writable for built-in modes, mode folder is not writable + File logFolder = Base.getSettingsFile("debug"); + if (!logFolder.exists()) { + logFolder.mkdir(); + } + File logFile = new File(logFolder, "DebugMode.%g.log"); + Handler handler = new FileHandler(logFile.getAbsolutePath(), LOG_SIZE, 10, false); + globalLogger.addHandler(handler); + + } catch (IOException ex) { + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); + } catch (SecurityException ex) { + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); + } + + // disable initial chattiness for now +// // output version from manifest file +// Package p = ExperimentalMode.class.getPackage(); +// String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; +// //System.out.println(titleAndVersion); +// Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); + } + + + @Override + public String getTitle() { + return "Experimental"; + } + + + public File[] getKeywordFiles() { + return new File[] { + Base.getContentFile("modes/java/keywords.txt") + }; + } + + + /** + * Create a new editor associated with this mode. + */ + @Override + public Editor createEditor(Base base, String path, EditorState state) { + return new DebugEditor(base, path, state, this); + } + + + /** + * Load a String value from theme.txt + * + * @param attribute the attribute key to load + * @param defaultValue the default value + * @return the attributes value, or the default value if the attribute + * couldn't be loaded + */ + public String loadThemeString(String attribute, String defaultValue) { + String newString = theme.get(attribute); + if (newString != null) { + return newString; + } + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Error loading String: {0}", attribute); + return defaultValue; + } + + + /** + * Load a Color value from theme.txt + * + * @param attribute the attribute key to load + * @param defaultValue the default value + * @return the attributes value, or the default value if the attribute + * couldn't be loaded + */ + public Color getThemeColor(String attribute, Color defaultValue) { + Color newColor = theme.getColor(attribute); + if (newColor != null) { + return newColor; + } + System.out.println("error loading color: " + attribute); + Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); + return defaultValue; + } + + + public ClassLoader getJavaModeClassLoader() { + for (Mode m : base.getModeList()) { + if (m.getClass() == JavaMode.class) { + JavaMode jMode = (JavaMode) m; + return jMode.getClassLoader(); + } + } + // badness + return null; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/FieldNode.java b/pdex/experimental/src/processing/mode/experimental/FieldNode.java new file mode 100755 index 000000000..dbe9d4fd9 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/FieldNode.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.Value; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Specialized {@link VariableNode} for representing fields. Overrides + * {@link #setValue} to properly change the value of the encapsulated field. + * + * @author Martin Leopold + */ +public class FieldNode extends VariableNode { + + protected Field field; + protected ObjectReference obj; + + /** + * Construct a {@link FieldNode}. + * + * @param name the name + * @param type the type + * @param value the value + * @param field the field + * @param obj a reference to the object containing the field + */ + public FieldNode(String name, String type, Value value, Field field, ObjectReference obj) { + super(name, type, value); + this.field = field; + this.obj = obj; + } + + @Override + public void setValue(Value value) { + try { + obj.setValue(field, value); + } catch (InvalidTypeException ex) { + Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotLoadedException ex) { + Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); + } + this.value = value; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/ImportStatement.java b/pdex/experimental/src/processing/mode/experimental/ImportStatement.java new file mode 100755 index 000000000..26d2db7d1 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/ImportStatement.java @@ -0,0 +1,57 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.experimental; + +/** + * Wrapper for import statements + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class ImportStatement { + /** + * Ex: processing.opengl.*, java.util.* + */ + String importName; + /** + * Which tab does it belong to? + */ + int tab; + + /** + * Line number(pde code) of the import + */ + int lineNumber; + + /** + * + * @param importName - Ex: processing.opengl.*, java.util.* + * @param tab - Which tab does it belong to? + * @param lineNumber - Line number(pde code) of the import + */ + public ImportStatement(String importName, int tab, int lineNumber) { + this.importName = importName; + this.tab = tab; + this.lineNumber = lineNumber; + } +} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/JavadocHelper.java b/pdex/experimental/src/processing/mode/experimental/JavadocHelper.java new file mode 100644 index 000000000..7cc582072 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/JavadocHelper.java @@ -0,0 +1,126 @@ +package processing.mode.experimental; + +import java.io.File; +import java.io.FileFilter; +import java.util.Iterator; +import java.util.TreeMap; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +public class JavadocHelper { + + public static void loadJavaDoc(TreeMap jdocMap, File p5Ref){ + Document doc; + + //Pattern pat = Pattern.compile("\\w+"); + try { + if (p5Ref == null) { + System.out.println("P5 Ref location null"); + p5Ref = new File( + "/home/quarkninja/Workspaces/processing-workspace/processing/build/linux/work/modes/java/reference"); + } + + FileFilter fileFilter = new FileFilter() { + public boolean accept(File file) { + if(!file.getName().endsWith("_.html")) + return false; + int k = 0; + for (int i = 0; i < file.getName().length(); i++) { + if(file.getName().charAt(i)== '_') + k++; + if(k > 1) + return false; + } + return true; + } + }; + + for (File docFile : p5Ref.listFiles(fileFilter)) { + + doc = Jsoup.parse(docFile, null); + Elements elm = doc.getElementsByClass("ref-item"); + String msg = ""; + String methodName = docFile.getName().substring(0, docFile.getName().indexOf('_')); + //System.out.println(methodName); + for (Iterator it = elm.iterator(); it.hasNext();) { + Element ele = (Element) it.next(); + msg = "
    " + + ele.html() + "
    "; + //mat.replaceAll(""); + msg = msg.replaceAll("img src=\"", "img src=\"" + + p5Ref.toURI().toURL().toString() + "/"); + //System.out.println(ele.text()); + } + jdocMap.put(methodName, msg); + } + System.out.println("JDoc loaded "+jdocMap.size()); + /* File javaDocFile = new File( + "/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html"); + //SimpleOpenNI.SimpleOpenNI + doc = Jsoup.parse(javaDocFile, null); + + String msg = ""; + Elements elm = doc.getElementsByTag("pre"); +// Elements desc = doc.getElementsByTag("dl"); + //System.out.println(elm.toString()); + + for (Iterator iterator = elm.iterator(); iterator.hasNext();) { + Element element = (Element) iterator.next(); + + //System.out.println(element.text()); +// if (element.nextElementSibling() != null) +// System.out.println(element.nextElementSibling().text()); + //System.out.println("-------------------"); + msg = "
    " + + element.html() + + element.nextElementSibling() + + "
    "; + int k = 0; + Matcher matcher = pat.matcher(element.text()); + ArrayList parts = new ArrayList(); + while (matcher.find()) { +// System.out.print("Start index: " + matcher.start()); +// System.out.print(" End index: " + matcher.end() + " "); + if (k == 0 && !matcher.group().equals("public")) { + k = -1; + break; + } + // System.out.print(matcher.group() + " "); + parts.add(matcher.group()); + k++; + } + if (k <= 0 || parts.size() < 3) + continue; + int i = 0; + if (parts.get(i).equals("public")) + i++; + if (parts.get(i).equals("static") || parts.get(i).equals("final") + || parts.get(i).equals("class")) + i++; + if (parts.get(i).equals("static") || parts.get(i).equals("final")) + i++; +// System.out.println("Ret Type " + parts.get(i)); + + i++; // return type + + //System.out.println("Name " + parts.get(i)); + jdocMap.put(parts.get(i), msg); + } + +// for (String key : jdocMap.keySet()) { +// System.out.println("Method: " + key); +// System.out.println("Method: " + jdocMap.get(key)); +// } + * + */ + } catch (Exception e) { + e.printStackTrace(); + } + + + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java b/pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java new file mode 100755 index 000000000..8d006fd9d --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Location; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.request.BreakpointRequest; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Model/Controller of a line breakpoint. Can be set before or while debugging. + * Adds a highlight using the debuggers view ({@link DebugEditor}). + * + * @author Martin Leopold + */ +public class LineBreakpoint implements ClassLoadListener { + + protected Debugger dbg; // the debugger + protected LineID line; // the line this breakpoint is set on + protected BreakpointRequest bpr; // the request on the VM's event request manager + protected ReferenceType theClass; // the class containing this breakpoint, null when not yet loaded + + /** + * Create a {@link LineBreakpoint}. If in a debug session, will try to + * immediately set the breakpoint. If not in a debug session or the + * corresponding class is not yet loaded the breakpoint will activate on + * class load. + * + * @param line the line id to create the breakpoint on + * @param dbg the {@link Debugger} + */ + public LineBreakpoint(LineID line, Debugger dbg) { + this.line = line; + line.startTracking(dbg.editor().getTab(line.fileName()).getDocument()); + this.dbg = dbg; + theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded + set(); // activate the breakpoint (show highlight, attach if debugger is running) + } + + /** + * Create a {@link LineBreakpoint} on a line in the current tab. + * + * @param lineIdx the line index of the current tab to create the breakpoint + * on + * @param dbg the {@link Debugger} + */ + // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)} + public LineBreakpoint(int lineIdx, Debugger dbg) { + this(dbg.editor().getLineIDInCurrentTab(lineIdx), dbg); + } + + /** + * Get the line id this breakpoint is on. + * + * @return the line id + */ + public LineID lineID() { + return line; + } + + /** + * Test if this breakpoint is on a certain line. + * + * @param testLine the line id to test + * @return true if this breakpoint is on the given line + */ + public boolean isOnLine(LineID testLine) { + return line.equals(testLine); + } + + /** + * Attach this breakpoint to the VM. Creates and enables a + * {@link BreakpointRequest}. VM needs to be paused. + */ + protected void attach() { + if (!dbg.isPaused()) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, debugger not paused"); + return; + } + + if (theClass == null) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, class not loaded: {0}", className()); + return; + } + + // find line in java space + LineID javaLine = dbg.sketchToJavaLine(line); + if (javaLine == null) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "couldn't find line {0} in the java code", line); + return; + } + try { + List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); + if (locations.isEmpty()) { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); + return; + } + // use first found location + bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0)); + bpr.enable(); + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "attached breakpoint to {0} -> {1}", new Object[]{line, javaLine}); + } catch (AbsentInformationException ex) { + Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Detach this breakpoint from the VM. Deletes the + * {@link BreakpointRequest}. + */ + protected void detach() { + if (bpr != null) { + dbg.vm().eventRequestManager().deleteEventRequest(bpr); + bpr = null; + } + } + + /** + * Set this breakpoint. Adds the line highlight. If Debugger is paused also + * attaches the breakpoint by calling {@link #attach()}. + */ + protected void set() { + dbg.addClassLoadListener(this); // class may not yet be loaded + dbg.editor().addBreakpointedLine(line); + if (theClass != null && dbg.isPaused()) { // class is loaded + // immediately activate the breakpoint + attach(); + } + if (dbg.editor().isInCurrentTab(line)) { + dbg.editor().getSketch().setModified(true); + } + } + + /** + * Remove this breakpoint. Clears the highlight and detaches the breakpoint + * if the debugger is paused. + */ + public void remove() { + dbg.removeClassLoadListener(this); + //System.out.println("removing " + line.lineIdx()); + dbg.editor().removeBreakpointedLine(line.lineIdx()); + if (dbg.isPaused()) { + // immediately remove the breakpoint + detach(); + } + line.stopTracking(); + if (dbg.editor().isInCurrentTab(line)) { + dbg.editor().getSketch().setModified(true); + } + } + +// public void enable() { +// } +// +// public void disable() { +// } + @Override + public String toString() { + return line.toString(); + } + + /** + * Get the name of the class this breakpoint belongs to. Needed for fetching + * the right location to create a breakpoint request. + * + * @return the class name + */ + protected String className() { + if (line.fileName().endsWith(".pde")) { + // standard tab + ReferenceType mainClass = dbg.getMainClass(); + if (mainClass == null) { + return null; + } + return dbg.getMainClass().name(); + } + + if (line.fileName().endsWith(".java")) { + // pure java tab + return line.fileName().substring(0, line.fileName().lastIndexOf(".java")); + } + + return null; + } + + /** + * Event handler called when a class is loaded in the debugger. Causes the + * breakpoint to be attached, if its class was loaded. + * + * @param theClass the class that was just loaded. + */ + @Override + public void classLoaded(ReferenceType theClass) { + // check if our class is being loaded + if (theClass.name().equals(className())) { + this.theClass = theClass; + attach(); + } + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/LineHighlight.java b/pdex/experimental/src/processing/mode/experimental/LineHighlight.java new file mode 100755 index 000000000..c1789cf24 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/LineHighlight.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.awt.Color; +import java.util.HashSet; +import java.util.Set; + +/** + * Model/Controller for a highlighted source code line. Implements a custom + * background color and a text based marker placed in the left-hand gutter area. + * + * @author Martin Leopold + */ +public class LineHighlight implements LineListener { + + protected DebugEditor editor; // the view, used for highlighting lines by setting a background color + protected Color bgColor; // the background color for highlighting lines + protected LineID lineID; // the id of the line + protected String marker; // + protected Color markerColor; + protected int priority = 0; + protected static Set allHighlights = new HashSet(); + + protected static boolean isHighestPriority(LineHighlight hl) { + for (LineHighlight check : allHighlights) { + if (check.lineID().equals(hl.lineID()) && check.priority() > hl.priority()) { + return false; + } + } + return true; + } + + /** + * Create a {@link LineHighlight}. + * + * @param lineID the line id to highlight + * @param bgColor the background color used for highlighting + * @param editor the {@link DebugEditor} + */ + public LineHighlight(LineID lineID, Color bgColor, DebugEditor editor) { + this.lineID = lineID; + this.bgColor = bgColor; + this.editor = editor; + lineID.addListener(this); + lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc? + paint(); // already checks if on current tab + allHighlights.add(this); + } + + public void setPriority(int p) { + this.priority = p; + } + + public int priority() { + return priority; + } + + /** + * Create a {@link LineHighlight} on the current tab. + * + * @param lineIdx the line index on the current tab to highlight + * @param bgColor the background color used for highlighting + * @param editor the {@link DebugEditor} + */ + // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, DebugEditor editor)} + public LineHighlight(int lineIdx, Color bgColor, DebugEditor editor) { + this(editor.getLineIDInCurrentTab(lineIdx), bgColor, editor); + } + + /** + * Set a text based marker displayed in the left hand gutter area of this + * highlighted line. + * + * @param marker the marker text + */ + public void setMarker(String marker) { + this.marker = marker; + paint(); + } + + /** + * Set a text based marker displayed in the left hand gutter area of this + * highlighted line. Also use a custom text color. + * + * @param marker the marker text + * @param markerColor the text color + */ + public void setMarker(String marker, Color markerColor) { + this.markerColor = markerColor; + setMarker(marker); + } + + /** + * Retrieve the line id of this {@link LineHighlight}. + * + * @return the line id + */ + public LineID lineID() { + return lineID; + } + + /** + * Retrieve the color for highlighting this line. + * + * @return the highlight color. + */ + public Color getColor() { + return bgColor; + } + + /** + * Test if this highlight is on a certain line. + * + * @param testLine the line to test + * @return true if this highlight is on the given line + */ + public boolean isOnLine(LineID testLine) { + return lineID.equals(testLine); + } + + /** + * Event handler for line number changes (due to editing). Will remove the + * highlight from the old line number and repaint it at the new location. + * + * @param line the line that has changed + * @param oldLineIdx the old line index (0-based) + * @param newLineIdx the new line index (0-based) + */ + @Override + public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { + // clear old line + if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { + editor.textArea().clearLineBgColor(oldLineIdx); + editor.textArea().clearGutterText(oldLineIdx); + } + + // paint new line + // but only if it's on top -> fixes current line being hidden by breakpoint moving it down. + // lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...) + if (LineHighlight.isHighestPriority(this)) { + paint(); + } + } + + /** + * Notify this line highlight that it is no longer used. Call this for + * cleanup before the {@link LineHighlight} is discarded. + */ + public void dispose() { + lineID.removeListener(this); + lineID.stopTracking(); + allHighlights.remove(this); + } + + /** + * (Re-)paint this line highlight. + */ + public void paint() { + if (editor.isInCurrentTab(lineID)) { + editor.textArea().setLineBgColor(lineID.lineIdx(), bgColor); + if (marker != null) { + if (markerColor != null) { + editor.textArea().setGutterText(lineID.lineIdx(), marker, markerColor); + } else { + editor.textArea().setGutterText(lineID.lineIdx(), marker); + } + } + } + } + + /** + * Clear this line highlight. + */ + public void clear() { + if (editor.isInCurrentTab(lineID)) { + editor.textArea().clearLineBgColor(lineID.lineIdx()); + editor.textArea().clearGutterText(lineID.lineIdx()); + } + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/LineID.java b/pdex/experimental/src/processing/mode/experimental/LineID.java new file mode 100755 index 000000000..a08d21296 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/LineID.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.Position; + +/** + * Describes an ID for a code line. Comprised of a file name and a (0-based) + * line number. Can track changes to the line number due to text editing by + * attaching a {@link Document}. Registered {@link LineListener}s are notified + * of changes to the line number. + * + * @author Martin Leopold + */ +public class LineID implements DocumentListener { + + protected String fileName; // the filename + protected int lineIdx; // the line number, 0-based + protected Document doc; // the Document to use for line number tracking + protected Position pos; // the Position acquired during line number tracking + protected Set listeners = new HashSet(); // listeners for line number changes + + public LineID(String fileName, int lineIdx) { + this.fileName = fileName; + this.lineIdx = lineIdx; + } + + /** + * Get the file name of this line. + * + * @return the file name + */ + public String fileName() { + return fileName; + } + + /** + * Get the (0-based) line number of this line. + * + * @return the line index (i.e. line number, starting at 0) + */ + public synchronized int lineIdx() { + return lineIdx; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + /** + * Test whether this {@link LineID} is equal to another object. Two + * {@link LineID}'s are equal when both their fileName and lineNo are equal. + * + * @param obj the object to test for equality + * @return {@code true} if equal + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final LineID other = (LineID) obj; + if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) { + return false; + } + if (this.lineIdx != other.lineIdx) { + return false; + } + return true; + } + + /** + * Output a string representation in the form fileName:lineIdx+1. Note this + * uses a 1-based line number as is customary for human-readable line + * numbers. + * + * @return the string representation of this line ID + */ + @Override + public String toString() { + return fileName + ":" + (lineIdx + 1); + } + +// /** +// * Retrieve a copy of this line ID. +// * +// * @return the copy +// */ +// @Override +// public LineID clone() { +// return new LineID(fileName, lineIdx); +// } + + /** + * Attach a {@link Document} to enable line number tracking when editing. + * The position to track is before the first non-whitespace character on the + * line. Edits happening before that position will cause the line number to + * update accordingly. Multiple {@link #startTracking} calls will replace + * the tracked document. Whoever wants a tracked line should track it and + * add itself as listener if necessary. + * ({@link LineHighlight}, {@link LineBreakpoint}) + * + * @param doc the {@link Document} to use for line number tracking + */ + public synchronized void startTracking(Document doc) { + //System.out.println("tracking: " + this); + if (doc == null) { + return; // null arg + } + if (doc == this.doc) { + return; // already tracking that doc + } + try { + Element line = doc.getDefaultRootElement().getElement(lineIdx); + if (line == null) { + return; // line doesn't exist + } + String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset()); + // set tracking position at (=before) first non-white space character on line + pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText)); + this.doc = doc; + doc.addDocumentListener(this); + } catch (BadLocationException ex) { + Logger.getLogger(LineID.class.getName()).log(Level.SEVERE, null, ex); + pos = null; + this.doc = null; + } + } + + /** + * Notify this {@link LineID} that it is no longer in use. Will stop + * position tracking. Call this when this {@link LineID} is no longer + * needed. + */ + public synchronized void stopTracking() { + if (doc != null) { + doc.removeDocumentListener(this); + doc = null; + } + } + + /** + * Update the tracked position. Will notify listeners if line number has + * changed. + */ + protected synchronized void updatePosition() { + if (doc != null && pos != null) { + // track position + int offset = pos.getOffset(); + int oldLineIdx = lineIdx; + lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo + if (lineIdx != oldLineIdx) { + for (LineListener l : listeners) { + if (l != null) { + l.lineChanged(this, oldLineIdx, lineIdx); + } else { + listeners.remove(l); // remove null listener + } + } + } + } + } + + /** + * Add listener to be notified when the line number changes. + * + * @param l the listener to add + */ + public void addListener(LineListener l) { + listeners.add(l); + } + + /** + * Remove a listener for line number changes. + * + * @param l the listener to remove + */ + public void removeListener(LineListener l) { + listeners.remove(l); + } + + /** + * Calculate the offset of the first non-whitespace character in a string. + * + * @param str the string to examine + * @return offset of first non-whitespace character in str + */ + protected static int nonWhiteSpaceOffset(String str) { + for (int i = 0; i < str.length(); i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return i; + } + } + return str.length(); + } + + /** + * Called when the {@link Document} registered using {@link #startTracking} + * is edited. This happens when text is inserted or removed. + * + * @param de + */ + protected void editEvent(DocumentEvent de) { + //System.out.println("document edit @ " + de.getOffset()); + if (de.getOffset() <= pos.getOffset()) { + updatePosition(); + //System.out.println("updating, new line no: " + lineNo); + } + } + + /** + * {@link DocumentListener} callback. Called when text is inserted. + * + * @param de + */ + @Override + public void insertUpdate(DocumentEvent de) { + editEvent(de); + } + + /** + * {@link DocumentListener} callback. Called when text is removed. + * + * @param de + */ + @Override + public void removeUpdate(DocumentEvent de) { + editEvent(de); + } + + /** + * {@link DocumentListener} callback. Called when attributes are changed. + * Not used. + * + * @param de + */ + @Override + public void changedUpdate(DocumentEvent de) { + // not needed. + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/LineListener.java b/pdex/experimental/src/processing/mode/experimental/LineListener.java new file mode 100755 index 000000000..c6c3ae1b0 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/LineListener.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +/** + * A Listener for line number changes. + * + * @author Martin Leopold + */ +public interface LineListener { + + /** + * Event handler for line number changes (due to editing). + * + * @param line the line that has changed + * @param oldLineIdx the old line index (0-based) + * @param newLineIdx the new line index (0-based) + */ + void lineChanged(LineID line, int oldLineIdx, int newLineIdx); +} diff --git a/pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java b/pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java new file mode 100755 index 000000000..d1bdb2092 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.StackFrame; +import com.sun.jdi.Value; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Specialized {@link VariableNode} for representing local variables. Overrides + * {@link #setValue} to properly change the value of the encapsulated local + * variable. + * + * @author Martin Leopold + */ +public class LocalVariableNode extends VariableNode { + + protected LocalVariable var; + protected StackFrame frame; + + /** + * Construct a {@link LocalVariableNode}. + * + * @param name the name + * @param type the type + * @param value the value + * @param var the local variable + * @param frame the stack frame containing the local variable + */ + public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) { + super(name, type, value); + this.var = var; + this.frame = frame; + } + + @Override + public void setValue(Value value) { + try { + frame.setValue(var, value); + } catch (InvalidTypeException ex) { + Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotLoadedException ex) { + Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); + } + this.value = value; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/Problem.java b/pdex/experimental/src/processing/mode/experimental/Problem.java new file mode 100644 index 000000000..56cc0e833 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/Problem.java @@ -0,0 +1,160 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.experimental; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.core.compiler.IProblem; + +/** + * Wrapper class for IProblem. + * + * Stores the tabIndex and line number according to its tab, including the + * original IProblem object + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class Problem { + /** + * The IProblem which is being wrapped + */ + private IProblem iProblem; + /** + * The tab number to which the error belongs to + */ + public int tabIndex; + /** + * Line number(pde code) of the error + */ + public int lineNumber; + + /** + * Error Message. Processed form of IProblem.getMessage() + */ + public String message; + + /** + * The type of error - WARNING or ERROR. + */ + public int type; + + public static final int ERROR = 1, WARNING = 2; + + /** + * + * @param iProblem - The IProblem which is being wrapped + * @param tabIndex - The tab number to which the error belongs to + * @param lineNumber - Line number(pde code) of the error + */ + public Problem(IProblem iProblem, int tabIndex, int lineNumber) { + this.iProblem = iProblem; + if(iProblem.isError()) { + type = ERROR; + } + else if(iProblem.isWarning()) { + type = WARNING; + } + this.tabIndex = tabIndex; + this.lineNumber = lineNumber; + this.message = process(iProblem); + } + + public String toString() { + return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: " + + message); + } + + public boolean isError(){ + return type == ERROR; + } + + public boolean isWarning(){ + return type == WARNING; + } + + public String getMessage(){ + return message; + } + + public IProblem getIProblem(){ + return iProblem; + } + + public void setType(int ProblemType){ + if(ProblemType == ERROR) + type = ERROR; + else if(ProblemType == WARNING) + type = WARNING; + else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)"); + } + + private static Pattern pattern; + private static Matcher matcher; + + private static final String tokenRegExp = "\\b token\\b"; + + public static String process(IProblem problem) { + return process(problem.getMessage()); + } + + /** + * Processes error messages and attempts to make them a bit more english like. + * Currently performs: + *
  • Remove all instances of token. "Syntax error on token 'blah', delete this token" + * becomes "Syntax error on 'blah', delete this" + * @param message - The message to be processed + * @return String - The processed message + */ + public static String process(String message) { + // Remove all instances of token + // "Syntax error on token 'blah', delete this token" + if(message == null) return null; + pattern = Pattern.compile(tokenRegExp); + matcher = pattern.matcher(message); + message = matcher.replaceAll(""); + + return message; + } + + // Split camel case words into separate words. + // "VaraibleDeclaration" becomes "Variable Declaration" + // But sadly "PApplet" become "P Applet" and so on. + public static String splitCamelCaseWord(String word) { + String newWord = ""; + for (int i = 1; i < word.length(); i++) { + if (Character.isUpperCase(word.charAt(i))) { + // System.out.println(word.substring(0, i) + " " + // + word.substring(i)); + newWord += word.substring(0, i) + " "; + word = word.substring(i); + i = 1; + } + } + newWord += word; + // System.out.println(newWord); + return newWord.trim(); + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/TextArea.java b/pdex/experimental/src/processing/mode/experimental/TextArea.java new file mode 100644 index 000000000..e07cda0b3 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/TextArea.java @@ -0,0 +1,630 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.FontMetrics; +import java.awt.Point; +import java.awt.event.ComponentListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + +import processing.app.syntax.JEditTextArea; +import processing.app.syntax.TextAreaDefaults; + +/** + * Customized text area. Adds support for line background colors. + * + * @author Martin Leopold + */ +public class TextArea extends JEditTextArea { + + protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler + + protected DebugEditor editor; // the editor + + // line properties + protected Map lineColors = new HashMap(); // contains line background colors + + // left-hand gutter properties + protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars + + protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color + + protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line + + protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter + + protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter + + protected Map gutterText = new HashMap(); // maps line index to gutter text + + protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color + + protected TextAreaPainter customPainter; + + protected ErrorCheckerService errorCheckerService; + + public TextArea(TextAreaDefaults defaults, DebugEditor editor) { + super(defaults); + this.editor = editor; + + // replace the painter: + // first save listeners, these are package-private in JEditTextArea, so not accessible + ComponentListener[] componentListeners = painter.getComponentListeners(); + mouseListeners = painter.getMouseListeners(); + MouseMotionListener[] mouseMotionListeners = painter + .getMouseMotionListeners(); + + remove(painter); + + // set new painter + customPainter = new TextAreaPainter(this, defaults); + painter = customPainter; + + // set listeners + for (ComponentListener cl : componentListeners) { + painter.addComponentListener(cl); + } + + for (MouseMotionListener mml : mouseMotionListeners) { + painter.addMouseMotionListener(mml); + } + + // use a custom mouse handler instead of directly using mouseListeners + MouseHandler mouseHandler = new MouseHandler(); + painter.addMouseListener(mouseHandler); + painter.addMouseMotionListener(mouseHandler); + addCompletionPopupListner(); + add(CENTER, painter); + + // load settings from theme.txt + ExperimentalMode theme = (ExperimentalMode) editor.getMode(); + gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); + gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); + gutterPadding = theme.getInteger("gutter.padding"); + breakpointMarker = theme.loadThemeString("breakpoint.marker", + breakpointMarker); + currentLineMarker = theme.loadThemeString("currentline.marker", + currentLineMarker); + } + + /** + * Sets ErrorCheckerService and loads theme for TextArea(XQMode) + * + * @param ecs + * @param mode + */ + public void setECSandThemeforTextArea(ErrorCheckerService ecs, + ExperimentalMode mode) { + errorCheckerService = ecs; + customPainter.setECSandTheme(ecs, mode); + } + + public void processKeyEvent(KeyEvent evt) { + if (evt.getID() == KeyEvent.KEY_PRESSED) { + if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { + if (suggestion.isVisible()) { + //System.out.println("KeyDown"); + suggestion.moveDown(); + return; + } + } else if (evt.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { + if (suggestion.isVisible()) { + //System.out.println("KeyUp"); + suggestion.moveUp(); + return; + } + } + if (evt.getKeyChar() == KeyEvent.VK_ENTER) { + if (suggestion != null) { + if (suggestion.isVisible()){ + if (suggestion.insertSelection()) { + final int position = getCaretPosition(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + //getDocument().remove(position - 1, 1); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + return; + } + } + } + } else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) { + System.out.println("BK Key"); + } + } + + super.processKeyEvent(evt); + if (evt.getID() == KeyEvent.KEY_TYPED) { + errorCheckerService.textModified.incrementAndGet(); + System.out.println(" Typing: " + fetchPhrase(evt) + " " + + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); + + } + + } + + private String fetchPhrase(KeyEvent evt) { + int off = getCaretPosition(); + System.out.print("off " + off); + if (off < 0) + return null; + int line = getCaretLine(); + if (line < 0) + return null; + String s = getLineText(line); + System.out.print("lin " + line); + /* + * if (s == null) return null; else if (s.length() == 0) return null; + */ +// else { + //System.out.print(s + " len " + s.length()); + + int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + if(x >= s.length() || x < 0) + return null; //TODO: Does this check cause problems? Verify. + System.out.print(" x char: " + s.charAt(x)); + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) + ; // accepted these keys + else if (keyChar == KeyEvent.CHAR_UNDEFINED) + + return null; + + String word = (x < s.length() ? s.charAt(x) : "") + ""; + if (s.trim().length() == 1) { +// word = "" +// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + errorCheckerService.astGenerator.updatePredictions(word, line + + errorCheckerService.mainClassOffset); + return word; + } +// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) +// ; // accepted these keys +// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) +// return null; + int i = 0; + int closeB = 0; + + while (true) { + i++; + //TODO: currently works on single line only. "a. b()" won't be detected + if (x1 >= 0) { +// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' + || s.charAt(x1) == '.' || s.charAt(x1) == ')') { + + if (s.charAt(x1) == ')') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '(') + closeB--; + if (s.charAt(x1) == ')') + closeB++; + x1--; + } + } else { + word = s.charAt(x1--) + word; + } + } else { + break; + } + } else { + break; + } + +// if (x2 >= 0 && x2 < s.length()) { +// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' +// || s.charAt(x2) == '$') +// word = word + s.charAt(x2++); +// else +// x2 = -1; +// } else +// x2 = -1; + +// if (x1 < 0 )//&& x2 < 0 +// break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); + break; + } + } +// if (keyChar != KeyEvent.CHAR_UNDEFINED) + + if (Character.isDigit(word.charAt(0))) + return null; + word = word.trim(); +// if (word.endsWith(".")) +// word = word.substring(0, word.length() - 1); + errorCheckerService.astGenerator.updatePredictions(word, line + + errorCheckerService.mainClassOffset); + //showSuggestionLater(); + return word; + + //} + } + + /** + * Retrieve the total width of the gutter area. + * + * @return gutter width in pixels + */ + protected int getGutterWidth() { + FontMetrics fm = painter.getFontMetrics(); +// System.out.println("fm: " + (fm == null)); +// System.out.println("editor: " + (editor == null)); + //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); + + int textWidth = Math.max(fm.stringWidth(breakpointMarker), + fm.stringWidth(currentLineMarker)); + return textWidth + 2 * gutterPadding; + } + + /** + * Retrieve the width of margins applied to the left and right of the gutter + * text. + * + * @return margins in pixels + */ + protected int getGutterMargins() { + return gutterPadding; + } + + /** + * Set the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @param text + * the text + */ + public void setGutterText(int lineIdx, String text) { + gutterText.put(lineIdx, text); + painter.invalidateLine(lineIdx); + } + + /** + * Set the gutter text and color of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @param text + * the text + * @param textColor + * the text color + */ + public void setGutterText(int lineIdx, String text, Color textColor) { + gutterTextColors.put(lineIdx, textColor); + setGutterText(lineIdx, text); + } + + /** + * Clear the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + */ + public void clearGutterText(int lineIdx) { + gutterText.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all gutter text. + */ + public void clearGutterText() { + for (int lineIdx : gutterText.keySet()) { + painter.invalidateLine(lineIdx); + } + gutterText.clear(); + } + + /** + * Retrieve the gutter text of a specific line. + * + * @param lineIdx + * the line index (0-based) + * @return the gutter text + */ + public String getGutterText(int lineIdx) { + return gutterText.get(lineIdx); + } + + /** + * Retrieve the gutter text color for a specific line. + * + * @param lineIdx + * the line index + * @return the gutter text color + */ + public Color getGutterTextColor(int lineIdx) { + return gutterTextColors.get(lineIdx); + } + + /** + * Set the background color of a line. + * + * @param lineIdx + * 0-based line number + * @param col + * the background color to set + */ + public void setLineBgColor(int lineIdx, Color col) { + lineColors.put(lineIdx, col); + painter.invalidateLine(lineIdx); + } + + /** + * Clear the background color of a line. + * + * @param lineIdx + * 0-based line number + */ + public void clearLineBgColor(int lineIdx) { + lineColors.remove(lineIdx); + painter.invalidateLine(lineIdx); + } + + /** + * Clear all line background colors. + */ + public void clearLineBgColors() { + for (int lineIdx : lineColors.keySet()) { + painter.invalidateLine(lineIdx); + } + lineColors.clear(); + } + + /** + * Get a lines background color. + * + * @param lineIdx + * 0-based line number + * @return the color or null if no color was set for the specified line + */ + public Color getLineBgColor(int lineIdx) { + return lineColors.get(lineIdx); + } + + /** + * Convert a character offset to a horizontal pixel position inside the text + * area. Overridden to take gutter width into account. + * + * @param line + * the 0-based line number + * @param offset + * the character offset (0 is the first character on a line) + * @return the horizontal position + */ + @Override + public int _offsetToX(int line, int offset) { + return super._offsetToX(line, offset) + getGutterWidth(); + } + + /** + * Convert a horizontal pixel position to a character offset. Overridden to + * take gutter width into account. + * + * @param line + * the 0-based line number + * @param x + * the horizontal pixel position + * @return he character offset (0 is the first character on a line) + */ + @Override + public int xToOffset(int line, int x) { + return super.xToOffset(line, x - getGutterWidth()); + } + + /** + * Custom mouse handler. Implements double clicking in the gutter area to + * toggle breakpoints, sets default cursor (instead of text cursor) in the + * gutter area. + */ + protected class MouseHandler implements MouseListener, MouseMotionListener { + + protected int lastX; // previous horizontal positon of the mouse cursor + + @Override + public void mouseClicked(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseClicked(me); + } + } + + @Override + public void mousePressed(MouseEvent me) { + // check if this happened in the gutter area + if (me.getX() < getGutterWidth()) { + if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { + int line = me.getY() / painter.getFontMetrics().getHeight() + + firstLine; + if (line >= 0 && line <= getLineCount() - 1) { + editor.gutterDblClicked(line); + } + } + } else { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mousePressed(me); + } + } + } + + @Override + public void mouseReleased(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseReleased(me); + } + } + + @Override + public void mouseEntered(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseEntered(me); + } + } + + @Override + public void mouseExited(MouseEvent me) { + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mouseExited(me); + } + } + + @Override + public void mouseDragged(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + // nop + } + + @Override + public void mouseMoved(MouseEvent me) { + // No need to forward since the standard MouseMotionListeners are called anyway + if (me.getX() < getGutterWidth()) { + if (lastX >= getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } else { + if (lastX < getGutterWidth()) { + painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + } + } + lastX = me.getX(); + } + } + + private CompletionPanel suggestion; + + //JEditTextArea textarea; + + private void addCompletionPopupListner() { + this.addKeyListener(new KeyListener() { + + @Override + public void keyTyped(KeyEvent e) { + + } + + @Override + public void keyReleased(KeyEvent e) { + if (Character.isLetterOrDigit(e.getKeyChar()) + || e.getKeyChar() == KeyEvent.VK_BACK_SPACE + || e.getKeyChar() == KeyEvent.VK_DELETE) { +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// showSuggestion(); +// } +// +// }); + } else if (Character.isWhitespace(e.getKeyChar())) { + hideSuggestion(); + } + } + + @Override + public void keyPressed(KeyEvent e) { + } + }); + } + + public void showSuggestionLater(final CompletionCandidate[] items) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + showSuggestion(items); + } + + }); + } + + protected void showSuggestion(CompletionCandidate[] items) { + hideSuggestion(); + final int position = getCaretPosition(); + Point location = new Point(); + try { + location.x = offsetToX(getCaretLine(), position + - getLineStartOffset(getCaretLine())); + location.y = lineToY(getCaretLine()) + + getPainter().getFontMetrics().getHeight(); + } catch (Exception e2) { + e2.printStackTrace(); + return; + } + String text = getText(); + int start = Math.max(0, position - 1); + while (start > 0) { + if (!Character.isWhitespace(text.charAt(start))) { + start--; + } else { + start++; + break; + } + } + if (start > position) { + return; + } + final String subWord = text.substring(start, position); + if (subWord.length() < 2) { + return; + } + suggestion = new CompletionPanel(this, position, subWord, items, location); +// requestFocusInWindow(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + requestFocusInWindow(); + } + }); + } + + private void hideSuggestion() { + if (suggestion != null) { + suggestion.hide(); + } + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java b/pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java new file mode 100644 index 000000000..9ee6b9539 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Segment; +import javax.swing.text.Utilities; + +import processing.app.syntax.TextAreaDefaults; +import processing.app.syntax.TokenMarker; + +/** + * Customized line painter. Adds support for background colors, left hand gutter + * area with background color and text. + * + * @author Martin Leopold + */ +public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { + + protected TextArea ta; // we need the subclassed textarea + + protected ErrorCheckerService errorCheckerService; + + /** + * Error line underline color + */ + public Color errorColor = new Color(0xED2630); + + /** + * Warning line underline color + */ + + public Color warningColor = new Color(0xFFC30E); + + /** + * Color of Error Marker + */ + public Color errorMarkerColor = new Color(0xED2630); + + /** + * Color of Warning Marker + */ + public Color warningMarkerColor = new Color(0xFFC30E); + + static int ctrlMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + + public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { + super(textArea, defaults); + ta = textArea; + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { +// System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); + if (evt.isControlDown()) + handleCtrlClick(evt); + } + }); + + } + +// public void processKeyEvent(KeyEvent evt) { +// System.out.println(evt); +// } + + void handleCtrlClick(MouseEvent evt) { + System.out.println("--handleCtrlClick--"); + int off = ta.xyToOffset(evt.getX(), evt.getY()); + if (off < 0) + return; + int line = ta.getLineOfOffset(off); + if (line < 0) + return; + String s = ta.getLineText(line); + if (s == null) + return; + else if (s.length() == 0) + return; + else { + int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + if (x < 0 || x >= s.length()) + return; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); + break; + } + } + if (Character.isDigit(word.charAt(0))) + return; + + System.out.print(errorCheckerService.mainClassOffset + line); + System.out.print("|" + line + "| offset " + xLS + word + " <= \n"); + errorCheckerService.astGenerator.scrollToDeclaration(line + + errorCheckerService.mainClassOffset, word, xLS); + } + } + + private void loadTheme(ExperimentalMode mode) { + errorColor = mode.getThemeColor("editor.errorcolor", errorColor); + warningColor = mode.getThemeColor("editor.warningcolor", warningColor); + errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", + errorMarkerColor); + warningMarkerColor = mode.getThemeColor("editor.warningmarkercolor", + warningMarkerColor); + } + + /** + * Paint a line. Paints the gutter (with background color and text) then the + * line (background color and text). + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number + * @param x + * horizontal position + */ + @Override + protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, + int x) { + + // paint gutter + paintGutterBg(gfx, line, x); + + paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + + paintGutterLine(gfx, line, x); + + // paint gutter symbol + paintGutterText(gfx, line, x); + + paintErrorLine(gfx, line, x); + + super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); + } + + /** + * Paint the gutter background (solid color). + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterBg(Graphics gfx, int line, int x) { + gfx.setColor(ta.gutterBgColor); + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); + } + + /** + * Paint the vertical gutter separator line. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterLine(Graphics gfx, int line, int x) { + int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); + gfx.setColor(ta.gutterLineColor); + gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), + y + fm.getHeight()); + } + + /** + * Paint the gutter text. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + * horizontal position + */ + protected void paintGutterText(Graphics gfx, int line, int x) { + String text = ta.getGutterText(line); + if (text == null) { + return; + } + + gfx.setFont(getFont()); + Color textColor = ta.getGutterTextColor(line); + if (textColor == null) { + gfx.setColor(getForeground()); + } else { + gfx.setColor(textColor); + } + int y = ta.lineToY(line) + fm.getHeight(); + + // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. + //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins(), y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins() + 1, y, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins(), y + 1, gfx, this, 0); + Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), + ta.getGutterMargins() + 1, y + 1, gfx, this, 0); + } + + /** + * Paint the background color of a line. + * + * @param gfx + * the graphics context + * @param line + * 0-based line number + * @param x + */ + protected void paintLineBgColor(Graphics gfx, int line, int x) { + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + + // get the color + Color col = ta.getLineBgColor(line); + //System.out.print("bg line " + line + ": "); + // no need to paint anything + if (col == null) { + //System.out.println("none"); + return; + } + // paint line background + gfx.setColor(col); + gfx.fillRect(0, y, getWidth(), height); + } + + /** + * Paints the underline for an error/warning line + * + * @param gfx + * the graphics context + * @param tokenMarker + * @param line + * 0-based line number: NOTE + * @param x + */ + protected void paintErrorLine(Graphics gfx, int line, int x) { + + if (errorCheckerService == null) { + return; + } + + if (errorCheckerService.problemsList == null) { + return; + } + + boolean notFound = true; + boolean isWarning = false; + + // Check if current line contains an error. If it does, find if it's an + // error or warning + for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { + if (emarker.problem.lineNumber == line + 1) { + notFound = false; + if (emarker.type == ErrorMarker.Warning) { + isWarning = true; + } + break; + } + } + + if (notFound) { + return; + } + + // Determine co-ordinates + // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + + // horizontalAdjustment); + int y = ta.lineToY(line); + y += fm.getLeading() + fm.getMaxDescent(); + int height = fm.getHeight(); + int start = ta.getLineStartOffset(line); + + try { + String linetext = null; + + try { + linetext = ta.getDocument().getText(start, + ta.getLineStopOffset(line) - start + - 1); + } catch (BadLocationException bl) { + // Error in the import statements or end of code. + // System.out.print("BL caught. " + ta.getLineCount() + " ," + // + line + " ,"); + // System.out.println((ta.getLineStopOffset(line) - start - 1)); + return; + } + + // Take care of offsets + int aw = fm.stringWidth(trimRight(linetext)) + ta.getHorizontalOffset(); // apparent width. Whitespaces + // to the left of line + text + // width + int rw = fm.stringWidth(linetext.trim()); // real width + int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; + // Adding offsets for the gutter + x1 += 20; + x2 += 20; + + // gfx.fillRect(x1, y, rw, height); + + // Let the painting begin! + gfx.setColor(errorMarkerColor); + if (isWarning) { + gfx.setColor(warningMarkerColor); + } + gfx.fillRect(1, y + 2, 3, height - 2); + + gfx.setColor(errorColor); + if (isWarning) { + gfx.setColor(warningColor); + } + int xx = x1; + + // Draw the jagged lines + while (xx < x2) { + gfx.drawLine(xx, y1, xx + 2, y1 + 1); + xx += 2; + gfx.drawLine(xx, y1 + 1, xx + 2, y1); + xx += 2; + } + } catch (Exception e) { + System.out + .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " + + e); + //e.printStackTrace(); + } + + // Won't highlight the line. Select the text instead. + // gfx.setColor(Color.RED); + // gfx.fillRect(2, y, 3, height); + } + + /** + * Trims out trailing whitespaces (to the right) + * + * @param string + * @return - String + */ + private String trimRight(String string) { + String newString = ""; + for (int i = 0; i < string.length(); i++) { + if (string.charAt(i) != ' ') { + newString = string.substring(0, i) + string.trim(); + break; + } + } + return newString; + } + + /** + * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) + * + * @param ecs + * @param mode + */ + public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode) { + this.errorCheckerService = ecs; + loadTheme(mode); + } + + public String getToolTipText(java.awt.event.MouseEvent evt) { + int off = ta.xyToOffset(evt.getX(), evt.getY()); + if (off < 0) + return null; + int line = ta.getLineOfOffset(off); + if (line < 0) + return null; + String s = ta.getLineText(line); + if (s == null) + return evt.toString(); + else if (s.length() == 0) + return null; + else { + int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + if (x < 0 || x >= s.length()) + return null; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return null; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return null; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); + break; + } + } + if (Character.isDigit(word.charAt(0))) + return null; + String tooltipText = errorCheckerService.astGenerator + .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, + xLS); + + System.out.print(errorCheckerService.mainClassOffset + " MCO "); + System.out.print("|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); + if (tooltipText != null) + return tooltipText; + return word; + } + + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/VMEventListener.java b/pdex/experimental/src/processing/mode/experimental/VMEventListener.java new file mode 100755 index 000000000..4cc648802 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/VMEventListener.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.event.EventSet; + +/** + * Interface for VM callbacks. + * + * @author Martin Leopold + */ +public interface VMEventListener { + + /** + * Receive an event from the VM. Events are sent in batches. See + * documentation of EventSet for more information. + * + * @param es Set of events + */ + void vmEvent(EventSet es); +} diff --git a/pdex/experimental/src/processing/mode/experimental/VMEventReader.java b/pdex/experimental/src/processing/mode/experimental/VMEventReader.java new file mode 100755 index 000000000..c4d05ddf9 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/VMEventReader.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Reader Thread for VM Events. Constantly monitors a VMs EventQueue for new + * events and forwards them to an VMEventListener. + * + * @author Martin Leopold + */ +public class VMEventReader extends Thread { + + EventQueue eventQueue; + VMEventListener listener; + + /** + * Construct a VMEventReader. Needs to be kicked off with start() once + * constructed. + * + * @param eventQueue The queue to read events from. Can be obtained from a + * VirtualMachine via eventQueue(). + * @param listener the listener to forward events to. + */ + public VMEventReader(EventQueue eventQueue, VMEventListener listener) { + super("VM Event Thread"); + this.eventQueue = eventQueue; + this.listener = listener; + } + + @Override + public void run() { + try { + while (true) { + EventSet eventSet = eventQueue.remove(); + listener.vmEvent(eventSet); + /* + * for (Event e : eventSet) { System.out.println("VM Event: " + + * e.toString()); } + */ + } + } catch (VMDisconnectedException e) { + Logger.getLogger(VMEventReader.class.getName()).log(Level.INFO, "VMEventReader quit on VM disconnect"); + } catch (Exception e) { + Logger.getLogger(VMEventReader.class.getName()).log(Level.SEVERE, "VMEventReader quit", e); + } + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/VariableInspector.form b/pdex/experimental/src/processing/mode/experimental/VariableInspector.form new file mode 100755 index 000000000..a5f40f1d3 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/VariableInspector.form @@ -0,0 +1,53 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/pdex/experimental/src/processing/mode/experimental/VariableInspector.java b/pdex/experimental/src/processing/mode/experimental/VariableInspector.java new file mode 100755 index 000000000..a38c19a8f --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/VariableInspector.java @@ -0,0 +1,929 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.Value; +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.DefaultCellEditor; +import javax.swing.GrayFilter; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.table.TableColumn; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.ExpandVetoException; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import org.netbeans.swing.outline.DefaultOutlineCellRenderer; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.ExtTreeWillExpandListener; +import org.netbeans.swing.outline.OutlineModel; +import org.netbeans.swing.outline.RenderDataProvider; +import org.netbeans.swing.outline.RowModel; + +/** + * Variable Inspector window. + * + * @author Martin Leopold + */ +public class VariableInspector extends javax.swing.JFrame { + + protected DefaultMutableTreeNode rootNode; // the root node (invisible) + protected DefaultMutableTreeNode builtins; // node for Processing built-in variables + protected DefaultTreeModel treeModel; // data model for the tree column + protected OutlineModel model; // data model for the whole Outline (tree and other columns) + protected List callStack; // the call stack + protected List locals; // current local variables + protected List thisFields; // all fields of the current this-object + protected List declaredThisFields; // declared i.e. non-inherited fields of this + protected DebugEditor editor; // the editor + protected Debugger dbg; // the debugger + protected List expandedNodes = new ArrayList(); // list of expanded tree paths. (using list to maintain the order of expansion) + protected boolean p5mode = true; // processing / "advanced" mode flag (currently not used + + /** + * Creates new form VariableInspector + */ + public VariableInspector(DebugEditor editor) { + this.editor = editor; + this.dbg = editor.dbg(); + + initComponents(); + + // setup Outline + rootNode = new DefaultMutableTreeNode("root"); + builtins = new DefaultMutableTreeNode("Processing"); + treeModel = new DefaultTreeModel(rootNode); // model for the tree column + model = DefaultOutlineModel.createOutlineModel(treeModel, new VariableRowModel(), true, "Name"); // model for all columns + + ExpansionHandler expansionHandler = new ExpansionHandler(); + model.getTreePathSupport().addTreeWillExpandListener(expansionHandler); + model.getTreePathSupport().addTreeExpansionListener(expansionHandler); + tree.setModel(model); + tree.setRootVisible(false); + tree.setRenderDataProvider(new OutlineRenderer()); + tree.setColumnHidingAllowed(false); // disable visible columns button (shows by default when right scroll bar is visible) + tree.setAutoscrolls(false); + + // set custom renderer and editor for value column, since we are using a custom class for values (VariableNode) + TableColumn valueColumn = tree.getColumnModel().getColumn(1); + valueColumn.setCellRenderer(new ValueCellRenderer()); + valueColumn.setCellEditor(new ValueCellEditor()); + + //System.out.println("renderer: " + tree.getDefaultRenderer(String.class).getClass()); + //System.out.println("editor: " + tree.getDefaultEditor(String.class).getClass()); + + callStack = new ArrayList(); + locals = new ArrayList(); + thisFields = new ArrayList(); + declaredThisFields = new ArrayList(); + + this.setTitle(editor.getSketch().getName()); + +// for (Entry entry : UIManager.getDefaults().entrySet()) { +// System.out.println(entry.getKey()); +// } + } + + @Override + public void setTitle(String title) { + super.setTitle(title + " | Variable Inspector"); + } + + /** + * Model for a Outline Row (excluding the tree column). Column 0 is "Value". + * Column 1 is "Type". Handles setting and getting values. TODO: Maybe use a + * TableCellRenderer instead of this to also have a different icon based on + * expanded state. See: + * http://kickjava.com/src/org/netbeans/swing/outline/DefaultOutlineCellRenderer.java.htm + */ + protected class VariableRowModel implements RowModel { + + protected String[] columnNames = {"Value", "Type"}; + protected int[] editableTypes = {VariableNode.TYPE_BOOLEAN, VariableNode.TYPE_FLOAT, VariableNode.TYPE_INTEGER, VariableNode.TYPE_STRING, VariableNode.TYPE_FLOAT, VariableNode.TYPE_DOUBLE, VariableNode.TYPE_LONG, VariableNode.TYPE_SHORT, VariableNode.TYPE_CHAR}; + + @Override + public int getColumnCount() { + if (p5mode) { + return 1; // only show value in p5 mode + } else { + return 2; + } + } + + @Override + public Object getValueFor(Object o, int i) { + if (o instanceof VariableNode) { + VariableNode var = (VariableNode) o; + switch (i) { + case 0: + return var; // will be converted to an appropriate String by ValueCellRenderer + case 1: + return var.getTypeName(); + default: + return ""; + } + } else { + return ""; + } + } + + @Override + public Class getColumnClass(int i) { + if (i == 0) { + return VariableNode.class; + } + return String.class; + } + + @Override + public boolean isCellEditable(Object o, int i) { + if (i == 0 && o instanceof VariableNode) { + VariableNode var = (VariableNode) o; + //System.out.println("type: " + var.getTypeName()); + for (int type : editableTypes) { + if (var.getType() == type) { + return true; + } + } + } + return false; + } + + @Override + public void setValueFor(Object o, int i, Object o1) { + VariableNode var = (VariableNode) o; + String stringValue = (String) o1; + + Value value = null; + try { + switch (var.getType()) { + case VariableNode.TYPE_INTEGER: + value = dbg.vm().mirrorOf(Integer.parseInt(stringValue)); + break; + case VariableNode.TYPE_BOOLEAN: + value = dbg.vm().mirrorOf(Boolean.parseBoolean(stringValue)); + break; + case VariableNode.TYPE_FLOAT: + value = dbg.vm().mirrorOf(Float.parseFloat(stringValue)); + break; + case VariableNode.TYPE_STRING: + value = dbg.vm().mirrorOf(stringValue); + break; + case VariableNode.TYPE_LONG: + value = dbg.vm().mirrorOf(Long.parseLong(stringValue)); + break; + case VariableNode.TYPE_BYTE: + value = dbg.vm().mirrorOf(Byte.parseByte(stringValue)); + break; + case VariableNode.TYPE_DOUBLE: + value = dbg.vm().mirrorOf(Double.parseDouble(stringValue)); + break; + case VariableNode.TYPE_SHORT: + value = dbg.vm().mirrorOf(Short.parseShort(stringValue)); + break; + case VariableNode.TYPE_CHAR: + // TODO: better char support + if (stringValue.length() > 0) { + value = dbg.vm().mirrorOf(stringValue.charAt(0)); + } + break; + } + } catch (NumberFormatException ex) { + Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "invalid value entered for {0}: {1}", new Object[]{var.getName(), stringValue}); + } + if (value != null) { + var.setValue(value); + Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "new value set: {0}", var.getStringValue()); + } + } + + @Override + public String getColumnName(int i) { + return columnNames[i]; + } + } + + /** + * Renderer for the tree portion of the outline component. Handles icons, + * text color and tool tips. + */ + protected class OutlineRenderer implements RenderDataProvider { + + protected Icon[][] icons; + protected static final int ICON_SIZE = 16; // icon size (square, size=width=height) + + public OutlineRenderer() { + // load icons + icons = loadIcons("theme/var-icons.gif"); + } + + /** + * Load multiple icons (horizotal) with multiple states (vertical) from + * a single file. + * + * @param fileName file path in the mode folder. + * @return a nested array (first index: icon, second index: state) or + * null if the file wasn't found. + */ + protected ImageIcon[][] loadIcons(String fileName) { + ExperimentalMode mode = editor.mode(); + File file = mode.getContentFile(fileName); + if (!file.exists()) { + Logger.getLogger(OutlineRenderer.class.getName()).log(Level.SEVERE, "icon file not found: {0}", file.getAbsolutePath()); + return null; + } + Image allIcons = mode.loadImage(fileName); + int cols = allIcons.getWidth(null) / ICON_SIZE; + int rows = allIcons.getHeight(null) / ICON_SIZE; + ImageIcon[][] iconImages = new ImageIcon[cols][rows]; + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + //Image image = createImage(ICON_SIZE, ICON_SIZE); + Image image = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB); + Graphics g = image.getGraphics(); + g.drawImage(allIcons, -i * ICON_SIZE, -j * ICON_SIZE, null); + iconImages[i][j] = new ImageIcon(image); + } + } + return iconImages; + } + + protected Icon getIcon(int type, int state) { + if (type < 0 || type > icons.length - 1) { + return null; + } + return icons[type][state]; + } + + protected VariableNode toVariableNode(Object o) { + if (o instanceof VariableNode) { + return (VariableNode) o; + } else { + return null; + } + } + + protected Icon toGray(Icon icon) { + if (icon instanceof ImageIcon) { + Image grayImage = GrayFilter.createDisabledImage(((ImageIcon) icon).getImage()); + return new ImageIcon(grayImage); + } + // Cannot convert + return icon; + } + + @Override + public String getDisplayName(Object o) { + return o.toString(); // VariableNode.toString() returns name; (for sorting) +// VariableNode var = toVariableNode(o); +// if (var != null) { +// return var.getName(); +// } else { +// return o.toString(); +// } + } + + @Override + public boolean isHtmlDisplayName(Object o) { + return false; + } + + @Override + public Color getBackground(Object o) { + return null; + } + + @Override + public Color getForeground(Object o) { + if (tree.isEnabled()) { + return null; // default + } else { + return Color.GRAY; + } + } + + @Override + public String getTooltipText(Object o) { + VariableNode var = toVariableNode(o); + if (var != null) { + return var.getDescription(); + } else { + return ""; + } + } + + @Override + public Icon getIcon(Object o) { + VariableNode var = toVariableNode(o); + if (var != null) { + if (tree.isEnabled()) { + return getIcon(var.getType(), 0); + } else { + return getIcon(var.getType(), 1); + } + } else { + if (o instanceof TreeNode) { +// TreeNode node = (TreeNode) o; +// AbstractLayoutCache layout = tree.getLayoutCache(); + UIDefaults defaults = UIManager.getDefaults(); + + boolean isLeaf = model.isLeaf(o); + Icon icon; + if (isLeaf) { + icon = defaults.getIcon("Tree.leafIcon"); + } else { + icon = defaults.getIcon("Tree.closedIcon"); + } + + if (!tree.isEnabled()) { + return toGray(icon); + } + return icon; + } + } + return null; // use standard icon + //UIManager.getIcon(o); + } + } + + // TODO: could probably extend the simpler javax.swing.table.DefaultTableCellRenderer here + /** + * Renderer for the value column. Uses an italic font for null values and + * Object values ("instance of ..."). Uses a gray color when tree is not + * enabled. + */ + protected class ValueCellRenderer extends DefaultOutlineCellRenderer { + + public ValueCellRenderer() { + super(); + } + + protected void setItalic(boolean on) { + if (on) { + setFont(new Font(getFont().getName(), Font.ITALIC, getFont().getSize())); + } else { + setFont(new Font(getFont().getName(), Font.PLAIN, getFont().getSize())); + } + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + if (!tree.isEnabled()) { + setForeground(Color.GRAY); + } else { + setForeground(Color.BLACK); + } + + if (value instanceof VariableNode) { + VariableNode var = (VariableNode) value; + + if (var.getValue() == null || var.getType() == VariableNode.TYPE_OBJECT) { + setItalic(true); + } else { + setItalic(false); + } + value = var.getStringValue(); + } + + setValue(value); + return c; + } + } + + /** + * Editor for the value column. Will show an empty string when editing + * String values that are null. + */ + protected class ValueCellEditor extends DefaultCellEditor { + + public ValueCellEditor() { + super(new JTextField()); + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + if (!(value instanceof VariableNode)) { + return super.getTableCellEditorComponent(table, value, isSelected, row, column); + } + VariableNode var = (VariableNode) value; + if (var.getType() == VariableNode.TYPE_STRING && var.getValue() == null) { + return super.getTableCellEditorComponent(table, "", isSelected, row, column); + } else { + return super.getTableCellEditorComponent(table, var.getStringValue(), isSelected, row, column); + } + } + } + + /** + * Handler for expanding and collapsing tree nodes. Implements lazy loading + * of tree data (on expand). + */ + protected class ExpansionHandler implements ExtTreeWillExpandListener, TreeExpansionListener { + + @Override + public void treeWillExpand(TreeExpansionEvent tee) throws ExpandVetoException { + //System.out.println("will expand"); + Object last = tee.getPath().getLastPathComponent(); + if (!(last instanceof VariableNode)) { + return; + } + VariableNode var = (VariableNode) last; + // load children +// if (!dbg.isPaused()) { +// System.out.println("throwing veto"); +// //throw new ExpandVetoException(tee, "Debugger busy"); +// } else { + var.removeAllChildren(); // TODO: should we only load it once? + // TODO: don't filter in advanced mode + //System.out.println("loading children for: " + var); + // true means include inherited + var.addChildren(filterNodes(dbg.getFields(var.getValue(), 0, true), new ThisFilter())); +// } + } + + @Override + public void treeWillCollapse(TreeExpansionEvent tee) throws ExpandVetoException { + //throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void treeExpanded(TreeExpansionEvent tee) { + //System.out.println("expanded: " + tee.getPath()); + if (!expandedNodes.contains(tee.getPath())) { + expandedNodes.add(tee.getPath()); + } + +// TreePath newPath = tee.getPath(); +// if (expandedLast != null) { +// // test each node of the path for equality +// for (int i = 0; i < expandedLast.getPathCount(); i++) { +// if (i < newPath.getPathCount()) { +// Object last = expandedLast.getPathComponent(i); +// Object cur = newPath.getPathComponent(i); +// System.out.println(last + " =? " + cur + ": " + last.equals(cur) + "/" + (last.hashCode() == cur.hashCode())); +// } +// } +// } +// System.out.println("path equality: " + newPath.equals(expandedLast)); +// expandedLast = newPath; + } + + @Override + public void treeCollapsed(TreeExpansionEvent tee) { + //System.out.println("collapsed: " + tee.getPath()); + + // first remove all children of collapsed path + // this makes sure children do not appear before parents in the list. + // (children can't be expanded before their parents) + List removalList = new ArrayList(); + for (TreePath path : expandedNodes) { + if (path.getParentPath().equals(tee.getPath())) { + removalList.add(path); + } + } + for (TreePath path : removalList) { + expandedNodes.remove(path); + } + // remove collapsed path + expandedNodes.remove(tee.getPath()); + } + + @Override + public void treeExpansionVetoed(TreeExpansionEvent tee, ExpandVetoException eve) { + //System.out.println("expansion vetoed"); + // nop + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + scrollPane = new javax.swing.JScrollPane(); + tree = new org.netbeans.swing.outline.Outline(); + + scrollPane.setViewportView(tree); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + +// /** +// * @param args the command line arguments +// */ +// public static void main(String args[]) { +// /* +// * Set the Nimbus look and feel +// */ +// // +// /* +// * If Nimbus (introduced in Java SE 6) is not available, stay with the +// * default look and feel. For details see +// * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html +// */ +// try { +// javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); +// } catch (ClassNotFoundException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } catch (InstantiationException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } catch (IllegalAccessException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } catch (javax.swing.UnsupportedLookAndFeelException ex) { +// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); +// } +// // +// +// /* +// * Create and display the form +// */ +// run(new VariableInspector()); +// } + protected static void run(final VariableInspector vi) { + /* + * Create and display the form + */ + java.awt.EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + vi.setVisible(true); + } + }); + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane scrollPane; + protected org.netbeans.swing.outline.Outline tree; + // End of variables declaration//GEN-END:variables + + /** + * Access the root node of the tree. + * + * @return the root node + */ + public DefaultMutableTreeNode getRootNode() { + return rootNode; + } + + /** + * Unlock the inspector window. Rebuild after this to avoid ... dots in the + * trees labels + */ + public void unlock() { + tree.setEnabled(true); + } + + /** + * Lock the inspector window. Cancels open edits. + */ + public void lock() { + if (tree.getCellEditor() != null) { + //tree.getCellEditor().stopCellEditing(); // force quit open edit + tree.getCellEditor().cancelCellEditing(); // cancel an open edit + } + tree.setEnabled(false); + } + + /** + * Reset the inspector windows data. Rebuild after this to make changes + * visible. + */ + public void reset() { + rootNode.removeAllChildren(); + // clear local data for good measure (in case someone rebuilds) + callStack.clear(); + locals.clear(); + thisFields.clear(); + declaredThisFields.clear(); + expandedNodes.clear(); + // update + treeModel.nodeStructureChanged(rootNode); + } + +// public void setAdvancedMode() { +// p5mode = false; +// } +// +// public void setP5Mode() { +// p5mode = true; +// } +// +// public void toggleMode() { +// if (p5mode) { +// setAdvancedMode(); +// } else { +// setP5Mode(); +// } +// } + /** + * Update call stack data. + * + * @param nodes a list of nodes that represent the call stack. + * @param title the title to be used when labeling or otherwise grouping + * call stack data. + */ + public void updateCallStack(List nodes, String title) { + callStack = nodes; + } + + /** + * Update locals data. + * + * @param nodes a list of {@link VariableNode} to be shown as local + * variables in the inspector. + * @param title the title to be used when labeling or otherwise grouping + * locals data. + */ + public void updateLocals(List nodes, String title) { + locals = nodes; + } + + /** + * Update this-fields data. + * + * @param nodes a list of {@link VariableNode}s to be shown as this-fields + * in the inspector. + * @param title the title to be used when labeling or otherwise grouping + * this-fields data. + */ + public void updateThisFields(List nodes, String title) { + thisFields = nodes; + } + + /** + * Update declared (non-inherited) this-fields data. + * + * @param nodes a list of {@link VariableNode}s to be shown as declared + * this-fields in the inspector. + * @param title the title to be used when labeling or otherwise grouping + * declared this-fields data. + */ + public void updateDeclaredThisFields(List nodes, String title) { + declaredThisFields = nodes; + } + + /** + * Rebuild the outline tree from current data. Uses the data provided by + * {@link #updateCallStack}, {@link #updateLocals}, {@link #updateThisFields} + * and {@link #updateDeclaredThisFields} + */ + public void rebuild() { + rootNode.removeAllChildren(); + if (p5mode) { + // add all locals to root + addAllNodes(rootNode, locals); + + // add non-inherited this fields + addAllNodes(rootNode, filterNodes(declaredThisFields, new LocalHidesThisFilter(locals, LocalHidesThisFilter.MODE_PREFIX))); + + // add p5 builtins in a new folder + builtins.removeAllChildren(); + addAllNodes(builtins, filterNodes(thisFields, new P5BuiltinsFilter())); + if (builtins.getChildCount() > 0) { // skip builtins in certain situations e.g. in pure java tabs. + rootNode.add(builtins); + } + + // notify tree (using model) changed a node and its children + // http://stackoverflow.com/questions/2730851/how-to-update-jtree-elements + // needs to be done before expanding paths! + treeModel.nodeStructureChanged(rootNode); + + // handle node expansions + for (TreePath path : expandedNodes) { + //System.out.println("re-expanding: " + path); + path = synthesizePath(path); + if (path != null) { + tree.expandPath(path); + } else { + //System.out.println("couldn't synthesize path"); + } + } + + // this expansion causes problems when sorted and stepping + //tree.expandPath(new TreePath(new Object[]{rootNode, builtins})); + + } else { + // TODO: implement advanced mode here + } + } + + /** + * Re-build a {@link TreePath} from a previous path using equals-checks + * starting at the root node. This is used to use paths from previous trees + * for use on the current tree. + * + * @param path the path to synthesize. + * @return the rebuilt path, usable on the current tree. + */ + protected TreePath synthesizePath(TreePath path) { + //System.out.println("synthesizing: " + path); + if (path.getPathCount() == 0 || !rootNode.equals(path.getPathComponent(0))) { + return null; + } + Object[] newPath = new Object[path.getPathCount()]; + newPath[0] = rootNode; + TreeNode currentNode = rootNode; + for (int i = 0; i < path.getPathCount() - 1; i++) { + // get next node + for (int j = 0; j < currentNode.getChildCount(); j++) { + TreeNode nextNode = currentNode.getChildAt(j); + if (nextNode.equals(path.getPathComponent(i + 1))) { + currentNode = nextNode; + newPath[i + 1] = nextNode; + //System.out.println("found node " + (i+1) + ": " + nextNode); + break; + } + } + if (newPath[i + 1] == null) { + //System.out.println("didn't find node"); + return null; + } + } + return new TreePath(newPath); + } + + /** + * Filter a list of nodes using a {@link VariableNodeFilter}. + * + * @param nodes the list of nodes to filter. + * @param filter the filter to be used. + * @return the filtered list. + */ + protected List filterNodes(List nodes, VariableNodeFilter filter) { + List filtered = new ArrayList(); + for (VariableNode node : nodes) { + if (filter.accept(node)) { + filtered.add(node); + } + } + return filtered; + } + + /** + * Add all nodes in a list to a root node. + * + * @param root the root node to add to. + * @param nodes the list of nodes to add. + */ + protected void addAllNodes(DefaultMutableTreeNode root, List nodes) { + for (MutableTreeNode node : nodes) { + root.add(node); + } + } + + /** + * A filter for {@link VariableNode}s. + */ + public interface VariableNodeFilter { + + /** + * Check whether the filter accepts a {@link VariableNode}. + * + * @param var the input node + * @return true when the filter accepts the input node otherwise false. + */ + public boolean accept(VariableNode var); + } + + /** + * A {@link VariableNodeFilter} that accepts Processing built-in variable + * names. + */ + public class P5BuiltinsFilter implements VariableNodeFilter { + + protected String[] p5Builtins = { + "focused", + "frameCount", + "frameRate", + "height", + "online", + "screen", + "width", + "mouseX", + "mouseY", + "pmouseX", + "pmouseY", + "key", + "keyCode", + "keyPressed" + }; + + @Override + public boolean accept(VariableNode var) { + return Arrays.asList(p5Builtins).contains(var.getName()); + } + } + + /** + * A {@link VariableNodeFilter} that rejects implicit this references. + * (Names starting with "this$") + */ + public class ThisFilter implements VariableNodeFilter { + + @Override + public boolean accept(VariableNode var) { + return !var.getName().startsWith("this$"); + } + } + + /** + * A {@link VariableNodeFilter} that either rejects this-fields if hidden by + * a local, or prefixes its name with "this." + */ + public class LocalHidesThisFilter implements VariableNodeFilter { + + /** + * Reject a this-field if hidden by a local. + */ + public static final int MODE_HIDE = 0; // don't show hidden this fields + /** + * Prefix a this-fields name with "this." if hidden by a local. + */ + public static final int MODE_PREFIX = 1; // prefix hidden this fields with "this." + protected List locals; + protected int mode; + + /** + * Construct a {@link LocalHidesThisFilter}. + * + * @param locals a list of locals to check against + * @param mode either {@link #MODE_HIDE} or {@link #MODE_PREFIX} + */ + public LocalHidesThisFilter(List locals, int mode) { + this.locals = locals; + this.mode = mode; + } + + @Override + public boolean accept(VariableNode var) { + // check if the same name appears in the list of locals i.e. the local hides the field + for (VariableNode local : locals) { + if (var.getName().equals(local.getName())) { + switch (mode) { + case MODE_PREFIX: + var.setName("this." + var.getName()); + return true; + case MODE_HIDE: + return false; + } + } + } + return true; + } + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/VariableNode.java b/pdex/experimental/src/processing/mode/experimental/VariableNode.java new file mode 100755 index 000000000..66b0575d7 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/VariableNode.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2012 Martin Leopold + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package processing.mode.experimental; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.StringReference; +import com.sun.jdi.Value; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; + +/** + * Model for a variable in the variable inspector. Has a type and name and + * optionally a value. Can have sub-variables (as is the case for objects, and + * arrays). + * + * @author Martin Leopold + */ +public class VariableNode implements MutableTreeNode { + + public static final int TYPE_UNKNOWN = -1; + public static final int TYPE_OBJECT = 0; + public static final int TYPE_ARRAY = 1; + public static final int TYPE_INTEGER = 2; + public static final int TYPE_FLOAT = 3; + public static final int TYPE_BOOLEAN = 4; + public static final int TYPE_CHAR = 5; + public static final int TYPE_STRING = 6; + public static final int TYPE_LONG = 7; + public static final int TYPE_DOUBLE = 8; + public static final int TYPE_BYTE = 9; + public static final int TYPE_SHORT = 10; + public static final int TYPE_VOID = 11; + protected String type; + protected String name; + protected Value value; + protected List children = new ArrayList(); + protected MutableTreeNode parent; + + /** + * Construct a {@link VariableNode}. + * @param name the name + * @param type the type + * @param value the value + */ + public VariableNode(String name, String type, Value value) { + this.name = name; + this.type = type; + this.value = value; + } + + public void setValue(Value value) { + this.value = value; + } + + public Value getValue() { + return value; + } + + /** + * Get a String representation of this variable nodes value. + * + * @return a String representing the value. + */ + public String getStringValue() { + String str; + if (value != null) { + if (getType() == TYPE_OBJECT) { + str = "instance of " + type; + } else if (getType() == TYPE_ARRAY) { + //instance of int[5] (id=998) --> instance of int[5] + str = value.toString().substring(0, value.toString().lastIndexOf(" ")); + } else if (getType() == TYPE_STRING) { + str = ((StringReference) value).value(); // use original string value (without quotes) + } else { + str = value.toString(); + } + } else { + str = "null"; + } + return str; + } + + public String getTypeName() { + return type; + } + + public int getType() { + if (type == null) { + return TYPE_UNKNOWN; + } + if (type.endsWith("[]")) { + return TYPE_ARRAY; + } + if (type.equals("int")) { + return TYPE_INTEGER; + } + if (type.equals("long")) { + return TYPE_LONG; + } + if (type.equals("byte")) { + return TYPE_BYTE; + } + if (type.equals("short")) { + return TYPE_SHORT; + } + if (type.equals("float")) { + return TYPE_FLOAT; + } + if (type.equals("double")) { + return TYPE_DOUBLE; + } + if (type.equals("char")) { + return TYPE_CHAR; + } + if (type.equals("java.lang.String")) { + return TYPE_STRING; + } + if (type.equals("boolean")) { + return TYPE_BOOLEAN; + } + if (type.equals("void")) { + return TYPE_VOID; //TODO: check if this is correct + } + return TYPE_OBJECT; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * Add a {@link VariableNode} as child. + * + * @param c the {@link VariableNode} to add. + */ + public void addChild(VariableNode c) { + children.add(c); + c.setParent(this); + } + + /** + * Add multiple {@link VariableNode}s as children. + * + * @param children the list of {@link VariableNode}s to add. + */ + public void addChildren(List children) { + for (VariableNode child : children) { + addChild(child); + } + } + + @Override + public TreeNode getChildAt(int i) { + return children.get(i); + } + + @Override + public int getChildCount() { + return children.size(); + } + + @Override + public TreeNode getParent() { + return parent; + } + + @Override + public int getIndex(TreeNode tn) { + return children.indexOf(tn); + } + + @Override + public boolean getAllowsChildren() { + if (value == null) { + return false; + } + + // handle strings + if (getType() == TYPE_STRING) { + return false; + } + + // handle arrays + if (getType() == TYPE_ARRAY) { + ArrayReference array = (ArrayReference) value; + return array.length() > 0; + } + // handle objects + if (getType() == TYPE_OBJECT) { // this also rules out null + // check if this object has any fields + ObjectReference obj = (ObjectReference) value; + return !obj.referenceType().visibleFields().isEmpty(); + } + + return false; + } + + /** + * This controls the default icon and disclosure triangle. + * + * @return true, will show "folder" icon and disclosure triangle. + */ + @Override + public boolean isLeaf() { + //return children.size() == 0; + return !getAllowsChildren(); + } + + @Override + public Enumeration children() { + return Collections.enumeration(children); + } + + /** + * Get a String representation of this {@link VariableNode}. + * + * @return the name of the variable (for sorting to work). + */ + @Override + public String toString() { + return getName(); // for sorting + } + + /** + * Get a String description of this {@link VariableNode}. Contains the type, + * name and value. + * + * @return the description + */ + public String getDescription() { + String str = ""; + if (type != null) { + str += type + " "; + } + str += name; + str += " = " + getStringValue(); + return str; + } + + @Override + public void insert(MutableTreeNode mtn, int i) { + children.add(i, this); + } + + @Override + public void remove(int i) { + MutableTreeNode mtn = children.remove(i); + if (mtn != null) { + mtn.setParent(null); + } + } + + @Override + public void remove(MutableTreeNode mtn) { + children.remove(mtn); + mtn.setParent(null); + } + + /** + * Remove all children from this {@link VariableNode}. + */ + public void removeAllChildren() { + for (MutableTreeNode mtn : children) { + mtn.setParent(null); + } + children.clear(); + } + + @Override + public void setUserObject(Object o) { + if (o instanceof Value) { + value = (Value) o; + } + } + + @Override + public void removeFromParent() { + parent.remove(this); + this.parent = null; + } + + @Override + public void setParent(MutableTreeNode mtn) { + parent = mtn; + } + + /** + * Test for equality. To be equal, two {@link VariableNode}s need to have + * equal type, name and value. + * + * @param obj the object to test for equality with this {@link VariableNode} + * @return true if the given object is equal to this {@link VariableNode} + */ + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final VariableNode other = (VariableNode) obj; + if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) { + //System.out.println("type not equal"); + return false; + } + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + //System.out.println("name not equal"); + return false; + } + if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { + //System.out.println("value not equal"); + return false; + } +// if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) { +// System.out.println("parent not equal: " + this.parent + "/" + other.parent); +// return false; +// } + return true; + } + + /** + * Returns a hash code based on type, name and value. + */ + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0); + hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); + hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0); +// hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0); + return hash; + } +} diff --git a/pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java b/pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java new file mode 100755 index 000000000..7d4ea9032 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java @@ -0,0 +1,131 @@ +package processing.mode.experimental; + +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.JPanel; + +/** + * Toggle Button displayed in the editor line status panel for toggling bewtween + * console and problems list. Glorified JPanel. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ + +public class XQConsoleToggle extends JPanel implements MouseListener { + public static final String[] text = { "Console", "Errors" }; + + private boolean toggleText = true; + private boolean toggleBG = true; + + /** + * Height of the component + */ + protected int height; + protected DebugEditor editor; + protected String buttonName; + + public XQConsoleToggle(DebugEditor editor, String buttonName, int height) { + this.editor = editor; + this.height = height; + this.buttonName = buttonName; + } + + public Dimension getPreferredSize() { + return new Dimension(70, height); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public Dimension getMaximumSize() { + return getPreferredSize(); + } + + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // On mouse hover, text and background color are changed. + if (toggleBG) { + g.setColor(new Color(0xff9DA7B0)); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.setColor(new Color(0xff29333D)); + g.fillRect(0, 0, 4, this.getHeight()); + g.setColor(Color.BLACK); + } else { + g.setColor(Color.DARK_GRAY); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.setColor(new Color(0xff29333D)); + g.fillRect(0, 0, 4, this.getHeight()); + g.setColor(Color.WHITE); + } + + g.drawString(buttonName, getWidth() / 2 + 2 // + 2 is a offset + - getFontMetrics(getFont()).stringWidth(buttonName) / 2, + this.getHeight() - 6); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + + this.repaint(); + try { + editor.toggleView(buttonName); + } catch (Exception e) { + System.out.println(e); + // e.printStackTrace(); + } + toggleText = !toggleText; + } + + @Override + public void mouseEntered(MouseEvent arg0) { + toggleBG = !toggleBG; + this.repaint(); + } + + @Override + public void mouseExited(MouseEvent arg0) { + toggleBG = !toggleBG; + this.repaint(); + } + + @Override + public void mousePressed(MouseEvent arg0) { + } + + @Override + public void mouseReleased(MouseEvent arg0) { + } +} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/XQErrorTable.java b/pdex/experimental/src/processing/mode/experimental/XQErrorTable.java new file mode 100755 index 000000000..e64cf2c4b --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/XQErrorTable.java @@ -0,0 +1,166 @@ +package processing.mode.experimental; + +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableModel; + +/** + * Custom JTable implementation for XQMode. Minor tweaks and addtions. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class XQErrorTable extends JTable { + + /** + * Column Names of JTable + */ + public static final String[] columnNames = { "Problem", "Tab", "Line" }; + + /** + * Column Widths of JTable. + */ + public int[] columnWidths = { 600, 100, 50 }; // Default Values + + /** + * Is the column being resized? + */ + private boolean columnResizing = false; + + /** + * ErrorCheckerService instance + */ + protected ErrorCheckerService errorCheckerService; + + @Override + public boolean isCellEditable(int rowIndex, int colIndex) { + return false; // Disallow the editing of any cell + } + + public XQErrorTable(final ErrorCheckerService errorCheckerService) { + this.errorCheckerService = errorCheckerService; + for (int i = 0; i < this.getColumnModel().getColumnCount(); i++) { + this.getColumnModel().getColumn(i) + .setPreferredWidth(columnWidths[i]); + } + + this.getTableHeader().setReorderingAllowed(false); + + this.addMouseListener(new MouseAdapter() { + @Override + synchronized public void mouseReleased(MouseEvent e) { + try { + errorCheckerService.scrollToErrorLine(((XQErrorTable) e + .getSource()).getSelectedRow()); + // System.out.print("Row clicked: " + // + ((XQErrorTable) e.getSource()).getSelectedRow()); + } catch (Exception e1) { + System.out.println("Exception XQErrorTable mouseReleased " + + e); + } + } + }); + + // Handles the resizing of columns. When mouse press is detected on + // table header, Stop updating the table, store new values of column + // widths,and resume updating. Updating is disabled as long as + // columnResizing is true + this.getTableHeader().addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + columnResizing = true; + } + + @Override + public void mouseReleased(MouseEvent e) { + columnResizing = false; + for (int i = 0; i < ((JTableHeader) e.getSource()) + .getColumnModel().getColumnCount(); i++) { + columnWidths[i] = ((JTableHeader) e.getSource()) + .getColumnModel().getColumn(i).getWidth(); + // System.out.println("nw " + columnWidths[i]); + } + } + }); + } + + + /** + * Updates table contents with new data + * @param tableModel - TableModel + * @return boolean - If table data was updated + */ + @SuppressWarnings("rawtypes") + synchronized public boolean updateTable(final TableModel tableModel) { + + // If problems list is not visible, no need to update + if (!this.isVisible()) { + return false; + } + + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + + try { + setModel(tableModel); + + // Set column widths to user defined widths + for (int i = 0; i < getColumnModel().getColumnCount(); i++) { + getColumnModel().getColumn(i).setPreferredWidth( + columnWidths[i]); + } + getTableHeader().setReorderingAllowed(false); + validate(); + repaint(); + } catch (Exception e) { + System.out.println("Exception at XQErrorTable.updateTable " + e); + // e.printStackTrace(); + } + } + }; + + try { + if (!columnResizing) { + worker.execute(); + } + } catch (Exception e) { + System.out.println("ErrorTable updateTable Worker's slacking." + + e.getMessage()); + // e.printStackTrace(); + } + return true; + } + +} diff --git a/pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java b/pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java new file mode 100755 index 000000000..34ee2a9a2 --- /dev/null +++ b/pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java @@ -0,0 +1,245 @@ +/* + Part of the XQMode project - https://github.com/Manindra29/XQMode + + Under Google Summer of Code 2012 - + http://www.google-melange.com/gsoc/homepage/google/gsoc2012 + + Copyright (C) 2012 Manindra Moharana + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package processing.mode.experimental; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.TextEdit; + +import processing.mode.java.preproc.PdePreprocessor; + +/** + * My implementation of P5 preprocessor. Uses Eclipse JDT features instead of + * ANTLR. Performance gains mostly and full control over debug output. But needs + * lots and lots of testing. There will always an option to switch back to PDE + * preproc. + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ +public class XQPreprocessor { + + private ASTRewrite rewrite = null; + private ArrayList imports; + private ArrayList extraImports; + + private String[] coreImports, defaultImports; + + public XQPreprocessor() { + PdePreprocessor p = new PdePreprocessor(null); + defaultImports = p.getDefaultImports(); + coreImports = p.getCoreImports(); + } + + /** + * The main method that performs preprocessing. Converts code into compilable java. + * @param source - String + * @param programImports - List of import statements + * @return String - Compile ready java code + */ + public String doYourThing(String source, + ArrayList programImports) { + this.extraImports = programImports; + //source = prepareImports() + source; + Document doc = new Document(source); + + ASTParser parser = ASTParser.newParser(AST.JLS4); + parser.setSource(doc.get().toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + @SuppressWarnings("unchecked") + Map options = JavaCore.getOptions(); + + // Ben has decided to move on to 1.6. Yay! + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + parser.setCompilerOptions(options); + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + cu.recordModifications(); + rewrite = ASTRewrite.create(cu.getAST()); + cu.accept(new XQASTVisitor()); + + TextEdit edits = cu.rewrite(doc, null); + try { + edits.apply(doc); + } catch (MalformedTreeException e) { + e.printStackTrace(); + } catch (BadLocationException e) { + e.printStackTrace(); + } + // System.out.println("------------XQPreProc-----------------"); + // System.out.println(doc.get()); + // System.out.println("------------XQPreProc End-----------------"); + + // Calculate main class offset + int position = doc.get().indexOf("{") + 1; + int lines = 0; + for (int i = 0; i < position; i++) { + if (doc.get().charAt(i) == '\n') { + lines++; + } + } + lines += 2; + // System.out.println("Lines: " + lines); + + return doc.get(); + } + + /** + * Returns all import statements as lines of code + * + * @return String - All import statements combined. Each import in a separate line. + */ + public String prepareImports() { + imports = new ArrayList(); + for (int i = 0; i < extraImports.size(); i++) { + imports.add(new String(extraImports.get(i).importName)); + } + imports.add(new String("// Default Imports")); + for (int i = 0; i < coreImports.length; i++) { + imports.add(new String("import " + coreImports[i] + ";")); + } + for (int i = 0; i < defaultImports.length; i++) { + imports.add(new String("import " + defaultImports[i] + ";")); + } + String totalImports = ""; + for (int i = 0; i < imports.size(); i++) { + totalImports += imports.get(i) + "\n"; + } + totalImports += "\n"; + return totalImports; + } + + public String prepareImports(ArrayList programImports) { + this.extraImports = programImports; + return prepareImports(); + } + + /** + * Visitor implementation that does all the substitution dirty work.
    + *
  • Any function not specified as being protected or private will be made + * 'public'. This means that void setup() becomes + * public void setup(). + * + *
  • Converts doubles into floats, i.e. 12.3 becomes 12.3f so that people + * don't have to add f after their numbers all the time since it's confusing + * for beginners. Also, most functions of p5 core deal with floats only. + * + * @author Manindra Moharana + * + */ + private class XQASTVisitor extends ASTVisitor { + @SuppressWarnings({ "unchecked", "rawtypes" }) + public boolean visit(MethodDeclaration node) { + if (node.getReturnType2() != null) { + // if return type is color, make it int + // if (node.getReturnType2().toString().equals("color")) { + // System.err.println("color type detected!"); + // node.setReturnType2(rewrite.getAST().newPrimitiveType( + // PrimitiveType.INT)); + // } + + // The return type is not void, no need to make it public + // if (!node.getReturnType2().toString().equals("void")) + // return true; + } + + // Simple method, make it public + if (node.modifiers().size() == 0 && !node.isConstructor()) { + // rewrite.set(node, node.getModifiersProperty(), + // Modifier.PUBLIC, + // null); + // rewrite.getListRewrite(node, + // node.getModifiersProperty()).insertLast(Modifier., null) + List newMod = rewrite.getAST().newModifiers(Modifier.PUBLIC); + node.modifiers().add(newMod.get(0)); + } + + return true; + } + + public boolean visit(NumberLiteral node) { + if (!node.getToken().endsWith("f") + && !node.getToken().endsWith("d")) { + for (int i = 0; i < node.getToken().length(); i++) { + if (node.getToken().charAt(i) == '.') { + + String s = node.getToken() + "f"; + node.setToken(s); + break; + } + } + } + return true; + } + + // public boolean visit(FieldDeclaration node) { + // if (node.getType().toString().equals("color")){ + // System.err.println("color type detected!"); + // node.setType(rewrite.getAST().newPrimitiveType( + // PrimitiveType.INT)); + // } + // return true; + // } + // + // public boolean visit(VariableDeclarationStatement node) { + // if (node.getType().toString().equals("color")){ + // System.err.println("color type detected!"); + // node.setType(rewrite.getAST().newPrimitiveType( + // PrimitiveType.INT)); + // } + // return true; + // } + + /** + * This is added just for debugging purposes - to make sure that all + * instances of color type have been substituded as in by the regex + * search in ErrorCheckerService.preprocessCode(). + */ + public boolean visit(SimpleType node) { + if (node.toString().equals("color")) { + System.err + .println("color type detected! \nThis shouldn't be happening! Please report this as an issue."); + } + return true; + + } + + } + +} diff --git a/pdex/experimental/theme/theme.txt b/pdex/experimental/theme/theme.txt new file mode 100755 index 000000000..1a6179f5c --- /dev/null +++ b/pdex/experimental/theme/theme.txt @@ -0,0 +1,34 @@ +# DEBUGGER + +# breakpointed line background color +breakpoint.bgcolor = #f0f0f0 +# marker for breakpointed lines in left hand gutter (2 ascii characters) +breakpoint.marker = <> +breakpoint.marker.color = #4a545e + +# current line background color +currentline.bgcolor = #ffff96 +# marker for the current line in left hand gutter (2 ascii characters) +currentline.marker = -> +currentline.marker.color = #e27500 + +# left hand gutter background color +gutter.bgcolor = #fcfcfc +# color of vertical separation line +gutter.linecolor = #e9e9e9 +# space (in px) added to left and right of gutter markers +gutter.padding = 3 + + +# XQMODE + +# underline colors +editor.errorcolor = #ed2630 +editor.warningcolor = #ffc30e +editor.errormarkercolor = #ed2630 +editor.warningmarkercolor = #ffc30e + +# ERROR BAR - error bar on the right that shows the markers +errorbar.errorcolor = #ed2630 +errorbar.warningcolor = #ffc30e +errorbar.backgroundcolor = #2c343d diff --git a/pdex/experimental/theme/var-icons.gif b/pdex/experimental/theme/var-icons.gif new file mode 100755 index 0000000000000000000000000000000000000000..1d0086a38ebb728a2a44d3b4d510cf12992fc1dd GIT binary patch literal 5152 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 Date: Sat, 29 Jun 2013 14:00:22 +0530 Subject: [PATCH 074/608] removing extra dir --- pdex/experimental/.classpath | 23 - .../.externalToolBuilders/Auto_Builder.launch | 17 - pdex/experimental/.gitignore | 1 - pdex/experimental/.project | 27 - .../.settings/org.eclipse.jdt.core.prefs | 11 - pdex/experimental/Todo, GSoC 2013.txt | 65 - pdex/experimental/build.xml | 65 - pdex/experimental/mode/.gitignore | 1 - pdex/experimental/mode/readme.txt | 5 - .../mode/experimental/ASTGenerator.java | 2329 ----------------- .../mode/experimental/ASTNodeWrapper.java | 425 --- .../mode/experimental/ArrayFieldNode.java | 65 - .../mode/experimental/ClassLoadListener.java | 37 - .../mode/experimental/Compiler.java | 367 --- .../experimental/CompletionCandidate.java | 130 - .../mode/experimental/CompletionPanel.java | 153 -- .../mode/experimental/DebugBuild.java | 73 - .../mode/experimental/DebugEditor.java | 1165 --------- .../mode/experimental/DebugRunner.java | 85 - .../mode/experimental/DebugToolbar.java | 249 -- .../mode/experimental/Debugger.java | 1364 ---------- .../mode/experimental/ErrorBar.java | 385 --- .../experimental/ErrorCheckerService.java | 1297 --------- .../mode/experimental/ErrorMarker.java | 36 - .../mode/experimental/ErrorWindow.java | 374 --- .../mode/experimental/ExperimentalMode.java | 171 -- .../mode/experimental/FieldNode.java | 65 - .../mode/experimental/ImportStatement.java | 57 - .../mode/experimental/JavadocHelper.java | 126 - .../mode/experimental/LineBreakpoint.java | 218 -- .../mode/experimental/LineHighlight.java | 196 -- .../processing/mode/experimental/LineID.java | 269 -- .../mode/experimental/LineListener.java | 35 - .../mode/experimental/LocalVariableNode.java | 66 - .../processing/mode/experimental/Problem.java | 160 -- .../mode/experimental/TextArea.java | 630 ----- .../mode/experimental/TextAreaPainter.java | 488 ---- .../mode/experimental/VMEventListener.java | 36 - .../mode/experimental/VMEventReader.java | 68 - .../mode/experimental/VariableInspector.form | 53 - .../mode/experimental/VariableInspector.java | 929 ------- .../mode/experimental/VariableNode.java | 358 --- .../mode/experimental/XQConsoleToggle.java | 131 - .../mode/experimental/XQErrorTable.java | 166 -- .../mode/experimental/XQPreprocessor.java | 245 -- pdex/experimental/theme/theme.txt | 34 - pdex/experimental/theme/var-icons.gif | Bin 5152 -> 0 bytes 47 files changed, 13250 deletions(-) delete mode 100644 pdex/experimental/.classpath delete mode 100644 pdex/experimental/.externalToolBuilders/Auto_Builder.launch delete mode 100644 pdex/experimental/.gitignore delete mode 100644 pdex/experimental/.project delete mode 100644 pdex/experimental/.settings/org.eclipse.jdt.core.prefs delete mode 100644 pdex/experimental/Todo, GSoC 2013.txt delete mode 100644 pdex/experimental/build.xml delete mode 100644 pdex/experimental/mode/.gitignore delete mode 100644 pdex/experimental/mode/readme.txt delete mode 100644 pdex/experimental/src/processing/mode/experimental/ASTGenerator.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/Compiler.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/CompletionPanel.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/DebugBuild.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/DebugEditor.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/DebugRunner.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/DebugToolbar.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/Debugger.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ErrorBar.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ErrorMarker.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ErrorWindow.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/FieldNode.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/ImportStatement.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/JavadocHelper.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/LineHighlight.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/LineID.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/LineListener.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/Problem.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/TextArea.java delete mode 100644 pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/VMEventListener.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/VMEventReader.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/VariableInspector.form delete mode 100755 pdex/experimental/src/processing/mode/experimental/VariableInspector.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/VariableNode.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/XQErrorTable.java delete mode 100755 pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java delete mode 100755 pdex/experimental/theme/theme.txt delete mode 100755 pdex/experimental/theme/var-icons.gif diff --git a/pdex/experimental/.classpath b/pdex/experimental/.classpath deleted file mode 100644 index 5bb5a9eb3..000000000 --- a/pdex/experimental/.classpath +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pdex/experimental/.externalToolBuilders/Auto_Builder.launch b/pdex/experimental/.externalToolBuilders/Auto_Builder.launch deleted file mode 100644 index dc7825b02..000000000 --- a/pdex/experimental/.externalToolBuilders/Auto_Builder.launch +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/pdex/experimental/.gitignore b/pdex/experimental/.gitignore deleted file mode 100644 index ba077a403..000000000 --- a/pdex/experimental/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bin diff --git a/pdex/experimental/.project b/pdex/experimental/.project deleted file mode 100644 index 85716855e..000000000 --- a/pdex/experimental/.project +++ /dev/null @@ -1,27 +0,0 @@ - - - processing-experimental - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Auto_Builder.launch - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/pdex/experimental/.settings/org.eclipse.jdt.core.prefs b/pdex/experimental/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 8000cd6ca..000000000 --- a/pdex/experimental/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/pdex/experimental/Todo, GSoC 2013.txt b/pdex/experimental/Todo, GSoC 2013.txt deleted file mode 100644 index 754eb4b3a..000000000 --- a/pdex/experimental/Todo, GSoC 2013.txt +++ /dev/null @@ -1,65 +0,0 @@ -TODO List for Experimental Mode Plus- GSOC 2013 - -This would also be a break down of my thought process and ideas as I tackle various tasks. Also lines are fairly long. Make sure you turn on word wrap. ;) - -Manindra Moharana (me@mkmoharana.com) - -* : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo - -Code Completion -============== -The big stuff: -x! Code competition for local code is working with recursive look up. -x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. -x Completion for external classes - ArrayList, HashMap, etc. -*! Recursive lookup for compiled(library) code! -*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned -ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. -*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. -x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. -* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. -*+ Differentiating between multiple statements on the same line. How to? - -Finer details -* Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. -* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? -* Sorted list of completion candidates - fields, then methods. It's unsorted presently. -*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. -* Reflection API - getMethods vs getDeclaredMethods. -* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? - -Offset Mapping -============== -First major hurdle is offset mapping -*! pde<->java code offset : precise conversion needed -x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. -* This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. -x Edge case - multiple statements in a single line -x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. -* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. - -Refactoring -=========== -Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. -1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. -2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. -x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. -x Renaming any constructor is equivalent to renaming the TD -3. Find corresponding PDE offsets of the SimpleNames, rename in each line. -x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. -4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. -* Undo misbehaves here, handle carefully. -* Handle saving. If sketch closed after renaming w/o saving find bugs. -* Refactoring ui -* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully - -Quick Navigation -================ -x Ctrl + Click on an element to scroll to its definition in code -x Local Vars -x Local Methods -x Local Classes -x Recursive lookup, a.b().c() -x Now highlihgting the declaration name, rather than the whole declaration. -*+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. - diff --git a/pdex/experimental/build.xml b/pdex/experimental/build.xml deleted file mode 100644 index 309946ae0..000000000 --- a/pdex/experimental/build.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pdex/experimental/mode/.gitignore b/pdex/experimental/mode/.gitignore deleted file mode 100644 index 9acf0e7e9..000000000 --- a/pdex/experimental/mode/.gitignore +++ /dev/null @@ -1 +0,0 @@ -experimental.jar diff --git a/pdex/experimental/mode/readme.txt b/pdex/experimental/mode/readme.txt deleted file mode 100644 index 2152b63de..000000000 --- a/pdex/experimental/mode/readme.txt +++ /dev/null @@ -1,5 +0,0 @@ -Packages from Eclipse 4.2.1: -http://download.eclipse.org/eclipse/downloads/ - -The jdi.jar and jdimodel.jar files are unpacked -from the org.eclipse.jdt.debug JAR file. diff --git a/pdex/experimental/src/processing/mode/experimental/ASTGenerator.java b/pdex/experimental/src/processing/mode/experimental/ASTGenerator.java deleted file mode 100644 index b4ebb3413..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ASTGenerator.java +++ /dev/null @@ -1,2329 +0,0 @@ -package processing.mode.experimental; - -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.GridLayout; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.TreeMap; - -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JEditorPane; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.JTextField; -import javax.swing.JTree; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.table.DefaultTableModel; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; - -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.dom.AST; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.Block; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.Expression; -import org.eclipse.jdt.core.dom.ExpressionStatement; -import org.eclipse.jdt.core.dom.FieldAccess; -import org.eclipse.jdt.core.dom.FieldDeclaration; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.MethodInvocation; -import org.eclipse.jdt.core.dom.Name; -import org.eclipse.jdt.core.dom.NodeFinder; -import org.eclipse.jdt.core.dom.QualifiedName; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.core.dom.SimpleType; -import org.eclipse.jdt.core.dom.SingleVariableDeclaration; -import org.eclipse.jdt.core.dom.StringLiteral; -import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; -import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.dom.VariableDeclarationExpression; -import org.eclipse.jdt.core.dom.VariableDeclarationFragment; -import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; - -import processing.app.Base; -import processing.app.SketchCode; - -import com.google.classpath.ClassPath; -import com.google.classpath.ClassPathFactory; -import com.google.classpath.RegExpResourceFilter; -import com.ibm.icu.util.StringTokenizer; -import com.sun.org.apache.bcel.internal.generic.GETSTATIC; -import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs; - -public class ASTGenerator { - - protected ErrorCheckerService errorCheckerService; - - protected DebugEditor editor; - - public DefaultMutableTreeNode codeTree = new DefaultMutableTreeNode(); - - private DefaultMutableTreeNode currentParent = null; - - /** - * AST Window - */ - private JFrame frame2; - - private JFrame frameAutoComp; - - /** - * Swing component wrapper for AST, used for internal testing - */ - private JTree jtree; - - /** - * JTree used for testing refactoring operations - */ - private JTree renameTree; - - private CompilationUnit compilationUnit; - - private JTable tableAuto; - - private JEditorPane javadocPane; - - private JScrollPane scrollPane; - - private JFrame renameWindow; - - private JButton renameButton; - - private JButton listOccurrence; - - private JTextField renameTextField; - - public ASTGenerator(ErrorCheckerService ecs) { - this.errorCheckerService = ecs; - this.editor = ecs.getEditor(); - frame2 = new JFrame(); - - jtree = new JTree(); - frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame2.setBounds(new Rectangle(680, 100, 460, 620)); - JScrollPane sp = new JScrollPane(); - sp.setViewportView(jtree); - frame2.add(sp); - - renameButton = new JButton("Rename"); - listOccurrence = new JButton("Find All"); - renameWindow = new JFrame(); - renameWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - renameWindow.setBounds(new Rectangle(680, 50, 150, 150)); - renameWindow.setLayout(new GridLayout(3, 1)); - renameWindow.add(renameButton); - renameWindow.add(listOccurrence); - renameTextField = new JTextField(); - renameTextField.setPreferredSize(new Dimension(150, 60)); - renameWindow.add(renameTextField); - renameWindow.setVisible(true); - - JFrame frame4 = new JFrame(); - frame4.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame4.setBounds(new Rectangle(1100, 50, 350, 500)); - - JScrollPane sp2 = new JScrollPane(); - renameTree = new JTree(); - sp2.setViewportView(renameTree); - frame4.add(sp2); - frame4.setVisible(true); - -// frameAutoComp = new JFrame(); -// frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); -// frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); -// tableAuto = new JTable(); -// JScrollPane sp2 = new JScrollPane(); -// sp2.setViewportView(tableAuto); -// frameAutoComp.add(sp2); - -// jdocWindow = new JFrame(); -// jdocWindow.setTitle("P5 InstaHelp"); -// //jdocWindow.setUndecorated(true); -// jdocWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); -// javadocPane = new JEditorPane(); -// javadocPane.setContentType("text/html"); -// javadocPane.setEditable(false); -// scrollPane = new JScrollPane(); -// scrollPane.setViewportView(javadocPane); -// jdocWindow.add(scrollPane); -// jdocMap = new TreeMap(); -//// loadJars(); - - //addCompletionPopupListner(); - addListeners(); - } - - private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { - if (cu == null) { - ASTParser parser = ASTParser.newParser(AST.JLS4); - parser.setSource(source.toCharArray()); - parser.setKind(ASTParser.K_COMPILATION_UNIT); - - Map options = JavaCore.getOptions(); - - JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); - options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - parser.setCompilerOptions(options); - compilationUnit = (CompilationUnit) parser.createAST(null); - } else { - compilationUnit = cu; - System.out.println("Other cu"); - } -// OutlineVisitor visitor = new OutlineVisitor(); -// compilationUnit.accept(visitor); - codeTree = new DefaultMutableTreeNode( - getNodeAsString((ASTNode) compilationUnit - .types().get(0))); - visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - if (codeTree != null) { - if (jtree.hasFocus() || frame2.hasFocus()) - return; - jtree.setModel(new DefaultTreeModel(codeTree)); - ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) { - frame2.setVisible(true); - } -// if (!frameAutoComp.isVisible()) { -// -// frameAutoComp.setVisible(true); -// -// } -// if (!jdocWindow.isVisible()) { -// long t = System.currentTimeMillis(); -// loadJars(); -// loadJavaDoc(); -// System.out.println("Time taken: " -// + (System.currentTimeMillis() - t)); -// jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() -// .getX() + errorCheckerService.getEditor().getWidth(), -// errorCheckerService.getEditor() -// .getY(), 450, 600)); -// jdocWindow.setVisible(true); -// } - jtree.validate(); - } - } - }; - worker.execute(); -// System.err.println("++>" + System.getProperty("java.class.path")); -// System.out.println(System.getProperty("java.class.path")); -// System.out.println("-------------------------------"); - return codeTree; - } - - private ClassPathFactory factory; - - private ClassPath classPath; - - private JFrame jdocWindow; - - /** - * Loads up .jar files and classes defined in it for completion lookup - */ - protected void loadJars() { -// SwingWorker worker = new SwingWorker() { -// protected void done(){ -// } -// protected Object doInBackground() throws Exception { -// return null; -// } -// }; -// worker.execute(); - - Thread t = new Thread(new Runnable() { - - public void run() { - try { - factory = new ClassPathFactory(); - - StringBuffer tehPath = new StringBuffer(System - .getProperty("java.class.path")); - tehPath.append(File.pathSeparatorChar - + System.getProperty("java.home") + "/lib/rt.jar" - + File.pathSeparatorChar); - if (errorCheckerService.classpathJars != null) { - for (URL jarPath : errorCheckerService.classpathJars) { - //System.out.println(jarPath.getPath()); - tehPath.append(jarPath.getPath() + File.pathSeparatorChar); - } - } - -// String paths[] = tehPath.toString().split(File.separatorChar +""); -// StringTokenizer st = new StringTokenizer(tehPath.toString(), -// File.pathSeparatorChar + ""); -// while (st.hasMoreElements()) { -// String sstr = (String) st.nextElement(); -// System.out.println(sstr); -// } - - classPath = factory.createFromPath(tehPath.toString()); -// for (String packageName : classPath.listPackages("")) { -// System.out.println(packageName); -// } - RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( - ".*", - "ArrayList.class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } - System.out.println("jars loaded."); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - t.start(); - } - - private TreeMap jdocMap; - - private void loadJavaDoc() { - - // presently loading only p5 reference for PApplet - Thread t = new Thread(new Runnable() { - - @Override - public void run() { - JavadocHelper.loadJavaDoc(jdocMap, editor.mode().getReferenceFolder()); - } - }); - t.start(); - - } - - public DefaultMutableTreeNode buildAST(CompilationUnit cu) { - return buildAST(errorCheckerService.sourceCode, cu); - } - - public String[] checkForTypes2(ASTNode node) { - - List vdfs = null; - switch (node.getNodeType()) { - case ASTNode.TYPE_DECLARATION: - return new String[] { ((TypeDeclaration) node).getName().toString() }; - - case ASTNode.METHOD_DECLARATION: - String[] ret1 = new String[] { ((MethodDeclaration) node).getName() - .toString() }; - return ret1; - - case ASTNode.SINGLE_VARIABLE_DECLARATION: - return new String[] { ((SingleVariableDeclaration) node).getName() - .toString() }; - - case ASTNode.FIELD_DECLARATION: - vdfs = ((FieldDeclaration) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - vdfs = ((VariableDeclarationStatement) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - vdfs = ((VariableDeclarationExpression) node).fragments(); - break; - default: - break; - } - - if (vdfs != null) { - String ret[] = new String[vdfs.size()]; - int i = 0; - for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = vdf.getName().toString(); - } - return ret; - } - - return null; - } - - public static CompletionCandidate[] checkForTypes(ASTNode node) { - - List vdfs = null; - switch (node.getNodeType()) { - case ASTNode.TYPE_DECLARATION: - return new CompletionCandidate[] { new CompletionCandidate( - getNodeAsString2(node), - ((TypeDeclaration) node) - .getName() - .toString()) }; - - case ASTNode.METHOD_DECLARATION: - MethodDeclaration md = (MethodDeclaration) node; - System.out.println(getNodeAsString(md)); - List params = (List) md - .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); - CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1]; - cand[0] = new CompletionCandidate(md); - for (int i = 0; i < params.size(); i++) { - cand[i + 1] = new CompletionCandidate(params.get(i).toString(), "", "", - CompletionCandidate.LOCAL_VAR); - } - return cand; - - case ASTNode.SINGLE_VARIABLE_DECLARATION: - return new CompletionCandidate[] { new CompletionCandidate( - getNodeAsString2(node), - "", - "", - CompletionCandidate.LOCAL_VAR) }; - - case ASTNode.FIELD_DECLARATION: - vdfs = ((FieldDeclaration) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - vdfs = ((VariableDeclarationStatement) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - vdfs = ((VariableDeclarationExpression) node).fragments(); - break; - default: - break; - } - - if (vdfs != null) { - CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()]; - int i = 0; - for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = new CompletionCandidate(getNodeAsString2(vdf), "", "", - CompletionCandidate.LOCAL_VAR); - } - return ret; - } - - return null; - } - - @SuppressWarnings("unchecked") - public ArrayList getNameIfType(ASTNode astnode) { - - ArrayList names = new ArrayList(); - List sprops = astnode - .structuralPropertiesForType(); - for (StructuralPropertyDescriptor sprop : sprops) { - ASTNode cnode = null; - if (!sprop.isChildListProperty()) { - if (astnode.getStructuralProperty(sprop) instanceof ASTNode) { - cnode = (ASTNode) astnode.getStructuralProperty(sprop); - //if(cnode) - } - } else { - // Childlist prop - List nodelist = (List) astnode - .getStructuralProperty(sprop); - for (ASTNode clnode : nodelist) { - - } - } - } - - return names; - } - - /** - * Find the parent of the expression in a().b, this would give me the return - * type of a(), so that we can find all children of a() begininng with b - * - * @param nearestNode - * @param expression - * @return - */ - public static ASTNode resolveExpression(ASTNode nearestNode, - ASTNode expression) { -// ASTNode anode = null; - System.out.println("Resolving " + getNodeAsString(expression)); - if (expression instanceof SimpleName) { - return findDeclaration2(((SimpleName) expression), nearestNode); - } else if (expression instanceof MethodInvocation) { - return findDeclaration2(((MethodInvocation) expression).getName(), - nearestNode); - } else if (expression instanceof FieldAccess) { - System.out.println("2. Field access " - + getNodeAsString(((FieldAccess) expression).getExpression())); - return resolveExpression(nearestNode, - ((FieldAccess) expression).getExpression()); - //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); - } else if (expression instanceof QualifiedName) { - System.out.println("1. Resolving " - + ((QualifiedName) expression).getQualifier() + " ||| " - + ((QualifiedName) expression).getName()); - return findDeclaration2(((QualifiedName) expression).getQualifier(), - nearestNode); - } - - return null; - } - - /** - * For a().abc.a123 this would return a123 - * - * @param expression - * @return - */ - public static ASTNode resolveChildExpression(ASTNode expression) { -// ASTNode anode = null; - if (expression instanceof SimpleName) { - return expression; - } else if (expression instanceof FieldAccess) { - return ((FieldAccess) expression).getName(); - } else if (expression instanceof QualifiedName) { - return ((QualifiedName) expression).getName(); - } - System.out.println(" resolveChildExpression returning NULL for " - + getNodeAsString(expression)); - return null; - } - - public static TypeDeclaration getDefiningNode(ASTNode node) { - ASTNode parent = node.getParent(); - while (!(parent instanceof TypeDeclaration)) { - parent = parent.getParent(); - if (parent instanceof CompilationUnit) - return null; - } - return (TypeDeclaration) parent; - } - - public void updatePredictions(final String word, final int line) { - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - - String word2 = word; - - //After typing 'arg.' all members of arg type are to be listed. This one is a flag for it - boolean noCompare = false; - if (word2.endsWith(".")) { - // return all matches - word2 = word2.substring(0, word.length() - 1); - noCompare = true; - } - - int lineNumber = line; - // Adjust line number for tabbed sketches - if (errorCheckerService != null) { - editor = errorCheckerService.getEditor(); - int codeIndex = editor.getSketch().getCodeIndex(editor - .getCurrentTab()); - if (codeIndex > 0) - for (int i = 0; i < codeIndex; i++) { - SketchCode sc = editor.getSketch().getCode(i); - int len = Base.countLines(sc.getProgram()) + 1; - lineNumber += len; - } - - } - - // Now parse the expression into an ASTNode object - ASTNode nearestNode = null; - ASTParser parser = ASTParser.newParser(AST.JLS4); - parser.setKind(ASTParser.K_EXPRESSION); - parser.setSource(word2.toCharArray()); - ASTNode testnode = parser.createAST(null); - - // Find closest ASTNode of the document to this word - System.err.print("Typed: " + word2 + "|"); - nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() - .get(0)); - if (nearestNode == null) - //Make sure nearestNode is not NULL if couldn't find a closeset node - nearestNode = (ASTNode) compilationUnit.types().get(0); - System.err.println(lineNumber + " Nearest ASTNode to PRED " - + getNodeAsString(nearestNode)); - - ArrayList candidates = new ArrayList(); - - // Determine the expression typed - - if (testnode instanceof SimpleName && !noCompare) { - System.err - .println("One word expression " + getNodeAsString(testnode)); - //==> Simple one word exprssion - so is just an identifier - - // Bottom up traversal of the AST to look for possible definitions at - // higher levels. - nearestNode = nearestNode.getParent(); - while (nearestNode != null) { - // If the current class has a super class, look inside it for - // definitions. - if (nearestNode instanceof TypeDeclaration) { - TypeDeclaration td = (TypeDeclaration) nearestNode; - if (td - .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) { - SimpleType st = (SimpleType) td - .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); - System.out.println("Superclass " + st.getName()); - for (CompletionCandidate can : getMembersForType(st.getName() - .toString(), word2, noCompare, false)) { - candidates.add(can); - } - //findDeclaration(st.getName()) - - } - } - List sprops = nearestNode - .structuralPropertiesForType(); - for (StructuralPropertyDescriptor sprop : sprops) { - ASTNode cnode = null; - if (!sprop.isChildListProperty()) { - if (nearestNode.getStructuralProperty(sprop) instanceof ASTNode) { - cnode = (ASTNode) nearestNode.getStructuralProperty(sprop); - CompletionCandidate[] types = checkForTypes(cnode); - if (types != null) { - for (int i = 0; i < types.length; i++) { - if (types[i].getElementName().startsWith(word2)) - candidates.add(types[i]); - } - } - } - } else { - // Childlist prop - List nodelist = (List) nearestNode - .getStructuralProperty(sprop); - for (ASTNode clnode : nodelist) { - CompletionCandidate[] types = checkForTypes(clnode); - if (types != null) { - for (int i = 0; i < types.length; i++) { - if (types[i].getElementName().startsWith(word2)) - candidates.add(types[i]); - } - } - } - } - } - nearestNode = nearestNode.getParent(); - } - if(candidates.isEmpty()){ - // We're seeing a simple name that's not defined locally or in - // the parent class. So most probably a pre-defined type. - System.out.println("Empty can. " + word2); - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", word2 + "[a-zA-Z_0-9]*.class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String matchedClass : resources) { - matchedClass = matchedClass.substring(0, - matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - int d = matchedClass.lastIndexOf('.'); - matchedClass = matchedClass.substring(d + 1); - candidates.add(new CompletionCandidate(matchedClass)); - //System.out.println("-> " + className); - } - } - - } else { - - // ==> Complex expression of type blah.blah2().doIt,etc - // Have to resolve it by carefully traversing AST of testNode - System.err.println("Complex expression " + getNodeAsString(testnode)); - - ASTNode det = resolveExpression(nearestNode, testnode); - // Find the parent of the expression - // in a().b, this would give me the return type of a(), so that we can - // find all children of a() begininng with b - System.err.println("DET " + getNodeAsString(det)); - if (det != null) { - TypeDeclaration td = null; - SimpleType stp = null; - if (det instanceof MethodDeclaration) { - if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { - stp = (SimpleType) (((MethodDeclaration) det).getReturnType2()); - td = (TypeDeclaration) findDeclaration(stp.getName()); - } - } else if (det instanceof FieldDeclaration) { - if (((FieldDeclaration) det).getType() instanceof SimpleType) { - stp = (SimpleType) (((FieldDeclaration) det).getType()); - td = (TypeDeclaration) findDeclaration(stp.getName()); - } - } else if (det instanceof VariableDeclarationStatement) { - stp = (SimpleType) (((VariableDeclarationStatement) det) - .getType()); - td = (TypeDeclaration) findDeclaration(stp.getName()); - } - System.out.println("ST is " + stp.getName()); - // Now td contains the type returned by a() - System.err.println(getNodeAsString(det) + " defined in " - + getNodeAsString(td)); - ASTNode child = resolveChildExpression(testnode); - if (td != null) { - - System.out.println("Completion candidate: " - + getNodeAsString(child)); - for (int i = 0; i < td.getFields().length; i++) { - List vdfs = td.getFields()[i] - .fragments(); - for (VariableDeclarationFragment vdf : vdfs) { - if (noCompare) { - candidates - .add(new CompletionCandidate(getNodeAsString2(vdf))); - } else if (vdf.getName().toString() - .startsWith(child.toString())) - candidates - .add(new CompletionCandidate(getNodeAsString2(vdf))); - } - - } - for (int i = 0; i < td.getMethods().length; i++) { - if (noCompare) { - candidates - .add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString(), "", - CompletionCandidate.METHOD)); - } else if (td.getMethods()[i].getName().toString() - .startsWith(child.toString())) - candidates - .add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString(), "", - CompletionCandidate.METHOD)); - } - } else { - if (stp != null) { - candidates = getMembersForType(stp.getName().toString(), - child.toString(), noCompare, - false); - } - } - - } else if (word.length() - word2.length() == 1) { - System.out.println(word + " w2 " + word2); -// int dC = 0; -// for (int i = 0; i < word.length(); i++) { -// if(word.charAt(i) == '.') -// dC++; -// } -// if(dC == 1 && word.charAt(word.length() - 1) == '.'){ - System.out.println("All members of " + word2); - candidates = getMembersForType(word2, "", true, true); -// } - } else { - System.out.println("Some members of " + word2); - int x = word2.indexOf('.'); - if (x != -1) { - candidates = getMembersForType(word2.substring(0, x), - word2.substring(x + 1), false, - true); - } - } - - } - - Collections.sort(candidates); - CompletionCandidate[][] candi = new CompletionCandidate[candidates - .size()][1]; - - for (int i = 0; i < candi.length; i++) { - candi[i][0] = candidates.get(i); - } - System.out.println("K = " + candidates.size()); - DefaultTableModel tm = new DefaultTableModel( - candi, - new String[] { "Suggestions" }); - tableAuto.setModel(tm); - tableAuto.validate(); - tableAuto.repaint(); - //String[] items = - CompletionCandidate[] candi2 = candidates - .toArray(new CompletionCandidate[candidates.size()]); - if (candidates.size() > 0) - errorCheckerService.getEditor().textArea().showSuggestion(candi2); - } - }; - - worker.execute(); - - } - - /** - * Loads classes from .jar files in sketch classpath - * - * @param typeName - * @param child - * @param noCompare - * @return - */ - public ArrayList getMembersForType(String typeName, - String child, - boolean noCompare, - boolean staticOnly) { - ArrayList candidates = new ArrayList(); - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } - if (resources.length > 0) { //TODO: Multiple matched classes? What about 'em? - String matchedClass = resources[0]; - matchedClass = matchedClass.substring(0, matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - System.out.println("In GMFT(), Matched class: " + matchedClass); - System.out.println("Looking for match " + child.toString()); - try { - Class probableClass = Class.forName(matchedClass, false, - errorCheckerService.classLoader); - - for (Method method : probableClass.getMethods()) { - if (!Modifier.isStatic(method.getModifiers()) && staticOnly) - continue; - StringBuffer label = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) - label.append(","); - } - - label.append(")"); - if (noCompare) - candidates.add(new CompletionCandidate(method)); - else if (label.toString().startsWith(child.toString())) - candidates.add(new CompletionCandidate(method)); - } - for (Field field : probableClass.getFields()) { - if (!Modifier.isStatic(field.getModifiers()) && staticOnly) - continue; - if (noCompare) - candidates.add(new CompletionCandidate(field)); - else if (field.getName().startsWith(child.toString())) - candidates.add(new CompletionCandidate(field)); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - System.out.println("Couldn't load " + matchedClass); - } - } - //updateJavaDoc(methodmatch) - - return candidates; - } - - public void updateJavaDoc(final CompletionCandidate candidate) { - String methodmatch = candidate.toString(); - if (methodmatch.indexOf('(') != -1) { - methodmatch = methodmatch.substring(0, methodmatch.indexOf('(')); - } - - //System.out.println("jdoc match " + methodmatch); - for (final String key : jdocMap.keySet()) { - if (key.startsWith(methodmatch) && key.length() > 3) { - System.out.println("Matched jdoc " + key); - - //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - System.out.println("Class: " + candidate.getDefiningClass()); - if (candidate.getDefiningClass().equals("processing.core.PApplet")) { - javadocPane.setText(jdocMap.get(key)); - //jdocWindow.setVisible(true); - //editor.textArea().requestFocus() - } else - javadocPane.setText(""); - javadocPane.setCaretPosition(0); - } - }); - break; - } - } - //jdocWindow.setVisible(false); - - } - - @SuppressWarnings("unchecked") - private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { - Iterator it = node - .structuralPropertiesForType().iterator(); - //System.err.println("Props of " + node.getClass().getName()); - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (node.getStructuralProperty(prop) != null) { -// System.out -// .println(node.getStructuralProperty(prop) + " -> " + (prop)); - if (node.getStructuralProperty(prop) instanceof ASTNode) { - ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); -// System.out.println("Looking at " + getNodeAsString(cnode)); - int cLineNum = ((CompilationUnit) cnode.getRoot()) - .getLineNumber(cnode.getStartPosition() + cnode.getLength()); - if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { - return findClosestParentNode(lineNumber, cnode); - } - } - } - } - - else if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - int cLineNum = ((CompilationUnit) cnode.getRoot()) - .getLineNumber(cnode.getStartPosition() + cnode.getLength()); -// System.out.println("Looking at " + getNodeAsString(cnode)); - if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { - return findClosestParentNode(lineNumber, cnode); - } - } - } - } - return node; - } - - @SuppressWarnings("unchecked") - private static ASTNode findClosestNode(int lineNumber, ASTNode node) { - ASTNode parent = findClosestParentNode(lineNumber, node); - if (parent == null) - return null; - if (getLineNumber(parent) == lineNumber) - return parent; - List nodes = null; - if (parent instanceof TypeDeclaration) { - nodes = (List) ((TypeDeclaration) parent) - .getStructuralProperty(TypeDeclaration.BODY_DECLARATIONS_PROPERTY); - } else if (parent instanceof Block) { - nodes = (List) ((Block) parent) - .getStructuralProperty(Block.STATEMENTS_PROPERTY); - } else { - System.err.println("THIS CONDITION SHOULD NOT OCCUR - findClosestNode " - + getNodeAsString(parent)); - return null; - } - - if (nodes.size() > 0) { - ASTNode retNode = nodes.get(0); - for (ASTNode cNode : nodes) { - if (getLineNumber(cNode) <= lineNumber) - retNode = cNode; - else - break; - } - - return retNode; - } - return null; - } - -// static DefaultMutableTreeNode findNodeBS(DefaultMutableTreeNode tree, -// int lineNumber, String name, -// int elementOffset) { -// if (tree.getUserObject() == null) -// return null; -// -// ASTNodeWrapper node = ((ASTNodeWrapper) tree.getUserObject()); -// -// if (node.getLineNumber() == lineNumber) { -// System.out.println("Located line " + lineNumber + " , " + tree); -// if (name == null) -// return tree; -// else -// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() -// .getStartPosition()); -// } -// -// int low = 0, high = tree.getChildCount() - 1, mid = (high + low) / 2; -// DefaultMutableTreeNode tnode = null; -// while (low <= high) { -// mid = (high + low) / 2; -// tnode = (DefaultMutableTreeNode) tree.getChildAt(mid); -// node = ((ASTNodeWrapper) tnode.getUserObject()); -// if (node.getLineNumber() == lineNumber) { -// System.out.println("Located line " + lineNumber + " , " + tnode); -// if (name == null) -// return tnode; -// else -// return findOnLine(tnode, lineNumber, name, elementOffset, node -// .getNode().getStartPosition()); -// } else if (lineNumber < node.getLineNumber()) { -// high = mid - 1; -// } else { -// if (high - mid <= 1) { -// if (lineNumber > ((ASTNodeWrapper) ((DefaultMutableTreeNode) tree -// .getChildAt(high)).getUserObject()).getLineNumber()) //high l no. -// low = mid + 1; -// else -// -// high = mid - 1; -// } -// low = mid + 1; -// } -// -// } -// -// if (!tnode.isLeaf()) -// return findNodeBS(tnode, lineNumber, name, elementOffset); -// else -// return tnode; -// -// //System.out.println("visiting: " + getNodeAsString(node.getNode()) + " on line "+node.getLineNumber()); -// if (node.getLineNumber() == lineNumber) { -// System.err.println("Located line: " + node.toString()); -// if (name == null) // name ==null, finds any node equal to line -// // number -// { -// System.out.println("Closest node at line: " + lineNumber); -// return tree; -// } else -// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() -// .getStartPosition()); -// -// } else if (!tree.isLeaf()) { -// for (int i = 0; i < tree.getChildCount(); i++) { -// .getChildAt(i), -// lineNumber, name, elementOffset); -// if (node2 != null) -// return node2; -// } -// } -// -// return null; -// } - - public DefaultMutableTreeNode getAST() { - return codeTree; - } - - public String getLabelForASTNode(int lineNumber, String name, int offset) { - retLabelString = ""; - getASTNodeAt(lineNumber, name, offset, false); - return retLabelString; - } - - public void scrollToDeclaration(int lineNumber, String name, int offset) { - getASTNodeAt(lineNumber, name, offset, true); - } - - String retLabelString; - - /** - * - * @param lineNumber - * @param name - * @param offset - line start nonwhitespace offset - * @param scrollOnly - * @return - */ - public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, - boolean scrollOnly) { - - System.out.println("----getASTNodeAt----"); - if (errorCheckerService != null) { - editor = errorCheckerService.getEditor(); - int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); - if (codeIndex > 0) { - for (int i = 0; i < codeIndex; i++) { - SketchCode sc = editor.getSketch().getCode(i); - int len = Base.countLines(sc.getProgram()) + 1; - lineNumber += len; - } - } - - } - System.out.println("FLON: " + lineNumber); - ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); - - System.out.println("+> " + lineNode); - ASTNode decl = null; - String nameOfNode = null; // The node name which is to be scrolled to - if (lineNode != null) { - - // Some delicate offset handling follows. - ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); - int altOff = offset; - int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); - if(ret != null){ - altOff = 0; - int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; - - for (; altOff < javaCodeMap.length; altOff++) { - if (javaCodeMap[altOff] == pdeCodeMap[offset]) { - break; - } - } - } - System.out.println("FLON2: " + lineNumber + " LN spos " - + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); - /* - * Now I need to see if multiple statements exist with this same line number - * If that's the case, I need to ensure the offset is right. - */ - ASTNode parLineNode = lineNode.getParent(); - - Iterator it = parLineNode - .structuralPropertiesForType().iterator(); - boolean flag = true; - int offAdjust = 0; - while (it.hasNext() && flag) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) parLineNode - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - if (getLineNumber(cnode) == lineNumber) { - if (cnode.getStartPosition() <= lineNode.getStartPosition() - + altOff - && cnode.getStartPosition() + cnode.getLength() > lineNode - .getStartPosition() + altOff) { - System.out.println(cnode); - offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); - lineNode = cnode; - altOff -= offAdjust; - flag = false; - break; - } - - } - } - } - } - System.out.println("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); - ASTNode simpName = pinpointOnLine(lineNode, altOff, - lineNode.getStartPosition(), name); - System.out.println("+++> " + simpName); - if (simpName instanceof SimpleName) { - nameOfNode = simpName.toString(); - System.out.println(getNodeAsString(simpName)); - decl = findDeclaration((SimpleName) simpName); - if (decl != null) { - System.err.println("DECLA: " + decl.getClass().getName()); - retLabelString = getNodeAsString(decl); - } else - System.err.println("null"); - - System.out.println(getNodeAsString(decl)); - } - } - - if (decl != null && scrollOnly) { - /* - * For scrolling, we highlight just the name of the node, - * i.e., a SimpleName instance. But the declared node always - * points to the declared node itself, like TypeDecl, MethodDecl, etc. - * This is important since it contains all the properties. - */ - ASTNode simpName2 = getNodeName(decl,nameOfNode); - System.err.println("FINAL String decl: " + getNodeAsString(decl)); - System.err.println("FINAL String label: " + getNodeAsString(simpName2)); - errorCheckerService.highlightNode(simpName2); - } - - return new ASTNodeWrapper(decl); - } - - /** - * Given a declaration type astnode, returns the SimpleName peroperty - * of that node. - * @param node - * @param name - The name we're looking for. - * @return SimpleName - */ - private static ASTNode getNodeName(ASTNode node, String name){ - List vdfs = null; - switch (node.getNodeType()) { - case ASTNode.TYPE_DECLARATION: - return ((TypeDeclaration) node).getName(); - case ASTNode.METHOD_DECLARATION: - return ((MethodDeclaration) node).getName(); - case ASTNode.SINGLE_VARIABLE_DECLARATION: - return ((SingleVariableDeclaration) node).getName(); - case ASTNode.FIELD_DECLARATION: - vdfs = ((FieldDeclaration) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - vdfs = ((VariableDeclarationStatement) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - vdfs = ((VariableDeclarationExpression) node).fragments(); - break; - default: - break; - } - - if (vdfs != null) { - for (VariableDeclarationFragment vdf : vdfs) { - if (vdf.getName().toString().equals(name)) { - return vdf.getName(); - } - } - - } - return null; - } - - /** - * Fetches line number of the node in its CompilationUnit. - * @param node - * @return - */ - private static int getLineNumber(ASTNode node) { - return ((CompilationUnit) node.getRoot()).getLineNumber(node - .getStartPosition()); - } - - public static void main(String[] args) { - traversal2(); - } - - public static void traversal2() { - ASTParser parser = ASTParser.newParser(AST.JLS4); - String source = readFile("/media/quarkninja/Work/TestStuff/low.java"); -// String source = "package decl; \npublic class ABC{\n int ret(){\n}\n}"; - parser.setSource(source.toCharArray()); - parser.setKind(ASTParser.K_COMPILATION_UNIT); - - Map options = JavaCore.getOptions(); - - JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); - options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - parser.setCompilerOptions(options); - - CompilationUnit cu = (CompilationUnit) parser.createAST(null); - System.out.println(CompilationUnit.propertyDescriptors(AST.JLS4).size()); - - DefaultMutableTreeNode astTree = new DefaultMutableTreeNode( - "CompilationUnit"); - System.err.println("Errors: " + cu.getProblems().length); - visitRecur(cu, astTree); - System.out.println(astTree.getChildCount()); - - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - JFrame frame2 = new JFrame(); - JTree jtree = new JTree(astTree); - frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame2.setBounds(new Rectangle(100, 100, 460, 620)); - JScrollPane sp = new JScrollPane(); - sp.setViewportView(jtree); - frame2.add(sp); - frame2.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - - ASTNode found = NodeFinder.perform(cu, 468, 5); - if (found != null) { - System.out.println(found); - } - } - - private void addListeners(){ - jtree.addTreeSelectionListener(new TreeSelectionListener() { - - @Override - public void valueChanged(TreeSelectionEvent e) { - System.out.println(e); - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - if(jtree - .getLastSelectedPathComponent() == null){ - return; - } - DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) jtree - .getLastSelectedPathComponent(); - if(tnode.getUserObject() == null){ - return; - } - - if (tnode.getUserObject() instanceof ASTNodeWrapper) { - ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - errorCheckerService.highlightNode(awrap); - } - } - }; - worker.execute(); - } - }); - - renameButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - if (editor.ta.getSelectedText() == null) - return; - if(renameTextField.getText().length() == 0) - return; - String newName = renameTextField.getText(); - DefaultMutableTreeNode defCU = findAllOccurrences(); - renameTree.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) renameTree.getModel()).reload(); - int lineOffsetDisplacementConst = newName.length() - - editor.ta.getSelectedText().length(); - HashMap lineOffsetDisplacement = new HashMap(); - - for (int i = defCU.getChildCount() - 1; i >= 0; i--) { - ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU - .getChildAt(i))).getUserObject(); - int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); - int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); - - // correction for pde enhancements related displacement on a line - int off = 0; - if(lineOffsetDisplacement.get(javaoffsets[0]) != null){ - off = lineOffsetDisplacement.get(javaoffsets[0]); - - lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst + off); - } - else{ - lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst); - } - - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1], - javaoffsets[1] + off, - javaoffsets[2]); - editor.ta.setSelectedText(newName); - } - for (Integer lineNum : lineOffsetDisplacement.keySet()) { - System.out.println(lineNum + "line, disp" - + lineOffsetDisplacement.get(lineNum)); - } - editor.getSketch().setModified(true); - } - }; - worker.execute(); - } - }); - // TODO: Diable this listner at deployment - listOccurrence.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - if (editor.ta.getSelectedText() == null) - return; - DefaultMutableTreeNode defCU = findAllOccurrences(); - renameTree.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) renameTree.getModel()).reload(); - } - }; - worker.execute(); - } - }); - - renameTree.addTreeSelectionListener(new TreeSelectionListener() { - - @Override - public void valueChanged(TreeSelectionEvent e) { - System.out.println(e); - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - if(renameTree - .getLastSelectedPathComponent() == null){ - return; - } - DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) renameTree - .getLastSelectedPathComponent(); - if(tnode.getUserObject() == null){ - return; - } - - if (tnode.getUserObject() instanceof ASTNodeWrapper) { - ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - errorCheckerService.highlightNode(awrap); - } - } - }; - worker.execute(); - } - }); - } - - private DefaultMutableTreeNode findAllOccurrences(){ - String selText = editor.ta.getSelectedText(); - int line = editor.ta.getSelectionStartLine(); - System.out.println(editor.ta.getSelectedText() - + "<- offsets " - + (line) - + ", " - + (editor.ta.getSelectionStart() - editor.ta - .getLineStartOffset(line)) - + ", " - + (editor.ta.getSelectionStop() - editor.ta - .getLineStartOffset(line))); - int offwhitespace = editor.ta - .getLineStartNonWhiteSpaceOffset(line); - ASTNodeWrapper wnode = getASTNodeAt(line - + errorCheckerService.mainClassOffset, - selText, - editor.ta.getSelectionStart() - - offwhitespace, false); - System.err.println("Gonna find all occurrences of " - + getNodeAsString(wnode.getNode())); - - //If wnode is a constructor, find the TD instead. - if (wnode.getNodeType() == ASTNode.METHOD_DECLARATION) { - MethodDeclaration md = (MethodDeclaration) wnode.getNode(); - ASTNode node = md.getParent(); - while (node != null) { - if (node instanceof TypeDeclaration) { - // System.out.println("Parent class " + getNodeAsString(node)); - break; - } - node = node.getParent(); - } - if(node != null && node instanceof TypeDeclaration){ - TypeDeclaration td = (TypeDeclaration) node; - if(td.getName().toString().equals(md.getName().toString())){ - System.err.println("Renaming constructor of " + getNodeAsString(td)); - wnode = new ASTNodeWrapper(td); - } - } - } - - DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); - dfsNameOnly(defCU, wnode.getNode(), selText); - System.out.println(wnode); - return defCU; - } - - @SuppressWarnings({ "unchecked" }) - /** - * Generates AST Swing component - * @param node - * @param tnode - */ - public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { - Iterator it = node - .structuralPropertiesForType().iterator(); - //System.err.println("Props of " + node.getClass().getName()); - DefaultMutableTreeNode ctnode = null; - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (node.getStructuralProperty(prop) != null) { -// System.out -// .println(node.getStructuralProperty(prop) + " -> " + (prop)); - if (node.getStructuralProperty(prop) instanceof ASTNode) { - ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); - if (isAddableASTNode(cnode)) { - ctnode = new DefaultMutableTreeNode( - new ASTNodeWrapper((ASTNode) node - .getStructuralProperty(prop))); - tnode.add(ctnode); - visitRecur(cnode, ctnode); - } - } else { - tnode.add(new DefaultMutableTreeNode(node - .getStructuralProperty(prop))); - } - } - } - - else if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - if (isAddableASTNode(cnode)) { - ctnode = new DefaultMutableTreeNode(new ASTNodeWrapper(cnode)); - tnode.add(ctnode); - visitRecur(cnode, ctnode); - } else - visitRecur(cnode, tnode); - } - } - } - } - - public void dfsNameOnly(DefaultMutableTreeNode tnode,ASTNode decl, String name) { - Stack temp = new Stack(); - temp.push(codeTree); - - while(!temp.isEmpty()){ - DefaultMutableTreeNode cnode = (DefaultMutableTreeNode) temp.pop(); - for (int i = 0; i < cnode.getChildCount(); i++) { - temp.push(cnode.getChildAt(i)); - } - - if(!(cnode.getUserObject() instanceof ASTNodeWrapper)) - continue; - ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); -// System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); - if(isInstanceOfType(awnode.getNode(), decl, name)){ - tnode.add(new DefaultMutableTreeNode(awnode)); - } - - } - } - - private boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ - if(node instanceof SimpleName){ - SimpleName sn = (SimpleName) node; - - if (sn.toString().equals(name)) { - ArrayList nodesToBeMatched = new ArrayList(); - nodesToBeMatched.add(decl); - if(decl instanceof TypeDeclaration){ - System.out.println("decl is a TD"); - TypeDeclaration td = (TypeDeclaration)decl; - MethodDeclaration[] mlist = td.getMethods(); - for (MethodDeclaration md : mlist) { - if(md.getName().toString().equals(name)){ - nodesToBeMatched.add(md); - } - } - } - System.out.println("Visiting: " + getNodeAsString(node)); - ASTNode decl2 = findDeclaration(sn); - System.err.println("It's decl: " + getNodeAsString(decl2)); - System.out.println("But we need: "+getNodeAsString(decl)); - for (ASTNode astNode : nodesToBeMatched) { - if(astNode.equals(decl2)){ - return true; - } - } - } - } - return false; - } - - public void handleRefactor(){ - if (!renameWindow.isVisible()) - renameWindow.setVisible(true); - renameWindow.toFront(); - } - - - public static void printRecur(ASTNode node) { - Iterator it = node - .structuralPropertiesForType().iterator(); - //System.err.println("Props of " + node.getClass().getName()); - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (node.getStructuralProperty(prop) != null) { -// System.out -// .println(node.getStructuralProperty(prop) + " -> " + (prop)); - if (node.getStructuralProperty(prop) instanceof ASTNode) { - ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); - System.out.println(getNodeAsString(cnode)); - printRecur(cnode); - } - } - } - - else if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - System.out.println(getNodeAsString(cnode)); - printRecur(cnode); - } - } - } - } - - @SuppressWarnings("unchecked") - private static ASTNode findLineOfNode(ASTNode node, int lineNumber, - int offset, String name) { - - CompilationUnit root = (CompilationUnit) node.getRoot(); -// System.out.println("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); - if (root.getLineNumber(node.getStartPosition()) == lineNumber) { - System.err - .println(3 + getNodeAsString(node) + " len " + node.getLength()); - return node; -// if (offset < node.getLength()) -// return node; -// else { -// System.err.println(-11); -// return null; -// } - } - for (Object oprop : node.structuralPropertiesForType()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (node.getStructuralProperty(prop) != null) { - if (node.getStructuralProperty(prop) instanceof ASTNode) { - ASTNode retNode = findLineOfNode((ASTNode) node - .getStructuralProperty(prop), - lineNumber, offset, name); - if (retNode != null) { -// System.err.println(11 + getNodeAsString(retNode)); - return retNode; - } - } - } - } else if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - for (ASTNode retNode : nodelist) { - - ASTNode rr = findLineOfNode(retNode, lineNumber, offset, name); - if (rr != null) { -// System.err.println(12 + getNodeAsString(rr)); - return rr; - } - } - } - } -// System.err.println("-1"); - return null; - } - - /** - * - * @param node - * @param offset - * - from textarea painter - * @param lineStartOffset - * - obtained from findLineOfNode - * @param name - * @param root - * @return - */ - @SuppressWarnings("unchecked") - public static ASTNode pinpointOnLine(ASTNode node, int offset, - int lineStartOffset, String name) { - - if (node instanceof SimpleName) { - SimpleName sn = (SimpleName) node; - System.out.println(offset+ "off,pol " + getNodeAsString(sn)); - if ((lineStartOffset + offset) >= sn.getStartPosition() - && (lineStartOffset + offset) <= sn.getStartPosition() - + sn.getLength()) { - if (sn.toString().equals(name)) { - return sn; - } - else { - return null; - } - } else { - return null; - } - } - for (Object oprop : node.structuralPropertiesForType()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (node.getStructuralProperty(prop) != null) { - if (node.getStructuralProperty(prop) instanceof ASTNode) { - ASTNode retNode = pinpointOnLine((ASTNode) node - .getStructuralProperty(prop), - offset, lineStartOffset, name); - if (retNode != null) { -// System.err.println(11 + getNodeAsString(retNode)); - return retNode; - } - } - } - } else if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - for (ASTNode retNode : nodelist) { - - ASTNode rr = pinpointOnLine(retNode, offset, lineStartOffset, name); - if (rr != null) { -// System.err.println(12 + getNodeAsString(rr)); - return rr; - } - } - } - } -// System.err.println("-1"); - return null; - } - - @SuppressWarnings("unchecked") - private static ASTNode findDeclaration(Name findMe) { - ASTNode declaringClass = null; - ASTNode parent = findMe.getParent(); - ASTNode ret = null; - ArrayList constrains = new ArrayList(); - if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { - Expression exp = (Expression) ((MethodInvocation) parent) - .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); - //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); - // Possibly a bug here. Investigate later. - if (((MethodInvocation) parent).getName().toString() - .equals(findMe.toString())) { - constrains.add(ASTNode.METHOD_DECLARATION); - - if (exp != null) { - constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("MI EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); - if (exp instanceof MethodInvocation) { - SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) - .getName())); - if (stp == null) - return null; - declaringClass = findDeclaration(stp.getName()); - return definedIn(declaringClass, ((MethodInvocation) parent) - .getName().toString(), constrains, declaringClass); - } else if (exp instanceof FieldAccess) { - SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) - .getName())); - if (stp == null) - return null; - declaringClass = findDeclaration((stp.getName())); - return definedIn(declaringClass, ((MethodInvocation) parent) - .getName().toString(), constrains, declaringClass); - } - if (exp instanceof SimpleName) { - SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); - if (stp == null) - return null; - declaringClass = findDeclaration(stp.getName()); - System.out.println("MI.SN " + getNodeAsString(declaringClass)); - constrains.add(ASTNode.METHOD_DECLARATION); - return definedIn(declaringClass, ((MethodInvocation) parent) - .getName().toString(), constrains, declaringClass); - } - - } - } else { - parent = parent.getParent(); // Move one up the ast. V V IMP!! - } - } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { - FieldAccess fa = (FieldAccess) parent; - Expression exp = fa.getExpression(); - if (fa.getName().toString().equals(findMe.toString())) { - constrains.add(ASTNode.FIELD_DECLARATION); - - if (exp != null) { - constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("FA EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); - if (exp instanceof MethodInvocation) { - SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) - .getName())); - if (stp == null) - return null; - declaringClass = findDeclaration(stp.getName()); - return definedIn(declaringClass, fa.getName().toString(), - constrains, declaringClass); - } else if (exp instanceof FieldAccess) { - SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) - .getName())); - if (stp == null) - return null; - declaringClass = findDeclaration((stp.getName())); - constrains.add(ASTNode.TYPE_DECLARATION); - return definedIn(declaringClass, fa.getName().toString(), - constrains, declaringClass); - } - if (exp instanceof SimpleName) { - SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); - if (stp == null) - return null; - declaringClass = findDeclaration(stp.getName()); - System.out.println("FA.SN " + getNodeAsString(declaringClass)); - constrains.add(ASTNode.METHOD_DECLARATION); - return definedIn(declaringClass, fa.getName().toString(), - constrains, declaringClass); - } - } - - } else { - parent = parent.getParent(); // Move one up the ast. V V IMP!! - } - } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { - - QualifiedName qn = (QualifiedName) parent; - if (!findMe.toString().equals(qn.getQualifier().toString())) { - - SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); - declaringClass = findDeclaration(stp.getName()); - System.out.println(qn.getQualifier() + "->" + qn.getName()); - System.out.println("QN decl class: " + getNodeAsString(declaringClass)); - constrains.clear(); - constrains.add(ASTNode.TYPE_DECLARATION); - constrains.add(ASTNode.FIELD_DECLARATION); - return definedIn(declaringClass, qn.getName().toString(), constrains, - null); - } - } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { - constrains.add(ASTNode.TYPE_DECLARATION); - if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) - constrains.add(ASTNode.CLASS_INSTANCE_CREATION); - } else if(parent.getNodeType() == ASTNode.TYPE_DECLARATION){ - // The condition where we look up the name of a class decl - TypeDeclaration td = (TypeDeclaration) parent; - if(findMe.equals(td.getName())) - { - return parent; - } - } - else if (parent instanceof Expression) { -// constrains.add(ASTNode.TYPE_DECLARATION); -// constrains.add(ASTNode.METHOD_DECLARATION); -// constrains.add(ASTNode.FIELD_DECLARATION); - } - while (parent != null) { - System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); - for (Object oprop : parent.structuralPropertiesForType()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (parent.getStructuralProperty(prop) instanceof ASTNode) { -// System.out.println(prop + " C/S Prop of -> " -// + getNodeAsString(parent)); - ret = definedIn((ASTNode) parent.getStructuralProperty(prop), - findMe.toString(), constrains, declaringClass); - if (ret != null) - return ret; - } - } else if (prop.isChildListProperty()) { -// System.out.println((prop) + " ChildList props of " -// + getNodeAsString(parent)); - List nodelist = (List) parent - .getStructuralProperty(prop); - for (ASTNode retNode : nodelist) { - ret = definedIn(retNode, findMe.toString(), constrains, - declaringClass); - if (ret != null) - return ret; - } - } - } - parent = parent.getParent(); - } - return null; - } - - private static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { - ASTNode declaringClass = null; - ASTNode parent = findMe.getParent(); - ASTNode ret = null; - ArrayList constrains = new ArrayList(); - if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { - Expression exp = (Expression) ((MethodInvocation) parent) - .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); - //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); - // Possibly a bug here. Investigate later. - if (((MethodInvocation) parent).getName().toString() - .equals(findMe.toString())) { - constrains.add(ASTNode.METHOD_DECLARATION); - - if (exp != null) { - constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("MI EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); - if (exp instanceof MethodInvocation) { - SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) - .getName(), - alternateParent)); - if (stp == null) - return null; - declaringClass = findDeclaration2(stp.getName(), alternateParent); - return definedIn(declaringClass, ((MethodInvocation) parent) - .getName().toString(), constrains, declaringClass); - } else if (exp instanceof FieldAccess) { - SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) - .getName(), - alternateParent)); - if (stp == null) - return null; - declaringClass = findDeclaration2((stp.getName()), alternateParent); - return definedIn(declaringClass, ((MethodInvocation) parent) - .getName().toString(), constrains, declaringClass); - } - if (exp instanceof SimpleName) { - SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), - alternateParent)); - if (stp == null) - return null; - declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println("MI.SN " + getNodeAsString(declaringClass)); - constrains.add(ASTNode.METHOD_DECLARATION); - return definedIn(declaringClass, ((MethodInvocation) parent) - .getName().toString(), constrains, declaringClass); - } - - } - } else { - parent = parent.getParent(); // Move one up the ast. V V IMP!! - alternateParent = alternateParent.getParent(); - } - } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { - FieldAccess fa = (FieldAccess) parent; - Expression exp = fa.getExpression(); - if (fa.getName().toString().equals(findMe.toString())) { - constrains.add(ASTNode.FIELD_DECLARATION); - - if (exp != null) { - constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("FA EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); - if (exp instanceof MethodInvocation) { - SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) - .getName(), - alternateParent)); - if (stp == null) - return null; - declaringClass = findDeclaration2(stp.getName(), alternateParent); - return definedIn(declaringClass, fa.getName().toString(), - constrains, declaringClass); - } else if (exp instanceof FieldAccess) { - SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp) - .getName(), - alternateParent)); - if (stp == null) - return null; - declaringClass = findDeclaration2((stp.getName()), alternateParent); - constrains.add(ASTNode.TYPE_DECLARATION); - return definedIn(declaringClass, fa.getName().toString(), - constrains, declaringClass); - } - if (exp instanceof SimpleName) { - SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp), - alternateParent)); - if (stp == null) - return null; - declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println("FA.SN " + getNodeAsString(declaringClass)); - constrains.add(ASTNode.METHOD_DECLARATION); - return definedIn(declaringClass, fa.getName().toString(), - constrains, declaringClass); - } - } - - } else { - parent = parent.getParent(); // Move one up the ast. V V IMP!! - alternateParent = alternateParent.getParent(); - } - } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { - - QualifiedName qn = (QualifiedName) parent; - if (!findMe.toString().equals(qn.getQualifier().toString())) { - - SimpleType stp = extracTypeInfo(findDeclaration2((qn.getQualifier()), - alternateParent)); - declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println(qn.getQualifier() + "->" + qn.getName()); - System.out.println("QN decl class: " + getNodeAsString(declaringClass)); - constrains.clear(); - constrains.add(ASTNode.TYPE_DECLARATION); - constrains.add(ASTNode.FIELD_DECLARATION); - return definedIn(declaringClass, qn.getName().toString(), constrains, - null); - } - } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { - constrains.add(ASTNode.TYPE_DECLARATION); - if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) - constrains.add(ASTNode.CLASS_INSTANCE_CREATION); - } else if (parent instanceof Expression) { -// constrains.add(ASTNode.TYPE_DECLARATION); -// constrains.add(ASTNode.METHOD_DECLARATION); -// constrains.add(ASTNode.FIELD_DECLARATION); - } // TODO: in findDec, we also have a case where parent of type TD is handled. - // Figure out if needed here as well. - System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); - while (alternateParent != null) { -// System.out.println("findDeclaration2 -> " -// + getNodeAsString(alternateParent)); - for (Object oprop : alternateParent.structuralPropertiesForType()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) { -// System.out.println(prop + " C/S Prop of -> " -// + getNodeAsString(alternateParent)); - ret = definedIn((ASTNode) alternateParent - .getStructuralProperty(prop), - findMe.toString(), constrains, declaringClass); - if (ret != null) - return ret; - } - } else if (prop.isChildListProperty()) { -// System.out.println((prop) + " ChildList props of " -// + getNodeAsString(alternateParent)); - List nodelist = (List) alternateParent - .getStructuralProperty(prop); - for (ASTNode retNode : nodelist) { - ret = definedIn(retNode, findMe.toString(), constrains, - declaringClass); - if (ret != null) - return ret; - } - } - } - alternateParent = alternateParent.getParent(); - } - return null; - } - - /** - * Find the SimpleType from FD, SVD, VDS, etc - * - * @param node - * @return - */ - private static SimpleType extracTypeInfo(ASTNode node) { - if (node == null) - return null; - switch (node.getNodeType()) { - case ASTNode.METHOD_DECLARATION: - return (SimpleType) ((MethodDeclaration) node) - .getStructuralProperty(MethodDeclaration.RETURN_TYPE2_PROPERTY); - case ASTNode.FIELD_DECLARATION: - return (SimpleType) ((FieldDeclaration) node) - .getStructuralProperty(FieldDeclaration.TYPE_PROPERTY); - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - return (SimpleType) ((VariableDeclarationExpression) node) - .getStructuralProperty(VariableDeclarationExpression.TYPE_PROPERTY); - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - return (SimpleType) ((VariableDeclarationStatement) node) - .getStructuralProperty(VariableDeclarationStatement.TYPE_PROPERTY); - case ASTNode.SINGLE_VARIABLE_DECLARATION: - return (SimpleType) ((SingleVariableDeclaration) node) - .getStructuralProperty(SingleVariableDeclaration.TYPE_PROPERTY); - } - return null; - } - - @SuppressWarnings("unchecked") - private static ASTNode definedIn(ASTNode node, String name, - ArrayList constrains, - ASTNode declaringClass) { - if (node == null) - return null; - if (constrains != null) { -// System.out.println("Looking at " + getNodeAsString(node) + " for " + name -// + " in definedIn"); - if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) { -// System.err.print("definedIn -1 " + " But constrain was "); -// for (Integer integer : constrains) { -// System.out.print(ASTNode.nodeClassForType(integer) + ","); -// } -// System.out.println(); - return null; - } - } - - List vdfList = null; - switch (node.getNodeType()) { - - case ASTNode.TYPE_DECLARATION: - System.err.println(getNodeAsString(node)); - TypeDeclaration td = (TypeDeclaration) node; - if (td.getName().toString().equals(name)) { - if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) { - // look for constructor; - MethodDeclaration[] methods = td.getMethods(); - for (MethodDeclaration md : methods) { - if (md.getName().toString().equals(name)) { - System.out.println("Found a constructor."); - return md; - } - } - } else { - // it's just the TD we're lookin for - return node; - } - } else { - if (constrains.contains(ASTNode.FIELD_DECLARATION)) { - // look for fields - FieldDeclaration[] fields = td.getFields(); - for (FieldDeclaration fd : fields) { - List fragments = fd.fragments(); - for (VariableDeclarationFragment vdf : fragments) { - if (vdf.getName().toString().equals(name)) - return fd; - } - } - } else if (constrains.contains(ASTNode.METHOD_DECLARATION)) { - // look for methods - MethodDeclaration[] methods = td.getMethods(); - for (MethodDeclaration md : methods) { - if (md.getName().toString().equals(name)) { - return md; - } - } - } - } - break; - case ASTNode.METHOD_DECLARATION: - System.err.println(getNodeAsString(node)); - if (((MethodDeclaration) node).getName().toString().equals(name)) - return node; - break; - case ASTNode.SINGLE_VARIABLE_DECLARATION: - System.err.println(getNodeAsString(node)); - if (((SingleVariableDeclaration) node).getName().toString().equals(name)) - return node; - break; - case ASTNode.FIELD_DECLARATION: - System.err.println("FD" + node); - vdfList = ((FieldDeclaration) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - System.err.println("VDE" + node); - vdfList = ((VariableDeclarationExpression) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - System.err.println("VDS" + node); - vdfList = ((VariableDeclarationStatement) node).fragments(); - break; - - default: - - } - if (vdfList != null) { - for (VariableDeclarationFragment vdf : vdfList) { - if (vdf.getName().toString().equals(name)) - return node; - } - } - return null; - } - - public static boolean isAddableASTNode(ASTNode node) { - switch (node.getNodeType()) { -// case ASTNode.STRING_LITERAL: -// case ASTNode.NUMBER_LITERAL: -// case ASTNode.BOOLEAN_LITERAL: -// case ASTNode.NULL_LITERAL: -// return false; - default: - return true; - } - } - - /** - * For any line or expression, finds the line start offset(java code). - * @param node - * @return - */ - public int getASTNodeLineStartOffset(ASTNode node){ - int nodeLineNo = getLineNumber(node); - while(node.getParent() != null){ - if (getLineNumber(node.getParent()) == nodeLineNo) { - node = node.getParent(); - } else { - break; - } - } - return node.getStartPosition(); - } - - /** - * For any node, finds various offsets (java code). - * - * @param node - * @return int[]{line number, line number start offset, node start offset, - * node length} - */ - public int[] getASTNodeAllOffsets(ASTNode node){ - int nodeLineNo = getLineNumber(node), nodeOffset = node.getStartPosition(), nodeLength = node - .getLength(); - while(node.getParent() != null){ - if (getLineNumber(node.getParent()) == nodeLineNo) { - node = node.getParent(); - } else { - break; - } - } - return new int[]{nodeLineNo, node.getStartPosition(), nodeOffset,nodeLength}; - } - - - - static private String getNodeAsString(ASTNode node) { - if (node == null) - return "NULL"; - String className = node.getClass().getName(); - int index = className.lastIndexOf("."); - if (index > 0) - className = className.substring(index + 1); - - // if(node instanceof BodyDeclaration) - // return className; - - String value = className; - - if (node instanceof TypeDeclaration) - value = ((TypeDeclaration) node).getName().toString() + " | " + className; - else if (node instanceof MethodDeclaration) - value = ((MethodDeclaration) node).getName().toString() + " | " - + className; - else if (node instanceof MethodInvocation) - value = ((MethodInvocation) node).getName().toString() + " | " - + className; - else if (node instanceof FieldDeclaration) - value = ((FieldDeclaration) node).toString() + " FldDecl| "; - else if (node instanceof SingleVariableDeclaration) - value = ((SingleVariableDeclaration) node).getName() + " - " - + ((SingleVariableDeclaration) node).getType() + " | SVD "; - else if (node instanceof ExpressionStatement) - value = node.toString() + className; - else if (node instanceof SimpleName) - value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; - else if (node instanceof QualifiedName) - value = node.toString() + " | " + className; - else if (className.startsWith("Variable")) - value = node.toString() + " | " + className; - else if (className.endsWith("Type")) - value = node.toString() + " |" + className; - value += " [" + node.getStartPosition() + "," - + (node.getStartPosition() + node.getLength()) + "]"; - value += " Line: " - + ((CompilationUnit) node.getRoot()).getLineNumber(node - .getStartPosition()); - return value; - } - - /** - * CompletionPanel name - * - * @param node - * @return - */ - static private String getNodeAsString2(ASTNode node) { - if (node == null) - return "NULL"; - String className = node.getClass().getName(); - int index = className.lastIndexOf("."); - if (index > 0) - className = className.substring(index + 1); - - // if(node instanceof BodyDeclaration) - // return className; - - String value = className; - - if (node instanceof TypeDeclaration) - value = ((TypeDeclaration) node).getName().toString(); - else if (node instanceof MethodDeclaration) - value = ((MethodDeclaration) node).getName().toString(); - else if (node instanceof MethodInvocation) - value = ((MethodInvocation) node).getName().toString() + " | " - + className; - else if (node instanceof FieldDeclaration) - value = ((FieldDeclaration) node).toString(); - else if (node instanceof SingleVariableDeclaration) - value = ((SingleVariableDeclaration) node).getName().toString(); - else if (node instanceof ExpressionStatement) - value = node.toString() + className; - else if (node instanceof SimpleName) - value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; - else if (node instanceof QualifiedName) - value = node.toString(); - else if (node instanceof VariableDeclarationFragment) - value = ((VariableDeclarationFragment) node).getName().toString(); - else if (className.startsWith("Variable")) - value = node.toString(); - else if (node instanceof VariableDeclarationStatement) - value = ((VariableDeclarationStatement) node).toString(); - else if (className.endsWith("Type")) - value = node.toString(); -// value += " [" + node.getStartPosition() + "," -// + (node.getStartPosition() + node.getLength()) + "]"; -// value += " Line: " -// + ((CompilationUnit) node.getRoot()).getLineNumber(node -// .getStartPosition()); - return value; - } - - public void jdocWindowVisible(boolean visible) { - jdocWindow.setVisible(visible); - } - - public static String readFile(String path) { - BufferedReader reader = null; - try { - reader = new BufferedReader( - new InputStreamReader( - new FileInputStream( - new File( - path)))); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - try { - StringBuilder ret = new StringBuilder(); - // ret.append("package " + className + ";\n"); - String line; - while ((line = reader.readLine()) != null) { - ret.append(line); - ret.append("\n"); - } - return ret.toString(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return null; - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java deleted file mode 100644 index 359d3d4e2..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ASTNodeWrapper.java +++ /dev/null @@ -1,425 +0,0 @@ -package processing.mode.experimental; - -import java.util.Iterator; -import java.util.List; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.ExpressionStatement; -import org.eclipse.jdt.core.dom.FieldDeclaration; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.MethodInvocation; -import org.eclipse.jdt.core.dom.QualifiedName; -import org.eclipse.jdt.core.dom.SimpleName; -import org.eclipse.jdt.core.dom.SingleVariableDeclaration; -import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; -import org.eclipse.jdt.core.dom.TypeDeclaration; - -public class ASTNodeWrapper { - private ASTNode Node; - - private String label; - - private int lineNumber; - - //private int apiLevel; - - /* - * TODO: Every ASTNode object in ASTGenerator.codetree is stored as a - * ASTNodeWrapper instance. So how resource heavy would it be to store a - * pointer to ECS in every instance of ASTNodeWrapper? Currently I will rather - * pass an ECS pointer in the argument when I need to access a method which - * requires a method defined in ECS, i.e, only on demand. - * Bad design choice for ECS methods? IDK, yet. - */ - - public ASTNodeWrapper(ASTNode node) { - if (node == null){ - return; - } - this.Node = node; - label = getNodeAsString(node); - if (label == null) - label = node.toString(); - lineNumber = getLineNumber(node); - label += " | Line " + lineNumber; - //apiLevel = 0; - } - - /** - * For this node, finds various offsets (java code). - * Note that line start offset for this node is int[2] - int[1] - * @return int[]{line number, line number start offset, node start offset, - * node length} - */ - public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { - int nodeOffset = Node.getStartPosition(), nodeLength = Node - .getLength(); - ASTNode thisNode = Node; - while (thisNode.getParent() != null) { - if (getLineNumber(thisNode.getParent()) == lineNumber) { - thisNode = thisNode.getParent(); - } else { - break; - } - } - /* - * There's an edge case here - multiple statements in a single line. - * After identifying the statement with the line number, I'll have to - * look at previous tree nodes in the same level for same line number. - * The correct line start offset would be the line start offset of - * the first node with this line number. - * - * Using linear search for now. P.S: Eclipse AST iterators are messy. - * TODO: binary search might improve speed by 0.001%? - */ - - int altStartPos = thisNode.getStartPosition(); - thisNode = thisNode.getParent(); - - Iterator it = thisNode - .structuralPropertiesForType().iterator(); - boolean flag = true; - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) thisNode - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - if (getLineNumber(cnode) == lineNumber) { - if (flag) { - altStartPos = cnode.getStartPosition(); - // System.out.println("multi..."); - - flag = false; - } else { - if(cnode == Node){ - // loop only till the current node. - break; - } - // We've located the first node in the line. - // Now normalize offsets till Node - //altStartPos += normalizeOffsets(cnode); - - } - - } - } - } - } - System.out.println("Altspos " + altStartPos); - int pdeoffsets[] = getPDECodeOffsets(ecs); - String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); - if (vals != null) - return new int[] { - lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; - else - return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; - } - - - /** - * - * @param source - * @param inpOffset - * @param nodeLen - * @return int[0] - difference in start offset, int[1] - node length - */ - private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { - - int ret[][] = getOffsetMapping(source); - if(ret == null){ - // no offset mapping needed - return null; - } - int javaCodeMap[] = ret[0]; - int pdeCodeMap[] = ret[1]; - int pi = 1, pj = 1; - pj = 0; - pi = 0; - int count = 1; - // first find the java code index - pj = inpOffset; - - int startIndex = javaCodeMap[pj]; - - // find beginning - while (pdeCodeMap[pi] != startIndex && pi < pdeCodeMap.length) - pi++; - int startoffDif = pi - pj; - int stopindex = javaCodeMap[pj + nodeLen - 1]; - System.out.println(startIndex + "SI,St" + stopindex + "sod " + startoffDif); - - // count till stopindex - while (pdeCodeMap[pi] < stopindex && pi < pdeCodeMap.length) { - pi++; - count++; - } - -// System.out.println("PDE maps from " + pdeeCodeMap[pi]); - - System.out.println("pde len " + count); - return new int[] { startoffDif, count }; - } - - /** - * Generates offset mapping between java and pde code - * - * @param source - * @return int[0] - java code offsets, int[1] = pde code offsets - */ - public int[][] getOffsetMapping(String source){ - - /* - * This is some tricky shiz. So detailed explanation follows: - * - * The main issue here is that pde enhancements like color vars, # literals - * and int() type casting deviate from standard java. But I need to exact - * index matching for pde and java versions of snippets.For ex: - * "color col = #ffaadd;" <-PDE version - * "int col = 0xffffaadd;" <-Converted to Java - * - * For exact index mapping, I need to know at which indices either is - * deviating from the other and by what amount. Turns out, it isn't quite - * easy.(1) First I take the pde version of the code as an argument(pde - * version fetched from the editor directly). I then find all instances - * which need to be converted to pure java, marking those indices and the - * index correction needed. (2) Now all java conversions are applied after - * marking the offsets. This ensures that the index order isn't disturbed by - * one at a time conversions as done in preprocessCode() in ECS. Took me - * sometime to figure out this was a bug. (3) Next I create a tables(two - * separate arrays) which allows me to look it up for matching any index - * between pde or java version of the snippet. This also lets me find out - * any difference in length between both versions. - * - * Keep in mind though, dark magic was involved in creating the final lookup - * table. - * - * TODO: This is a work in progress. There may be more bugs here in hiding. - */ - - System.out.println("Src:" + source); - String sourceAlt = new String(source); - TreeMap offsetmap = new TreeMap(); - - // Find all #[web color] - // Should be 6 digits only. - final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; - Pattern webPattern = Pattern.compile(webColorRegexp); - Matcher webMatcher = webPattern.matcher(sourceAlt); - while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - // System.out.println("-> " + found); - offsetmap.put(webMatcher.end() - 1, 3); - } - - // Find all color data types - final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; - Pattern colorPattern = Pattern.compile(colorTypeRegex); - Matcher colorMatcher = colorPattern.matcher(sourceAlt); - while (colorMatcher.find()) { -// System.out.print("Start index: " + colorMatcher.start()); -// System.out.println(" End index: " + colorMatcher.end() + " "); -// System.out.println("-->" + colorMatcher.group() + "<--"); - offsetmap.put(colorMatcher.end() - 1, -2); - } - - // Find all int(), char() - String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; - - for (String dataType : dataTypeFunc) { - String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; - Pattern pattern = Pattern.compile(dataTypeRegexp); - Matcher matcher = pattern.matcher(sourceAlt); - - while (matcher.find()) { -// System.out.print("Start index: " + matcher.start()); -// System.out.println(" End index: " + matcher.end() + " "); -// System.out.println("-->" + matcher.group() + "<--"); - offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); - } - matcher.reset(); - sourceAlt = matcher.replaceAll("PApplet.parse" - + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) - + "("); - - } - if(offsetmap.isEmpty()){ - System.out.println("No offset matching needed."); - return null; - } - // replace with 0xff[webcolor] and others - webMatcher = webPattern.matcher(sourceAlt); - while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); - // System.out.println("-> " + found); - sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); - webMatcher = webPattern.matcher(sourceAlt); - } - - colorMatcher = colorPattern.matcher(sourceAlt); - sourceAlt = colorMatcher.replaceAll("int"); - - System.out.println(sourceAlt); - - // Create code map. Beware! Dark magic ahead. - int javaCodeMap[] = new int[source.length() * 2]; - int pdeCodeMap[] = new int[source.length() * 2]; - int pi = 1, pj = 1; - int keySum = 0; - for (Integer key : offsetmap.keySet()) { - for (; pi < key +keySum; pi++) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - } - for (; pj < key; pj++) { - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - } - - System.out.println(key + ":" + offsetmap.get(key)); - - int kval = offsetmap.get(key); - if (kval > 0) { - // repeat java offsets - pi--; - pj--; - for (int i = 0; i < kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1]; - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - } - } else { - // repeat pde offsets - pi--; - pj--; - for (int i = 0; i < -kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pdeCodeMap[pj] = pdeCodeMap[pj - 1]; - } - } - - // after each adjustment, the key values need to keep - // up with changed offset - keySum += kval; - } - - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - - while (pi < sourceAlt.length()) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pi++; - } - while (pj < source.length()) { - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; - pj++; - } - - // deubg o/p - for (int i = 0; i < pdeCodeMap.length; i++) { - if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { - if (i < source.length()) - System.out.print(source.charAt(i)); - System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]); - if (i < sourceAlt.length()) - System.out.print(sourceAlt.charAt(i)); - System.out.print(" <-[" + i + "]"); - System.out.println(); - } - } - System.out.println(); - - return new int[][]{javaCodeMap,pdeCodeMap}; - } - - public int[][] getOffsetMapping(ErrorCheckerService ecs){ - int pdeoffsets[] = getPDECodeOffsets(ecs); - String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - return getOffsetMapping(pdeCode); - } - - /** - * - * @param ecs - * - ErrorCheckerService instance - * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] - * - line start offset, int[3] - offset from line start int[2] and - * int[3] are on TODO - */ - public int[] getPDECodeOffsets(ErrorCheckerService ecs) { - return ecs.JavaToPdeOffsets(lineNumber + 1, Node.getStartPosition()); - } - - public String toString() { - return label; - } - - public ASTNode getNode() { - return Node; - } - - public String getLabel() { - return label; - } - - public int getNodeType() { - return Node.getNodeType(); - } - - public int getLineNumber() { - return lineNumber; - } - - private static int getLineNumber(ASTNode node) { - return ((CompilationUnit) node.getRoot()).getLineNumber(node - .getStartPosition()); - } - - static private String getNodeAsString(ASTNode node) { - if (node == null) - return "NULL"; - String className = node.getClass().getName(); - int index = className.lastIndexOf("."); - if (index > 0) - className = className.substring(index + 1); - - // if(node instanceof BodyDeclaration) - // return className; - - String value = className; - - if (node instanceof TypeDeclaration) - value = ((TypeDeclaration) node).getName().toString() + " | " + className; - else if (node instanceof MethodDeclaration) - value = ((MethodDeclaration) node).getName().toString() + " | " - + className; - else if (node instanceof MethodInvocation) - value = ((MethodInvocation) node).getName().toString() + " | " - + className; - else if (node instanceof FieldDeclaration) - value = ((FieldDeclaration) node).toString() + " FldDecl| "; - else if (node instanceof SingleVariableDeclaration) - value = ((SingleVariableDeclaration) node).getName() + " - " - + ((SingleVariableDeclaration) node).getType() + " | SVD "; - else if (node instanceof ExpressionStatement) - value = node.toString() + className; - else if (node instanceof SimpleName) - value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; - else if (node instanceof QualifiedName) - value = node.toString() + " | " + className; - else if (className.startsWith("Variable")) - value = node.toString() + " | " + className; - else if (className.endsWith("Type")) - value = node.toString() + " |" + className; - value += " [" + node.getStartPosition() + "," - + (node.getStartPosition() + node.getLength()) + "]"; - value += " Line: " - + ((CompilationUnit) node.getRoot()).getLineNumber(node - .getStartPosition()); - return value; - } -} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java b/pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java deleted file mode 100755 index 04b3fb111..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ArrayFieldNode.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.ArrayReference; -import com.sun.jdi.ClassNotLoadedException; -import com.sun.jdi.InvalidTypeException; -import com.sun.jdi.Value; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Specialized {@link VariableNode} for representing single fields in an array. - * Overrides {@link #setValue} to properly change the value of the encapsulated - * array field. - * - * @author Martin Leopold - */ -public class ArrayFieldNode extends VariableNode { - - protected ArrayReference array; - protected int index; - - /** - * Construct an {@link ArrayFieldNode}. - * - * @param name the name - * @param type the type - * @param value the value - * @param array a reference to the array - * @param index the index inside the array - */ - public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) { - super(name, type, value); - this.array = array; - this.index = index; - } - - @Override - public void setValue(Value value) { - try { - array.setValue(index, value); - } catch (InvalidTypeException ex) { - Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); - } catch (ClassNotLoadedException ex) { - Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex); - } - this.value = value; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java b/pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java deleted file mode 100755 index 64bd5516b..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ClassLoadListener.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.ReferenceType; - -/** - * Listener to be notified when a class is loaded in the debugger. Used by - * {@link LineBreakpoint}s to activate themselves as soon as the respective - * class is loaded. - * - * @author Martin Leopold - */ -public interface ClassLoadListener { - - /** - * Event handler called when a class is loaded. - * - * @param theClass the class - */ - public void classLoaded(ReferenceType theClass); -} diff --git a/pdex/experimental/src/processing/mode/experimental/Compiler.java b/pdex/experimental/src/processing/mode/experimental/Compiler.java deleted file mode 100755 index 1a85c6a29..000000000 --- a/pdex/experimental/src/processing/mode/experimental/Compiler.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.io.*; -import java.lang.reflect.Method; -import processing.app.Base; -import processing.app.SketchException; -import processing.core.PApplet; - -/** - * Copied from processing.mode.java.Compiler, just added -g switch to generate - * debugging info. - * - * @author Martin Leopold - */ -public class Compiler extends processing.mode.java.Compiler { - /** - * Compile with ECJ. See http://j.mp/8paifz for documentation. - * - * @return true if successful. - * @throws RunnerException Only if there's a problem. Only then. - */ -// public boolean compile(Sketch sketch, -// File srcFolder, -// File binFolder, -// String primaryClassName, -// String sketchClassPath, -// String bootClassPath) throws RunnerException { - static public boolean compile(DebugBuild build) throws SketchException { - - // This will be filled in if anyone gets angry - SketchException exception = null; - boolean success = false; - - String baseCommand[] = new String[] { - "-g", - "-Xemacs", - //"-noExit", // not necessary for ecj - "-source", "1.6", - "-target", "1.6", - "-classpath", build.getClassPath(), - "-nowarn", // we're not currently interested in warnings (works in ecj) - "-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath - }; - //PApplet.println(baseCommand); - - // make list of code files that need to be compiled -// String[] sourceFiles = new String[sketch.getCodeCount()]; -// int sourceCount = 0; -// sourceFiles[sourceCount++] = -// new File(buildPath, primaryClassName + ".java").getAbsolutePath(); -// -// for (SketchCode code : sketch.getCode()) { -// if (code.isExtension("java")) { -// String path = new File(buildPath, code.getFileName()).getAbsolutePath(); -// sourceFiles[sourceCount++] = path; -// } -// } - String[] sourceFiles = Base.listFiles(build.getSrcFolder(), false, ".java"); - -// String[] command = new String[baseCommand.length + sourceFiles.length]; -// System.arraycopy(baseCommand, 0, command, 0, baseCommand.length); -// // append each of the files to the command string -// System.arraycopy(sourceFiles, 0, command, baseCommand.length, sourceCount); - String[] command = PApplet.concat(baseCommand, sourceFiles); - - //PApplet.println(command); - - try { - // Load errors into a local StringBuffer - final StringBuffer errorBuffer = new StringBuffer(); - - // Create single method dummy writer class to slurp errors from ecj - Writer internalWriter = new Writer() { - public void write(char[] buf, int off, int len) { - errorBuffer.append(buf, off, len); - } - - public void flush() { } - - public void close() { } - }; - // Wrap as a PrintWriter since that's what compile() wants - PrintWriter writer = new PrintWriter(internalWriter); - - //result = com.sun.tools.javac.Main.compile(command, writer); - - PrintWriter outWriter = new PrintWriter(System.out); - - // Version that's not dynamically loaded - //CompilationProgress progress = null; - //success = BatchCompiler.compile(command, outWriter, writer, progress); - - // Version that *is* dynamically loaded. First gets the mode class loader - // so that it can grab the compiler JAR files from it. - ClassLoader loader = build.getMode().getJavaModeClassLoader(); - //ClassLoader loader = build.getMode().getClassLoader(); - try { - Class batchClass = - Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader); - Class progressClass = - Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader); - Class[] compileArgs = - new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass }; - Method compileMethod = batchClass.getMethod("compile", compileArgs); - success = (Boolean) - compileMethod.invoke(null, new Object[] { command, outWriter, writer, null }); - } catch (Exception e) { - e.printStackTrace(); - throw new SketchException("Unknown error inside the compiler."); - } - - // Close out the stream for good measure - writer.flush(); - writer.close(); - - BufferedReader reader = - new BufferedReader(new StringReader(errorBuffer.toString())); - //System.err.println(errorBuffer.toString()); - - String line = null; - while ((line = reader.readLine()) != null) { - //System.out.println("got line " + line); // debug - - // get first line, which contains file name, line number, - // and at least the first line of the error message - String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*"; - String[] pieces = PApplet.match(line, errorFormat); - //PApplet.println(pieces); - - // if it's something unexpected, die and print the mess to the console - if (pieces == null) { - exception = new SketchException("Cannot parse error text: " + line); - exception.hideStackTrace(); - // Send out the rest of the error message to the console. - System.err.println(line); - while ((line = reader.readLine()) != null) { - System.err.println(line); - } - break; - } - - // translate the java filename and line number into a un-preprocessed - // location inside a source file or tab in the environment. - String dotJavaFilename = pieces[1]; - // Line numbers are 1-indexed from javac - int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1; - String errorMessage = pieces[4]; - - exception = build.placeException(errorMessage, - dotJavaFilename, - dotJavaLineIndex); - /* - int codeIndex = 0; //-1; - int codeLine = -1; - - // first check to see if it's a .java file - for (int i = 0; i < sketch.getCodeCount(); i++) { - SketchCode code = sketch.getCode(i); - if (code.isExtension("java")) { - if (dotJavaFilename.equals(code.getFileName())) { - codeIndex = i; - codeLine = dotJavaLineIndex; - } - } - } - - // if it's not a .java file, codeIndex will still be 0 - if (codeIndex == 0) { // main class, figure out which tab - //for (int i = 1; i < sketch.getCodeCount(); i++) { - for (int i = 0; i < sketch.getCodeCount(); i++) { - SketchCode code = sketch.getCode(i); - - if (code.isExtension("pde")) { - if (code.getPreprocOffset() <= dotJavaLineIndex) { - codeIndex = i; - //System.out.println("i'm thinkin file " + i); - codeLine = dotJavaLineIndex - code.getPreprocOffset(); - } - } - } - } - //System.out.println("code line now " + codeLine); - exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false); - */ - - if (exception == null) { - exception = new SketchException(errorMessage); - } - - // for a test case once message parsing is implemented, - // use new Font(...) since that wasn't getting picked up properly. - - /* - if (errorMessage.equals("cannot find symbol")) { - handleCannotFindSymbol(reader, exception); - - } else if (errorMessage.indexOf("is already defined") != -1) { - reader.readLine(); // repeats the line of code w/ error - int codeColumn = caretColumn(reader.readLine()); - exception = new RunnerException(errorMessage, - codeIndex, codeLine, codeColumn); - - } else if (errorMessage.startsWith("package") && - errorMessage.endsWith("does not exist")) { - // Because imports are stripped out and re-added to the 0th line of - // the preprocessed code, codeLine will always be wrong for imports. - exception = new RunnerException("P" + errorMessage.substring(1) + - ". You might be missing a library."); - } else { - exception = new RunnerException(errorMessage); - } - */ - if (errorMessage.startsWith("The import ") && - errorMessage.endsWith("cannot be resolved")) { - // The import poo cannot be resolved - //import poo.shoe.blah.*; - //String what = errorMessage.substring("The import ".length()); - String[] m = PApplet.match(errorMessage, "The import (.*) cannot be resolved"); - //what = what.substring(0, what.indexOf(' ')); - if (m != null) { -// System.out.println("'" + m[1] + "'"); - if (m[1].equals("processing.xml")) { - exception.setMessage("processing.xml no longer exists, this code needs to be updated for 2.0."); - System.err.println("The processing.xml library has been replaced " + - "with a new 'XML' class that's built-in."); - handleCrustyCode(); - - } else { - exception.setMessage("The package " + - "\u201C" + m[1] + "\u201D" + - " does not exist. " + - "You might be missing a library."); - System.err.println("Libraries must be " + - "installed in a folder named 'libraries' " + - "inside the 'sketchbook' folder."); - } - } - -// // Actually create the folder and open it for the user -// File sketchbookLibraries = Base.getSketchbookLibrariesFolder(); -// if (!sketchbookLibraries.exists()) { -// if (sketchbookLibraries.mkdirs()) { -// Base.openFolder(sketchbookLibraries); -// } -// } - - } else if (errorMessage.endsWith("cannot be resolved to a type")) { - // xxx cannot be resolved to a type - //xxx c; - - String what = errorMessage.substring(0, errorMessage.indexOf(' ')); - - if (what.equals("BFont") || - what.equals("BGraphics") || - what.equals("BImage")) { - exception.setMessage(what + " has been replaced with P" + what.substring(1)); - handleCrustyCode(); - - } else { - exception.setMessage("Cannot find a class or type " + - "named \u201C" + what + "\u201D"); - } - - } else if (errorMessage.endsWith("cannot be resolved")) { - // xxx cannot be resolved - //println(xxx); - - String what = errorMessage.substring(0, errorMessage.indexOf(' ')); - - if (what.equals("LINE_LOOP") || - what.equals("LINE_STRIP")) { - exception.setMessage("LINE_LOOP and LINE_STRIP are not available, " + - "please update your code."); - handleCrustyCode(); - - } else if (what.equals("framerate")) { - exception.setMessage("framerate should be changed to frameRate."); - handleCrustyCode(); - - } else if (what.equals("screen")) { - exception.setMessage("Change screen.width and screen.height to " + - "displayWidth and displayHeight."); - handleCrustyCode(); - - } else if (what.equals("screenWidth") || - what.equals("screenHeight")) { - exception.setMessage("Change screenWidth and screenHeight to " + - "displayWidth and displayHeight."); - handleCrustyCode(); - - } else { - exception.setMessage("Cannot find anything " + - "named \u201C" + what + "\u201D"); - } - - } else if (errorMessage.startsWith("Duplicate")) { - // "Duplicate nested type xxx" - // "Duplicate local variable xxx" - - } else { - String[] parts = null; - - // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX - //xxx("blah"); - // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX - //xxx("blah", 34); - // The method xxx(String, int) is undefined for the type PApplet - //PApplet.sub("ding"); - String undefined = - "The method (\\S+\\(.*\\)) is undefined for the type (.*)"; - parts = PApplet.match(errorMessage, undefined); - if (parts != null) { - if (parts[1].equals("framerate(int)")) { - exception.setMessage("framerate() no longer exists, use frameRate() instead."); - handleCrustyCode(); - - } else if (parts[1].equals("push()")) { - exception.setMessage("push() no longer exists, use pushMatrix() instead."); - handleCrustyCode(); - - } else if (parts[1].equals("pop()")) { - exception.setMessage("pop() no longer exists, use popMatrix() instead."); - handleCrustyCode(); - - } else { - String mess = "The function " + parts[1] + " does not exist."; - exception.setMessage(mess); - } - break; - } - } - if (exception != null) { - // The stack trace just shows that this happened inside the compiler, - // which is a red herring. Don't ever show it for compiler stuff. - exception.hideStackTrace(); - break; - } - } - } catch (IOException e) { - String bigSigh = "Error while compiling. (" + e.getMessage() + ")"; - exception = new SketchException(bigSigh); - e.printStackTrace(); - success = false; - } - // In case there was something else. - if (exception != null) throw exception; - - return success; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java b/pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java deleted file mode 100644 index 4ff73400f..000000000 --- a/pdex/experimental/src/processing/mode/experimental/CompletionCandidate.java +++ /dev/null @@ -1,130 +0,0 @@ -package processing.mode.experimental; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.List; - -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.MethodDeclaration; - -public class CompletionCandidate implements Comparable{ - - private String definingClass; - - private String elementName; // - - private String label; // the toString value - - private String completionString; - - private int type; - - public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3; - - public CompletionCandidate(String name, String className, String label, - int TYPE) { - definingClass = className; - elementName = name; - if (label.length() > 0) - this.label = label; - else - this.label = name; - this.type = TYPE; - if (type == METHOD) { - this.label += "()"; - } - completionString = this.label; - } - - public CompletionCandidate(Method method) { - definingClass = method.getDeclaringClass().getName(); - elementName = method.getName(); - type = METHOD; - StringBuffer label = new StringBuffer(method.getName() + "("); - StringBuffer cstr = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) { - label.append(","); - cstr.append(","); - } - } - - label.append(")"); - cstr.append(")"); - this.label = label.toString(); - this.completionString = cstr.toString(); - } - - public CompletionCandidate(MethodDeclaration method) { - definingClass = ""; - elementName = method.getName().toString(); - type = METHOD; - List params = (List) method - .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); - StringBuffer label = new StringBuffer(elementName + "("); - StringBuffer cstr = new StringBuffer(method.getName() + "("); - for (int i = 0; i < params.size(); i++) { - label.append(params.get(i).toString()); - if (i < params.size() - 1){ - label.append(","); - cstr.append(","); - } - } - label.append(")"); - cstr.append(")"); - this.label = label.toString(); - this.completionString = cstr.toString(); - } - - public CompletionCandidate(Field f) { - definingClass = f.getDeclaringClass().getName(); - elementName = f.getName(); - type = FIELD; - label = f.getName(); - completionString = elementName; - } - - public CompletionCandidate(String name, String className) { - definingClass = className; - elementName = name; - label = name; - completionString = name; - } - - public CompletionCandidate(String name) { - definingClass = ""; - elementName = name; - label = name; - completionString = name; - } - - public String getDefiningClass() { - return definingClass; - } - - public String getElementName() { - return elementName; - } - - public String getCompletionString() { - return completionString; - } - - public String toString() { - return label; - } - - public int getType() { - return type; - } - - public int compareTo(CompletionCandidate cc) { - if(type != cc.getType()){ - return cc.getType() - type; - } - - return (elementName.compareTo(cc.getElementName())); - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/CompletionPanel.java b/pdex/experimental/src/processing/mode/experimental/CompletionPanel.java deleted file mode 100644 index 3e0f7678d..000000000 --- a/pdex/experimental/src/processing/mode/experimental/CompletionPanel.java +++ /dev/null @@ -1,153 +0,0 @@ -package processing.mode.experimental; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.BorderFactory; -import javax.swing.JList; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.ListSelectionModel; -import javax.swing.text.BadLocationException; - -import processing.app.syntax.JEditTextArea; - -public class CompletionPanel { - private JList list; - - private JPopupMenu popupMenu; - - private String subWord; - - private final int insertionPosition; - - private TextArea textarea; - - private JScrollPane scrollPane; - - public CompletionPanel(JEditTextArea textarea, int position, String subWord, - CompletionCandidate[] items, Point location) { - this.textarea = (TextArea) textarea; - this.insertionPosition = position; - if (subWord.indexOf('.') != -1) - this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); - else - this.subWord = subWord; - popupMenu = new JPopupMenu(); - popupMenu.removeAll(); - popupMenu.setOpaque(false); - popupMenu.setBorder(null); - scrollPane = new JScrollPane(); - scrollPane.setViewportView(list = createSuggestionList(position, items)); - popupMenu.add(scrollPane, BorderLayout.CENTER); - this.textarea.errorCheckerService.astGenerator - .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); - popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) - + location.y); - - } - - public void hide() { - popupMenu.setVisible(false); - } - - public boolean isVisible() { - return popupMenu.isVisible(); - } - - public JList createSuggestionList(final int position, - final CompletionCandidate[] items) { - - JList list = new JList(items); - list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); - list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.setSelectedIndex(0); - list.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - insertSelection(); - hideSuggestion(); - } - } - }); - return list; - } - - public boolean insertSelection() { - if (list.getSelectedValue() != null) { - try { - final String selectedSuggestion = ((CompletionCandidate) list - .getSelectedValue()).getCompletionString().substring(subWord.length()); - textarea.getDocument().insertString(insertionPosition, - selectedSuggestion, null); - textarea.setCaretPosition(insertionPosition - + selectedSuggestion.length()); - return true; - } catch (BadLocationException e1) { - e1.printStackTrace(); - } - hideSuggestion(); - } - return false; - } - - public void hideSuggestion() { - hide(); - //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); - } - - public void moveUp() { - if (list.getSelectedIndex() == 0) { - scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); - selectIndex(list.getModel().getSize() - 1); - return; - } else { - int index = Math.max(list.getSelectedIndex() - 1, 0); - selectIndex(index); - } - int step = scrollPane.getVerticalScrollBar().getMaximum() - / list.getModel().getSize(); - scrollPane.getVerticalScrollBar().setValue(scrollPane - .getVerticalScrollBar() - .getValue() - - step); - textarea.errorCheckerService.astGenerator - .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); - - } - - public void moveDown() { - if (list.getSelectedIndex() == list.getModel().getSize() - 1) { - scrollPane.getVerticalScrollBar().setValue(0); - selectIndex(0); - return; - } else { - int index = Math.min(list.getSelectedIndex() + 1, list.getModel() - .getSize() - 1); - selectIndex(index); - } - textarea.errorCheckerService.astGenerator - .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); - int step = scrollPane.getVerticalScrollBar().getMaximum() - / list.getModel().getSize(); - scrollPane.getVerticalScrollBar().setValue(scrollPane - .getVerticalScrollBar() - .getValue() - + step); - } - - private void selectIndex(int index) { - list.setSelectedIndex(index); -// final int position = textarea.getCaretPosition(); -// SwingUtilities.invokeLater(new Runnable() { -// @Override -// public void run() { -// textarea.setCaretPosition(position); -// }; -// }); - } -} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/DebugBuild.java b/pdex/experimental/src/processing/mode/experimental/DebugBuild.java deleted file mode 100755 index fdb9b34e3..000000000 --- a/pdex/experimental/src/processing/mode/experimental/DebugBuild.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.io.File; -import processing.app.Sketch; -import processing.app.SketchException; -import processing.mode.java.JavaBuild; - -/** - * Copied from processing.mode.java.JavaBuild, just changed compiler. - * - * @author Martin Leopold - */ -public class DebugBuild extends JavaBuild { - - public DebugBuild(Sketch sketch) { - super(sketch); - } - - /** - * Preprocess and compile sketch. Copied from - * processing.mode.java.JavaBuild, just changed compiler. - * - * @param srcFolder - * @param binFolder - * @param sizeWarning - * @return main class name or null on compile failure - * @throws SketchException - */ - @Override - public String build(File srcFolder, File binFolder, boolean sizeWarning) throws SketchException { - this.srcFolder = srcFolder; - this.binFolder = binFolder; - -// Base.openFolder(srcFolder); -// Base.openFolder(binFolder); - - // run the preprocessor - String classNameFound = preprocess(srcFolder, sizeWarning); - - // compile the program. errors will happen as a RunnerException - // that will bubble up to whomever called build(). -// Compiler compiler = new Compiler(this); -// String bootClasses = System.getProperty("sun.boot.class.path"); -// if (compiler.compile(this, srcFolder, binFolder, primaryClassName, getClassPath(), bootClasses)) { - - if (Compiler.compile(this)) { // use compiler with debug info enabled (-g switch flicked) - sketchClassName = classNameFound; - return classNameFound; - } - return null; - } - - public ExperimentalMode getMode() { - return (ExperimentalMode)mode; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/DebugEditor.java b/pdex/experimental/src/processing/mode/experimental/DebugEditor.java deleted file mode 100755 index 099e90d1a..000000000 --- a/pdex/experimental/src/processing/mode/experimental/DebugEditor.java +++ /dev/null @@ -1,1165 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.Frame; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.Box; -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.border.EtchedBorder; -import javax.swing.table.TableModel; -import javax.swing.text.Document; -import processing.app.*; -import processing.app.syntax.JEditTextArea; -import processing.app.syntax.PdeTextAreaDefaults; -import processing.core.PApplet; -import processing.mode.java.JavaEditor; - -/** - * Main View Class. Handles the editor window including tool bar and menu. Has - * access to the Sketch. Provides line highlighting (for breakpoints and the - * debuggers current line). - * - * @author Martin Leopold - * @author Manindra Moharana <me@mkmoharana.com> - * - * - */ -public class DebugEditor extends JavaEditor implements ActionListener { - // important fields from superclass - //protected Sketch sketch; - //private JMenu fileMenu; - //protected EditorToolbar toolbar; - - // highlighting - protected Color breakpointColor = new Color(240, 240, 240); // the background color for highlighting lines - protected Color currentLineColor = new Color(255, 255, 150); // the background color for highlighting lines - protected Color breakpointMarkerColor = new Color(74, 84, 94); // the color of breakpoint gutter markers - protected Color currentLineMarkerColor = new Color(226, 117, 0); // the color of current line gutter markers - protected List breakpointedLines = new ArrayList(); // breakpointed lines - protected LineHighlight currentLine; // line the debugger is currently suspended at - protected final String breakpointMarkerComment = " //<>//"; // breakpoint marker comment - // menus - protected JMenu debugMenu; // the debug menu - // debugger control - protected JMenuItem debugMenuItem; - protected JMenuItem continueMenuItem; - protected JMenuItem stopMenuItem; - // breakpoints - protected JMenuItem toggleBreakpointMenuItem; - protected JMenuItem listBreakpointsMenuItem; - // stepping - protected JMenuItem stepOverMenuItem; - protected JMenuItem stepIntoMenuItem; - protected JMenuItem stepOutMenuItem; - // info - protected JMenuItem printStackTraceMenuItem; - protected JMenuItem printLocalsMenuItem; - protected JMenuItem printThisMenuItem; - protected JMenuItem printSourceMenuItem; - protected JMenuItem printThreads; - // variable inspector - protected JMenuItem toggleVariableInspectorMenuItem; - // references - protected ExperimentalMode dmode; // the mode - protected Debugger dbg; // the debugger - protected VariableInspector vi; // the variable inspector frame - protected TextArea ta; // the text area - - - protected ErrorBar errorBar; - /** - * Show Console button - */ - protected XQConsoleToggle btnShowConsole; - - /** - * Show Problems button - */ - protected XQConsoleToggle btnShowErrors; - - /** - * Scroll pane for Error Table - */ - protected JScrollPane errorTableScrollPane; - - /** - * Panel with card layout which contains the p5 console and Error Table - * panes - */ - protected JPanel consoleProblemsPane; - - protected XQErrorTable errorTable; - - /** - * Enable/Disable compilation checking - */ - protected boolean compilationCheckEnabled = true; - - /** - * Show warnings menu item - */ - protected JCheckBoxMenuItem showWarnings; - - /** - * Check box menu item for show/hide Problem Window - */ - public JCheckBoxMenuItem problemWindowMenuCB; - - public DebugEditor(Base base, String path, EditorState state, Mode mode) { - super(base, path, state, mode); - - // get mode - dmode = (ExperimentalMode) mode; - - // init controller class - dbg = new Debugger(this); - - // variable inspector window - vi = new VariableInspector(this); - - // access to customized (i.e. subclassed) text area - ta = (TextArea) textarea; - - // add refactor option - JMenuItem renameItem = new JMenuItem("Rename.."); - renameItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleRefactor(); - } - }); - // TODO: Add support for word select on right click and rename. -// ta.customPainter.addMouseListener(new MouseAdapter() { -// public void mouseClicked(MouseEvent evt) { -// System.out.println(evt); -// } -// }); - ta.getRightClickPopup().add(renameItem); - // set action on frame close -// addWindowListener(new WindowAdapter() { -// @Override -// public void windowClosing(WindowEvent e) { -// onWindowClosing(e); -// } -// }); - - // load settings from theme.txt - ExperimentalMode theme = dmode; - breakpointColor = theme.getThemeColor("breakpoint.bgcolor", breakpointColor); - breakpointMarkerColor = theme.getThemeColor("breakpoint.marker.color", breakpointMarkerColor); - currentLineColor = theme.getThemeColor("currentline.bgcolor", currentLineColor); - currentLineMarkerColor = theme.getThemeColor("currentline.marker.color", currentLineMarkerColor); - - // set breakpoints from marker comments - for (LineID lineID : stripBreakpointComments()) { - //System.out.println("setting: " + lineID); - dbg.setBreakpoint(lineID); - } - getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here - - checkForJavaTabs(); - initializeErrorChecker(); - ta.setECSandThemeforTextArea(errorCheckerService, dmode); - addXQModeUI(); - //TODO: Remove this later - setBounds(160, 300, getWidth(), getHeight()); - } - - private void addXQModeUI(){ - - // Adding ErrorBar - JPanel textAndError = new JPanel(); - Box box = (Box) textarea.getParent(); - box.remove(2); // Remove textArea from it's container, i.e Box - textAndError.setLayout(new BorderLayout()); - errorBar = new ErrorBar(this, textarea.getMinimumSize().height, dmode); - textAndError.add(errorBar, BorderLayout.EAST); - textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight()); - textAndError.add(textarea); - box.add(textAndError); - - // Adding Error Table in a scroll pane - errorTableScrollPane = new JScrollPane(); - errorTable = new XQErrorTable(errorCheckerService); - // errorTableScrollPane.setBorder(new EmptyBorder(2, 2, 2, 2)); - errorTableScrollPane.setBorder(new EtchedBorder()); - errorTableScrollPane.setViewportView(errorTable); - - // Adding toggle console button - consolePanel.remove(2); - JPanel lineStatusPanel = new JPanel(); - lineStatusPanel.setLayout(new BorderLayout()); - btnShowConsole = new XQConsoleToggle(this, - XQConsoleToggle.text[0], lineStatus.getHeight()); - btnShowErrors = new XQConsoleToggle(this, - XQConsoleToggle.text[1], lineStatus.getHeight()); - btnShowConsole.addMouseListener(btnShowConsole); - - // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST); - // lineStatusPanel.add(btnShowErrors); - btnShowErrors.addMouseListener(btnShowErrors); - - JPanel toggleButtonPanel = new JPanel(new BorderLayout()); - toggleButtonPanel.add(btnShowConsole, BorderLayout.EAST); - toggleButtonPanel.add(btnShowErrors, BorderLayout.WEST); - lineStatusPanel.add(toggleButtonPanel, BorderLayout.EAST); - lineStatus.setBounds(0, 0, toggleButtonPanel.getX() - 1, - toggleButtonPanel.getHeight()); - lineStatusPanel.add(lineStatus); - consolePanel.add(lineStatusPanel, BorderLayout.SOUTH); - lineStatusPanel.repaint(); - - // Adding JPanel with CardLayout for Console/Problems Toggle - consolePanel.remove(1); - consoleProblemsPane = new JPanel(new CardLayout()); - consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.text[1]); - consoleProblemsPane.add(console, XQConsoleToggle.text[0]); - consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); - } - -// /** -// * Event handler called when closing the editor window. Kills the variable -// * inspector window. -// * -// * @param e the event object -// */ -// protected void onWindowClosing(WindowEvent e) { -// // remove var.inspector -// vi.dispose(); -// // quit running debug session -// dbg.stopDebug(); -// } - /** - * Used instead of the windowClosing event handler, since it's not called on - * mode switch. Called when closing the editor window. Stops running debug - * sessions and kills the variable inspector window. - */ - @Override - public void dispose() { - //System.out.println("window dispose"); - // quit running debug session - dbg.stopDebug(); - // remove var.inspector - vi.dispose(); - // original dispose - super.dispose(); - } - - /** - * Overrides sketch menu creation to change keyboard shortcuts from "Run". - * - * @return the sketch menu - */ - @Override - public JMenu buildSketchMenu() { - JMenuItem runItem = Toolkit.newJMenuItemShift(DebugToolbar.getTitle(DebugToolbar.RUN, false), KeyEvent.VK_R); - runItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - handleRun(); - } - }); - - JMenuItem presentItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.RUN, true)); - presentItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - handlePresent(); - } - }); - - JMenuItem stopItem = new JMenuItem(DebugToolbar.getTitle(DebugToolbar.STOP, false)); - stopItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - handleStop(); - } - }); - return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); - } - - /** - * Creates the debug menu. Includes ActionListeners for the menu items. - * Intended for adding to the menu bar. - * - * @return The debug menu - */ - protected JMenu buildDebugMenu() { - debugMenu = new JMenu("Debug"); - - debugMenuItem = Toolkit.newJMenuItem("Debug", KeyEvent.VK_R); - debugMenuItem.addActionListener(this); - continueMenuItem = Toolkit.newJMenuItem("Continue", KeyEvent.VK_U); - continueMenuItem.addActionListener(this); - stopMenuItem = new JMenuItem("Stop"); - stopMenuItem.addActionListener(this); - - toggleBreakpointMenuItem = Toolkit.newJMenuItem("Toggle Breakpoint", KeyEvent.VK_B); - toggleBreakpointMenuItem.addActionListener(this); - listBreakpointsMenuItem = new JMenuItem("List Breakpoints"); - listBreakpointsMenuItem.addActionListener(this); - - stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_J); - stepOverMenuItem.addActionListener(this); - stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_J); - stepIntoMenuItem.addActionListener(this); - stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_J); - stepOutMenuItem.addActionListener(this); - - printStackTraceMenuItem = new JMenuItem("Print Stack Trace"); - printStackTraceMenuItem.addActionListener(this); - printLocalsMenuItem = new JMenuItem("Print Locals"); - printLocalsMenuItem.addActionListener(this); - printThisMenuItem = new JMenuItem("Print Fields"); - printThisMenuItem.addActionListener(this); - printSourceMenuItem = new JMenuItem("Print Source Location"); - printSourceMenuItem.addActionListener(this); - printThreads = new JMenuItem("Print Threads"); - printThreads.addActionListener(this); - - toggleVariableInspectorMenuItem = Toolkit.newJMenuItem("Toggle Variable Inspector", KeyEvent.VK_I); - toggleVariableInspectorMenuItem.addActionListener(this); - - debugMenu.add(debugMenuItem); - debugMenu.add(continueMenuItem); - debugMenu.add(stopMenuItem); - debugMenu.addSeparator(); - debugMenu.add(toggleBreakpointMenuItem); - debugMenu.add(listBreakpointsMenuItem); - debugMenu.addSeparator(); - debugMenu.add(stepOverMenuItem); - debugMenu.add(stepIntoMenuItem); - debugMenu.add(stepOutMenuItem); - debugMenu.addSeparator(); - debugMenu.add(printStackTraceMenuItem); - debugMenu.add(printLocalsMenuItem); - debugMenu.add(printThisMenuItem); - debugMenu.add(printSourceMenuItem); - debugMenu.add(printThreads); - debugMenu.addSeparator(); - debugMenu.add(toggleVariableInspectorMenuItem); - debugMenu.addSeparator(); - - // XQMode menu items - - JCheckBoxMenuItem item; - final DebugEditor thisEditor = this; - item = new JCheckBoxMenuItem("Error Checker Enabled"); - item.setSelected(true); - item.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { - // unticked Menu Item - errorCheckerService.pauseThread(); - System.out.println(thisEditor.getSketch().getName() - + " - Error Checker paused."); - errorBar.errorPoints.clear(); - errorCheckerService.problemsList.clear(); - errorCheckerService.updateErrorTable(); - errorCheckerService.updateEditorStatus(); - getTextArea().repaint(); - errorBar.repaint(); - } else { - errorCheckerService.resumeThread(); - System.out.println(thisEditor.getSketch().getName() - + " - Error Checker resumed."); - } - } - }); - debugMenu.add(item); - - problemWindowMenuCB = new JCheckBoxMenuItem("Show Problem Window"); - // problemWindowMenuCB.setSelected(true); - problemWindowMenuCB.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (errorCheckerService.errorWindow == null) { - return; - } - errorCheckerService.errorWindow - .setVisible(((JCheckBoxMenuItem) e.getSource()) - .isSelected()); - // switch to console, now that Error Window is open - toggleView(XQConsoleToggle.text[0]); - } - }); - debugMenu.add(problemWindowMenuCB); - - showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); - showWarnings.setSelected(true); - showWarnings.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e - .getSource()).isSelected(); - } - }); - debugMenu.add(showWarnings); - - - return debugMenu; - } - - @Override - public JMenu buildModeMenu() { - return buildDebugMenu(); - } - - /** - * Callback for menu items. Implementation of Swing ActionListener. - * - * @param ae Action event - */ - @Override - public void actionPerformed(ActionEvent ae) { - //System.out.println("ActionEvent: " + ae.toString()); - - JMenuItem source = (JMenuItem) ae.getSource(); - if (source == debugMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Debug' menu item"); - //dmode.handleDebug(sketch, this); - dbg.startDebug(); - } else if (source == stopMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Stop' menu item"); - //dmode.handleDebug(sketch, this); - dbg.stopDebug(); - } else if (source == continueMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Continue' menu item"); - //dmode.handleDebug(sketch, this); - dbg.continueDebug(); - } else if (source == stepOverMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Over' menu item"); - dbg.stepOver(); - } else if (source == stepIntoMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Into' menu item"); - dbg.stepInto(); - } else if (source == stepOutMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Step Out' menu item"); - dbg.stepOut(); - } else if (source == printStackTraceMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Stack Trace' menu item"); - dbg.printStackTrace(); - } else if (source == printLocalsMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Locals' menu item"); - dbg.printLocals(); - } else if (source == printThisMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print This' menu item"); - dbg.printThis(); - } else if (source == printSourceMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Source' menu item"); - dbg.printSource(); - } else if (source == printThreads) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Print Threads' menu item"); - dbg.printThreads(); - } else if (source == toggleBreakpointMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' menu item"); - dbg.toggleBreakpoint(); - } else if (source == listBreakpointsMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'List Breakpoints' menu item"); - dbg.listBreakpoints(); - } else if (source == toggleVariableInspectorMenuItem) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); - toggleVariableInspector(); - } - } - -// @Override -// public void handleRun() { -// dbg.continueDebug(); -// } - /** - * Event handler called when hitting the stop button. Stops a running debug - * session or performs standard stop action if not currently debugging. - */ - @Override - public void handleStop() { - if (dbg.isStarted()) { - dbg.stopDebug(); - } else { - super.handleStop(); - } - } - - /** - * Event handler called when loading another sketch in this editor. Clears - * breakpoints of previous sketch. - * - * @param path - * @return true if a sketch was opened, false if aborted - */ - @Override - protected boolean handleOpenInternal(String path) { - boolean didOpen = super.handleOpenInternal(path); - if (didOpen && dbg != null) { - // should already been stopped (open calls handleStop) - dbg.clearBreakpoints(); - clearBreakpointedLines(); // force clear breakpoint highlights - variableInspector().reset(); // clear contents of variable inspector - } - return didOpen; - } - - /** - * Extract breakpointed lines from source code marker comments. This removes - * marker comments from the editor text. Intended to be called on loading a - * sketch, since re-setting the sketches contents after removing the markers - * will clear all breakpoints. - * - * @return the list of {@link LineID}s where breakpoint marker comments were - * removed from. - */ - protected List stripBreakpointComments() { - List bps = new ArrayList(); - // iterate over all tabs - Sketch sketch = getSketch(); - for (int i = 0; i < sketch.getCodeCount(); i++) { - SketchCode tab = sketch.getCode(i); - String code = tab.getProgram(); - String lines[] = code.split("\\r?\\n"); // newlines not included - //System.out.println(code); - - // scan code for breakpoint comments - int lineIdx = 0; - for (String line : lines) { - //System.out.println(line); - if (line.endsWith(breakpointMarkerComment)) { - LineID lineID = new LineID(tab.getFileName(), lineIdx); - bps.add(lineID); - //System.out.println("found breakpoint: " + lineID); - // got a breakpoint - //dbg.setBreakpoint(lineID); - int index = line.lastIndexOf(breakpointMarkerComment); - lines[lineIdx] = line.substring(0, index); - } - lineIdx++; - } - //tab.setProgram(code); - code = PApplet.join(lines, "\n"); - setTabContents(tab.getFileName(), code); - } - return bps; - } - - /** - * Add breakpoint marker comments to the source file of a specific tab. This - * acts on the source file on disk, not the editor text. Intended to be - * called just after saving the sketch. - * - * @param tabFilename the tab file name - */ - protected void addBreakpointComments(String tabFilename) { - SketchCode tab = getTab(tabFilename); - List bps = dbg.getBreakpoints(tab.getFileName()); - - // load the source file - File sourceFile = new File(sketch.getFolder(), tab.getFileName()); - //System.out.println("file: " + sourceFile); - try { - String code = Base.loadFile(sourceFile); - //System.out.println("code: " + code); - String lines[] = code.split("\\r?\\n"); // newlines not included - for (LineBreakpoint bp : bps) { - //System.out.println("adding bp: " + bp.lineID()); - lines[bp.lineID().lineIdx()] += breakpointMarkerComment; - } - code = PApplet.join(lines, "\n"); - //System.out.println("new code: " + code); - Base.saveFile(code, sourceFile); - } catch (IOException ex) { - Logger.getLogger(DebugEditor.class.getName()).log(Level.SEVERE, null, ex); - } - } - - @Override - public boolean handleSave(boolean immediately) { - //System.out.println("handleSave " + immediately); - - // note modified tabs - final List modified = new ArrayList(); - for (int i = 0; i < getSketch().getCodeCount(); i++) { - SketchCode tab = getSketch().getCode(i); - if (tab.isModified()) { - modified.add(tab.getFileName()); - } - } - - boolean saved = super.handleSave(immediately); - if (saved) { - if (immediately) { - for (String tabFilename : modified) { - addBreakpointComments(tabFilename); - } - } else { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - for (String tabFilename : modified) { - addBreakpointComments(tabFilename); - } - } - }); - } - } - return saved; - } - - @Override - public boolean handleSaveAs() { - //System.out.println("handleSaveAs"); - String oldName = getSketch().getCode(0).getFileName(); - //System.out.println("old name: " + oldName); - boolean saved = super.handleSaveAs(); - if (saved) { - // re-set breakpoints in first tab (name has changed) - List bps = dbg.getBreakpoints(oldName); - dbg.clearBreakpoints(oldName); - String newName = getSketch().getCode(0).getFileName(); - //System.out.println("new name: " + newName); - for (LineBreakpoint bp : bps) { - LineID line = new LineID(newName, bp.lineID().lineIdx()); - //System.out.println("setting: " + line); - dbg.setBreakpoint(line); - } - // add breakpoint marker comments to source file - for (int i = 0; i < getSketch().getCodeCount(); i++) { - addBreakpointComments(getSketch().getCode(i).getFileName()); - } - - // set new name of variable inspector - vi.setTitle(getSketch().getName()); - } - return saved; - } - - /** - * Set text contents of a specific tab. Updates underlying document and text - * area. Clears Breakpoints. - * - * @param tabFilename the tab file name - * @param code the text to set - */ - protected void setTabContents(String tabFilename, String code) { - // remove all breakpoints of this tab - dbg.clearBreakpoints(tabFilename); - - SketchCode currentTab = getCurrentTab(); - - // set code of tab - SketchCode tab = getTab(tabFilename); - if (tab != null) { - tab.setProgram(code); - // this updates document and text area - // TODO: does this have any negative effects? (setting the doc to null) - tab.setDocument(null); - setCode(tab); - - // switch back to original tab - setCode(currentTab); - } - } - - /** - * Clear the console. - */ - public void clearConsole() { - console.clear(); - } - - /** - * Clear current text selection. - */ - public void clearSelection() { - setSelection(getCaretOffset(), getCaretOffset()); - } - - /** - * Select a line in the current tab. - * - * @param lineIdx 0-based line number - */ - public void selectLine(int lineIdx) { - setSelection(getLineStartOffset(lineIdx), getLineStopOffset(lineIdx)); - } - - /** - * Set the cursor to the start of a line. - * - * @param lineIdx 0-based line number - */ - public void cursorToLineStart(int lineIdx) { - setSelection(getLineStartOffset(lineIdx), getLineStartOffset(lineIdx)); - } - - /** - * Set the cursor to the end of a line. - * - * @param lineIdx 0-based line number - */ - public void cursorToLineEnd(int lineIdx) { - setSelection(getLineStopOffset(lineIdx), getLineStopOffset(lineIdx)); - } - - /** - * Switch to a tab. - * - * @param tabFileName the file name identifying the tab. (as in - * {@link SketchCode#getFileName()}) - */ - public void switchToTab(String tabFileName) { - Sketch s = getSketch(); - for (int i = 0; i < s.getCodeCount(); i++) { - if (tabFileName.equals(s.getCode(i).getFileName())) { - s.setCurrentCode(i); - break; - } - } - } - - /** - * Access the debugger. - * - * @return the debugger controller object - */ - public Debugger dbg() { - return dbg; - } - - /** - * Access the mode. - * - * @return the mode object - */ - public ExperimentalMode mode() { - return dmode; - } - - /** - * Access the custom text area object. - * - * @return the text area object - */ - public TextArea textArea() { - return ta; - } - - /** - * Access variable inspector window. - * - * @return the variable inspector object - */ - public VariableInspector variableInspector() { - return vi; - } - - public DebugToolbar toolbar() { - return (DebugToolbar) toolbar; - } - - /** - * Show the variable inspector window. - */ - public void showVariableInspector() { - vi.setVisible(true); - } - - /** - * Set visibility of the variable inspector window. - * - * @param visible true to set the variable inspector visible, false for - * invisible. - */ - public void showVariableInspector(boolean visible) { - vi.setVisible(visible); - } - - /** - * Hide the variable inspector window. - */ - public void hideVariableInspector() { - vi.setVisible(true); - } - - /** - * Toggle visibility of the variable inspector window. - */ - public void toggleVariableInspector() { - vi.setFocusableWindowState(false); // to not get focus when set visible - vi.setVisible(!vi.isVisible()); - vi.setFocusableWindowState(true); // allow to get focus again - } - - /** - * Text area factory method. Instantiates the customized TextArea. - * - * @return the customized text area object - */ - @Override - protected JEditTextArea createTextArea() { - //System.out.println("overriding creation of text area"); - return new TextArea(new PdeTextAreaDefaults(mode), this); - } - - /** - * Set the line to highlight as currently suspended at. Will override the - * breakpoint color, if set. Switches to the appropriate tab and scroll to - * the line by placing the cursor there. - * - * @param line the line to highlight as current suspended line - */ - public void setCurrentLine(LineID line) { - clearCurrentLine(); - if (line == null) { - return; // safety, e.g. when no line mapping is found and the null line is used. - } - switchToTab(line.fileName()); - // scroll to line, by setting the cursor - cursorToLineStart(line.lineIdx()); - // highlight line - currentLine = new LineHighlight(line.lineIdx(), currentLineColor, this); - currentLine.setMarker(ta.currentLineMarker, currentLineMarkerColor); - currentLine.setPriority(10); // fixes current line being hidden by the breakpoint when moved down - } - - /** - * Clear the highlight for the debuggers current line. - */ - public void clearCurrentLine() { - if (currentLine != null) { - currentLine.clear(); - currentLine.dispose(); - - // revert to breakpoint color if any is set on this line - for (LineHighlight hl : breakpointedLines) { - if (hl.lineID().equals(currentLine.lineID())) { - hl.paint(); - break; - } - } - currentLine = null; - } - } - - /** - * Add highlight for a breakpointed line. - * - * @param lineID the line id to highlight as breakpointed - */ - public void addBreakpointedLine(LineID lineID) { - LineHighlight hl = new LineHighlight(lineID, breakpointColor, this); - hl.setMarker(ta.breakpointMarker, breakpointMarkerColor); - breakpointedLines.add(hl); - // repaint current line if it's on this line - if (currentLine != null && currentLine.lineID().equals(lineID)) { - currentLine.paint(); - } - } - - /** - * Add highlight for a breakpointed line on the current tab. - * - * @param lineIdx the line index on the current tab to highlight as - * breakpointed - */ - //TODO: remove and replace by {@link #addBreakpointedLine(LineID lineID)} - public void addBreakpointedLine(int lineIdx) { - addBreakpointedLine(getLineIDInCurrentTab(lineIdx)); - } - - /** - * Remove a highlight for a breakpointed line. Needs to be on the current - * tab. - * - * @param lineIdx the line index on the current tab to remove a breakpoint - * highlight from - */ - public void removeBreakpointedLine(int lineIdx) { - LineID line = getLineIDInCurrentTab(lineIdx); - //System.out.println("line id: " + line.fileName() + " " + line.lineIdx()); - LineHighlight foundLine = null; - for (LineHighlight hl : breakpointedLines) { - if (hl.lineID.equals(line)) { - foundLine = hl; - break; - } - } - if (foundLine != null) { - foundLine.clear(); - breakpointedLines.remove(foundLine); - foundLine.dispose(); - // repaint current line if it's on this line - if (currentLine != null && currentLine.lineID().equals(line)) { - currentLine.paint(); - } - } - } - - /** - * Remove all highlights for breakpointed lines. - */ - public void clearBreakpointedLines() { - for (LineHighlight hl : breakpointedLines) { - hl.clear(); - hl.dispose(); - } - breakpointedLines.clear(); // remove all breakpoints - // fix highlights not being removed when tab names have changed due to opening a new sketch in same editor - ta.clearLineBgColors(); // force clear all highlights - ta.clearGutterText(); - - // repaint current line - if (currentLine != null) { - currentLine.paint(); - } - } - - /** - * Retrieve a {@link LineID} object for a line on the current tab. - * - * @param lineIdx the line index on the current tab - * @return the {@link LineID} object representing a line index on the - * current tab - */ - public LineID getLineIDInCurrentTab(int lineIdx) { - return new LineID(getSketch().getCurrentCode().getFileName(), lineIdx); - } - - /** - * Retrieve line of sketch where the cursor currently resides. - * - * @return the current {@link LineID} - */ - protected LineID getCurrentLineID() { - String tab = getSketch().getCurrentCode().getFileName(); - int lineNo = getTextArea().getCaretLine(); - return new LineID(tab, lineNo); - } - - /** - * Check whether a {@link LineID} is on the current tab. - * - * @param line the {@link LineID} - * @return true, if the {@link LineID} is on the current tab. - */ - public boolean isInCurrentTab(LineID line) { - return line.fileName().equals(getSketch().getCurrentCode().getFileName()); - } - - /** - * Event handler called when switching between tabs. Loads all line - * background colors set for the tab. - * - * @param code tab to switch to - */ - @Override - protected void setCode(SketchCode code) { - //System.out.println("tab switch: " + code.getFileName()); - super.setCode(code); // set the new document in the textarea, etc. need to do this first - - // set line background colors for tab - if (ta != null) { // can be null when setCode is called the first time (in constructor) - // clear all line backgrounds - ta.clearLineBgColors(); - // clear all gutter text - ta.clearGutterText(); - // load appropriate line backgrounds for tab - // first paint breakpoints - for (LineHighlight hl : breakpointedLines) { - if (isInCurrentTab(hl.lineID())) { - hl.paint(); - } - } - // now paint current line (if any) - if (currentLine != null) { - if (isInCurrentTab(currentLine.lineID())) { - currentLine.paint(); - } - } - } - if (dbg() != null && dbg().isStarted()) { - dbg().startTrackingLineChanges(); - } - } - - /** - * Get a tab by its file name. - * - * @param fileName the filename to search for. - * @return the {@link SketchCode} object representing the tab, or null if - * not found - */ - public SketchCode getTab(String fileName) { - Sketch s = getSketch(); - for (SketchCode c : s.getCode()) { - if (c.getFileName().equals(fileName)) { - return c; - } - } - return null; - } - - /** - * Retrieve the current tab. - * - * @return the {@link SketchCode} representing the current tab - */ - public SketchCode getCurrentTab() { - return getSketch().getCurrentCode(); - } - - /** - * Access the currently edited document. - * - * @return the document object - */ - public Document currentDocument() { - //return ta.getDocument(); - return getCurrentTab().getDocument(); - } - - /** - * Factory method for the editor toolbar. Instantiates the customized - * toolbar. - * - * @return the toolbar - */ - @Override - public EditorToolbar createToolbar() { - return new DebugToolbar(this, base); - } - - /** - * Event Handler for double clicking in the left hand gutter area. - * - * @param lineIdx the line (0-based) that was double clicked - */ - public void gutterDblClicked(int lineIdx) { - if (dbg != null) { - dbg.toggleBreakpoint(lineIdx); - } - } - - public void statusBusy() { - statusNotice("Debugger busy..."); - } - - public void statusHalted() { - statusNotice("Debugger halted."); - } - - ErrorCheckerService errorCheckerService; - - /** - * Initializes and starts Error Checker Service - */ - private void initializeErrorChecker() { - Thread errorCheckerThread = null; - - if (errorCheckerThread == null) { - errorCheckerService = new ErrorCheckerService(this); - errorCheckerThread = new Thread(errorCheckerService); - try { - errorCheckerThread.start(); - } catch (Exception e) { - System.err - .println("Error Checker Service not initialized [XQEditor]: " - + e); - // e.printStackTrace(); - } - // System.out.println("Error Checker Service initialized."); - } - - } - - /** - * Updates the error bar - * @param problems - */ - public void updateErrorBar(ArrayList problems) { - errorBar.updateErrorPoints(problems); - } - - /** - * Toggle between Console and Errors List - * - * @param buttonName - * - Button Label - */ - public void toggleView(String buttonName) { - CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); - cl.show(consoleProblemsPane, buttonName); - } - - /** - * Updates the error table - * @param tableModel - * @return - */ - synchronized public boolean updateTable(final TableModel tableModel) { - return errorTable.updateTable(tableModel); - } - - private void handleRefactor() { - System.out.println("Caret at:"); - System.out.println(ta.getLineText(ta.getCaretLine())); - errorCheckerService.astGenerator.handleRefactor(); - } - - /** - * Checks if the sketch contains java tabs. If it does, XQMode ain't built - * for it, yet. Also, user should really start looking at Eclipse. Disable - * compilation check. - */ - private void checkForJavaTabs() { - for (int i = 0; i < this.getSketch().getCodeCount(); i++) { - if (this.getSketch().getCode(i).getExtension().equals("java")) { - compilationCheckEnabled = false; - JOptionPane.showMessageDialog(new Frame(), this - .getSketch().getName() - + " contains .java tabs. Live compilation error checking isn't " - + "supported for java tabs. Only " - + "syntax errors will be reported for .pde tabs."); - break; - } - } - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/DebugRunner.java b/pdex/experimental/src/processing/mode/experimental/DebugRunner.java deleted file mode 100755 index 1f810d964..000000000 --- a/pdex/experimental/src/processing/mode/experimental/DebugRunner.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.VirtualMachine; -import processing.app.RunnerListener; -import processing.app.SketchException; -import processing.app.exec.StreamRedirectThread; -import processing.mode.java.JavaBuild; -import processing.mode.java.runner.MessageSiphon; - -/** - * Runs a {@link JavaBuild}. Launches the build in a new debuggee VM. - * - * @author Martin Leopold - */ -public class DebugRunner extends processing.mode.java.runner.Runner { - - // important inherited fields - // protected VirtualMachine vm; - public DebugRunner(JavaBuild build, RunnerListener listener) throws SketchException { - super(build, listener); - } - - /** - * Launch the virtual machine. Simple non-blocking launch. VM starts - * suspended. - * - * @return debuggee VM or null on failure - */ - public VirtualMachine launch() { -// String[] machineParamList = getMachineParams(); -// String[] sketchParamList = getSketchParams(false); -// /* -// * System.out.println("vm launch sketch params:"); for (int i=0; -// * i - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.awt.Image; -import java.awt.event.MouseEvent; -import java.util.logging.Level; -import java.util.logging.Logger; -import processing.app.Base; -import processing.app.Editor; -import processing.mode.java.JavaToolbar; - -/** - * Custom toolbar for the editor window. Preserves original button numbers - * ({@link JavaToolbar#RUN}, {@link JavaToolbar#STOP}, {@link JavaToolbar#NEW}, - * {@link JavaToolbar#OPEN}, {@link JavaToolbar#SAVE}, {@link JavaToolbar#EXPORT}) - * which can be used e.g. in {@link #activate} and - * {@link #deactivate}. - * - * @author Martin Leopold - */ -public class DebugToolbar extends JavaToolbar { - // preserve original button id's, but re-define so they are accessible - // (they are used by DebugEditor, so they want to be public) - - static protected final int RUN = 100; // change this, to be able to get it's name via getTitle() - static protected final int DEBUG = JavaToolbar.RUN; - - static protected final int CONTINUE = 101; - static protected final int STEP = 102; - static protected final int TOGGLE_BREAKPOINT = 103; - static protected final int TOGGLE_VAR_INSPECTOR = 104; - - static protected final int STOP = JavaToolbar.STOP; - - static protected final int NEW = JavaToolbar.NEW; - static protected final int OPEN = JavaToolbar.OPEN; - static protected final int SAVE = JavaToolbar.SAVE; - static protected final int EXPORT = JavaToolbar.EXPORT; - - - // the sequence of button ids. (this maps button position = index to button ids) - static protected final int[] buttonSequence = { - DEBUG, CONTINUE, STEP, STOP, TOGGLE_BREAKPOINT, TOGGLE_VAR_INSPECTOR, - NEW, OPEN, SAVE, EXPORT - }; - - - public DebugToolbar(Editor editor, Base base) { - super(editor, base); - } - - - /** - * Initialize buttons. Loads images and adds the buttons to the toolbar. - */ - @Override - public void init() { - Image[][] images = loadImages(); - for (int idx = 0; idx < buttonSequence.length; idx++) { - int id = buttonId(idx); - addButton(getTitle(id, false), getTitle(id, true), images[idx], id == NEW || id == TOGGLE_BREAKPOINT); - } - } - - - /** - * Get the title for a toolbar button. Displayed in the toolbar when - * hovering over a button. - * @param id id of the toolbar button - * @param shift true if shift is pressed - * @return the title - */ - public static String getTitle(int id, boolean shift) { - switch (id) { - case DebugToolbar.RUN: - return JavaToolbar.getTitle(JavaToolbar.RUN, shift); - case STOP: - return JavaToolbar.getTitle(JavaToolbar.STOP, shift); - case NEW: - return JavaToolbar.getTitle(JavaToolbar.NEW, shift); - case OPEN: - return JavaToolbar.getTitle(JavaToolbar.OPEN, shift); - case SAVE: - return JavaToolbar.getTitle(JavaToolbar.SAVE, shift); - case EXPORT: - return JavaToolbar.getTitle(JavaToolbar.EXPORT, shift); - case DEBUG: - if (shift) { - return "Run"; - } else { - return "Debug"; - } - case CONTINUE: - return "Continue"; - case TOGGLE_BREAKPOINT: - return "Toggle Breakpoint"; - case STEP: - if (shift) { - return "Step Into"; - } else { - return "Step"; - } - case TOGGLE_VAR_INSPECTOR: - return "Variable Inspector"; - } - return null; - } - - - /** - * Event handler called when a toolbar button is clicked. - * @param e the mouse event - * @param idx index (i.e. position) of the toolbar button clicked - */ - @Override - public void handlePressed(MouseEvent e, int idx) { - boolean shift = e.isShiftDown(); - DebugEditor deditor = (DebugEditor) editor; - int id = buttonId(idx); // convert index/position to button id - - switch (id) { -// case DebugToolbar.RUN: -// super.handlePressed(e, JavaToolbar.RUN); -// break; - case STOP: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Stop' toolbar button"); - super.handlePressed(e, JavaToolbar.STOP); - break; - case NEW: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'New' toolbar button"); - super.handlePressed(e, JavaToolbar.NEW); - break; - case OPEN: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Open' toolbar button"); - super.handlePressed(e, JavaToolbar.OPEN); - break; - case SAVE: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Save' toolbar button"); - super.handlePressed(e, JavaToolbar.SAVE); - break; - case EXPORT: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Export' toolbar button"); - super.handlePressed(e, JavaToolbar.EXPORT); - break; - case DEBUG: - deditor.handleStop(); // Close any running sketches - if (shift) { - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button"); - deditor.handleRun(); - } else { - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Debug' toolbar button"); - deditor.dbg.startDebug(); - } - break; - case CONTINUE: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Continue' toolbar button"); - deditor.dbg.continueDebug(); - break; - case TOGGLE_BREAKPOINT: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' toolbar button"); - deditor.dbg.toggleBreakpoint(); - break; - case STEP: - if (shift) { - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step Into' toolbar button"); - deditor.dbg.stepInto(); - } else { - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step' toolbar button"); - deditor.dbg.stepOver(); - } - break; -// case STEP_INTO: -// deditor.dbg.stepInto(); -// break; -// case STEP_OUT: -// deditor.dbg.stepOut(); -// break; - case TOGGLE_VAR_INSPECTOR: - Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Variable Inspector' toolbar button"); - deditor.toggleVariableInspector(); - break; - } - } - - - /** - * Activate (light up) a button. - * @param id the button id - */ - @Override - public void activate(int id) { - //System.out.println("activate button idx: " + buttonIndex(id)); - super.activate(buttonIndex(id)); - } - - - /** - * Set a button to be inactive. - * @param id the button id - */ - @Override - public void deactivate(int id) { - //System.out.println("deactivate button idx: " + buttonIndex(id)); - super.deactivate(buttonIndex(id)); - } - - - /** - * Get button position (index) from it's id. - * @param buttonId the button id - * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...) - * @return the button index - */ - protected int buttonIndex(int buttonId) { - for (int i = 0; i < buttonSequence.length; i++) { - if (buttonSequence[i] == buttonId) { - return i; - } - } - return -1; - } - - - /** - * Get the button id from its position (index). - * @param buttonIdx the button index - * @return the button id - * ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...) - */ - protected int buttonId(int buttonIdx) { - return buttonSequence[buttonIdx]; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/Debugger.java b/pdex/experimental/src/processing/mode/experimental/Debugger.java deleted file mode 100755 index 758f6cfae..000000000 --- a/pdex/experimental/src/processing/mode/experimental/Debugger.java +++ /dev/null @@ -1,1364 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.*; -import com.sun.jdi.event.*; -import com.sun.jdi.request.*; -import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.JTree; // needed for javadocs -import javax.swing.tree.DefaultMutableTreeNode; -import processing.app.Sketch; -import processing.app.SketchCode; - -/** - * Main controller class for debugging mode. Mainly works with DebugEditor as - * the corresponding "view". Uses DebugRunner to launch a VM. - * - * @author Martin Leopold - */ -public class Debugger implements VMEventListener { - - protected DebugEditor editor; // editor window, acting as main view - protected DebugRunner runtime; // the runtime, contains debuggee VM - protected boolean started = false; // debuggee vm has started, VMStartEvent received, main class loaded - protected boolean paused = false; // currently paused at breakpoint or step - protected ThreadReference currentThread; // thread the last breakpoint or step occured in - protected String mainClassName; // name of the main class that's currently being debugged - protected ReferenceType mainClass; // the debuggee's main class - protected Set classes = new HashSet(); // holds all loaded classes in the debuggee VM - protected List classLoadListeners = new ArrayList(); // listeners for class load events - protected String srcPath; // path to the src folder of the current build - protected List breakpoints = new ArrayList(); // list of current breakpoints - protected StepRequest requestedStep; // the step request we are currently in, or null if not in a step - protected Map runtimeLineChanges = new HashMap(); // maps line number changes at runtime (orig -> changed) - protected Set runtimeTabsTracked = new HashSet(); // contains tab filenames which already have been tracked for runtime changes - - /** - * Construct a Debugger object. - * - * @param editor The Editor that will act as primary view - */ - public Debugger(DebugEditor editor) { - this.editor = editor; - } - - /** - * Access the VM. - * - * @return the virtual machine object or null if not available. - */ - public VirtualMachine vm() { - if (runtime != null) { - return runtime.vm(); - } else { - return null; - } - } - - /** - * Access the editor associated with this debugger. - * - * @return the editor object - */ - public DebugEditor editor() { - return editor; - } - - /** - * Retrieve the main class of the debuggee VM. - * - * @return the main classes {@link ReferenceType} or null if the debugger is - * not started. - */ - public ReferenceType getMainClass() { - if (isStarted()) { - return mainClass; - } else { - return null; - } - - } - - /** - * Get the {@link ReferenceType} for a class name. - * - * @param name the class name - * @return the {@link ReferenceType} or null if not found (e.g. not yet - * loaded) - */ - public ReferenceType getClass(String name) { - if (name == null) { - return null; - } - if (name.equals(mainClassName)) { - return mainClass; - } - for (ReferenceType rt : classes) { - if (rt.name().equals(name)) { - return rt; - } - } - return null; - } - - /** - * Add a class load listener. Will be notified when a class is loaded in the - * debuggee VM. - * - * @param listener the {@link ClassLoadListener} - */ - public void addClassLoadListener(ClassLoadListener listener) { - classLoadListeners.add(listener); - } - - /** - * Remove a class load listener. Cease to be notified when classes are - * loaded in the debuggee VM. - * - * @param listener {@link ClassLoadListener} - */ - public void removeClassLoadListener(ClassLoadListener listener) { - classLoadListeners.remove(listener); - } - - /** - * Start a debugging session. Builds the sketch and launches a VM to run it. - * VM starts suspended. Should produce a VMStartEvent. - */ - public synchronized void startDebug() { - //stopDebug(); // stop any running sessions - if (isStarted()) { - return; // do nothing - } - - // we are busy now - editor.statusBusy(); - - // clear console - editor.clearConsole(); - - // clear variable inspector (also resets expanded states) - editor.variableInspector().reset(); - - // load edits into sketch obj, etc... - editor.prepareRun(); - - editor.toolbar().activate(DebugToolbar.DEBUG); // after prepareRun, since this removes highlights - - try { - Sketch sketch = editor.getSketch(); - DebugBuild build = new DebugBuild(sketch); - - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "building sketch: {0}", sketch.getName()); - //LineMapping.addLineNumbers(sketch); // annotate - mainClassName = build.build(false); - //LineMapping.removeLineNumbers(sketch); // annotate - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class: {0}", mainClassName); - - // folder with assembled/preprocessed src - srcPath = build.getSrcFolder().getPath(); - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build src: {0}", srcPath); - // folder with compiled code (.class files) - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "build bin: {0}", build.getBinFolder().getPath()); - - if (mainClassName != null) { - // generate the source line mapping - //lineMap = LineMapping.generateMapping(srcPath + File.separator + mainClassName + ".java"); - - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "launching debuggee runtime"); - runtime = new DebugRunner(build, editor); - VirtualMachine vm = runtime.launch(); // non-blocking - if (vm == null) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "error 37: launch failed"); - } - - // start receiving vm events - VMEventReader eventThread = new VMEventReader(vm.eventQueue(), this); - eventThread.start(); - - //return runtime; - - /* - * // launch runner in new thread new Thread(new Runnable() { - * - * @Override public void run() { runtime.launch(false); // this - * blocks until finished } }).start(); return runtime; - */ - - startTrackingLineChanges(); - editor.statusBusy(); - } - } catch (Exception e) { - editor.statusError(e); - } - } - - /** - * End debugging session. Stops and disconnects VM. Should produce - * VMDisconnectEvent. - */ - public synchronized void stopDebug() { - editor.variableInspector().lock(); - if (runtime != null) { - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "closing runtime"); - runtime.close(); - runtime = null; - //build = null; - classes.clear(); - // need to clear highlight here because, VMDisconnectedEvent seems to be unreliable. TODO: likely synchronization problem - editor.clearCurrentLine(); - } - stopTrackingLineChanges(); - started = false; - editor.toolbar().deactivate(DebugToolbar.DEBUG); - editor.toolbar().deactivate(DebugToolbar.CONTINUE); - editor.toolbar().deactivate(DebugToolbar.STEP); - editor.statusEmpty(); - } - - /** - * Resume paused debugging session. Resumes VM. - */ - public synchronized void continueDebug() { - editor.toolbar().activate(DebugToolbar.CONTINUE); - editor.variableInspector().lock(); - //editor.clearSelection(); - //clearHighlight(); - editor.clearCurrentLine(); - if (!isStarted()) { - startDebug(); - } else if (isPaused()) { - runtime.vm().resume(); - paused = false; - editor.statusBusy(); - } - } - - /** - * Step through source code lines. - * - * @param stepDepth the step depth ({@link StepRequest#STEP_OVER}, - * {@link StepRequest#STEP_INTO} or {@link StepRequest#STEP_OUT}) - */ - protected void step(int stepDepth) { - if (!isStarted()) { - startDebug(); - } else if (isPaused()) { - editor.variableInspector().lock(); - editor.toolbar().activate(DebugToolbar.STEP); - - // use global to mark that there is a step request pending - requestedStep = runtime.vm().eventRequestManager().createStepRequest(currentThread, StepRequest.STEP_LINE, stepDepth); - requestedStep.addCountFilter(1); // valid for one step only - requestedStep.enable(); - paused = false; - runtime.vm().resume(); - editor.statusBusy(); - } - } - - /** - * Step over current statement. - */ - public synchronized void stepOver() { - step(StepRequest.STEP_OVER); - } - - /** - * Step into current statement. - */ - public synchronized void stepInto() { - step(StepRequest.STEP_INTO); - } - - /** - * Step out of current function. - */ - public synchronized void stepOut() { - step(StepRequest.STEP_OUT); - } - - /** - * Print the current stack trace. - */ - public synchronized void printStackTrace() { - if (isStarted()) { - printStackTrace(currentThread); - } - } - - /** - * Print local variables. Outputs type, name and value of each variable. - */ - public synchronized void printLocals() { - if (isStarted()) { - printLocalVariables(currentThread); - } - } - - /** - * Print fields of current {@code this}-object. Outputs type, name and value - * of each field. - */ - public synchronized void printThis() { - if (isStarted()) { - printThis(currentThread); - } - } - - /** - * Print a source code snippet of the current location. - */ - public synchronized void printSource() { - if (isStarted()) { - printSourceLocation(currentThread); - } - } - - /** - * Set a breakpoint on the current line. - */ - public synchronized void setBreakpoint() { - setBreakpoint(editor.getCurrentLineID()); - } - - /** - * Set a breakpoint on a line in the current tab. - * - * @param lineIdx the line index (0-based) of the current tab to set the - * breakpoint on - */ - public synchronized void setBreakpoint(int lineIdx) { - setBreakpoint(editor.getLineIDInCurrentTab(lineIdx)); - } - - /** - * Set a breakpoint. - * - * @param line the line id to set the breakpoint on - */ - public synchronized void setBreakpoint(LineID line) { - // do nothing if we are kinda busy - if (isStarted() && !isPaused()) { - return; - } - // do nothing if there already is a breakpoint on this line - if (hasBreakpoint(line)) { - return; - } - breakpoints.add(new LineBreakpoint(line, this)); - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "set breakpoint on line {0}", line); - } - - /** - * Remove a breakpoint from the current line (if set). - */ - public synchronized void removeBreakpoint() { - removeBreakpoint(editor.getCurrentLineID().lineIdx()); - } - - /** - * Remove a breakpoint from a line in the current tab. - * - * @param lineIdx the line index (0-based) in the current tab to remove the - * breakpoint from - */ - protected void removeBreakpoint(int lineIdx) { - // do nothing if we are kinda busy - if (isBusy()) { - return; - } - - LineBreakpoint bp = breakpointOnLine(editor.getLineIDInCurrentTab(lineIdx)); - if (bp != null) { - bp.remove(); - breakpoints.remove(bp); - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "removed breakpoint {0}", bp); - } - } - - /** - * Remove all breakpoints. - */ - public synchronized void clearBreakpoints() { - //TODO: handle busy-ness correctly - if (isBusy()) { - Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy"); - return; - } - - for (LineBreakpoint bp : breakpoints) { - bp.remove(); - } - breakpoints.clear(); - } - - /** - * Clear breakpoints in a specific tab. - * - * @param tabFilename the tab's file name - */ - public synchronized void clearBreakpoints(String tabFilename) { - //TODO: handle busy-ness correctly - if (isBusy()) { - Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "busy"); - return; - } - - Iterator i = breakpoints.iterator(); - while (i.hasNext()) { - LineBreakpoint bp = i.next(); - if (bp.lineID().fileName().equals(tabFilename)) { - bp.remove(); - i.remove(); - } - } - } - - /** - * Get the breakpoint on a certain line, if set. - * - * @param line the line to get the breakpoint from - * @return the breakpoint, or null if no breakpoint is set on the specified - * line. - */ - protected LineBreakpoint breakpointOnLine(LineID line) { - for (LineBreakpoint bp : breakpoints) { - if (bp.isOnLine(line)) { - return bp; - } - } - return null; - } - - /** - * Toggle a breakpoint on the current line. - */ - public synchronized void toggleBreakpoint() { - toggleBreakpoint(editor.getCurrentLineID().lineIdx()); - } - - /** - * Toggle a breakpoint on a line in the current tab. - * - * @param lineIdx the line index (0-based) in the current tab - */ - public synchronized void toggleBreakpoint(int lineIdx) { - LineID line = editor.getLineIDInCurrentTab(lineIdx); - if (!hasBreakpoint(line)) { - setBreakpoint(line.lineIdx()); - } else { - removeBreakpoint(line.lineIdx()); - } - } - - /** - * Check if there's a breakpoint on a particular line. - * - * @param line the line id - * @return true if a breakpoint is set on the given line, otherwise false - */ - protected boolean hasBreakpoint(LineID line) { - LineBreakpoint bp = breakpointOnLine(line); - return bp != null; - } - - /** - * Print a list of currently set breakpoints. - */ - public synchronized void listBreakpoints() { - if (breakpoints.isEmpty()) { - System.out.println("no breakpoints"); - } else { - System.out.println("line breakpoints:"); - for (LineBreakpoint bp : breakpoints) { - System.out.println(bp); - } - } - } - - /** - * Retrieve a list of breakpoint in a particular tab. - * - * @param tabFilename the tab's file name - * @return the list of breakpoints in the given tab - */ - public synchronized List getBreakpoints(String tabFilename) { - List list = new ArrayList(); - for (LineBreakpoint bp : breakpoints) { - if (bp.lineID().fileName().equals(tabFilename)) { - list.add(bp); - } - } - return list; - } - - /** - * Callback for VM events. Will be called from another thread. - * ({@link VMEventReader}) - * - * @param es Incoming set of events from VM - */ - @Override - public synchronized void vmEvent(EventSet es) { - for (Event e : es) { - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "*** VM Event: {0}", e.toString()); - if (e instanceof VMStartEvent) { - //initialThread = ((VMStartEvent) e).thread(); -// ThreadReference t = ((VMStartEvent) e).thread(); - //printStackTrace(t); - - // break on main class load - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on main class load: {0}", mainClassName); - ClassPrepareRequest mainClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); - mainClassPrepare.addClassFilter(mainClassName); - mainClassPrepare.enable(); - - // break on loading custom classes - for (SketchCode tab : editor.getSketch().getCode()) { - if (tab.isExtension("java")) { - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "requesting event on class load: {0}", tab.getPrettyName()); - ClassPrepareRequest customClassPrepare = runtime.vm().eventRequestManager().createClassPrepareRequest(); - customClassPrepare.addClassFilter(tab.getPrettyName()); - customClassPrepare.enable(); - } - } - - runtime.vm().resume(); - } else if (e instanceof ClassPrepareEvent) { - ClassPrepareEvent ce = (ClassPrepareEvent) e; - ReferenceType rt = ce.referenceType(); - currentThread = ce.thread(); - paused = true; // for now we're paused - - if (rt.name().equals(mainClassName)) { - //printType(rt); - mainClass = rt; - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "main class load: {0}", rt.name()); - started = true; // now that main class is loaded, we're started - } else { - classes.add(rt); // save loaded classes - Logger.getLogger(Debugger.class.getName()).log(Level.INFO, "class load: {0}", rt.name()); - } - - // notify listeners - for (ClassLoadListener listener : classLoadListeners) { - if (listener != null) { - listener.classLoaded(rt); - } - } - - paused = false; // resuming now - runtime.vm().resume(); - } else if (e instanceof BreakpointEvent) { - BreakpointEvent be = (BreakpointEvent) e; - currentThread = be.thread(); // save this thread -// BreakpointRequest br = (BreakpointRequest) be.request(); - - //printSourceLocation(currentThread); - updateVariableInspector(currentThread); // this is already on the EDT - final LineID newCurrentLine = locationToLineID(be.location()); - javax.swing.SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - editor.setCurrentLine(newCurrentLine); - editor.toolbar().deactivate(DebugToolbar.STEP); - editor.toolbar().deactivate(DebugToolbar.CONTINUE); - } - }); - - // hit a breakpoint during a step, need to cancel the step. - if (requestedStep != null) { - runtime.vm().eventRequestManager().deleteEventRequest(requestedStep); - requestedStep = null; - } - - // fix canvas update issue - // TODO: is this a good solution? - resumeOtherThreads(currentThread); - - paused = true; - editor.statusHalted(); - } else if (e instanceof StepEvent) { - StepEvent se = (StepEvent) e; - currentThread = se.thread(); - - //printSourceLocation(currentThread); - updateVariableInspector(currentThread); // this is already on the EDT - final LineID newCurrentLine = locationToLineID(se.location()); - javax.swing.SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - editor.setCurrentLine(newCurrentLine); - editor.toolbar().deactivate(DebugToolbar.STEP); - editor.toolbar().deactivate(DebugToolbar.CONTINUE); - } - }); - - // delete the steprequest that triggered this step so new ones can be placed (only one per thread) - EventRequestManager mgr = runtime.vm().eventRequestManager(); - mgr.deleteEventRequest(se.request()); - requestedStep = null; // mark that there is no step request pending - paused = true; - editor.statusHalted(); - - // disallow stepping into invisible lines - if (!locationIsVisible(se.location())) { - stepOutIntoViewOrContinue(); // TODO: this leads to stepping, should it run on the EDT? - } - } else if (e instanceof VMDisconnectEvent) { -// started = false; -// // clear line highlight -// editor.clearCurrentLine(); - stopDebug(); - } else if (e instanceof VMDeathEvent) { - started = false; - editor.statusEmpty(); - } - } - } - - /** - * Check whether a location corresponds to a code line in the editor. - * - * @param l the location - * @return true if the location corresponds to a line in the editor - */ - protected boolean locationIsVisible(Location l) { - return locationToLineID(l) != null; - } - - /** - * Step out if this results in a visible location, otherwise continue. - */ - protected void stepOutIntoViewOrContinue() { - try { - List frames = currentThread.frames(); - if (frames.size() > 1) { - if (locationIsVisible(frames.get(1).location())) { - //System.out.println("stepping out to: " + locationToString(frames.get(1).location())); - stepOut(); - return; - } - } - continueDebug(); - -// //Step out to the next visible location on the stack frame -// if (thread.frames(i, i1)) -// for (StackFrame f : thread.frames()) { -// Location l = f.location(); -// if (locationIsVisible(l)) { -// System.out.println("need to step out to: " + locationToString(l)); -// } -// } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Check whether a debugging session is running. i.e. the debugger is - * connected to a debuggee VM, VMStartEvent has been received and main class - * is loaded. - * - * @return true if the debugger is started. - */ - public synchronized boolean isStarted() { - return started && runtime != null && runtime.vm() != null; - } - - /** - * Check whether the debugger is paused. i.e. it is currently suspended at a - * breakpoint or step. - * - * @return true if the debugger is paused, false otherwise or if not started - * ({@link #isStarted()}) - */ - public synchronized boolean isPaused() { - return isStarted() && paused && currentThread != null && currentThread.isSuspended(); - } - - /** - * Check whether the debugger is currently busy. i.e. running (not - * suspended). - * - * @return true if the debugger is currently running and not suspended. - */ - public synchronized boolean isBusy() { - return isStarted() && !isPaused(); - } - - /** - * Print call stack trace of a thread. Only works on suspended threads. - * - * @param t suspended thread to print stack trace of - */ - protected void printStackTrace(ThreadReference t) { - if (!t.isSuspended()) { - return; - } - try { - System.out.println("stack trace for thread " + t.name() + ":"); - int i = 0; - for (StackFrame f : t.frames()) { -// Location l = f.location(); - System.out.println(i++ + ": " + f.toString()); - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Resume all other threads except the one given as parameter. Useful e.g. - * to just keep the thread suspended a breakpoint occurred in. - * - * @param t the thread not to resume - */ - protected void resumeOtherThreads(ThreadReference t) { - if (!isStarted()) { - return; - } - for (ThreadReference other : vm().allThreads()) { - if (!other.equals(t) && other.isSuspended()) { - other.resume(); - } - } - } - - /** - * Print info about all current threads. Includes name, status, isSuspended, - * isAtBreakpoint. - */ - public synchronized void printThreads() { - if (!isPaused()) { - return; - } - System.out.println("threads:"); - for (ThreadReference t : vm().allThreads()) { - printThread(t); - } - } - - /** - * Print info about a thread. Includes name, status, isSuspended, - * isAtBreakpoint. - * - * @param t the thread to print info about - */ - protected void printThread(ThreadReference t) { - System.out.println(t.name()); - System.out.println(" is suspended: " + t.isSuspended()); - System.out.println(" is at breakpoint: " + t.isAtBreakpoint()); - System.out.println(" status: " + threadStatusToString(t.status())); - } - - /** - * Convert a status code returned by {@link ThreadReference#status() } to a - * human readable form. - * - * @param status {@link ThreadReference#THREAD_STATUS_MONITOR}, - * {@link ThreadReference#THREAD_STATUS_NOT_STARTED}, - * {@link ThreadReference#THREAD_STATUS_RUNNING}, - * {@link ThreadReference#THREAD_STATUS_SLEEPING}, - * {@link ThreadReference#THREAD_STATUS_UNKNOWN}, - * {@link ThreadReference#THREAD_STATUS_WAIT} or - * {@link ThreadReference#THREAD_STATUS_ZOMBIE} - * @return String containing readable status code. - */ - protected String threadStatusToString(int status) { - switch (status) { - case ThreadReference.THREAD_STATUS_MONITOR: - return "THREAD_STATUS_MONITOR"; - case ThreadReference.THREAD_STATUS_NOT_STARTED: - return "THREAD_STATUS_NOT_STARTED"; - case ThreadReference.THREAD_STATUS_RUNNING: - return "THREAD_STATUS_RUNNING"; - case ThreadReference.THREAD_STATUS_SLEEPING: - return "THREAD_STATUS_SLEEPING"; - case ThreadReference.THREAD_STATUS_UNKNOWN: - return "THREAD_STATUS_UNKNOWN"; - case ThreadReference.THREAD_STATUS_WAIT: - return "THREAD_STATUS_WAIT"; - case ThreadReference.THREAD_STATUS_ZOMBIE: - return "THREAD_STATUS_ZOMBIE"; - default: - return ""; - } - } - - /** - * Print local variables on a suspended thread. Takes the topmost stack - * frame and lists all local variables and their values. - * - * @param t suspended thread - */ - protected void printLocalVariables(ThreadReference t) { - if (!t.isSuspended()) { - return; - } - try { - if (t.frameCount() == 0) { - System.out.println("call stack empty"); - } else { - StackFrame sf = t.frame(0); - List locals = sf.visibleVariables(); - if (locals.isEmpty()) { - System.out.println("no local variables"); - return; - } - for (LocalVariable lv : locals) { - System.out.println(lv.typeName() + " " + lv.name() + " = " + sf.getValue(lv)); - } - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } catch (AbsentInformationException ex) { - System.out.println("local variable information not available"); - } - } - - /** - * Update variable inspector window. Displays local variables and this - * fields. - * - * @param t suspended thread to retrieve locals and this - */ - protected void updateVariableInspector(ThreadReference t) { - if (!t.isSuspended()) { - return; - } - try { - if (t.frameCount() == 0) { - // TODO: needs to be handled in a better way: - Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "call stack empty"); - } else { - final VariableInspector vi = editor.variableInspector(); - // first get data - final List stackTrace = getStackTrace(t); - final List locals = getLocals(t, 0); - final String currentLocation = currentLocation(t); - final List thisFields = getThisFields(t, 0, true); - final List declaredThisFields = getThisFields(t, 0, false); - final String thisName = thisName(t); - // now update asynchronously - javax.swing.SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - //System.out.println("updating vi. from EDT: " + javax.swing.SwingUtilities.isEventDispatchThread()); - vi.updateCallStack(stackTrace, "Call Stack"); - vi.updateLocals(locals, "Locals at " + currentLocation); - vi.updateThisFields(thisFields, "Class " + thisName); - vi.updateDeclaredThisFields(declaredThisFields, "Class " + thisName); - vi.unlock(); // need to do this before rebuilding, otherwise we get these ... dots in the labels - vi.rebuild(); - } - }); - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Get the class name of the current this object in a suspended thread. - * - * @param t a suspended thread - * @return the class name of this - */ - protected String thisName(ThreadReference t) { - try { - if (!t.isSuspended() || t.frameCount() == 0) { - return ""; - } - return t.frame(0).thisObject().referenceType().name(); - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - return ""; - } - } - - /** - * Get a description of the current location in a suspended thread. Format: - * class.method:translated_line_number - * - * @param t a suspended thread - * @return descriptive string for the given location - */ - protected String currentLocation(ThreadReference t) { - try { - if (!t.isSuspended() || t.frameCount() == 0) { - return ""; - } - return locationToString(t.frame(0).location()); - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - return ""; - } - } - - /** - * Get a string describing a location. Format: - * class.method:translated_line_number - * - * @param l a location - * @return descriptive string for the given location - */ - protected String locationToString(Location l) { - LineID line = locationToLineID(l); - int lineNumber; - if (line != null) { - lineNumber = line.lineIdx() + 1; - } else { - lineNumber = l.lineNumber(); - } - return l.declaringType().name() + "." + l.method().name() + ":" + lineNumber; - } - - /** - * Compile a list of current locals usable for insertion into a - * {@link JTree}. Recursively resolves object references. - * - * @param t the suspended thread to get locals for - * @param depth how deep to resolve nested object references. 0 will not - * resolve nested objects. - * @return the list of current locals - */ - protected List getLocals(ThreadReference t, int depth) { - //System.out.println("getting locals"); - List vars = new ArrayList(); - try { - if (t.frameCount() > 0) { - StackFrame sf = t.frame(0); - for (LocalVariable lv : sf.visibleVariables()) { - //System.out.println("local var: " + lv.name()); - Value val = sf.getValue(lv); - VariableNode var = new LocalVariableNode(lv.name(), lv.typeName(), val, lv, sf); - if (depth > 0) { - var.addChildren(getFields(val, depth - 1, true)); - } - vars.add(var); - } - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } catch (AbsentInformationException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.WARNING, "local variable information not available", ex); - } - return vars; - } - - /** - * Compile a list of fields in the current this object usable for insertion - * into a {@link JTree}. Recursively resolves object references. - * - * @param t the suspended thread to get locals for - * @param depth how deep to resolve nested object references. 0 will not - * resolve nested objects. - * @return the list of fields in the current this object - */ - protected List getThisFields(ThreadReference t, int depth, boolean includeInherited) { - //System.out.println("getting this"); - try { - if (t.frameCount() > 0) { - StackFrame sf = t.frame(0); - ObjectReference thisObj = sf.thisObject(); - return getFields(thisObj, depth, includeInherited); - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - return new ArrayList(); - } - - /** - * Recursively get the fields of a {@link Value} for insertion into a - * {@link JTree}. - * - * @param value must be an instance of {@link ObjectReference} - * @param depth the current depth - * @param maxDepth the depth to stop at (inclusive) - * @return list of child fields of the given value - */ - protected List getFields(Value value, int depth, int maxDepth, boolean includeInherited) { - // remember: Value <- ObjectReference, ArrayReference - List vars = new ArrayList(); - if (depth <= maxDepth) { - if (value instanceof ArrayReference) { - return getArrayFields((ArrayReference) value); - } else if (value instanceof ObjectReference) { - ObjectReference obj = (ObjectReference) value; - // get the fields of this object - List fields = includeInherited ? obj.referenceType().visibleFields() : obj.referenceType().fields(); - for (Field field : fields) { - Value val = obj.getValue(field); // get the value, may be null - VariableNode var = new FieldNode(field.name(), field.typeName(), val, field, obj); - // recursively add children - if (val != null) { - var.addChildren(getFields(val, depth + 1, maxDepth, includeInherited)); - } - vars.add(var); - } - } - } - return vars; - } - - /** - * Recursively get the fields of a {@link Value} for insertion into a - * {@link JTree}. - * - * @param value must be an instance of {@link ObjectReference} - * @param maxDepth max recursion depth. 0 will give only direct children - * @return list of child fields of the given value - */ - protected List getFields(Value value, int maxDepth, boolean includeInherited) { - return getFields(value, 0, maxDepth, includeInherited); - } - - /** - * Get the fields of an array for insertion into a {@link JTree}. - * - * @param array the array reference - * @return list of array fields - */ - protected List getArrayFields(ArrayReference array) { - List fields = new ArrayList(); - if (array != null) { - String arrayType = array.type().name(); - if (arrayType.endsWith("[]")) { - arrayType = arrayType.substring(0, arrayType.length() - 2); - } - int i = 0; - for (Value val : array.getValues()) { - VariableNode var = new ArrayFieldNode("[" + i + "]", arrayType, val, array, i); - fields.add(var); - i++; - } - } - return fields; - } - - /** - * Get the current call stack trace usable for insertion into a - * {@link JTree}. - * - * @param t the suspended thread to retrieve the call stack from - * @return call stack as list of {@link DefaultMutableTreeNode}s - */ - protected List getStackTrace(ThreadReference t) { - List stack = new ArrayList(); - try { -// int i = 0; - for (StackFrame f : t.frames()) { - stack.add(new DefaultMutableTreeNode(locationToString(f.location()))); - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - return stack; - } - - /** - * Print visible fields of current "this" object on a suspended thread. - * Prints type, name and value. - * - * @param t suspended thread - */ - protected void printThis(ThreadReference t) { - if (!t.isSuspended()) { - return; - } - try { - if (t.frameCount() == 0) { - // TODO: needs to be handled in a better way - System.out.println("call stack empty"); - } else { - StackFrame sf = t.frame(0); - ObjectReference thisObject = sf.thisObject(); - if (this != null) { - ReferenceType type = thisObject.referenceType(); - System.out.println("fields in this (" + type.name() + "):"); - for (Field f : type.visibleFields()) { - System.out.println(f.typeName() + " " + f.name() + " = " + thisObject.getValue(f)); - } - } else { - System.out.println("can't get this (in native or static method)"); - } - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Print source code snippet of current location in a suspended thread. - * - * @param t suspended thread - */ - protected void printSourceLocation(ThreadReference t) { - try { - if (t.frameCount() == 0) { - // TODO: needs to be handled in a better way - System.out.println("call stack empty"); - } else { - Location l = t.frame(0).location(); // current stack frame location - printSourceLocation(l); - } - } catch (IncompatibleThreadStateException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Print source code snippet. - * - * @param l {@link Location} object to print source code for - */ - protected void printSourceLocation(Location l) { - try { - //System.out.println(l.sourceName() + ":" + l.lineNumber()); - System.out.println("in method " + l.method() + ":"); - System.out.println(getSourceLine(l.sourcePath(), l.lineNumber(), 2)); - - } catch (AbsentInformationException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Read a line from the given file in the builds src folder. 1-based i.e. - * first line has line no. 1 - * - * @param filePath - * @param lineNo - * @return the requested source line - */ - protected String getSourceLine(String filePath, int lineNo, int radius) { - if (lineNo == -1) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, "invalid line number: {0}", lineNo); - return ""; - } - //System.out.println("getting line: " + lineNo); - File f = new File(srcPath + File.separator + filePath); - String output = ""; - try { - BufferedReader r = new BufferedReader(new FileReader(f)); - int i = 1; - //String line = ""; - while (i <= lineNo + radius) { - String line = r.readLine(); // line no. i - if (line == null) { - break; // end of file - } - if (i >= lineNo - radius) { - if (i > lineNo - radius) { - output += "\n"; // add newlines before all lines but the first - } - output += f.getName() + ":" + i + (i == lineNo ? " => " : " ") + line; - } - i++; - } - r.close(); - return output; - } catch (FileNotFoundException ex) { - //System.err.println(ex); - return f.getName() + ":" + lineNo; - } catch (IOException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - return ""; - } - } - - /** - * Print info about a ReferenceType. Prints class name, source file name, - * lists methods. - * - * @param rt the reference type to print out - */ - protected void printType(ReferenceType rt) { - System.out.println("ref.type: " + rt); - System.out.println("name: " + rt.name()); - try { - System.out.println("sourceName: " + rt.sourceName()); - } catch (AbsentInformationException ex) { - System.out.println("sourceName: unknown"); - } - System.out.println("methods:"); - for (Method m : rt.methods()) { - System.out.println(m.toString()); - } - } - - /** - * Translate a java source location to a sketch line id. - * - * @param l the location to translate - * @return the corresponding line id, or null if not found - */ - protected LineID locationToLineID(Location l) { - try { - //return lineMap.get(LineID.create(l.sourceName(), l.lineNumber() - 1)); - return javaToSketchLine(new LineID(l.sourceName(), l.lineNumber() - 1)); - - } catch (AbsentInformationException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - return null; - } - } - - /** - * Translate a line (index) from java space to sketch space. - * - * @param javaLine the java line id - * @return the corresponding sketch line id or null if failed to translate - */ - public LineID javaToSketchLine(LineID javaLine) { - Sketch sketch = editor.getSketch(); - - // it may belong to a pure java file created in the sketch - // try to find an exact filename match and check the extension - SketchCode tab = editor.getTab(javaLine.fileName()); - if (tab != null && tab.isExtension("java")) { - // can translate 1:1 - return originalToRuntimeLine(javaLine); - } - - // check if it is the preprocessed/assembled file for this sketch - // java file name needs to match the sketches filename - if (!javaLine.fileName().equals(sketch.getName() + ".java")) { - return null; - } - - // find the tab (.pde file) this line belongs to - // get the last tab that has an offset not greater than the java line number - for (int i = sketch.getCodeCount() - 1; i >= 0; i--) { - tab = sketch.getCode(i); - // ignore .java files - // the tab's offset must not be greater than the java line number - if (tab.isExtension("pde") && tab.getPreprocOffset() <= javaLine.lineIdx()) { - return originalToRuntimeLine(new LineID(tab.getFileName(), javaLine.lineIdx() - tab.getPreprocOffset())); - } - } - - return null; - } - - /** - * Get the runtime-changed line id for an original sketch line. Used to - * translate line numbers from the VM (which runs on the original line - * numbers) to their current (possibly changed) counterparts. - * - * @param line the original line id (at compile time) - * @return the changed version or the line given as parameter if not found - */ - protected LineID originalToRuntimeLine(LineID line) { - LineID transformed = runtimeLineChanges.get(line); - if (transformed == null) { - return line; - } - return transformed; - } - - /** - * Get the original line id for a sketch line that was changed at runtime. - * Used to translate line numbers from the UI at runtime (which can differ - * from the ones the VM runs on) to their original counterparts. - * - * @param line the (possibly) changed runtime line - * @return the original line or the line given as parameter if not found - */ - protected LineID runtimeToOriginalLine(LineID line) { - for (Entry entry : runtimeLineChanges.entrySet()) { - if (entry.getValue().equals(line)) { - return entry.getKey(); - } - } - return line; - } - - /** - * Translate a line (index) from sketch space to java space. - * - * @param sketchLine the sketch line id - * @return the corresponding java line id or null if failed to translate - */ - public LineID sketchToJavaLine(LineID sketchLine) { - sketchLine = runtimeToOriginalLine(sketchLine); // transform back to orig (before changes at runtime) - - // check if there is a tab for this line - SketchCode tab = editor.getTab(sketchLine.fileName()); - if (tab == null) { - return null; - } - - // check if the tab is a pure java file anyway - if (tab.isExtension("java")) { - // 1:1 translation - return sketchLine; - } - - // the java file has a name sketchname.java - // just add the tab's offset to get the java name - LineID javaLine = new LineID(editor.getSketch().getName() + ".java", sketchLine.lineIdx() + tab.getPreprocOffset()); - return javaLine; - } - - /** - * Start tracking all line changes (due to edits) in the current tab. - */ - // TODO: maybe move this to the editor? - protected void startTrackingLineChanges() { - SketchCode tab = editor.getSketch().getCurrentCode(); - if (runtimeTabsTracked.contains(tab.getFileName())) { - return; - } - - for (int i = 0; i < tab.getLineCount(); i++) { - LineID old = new LineID(tab.getFileName(), i); - LineID tracked = new LineID(tab.getFileName(), i); - tracked.startTracking(editor.currentDocument()); - runtimeLineChanges.put(old, tracked); - } - runtimeTabsTracked.add(tab.getFileName()); - //System.out.println("tracking tab: " + tab.getFileName()); - } - - /** - * Stop tracking line changes in all tabs. - */ - protected void stopTrackingLineChanges() { - //System.out.println("stop tracking line changes"); - for (LineID tracked : runtimeLineChanges.values()) { - tracked.stopTracking(); - } - runtimeLineChanges.clear(); - runtimeTabsTracked.clear(); - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorBar.java b/pdex/experimental/src/processing/mode/experimental/ErrorBar.java deleted file mode 100755 index 24d552ae5..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ErrorBar.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package processing.mode.experimental; - -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionListener; -import java.util.ArrayList; - -import javax.swing.JPanel; -import javax.swing.SwingWorker; - -import processing.app.Base; -import processing.app.SketchCode; - -/** - * The bar on the left of the text area which displays all errors as rectangles.
    - *
    - * All errors and warnings of a sketch are drawn on the bar, clicking on one, - * scrolls to the tab and location. Error messages displayed on hover. Markers - * are not in sync with the error line. Similar to eclipse's right error bar - * which displays the overall errors in a document - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ -public class ErrorBar extends JPanel { - /** - * Preferred height of the component - */ - protected int preferredHeight; - - /** - * Preferred height of the component - */ - protected int preferredWidth = 12; - - /** - * Height of marker - */ - public static final int errorMarkerHeight = 4; - - /** - * Color of Error Marker - */ - public Color errorColor = new Color(0xED2630); - - /** - * Color of Warning Marker - */ - public Color warningColor = new Color(0xFFC30E); - - /** - * Background color of the component - */ - public Color backgroundColor = new Color(0x2C343D); - - /** - * DebugEditor instance - */ - protected DebugEditor editor; - - /** - * ErrorCheckerService instance - */ - protected ErrorCheckerService errorCheckerService; - - /** - * Stores error markers displayed PER TAB along the error bar. - */ - protected ArrayList errorPoints = new ArrayList(); - - /** - * Stores previous list of error markers. - */ - protected ArrayList errorPointsOld = new ArrayList(); - - public void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g.setColor(backgroundColor); - g.fillRect(0, 0, getWidth(), getHeight()); - - for (ErrorMarker emarker : errorPoints) { - if (emarker.type == ErrorMarker.Error) { - g.setColor(errorColor); - } else { - g.setColor(warningColor); - } - g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight); - } - } - - public Dimension getPreferredSize() { - return new Dimension(preferredWidth, preferredHeight); - } - - public Dimension getMinimumSize() { - return getPreferredSize(); - } - - public ErrorBar(DebugEditor editor, int height, ExperimentalMode mode) { - this.editor = editor; - this.preferredHeight = height; - this.errorCheckerService = editor.errorCheckerService; - errorColor = mode.getThemeColor("errorbar.errorcolor", errorColor); - warningColor = mode - .getThemeColor("errorbar.warningcolor", warningColor); - backgroundColor = mode.getThemeColor("errorbar.backgroundcolor", - backgroundColor); - addListeners(); - } - - /** - * Update error markers in the error bar. - * - * @param problems - * - List of problems. - */ - synchronized public void updateErrorPoints(final ArrayList problems) { - - // NOTE TO SELF: ErrorMarkers are calculated for the present tab only - // Error Marker index in the arraylist is LOCALIZED for current tab. - // Also, need to do the update in the UI thread to prevent concurrency issues. - final int fheight = this.getHeight(); - SwingWorker worker = new SwingWorker() { - - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - int totalLines = 0; - int currentTab = 0; - for (SketchCode sc : editor.getSketch().getCode()) { - if (sc.isExtension("pde")) { - try { - if (editor.getSketch().getCurrentCode().equals(sc)) { - // Adding + 1 to len because \n gets appended - // for each - // sketchcode extracted during processPDECode() - totalLines = Base.countLines(sc.getDocument() - .getText(0, - sc.getDocument().getLength())) + 1; - break; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - currentTab++; - } - // System.out.println("Total lines: " + totalLines); - - errorPointsOld.clear(); - for (ErrorMarker marker : errorPoints) { - errorPointsOld.add(marker); - } - errorPoints.clear(); - - // Each problem.getSourceLine() will have an extra line added - // because of - // class declaration in the beginning as well as default imports - for (Problem problem : problems) { - if (problem.tabIndex == currentTab) { - // Ratio of error line to total lines - float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset) - / ((float) totalLines); - // Ratio multiplied by height of the error bar - y *= fheight - 15; // -15 is just a vertical offset - errorPoints.add(new ErrorMarker(problem, (int) y, - problem.isError() ? ErrorMarker.Error - : ErrorMarker.Warning)); - // System.out.println("Y: " + y); - } - } - - repaint(); - } - }; - - try { - worker.execute(); // I eat concurrency bugs for breakfast. - } catch (Exception exp) { - System.out.println("Errorbar update markers is slacking." - + exp.getMessage()); - // e.printStackTrace(); - } - } - - /** - * Check if new errors have popped up in the sketch since the last check - * - * @return true - if errors have changed - */ - public boolean errorPointsChanged() { - if (errorPointsOld.size() != errorPoints.size()) { - editor.getTextArea().repaint(); - // System.out.println("2 Repaint " + System.currentTimeMillis()); - return true; - } - - else { - for (int i = 0; i < errorPoints.size(); i++) { - if (errorPoints.get(i).y != errorPointsOld.get(i).y) { - editor.getTextArea().repaint(); - // System.out.println("3 Repaint " + - // System.currentTimeMillis()); - return true; - } - } - } - return false; - } - - /** - * Add various mouse listeners. - */ - protected void addListeners() { - - this.addMouseListener(new MouseAdapter() { - - // Find out which error/warning the user has clicked - // and then scroll to that - @SuppressWarnings("rawtypes") - @Override - public void mouseClicked(final MouseEvent e) { - SwingWorker worker = new SwingWorker() { - - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - for (ErrorMarker eMarker : errorPoints) { - // -2 and +2 are extra allowance, clicks in the - // vicinity of the markers register that way - if (e.getY() >= eMarker.y - 2 - && e.getY() <= eMarker.y + 2 - + errorMarkerHeight) { - int currentTabErrorIndex = errorPoints - .indexOf(eMarker); - // System.out.println("Index: " + - // currentTabErrorIndex); - int currentTab = editor.getSketch() - .getCodeIndex( - editor.getSketch() - .getCurrentCode()); - - int totalErrorIndex = currentTabErrorIndex; - - for (int i = 0; i < errorCheckerService.problemsList - .size(); i++) { - Problem p = errorCheckerService.problemsList - .get(i); - if (p.tabIndex < currentTab) { - totalErrorIndex++; - } - if (p.tabIndex == currentTab) { - break; - } - } - errorCheckerService - .scrollToErrorLine(totalErrorIndex); - } - } - - } - }; - - try { - worker.execute(); - } catch (Exception exp) { - System.out.println("Errorbar mouseClicked is slacking." - + exp.getMessage()); - // e.printStackTrace(); - } - - } - }); - - // Tooltip on hover - this.addMouseMotionListener(new MouseMotionListener() { - - @SuppressWarnings("rawtypes") - @Override - public void mouseMoved(final MouseEvent e) { - // System.out.println(e); - SwingWorker worker = new SwingWorker() { - - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - - for (ErrorMarker eMarker : errorPoints) { - if (e.getY() >= eMarker.y - 2 - && e.getY() <= eMarker.y + 2 - + errorMarkerHeight) { - // System.out.println("Index: " + - // errorPoints.indexOf(y)); - int currentTab = editor.getSketch() - .getCodeIndex( - editor.getSketch() - .getCurrentCode()); - int currentTabErrorCount = 0; - - for (int i = 0; i < errorPoints.size(); i++) { - Problem p = errorPoints.get(i).problem; - if (p.tabIndex == currentTab) { - if (currentTabErrorCount == errorPoints - .indexOf(eMarker)) { - // System.out.println("Roger that."); - String msg = (p.isError() ? "Error: " - : "Warning: ") - + p.message; - setToolTipText(msg); - setCursor(Cursor - .getPredefinedCursor(Cursor.HAND_CURSOR)); - return; - } else { - currentTabErrorCount++; - // System.out.println("Still looking.."); - } - } - - } - } - // Reset cursor and tooltip - else { - setToolTipText(""); - setCursor(Cursor - .getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - - } - }; - try { - worker.execute(); - } catch (Exception exp) { - System.out - .println("Errorbar mousemoved Worker is slacking." - + exp.getMessage()); - // e.printStackTrace(); - } - } - - @Override - public void mouseDragged(MouseEvent arg0) { - - } - }); - - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java deleted file mode 100644 index 395def5e2..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ErrorCheckerService.java +++ /dev/null @@ -1,1297 +0,0 @@ -package processing.mode.experimental; - -import java.awt.EventQueue; -import java.io.File; -import java.io.FileFilter; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.swing.table.DefaultTableModel; - -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.core.dom.AST; -import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; - -import processing.app.Base; -import processing.app.Editor; -import processing.app.Library; -import processing.app.SketchCode; -import processing.core.PApplet; -import processing.mode.java.preproc.PdePreprocessor; - -public class ErrorCheckerService implements Runnable{ - - private DebugEditor editor; - /** - * Error check happens every sleepTime milliseconds - */ - public static final int sleepTime = 1000; - - /** - * The amazing eclipse ast parser - */ - private ASTParser parser; - - /** - * Used to indirectly stop the Error Checker Thread - */ - public boolean stopThread = false; - - /** - * If true, Error Checking is paused. Calls to checkCode() become useless. - */ - private boolean pauseThread = false; - - protected ErrorWindow errorWindow; - - /** - * IProblem[] returned by parser stored in here - */ - private IProblem[] problems; - - /** - * Class name of current sketch - */ - protected String className; - - /** - * Source code of current sketch - */ - protected String sourceCode; - - /** - * URLs of extra imports jar files stored here. - */ - protected URL[] classpath; - - /** - * Stores all Problems in the sketch - */ - public ArrayList problemsList; - - /** - * How many lines are present till the initial class declaration? In static - * mode, this would include imports, class declaration and setup - * declaration. In nomral mode, this would include imports, class - * declaration only. It's fate is decided inside preprocessCode() - */ - public int mainClassOffset; - - /** - * Fixed p5 offsets for all sketches - */ - public int defaultImportsOffset; - - /** - * Is the sketch running in static mode or active mode? - */ - public boolean staticMode = false; - - /** - * Compilation Unit for current sketch - */ - protected CompilationUnit cu; - - /** - * If true, compilation checker will be reloaded with updated classpath - * items. - */ - private boolean loadCompClass = true; - - /** - * Compiler Checker class. Note that methods for compilation checking are - * called from the compilationChecker object, not from this - */ - protected Class checkerClass; - - /** - * Compilation Checker object. - */ - protected Object compilationChecker; - - - /** - * List of jar files to be present in compilation checker's classpath - */ - protected ArrayList classpathJars; - - /** - * Timestamp - for measuring total overhead - */ - private long lastTimeStamp = System.currentTimeMillis(); - - /** - * Used for displaying the rotating slash on the Problem Window title bar - */ - private String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--", - "\\" }; - private int slashAnimationIndex = 0; - - /** - * Used to detect if the current tab index has changed and thus repaint the - * textarea. - */ - public int currentTab = 0, lastTab = 0; - - /** - * Stores the current import statements in the program. Used to compare for - * changed import statements and update classpath if needed. - */ - protected ArrayList programImports; - - /** - * List of imports when sketch was last checked. Used for checking for - * changed imports - */ - protected ArrayList previousImports = new ArrayList(); - - /** - * Teh Preprocessor - */ - protected XQPreprocessor xqpreproc; - - /** - * Regexp for import statements. (Used from Processing source) - */ - final public String importRegexp = "(?:^|;)\\s*(import\\s+)((?:static\\s+)?\\S+)(\\s*;)"; - - /** - * Regexp for function declarations. (Used from Processing source) - */ - final Pattern FUNCTION_DECL = Pattern - .compile("(^|;)\\s*((public|private|protected|final|static)\\s+)*" - + "(void|int|float|double|String|char|byte)" - + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(", Pattern.MULTILINE); - - public ErrorCheckerService(DebugEditor debugEditor) { - this.editor = debugEditor; - initParser(); - initializeErrorWindow(); - xqpreproc = new XQPreprocessor(); - PdePreprocessor pdePrepoc = new PdePreprocessor(null); - defaultImportsOffset = pdePrepoc.getCoreImports().length + - pdePrepoc.getDefaultImports().length + 1; - astGenerator = new ASTGenerator(this); - } - - /** - * Initializes ASTParser - */ - private void initParser() { - try { - parser = ASTParser.newParser(AST.JLS4); - } catch (Exception e) { - System.err.println("Experimental Mode initialization failed. " - + "Are you running the right version of Processing? "); - pauseThread(); - } catch (Error e) { - System.err.println("Experimental Mode initialization failed. "); - e.printStackTrace(); - pauseThread(); - } - } - - /** - * Initialiazes the Error Window - */ - public void initializeErrorWindow() { - - if (editor == null) { - return; - } - - if (errorWindow != null) { - return; - } - - final ErrorCheckerService thisService = this; - final DebugEditor thisEditor = editor; - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - errorWindow = new ErrorWindow(thisEditor, thisService); - // errorWindow.setVisible(true); - editor.toFront(); - errorWindow.errorTable.setFocusable(false); - editor.setSelection(0, 0); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - public void run() { - stopThread = false; - - checkCode(); - while (!stopThread) { - try { - // Take a nap. - Thread.sleep(sleepTime); - } catch (Exception e) { - System.out.println("Oops! [ErrorCheckerThreaded]: " + e); - // e.printStackTrace(); - } - - updatePaintedThingys(); - - if (pauseThread) - continue; - if(textModified.get() == 0) - continue; - // Check every x seconds - checkCode(); - - } - } - - protected ASTGenerator astGenerator; - AtomicInteger textModified = new AtomicInteger(); - private boolean checkCode() { - System.out.println("checkCode() " + textModified.get() ); - lastTimeStamp = System.currentTimeMillis(); - try { - sourceCode = preprocessCode(editor.getSketch().getMainProgram()); - - syntaxCheck(); - System.out.println(editor.getSketch().getName() + "1 MCO " - + mainClassOffset); - // No syntax errors, proceed for compilation check, Stage 2. - - if (problems.length == 0 && editor.compilationCheckEnabled) { - //mainClassOffset++; // just a hack. - astGenerator.buildAST(cu); - sourceCode = xqpreproc.doYourThing(sourceCode, programImports); - prepareCompilerClasspath(); -// mainClassOffset = xqpreproc.mainClassOffset; // tiny, but -// // significant -// if (staticMode) { -// mainClassOffset++; // Extra line for setup() decl. -// } - // System.out.println(sourceCode); - // System.out.println("--------------------------"); - compileCheck(); - System.out.println(editor.getSketch().getName() + "2 MCO " - + mainClassOffset); - } - - updateErrorTable(); - editor.updateErrorBar(problemsList); - updateEditorStatus(); - updatePaintedThingys(); - int x = textModified.get(); - //System.out.println("TM " + x); - if(x>=3){ - textModified.set(3); - x = 3; - } - - if(x>0) - textModified.set(x - 1); - else - textModified.set(0); - return true; - - } catch (Exception e) { - System.out.println("Oops! [ErrorCheckerService.checkCode]: " + e); - e.printStackTrace(); - } - return false; - } - - private void syntaxCheck() { - parser.setSource(sourceCode.toCharArray()); - parser.setKind(ASTParser.K_COMPILATION_UNIT); - - @SuppressWarnings("unchecked") - Map options = JavaCore.getOptions(); - - JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); - options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - parser.setCompilerOptions(options); - cu = (CompilationUnit) parser.createAST(null); - - // Store errors returned by the ast parser - problems = cu.getProblems(); - // System.out.println("Problem Count: " + problems.length); - // Populate the probList - problemsList = new ArrayList(); - for (int i = 0; i < problems.length; i++) { - int a[] = calculateTabIndexAndLineNumber(problems[i]); - Problem p = new Problem(problems[i], a[0], a[1]); - problemsList.add(p); - // System.out.println(p.toString()); - } - } - protected URLClassLoader classLoader; - private void compileCheck() { - - // Currently (Sept, 2012) I'm using Java's reflection api to load the - // CompilationChecker class(from CompilationChecker.jar) that houses the - // Eclispe JDT compiler and call its getErrorsAsObj method to obtain - // errors. This way, I'm able to add the paths of contributed libraries - // to the classpath of CompilationChecker, dynamically. The eclipse compiler - // needs all referenced libraries in the classpath. - - try { - - // NOTE TO SELF: If classpath contains null Strings - // URLClassLoader gets angry. Drops NPE bombs. - - // If imports have changed, reload classes with new classpath. - if (loadCompClass) { - - // if (classpathJars.size() > 0) - // System.out - // .println("Experimental Mode: Loading contributed libraries referenced by import statements."); - - File f = Base.getContentFile("modes" + File.separator + "experimental" - + File.separator + "mode"); - - if(!f.exists()) { - System.err.println("Could not locate the files required for on-the-fly error checking. Bummer."); - return; - } - - FileFilter fileFilter = new FileFilter() { - public boolean accept(File file) { - return (file.getName().endsWith(".jar") && !file - .getName().startsWith("experimental")); - } - }; - - File[] jarFiles = f.listFiles(fileFilter); - // System.out.println( "Jar files found? " + (jarFiles != null)); - //for (File jarFile : jarFiles) { - //classpathJars.add(jarFile.toURI().toURL()); - //} - - classpath = new URL[classpathJars.size() + jarFiles.length]; - int ii = 0; - for (; ii < classpathJars.size(); ii++) { - classpath[ii] = classpathJars.get(ii); - } - for (int i = 0; i < jarFiles.length; i++) { - classpath[ii++] = jarFiles[i].toURI().toURL(); - } - - // System.out.println("CP Len -- " + classpath.length); - classLoader = new URLClassLoader(classpath); - // System.out.println("1."); - checkerClass = Class.forName("CompilationChecker", true, - classLoader); - // System.out.println("2."); - compilationChecker = checkerClass.newInstance(); - - astGenerator.loadJars(); // Update jar files for completition list - loadCompClass = false; - } - - if (compilerSettings == null) { - prepareCompilerSetting(); - } - Method getErrors = checkerClass.getMethod("getErrorsAsObjArr", - new Class[] { String.class, String.class, Map.class }); - - Object[][] errorList = (Object[][]) getErrors - .invoke(compilationChecker, className, sourceCode, - compilerSettings); - - if (errorList == null) { - return; - } - - problems = new DefaultProblem[errorList.length]; - - for (int i = 0; i < errorList.length; i++) { - - // for (int j = 0; j < errorList[i].length; j++) - // System.out.print(errorList[i][j] + ", "); - - problems[i] = new DefaultProblem((char[]) errorList[i][0], - (String) errorList[i][1], - ((Integer) errorList[i][2]).intValue(), - (String[]) errorList[i][3], - ((Integer) errorList[i][4]).intValue(), - ((Integer) errorList[i][5]).intValue(), - ((Integer) errorList[i][6]).intValue(), - ((Integer) errorList[i][7]).intValue(), 0); - - // System.out - // .println("ECS: " + problems[i].getMessage() + "," - // + problems[i].isError() + "," - // + problems[i].isWarning()); - - IProblem problem = problems[i]; - - int a[] = calculateTabIndexAndLineNumber(problem); - Problem p = new Problem(problem, a[0], a[1]); - if ((Boolean) errorList[i][8]) { - p.setType(Problem.ERROR); - } - - if ((Boolean) errorList[i][9]) { - p.setType(Problem.WARNING); - } - - // If warnings are disabled, skip 'em - if (p.isWarning() && !warningsEnabled) { - continue; - } - problemsList.add(p); - } - - } catch (ClassNotFoundException e) { - System.err.println("Compiltation Checker files couldn't be found! " - + e + " compileCheck() problem."); - stopThread(); - } catch (MalformedURLException e) { - System.err.println("Compiltation Checker files couldn't be found! " - + e + " compileCheck() problem."); - stopThread(); - } catch (Exception e) { - System.err.println("compileCheck() problem." + e); - e.printStackTrace(); - stopThread(); - } catch (NoClassDefFoundError e) { - System.err - .println(e - + " compileCheck() problem. Somebody tried to mess with Experimental Mode files."); - stopThread(); - } - // System.out.println("Compilecheck, Done."); - } - - /** - * Processes import statements to obtain classpaths of contributed - * libraries. This would be needed for compilation check. Also, adds - * stuff(jar files, class files, candy) from the code folder. And it looks - * messed up. - * - */ - private void prepareCompilerClasspath() { - if (!loadCompClass) { - return; - } - - // System.out.println("1.."); - classpathJars = new ArrayList(); - String entry = ""; - boolean codeFolderChecked = false; - for (ImportStatement impstat : programImports) { - String item = impstat.importName; - int dot = item.lastIndexOf('.'); - entry = (dot == -1) ? item : item.substring(0, dot); - - entry = entry.substring(6).trim(); - // System.out.println("Entry--" + entry); - if (ignorableImport(entry)) { - // System.out.println("Ignoring: " + entry); - continue; - } - Library library = null; - - // Try to get the library classpath and add it to the list - try { - library = editor.getMode().getLibrary(entry); - // System.out.println("lib->" + library.getClassPath() + "<-"); - String libraryPath[] = PApplet.split(library.getClassPath() - .substring(1).trim(), File.pathSeparatorChar); - for (int i = 0; i < libraryPath.length; i++) { - // System.out.println(entry + " ::" - // + new File(libraryPath[i]).toURI().toURL()); - classpathJars.add(new File(libraryPath[i]).toURI().toURL()); - } - // System.out.println("-- "); - // classpath[count] = (new File(library.getClassPath() - // .substring(1))).toURI().toURL(); - // System.out.println(" found "); - // System.out.println(library.getClassPath().substring(1)); - } catch (Exception e) { - if (library == null && !codeFolderChecked) { - // System.out.println(1); - // Look around in the code folder for jar files - if (editor.getSketch().hasCodeFolder()) { - File codeFolder = editor.getSketch().getCodeFolder(); - - // get a list of .jar files in the "code" folder - // (class files in subfolders should also be picked up) - String codeFolderClassPath = Base - .contentsToClassPath(codeFolder); - codeFolderChecked = true; - if (codeFolderClassPath.equalsIgnoreCase("")) { - System.err.println("Experimental Mode: Yikes! Can't find \"" - + entry - + "\" library! Line: " - + impstat.lineNumber - + " in tab: " - + editor.getSketch().getCode(impstat.tab) - .getPrettyName()); - System.out - .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); - - } - String codeFolderPath[] = PApplet.split( - codeFolderClassPath.substring(1).trim(), - File.pathSeparatorChar); - try { - for (int i = 0; i < codeFolderPath.length; i++) { - classpathJars.add(new File(codeFolderPath[i]) - .toURI().toURL()); - } - - } catch (Exception e2) { - System.out - .println("Yikes! codefolder, prepareImports(): " - + e2); - } - } else { - System.err.println("Experimental Mode: Yikes! Can't find \"" - + entry - + "\" library! Line: " - + impstat.lineNumber - + " in tab: " - + editor.getSketch().getCode(impstat.tab) - .getPrettyName()); - System.out - .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); - } - - } else { - System.err - .println("Yikes! There was some problem in prepareImports(): " - + e); - System.err.println("I was processing: " + entry); - - // e.printStackTrace(); - } - } - - } - - } - - /** - * Ignore processing packages, java.*.*. etc. - * - * @param packageName - * @return boolean - */ - protected boolean ignorableImport(String packageName) { - // packageName.startsWith("processing.") - // || - if (packageName.startsWith("java.") || packageName.startsWith("javax.")) { - return true; - } - return false; - } - - /** - * Various option for JDT Compiler - */ - @SuppressWarnings("rawtypes") - protected Map compilerSettings; - - /** - * Enable/Disable warnings from being shown - */ - public boolean warningsEnabled = true; - - /** - * Sets compiler options for JDT Compiler - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected void prepareCompilerSetting() { - compilerSettings = new HashMap(); - - compilerSettings.put(CompilerOptions.OPTION_LineNumberAttribute, - CompilerOptions.GENERATE); - compilerSettings.put(CompilerOptions.OPTION_SourceFileAttribute, - CompilerOptions.GENERATE); - compilerSettings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_6); - compilerSettings.put(CompilerOptions.OPTION_ReportUnusedImport, - CompilerOptions.IGNORE); - compilerSettings.put(CompilerOptions.OPTION_ReportMissingSerialVersion, - CompilerOptions.IGNORE); - compilerSettings.put(CompilerOptions.OPTION_ReportRawTypeReference, - CompilerOptions.IGNORE); - compilerSettings.put( - CompilerOptions.OPTION_ReportUncheckedTypeOperation, - CompilerOptions.IGNORE); - } - - - /** - * Updates the error table in the Error Window. - */ - synchronized public void updateErrorTable() { - - try { - String[][] errorData = new String[problemsList.size()][3]; - for (int i = 0; i < problemsList.size(); i++) { - errorData[i][0] = problemsList.get(i).message; - errorData[i][1] = editor.getSketch() - .getCode(problemsList.get(i).tabIndex).getPrettyName(); - errorData[i][2] = problemsList.get(i).lineNumber + ""; - } - - if (errorWindow != null) { - DefaultTableModel tm = new DefaultTableModel(errorData, - XQErrorTable.columnNames); - if (errorWindow.isVisible()) { - errorWindow.updateTable(tm); - } - - // Update error table in the editor - editor.updateTable(tm); - - // A rotating slash animation on the title bar to show - // that error checker thread is running - - slashAnimationIndex++; - if (slashAnimationIndex == slashAnimation.length) { - slashAnimationIndex = 0; - } - if (editor != null) { - String info = slashAnimation[slashAnimationIndex] + " T:" - + (System.currentTimeMillis() - lastTimeStamp) - + "ms"; - errorWindow.setTitle("Problems - " - + editor.getSketch().getName() + " " + info); - } - } - - } catch (Exception e) { - System.out.println("Exception at updateErrorTable() " + e); - e.printStackTrace(); - stopThread(); - } - - } - - /** - * Repaints the textarea if required - */ - public void updatePaintedThingys() { - editor.getTextArea().repaint(); - updateEditorStatus(); - currentTab = editor.getSketch().getCodeIndex( - editor.getSketch().getCurrentCode()); - //System.out.println("awesome! " + currentTab + " LT " + lastTab); - if (currentTab != lastTab) { - textModified.incrementAndGet(); - lastTab = currentTab; - return; - } - - } - - /** - * Updates editor status bar, depending on whether the caret is on an error - * line or not - */ - public void updateEditorStatus() { - // editor.statusNotice("Position: " + - // editor.getTextArea().getCaretLine()); - boolean notFound = true; - for (ErrorMarker emarker : editor.errorBar.errorPoints) { - if (emarker.problem.lineNumber == editor.getTextArea() - .getCaretLine() + 1) { - if (emarker.type == ErrorMarker.Warning) { - editor.statusNotice(emarker.problem.message); - } - else { - editor.statusError(emarker.problem.message); - } - return; - } - } - if (notFound) { - editor.statusEmpty(); - } - } - - /** - * Maps offset from java code to pde code. Returns a bunch of offsets as array - * - * @param line - * - line number in java code - * @param offset - * - offset from the start of the 'line' - * @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2] - * - line start offset, int[3] - offset from line start. int[2] and - * int[3] are on TODO - */ - public int[] JavaToPdeOffsets(int line, int offset){ - int codeIndex = 0; - - int x = line - mainClassOffset; - if (x < 0) { - // System.out.println("Negative line number " - // + problem.getSourceLineNumber() + " , offset " - // + mainClassOffset); - x = line - 2; // Another -1 for 0 index - if (x < programImports.size() && x >= 0) { - ImportStatement is = programImports.get(x); - // System.out.println(is.importName + ", " + is.tab + ", " - // + is.lineNumber); - return new int[] { is.tab, is.lineNumber }; - } else { - - // Some seriously ugly stray error, just can't find the source - // line! Simply return first line for first tab. - return new int[] { 0, 1 }; - } - - } - - try { - for (SketchCode sc : editor.getSketch().getCode()) { - if (sc.isExtension("pde")) { - int len = 0; - if (editor.getSketch().getCurrentCode().equals(sc)) { - len = Base.countLines(sc.getDocument().getText(0, - sc.getDocument().getLength())) + 1; - } else { - len = Base.countLines(sc.getProgram()) + 1; - } - - // System.out.println("x,len, CI: " + x + "," + len + "," - // + codeIndex); - - if (x >= len) { - - // We're in the last tab and the line count is greater - // than the no. - // of lines in the tab, - if (codeIndex >= editor.getSketch().getCodeCount() - 1) { - // System.out.println("Exceeds lc " + x + "," + len - // + problem.toString()); - // x = len - x = editor.getSketch().getCode(codeIndex) - .getLineCount(); - // TODO: Obtain line having last non-white space - // character in the code. - break; - } else { - x -= len; - codeIndex++; - } - } else { - - if (codeIndex >= editor.getSketch().getCodeCount()) { - codeIndex = editor.getSketch().getCodeCount() - 1; - } - break; - } - - } - } - } catch (Exception e) { - System.err - .println("Things got messed up in ErrorCheckerService.JavaToPdeOffset()"); - } - return new int[] { codeIndex, x }; - } - - public String getPDECodeAtLine(int tab, int linenumber){ - editor.getSketch().setCurrentCode(tab); - return editor.ta.getLineText(linenumber); - } - - /** - * Calculates the tab number and line number of the error in that particular - * tab. Provides mapping between pure java and pde code. - * - * @param problem - * - IProblem - * @return int[0] - tab number, int[1] - line number - */ - public int[] calculateTabIndexAndLineNumber(IProblem problem) { - // String[] lines = {};// = PApplet.split(sourceString, '\n'); - int codeIndex = 0; - - int x = problem.getSourceLineNumber() - mainClassOffset; - if (x < 0) { - // System.out.println("Negative line number " - // + problem.getSourceLineNumber() + " , offset " - // + mainClassOffset); - x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index - if (x < programImports.size() && x >= 0) { - ImportStatement is = programImports.get(x); - // System.out.println(is.importName + ", " + is.tab + ", " - // + is.lineNumber); - return new int[] { is.tab, is.lineNumber }; - } else { - - // Some seriously ugly stray error, just can't find the source - // line! Simply return first line for first tab. - return new int[] { 0, 1 }; - } - - } - - try { - for (SketchCode sc : editor.getSketch().getCode()) { - if (sc.isExtension("pde")) { - int len = 0; - if (editor.getSketch().getCurrentCode().equals(sc)) { - len = Base.countLines(sc.getDocument().getText(0, - sc.getDocument().getLength())) + 1; - } else { - len = Base.countLines(sc.getProgram()) + 1; - } - - // System.out.println("x,len, CI: " + x + "," + len + "," - // + codeIndex); - - if (x >= len) { - - // We're in the last tab and the line count is greater - // than the no. - // of lines in the tab, - if (codeIndex >= editor.getSketch().getCodeCount() - 1) { - // System.out.println("Exceeds lc " + x + "," + len - // + problem.toString()); - // x = len - x = editor.getSketch().getCode(codeIndex) - .getLineCount(); - // TODO: Obtain line having last non-white space - // character in the code. - break; - } else { - x -= len; - codeIndex++; - } - } else { - - if (codeIndex >= editor.getSketch().getCodeCount()) { - codeIndex = editor.getSketch().getCodeCount() - 1; - } - break; - } - - } - } - } catch (Exception e) { - System.err - .println("Things got messed up in ErrorCheckerService.calculateTabIndexAndLineNumber()"); - } - - return new int[] { codeIndex, x }; - } - - /** - * Fetches code from the editor tabs and pre-processes it into parsable pure - * java source. And there's a difference between parsable and compilable. - * XQPrerocessor.java makes this code compilable.
    - * Handles:
  • Removal of import statements
  • Conversion of int(), - * char(), etc to PApplet.parseInt(), etc.
  • Replacing '#' with 0xff for - * color representation
  • Converts all 'color' datatypes to int - * (experimental)
  • Appends class declaration statement after determining - * the mode the sketch is in - ACTIVE or STATIC - * - * @return String - Pure java representation of PDE code. Note that this - * code is not yet compile ready. - */ - - private String preprocessCode(String pdeCode) { - - programImports = new ArrayList(); - - StringBuffer rawCode = new StringBuffer(); - - try { - - for (SketchCode sc : editor.getSketch().getCode()) { - if (sc.isExtension("pde")) { - - try { - - if (editor.getSketch().getCurrentCode().equals(sc)) { - - rawCode.append(scrapImportStatements(sc.getDocument() - .getText(0, - sc.getDocument() - .getLength()), - editor.getSketch() - .getCodeIndex(sc))); - } else { - - rawCode.append(scrapImportStatements(sc.getProgram(), editor - .getSketch().getCodeIndex(sc))); - - } - rawCode.append('\n'); - } catch (Exception e) { - System.err.println("Exception in preprocessCode() - bigCode " - + e.toString()); - } - rawCode.append('\n'); - } - } - - } catch (Exception e) { - System.out.println("Exception in preprocessCode()"); - } - String sourceAlt = rawCode.toString(); - // Replace comments with whitespaces - // sourceAlt = scrubComments(sourceAlt); - - // Find all int(*), replace with PApplet.parseInt(*) - - // \bint\s*\(\s*\b , i.e all exclusive "int(" - - String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; - - for (String dataType : dataTypeFunc) { - String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; - Pattern pattern = Pattern.compile(dataTypeRegexp); - Matcher matcher = pattern.matcher(sourceAlt); - - // while (matcher.find()) { - // System.out.print("Start index: " + matcher.start()); - // System.out.println(" End index: " + matcher.end() + " "); - // System.out.println("-->" + matcher.group() + "<--"); - // } - sourceAlt = matcher.replaceAll("PApplet.parse" - + Character.toUpperCase(dataType.charAt(0)) - + dataType.substring(1) + "("); - - } - - // Find all #[web color] and replace with 0xff[webcolor] - // Should be 6 digits only. - final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; - Pattern webPattern = Pattern.compile(webColorRegexp); - Matcher webMatcher = webPattern.matcher(sourceAlt); - while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - String found = sourceAlt.substring(webMatcher.start(), - webMatcher.end()); - // System.out.println("-> " + found); - sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); - webMatcher = webPattern.matcher(sourceAlt); - } - - // Replace all color data types with int - // Regex, Y U SO powerful? - final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; - Pattern colorPattern = Pattern.compile(colorTypeRegex); - Matcher colorMatcher = colorPattern.matcher(sourceAlt); - sourceAlt = colorMatcher.replaceAll("int"); - - checkForChangedImports(); - - className = (editor == null) ? "DefaultClass" : editor.getSketch() - .getName(); - - - // Check whether the code is being written in STATIC mode(no function - // declarations) - append class declaration and void setup() declaration - Matcher matcher = FUNCTION_DECL.matcher(sourceAlt); - if (!matcher.find()) { - sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" - + "public void setup() {\n" + sourceAlt - + "\nnoLoop();\n}\n" + "\n}\n"; - staticMode = true; - - } else { - sourceAlt = xqpreproc.prepareImports(programImports) + "public class " + className + " extends PApplet {\n" - + sourceAlt + "\n}"; - staticMode = false; - } - - int position = sourceAlt.indexOf("{") + 1; - mainClassOffset = 1; - for (int i = 0; i <= position; i++) { - if (sourceAlt.charAt(i) == '\n') { - mainClassOffset++; - } - } - if(staticMode) { - mainClassOffset++; - } - //mainClassOffset += 2; - // Handle unicode characters - sourceAlt = substituteUnicode(sourceAlt); - -// System.out.println("-->\n" + sourceAlt + "\n<--"); -// System.out.println("PDE code processed - " -// + editor.getSketch().getName()); - sourceCode = sourceAlt; - return sourceAlt; - - } - - /** - * The super method that highlights any ASTNode in the pde editor =D - * @param node - * @return true - if highlighting happened correctly. - */ - public boolean highlightNode(ASTNodeWrapper awrap){ - int pdeoffsets[] = awrap.getPDECodeOffsets(this); - int javaoffsets[] = awrap.getJavaCodeOffsets(this); - try { - scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1],javaoffsets[1], - javaoffsets[2]); - return true; - } catch (Exception e) { - - e.printStackTrace(); - } - return false; - } - - public boolean highlightNode(ASTNode node){ - ASTNodeWrapper awrap = new ASTNodeWrapper(node); - return highlightNode(awrap); - } - - /** - * Scrolls to the error source in code. And selects the line text. Used by - * XQErrorTable and ErrorBar - * - * @param errorIndex - * - index of error - */ - public void scrollToErrorLine(int errorIndex) { - if (editor == null) { - return; - } - - if (errorIndex < problemsList.size() && errorIndex >= 0) { - Problem p = problemsList.get(errorIndex); - scrollToErrorLine(p); - } - } - - public void scrollToErrorLine(Problem p) { - if (editor == null) { - return; - } - if (p == null) - return; - try { - editor.toFront(); - editor.getSketch().setCurrentCode(p.tabIndex); - - editor - .setSelection(editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) - + editor.getTextArea() - .getLineText(p.lineNumber - 1).trim().length(), - editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); - editor.getTextArea().scrollTo(p.lineNumber - 1, 0); - editor.repaint(); - } catch (Exception e) { - System.err.println(e - + " : Error while selecting text in scrollToErrorLine()"); - e.printStackTrace(); - } - // System.out.println("---"); - } - - /** - * Static method for scroll to a particular line in the PDE. Also highlights - * the length of the text. Requires the editor instance as arguement. - * - * @param edt - * @param tabIndex - * @param lineNoInTab - * - line number in the corresponding tab - * @param lineStartOffset - * - selection start offset(from line start non-whitespace offset) - * @param length - * - length of selection - * @return - true, if scroll was successful - */ - public static boolean scrollToErrorLine(Editor edt, int tabIndex, int lineNoInTab, int lineStartOffset, int length) { - if (edt == null) { - return false; - } - try { - edt.toFront(); - edt.getSketch().setCurrentCode(tabIndex); - int lsno = edt.getTextArea() - .getLineStartNonWhiteSpaceOffset(lineNoInTab - 1) + lineStartOffset; - edt.setSelection(lsno, lsno + length); - edt.getTextArea().scrollTo(lineNoInTab - 1, 0); - edt.repaint(); - System.out.println(lineStartOffset + " LSO,len " + length); - } catch (Exception e) { - System.err.println(e - + " : Error while selecting text in static scrollToErrorLine()"); - e.printStackTrace(); - return false; - } - return true; - } - - /** - * Checks if import statements in the sketch have changed. If they have, - * compiler classpath needs to be updated. - */ - private void checkForChangedImports() { - // System.out.println("Imports: " + programImports.size() + - // " Prev Imp: " - // + previousImports.size()); - if (programImports.size() != previousImports.size()) { - // System.out.println(1); - loadCompClass = true; - previousImports = programImports; - } else { - for (int i = 0; i < programImports.size(); i++) { - if (!programImports.get(i).importName.equals(previousImports - .get(i).importName)) { - // System.out.println(2); - loadCompClass = true; - previousImports = programImports; - break; - } - } - } - // System.out.println("load..? " + loadCompClass); - } - - /** - * Removes import statements from tabSource, replaces each with white spaces - * and adds the import to the list of program imports - * - * @param tabProgram - * - Code in a tab - * @param tabNumber - * - index of the tab - * @return String - Tab code with imports replaced with white spaces - */ - private String scrapImportStatements(String tabProgram, int tabNumber) { - //TODO: Commented out imports are still detected as main imports. - String tabSource = new String(tabProgram); - do { - // System.out.println("-->\n" + sourceAlt + "\n<--"); - String[] pieces = PApplet.match(tabSource, importRegexp); - - // Stop the loop if we've removed all the import lines - if (pieces == null) { - break; - } - - String piece = pieces[1] + pieces[2] + pieces[3]; - int len = piece.length(); // how much to trim out - - // programImports.add(piece); // the package name - - // find index of this import in the program - int idx = tabSource.indexOf(piece); - // System.out.print("Import -> " + piece); - // System.out.println(" - " - // + Base.countLines(tabSource.substring(0, idx)) + " tab " - // + tabNumber); - programImports.add(new ImportStatement(piece, tabNumber, Base - .countLines(tabSource.substring(0, idx)))); - // Remove the import from the main program - // Substitute with white spaces - String whiteSpace = ""; - for (int j = 0; j < piece.length(); j++) { - whiteSpace += " "; - } - tabSource = tabSource.substring(0, idx) + whiteSpace - + tabSource.substring(idx + len); - - } while (true); - // System.out.println(tabSource); - return tabSource; - } - - /** - * Replaces non-ascii characters with their unicode escape sequences and - * stuff. Used as it is from - * processing.src.processing.mode.java.preproc.PdePreprocessor - * - * @param program - * - Input String containing non ascii characters - * @return String - Converted String - */ - public static String substituteUnicode(String program) { - // check for non-ascii chars (these will be/must be in unicode format) - char p[] = program.toCharArray(); - int unicodeCount = 0; - for (int i = 0; i < p.length; i++) { - if (p[i] > 127) { - unicodeCount++; - } - } - if (unicodeCount == 0) { - return program; - } - // if non-ascii chars are in there, convert to unicode escapes - // add unicodeCount * 5.. replacing each unicode char - // with six digit uXXXX sequence (xxxx is in hex) - // (except for nbsp chars which will be a replaced with a space) - int index = 0; - char p2[] = new char[p.length + unicodeCount * 5]; - for (int i = 0; i < p.length; i++) { - if (p[i] < 128) { - p2[index++] = p[i]; - } else if (p[i] == 160) { // unicode for non-breaking space - p2[index++] = ' '; - } else { - int c = p[i]; - p2[index++] = '\\'; - p2[index++] = 'u'; - char str[] = Integer.toHexString(c).toCharArray(); - // add leading zeros, so that the length is 4 - // for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0'; - for (int m = 0; m < 4 - str.length; m++) - p2[index++] = '0'; - System.arraycopy(str, 0, p2, index, str.length); - index += str.length; - } - } - return new String(p2, 0, index); - } - - /** - * Stops the Error Checker Service thread - */ - public void stopThread() { - stopThread = true; - } - - /** - * Pauses the Error Checker Service thread - */ - public void pauseThread() { - pauseThread = true; - } - - /** - * Resumes the Error Checker Service thread - */ - public void resumeThread() { - pauseThread = false; - } - - public DebugEditor getEditor() { - return editor; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorMarker.java b/pdex/experimental/src/processing/mode/experimental/ErrorMarker.java deleted file mode 100755 index 0a10cff4b..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ErrorMarker.java +++ /dev/null @@ -1,36 +0,0 @@ -package processing.mode.experimental; -/** - * Error markers displayed on the Error Bar. - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ - public class ErrorMarker { - /** - * y co-ordinate of the marker - */ - public int y; - /** - * Type of marker: Error or Warning? - */ - public int type = -1; - /** - * Error Type constant - */ - public static final int Error = 1; - /** - * Warning Type constant - */ - public static final int Warning = 2; - /** - * Problem that the error marker represents - * @see Problem - */ - public Problem problem; - - public ErrorMarker(Problem problem, int y, int type) { - this.problem = problem; - this.y = y; - this.type = type; - } - } \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/ErrorWindow.java b/pdex/experimental/src/processing/mode/experimental/ErrorWindow.java deleted file mode 100755 index 6494b58ed..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ErrorWindow.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package processing.mode.experimental; - -import java.awt.BorderLayout; -import java.awt.Frame; -import java.awt.Point; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.WindowConstants; -import javax.swing.border.EmptyBorder; -import javax.swing.table.TableModel; - -import processing.app.Editor; -import processing.app.Toolkit; - -/** - * Error Window that displays a tablular list of errors. Clicking on an error - * scrolls to its location in the code. - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ -public class ErrorWindow extends JFrame { - - private JPanel contentPane; - /** - * The table displaying the errors - */ - protected XQErrorTable errorTable; - /** - * Scroll pane that contains the Error Table - */ - protected JScrollPane scrollPane; - - protected DebugEditor thisEditor; - private JFrame thisErrorWindow; - - /** - * Handles the sticky Problem window - */ - private DockTool2Base Docker; - - protected ErrorCheckerService errorCheckerService; - - /** - * Preps up ErrorWindow - * - * @param editor - * - Editor - * @param ecs - ErrorCheckerService - */ - public ErrorWindow(DebugEditor editor, ErrorCheckerService ecs) { - thisErrorWindow = this; - errorCheckerService = ecs; - thisEditor = editor; - setTitle("Problems"); - prepareFrame(); - } - - /** - * Sets up ErrorWindow - */ - protected void prepareFrame() { - Toolkit.setIcon(this); - setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); - // Default size: setBounds(100, 100, 458, 160); - setBounds(100, 100, 458, 160); // Yeah, I hardcode such things sometimes. Hate me. - - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - setContentPane(contentPane); - contentPane.setLayout(new BorderLayout(0, 0)); - - scrollPane = new JScrollPane(); - contentPane.add(scrollPane); - - errorTable = new XQErrorTable(errorCheckerService); - scrollPane.setViewportView(errorTable); - - try { - Docker = new DockTool2Base(); - addListeners(); - } catch (Exception e) { - System.out.println("addListeners() acted silly."); - e.printStackTrace(); - } - - if (thisEditor != null) { - setLocation(new Point(thisEditor.getLocation().x - + thisEditor.getWidth(), thisEditor.getLocation().y)); - } - - } - - /** - * Updates the error table with new data(Table Model). Called from Error - * Checker Service. - * - * @param tableModel - * - Table Model - * @return True - If error table was updated successfully. - */ - synchronized public boolean updateTable(final TableModel tableModel) { - // XQErrorTable handles evrything now - return errorTable.updateTable(tableModel); - } - - /** - * Adds various listeners to components of EditorWindow and to the Editor - * window - */ - protected void addListeners() { - - if (thisErrorWindow == null) - System.out.println("ERW null"); - - thisErrorWindow.addComponentListener(new ComponentListener() { - - @Override - public void componentShown(ComponentEvent e) { - - } - - @Override - public void componentResized(ComponentEvent e) { - Docker.tryDocking(); - } - - @Override - public void componentMoved(ComponentEvent e) { - Docker.tryDocking(); - } - - @Override - public void componentHidden(ComponentEvent e) { - - } - }); - - thisErrorWindow.addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - thisEditor.problemWindowMenuCB.setSelected(false); - } - - @Override - public void windowDeiconified(WindowEvent e) { - thisEditor.setExtendedState(Frame.NORMAL); - } - - }); - - if (thisEditor == null) { - System.out.println("Editor null"); - return; - } - - thisEditor.addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - - } - - @Override - public void windowClosed(WindowEvent e) { - errorCheckerService.pauseThread(); - errorCheckerService.stopThread(); // Bye bye thread. - thisErrorWindow.dispose(); - } - - @Override - public void windowIconified(WindowEvent e) { - thisErrorWindow.setExtendedState(Frame.ICONIFIED); - } - - @Override - public void windowDeiconified(WindowEvent e) { - thisErrorWindow.setExtendedState(Frame.NORMAL); - } - - }); - - thisEditor.addComponentListener(new ComponentListener() { - - @Override - public void componentShown(ComponentEvent e) { - - } - - @Override - public void componentResized(ComponentEvent e) { - if (Docker.isDocked()) { - Docker.dock(); - } else { - Docker.tryDocking(); - } - } - - @Override - public void componentMoved(ComponentEvent e) { - - if (Docker.isDocked()) { - Docker.dock(); - } else { - Docker.tryDocking(); - } - - } - - @Override - public void componentHidden(ComponentEvent e) { - // System.out.println("ed hidden"); - } - }); - - } - - - /** - * Implements the docking feature of the tool - The frame sticks to the - * editor and once docked, moves along with it as the editor is resized, - * moved, or closed. - * - * This class has been borrowed from Tab Manager tool by Thomas Diewald. It - * has been slightly modified and used here. - * - * @author Thomas Diewald , http://thomasdiewald.com - */ - private class DockTool2Base { - - private int docking_border = 0; - private int dock_on_editor_y_offset_ = 0; - private int dock_on_editor_x_offset_ = 0; - - // /////////////////////////////// - // ____2____ - // | | - // | | - // 0 | editor | 1 - // | | - // |_________| - // 3 - // /////////////////////////////// - - // public void reset() { - // dock_on_editor_y_offset_ = 0; - // dock_on_editor_x_offset_ = 0; - // docking_border = 0; - // } - - public boolean isDocked() { - return (docking_border >= 0); - } - - private final int MAX_GAP_ = 20; - - // - public void tryDocking() { - if (thisEditor == null) - return; - Editor editor = thisEditor; - Frame frame = thisErrorWindow; - - int ex = editor.getX(); - int ey = editor.getY(); - int ew = editor.getWidth(); - int eh = editor.getHeight(); - - int fx = frame.getX(); - int fy = frame.getY(); - int fw = frame.getWidth(); - int fh = frame.getHeight(); - - if (((fy > ey) && (fy < ey + eh)) - || ((fy + fh > ey) && (fy + fh < ey + eh))) { - int dis_border_left = Math.abs(ex - (fx + fw)); - int dis_border_right = Math.abs((ex + ew) - (fx)); - - if (dis_border_left < MAX_GAP_ || dis_border_right < MAX_GAP_) { - docking_border = (dis_border_left < dis_border_right) ? 0 - : 1; - dock_on_editor_y_offset_ = fy - ey; - dock(); - return; - } - } - - if (((fx > ex) && (fx < ex + ew)) - || ((fx + fw > ey) && (fx + fw < ex + ew))) { - int dis_border_top = Math.abs(ey - (fy + fh)); - int dis_border_bot = Math.abs((ey + eh) - (fy)); - - if (dis_border_top < MAX_GAP_ || dis_border_bot < MAX_GAP_) { - docking_border = (dis_border_top < dis_border_bot) ? 2 : 3; - dock_on_editor_x_offset_ = fx - ex; - dock(); - return; - } - } - docking_border = -1; - } - - public void dock() { - if (thisEditor == null) - return; - Editor editor = thisEditor; - Frame frame = thisErrorWindow; - - int ex = editor.getX(); - int ey = editor.getY(); - int ew = editor.getWidth(); - int eh = editor.getHeight(); - - // int fx = frame.getX(); - // int fy = frame.getY(); - int fw = frame.getWidth(); - int fh = frame.getHeight(); - - int x = 0, y = 0; - if (docking_border == -1) { - return; - } - - if (docking_border == 0) { - x = ex - fw; - y = ey + dock_on_editor_y_offset_; - } - if (docking_border == 1) { - x = ex + ew; - y = ey + dock_on_editor_y_offset_; - } - - if (docking_border == 2) { - x = ex + dock_on_editor_x_offset_; - y = ey - fh; - } - if (docking_border == 3) { - x = ex + dock_on_editor_x_offset_; - y = ey + eh; - } - frame.setLocation(x, y); - } - - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java b/pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java deleted file mode 100755 index 50d7ce4b3..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ExperimentalMode.java +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2012 The Processing Foundation - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.mode.experimental; - -import java.awt.Color; -import java.io.File; -import java.io.IOException; -import java.util.logging.FileHandler; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; -import processing.app.Base; -import processing.app.Editor; -import processing.app.EditorState; -import processing.app.Mode; -import processing.mode.java.JavaMode; - - -/** - * Experimental Mode for Processing, combines Debug Mode and XQMode and - * starts us working toward our next generation editor/debugger setup. - */ -public class ExperimentalMode extends JavaMode { - public static final boolean VERBOSE_LOGGING = true; - //public static final boolean VERBOSE_LOGGING = false; - public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - - - public ExperimentalMode(Base base, File folder) { - super(base, folder); - - // use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus - for (Mode m : base.getModeList()) { - if (m.getClass() == JavaMode.class) { - JavaMode jMode = (JavaMode) m; - librariesFolder = jMode.getLibrariesFolder(); - rebuildLibraryList(); - break; - } - } - - // Fetch examples and reference from java mode - // thx to Manindra (https://github.com/martinleopold/DebugMode/issues/4) - examplesFolder = Base.getContentFile("modes/java/examples"); - // https://github.com/martinleopold/DebugMode/issues/6 - referenceFolder = Base.getContentFile("modes/java/reference"); - - // set logging level - Logger globalLogger = Logger.getLogger(""); - //Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // doesn't work on os x - if (VERBOSE_LOGGING) { - globalLogger.setLevel(Level.INFO); - } else { - globalLogger.setLevel(Level.WARNING); - } - - // enable logging to file - try { - // settings is writable for built-in modes, mode folder is not writable - File logFolder = Base.getSettingsFile("debug"); - if (!logFolder.exists()) { - logFolder.mkdir(); - } - File logFile = new File(logFolder, "DebugMode.%g.log"); - Handler handler = new FileHandler(logFile.getAbsolutePath(), LOG_SIZE, 10, false); - globalLogger.addHandler(handler); - - } catch (IOException ex) { - Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); - } catch (SecurityException ex) { - Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex); - } - - // disable initial chattiness for now -// // output version from manifest file -// Package p = ExperimentalMode.class.getPackage(); -// String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; -// //System.out.println(titleAndVersion); -// Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); - } - - - @Override - public String getTitle() { - return "Experimental"; - } - - - public File[] getKeywordFiles() { - return new File[] { - Base.getContentFile("modes/java/keywords.txt") - }; - } - - - /** - * Create a new editor associated with this mode. - */ - @Override - public Editor createEditor(Base base, String path, EditorState state) { - return new DebugEditor(base, path, state, this); - } - - - /** - * Load a String value from theme.txt - * - * @param attribute the attribute key to load - * @param defaultValue the default value - * @return the attributes value, or the default value if the attribute - * couldn't be loaded - */ - public String loadThemeString(String attribute, String defaultValue) { - String newString = theme.get(attribute); - if (newString != null) { - return newString; - } - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Error loading String: {0}", attribute); - return defaultValue; - } - - - /** - * Load a Color value from theme.txt - * - * @param attribute the attribute key to load - * @param defaultValue the default value - * @return the attributes value, or the default value if the attribute - * couldn't be loaded - */ - public Color getThemeColor(String attribute, Color defaultValue) { - Color newColor = theme.getColor(attribute); - if (newColor != null) { - return newColor; - } - System.out.println("error loading color: " + attribute); - Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); - return defaultValue; - } - - - public ClassLoader getJavaModeClassLoader() { - for (Mode m : base.getModeList()) { - if (m.getClass() == JavaMode.class) { - JavaMode jMode = (JavaMode) m; - return jMode.getClassLoader(); - } - } - // badness - return null; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/FieldNode.java b/pdex/experimental/src/processing/mode/experimental/FieldNode.java deleted file mode 100755 index dbe9d4fd9..000000000 --- a/pdex/experimental/src/processing/mode/experimental/FieldNode.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.ClassNotLoadedException; -import com.sun.jdi.Field; -import com.sun.jdi.InvalidTypeException; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.Value; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Specialized {@link VariableNode} for representing fields. Overrides - * {@link #setValue} to properly change the value of the encapsulated field. - * - * @author Martin Leopold - */ -public class FieldNode extends VariableNode { - - protected Field field; - protected ObjectReference obj; - - /** - * Construct a {@link FieldNode}. - * - * @param name the name - * @param type the type - * @param value the value - * @param field the field - * @param obj a reference to the object containing the field - */ - public FieldNode(String name, String type, Value value, Field field, ObjectReference obj) { - super(name, type, value); - this.field = field; - this.obj = obj; - } - - @Override - public void setValue(Value value) { - try { - obj.setValue(field, value); - } catch (InvalidTypeException ex) { - Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); - } catch (ClassNotLoadedException ex) { - Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex); - } - this.value = value; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/ImportStatement.java b/pdex/experimental/src/processing/mode/experimental/ImportStatement.java deleted file mode 100755 index 26d2db7d1..000000000 --- a/pdex/experimental/src/processing/mode/experimental/ImportStatement.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package processing.mode.experimental; - -/** - * Wrapper for import statements - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ -public class ImportStatement { - /** - * Ex: processing.opengl.*, java.util.* - */ - String importName; - /** - * Which tab does it belong to? - */ - int tab; - - /** - * Line number(pde code) of the import - */ - int lineNumber; - - /** - * - * @param importName - Ex: processing.opengl.*, java.util.* - * @param tab - Which tab does it belong to? - * @param lineNumber - Line number(pde code) of the import - */ - public ImportStatement(String importName, int tab, int lineNumber) { - this.importName = importName; - this.tab = tab; - this.lineNumber = lineNumber; - } -} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/JavadocHelper.java b/pdex/experimental/src/processing/mode/experimental/JavadocHelper.java deleted file mode 100644 index 7cc582072..000000000 --- a/pdex/experimental/src/processing/mode/experimental/JavadocHelper.java +++ /dev/null @@ -1,126 +0,0 @@ -package processing.mode.experimental; - -import java.io.File; -import java.io.FileFilter; -import java.util.Iterator; -import java.util.TreeMap; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -public class JavadocHelper { - - public static void loadJavaDoc(TreeMap jdocMap, File p5Ref){ - Document doc; - - //Pattern pat = Pattern.compile("\\w+"); - try { - if (p5Ref == null) { - System.out.println("P5 Ref location null"); - p5Ref = new File( - "/home/quarkninja/Workspaces/processing-workspace/processing/build/linux/work/modes/java/reference"); - } - - FileFilter fileFilter = new FileFilter() { - public boolean accept(File file) { - if(!file.getName().endsWith("_.html")) - return false; - int k = 0; - for (int i = 0; i < file.getName().length(); i++) { - if(file.getName().charAt(i)== '_') - k++; - if(k > 1) - return false; - } - return true; - } - }; - - for (File docFile : p5Ref.listFiles(fileFilter)) { - - doc = Jsoup.parse(docFile, null); - Elements elm = doc.getElementsByClass("ref-item"); - String msg = ""; - String methodName = docFile.getName().substring(0, docFile.getName().indexOf('_')); - //System.out.println(methodName); - for (Iterator it = elm.iterator(); it.hasNext();) { - Element ele = (Element) it.next(); - msg = "
    " - + ele.html() + "
    "; - //mat.replaceAll(""); - msg = msg.replaceAll("img src=\"", "img src=\"" - + p5Ref.toURI().toURL().toString() + "/"); - //System.out.println(ele.text()); - } - jdocMap.put(methodName, msg); - } - System.out.println("JDoc loaded "+jdocMap.size()); - /* File javaDocFile = new File( - "/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html"); - //SimpleOpenNI.SimpleOpenNI - doc = Jsoup.parse(javaDocFile, null); - - String msg = ""; - Elements elm = doc.getElementsByTag("pre"); -// Elements desc = doc.getElementsByTag("dl"); - //System.out.println(elm.toString()); - - for (Iterator iterator = elm.iterator(); iterator.hasNext();) { - Element element = (Element) iterator.next(); - - //System.out.println(element.text()); -// if (element.nextElementSibling() != null) -// System.out.println(element.nextElementSibling().text()); - //System.out.println("-------------------"); - msg = "
    " - + element.html() - + element.nextElementSibling() - + "
    "; - int k = 0; - Matcher matcher = pat.matcher(element.text()); - ArrayList parts = new ArrayList(); - while (matcher.find()) { -// System.out.print("Start index: " + matcher.start()); -// System.out.print(" End index: " + matcher.end() + " "); - if (k == 0 && !matcher.group().equals("public")) { - k = -1; - break; - } - // System.out.print(matcher.group() + " "); - parts.add(matcher.group()); - k++; - } - if (k <= 0 || parts.size() < 3) - continue; - int i = 0; - if (parts.get(i).equals("public")) - i++; - if (parts.get(i).equals("static") || parts.get(i).equals("final") - || parts.get(i).equals("class")) - i++; - if (parts.get(i).equals("static") || parts.get(i).equals("final")) - i++; -// System.out.println("Ret Type " + parts.get(i)); - - i++; // return type - - //System.out.println("Name " + parts.get(i)); - jdocMap.put(parts.get(i), msg); - } - -// for (String key : jdocMap.keySet()) { -// System.out.println("Method: " + key); -// System.out.println("Method: " + jdocMap.get(key)); -// } - * - */ - } catch (Exception e) { - e.printStackTrace(); - } - - - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java b/pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java deleted file mode 100755 index 8d006fd9d..000000000 --- a/pdex/experimental/src/processing/mode/experimental/LineBreakpoint.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.AbsentInformationException; -import com.sun.jdi.Location; -import com.sun.jdi.ReferenceType; -import com.sun.jdi.request.BreakpointRequest; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Model/Controller of a line breakpoint. Can be set before or while debugging. - * Adds a highlight using the debuggers view ({@link DebugEditor}). - * - * @author Martin Leopold - */ -public class LineBreakpoint implements ClassLoadListener { - - protected Debugger dbg; // the debugger - protected LineID line; // the line this breakpoint is set on - protected BreakpointRequest bpr; // the request on the VM's event request manager - protected ReferenceType theClass; // the class containing this breakpoint, null when not yet loaded - - /** - * Create a {@link LineBreakpoint}. If in a debug session, will try to - * immediately set the breakpoint. If not in a debug session or the - * corresponding class is not yet loaded the breakpoint will activate on - * class load. - * - * @param line the line id to create the breakpoint on - * @param dbg the {@link Debugger} - */ - public LineBreakpoint(LineID line, Debugger dbg) { - this.line = line; - line.startTracking(dbg.editor().getTab(line.fileName()).getDocument()); - this.dbg = dbg; - theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded - set(); // activate the breakpoint (show highlight, attach if debugger is running) - } - - /** - * Create a {@link LineBreakpoint} on a line in the current tab. - * - * @param lineIdx the line index of the current tab to create the breakpoint - * on - * @param dbg the {@link Debugger} - */ - // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)} - public LineBreakpoint(int lineIdx, Debugger dbg) { - this(dbg.editor().getLineIDInCurrentTab(lineIdx), dbg); - } - - /** - * Get the line id this breakpoint is on. - * - * @return the line id - */ - public LineID lineID() { - return line; - } - - /** - * Test if this breakpoint is on a certain line. - * - * @param testLine the line id to test - * @return true if this breakpoint is on the given line - */ - public boolean isOnLine(LineID testLine) { - return line.equals(testLine); - } - - /** - * Attach this breakpoint to the VM. Creates and enables a - * {@link BreakpointRequest}. VM needs to be paused. - */ - protected void attach() { - if (!dbg.isPaused()) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, debugger not paused"); - return; - } - - if (theClass == null) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, class not loaded: {0}", className()); - return; - } - - // find line in java space - LineID javaLine = dbg.sketchToJavaLine(line); - if (javaLine == null) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "couldn't find line {0} in the java code", line); - return; - } - try { - List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); - if (locations.isEmpty()) { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); - return; - } - // use first found location - bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0)); - bpr.enable(); - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "attached breakpoint to {0} -> {1}", new Object[]{line, javaLine}); - } catch (AbsentInformationException ex) { - Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex); - } - } - - /** - * Detach this breakpoint from the VM. Deletes the - * {@link BreakpointRequest}. - */ - protected void detach() { - if (bpr != null) { - dbg.vm().eventRequestManager().deleteEventRequest(bpr); - bpr = null; - } - } - - /** - * Set this breakpoint. Adds the line highlight. If Debugger is paused also - * attaches the breakpoint by calling {@link #attach()}. - */ - protected void set() { - dbg.addClassLoadListener(this); // class may not yet be loaded - dbg.editor().addBreakpointedLine(line); - if (theClass != null && dbg.isPaused()) { // class is loaded - // immediately activate the breakpoint - attach(); - } - if (dbg.editor().isInCurrentTab(line)) { - dbg.editor().getSketch().setModified(true); - } - } - - /** - * Remove this breakpoint. Clears the highlight and detaches the breakpoint - * if the debugger is paused. - */ - public void remove() { - dbg.removeClassLoadListener(this); - //System.out.println("removing " + line.lineIdx()); - dbg.editor().removeBreakpointedLine(line.lineIdx()); - if (dbg.isPaused()) { - // immediately remove the breakpoint - detach(); - } - line.stopTracking(); - if (dbg.editor().isInCurrentTab(line)) { - dbg.editor().getSketch().setModified(true); - } - } - -// public void enable() { -// } -// -// public void disable() { -// } - @Override - public String toString() { - return line.toString(); - } - - /** - * Get the name of the class this breakpoint belongs to. Needed for fetching - * the right location to create a breakpoint request. - * - * @return the class name - */ - protected String className() { - if (line.fileName().endsWith(".pde")) { - // standard tab - ReferenceType mainClass = dbg.getMainClass(); - if (mainClass == null) { - return null; - } - return dbg.getMainClass().name(); - } - - if (line.fileName().endsWith(".java")) { - // pure java tab - return line.fileName().substring(0, line.fileName().lastIndexOf(".java")); - } - - return null; - } - - /** - * Event handler called when a class is loaded in the debugger. Causes the - * breakpoint to be attached, if its class was loaded. - * - * @param theClass the class that was just loaded. - */ - @Override - public void classLoaded(ReferenceType theClass) { - // check if our class is being loaded - if (theClass.name().equals(className())) { - this.theClass = theClass; - attach(); - } - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/LineHighlight.java b/pdex/experimental/src/processing/mode/experimental/LineHighlight.java deleted file mode 100755 index c1789cf24..000000000 --- a/pdex/experimental/src/processing/mode/experimental/LineHighlight.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.awt.Color; -import java.util.HashSet; -import java.util.Set; - -/** - * Model/Controller for a highlighted source code line. Implements a custom - * background color and a text based marker placed in the left-hand gutter area. - * - * @author Martin Leopold - */ -public class LineHighlight implements LineListener { - - protected DebugEditor editor; // the view, used for highlighting lines by setting a background color - protected Color bgColor; // the background color for highlighting lines - protected LineID lineID; // the id of the line - protected String marker; // - protected Color markerColor; - protected int priority = 0; - protected static Set allHighlights = new HashSet(); - - protected static boolean isHighestPriority(LineHighlight hl) { - for (LineHighlight check : allHighlights) { - if (check.lineID().equals(hl.lineID()) && check.priority() > hl.priority()) { - return false; - } - } - return true; - } - - /** - * Create a {@link LineHighlight}. - * - * @param lineID the line id to highlight - * @param bgColor the background color used for highlighting - * @param editor the {@link DebugEditor} - */ - public LineHighlight(LineID lineID, Color bgColor, DebugEditor editor) { - this.lineID = lineID; - this.bgColor = bgColor; - this.editor = editor; - lineID.addListener(this); - lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc? - paint(); // already checks if on current tab - allHighlights.add(this); - } - - public void setPriority(int p) { - this.priority = p; - } - - public int priority() { - return priority; - } - - /** - * Create a {@link LineHighlight} on the current tab. - * - * @param lineIdx the line index on the current tab to highlight - * @param bgColor the background color used for highlighting - * @param editor the {@link DebugEditor} - */ - // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, DebugEditor editor)} - public LineHighlight(int lineIdx, Color bgColor, DebugEditor editor) { - this(editor.getLineIDInCurrentTab(lineIdx), bgColor, editor); - } - - /** - * Set a text based marker displayed in the left hand gutter area of this - * highlighted line. - * - * @param marker the marker text - */ - public void setMarker(String marker) { - this.marker = marker; - paint(); - } - - /** - * Set a text based marker displayed in the left hand gutter area of this - * highlighted line. Also use a custom text color. - * - * @param marker the marker text - * @param markerColor the text color - */ - public void setMarker(String marker, Color markerColor) { - this.markerColor = markerColor; - setMarker(marker); - } - - /** - * Retrieve the line id of this {@link LineHighlight}. - * - * @return the line id - */ - public LineID lineID() { - return lineID; - } - - /** - * Retrieve the color for highlighting this line. - * - * @return the highlight color. - */ - public Color getColor() { - return bgColor; - } - - /** - * Test if this highlight is on a certain line. - * - * @param testLine the line to test - * @return true if this highlight is on the given line - */ - public boolean isOnLine(LineID testLine) { - return lineID.equals(testLine); - } - - /** - * Event handler for line number changes (due to editing). Will remove the - * highlight from the old line number and repaint it at the new location. - * - * @param line the line that has changed - * @param oldLineIdx the old line index (0-based) - * @param newLineIdx the new line index (0-based) - */ - @Override - public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { - // clear old line - if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { - editor.textArea().clearLineBgColor(oldLineIdx); - editor.textArea().clearGutterText(oldLineIdx); - } - - // paint new line - // but only if it's on top -> fixes current line being hidden by breakpoint moving it down. - // lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...) - if (LineHighlight.isHighestPriority(this)) { - paint(); - } - } - - /** - * Notify this line highlight that it is no longer used. Call this for - * cleanup before the {@link LineHighlight} is discarded. - */ - public void dispose() { - lineID.removeListener(this); - lineID.stopTracking(); - allHighlights.remove(this); - } - - /** - * (Re-)paint this line highlight. - */ - public void paint() { - if (editor.isInCurrentTab(lineID)) { - editor.textArea().setLineBgColor(lineID.lineIdx(), bgColor); - if (marker != null) { - if (markerColor != null) { - editor.textArea().setGutterText(lineID.lineIdx(), marker, markerColor); - } else { - editor.textArea().setGutterText(lineID.lineIdx(), marker); - } - } - } - } - - /** - * Clear this line highlight. - */ - public void clear() { - if (editor.isInCurrentTab(lineID)) { - editor.textArea().clearLineBgColor(lineID.lineIdx()); - editor.textArea().clearGutterText(lineID.lineIdx()); - } - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/LineID.java b/pdex/experimental/src/processing/mode/experimental/LineID.java deleted file mode 100755 index a08d21296..000000000 --- a/pdex/experimental/src/processing/mode/experimental/LineID.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.util.HashSet; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.Element; -import javax.swing.text.Position; - -/** - * Describes an ID for a code line. Comprised of a file name and a (0-based) - * line number. Can track changes to the line number due to text editing by - * attaching a {@link Document}. Registered {@link LineListener}s are notified - * of changes to the line number. - * - * @author Martin Leopold - */ -public class LineID implements DocumentListener { - - protected String fileName; // the filename - protected int lineIdx; // the line number, 0-based - protected Document doc; // the Document to use for line number tracking - protected Position pos; // the Position acquired during line number tracking - protected Set listeners = new HashSet(); // listeners for line number changes - - public LineID(String fileName, int lineIdx) { - this.fileName = fileName; - this.lineIdx = lineIdx; - } - - /** - * Get the file name of this line. - * - * @return the file name - */ - public String fileName() { - return fileName; - } - - /** - * Get the (0-based) line number of this line. - * - * @return the line index (i.e. line number, starting at 0) - */ - public synchronized int lineIdx() { - return lineIdx; - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - /** - * Test whether this {@link LineID} is equal to another object. Two - * {@link LineID}'s are equal when both their fileName and lineNo are equal. - * - * @param obj the object to test for equality - * @return {@code true} if equal - */ - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final LineID other = (LineID) obj; - if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) { - return false; - } - if (this.lineIdx != other.lineIdx) { - return false; - } - return true; - } - - /** - * Output a string representation in the form fileName:lineIdx+1. Note this - * uses a 1-based line number as is customary for human-readable line - * numbers. - * - * @return the string representation of this line ID - */ - @Override - public String toString() { - return fileName + ":" + (lineIdx + 1); - } - -// /** -// * Retrieve a copy of this line ID. -// * -// * @return the copy -// */ -// @Override -// public LineID clone() { -// return new LineID(fileName, lineIdx); -// } - - /** - * Attach a {@link Document} to enable line number tracking when editing. - * The position to track is before the first non-whitespace character on the - * line. Edits happening before that position will cause the line number to - * update accordingly. Multiple {@link #startTracking} calls will replace - * the tracked document. Whoever wants a tracked line should track it and - * add itself as listener if necessary. - * ({@link LineHighlight}, {@link LineBreakpoint}) - * - * @param doc the {@link Document} to use for line number tracking - */ - public synchronized void startTracking(Document doc) { - //System.out.println("tracking: " + this); - if (doc == null) { - return; // null arg - } - if (doc == this.doc) { - return; // already tracking that doc - } - try { - Element line = doc.getDefaultRootElement().getElement(lineIdx); - if (line == null) { - return; // line doesn't exist - } - String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset()); - // set tracking position at (=before) first non-white space character on line - pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText)); - this.doc = doc; - doc.addDocumentListener(this); - } catch (BadLocationException ex) { - Logger.getLogger(LineID.class.getName()).log(Level.SEVERE, null, ex); - pos = null; - this.doc = null; - } - } - - /** - * Notify this {@link LineID} that it is no longer in use. Will stop - * position tracking. Call this when this {@link LineID} is no longer - * needed. - */ - public synchronized void stopTracking() { - if (doc != null) { - doc.removeDocumentListener(this); - doc = null; - } - } - - /** - * Update the tracked position. Will notify listeners if line number has - * changed. - */ - protected synchronized void updatePosition() { - if (doc != null && pos != null) { - // track position - int offset = pos.getOffset(); - int oldLineIdx = lineIdx; - lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo - if (lineIdx != oldLineIdx) { - for (LineListener l : listeners) { - if (l != null) { - l.lineChanged(this, oldLineIdx, lineIdx); - } else { - listeners.remove(l); // remove null listener - } - } - } - } - } - - /** - * Add listener to be notified when the line number changes. - * - * @param l the listener to add - */ - public void addListener(LineListener l) { - listeners.add(l); - } - - /** - * Remove a listener for line number changes. - * - * @param l the listener to remove - */ - public void removeListener(LineListener l) { - listeners.remove(l); - } - - /** - * Calculate the offset of the first non-whitespace character in a string. - * - * @param str the string to examine - * @return offset of first non-whitespace character in str - */ - protected static int nonWhiteSpaceOffset(String str) { - for (int i = 0; i < str.length(); i++) { - if (!Character.isWhitespace(str.charAt(i))) { - return i; - } - } - return str.length(); - } - - /** - * Called when the {@link Document} registered using {@link #startTracking} - * is edited. This happens when text is inserted or removed. - * - * @param de - */ - protected void editEvent(DocumentEvent de) { - //System.out.println("document edit @ " + de.getOffset()); - if (de.getOffset() <= pos.getOffset()) { - updatePosition(); - //System.out.println("updating, new line no: " + lineNo); - } - } - - /** - * {@link DocumentListener} callback. Called when text is inserted. - * - * @param de - */ - @Override - public void insertUpdate(DocumentEvent de) { - editEvent(de); - } - - /** - * {@link DocumentListener} callback. Called when text is removed. - * - * @param de - */ - @Override - public void removeUpdate(DocumentEvent de) { - editEvent(de); - } - - /** - * {@link DocumentListener} callback. Called when attributes are changed. - * Not used. - * - * @param de - */ - @Override - public void changedUpdate(DocumentEvent de) { - // not needed. - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/LineListener.java b/pdex/experimental/src/processing/mode/experimental/LineListener.java deleted file mode 100755 index c6c3ae1b0..000000000 --- a/pdex/experimental/src/processing/mode/experimental/LineListener.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -/** - * A Listener for line number changes. - * - * @author Martin Leopold - */ -public interface LineListener { - - /** - * Event handler for line number changes (due to editing). - * - * @param line the line that has changed - * @param oldLineIdx the old line index (0-based) - * @param newLineIdx the new line index (0-based) - */ - void lineChanged(LineID line, int oldLineIdx, int newLineIdx); -} diff --git a/pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java b/pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java deleted file mode 100755 index d1bdb2092..000000000 --- a/pdex/experimental/src/processing/mode/experimental/LocalVariableNode.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.ClassNotLoadedException; -import com.sun.jdi.InvalidTypeException; -import com.sun.jdi.LocalVariable; -import com.sun.jdi.StackFrame; -import com.sun.jdi.Value; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Specialized {@link VariableNode} for representing local variables. Overrides - * {@link #setValue} to properly change the value of the encapsulated local - * variable. - * - * @author Martin Leopold - */ -public class LocalVariableNode extends VariableNode { - - protected LocalVariable var; - protected StackFrame frame; - - /** - * Construct a {@link LocalVariableNode}. - * - * @param name the name - * @param type the type - * @param value the value - * @param var the local variable - * @param frame the stack frame containing the local variable - */ - public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) { - super(name, type, value); - this.var = var; - this.frame = frame; - } - - @Override - public void setValue(Value value) { - try { - frame.setValue(var, value); - } catch (InvalidTypeException ex) { - Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); - } catch (ClassNotLoadedException ex) { - Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex); - } - this.value = value; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/Problem.java b/pdex/experimental/src/processing/mode/experimental/Problem.java deleted file mode 100644 index 56cc0e833..000000000 --- a/pdex/experimental/src/processing/mode/experimental/Problem.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package processing.mode.experimental; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jdt.core.compiler.IProblem; - -/** - * Wrapper class for IProblem. - * - * Stores the tabIndex and line number according to its tab, including the - * original IProblem object - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ -public class Problem { - /** - * The IProblem which is being wrapped - */ - private IProblem iProblem; - /** - * The tab number to which the error belongs to - */ - public int tabIndex; - /** - * Line number(pde code) of the error - */ - public int lineNumber; - - /** - * Error Message. Processed form of IProblem.getMessage() - */ - public String message; - - /** - * The type of error - WARNING or ERROR. - */ - public int type; - - public static final int ERROR = 1, WARNING = 2; - - /** - * - * @param iProblem - The IProblem which is being wrapped - * @param tabIndex - The tab number to which the error belongs to - * @param lineNumber - Line number(pde code) of the error - */ - public Problem(IProblem iProblem, int tabIndex, int lineNumber) { - this.iProblem = iProblem; - if(iProblem.isError()) { - type = ERROR; - } - else if(iProblem.isWarning()) { - type = WARNING; - } - this.tabIndex = tabIndex; - this.lineNumber = lineNumber; - this.message = process(iProblem); - } - - public String toString() { - return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: " - + message); - } - - public boolean isError(){ - return type == ERROR; - } - - public boolean isWarning(){ - return type == WARNING; - } - - public String getMessage(){ - return message; - } - - public IProblem getIProblem(){ - return iProblem; - } - - public void setType(int ProblemType){ - if(ProblemType == ERROR) - type = ERROR; - else if(ProblemType == WARNING) - type = WARNING; - else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)"); - } - - private static Pattern pattern; - private static Matcher matcher; - - private static final String tokenRegExp = "\\b token\\b"; - - public static String process(IProblem problem) { - return process(problem.getMessage()); - } - - /** - * Processes error messages and attempts to make them a bit more english like. - * Currently performs: - *
  • Remove all instances of token. "Syntax error on token 'blah', delete this token" - * becomes "Syntax error on 'blah', delete this" - * @param message - The message to be processed - * @return String - The processed message - */ - public static String process(String message) { - // Remove all instances of token - // "Syntax error on token 'blah', delete this token" - if(message == null) return null; - pattern = Pattern.compile(tokenRegExp); - matcher = pattern.matcher(message); - message = matcher.replaceAll(""); - - return message; - } - - // Split camel case words into separate words. - // "VaraibleDeclaration" becomes "Variable Declaration" - // But sadly "PApplet" become "P Applet" and so on. - public static String splitCamelCaseWord(String word) { - String newWord = ""; - for (int i = 1; i < word.length(); i++) { - if (Character.isUpperCase(word.charAt(i))) { - // System.out.println(word.substring(0, i) + " " - // + word.substring(i)); - newWord += word.substring(0, i) + " "; - word = word.substring(i); - i = 1; - } - } - newWord += word; - // System.out.println(newWord); - return newWord.trim(); - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/TextArea.java b/pdex/experimental/src/processing/mode/experimental/TextArea.java deleted file mode 100644 index e07cda0b3..000000000 --- a/pdex/experimental/src/processing/mode/experimental/TextArea.java +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.awt.Color; -import java.awt.Cursor; -import java.awt.FontMetrics; -import java.awt.Point; -import java.awt.event.ComponentListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.SwingUtilities; -import javax.swing.text.BadLocationException; - -import processing.app.syntax.JEditTextArea; -import processing.app.syntax.TextAreaDefaults; - -/** - * Customized text area. Adds support for line background colors. - * - * @author Martin Leopold - */ -public class TextArea extends JEditTextArea { - - protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler - - protected DebugEditor editor; // the editor - - // line properties - protected Map lineColors = new HashMap(); // contains line background colors - - // left-hand gutter properties - protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars - - protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color - - protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line - - protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter - - protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter - - protected Map gutterText = new HashMap(); // maps line index to gutter text - - protected Map gutterTextColors = new HashMap(); // maps line index to gutter text color - - protected TextAreaPainter customPainter; - - protected ErrorCheckerService errorCheckerService; - - public TextArea(TextAreaDefaults defaults, DebugEditor editor) { - super(defaults); - this.editor = editor; - - // replace the painter: - // first save listeners, these are package-private in JEditTextArea, so not accessible - ComponentListener[] componentListeners = painter.getComponentListeners(); - mouseListeners = painter.getMouseListeners(); - MouseMotionListener[] mouseMotionListeners = painter - .getMouseMotionListeners(); - - remove(painter); - - // set new painter - customPainter = new TextAreaPainter(this, defaults); - painter = customPainter; - - // set listeners - for (ComponentListener cl : componentListeners) { - painter.addComponentListener(cl); - } - - for (MouseMotionListener mml : mouseMotionListeners) { - painter.addMouseMotionListener(mml); - } - - // use a custom mouse handler instead of directly using mouseListeners - MouseHandler mouseHandler = new MouseHandler(); - painter.addMouseListener(mouseHandler); - painter.addMouseMotionListener(mouseHandler); - addCompletionPopupListner(); - add(CENTER, painter); - - // load settings from theme.txt - ExperimentalMode theme = (ExperimentalMode) editor.getMode(); - gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor); - gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor); - gutterPadding = theme.getInteger("gutter.padding"); - breakpointMarker = theme.loadThemeString("breakpoint.marker", - breakpointMarker); - currentLineMarker = theme.loadThemeString("currentline.marker", - currentLineMarker); - } - - /** - * Sets ErrorCheckerService and loads theme for TextArea(XQMode) - * - * @param ecs - * @param mode - */ - public void setECSandThemeforTextArea(ErrorCheckerService ecs, - ExperimentalMode mode) { - errorCheckerService = ecs; - customPainter.setECSandTheme(ecs, mode); - } - - public void processKeyEvent(KeyEvent evt) { - if (evt.getID() == KeyEvent.KEY_PRESSED) { - if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { - if (suggestion.isVisible()) { - //System.out.println("KeyDown"); - suggestion.moveDown(); - return; - } - } else if (evt.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { - if (suggestion.isVisible()) { - //System.out.println("KeyUp"); - suggestion.moveUp(); - return; - } - } - if (evt.getKeyChar() == KeyEvent.VK_ENTER) { - if (suggestion != null) { - if (suggestion.isVisible()){ - if (suggestion.insertSelection()) { - final int position = getCaretPosition(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - //getDocument().remove(position - 1, 1); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - return; - } - } - } - } else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) { - System.out.println("BK Key"); - } - } - - super.processKeyEvent(evt); - if (evt.getID() == KeyEvent.KEY_TYPED) { - errorCheckerService.textModified.incrementAndGet(); - System.out.println(" Typing: " + fetchPhrase(evt) + " " - + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); - - } - - } - - private String fetchPhrase(KeyEvent evt) { - int off = getCaretPosition(); - System.out.print("off " + off); - if (off < 0) - return null; - int line = getCaretLine(); - if (line < 0) - return null; - String s = getLineText(line); - System.out.print("lin " + line); - /* - * if (s == null) return null; else if (s.length() == 0) return null; - */ -// else { - //System.out.print(s + " len " + s.length()); - - int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; - if(x >= s.length() || x < 0) - return null; //TODO: Does this check cause problems? Verify. - System.out.print(" x char: " + s.charAt(x)); - //int xLS = off - getLineStartNonWhiteSpaceOffset(line); - char keyChar = evt.getKeyChar(); - if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) - ; // accepted these keys - else if (keyChar == KeyEvent.CHAR_UNDEFINED) - - return null; - - String word = (x < s.length() ? s.charAt(x) : "") + ""; - if (s.trim().length() == 1) { -// word = "" -// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); - //word = (x < s.length()?s.charAt(x):"") + ""; - word = word.trim(); - if (word.endsWith(".")) - word = word.substring(0, word.length() - 1); - errorCheckerService.astGenerator.updatePredictions(word, line - + errorCheckerService.mainClassOffset); - return word; - } -// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) -// ; // accepted these keys -// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) -// return null; - int i = 0; - int closeB = 0; - - while (true) { - i++; - //TODO: currently works on single line only. "a. b()" won't be detected - if (x1 >= 0) { -// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') - if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' - || s.charAt(x1) == '.' || s.charAt(x1) == ')') { - - if (s.charAt(x1) == ')') { - word = s.charAt(x1--) + word; - closeB++; - while (x1 >= 0 && closeB > 0) { - word = s.charAt(x1) + word; - if (s.charAt(x1) == '(') - closeB--; - if (s.charAt(x1) == ')') - closeB++; - x1--; - } - } else { - word = s.charAt(x1--) + word; - } - } else { - break; - } - } else { - break; - } - -// if (x2 >= 0 && x2 < s.length()) { -// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' -// || s.charAt(x2) == '$') -// word = word + s.charAt(x2++); -// else -// x2 = -1; -// } else -// x2 = -1; - -// if (x1 < 0 )//&& x2 < 0 -// break; - if (i > 200) { - // time out! - System.err.println("Whoopsy! :P"); - break; - } - } -// if (keyChar != KeyEvent.CHAR_UNDEFINED) - - if (Character.isDigit(word.charAt(0))) - return null; - word = word.trim(); -// if (word.endsWith(".")) -// word = word.substring(0, word.length() - 1); - errorCheckerService.astGenerator.updatePredictions(word, line - + errorCheckerService.mainClassOffset); - //showSuggestionLater(); - return word; - - //} - } - - /** - * Retrieve the total width of the gutter area. - * - * @return gutter width in pixels - */ - protected int getGutterWidth() { - FontMetrics fm = painter.getFontMetrics(); -// System.out.println("fm: " + (fm == null)); -// System.out.println("editor: " + (editor == null)); - //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); - - int textWidth = Math.max(fm.stringWidth(breakpointMarker), - fm.stringWidth(currentLineMarker)); - return textWidth + 2 * gutterPadding; - } - - /** - * Retrieve the width of margins applied to the left and right of the gutter - * text. - * - * @return margins in pixels - */ - protected int getGutterMargins() { - return gutterPadding; - } - - /** - * Set the gutter text of a specific line. - * - * @param lineIdx - * the line index (0-based) - * @param text - * the text - */ - public void setGutterText(int lineIdx, String text) { - gutterText.put(lineIdx, text); - painter.invalidateLine(lineIdx); - } - - /** - * Set the gutter text and color of a specific line. - * - * @param lineIdx - * the line index (0-based) - * @param text - * the text - * @param textColor - * the text color - */ - public void setGutterText(int lineIdx, String text, Color textColor) { - gutterTextColors.put(lineIdx, textColor); - setGutterText(lineIdx, text); - } - - /** - * Clear the gutter text of a specific line. - * - * @param lineIdx - * the line index (0-based) - */ - public void clearGutterText(int lineIdx) { - gutterText.remove(lineIdx); - painter.invalidateLine(lineIdx); - } - - /** - * Clear all gutter text. - */ - public void clearGutterText() { - for (int lineIdx : gutterText.keySet()) { - painter.invalidateLine(lineIdx); - } - gutterText.clear(); - } - - /** - * Retrieve the gutter text of a specific line. - * - * @param lineIdx - * the line index (0-based) - * @return the gutter text - */ - public String getGutterText(int lineIdx) { - return gutterText.get(lineIdx); - } - - /** - * Retrieve the gutter text color for a specific line. - * - * @param lineIdx - * the line index - * @return the gutter text color - */ - public Color getGutterTextColor(int lineIdx) { - return gutterTextColors.get(lineIdx); - } - - /** - * Set the background color of a line. - * - * @param lineIdx - * 0-based line number - * @param col - * the background color to set - */ - public void setLineBgColor(int lineIdx, Color col) { - lineColors.put(lineIdx, col); - painter.invalidateLine(lineIdx); - } - - /** - * Clear the background color of a line. - * - * @param lineIdx - * 0-based line number - */ - public void clearLineBgColor(int lineIdx) { - lineColors.remove(lineIdx); - painter.invalidateLine(lineIdx); - } - - /** - * Clear all line background colors. - */ - public void clearLineBgColors() { - for (int lineIdx : lineColors.keySet()) { - painter.invalidateLine(lineIdx); - } - lineColors.clear(); - } - - /** - * Get a lines background color. - * - * @param lineIdx - * 0-based line number - * @return the color or null if no color was set for the specified line - */ - public Color getLineBgColor(int lineIdx) { - return lineColors.get(lineIdx); - } - - /** - * Convert a character offset to a horizontal pixel position inside the text - * area. Overridden to take gutter width into account. - * - * @param line - * the 0-based line number - * @param offset - * the character offset (0 is the first character on a line) - * @return the horizontal position - */ - @Override - public int _offsetToX(int line, int offset) { - return super._offsetToX(line, offset) + getGutterWidth(); - } - - /** - * Convert a horizontal pixel position to a character offset. Overridden to - * take gutter width into account. - * - * @param line - * the 0-based line number - * @param x - * the horizontal pixel position - * @return he character offset (0 is the first character on a line) - */ - @Override - public int xToOffset(int line, int x) { - return super.xToOffset(line, x - getGutterWidth()); - } - - /** - * Custom mouse handler. Implements double clicking in the gutter area to - * toggle breakpoints, sets default cursor (instead of text cursor) in the - * gutter area. - */ - protected class MouseHandler implements MouseListener, MouseMotionListener { - - protected int lastX; // previous horizontal positon of the mouse cursor - - @Override - public void mouseClicked(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseClicked(me); - } - } - - @Override - public void mousePressed(MouseEvent me) { - // check if this happened in the gutter area - if (me.getX() < getGutterWidth()) { - if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { - int line = me.getY() / painter.getFontMetrics().getHeight() - + firstLine; - if (line >= 0 && line <= getLineCount() - 1) { - editor.gutterDblClicked(line); - } - } - } else { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mousePressed(me); - } - } - } - - @Override - public void mouseReleased(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseReleased(me); - } - } - - @Override - public void mouseEntered(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseEntered(me); - } - } - - @Override - public void mouseExited(MouseEvent me) { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mouseExited(me); - } - } - - @Override - public void mouseDragged(MouseEvent me) { - // No need to forward since the standard MouseMotionListeners are called anyway - // nop - } - - @Override - public void mouseMoved(MouseEvent me) { - // No need to forward since the standard MouseMotionListeners are called anyway - if (me.getX() < getGutterWidth()) { - if (lastX >= getGutterWidth()) { - painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } else { - if (lastX < getGutterWidth()) { - painter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); - } - } - lastX = me.getX(); - } - } - - private CompletionPanel suggestion; - - //JEditTextArea textarea; - - private void addCompletionPopupListner() { - this.addKeyListener(new KeyListener() { - - @Override - public void keyTyped(KeyEvent e) { - - } - - @Override - public void keyReleased(KeyEvent e) { - if (Character.isLetterOrDigit(e.getKeyChar()) - || e.getKeyChar() == KeyEvent.VK_BACK_SPACE - || e.getKeyChar() == KeyEvent.VK_DELETE) { -// SwingUtilities.invokeLater(new Runnable() { -// @Override -// public void run() { -// showSuggestion(); -// } -// -// }); - } else if (Character.isWhitespace(e.getKeyChar())) { - hideSuggestion(); - } - } - - @Override - public void keyPressed(KeyEvent e) { - } - }); - } - - public void showSuggestionLater(final CompletionCandidate[] items) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - showSuggestion(items); - } - - }); - } - - protected void showSuggestion(CompletionCandidate[] items) { - hideSuggestion(); - final int position = getCaretPosition(); - Point location = new Point(); - try { - location.x = offsetToX(getCaretLine(), position - - getLineStartOffset(getCaretLine())); - location.y = lineToY(getCaretLine()) - + getPainter().getFontMetrics().getHeight(); - } catch (Exception e2) { - e2.printStackTrace(); - return; - } - String text = getText(); - int start = Math.max(0, position - 1); - while (start > 0) { - if (!Character.isWhitespace(text.charAt(start))) { - start--; - } else { - start++; - break; - } - } - if (start > position) { - return; - } - final String subWord = text.substring(start, position); - if (subWord.length() < 2) { - return; - } - suggestion = new CompletionPanel(this, position, subWord, items, location); -// requestFocusInWindow(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - requestFocusInWindow(); - } - }); - } - - private void hideSuggestion() { - if (suggestion != null) { - suggestion.hide(); - } - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java b/pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java deleted file mode 100644 index 9ee6b9539..000000000 --- a/pdex/experimental/src/processing/mode/experimental/TextAreaPainter.java +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Toolkit; -import java.awt.event.InputEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -import javax.swing.text.BadLocationException; -import javax.swing.text.Segment; -import javax.swing.text.Utilities; - -import processing.app.syntax.TextAreaDefaults; -import processing.app.syntax.TokenMarker; - -/** - * Customized line painter. Adds support for background colors, left hand gutter - * area with background color and text. - * - * @author Martin Leopold - */ -public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { - - protected TextArea ta; // we need the subclassed textarea - - protected ErrorCheckerService errorCheckerService; - - /** - * Error line underline color - */ - public Color errorColor = new Color(0xED2630); - - /** - * Warning line underline color - */ - - public Color warningColor = new Color(0xFFC30E); - - /** - * Color of Error Marker - */ - public Color errorMarkerColor = new Color(0xED2630); - - /** - * Color of Warning Marker - */ - public Color warningMarkerColor = new Color(0xFFC30E); - - static int ctrlMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - - public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) { - super(textArea, defaults); - ta = textArea; - addMouseListener(new MouseAdapter() { - public void mouseClicked(MouseEvent evt) { -// System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); - if (evt.isControlDown()) - handleCtrlClick(evt); - } - }); - - } - -// public void processKeyEvent(KeyEvent evt) { -// System.out.println(evt); -// } - - void handleCtrlClick(MouseEvent evt) { - System.out.println("--handleCtrlClick--"); - int off = ta.xyToOffset(evt.getX(), evt.getY()); - if (off < 0) - return; - int line = ta.getLineOfOffset(off); - if (line < 0) - return; - String s = ta.getLineText(line); - if (s == null) - return; - else if (s.length() == 0) - return; - else { - int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; - int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); - if (x < 0 || x >= s.length()) - return; - String word = s.charAt(x) + ""; - if (s.charAt(x) == ' ') - return; - if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s - .charAt(x) == '$')) - return; - int i = 0; - while (true) { - i++; - if (x1 >= 0 && x1 < s.length()) { - if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { - word = s.charAt(x1--) + word; - } else - x1 = -1; - } else - x1 = -1; - - if (x2 >= 0 && x2 < s.length()) { - if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' - || s.charAt(x2) == '$') - word = word + s.charAt(x2++); - else - x2 = -1; - } else - x2 = -1; - - if (x1 < 0 && x2 < 0) - break; - if (i > 200) { - // time out! - System.err.println("Whoopsy! :P"); - break; - } - } - if (Character.isDigit(word.charAt(0))) - return; - - System.out.print(errorCheckerService.mainClassOffset + line); - System.out.print("|" + line + "| offset " + xLS + word + " <= \n"); - errorCheckerService.astGenerator.scrollToDeclaration(line - + errorCheckerService.mainClassOffset, word, xLS); - } - } - - private void loadTheme(ExperimentalMode mode) { - errorColor = mode.getThemeColor("editor.errorcolor", errorColor); - warningColor = mode.getThemeColor("editor.warningcolor", warningColor); - errorMarkerColor = mode.getThemeColor("editor.errormarkercolor", - errorMarkerColor); - warningMarkerColor = mode.getThemeColor("editor.warningmarkercolor", - warningMarkerColor); - } - - /** - * Paint a line. Paints the gutter (with background color and text) then the - * line (background color and text). - * - * @param gfx - * the graphics context - * @param tokenMarker - * @param line - * 0-based line number - * @param x - * horizontal position - */ - @Override - protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, - int x) { - - // paint gutter - paintGutterBg(gfx, line, x); - - paintLineBgColor(gfx, line, x + ta.getGutterWidth()); - - paintGutterLine(gfx, line, x); - - // paint gutter symbol - paintGutterText(gfx, line, x); - - paintErrorLine(gfx, line, x); - - super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); - } - - /** - * Paint the gutter background (solid color). - * - * @param gfx - * the graphics context - * @param line - * 0-based line number - * @param x - * horizontal position - */ - protected void paintGutterBg(Graphics gfx, int line, int x) { - gfx.setColor(ta.gutterBgColor); - int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); - gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight()); - } - - /** - * Paint the vertical gutter separator line. - * - * @param gfx - * the graphics context - * @param line - * 0-based line number - * @param x - * horizontal position - */ - protected void paintGutterLine(Graphics gfx, int line, int x) { - int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent(); - gfx.setColor(ta.gutterLineColor); - gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(), - y + fm.getHeight()); - } - - /** - * Paint the gutter text. - * - * @param gfx - * the graphics context - * @param line - * 0-based line number - * @param x - * horizontal position - */ - protected void paintGutterText(Graphics gfx, int line, int x) { - String text = ta.getGutterText(line); - if (text == null) { - return; - } - - gfx.setFont(getFont()); - Color textColor = ta.getGutterTextColor(line); - if (textColor == null) { - gfx.setColor(getForeground()); - } else { - gfx.setColor(textColor); - } - int y = ta.lineToY(line) + fm.getHeight(); - - // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right. - //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length(); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), - ta.getGutterMargins(), y, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), - ta.getGutterMargins() + 1, y, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), - ta.getGutterMargins(), y + 1, gfx, this, 0); - Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()), - ta.getGutterMargins() + 1, y + 1, gfx, this, 0); - } - - /** - * Paint the background color of a line. - * - * @param gfx - * the graphics context - * @param line - * 0-based line number - * @param x - */ - protected void paintLineBgColor(Graphics gfx, int line, int x) { - int y = ta.lineToY(line); - y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); - - // get the color - Color col = ta.getLineBgColor(line); - //System.out.print("bg line " + line + ": "); - // no need to paint anything - if (col == null) { - //System.out.println("none"); - return; - } - // paint line background - gfx.setColor(col); - gfx.fillRect(0, y, getWidth(), height); - } - - /** - * Paints the underline for an error/warning line - * - * @param gfx - * the graphics context - * @param tokenMarker - * @param line - * 0-based line number: NOTE - * @param x - */ - protected void paintErrorLine(Graphics gfx, int line, int x) { - - if (errorCheckerService == null) { - return; - } - - if (errorCheckerService.problemsList == null) { - return; - } - - boolean notFound = true; - boolean isWarning = false; - - // Check if current line contains an error. If it does, find if it's an - // error or warning - for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { - if (emarker.problem.lineNumber == line + 1) { - notFound = false; - if (emarker.type == ErrorMarker.Warning) { - isWarning = true; - } - break; - } - } - - if (notFound) { - return; - } - - // Determine co-ordinates - // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + - // horizontalAdjustment); - int y = ta.lineToY(line); - y += fm.getLeading() + fm.getMaxDescent(); - int height = fm.getHeight(); - int start = ta.getLineStartOffset(line); - - try { - String linetext = null; - - try { - linetext = ta.getDocument().getText(start, - ta.getLineStopOffset(line) - start - - 1); - } catch (BadLocationException bl) { - // Error in the import statements or end of code. - // System.out.print("BL caught. " + ta.getLineCount() + " ," - // + line + " ,"); - // System.out.println((ta.getLineStopOffset(line) - start - 1)); - return; - } - - // Take care of offsets - int aw = fm.stringWidth(trimRight(linetext)) + ta.getHorizontalOffset(); // apparent width. Whitespaces - // to the left of line + text - // width - int rw = fm.stringWidth(linetext.trim()); // real width - int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; - // Adding offsets for the gutter - x1 += 20; - x2 += 20; - - // gfx.fillRect(x1, y, rw, height); - - // Let the painting begin! - gfx.setColor(errorMarkerColor); - if (isWarning) { - gfx.setColor(warningMarkerColor); - } - gfx.fillRect(1, y + 2, 3, height - 2); - - gfx.setColor(errorColor); - if (isWarning) { - gfx.setColor(warningColor); - } - int xx = x1; - - // Draw the jagged lines - while (xx < x2) { - gfx.drawLine(xx, y1, xx + 2, y1 + 1); - xx += 2; - gfx.drawLine(xx, y1 + 1, xx + 2, y1); - xx += 2; - } - } catch (Exception e) { - System.out - .println("Looks like I messed up! XQTextAreaPainter.paintLine() : " - + e); - //e.printStackTrace(); - } - - // Won't highlight the line. Select the text instead. - // gfx.setColor(Color.RED); - // gfx.fillRect(2, y, 3, height); - } - - /** - * Trims out trailing whitespaces (to the right) - * - * @param string - * @return - String - */ - private String trimRight(String string) { - String newString = ""; - for (int i = 0; i < string.length(); i++) { - if (string.charAt(i) != ' ') { - newString = string.substring(0, i) + string.trim(); - break; - } - } - return newString; - } - - /** - * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) - * - * @param ecs - * @param mode - */ - public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode) { - this.errorCheckerService = ecs; - loadTheme(mode); - } - - public String getToolTipText(java.awt.event.MouseEvent evt) { - int off = ta.xyToOffset(evt.getX(), evt.getY()); - if (off < 0) - return null; - int line = ta.getLineOfOffset(off); - if (line < 0) - return null; - String s = ta.getLineText(line); - if (s == null) - return evt.toString(); - else if (s.length() == 0) - return null; - else { - int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; - int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); - if (x < 0 || x >= s.length()) - return null; - String word = s.charAt(x) + ""; - if (s.charAt(x) == ' ') - return null; - if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s - .charAt(x) == '$')) - return null; - int i = 0; - while (true) { - i++; - if (x1 >= 0 && x1 < s.length()) { - if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { - word = s.charAt(x1--) + word; - } else - x1 = -1; - } else - x1 = -1; - - if (x2 >= 0 && x2 < s.length()) { - if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' - || s.charAt(x2) == '$') - word = word + s.charAt(x2++); - else - x2 = -1; - } else - x2 = -1; - - if (x1 < 0 && x2 < 0) - break; - if (i > 200) { - // time out! - System.err.println("Whoopsy! :P"); - break; - } - } - if (Character.isDigit(word.charAt(0))) - return null; - String tooltipText = errorCheckerService.astGenerator - .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, - xLS); - - System.out.print(errorCheckerService.mainClassOffset + " MCO "); - System.out.print("|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); - if (tooltipText != null) - return tooltipText; - return word; - } - - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/VMEventListener.java b/pdex/experimental/src/processing/mode/experimental/VMEventListener.java deleted file mode 100755 index 4cc648802..000000000 --- a/pdex/experimental/src/processing/mode/experimental/VMEventListener.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.event.EventSet; - -/** - * Interface for VM callbacks. - * - * @author Martin Leopold - */ -public interface VMEventListener { - - /** - * Receive an event from the VM. Events are sent in batches. See - * documentation of EventSet for more information. - * - * @param es Set of events - */ - void vmEvent(EventSet es); -} diff --git a/pdex/experimental/src/processing/mode/experimental/VMEventReader.java b/pdex/experimental/src/processing/mode/experimental/VMEventReader.java deleted file mode 100755 index c4d05ddf9..000000000 --- a/pdex/experimental/src/processing/mode/experimental/VMEventReader.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.VMDisconnectedException; -import com.sun.jdi.event.EventQueue; -import com.sun.jdi.event.EventSet; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Reader Thread for VM Events. Constantly monitors a VMs EventQueue for new - * events and forwards them to an VMEventListener. - * - * @author Martin Leopold - */ -public class VMEventReader extends Thread { - - EventQueue eventQueue; - VMEventListener listener; - - /** - * Construct a VMEventReader. Needs to be kicked off with start() once - * constructed. - * - * @param eventQueue The queue to read events from. Can be obtained from a - * VirtualMachine via eventQueue(). - * @param listener the listener to forward events to. - */ - public VMEventReader(EventQueue eventQueue, VMEventListener listener) { - super("VM Event Thread"); - this.eventQueue = eventQueue; - this.listener = listener; - } - - @Override - public void run() { - try { - while (true) { - EventSet eventSet = eventQueue.remove(); - listener.vmEvent(eventSet); - /* - * for (Event e : eventSet) { System.out.println("VM Event: " + - * e.toString()); } - */ - } - } catch (VMDisconnectedException e) { - Logger.getLogger(VMEventReader.class.getName()).log(Level.INFO, "VMEventReader quit on VM disconnect"); - } catch (Exception e) { - Logger.getLogger(VMEventReader.class.getName()).log(Level.SEVERE, "VMEventReader quit", e); - } - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/VariableInspector.form b/pdex/experimental/src/processing/mode/experimental/VariableInspector.form deleted file mode 100755 index a5f40f1d3..000000000 --- a/pdex/experimental/src/processing/mode/experimental/VariableInspector.form +++ /dev/null @@ -1,53 +0,0 @@ - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/pdex/experimental/src/processing/mode/experimental/VariableInspector.java b/pdex/experimental/src/processing/mode/experimental/VariableInspector.java deleted file mode 100755 index a38c19a8f..000000000 --- a/pdex/experimental/src/processing/mode/experimental/VariableInspector.java +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.Value; -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.DefaultCellEditor; -import javax.swing.GrayFilter; -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JTable; -import javax.swing.JTextField; -import javax.swing.UIDefaults; -import javax.swing.UIManager; -import javax.swing.event.TreeExpansionEvent; -import javax.swing.event.TreeExpansionListener; -import javax.swing.table.TableColumn; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.ExpandVetoException; -import javax.swing.tree.MutableTreeNode; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; -import org.netbeans.swing.outline.DefaultOutlineCellRenderer; -import org.netbeans.swing.outline.DefaultOutlineModel; -import org.netbeans.swing.outline.ExtTreeWillExpandListener; -import org.netbeans.swing.outline.OutlineModel; -import org.netbeans.swing.outline.RenderDataProvider; -import org.netbeans.swing.outline.RowModel; - -/** - * Variable Inspector window. - * - * @author Martin Leopold - */ -public class VariableInspector extends javax.swing.JFrame { - - protected DefaultMutableTreeNode rootNode; // the root node (invisible) - protected DefaultMutableTreeNode builtins; // node for Processing built-in variables - protected DefaultTreeModel treeModel; // data model for the tree column - protected OutlineModel model; // data model for the whole Outline (tree and other columns) - protected List callStack; // the call stack - protected List locals; // current local variables - protected List thisFields; // all fields of the current this-object - protected List declaredThisFields; // declared i.e. non-inherited fields of this - protected DebugEditor editor; // the editor - protected Debugger dbg; // the debugger - protected List expandedNodes = new ArrayList(); // list of expanded tree paths. (using list to maintain the order of expansion) - protected boolean p5mode = true; // processing / "advanced" mode flag (currently not used - - /** - * Creates new form VariableInspector - */ - public VariableInspector(DebugEditor editor) { - this.editor = editor; - this.dbg = editor.dbg(); - - initComponents(); - - // setup Outline - rootNode = new DefaultMutableTreeNode("root"); - builtins = new DefaultMutableTreeNode("Processing"); - treeModel = new DefaultTreeModel(rootNode); // model for the tree column - model = DefaultOutlineModel.createOutlineModel(treeModel, new VariableRowModel(), true, "Name"); // model for all columns - - ExpansionHandler expansionHandler = new ExpansionHandler(); - model.getTreePathSupport().addTreeWillExpandListener(expansionHandler); - model.getTreePathSupport().addTreeExpansionListener(expansionHandler); - tree.setModel(model); - tree.setRootVisible(false); - tree.setRenderDataProvider(new OutlineRenderer()); - tree.setColumnHidingAllowed(false); // disable visible columns button (shows by default when right scroll bar is visible) - tree.setAutoscrolls(false); - - // set custom renderer and editor for value column, since we are using a custom class for values (VariableNode) - TableColumn valueColumn = tree.getColumnModel().getColumn(1); - valueColumn.setCellRenderer(new ValueCellRenderer()); - valueColumn.setCellEditor(new ValueCellEditor()); - - //System.out.println("renderer: " + tree.getDefaultRenderer(String.class).getClass()); - //System.out.println("editor: " + tree.getDefaultEditor(String.class).getClass()); - - callStack = new ArrayList(); - locals = new ArrayList(); - thisFields = new ArrayList(); - declaredThisFields = new ArrayList(); - - this.setTitle(editor.getSketch().getName()); - -// for (Entry entry : UIManager.getDefaults().entrySet()) { -// System.out.println(entry.getKey()); -// } - } - - @Override - public void setTitle(String title) { - super.setTitle(title + " | Variable Inspector"); - } - - /** - * Model for a Outline Row (excluding the tree column). Column 0 is "Value". - * Column 1 is "Type". Handles setting and getting values. TODO: Maybe use a - * TableCellRenderer instead of this to also have a different icon based on - * expanded state. See: - * http://kickjava.com/src/org/netbeans/swing/outline/DefaultOutlineCellRenderer.java.htm - */ - protected class VariableRowModel implements RowModel { - - protected String[] columnNames = {"Value", "Type"}; - protected int[] editableTypes = {VariableNode.TYPE_BOOLEAN, VariableNode.TYPE_FLOAT, VariableNode.TYPE_INTEGER, VariableNode.TYPE_STRING, VariableNode.TYPE_FLOAT, VariableNode.TYPE_DOUBLE, VariableNode.TYPE_LONG, VariableNode.TYPE_SHORT, VariableNode.TYPE_CHAR}; - - @Override - public int getColumnCount() { - if (p5mode) { - return 1; // only show value in p5 mode - } else { - return 2; - } - } - - @Override - public Object getValueFor(Object o, int i) { - if (o instanceof VariableNode) { - VariableNode var = (VariableNode) o; - switch (i) { - case 0: - return var; // will be converted to an appropriate String by ValueCellRenderer - case 1: - return var.getTypeName(); - default: - return ""; - } - } else { - return ""; - } - } - - @Override - public Class getColumnClass(int i) { - if (i == 0) { - return VariableNode.class; - } - return String.class; - } - - @Override - public boolean isCellEditable(Object o, int i) { - if (i == 0 && o instanceof VariableNode) { - VariableNode var = (VariableNode) o; - //System.out.println("type: " + var.getTypeName()); - for (int type : editableTypes) { - if (var.getType() == type) { - return true; - } - } - } - return false; - } - - @Override - public void setValueFor(Object o, int i, Object o1) { - VariableNode var = (VariableNode) o; - String stringValue = (String) o1; - - Value value = null; - try { - switch (var.getType()) { - case VariableNode.TYPE_INTEGER: - value = dbg.vm().mirrorOf(Integer.parseInt(stringValue)); - break; - case VariableNode.TYPE_BOOLEAN: - value = dbg.vm().mirrorOf(Boolean.parseBoolean(stringValue)); - break; - case VariableNode.TYPE_FLOAT: - value = dbg.vm().mirrorOf(Float.parseFloat(stringValue)); - break; - case VariableNode.TYPE_STRING: - value = dbg.vm().mirrorOf(stringValue); - break; - case VariableNode.TYPE_LONG: - value = dbg.vm().mirrorOf(Long.parseLong(stringValue)); - break; - case VariableNode.TYPE_BYTE: - value = dbg.vm().mirrorOf(Byte.parseByte(stringValue)); - break; - case VariableNode.TYPE_DOUBLE: - value = dbg.vm().mirrorOf(Double.parseDouble(stringValue)); - break; - case VariableNode.TYPE_SHORT: - value = dbg.vm().mirrorOf(Short.parseShort(stringValue)); - break; - case VariableNode.TYPE_CHAR: - // TODO: better char support - if (stringValue.length() > 0) { - value = dbg.vm().mirrorOf(stringValue.charAt(0)); - } - break; - } - } catch (NumberFormatException ex) { - Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "invalid value entered for {0}: {1}", new Object[]{var.getName(), stringValue}); - } - if (value != null) { - var.setValue(value); - Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "new value set: {0}", var.getStringValue()); - } - } - - @Override - public String getColumnName(int i) { - return columnNames[i]; - } - } - - /** - * Renderer for the tree portion of the outline component. Handles icons, - * text color and tool tips. - */ - protected class OutlineRenderer implements RenderDataProvider { - - protected Icon[][] icons; - protected static final int ICON_SIZE = 16; // icon size (square, size=width=height) - - public OutlineRenderer() { - // load icons - icons = loadIcons("theme/var-icons.gif"); - } - - /** - * Load multiple icons (horizotal) with multiple states (vertical) from - * a single file. - * - * @param fileName file path in the mode folder. - * @return a nested array (first index: icon, second index: state) or - * null if the file wasn't found. - */ - protected ImageIcon[][] loadIcons(String fileName) { - ExperimentalMode mode = editor.mode(); - File file = mode.getContentFile(fileName); - if (!file.exists()) { - Logger.getLogger(OutlineRenderer.class.getName()).log(Level.SEVERE, "icon file not found: {0}", file.getAbsolutePath()); - return null; - } - Image allIcons = mode.loadImage(fileName); - int cols = allIcons.getWidth(null) / ICON_SIZE; - int rows = allIcons.getHeight(null) / ICON_SIZE; - ImageIcon[][] iconImages = new ImageIcon[cols][rows]; - - for (int i = 0; i < cols; i++) { - for (int j = 0; j < rows; j++) { - //Image image = createImage(ICON_SIZE, ICON_SIZE); - Image image = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB); - Graphics g = image.getGraphics(); - g.drawImage(allIcons, -i * ICON_SIZE, -j * ICON_SIZE, null); - iconImages[i][j] = new ImageIcon(image); - } - } - return iconImages; - } - - protected Icon getIcon(int type, int state) { - if (type < 0 || type > icons.length - 1) { - return null; - } - return icons[type][state]; - } - - protected VariableNode toVariableNode(Object o) { - if (o instanceof VariableNode) { - return (VariableNode) o; - } else { - return null; - } - } - - protected Icon toGray(Icon icon) { - if (icon instanceof ImageIcon) { - Image grayImage = GrayFilter.createDisabledImage(((ImageIcon) icon).getImage()); - return new ImageIcon(grayImage); - } - // Cannot convert - return icon; - } - - @Override - public String getDisplayName(Object o) { - return o.toString(); // VariableNode.toString() returns name; (for sorting) -// VariableNode var = toVariableNode(o); -// if (var != null) { -// return var.getName(); -// } else { -// return o.toString(); -// } - } - - @Override - public boolean isHtmlDisplayName(Object o) { - return false; - } - - @Override - public Color getBackground(Object o) { - return null; - } - - @Override - public Color getForeground(Object o) { - if (tree.isEnabled()) { - return null; // default - } else { - return Color.GRAY; - } - } - - @Override - public String getTooltipText(Object o) { - VariableNode var = toVariableNode(o); - if (var != null) { - return var.getDescription(); - } else { - return ""; - } - } - - @Override - public Icon getIcon(Object o) { - VariableNode var = toVariableNode(o); - if (var != null) { - if (tree.isEnabled()) { - return getIcon(var.getType(), 0); - } else { - return getIcon(var.getType(), 1); - } - } else { - if (o instanceof TreeNode) { -// TreeNode node = (TreeNode) o; -// AbstractLayoutCache layout = tree.getLayoutCache(); - UIDefaults defaults = UIManager.getDefaults(); - - boolean isLeaf = model.isLeaf(o); - Icon icon; - if (isLeaf) { - icon = defaults.getIcon("Tree.leafIcon"); - } else { - icon = defaults.getIcon("Tree.closedIcon"); - } - - if (!tree.isEnabled()) { - return toGray(icon); - } - return icon; - } - } - return null; // use standard icon - //UIManager.getIcon(o); - } - } - - // TODO: could probably extend the simpler javax.swing.table.DefaultTableCellRenderer here - /** - * Renderer for the value column. Uses an italic font for null values and - * Object values ("instance of ..."). Uses a gray color when tree is not - * enabled. - */ - protected class ValueCellRenderer extends DefaultOutlineCellRenderer { - - public ValueCellRenderer() { - super(); - } - - protected void setItalic(boolean on) { - if (on) { - setFont(new Font(getFont().getName(), Font.ITALIC, getFont().getSize())); - } else { - setFont(new Font(getFont().getName(), Font.PLAIN, getFont().getSize())); - } - } - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - if (!tree.isEnabled()) { - setForeground(Color.GRAY); - } else { - setForeground(Color.BLACK); - } - - if (value instanceof VariableNode) { - VariableNode var = (VariableNode) value; - - if (var.getValue() == null || var.getType() == VariableNode.TYPE_OBJECT) { - setItalic(true); - } else { - setItalic(false); - } - value = var.getStringValue(); - } - - setValue(value); - return c; - } - } - - /** - * Editor for the value column. Will show an empty string when editing - * String values that are null. - */ - protected class ValueCellEditor extends DefaultCellEditor { - - public ValueCellEditor() { - super(new JTextField()); - } - - @Override - public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { - if (!(value instanceof VariableNode)) { - return super.getTableCellEditorComponent(table, value, isSelected, row, column); - } - VariableNode var = (VariableNode) value; - if (var.getType() == VariableNode.TYPE_STRING && var.getValue() == null) { - return super.getTableCellEditorComponent(table, "", isSelected, row, column); - } else { - return super.getTableCellEditorComponent(table, var.getStringValue(), isSelected, row, column); - } - } - } - - /** - * Handler for expanding and collapsing tree nodes. Implements lazy loading - * of tree data (on expand). - */ - protected class ExpansionHandler implements ExtTreeWillExpandListener, TreeExpansionListener { - - @Override - public void treeWillExpand(TreeExpansionEvent tee) throws ExpandVetoException { - //System.out.println("will expand"); - Object last = tee.getPath().getLastPathComponent(); - if (!(last instanceof VariableNode)) { - return; - } - VariableNode var = (VariableNode) last; - // load children -// if (!dbg.isPaused()) { -// System.out.println("throwing veto"); -// //throw new ExpandVetoException(tee, "Debugger busy"); -// } else { - var.removeAllChildren(); // TODO: should we only load it once? - // TODO: don't filter in advanced mode - //System.out.println("loading children for: " + var); - // true means include inherited - var.addChildren(filterNodes(dbg.getFields(var.getValue(), 0, true), new ThisFilter())); -// } - } - - @Override - public void treeWillCollapse(TreeExpansionEvent tee) throws ExpandVetoException { - //throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public void treeExpanded(TreeExpansionEvent tee) { - //System.out.println("expanded: " + tee.getPath()); - if (!expandedNodes.contains(tee.getPath())) { - expandedNodes.add(tee.getPath()); - } - -// TreePath newPath = tee.getPath(); -// if (expandedLast != null) { -// // test each node of the path for equality -// for (int i = 0; i < expandedLast.getPathCount(); i++) { -// if (i < newPath.getPathCount()) { -// Object last = expandedLast.getPathComponent(i); -// Object cur = newPath.getPathComponent(i); -// System.out.println(last + " =? " + cur + ": " + last.equals(cur) + "/" + (last.hashCode() == cur.hashCode())); -// } -// } -// } -// System.out.println("path equality: " + newPath.equals(expandedLast)); -// expandedLast = newPath; - } - - @Override - public void treeCollapsed(TreeExpansionEvent tee) { - //System.out.println("collapsed: " + tee.getPath()); - - // first remove all children of collapsed path - // this makes sure children do not appear before parents in the list. - // (children can't be expanded before their parents) - List removalList = new ArrayList(); - for (TreePath path : expandedNodes) { - if (path.getParentPath().equals(tee.getPath())) { - removalList.add(path); - } - } - for (TreePath path : removalList) { - expandedNodes.remove(path); - } - // remove collapsed path - expandedNodes.remove(tee.getPath()); - } - - @Override - public void treeExpansionVetoed(TreeExpansionEvent tee, ExpandVetoException eve) { - //System.out.println("expansion vetoed"); - // nop - } - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - scrollPane = new javax.swing.JScrollPane(); - tree = new org.netbeans.swing.outline.Outline(); - - scrollPane.setViewportView(tree); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)) - ); - - pack(); - }// //GEN-END:initComponents - -// /** -// * @param args the command line arguments -// */ -// public static void main(String args[]) { -// /* -// * Set the Nimbus look and feel -// */ -// // -// /* -// * If Nimbus (introduced in Java SE 6) is not available, stay with the -// * default look and feel. For details see -// * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html -// */ -// try { -// javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); -// } catch (ClassNotFoundException ex) { -// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); -// } catch (InstantiationException ex) { -// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); -// } catch (IllegalAccessException ex) { -// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); -// } catch (javax.swing.UnsupportedLookAndFeelException ex) { -// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); -// } -// // -// -// /* -// * Create and display the form -// */ -// run(new VariableInspector()); -// } - protected static void run(final VariableInspector vi) { - /* - * Create and display the form - */ - java.awt.EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - vi.setVisible(true); - } - }); - } - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JScrollPane scrollPane; - protected org.netbeans.swing.outline.Outline tree; - // End of variables declaration//GEN-END:variables - - /** - * Access the root node of the tree. - * - * @return the root node - */ - public DefaultMutableTreeNode getRootNode() { - return rootNode; - } - - /** - * Unlock the inspector window. Rebuild after this to avoid ... dots in the - * trees labels - */ - public void unlock() { - tree.setEnabled(true); - } - - /** - * Lock the inspector window. Cancels open edits. - */ - public void lock() { - if (tree.getCellEditor() != null) { - //tree.getCellEditor().stopCellEditing(); // force quit open edit - tree.getCellEditor().cancelCellEditing(); // cancel an open edit - } - tree.setEnabled(false); - } - - /** - * Reset the inspector windows data. Rebuild after this to make changes - * visible. - */ - public void reset() { - rootNode.removeAllChildren(); - // clear local data for good measure (in case someone rebuilds) - callStack.clear(); - locals.clear(); - thisFields.clear(); - declaredThisFields.clear(); - expandedNodes.clear(); - // update - treeModel.nodeStructureChanged(rootNode); - } - -// public void setAdvancedMode() { -// p5mode = false; -// } -// -// public void setP5Mode() { -// p5mode = true; -// } -// -// public void toggleMode() { -// if (p5mode) { -// setAdvancedMode(); -// } else { -// setP5Mode(); -// } -// } - /** - * Update call stack data. - * - * @param nodes a list of nodes that represent the call stack. - * @param title the title to be used when labeling or otherwise grouping - * call stack data. - */ - public void updateCallStack(List nodes, String title) { - callStack = nodes; - } - - /** - * Update locals data. - * - * @param nodes a list of {@link VariableNode} to be shown as local - * variables in the inspector. - * @param title the title to be used when labeling or otherwise grouping - * locals data. - */ - public void updateLocals(List nodes, String title) { - locals = nodes; - } - - /** - * Update this-fields data. - * - * @param nodes a list of {@link VariableNode}s to be shown as this-fields - * in the inspector. - * @param title the title to be used when labeling or otherwise grouping - * this-fields data. - */ - public void updateThisFields(List nodes, String title) { - thisFields = nodes; - } - - /** - * Update declared (non-inherited) this-fields data. - * - * @param nodes a list of {@link VariableNode}s to be shown as declared - * this-fields in the inspector. - * @param title the title to be used when labeling or otherwise grouping - * declared this-fields data. - */ - public void updateDeclaredThisFields(List nodes, String title) { - declaredThisFields = nodes; - } - - /** - * Rebuild the outline tree from current data. Uses the data provided by - * {@link #updateCallStack}, {@link #updateLocals}, {@link #updateThisFields} - * and {@link #updateDeclaredThisFields} - */ - public void rebuild() { - rootNode.removeAllChildren(); - if (p5mode) { - // add all locals to root - addAllNodes(rootNode, locals); - - // add non-inherited this fields - addAllNodes(rootNode, filterNodes(declaredThisFields, new LocalHidesThisFilter(locals, LocalHidesThisFilter.MODE_PREFIX))); - - // add p5 builtins in a new folder - builtins.removeAllChildren(); - addAllNodes(builtins, filterNodes(thisFields, new P5BuiltinsFilter())); - if (builtins.getChildCount() > 0) { // skip builtins in certain situations e.g. in pure java tabs. - rootNode.add(builtins); - } - - // notify tree (using model) changed a node and its children - // http://stackoverflow.com/questions/2730851/how-to-update-jtree-elements - // needs to be done before expanding paths! - treeModel.nodeStructureChanged(rootNode); - - // handle node expansions - for (TreePath path : expandedNodes) { - //System.out.println("re-expanding: " + path); - path = synthesizePath(path); - if (path != null) { - tree.expandPath(path); - } else { - //System.out.println("couldn't synthesize path"); - } - } - - // this expansion causes problems when sorted and stepping - //tree.expandPath(new TreePath(new Object[]{rootNode, builtins})); - - } else { - // TODO: implement advanced mode here - } - } - - /** - * Re-build a {@link TreePath} from a previous path using equals-checks - * starting at the root node. This is used to use paths from previous trees - * for use on the current tree. - * - * @param path the path to synthesize. - * @return the rebuilt path, usable on the current tree. - */ - protected TreePath synthesizePath(TreePath path) { - //System.out.println("synthesizing: " + path); - if (path.getPathCount() == 0 || !rootNode.equals(path.getPathComponent(0))) { - return null; - } - Object[] newPath = new Object[path.getPathCount()]; - newPath[0] = rootNode; - TreeNode currentNode = rootNode; - for (int i = 0; i < path.getPathCount() - 1; i++) { - // get next node - for (int j = 0; j < currentNode.getChildCount(); j++) { - TreeNode nextNode = currentNode.getChildAt(j); - if (nextNode.equals(path.getPathComponent(i + 1))) { - currentNode = nextNode; - newPath[i + 1] = nextNode; - //System.out.println("found node " + (i+1) + ": " + nextNode); - break; - } - } - if (newPath[i + 1] == null) { - //System.out.println("didn't find node"); - return null; - } - } - return new TreePath(newPath); - } - - /** - * Filter a list of nodes using a {@link VariableNodeFilter}. - * - * @param nodes the list of nodes to filter. - * @param filter the filter to be used. - * @return the filtered list. - */ - protected List filterNodes(List nodes, VariableNodeFilter filter) { - List filtered = new ArrayList(); - for (VariableNode node : nodes) { - if (filter.accept(node)) { - filtered.add(node); - } - } - return filtered; - } - - /** - * Add all nodes in a list to a root node. - * - * @param root the root node to add to. - * @param nodes the list of nodes to add. - */ - protected void addAllNodes(DefaultMutableTreeNode root, List nodes) { - for (MutableTreeNode node : nodes) { - root.add(node); - } - } - - /** - * A filter for {@link VariableNode}s. - */ - public interface VariableNodeFilter { - - /** - * Check whether the filter accepts a {@link VariableNode}. - * - * @param var the input node - * @return true when the filter accepts the input node otherwise false. - */ - public boolean accept(VariableNode var); - } - - /** - * A {@link VariableNodeFilter} that accepts Processing built-in variable - * names. - */ - public class P5BuiltinsFilter implements VariableNodeFilter { - - protected String[] p5Builtins = { - "focused", - "frameCount", - "frameRate", - "height", - "online", - "screen", - "width", - "mouseX", - "mouseY", - "pmouseX", - "pmouseY", - "key", - "keyCode", - "keyPressed" - }; - - @Override - public boolean accept(VariableNode var) { - return Arrays.asList(p5Builtins).contains(var.getName()); - } - } - - /** - * A {@link VariableNodeFilter} that rejects implicit this references. - * (Names starting with "this$") - */ - public class ThisFilter implements VariableNodeFilter { - - @Override - public boolean accept(VariableNode var) { - return !var.getName().startsWith("this$"); - } - } - - /** - * A {@link VariableNodeFilter} that either rejects this-fields if hidden by - * a local, or prefixes its name with "this." - */ - public class LocalHidesThisFilter implements VariableNodeFilter { - - /** - * Reject a this-field if hidden by a local. - */ - public static final int MODE_HIDE = 0; // don't show hidden this fields - /** - * Prefix a this-fields name with "this." if hidden by a local. - */ - public static final int MODE_PREFIX = 1; // prefix hidden this fields with "this." - protected List locals; - protected int mode; - - /** - * Construct a {@link LocalHidesThisFilter}. - * - * @param locals a list of locals to check against - * @param mode either {@link #MODE_HIDE} or {@link #MODE_PREFIX} - */ - public LocalHidesThisFilter(List locals, int mode) { - this.locals = locals; - this.mode = mode; - } - - @Override - public boolean accept(VariableNode var) { - // check if the same name appears in the list of locals i.e. the local hides the field - for (VariableNode local : locals) { - if (var.getName().equals(local.getName())) { - switch (mode) { - case MODE_PREFIX: - var.setName("this." + var.getName()); - return true; - case MODE_HIDE: - return false; - } - } - } - return true; - } - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/VariableNode.java b/pdex/experimental/src/processing/mode/experimental/VariableNode.java deleted file mode 100755 index 66b0575d7..000000000 --- a/pdex/experimental/src/processing/mode/experimental/VariableNode.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2012 Martin Leopold - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - */ -package processing.mode.experimental; - -import com.sun.jdi.ArrayReference; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.StringReference; -import com.sun.jdi.Value; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import javax.swing.tree.MutableTreeNode; -import javax.swing.tree.TreeNode; - -/** - * Model for a variable in the variable inspector. Has a type and name and - * optionally a value. Can have sub-variables (as is the case for objects, and - * arrays). - * - * @author Martin Leopold - */ -public class VariableNode implements MutableTreeNode { - - public static final int TYPE_UNKNOWN = -1; - public static final int TYPE_OBJECT = 0; - public static final int TYPE_ARRAY = 1; - public static final int TYPE_INTEGER = 2; - public static final int TYPE_FLOAT = 3; - public static final int TYPE_BOOLEAN = 4; - public static final int TYPE_CHAR = 5; - public static final int TYPE_STRING = 6; - public static final int TYPE_LONG = 7; - public static final int TYPE_DOUBLE = 8; - public static final int TYPE_BYTE = 9; - public static final int TYPE_SHORT = 10; - public static final int TYPE_VOID = 11; - protected String type; - protected String name; - protected Value value; - protected List children = new ArrayList(); - protected MutableTreeNode parent; - - /** - * Construct a {@link VariableNode}. - * @param name the name - * @param type the type - * @param value the value - */ - public VariableNode(String name, String type, Value value) { - this.name = name; - this.type = type; - this.value = value; - } - - public void setValue(Value value) { - this.value = value; - } - - public Value getValue() { - return value; - } - - /** - * Get a String representation of this variable nodes value. - * - * @return a String representing the value. - */ - public String getStringValue() { - String str; - if (value != null) { - if (getType() == TYPE_OBJECT) { - str = "instance of " + type; - } else if (getType() == TYPE_ARRAY) { - //instance of int[5] (id=998) --> instance of int[5] - str = value.toString().substring(0, value.toString().lastIndexOf(" ")); - } else if (getType() == TYPE_STRING) { - str = ((StringReference) value).value(); // use original string value (without quotes) - } else { - str = value.toString(); - } - } else { - str = "null"; - } - return str; - } - - public String getTypeName() { - return type; - } - - public int getType() { - if (type == null) { - return TYPE_UNKNOWN; - } - if (type.endsWith("[]")) { - return TYPE_ARRAY; - } - if (type.equals("int")) { - return TYPE_INTEGER; - } - if (type.equals("long")) { - return TYPE_LONG; - } - if (type.equals("byte")) { - return TYPE_BYTE; - } - if (type.equals("short")) { - return TYPE_SHORT; - } - if (type.equals("float")) { - return TYPE_FLOAT; - } - if (type.equals("double")) { - return TYPE_DOUBLE; - } - if (type.equals("char")) { - return TYPE_CHAR; - } - if (type.equals("java.lang.String")) { - return TYPE_STRING; - } - if (type.equals("boolean")) { - return TYPE_BOOLEAN; - } - if (type.equals("void")) { - return TYPE_VOID; //TODO: check if this is correct - } - return TYPE_OBJECT; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - /** - * Add a {@link VariableNode} as child. - * - * @param c the {@link VariableNode} to add. - */ - public void addChild(VariableNode c) { - children.add(c); - c.setParent(this); - } - - /** - * Add multiple {@link VariableNode}s as children. - * - * @param children the list of {@link VariableNode}s to add. - */ - public void addChildren(List children) { - for (VariableNode child : children) { - addChild(child); - } - } - - @Override - public TreeNode getChildAt(int i) { - return children.get(i); - } - - @Override - public int getChildCount() { - return children.size(); - } - - @Override - public TreeNode getParent() { - return parent; - } - - @Override - public int getIndex(TreeNode tn) { - return children.indexOf(tn); - } - - @Override - public boolean getAllowsChildren() { - if (value == null) { - return false; - } - - // handle strings - if (getType() == TYPE_STRING) { - return false; - } - - // handle arrays - if (getType() == TYPE_ARRAY) { - ArrayReference array = (ArrayReference) value; - return array.length() > 0; - } - // handle objects - if (getType() == TYPE_OBJECT) { // this also rules out null - // check if this object has any fields - ObjectReference obj = (ObjectReference) value; - return !obj.referenceType().visibleFields().isEmpty(); - } - - return false; - } - - /** - * This controls the default icon and disclosure triangle. - * - * @return true, will show "folder" icon and disclosure triangle. - */ - @Override - public boolean isLeaf() { - //return children.size() == 0; - return !getAllowsChildren(); - } - - @Override - public Enumeration children() { - return Collections.enumeration(children); - } - - /** - * Get a String representation of this {@link VariableNode}. - * - * @return the name of the variable (for sorting to work). - */ - @Override - public String toString() { - return getName(); // for sorting - } - - /** - * Get a String description of this {@link VariableNode}. Contains the type, - * name and value. - * - * @return the description - */ - public String getDescription() { - String str = ""; - if (type != null) { - str += type + " "; - } - str += name; - str += " = " + getStringValue(); - return str; - } - - @Override - public void insert(MutableTreeNode mtn, int i) { - children.add(i, this); - } - - @Override - public void remove(int i) { - MutableTreeNode mtn = children.remove(i); - if (mtn != null) { - mtn.setParent(null); - } - } - - @Override - public void remove(MutableTreeNode mtn) { - children.remove(mtn); - mtn.setParent(null); - } - - /** - * Remove all children from this {@link VariableNode}. - */ - public void removeAllChildren() { - for (MutableTreeNode mtn : children) { - mtn.setParent(null); - } - children.clear(); - } - - @Override - public void setUserObject(Object o) { - if (o instanceof Value) { - value = (Value) o; - } - } - - @Override - public void removeFromParent() { - parent.remove(this); - this.parent = null; - } - - @Override - public void setParent(MutableTreeNode mtn) { - parent = mtn; - } - - /** - * Test for equality. To be equal, two {@link VariableNode}s need to have - * equal type, name and value. - * - * @param obj the object to test for equality with this {@link VariableNode} - * @return true if the given object is equal to this {@link VariableNode} - */ - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final VariableNode other = (VariableNode) obj; - if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) { - //System.out.println("type not equal"); - return false; - } - if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { - //System.out.println("name not equal"); - return false; - } - if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { - //System.out.println("value not equal"); - return false; - } -// if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) { -// System.out.println("parent not equal: " + this.parent + "/" + other.parent); -// return false; -// } - return true; - } - - /** - * Returns a hash code based on type, name and value. - */ - @Override - public int hashCode() { - int hash = 3; - hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0); - hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); - hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0); -// hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0); - return hash; - } -} diff --git a/pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java b/pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java deleted file mode 100755 index 7d4ea9032..000000000 --- a/pdex/experimental/src/processing/mode/experimental/XQConsoleToggle.java +++ /dev/null @@ -1,131 +0,0 @@ -package processing.mode.experimental; - -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -import javax.swing.JPanel; - -/** - * Toggle Button displayed in the editor line status panel for toggling bewtween - * console and problems list. Glorified JPanel. - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ - -public class XQConsoleToggle extends JPanel implements MouseListener { - public static final String[] text = { "Console", "Errors" }; - - private boolean toggleText = true; - private boolean toggleBG = true; - - /** - * Height of the component - */ - protected int height; - protected DebugEditor editor; - protected String buttonName; - - public XQConsoleToggle(DebugEditor editor, String buttonName, int height) { - this.editor = editor; - this.height = height; - this.buttonName = buttonName; - } - - public Dimension getPreferredSize() { - return new Dimension(70, height); - } - - public Dimension getMinimumSize() { - return getPreferredSize(); - } - - public Dimension getMaximumSize() { - return getPreferredSize(); - } - - public void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - - // On mouse hover, text and background color are changed. - if (toggleBG) { - g.setColor(new Color(0xff9DA7B0)); - g.fillRect(0, 0, this.getWidth(), this.getHeight()); - g.setColor(new Color(0xff29333D)); - g.fillRect(0, 0, 4, this.getHeight()); - g.setColor(Color.BLACK); - } else { - g.setColor(Color.DARK_GRAY); - g.fillRect(0, 0, this.getWidth(), this.getHeight()); - g.setColor(new Color(0xff29333D)); - g.fillRect(0, 0, 4, this.getHeight()); - g.setColor(Color.WHITE); - } - - g.drawString(buttonName, getWidth() / 2 + 2 // + 2 is a offset - - getFontMetrics(getFont()).stringWidth(buttonName) / 2, - this.getHeight() - 6); - } - - @Override - public void mouseClicked(MouseEvent arg0) { - - this.repaint(); - try { - editor.toggleView(buttonName); - } catch (Exception e) { - System.out.println(e); - // e.printStackTrace(); - } - toggleText = !toggleText; - } - - @Override - public void mouseEntered(MouseEvent arg0) { - toggleBG = !toggleBG; - this.repaint(); - } - - @Override - public void mouseExited(MouseEvent arg0) { - toggleBG = !toggleBG; - this.repaint(); - } - - @Override - public void mousePressed(MouseEvent arg0) { - } - - @Override - public void mouseReleased(MouseEvent arg0) { - } -} \ No newline at end of file diff --git a/pdex/experimental/src/processing/mode/experimental/XQErrorTable.java b/pdex/experimental/src/processing/mode/experimental/XQErrorTable.java deleted file mode 100755 index e64cf2c4b..000000000 --- a/pdex/experimental/src/processing/mode/experimental/XQErrorTable.java +++ /dev/null @@ -1,166 +0,0 @@ -package processing.mode.experimental; - -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.JTable; -import javax.swing.SwingWorker; -import javax.swing.table.JTableHeader; -import javax.swing.table.TableModel; - -/** - * Custom JTable implementation for XQMode. Minor tweaks and addtions. - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ -public class XQErrorTable extends JTable { - - /** - * Column Names of JTable - */ - public static final String[] columnNames = { "Problem", "Tab", "Line" }; - - /** - * Column Widths of JTable. - */ - public int[] columnWidths = { 600, 100, 50 }; // Default Values - - /** - * Is the column being resized? - */ - private boolean columnResizing = false; - - /** - * ErrorCheckerService instance - */ - protected ErrorCheckerService errorCheckerService; - - @Override - public boolean isCellEditable(int rowIndex, int colIndex) { - return false; // Disallow the editing of any cell - } - - public XQErrorTable(final ErrorCheckerService errorCheckerService) { - this.errorCheckerService = errorCheckerService; - for (int i = 0; i < this.getColumnModel().getColumnCount(); i++) { - this.getColumnModel().getColumn(i) - .setPreferredWidth(columnWidths[i]); - } - - this.getTableHeader().setReorderingAllowed(false); - - this.addMouseListener(new MouseAdapter() { - @Override - synchronized public void mouseReleased(MouseEvent e) { - try { - errorCheckerService.scrollToErrorLine(((XQErrorTable) e - .getSource()).getSelectedRow()); - // System.out.print("Row clicked: " - // + ((XQErrorTable) e.getSource()).getSelectedRow()); - } catch (Exception e1) { - System.out.println("Exception XQErrorTable mouseReleased " - + e); - } - } - }); - - // Handles the resizing of columns. When mouse press is detected on - // table header, Stop updating the table, store new values of column - // widths,and resume updating. Updating is disabled as long as - // columnResizing is true - this.getTableHeader().addMouseListener(new MouseAdapter() { - - @Override - public void mousePressed(MouseEvent e) { - columnResizing = true; - } - - @Override - public void mouseReleased(MouseEvent e) { - columnResizing = false; - for (int i = 0; i < ((JTableHeader) e.getSource()) - .getColumnModel().getColumnCount(); i++) { - columnWidths[i] = ((JTableHeader) e.getSource()) - .getColumnModel().getColumn(i).getWidth(); - // System.out.println("nw " + columnWidths[i]); - } - } - }); - } - - - /** - * Updates table contents with new data - * @param tableModel - TableModel - * @return boolean - If table data was updated - */ - @SuppressWarnings("rawtypes") - synchronized public boolean updateTable(final TableModel tableModel) { - - // If problems list is not visible, no need to update - if (!this.isVisible()) { - return false; - } - - SwingWorker worker = new SwingWorker() { - - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - - try { - setModel(tableModel); - - // Set column widths to user defined widths - for (int i = 0; i < getColumnModel().getColumnCount(); i++) { - getColumnModel().getColumn(i).setPreferredWidth( - columnWidths[i]); - } - getTableHeader().setReorderingAllowed(false); - validate(); - repaint(); - } catch (Exception e) { - System.out.println("Exception at XQErrorTable.updateTable " + e); - // e.printStackTrace(); - } - } - }; - - try { - if (!columnResizing) { - worker.execute(); - } - } catch (Exception e) { - System.out.println("ErrorTable updateTable Worker's slacking." - + e.getMessage()); - // e.printStackTrace(); - } - return true; - } - -} diff --git a/pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java b/pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java deleted file mode 100755 index 34ee2a9a2..000000000 --- a/pdex/experimental/src/processing/mode/experimental/XQPreprocessor.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - Part of the XQMode project - https://github.com/Manindra29/XQMode - - Under Google Summer of Code 2012 - - http://www.google-melange.com/gsoc/homepage/google/gsoc2012 - - Copyright (C) 2012 Manindra Moharana - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -package processing.mode.experimental; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.dom.AST; -import org.eclipse.jdt.core.dom.ASTParser; -import org.eclipse.jdt.core.dom.ASTVisitor; -import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.MethodDeclaration; -import org.eclipse.jdt.core.dom.Modifier; -import org.eclipse.jdt.core.dom.NumberLiteral; -import org.eclipse.jdt.core.dom.SimpleType; -import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.Document; -import org.eclipse.text.edits.MalformedTreeException; -import org.eclipse.text.edits.TextEdit; - -import processing.mode.java.preproc.PdePreprocessor; - -/** - * My implementation of P5 preprocessor. Uses Eclipse JDT features instead of - * ANTLR. Performance gains mostly and full control over debug output. But needs - * lots and lots of testing. There will always an option to switch back to PDE - * preproc. - * - * @author Manindra Moharana <me@mkmoharana.com> - * - */ -public class XQPreprocessor { - - private ASTRewrite rewrite = null; - private ArrayList imports; - private ArrayList extraImports; - - private String[] coreImports, defaultImports; - - public XQPreprocessor() { - PdePreprocessor p = new PdePreprocessor(null); - defaultImports = p.getDefaultImports(); - coreImports = p.getCoreImports(); - } - - /** - * The main method that performs preprocessing. Converts code into compilable java. - * @param source - String - * @param programImports - List of import statements - * @return String - Compile ready java code - */ - public String doYourThing(String source, - ArrayList programImports) { - this.extraImports = programImports; - //source = prepareImports() + source; - Document doc = new Document(source); - - ASTParser parser = ASTParser.newParser(AST.JLS4); - parser.setSource(doc.get().toCharArray()); - parser.setKind(ASTParser.K_COMPILATION_UNIT); - - @SuppressWarnings("unchecked") - Map options = JavaCore.getOptions(); - - // Ben has decided to move on to 1.6. Yay! - JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); - options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); - parser.setCompilerOptions(options); - CompilationUnit cu = (CompilationUnit) parser.createAST(null); - cu.recordModifications(); - rewrite = ASTRewrite.create(cu.getAST()); - cu.accept(new XQASTVisitor()); - - TextEdit edits = cu.rewrite(doc, null); - try { - edits.apply(doc); - } catch (MalformedTreeException e) { - e.printStackTrace(); - } catch (BadLocationException e) { - e.printStackTrace(); - } - // System.out.println("------------XQPreProc-----------------"); - // System.out.println(doc.get()); - // System.out.println("------------XQPreProc End-----------------"); - - // Calculate main class offset - int position = doc.get().indexOf("{") + 1; - int lines = 0; - for (int i = 0; i < position; i++) { - if (doc.get().charAt(i) == '\n') { - lines++; - } - } - lines += 2; - // System.out.println("Lines: " + lines); - - return doc.get(); - } - - /** - * Returns all import statements as lines of code - * - * @return String - All import statements combined. Each import in a separate line. - */ - public String prepareImports() { - imports = new ArrayList(); - for (int i = 0; i < extraImports.size(); i++) { - imports.add(new String(extraImports.get(i).importName)); - } - imports.add(new String("// Default Imports")); - for (int i = 0; i < coreImports.length; i++) { - imports.add(new String("import " + coreImports[i] + ";")); - } - for (int i = 0; i < defaultImports.length; i++) { - imports.add(new String("import " + defaultImports[i] + ";")); - } - String totalImports = ""; - for (int i = 0; i < imports.size(); i++) { - totalImports += imports.get(i) + "\n"; - } - totalImports += "\n"; - return totalImports; - } - - public String prepareImports(ArrayList programImports) { - this.extraImports = programImports; - return prepareImports(); - } - - /** - * Visitor implementation that does all the substitution dirty work.
    - *
  • Any function not specified as being protected or private will be made - * 'public'. This means that void setup() becomes - * public void setup(). - * - *
  • Converts doubles into floats, i.e. 12.3 becomes 12.3f so that people - * don't have to add f after their numbers all the time since it's confusing - * for beginners. Also, most functions of p5 core deal with floats only. - * - * @author Manindra Moharana - * - */ - private class XQASTVisitor extends ASTVisitor { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public boolean visit(MethodDeclaration node) { - if (node.getReturnType2() != null) { - // if return type is color, make it int - // if (node.getReturnType2().toString().equals("color")) { - // System.err.println("color type detected!"); - // node.setReturnType2(rewrite.getAST().newPrimitiveType( - // PrimitiveType.INT)); - // } - - // The return type is not void, no need to make it public - // if (!node.getReturnType2().toString().equals("void")) - // return true; - } - - // Simple method, make it public - if (node.modifiers().size() == 0 && !node.isConstructor()) { - // rewrite.set(node, node.getModifiersProperty(), - // Modifier.PUBLIC, - // null); - // rewrite.getListRewrite(node, - // node.getModifiersProperty()).insertLast(Modifier., null) - List newMod = rewrite.getAST().newModifiers(Modifier.PUBLIC); - node.modifiers().add(newMod.get(0)); - } - - return true; - } - - public boolean visit(NumberLiteral node) { - if (!node.getToken().endsWith("f") - && !node.getToken().endsWith("d")) { - for (int i = 0; i < node.getToken().length(); i++) { - if (node.getToken().charAt(i) == '.') { - - String s = node.getToken() + "f"; - node.setToken(s); - break; - } - } - } - return true; - } - - // public boolean visit(FieldDeclaration node) { - // if (node.getType().toString().equals("color")){ - // System.err.println("color type detected!"); - // node.setType(rewrite.getAST().newPrimitiveType( - // PrimitiveType.INT)); - // } - // return true; - // } - // - // public boolean visit(VariableDeclarationStatement node) { - // if (node.getType().toString().equals("color")){ - // System.err.println("color type detected!"); - // node.setType(rewrite.getAST().newPrimitiveType( - // PrimitiveType.INT)); - // } - // return true; - // } - - /** - * This is added just for debugging purposes - to make sure that all - * instances of color type have been substituded as in by the regex - * search in ErrorCheckerService.preprocessCode(). - */ - public boolean visit(SimpleType node) { - if (node.toString().equals("color")) { - System.err - .println("color type detected! \nThis shouldn't be happening! Please report this as an issue."); - } - return true; - - } - - } - -} diff --git a/pdex/experimental/theme/theme.txt b/pdex/experimental/theme/theme.txt deleted file mode 100755 index 1a6179f5c..000000000 --- a/pdex/experimental/theme/theme.txt +++ /dev/null @@ -1,34 +0,0 @@ -# DEBUGGER - -# breakpointed line background color -breakpoint.bgcolor = #f0f0f0 -# marker for breakpointed lines in left hand gutter (2 ascii characters) -breakpoint.marker = <> -breakpoint.marker.color = #4a545e - -# current line background color -currentline.bgcolor = #ffff96 -# marker for the current line in left hand gutter (2 ascii characters) -currentline.marker = -> -currentline.marker.color = #e27500 - -# left hand gutter background color -gutter.bgcolor = #fcfcfc -# color of vertical separation line -gutter.linecolor = #e9e9e9 -# space (in px) added to left and right of gutter markers -gutter.padding = 3 - - -# XQMODE - -# underline colors -editor.errorcolor = #ed2630 -editor.warningcolor = #ffc30e -editor.errormarkercolor = #ed2630 -editor.warningmarkercolor = #ffc30e - -# ERROR BAR - error bar on the right that shows the markers -errorbar.errorcolor = #ed2630 -errorbar.warningcolor = #ffc30e -errorbar.backgroundcolor = #2c343d diff --git a/pdex/experimental/theme/var-icons.gif b/pdex/experimental/theme/var-icons.gif deleted file mode 100755 index 1d0086a38ebb728a2a44d3b4d510cf12992fc1dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5152 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 Date: Sat, 29 Jun 2013 16:19:01 +0530 Subject: [PATCH 075/608] Updated readme --- pdex/README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pdex/README.md b/pdex/README.md index 4b7b12b6c..0ca2aa456 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -1,4 +1,9 @@ -processing-experimental -======================= - Experimental Mode for the PDE +========================= + +This project is in the process of being moved out of the main project so that it can be developed in parallel with the PDE. Right now, it's in a messy state and not stable, forking isn't recommened. + +Stay tuned for updates. + +Manindra Moharana +29 June 2013 From da0eb2144975797a1ec81210ffa4840de898f010 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 21:21:45 +0530 Subject: [PATCH 076/608] setting things up for new locations --- pdex/.classpath | 2 ++ pdex/.project | 10 ---------- pdex/build.xml | 15 +++++++++------ .../mode/experimental/ASTGenerator.java | 10 ---------- .../mode/experimental/ErrorCheckerService.java | 5 +++-- 5 files changed, 14 insertions(+), 28 deletions(-) diff --git a/pdex/.classpath b/pdex/.classpath index 5bb5a9eb3..8de404320 100644 --- a/pdex/.classpath +++ b/pdex/.classpath @@ -19,5 +19,7 @@ + + diff --git a/pdex/.project b/pdex/.project index 85716855e..1be6ebc0c 100644 --- a/pdex/.project +++ b/pdex/.project @@ -10,16 +10,6 @@ - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Auto_Builder.launch - - - org.eclipse.jdt.core.javanature diff --git a/pdex/build.xml b/pdex/build.xml index 309946ae0..f0ddbdd74 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -1,6 +1,8 @@ + + @@ -8,7 +10,7 @@ - + @@ -47,19 +49,20 @@ destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar;mode/classpath-explorer-1.0.jar; mode/jsoup-1.7.1.jar;" + classpath="${core.library.location}/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ${app.library.location}/lib/ant.jar; ${app.library.location}/lib/ant-launcher.jar; ${app.library.location}/lib/antlr.jar; ${app.library.location}/lib/apple.jar; ${app.library.location}/lib/jdt-core.jar; ${app.library.location}/lib/jna.jar; ${app.library.location}/lib/org-netbeans-swing-outline.jar; ${app.library.location}/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar;mode/classpath-explorer-1.0.jar; mode/jsoup-1.7.1.jar;" + debug="off"> - + - + - - + + diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b4ebb3413..86a4fdc3b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,13 +1,10 @@ package processing.mode.experimental; import java.awt.Dimension; -import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -27,11 +24,9 @@ import java.util.Map; import java.util.Stack; import java.util.TreeMap; -import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; -import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; @@ -63,13 +58,11 @@ import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; -import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; import processing.app.SketchCode; @@ -77,9 +70,6 @@ import processing.app.SketchCode; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; import com.google.classpath.RegExpResourceFilter; -import com.ibm.icu.util.StringTokenizer; -import com.sun.org.apache.bcel.internal.generic.GETSTATIC; -import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs; public class ASTGenerator { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 395def5e2..39de86ea4 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -359,7 +359,8 @@ public class ErrorCheckerService implements Runnable{ // System.out // .println("Experimental Mode: Loading contributed libraries referenced by import statements."); - File f = Base.getContentFile("modes" + File.separator + "experimental" + // The folder SketchBook/modes/ExperimentalMode/mode + File f = new File(Base.getSketchbookModesFolder().getAbsolutePath() + File.separator + "ExperimentalMode" + File.separator + "mode"); if(!f.exists()) { @@ -370,7 +371,7 @@ public class ErrorCheckerService implements Runnable{ FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return (file.getName().endsWith(".jar") && !file - .getName().startsWith("experimental")); + .getName().startsWith("ExperimentalMode")); } }; From ad4b4dd1f3cc130c9aee54128edc057394ad2009 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 21:23:00 +0530 Subject: [PATCH 077/608] build properties --- pdex/build.properties | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 pdex/build.properties diff --git a/pdex/build.properties b/pdex/build.properties new file mode 100644 index 000000000..ab648798d --- /dev/null +++ b/pdex/build.properties @@ -0,0 +1,5 @@ +sketchbook.location=${user.home}/Documents/Processing +classpath.local.location=${user.home}/Documents/workspace/libs +core.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/core/library +app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/ +java.target.version=1.6 \ No newline at end of file From 73258d3cad56d8ac044268970965d68f635ba21c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 29 Jun 2013 22:22:04 +0530 Subject: [PATCH 078/608] refactoring line offset displaced bug fix --- pdex/.externalToolBuilders/Ant_Builder.launch | 18 +++++++++++++ pdex/.project | 9 +++++++ .../mode/experimental/ASTGenerator.java | 25 ++++++++++++------- 3 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 pdex/.externalToolBuilders/Ant_Builder.launch diff --git a/pdex/.externalToolBuilders/Ant_Builder.launch b/pdex/.externalToolBuilders/Ant_Builder.launch new file mode 100644 index 000000000..c6037b992 --- /dev/null +++ b/pdex/.externalToolBuilders/Ant_Builder.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/pdex/.project b/pdex/.project index 1be6ebc0c..1dc755de3 100644 --- a/pdex/.project +++ b/pdex/.project @@ -10,6 +10,15 @@ + + org.eclipse.ui.externaltools.ExternalToolBuilder + + + LaunchConfigHandle + <project>/.externalToolBuilders/Ant_Builder.launch + + + org.eclipse.jdt.core.javanature diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 86a4fdc3b..68a37a5b4 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -134,6 +134,7 @@ public class ASTGenerator { renameWindow.setLayout(new GridLayout(3, 1)); renameWindow.add(renameButton); renameWindow.add(listOccurrence); + renameWindow.setTitle("Rename.."); renameTextField = new JTextField(); renameTextField.setPreferredSize(new Dimension(150, 60)); renameWindow.add(renameTextField); @@ -1299,25 +1300,31 @@ public class ASTGenerator { - editor.ta.getSelectedText().length(); HashMap lineOffsetDisplacement = new HashMap(); + // I need to store the pde and java offsets beforehand because once + // the replace starts, all offsets returned are affected + int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; for (int i = defCU.getChildCount() - 1; i >= 0; i--) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); - int pdeoffsets[] = awrap.getPDECodeOffsets(errorCheckerService); - int javaoffsets[] = awrap.getJavaCodeOffsets(errorCheckerService); - + offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); + offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); + } + + for (int i = defCU.getChildCount() - 1; i >= 0; i--) { + int pdeoffsets[] = offsetsMap[i][0]; + int javaoffsets[] = offsetsMap[i][1]; // correction for pde enhancements related displacement on a line int off = 0; - if(lineOffsetDisplacement.get(javaoffsets[0]) != null){ + if (lineOffsetDisplacement.get(javaoffsets[0]) != null) { off = lineOffsetDisplacement.get(javaoffsets[0]); - + lineOffsetDisplacement.put(javaoffsets[0], lineOffsetDisplacementConst + off); - } - else{ + } else { lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst); + lineOffsetDisplacementConst); } - + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], pdeoffsets[1], javaoffsets[1] + off, From 6edd537c4141fd430fc719447f307c707085b179 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 00:16:21 +0530 Subject: [PATCH 079/608] added manual error check function to ECS --- .../mode/experimental/ASTGenerator.java | 35 +++++++++++-------- .../experimental/ErrorCheckerService.java | 10 +++++- .../mode/experimental/TextArea.java | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 68a37a5b4..1229aa1dc 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -110,45 +110,47 @@ public class ASTGenerator { private JButton renameButton; - private JButton listOccurrence; + private JButton btnListOccurrence; private JTextField renameTextField; + private JFrame occurenceListFrame; + public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; this.editor = ecs.getEditor(); frame2 = new JFrame(); jtree = new JTree(); - frame2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame2.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frame2.setBounds(new Rectangle(680, 100, 460, 620)); JScrollPane sp = new JScrollPane(); sp.setViewportView(jtree); frame2.add(sp); renameButton = new JButton("Rename"); - listOccurrence = new JButton("Find All"); + btnListOccurrence = new JButton("Find All"); renameWindow = new JFrame(); - renameWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + renameWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); renameWindow.setBounds(new Rectangle(680, 50, 150, 150)); renameWindow.setLayout(new GridLayout(3, 1)); renameWindow.add(renameButton); - renameWindow.add(listOccurrence); + renameWindow.add(btnListOccurrence); renameWindow.setTitle("Rename.."); renameTextField = new JTextField(); renameTextField.setPreferredSize(new Dimension(150, 60)); renameWindow.add(renameTextField); - renameWindow.setVisible(true); + //renameWindow.setVisible(true); - JFrame frame4 = new JFrame(); - frame4.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame4.setBounds(new Rectangle(1100, 50, 350, 500)); + occurenceListFrame = new JFrame(); + occurenceListFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + occurenceListFrame.setBounds(new Rectangle(1100, 50, 350, 500)); JScrollPane sp2 = new JScrollPane(); renameTree = new JTree(); sp2.setViewportView(renameTree); - frame4.add(sp2); - frame4.setVisible(true); + occurenceListFrame.add(sp2); + //occurenceListFrame.setVisible(true); // frameAutoComp = new JFrame(); // frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); @@ -1296,6 +1298,7 @@ public class ASTGenerator { DefaultMutableTreeNode defCU = findAllOccurrences(); renameTree.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) renameTree.getModel()).reload(); + occurenceListFrame.setVisible(true); int lineOffsetDisplacementConst = newName.length() - editor.ta.getSelectedText().length(); HashMap lineOffsetDisplacement = new HashMap(); @@ -1336,13 +1339,16 @@ public class ASTGenerator { + lineOffsetDisplacement.get(lineNum)); } editor.getSketch().setModified(true); + errorCheckerService.runManualErrorCheck(); + occurenceListFrame.setVisible(false); + renameWindow.setVisible(false); } }; worker.execute(); } }); // TODO: Diable this listner at deployment - listOccurrence.addActionListener(new ActionListener() { + btnListOccurrence.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -1356,9 +1362,10 @@ public class ASTGenerator { protected void done() { if (editor.ta.getSelectedText() == null) return; - DefaultMutableTreeNode defCU = findAllOccurrences(); + DefaultMutableTreeNode defCU = findAllOccurrences(); renameTree.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) renameTree.getModel()).reload(); + ((DefaultTreeModel) renameTree.getModel()).reload(); + occurenceListFrame.setVisible(true); } }; worker.execute(); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 39de86ea4..67448450b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -260,7 +260,15 @@ public class ErrorCheckerService implements Runnable{ } protected ASTGenerator astGenerator; - AtomicInteger textModified = new AtomicInteger(); + private AtomicInteger textModified = new AtomicInteger(); + + /** + * Triggers error check + */ + public void runManualErrorCheck() { + textModified.incrementAndGet(); + } + private boolean checkCode() { System.out.println("checkCode() " + textModified.get() ); lastTimeStamp = System.currentTimeMillis(); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index e07cda0b3..1ec3c2ffc 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -166,7 +166,7 @@ public class TextArea extends JEditTextArea { super.processKeyEvent(evt); if (evt.getID() == KeyEvent.KEY_TYPED) { - errorCheckerService.textModified.incrementAndGet(); + errorCheckerService.runManualErrorCheck(); System.out.println(" Typing: " + fetchPhrase(evt) + " " + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); From 17184b499ecafa2997b02ca856727a0ff6f41def Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 00:34:32 +0530 Subject: [PATCH 080/608] refactoring fields --- .../mode/experimental/ASTGenerator.java | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1229aa1dc..9ec48f6e2 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -96,7 +96,7 @@ public class ASTGenerator { /** * JTree used for testing refactoring operations */ - private JTree renameTree; + private JTree treeRename; private CompilationUnit compilationUnit; @@ -108,17 +108,23 @@ public class ASTGenerator { private JFrame renameWindow; - private JButton renameButton; + private JButton btnRename; private JButton btnListOccurrence; private JTextField renameTextField; - private JFrame occurenceListFrame; + private JFrame frmOccurenceList; public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; this.editor = ecs.getEditor(); + setupGUI(); + //addCompletionPopupListner(); + addListeners(); + } + + private void setupGUI(){ frame2 = new JFrame(); jtree = new JTree(); @@ -128,13 +134,13 @@ public class ASTGenerator { sp.setViewportView(jtree); frame2.add(sp); - renameButton = new JButton("Rename"); + btnRename = new JButton("Rename"); btnListOccurrence = new JButton("Find All"); renameWindow = new JFrame(); renameWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); renameWindow.setBounds(new Rectangle(680, 50, 150, 150)); renameWindow.setLayout(new GridLayout(3, 1)); - renameWindow.add(renameButton); + renameWindow.add(btnRename); renameWindow.add(btnListOccurrence); renameWindow.setTitle("Rename.."); renameTextField = new JTextField(); @@ -142,14 +148,14 @@ public class ASTGenerator { renameWindow.add(renameTextField); //renameWindow.setVisible(true); - occurenceListFrame = new JFrame(); - occurenceListFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - occurenceListFrame.setBounds(new Rectangle(1100, 50, 350, 500)); + frmOccurenceList = new JFrame(); + frmOccurenceList.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + frmOccurenceList.setBounds(new Rectangle(1100, 50, 350, 500)); JScrollPane sp2 = new JScrollPane(); - renameTree = new JTree(); - sp2.setViewportView(renameTree); - occurenceListFrame.add(sp2); + treeRename = new JTree(); + sp2.setViewportView(treeRename); + frmOccurenceList.add(sp2); //occurenceListFrame.setVisible(true); // frameAutoComp = new JFrame(); @@ -172,9 +178,6 @@ public class ASTGenerator { // jdocWindow.add(scrollPane); // jdocMap = new TreeMap(); //// loadJars(); - - //addCompletionPopupListner(); - addListeners(); } private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { @@ -1278,7 +1281,7 @@ public class ASTGenerator { } }); - renameButton.addActionListener(new ActionListener() { + btnRename.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -1296,9 +1299,9 @@ public class ASTGenerator { return; String newName = renameTextField.getText(); DefaultMutableTreeNode defCU = findAllOccurrences(); - renameTree.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) renameTree.getModel()).reload(); - occurenceListFrame.setVisible(true); + treeRename.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) treeRename.getModel()).reload(); + frmOccurenceList.setVisible(true); int lineOffsetDisplacementConst = newName.length() - editor.ta.getSelectedText().length(); HashMap lineOffsetDisplacement = new HashMap(); @@ -1340,7 +1343,7 @@ public class ASTGenerator { } editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); - occurenceListFrame.setVisible(false); + frmOccurenceList.setVisible(false); renameWindow.setVisible(false); } }; @@ -1363,16 +1366,16 @@ public class ASTGenerator { if (editor.ta.getSelectedText() == null) return; DefaultMutableTreeNode defCU = findAllOccurrences(); - renameTree.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) renameTree.getModel()).reload(); - occurenceListFrame.setVisible(true); + treeRename.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) treeRename.getModel()).reload(); + frmOccurenceList.setVisible(true); } }; worker.execute(); } }); - renameTree.addTreeSelectionListener(new TreeSelectionListener() { + treeRename.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { @@ -1385,11 +1388,11 @@ public class ASTGenerator { } protected void done() { - if(renameTree + if(treeRename .getLastSelectedPathComponent() == null){ return; } - DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) renameTree + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) treeRename .getLastSelectedPathComponent(); if(tnode.getUserObject() == null){ return; From 4fe3de6ee3fc41e9270d60573ab0a5dea4a17341 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 01:11:36 +0530 Subject: [PATCH 081/608] work on renaming ui --- .../mode/experimental/ASTGenerator.java | 79 +++++++++++++------ 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9ec48f6e2..c8774bfef 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -24,9 +24,14 @@ import java.util.Map; import java.util.Stack; import java.util.TreeMap; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; @@ -106,16 +111,18 @@ public class ASTGenerator { private JScrollPane scrollPane; - private JFrame renameWindow; + private JFrame frmRename; private JButton btnRename; private JButton btnListOccurrence; - private JTextField renameTextField; + private JTextField txtRenameField; private JFrame frmOccurenceList; + private JLabel lblRefactorOldName; + public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; this.editor = ecs.getEditor(); @@ -136,17 +143,32 @@ public class ASTGenerator { btnRename = new JButton("Rename"); btnListOccurrence = new JButton("Find All"); - renameWindow = new JFrame(); - renameWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - renameWindow.setBounds(new Rectangle(680, 50, 150, 150)); - renameWindow.setLayout(new GridLayout(3, 1)); - renameWindow.add(btnRename); - renameWindow.add(btnListOccurrence); - renameWindow.setTitle("Rename.."); - renameTextField = new JTextField(); - renameTextField.setPreferredSize(new Dimension(150, 60)); - renameWindow.add(renameTextField); + frmRename = new JFrame(); + frmRename.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + frmRename.setBounds(new Rectangle(680, 50, 250, 130)); + frmRename.setLayout(new BoxLayout(frmRename.getContentPane(), BoxLayout.Y_AXIS)); + JPanel panelTop = new JPanel(), panelBottom = new JPanel(); + panelTop.setLayout(new BoxLayout(panelTop, BoxLayout.Y_AXIS)); + panelTop.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.X_AXIS)); + panelBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + panelBottom.add(Box.createHorizontalGlue()); + panelBottom.add(btnListOccurrence); + panelBottom.add(Box.createRigidArea(new Dimension(15, 0))); + panelBottom.add(btnRename); + frmRename.setTitle("Enter new name:"); + txtRenameField = new JTextField(); + txtRenameField.setPreferredSize(new Dimension(150, 60)); + panelTop.add(txtRenameField); //renameWindow.setVisible(true); + lblRefactorOldName = new JLabel(); + lblRefactorOldName.setText("Old Name: "); + panelTop.add(Box.createRigidArea(new Dimension(0, 10))); + panelTop.add(lblRefactorOldName); + frmRename.add(panelTop); + frmRename.add(panelBottom); + + frmRename.setMinimumSize(frmRename.getSize()); frmOccurenceList = new JFrame(); frmOccurenceList.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); @@ -1284,7 +1306,9 @@ public class ASTGenerator { btnRename.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionPerformed(ActionEvent e) { + if(txtRenameField.getText().length() == 0) + return; SwingWorker worker = new SwingWorker() { @Override @@ -1293,11 +1317,8 @@ public class ASTGenerator { } protected void done() { - if (editor.ta.getSelectedText() == null) - return; - if(renameTextField.getText().length() == 0) - return; - String newName = renameTextField.getText(); + + String newName = txtRenameField.getText(); DefaultMutableTreeNode defCU = findAllOccurrences(); treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); @@ -1344,7 +1365,7 @@ public class ASTGenerator { editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); frmOccurenceList.setVisible(false); - renameWindow.setVisible(false); + frmRename.setVisible(false); } }; worker.execute(); @@ -1363,8 +1384,6 @@ public class ASTGenerator { } protected void done() { - if (editor.ta.getSelectedText() == null) - return; DefaultMutableTreeNode defCU = findAllOccurrences(); treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); @@ -1560,9 +1579,21 @@ public class ASTGenerator { } public void handleRefactor(){ - if (!renameWindow.isVisible()) - renameWindow.setVisible(true); - renameWindow.toFront(); + if(editor.ta.getSelectedText() == null){ + return; + } + if (!frmRename.isVisible()){ + frmRename.setVisible(true); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + lblRefactorOldName.setText("Current name: " + + editor.ta.getSelectedText()); + txtRenameField.requestFocus(); + } + }); + } + frmRename.toFront(); } From 6d3629305b4f88bcffd14e4828ec71014fd966a8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 01:48:10 +0530 Subject: [PATCH 082/608] repaint quirks --- .../processing/mode/experimental/ASTGenerator.java | 1 + .../mode/experimental/ErrorCheckerService.java | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index c8774bfef..7d06e953c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1580,6 +1580,7 @@ public class ASTGenerator { public void handleRefactor(){ if(editor.ta.getSelectedText() == null){ + editor.statusError("Highlight the class/function/variable name first"); return; } if (!frmRename.isVisible()){ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 67448450b..a80dba777 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -300,6 +300,7 @@ public class ErrorCheckerService implements Runnable{ updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); + editor.getTextArea().repaint(); updatePaintedThingys(); int x = textModified.get(); //System.out.println("TM " + x); @@ -698,15 +699,15 @@ public class ErrorCheckerService implements Runnable{ /** * Repaints the textarea if required */ - public void updatePaintedThingys() { - editor.getTextArea().repaint(); - updateEditorStatus(); + public void updatePaintedThingys() { currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); - //System.out.println("awesome! " + currentTab + " LT " + lastTab); + //System.out.println("Tab changed " + currentTab + " LT " + lastTab); if (currentTab != lastTab) { - textModified.incrementAndGet(); + textModified.set(5); lastTab = currentTab; + editor.getTextArea().repaint(); + updateEditorStatus(); return; } From dabba4d46a9c4a63caf96c0464a77132d69a9d3b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 01:50:50 +0530 Subject: [PATCH 083/608] probably nicked something elsewhere, so for now. --- pdex/src/processing/mode/experimental/ErrorCheckerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index a80dba777..4f132412a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -341,7 +341,8 @@ public class ErrorCheckerService implements Runnable{ problemsList = new ArrayList(); for (int i = 0; i < problems.length; i++) { int a[] = calculateTabIndexAndLineNumber(problems[i]); - Problem p = new Problem(problems[i], a[0], a[1]); + Problem p = new Problem(problems[i], a[0], a[1] + 1); + //TODO: ^Why do cheeky stuff? problemsList.add(p); // System.out.println(p.toString()); } From 67d67db602261580db9a1d380109acd6ebe7e60c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 02:05:39 +0530 Subject: [PATCH 084/608] an error msg for spl case --- pdex/src/processing/mode/experimental/ASTGenerator.java | 5 +++++ .../mode/experimental/ErrorCheckerService.java | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 7d06e953c..29348659d 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1583,6 +1583,11 @@ public class ASTGenerator { editor.statusError("Highlight the class/function/variable name first"); return; } + + if(errorCheckerService.hasSyntaxErrors()){ + editor.statusError("Can't rename until syntax errors are fixed :("); + return; + } if (!frmRename.isVisible()){ frmRename.setVisible(true); SwingUtilities.invokeLater(new Runnable() { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 4f132412a..5f5389a2b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -185,6 +185,7 @@ public class ErrorCheckerService implements Runnable{ defaultImportsOffset = pdePrepoc.getCoreImports().length + pdePrepoc.getDefaultImports().length + 1; astGenerator = new ASTGenerator(this); + syntaxErrors = true; } /** @@ -321,6 +322,12 @@ public class ErrorCheckerService implements Runnable{ } return false; } + + private boolean syntaxErrors; + + public boolean hasSyntaxErrors(){ + return syntaxErrors; + } private void syntaxCheck() { parser.setSource(sourceCode.toCharArray()); @@ -346,6 +353,8 @@ public class ErrorCheckerService implements Runnable{ problemsList.add(p); // System.out.println(p.toString()); } + + syntaxErrors = problems.length == 0 ? false : true; } protected URLClassLoader classLoader; private void compileCheck() { From 2d8ceb608821270f75e0e7fab26919fc598ada27 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 02:17:39 +0530 Subject: [PATCH 085/608] editor status update fix --- .../src/processing/mode/experimental/ErrorCheckerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 5f5389a2b..d16b08f7b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -249,7 +249,7 @@ public class ErrorCheckerService implements Runnable{ } updatePaintedThingys(); - + updateEditorStatus(); if (pauseThread) continue; if(textModified.get() == 0) @@ -717,7 +717,7 @@ public class ErrorCheckerService implements Runnable{ textModified.set(5); lastTab = currentTab; editor.getTextArea().repaint(); - updateEditorStatus(); + editor.statusEmpty(); return; } From 0ff824c7fac93dff7b91d31b54944eaefeeacc0e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Jun 2013 02:21:01 +0530 Subject: [PATCH 086/608] updated todo --- pdex/README.md | 1 + pdex/Todo, GSoC 2013.txt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pdex/README.md b/pdex/README.md index 0ca2aa456..4b944dedf 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -6,4 +6,5 @@ This project is in the process of being moved out of the main project so that it Stay tuned for updates. Manindra Moharana + 29 June 2013 diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 754eb4b3a..caa3b1df8 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -50,7 +50,8 @@ x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. * Undo misbehaves here, handle carefully. * Handle saving. If sketch closed after renaming w/o saving find bugs. -* Refactoring ui +x Refactoring ui +x For now, user needs to highlight the name of the var, and then right-click -> Rename.. * Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully Quick Navigation From 16cb89900632494ff01baecc0a016f39d4e26aa0 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 5 Jul 2013 18:15:35 +0530 Subject: [PATCH 087/608] Updated gitignore --- pdex/.gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pdex/.gitignore b/pdex/.gitignore index ba077a403..d86e35085 100644 --- a/pdex/.gitignore +++ b/pdex/.gitignore @@ -1 +1,7 @@ +.DS_Store +.AppleDouble +._* +*~ bin +mode/ExperimentalMode.jar + From 1c593af14db09a318d50dc4517b82b76d90ae029 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 5 Jul 2013 18:19:37 +0530 Subject: [PATCH 088/608] Updated todo, untracking EMode.jar --- pdex/Todo, GSoC 2013.txt | 11 +++++------ .../processing/mode/experimental/ASTGenerator.java | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index caa3b1df8..2185b7af6 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -13,27 +13,26 @@ x! Code competition for local code is working with recursive look up. x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. x Completion for external classes - ArrayList, HashMap, etc. *! Recursive lookup for compiled(library) code! -*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned -ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. +*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. *! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. -*+ Differentiating between multiple statements on the same line. How to? +x Differentiating between multiple statements on the same line. How to? Done with offset handling. Finer details * Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? * Sorted list of completion candidates - fields, then methods. It's unsorted presently. -*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. +*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * Reflection API - getMethods vs getDeclaredMethods. -* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? +* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement Offset Mapping ============== First major hurdle is offset mapping *! pde<->java code offset : precise conversion needed x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. -* This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. +x This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. x Edge case - multiple statements in a single line x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. * The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 29348659d..99c522ba4 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -183,7 +183,7 @@ public class ASTGenerator { // frameAutoComp = new JFrame(); // frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); -// tableAuto = new JTable(); + tableAuto = new JTable(); // JScrollPane sp2 = new JScrollPane(); // sp2.setViewportView(tableAuto); // frameAutoComp.add(sp2); @@ -1593,6 +1593,8 @@ public class ASTGenerator { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { + frmOccurenceList.setTitle("All occurrences of " + + editor.ta.getSelectedText()); lblRefactorOldName.setText("Current name: " + editor.ta.getSelectedText()); txtRenameField.requestFocus(); From 633837ffa7b6a428a865ec1e171d8fa05eb87a33 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 5 Jul 2013 21:01:51 +0530 Subject: [PATCH 089/608] changing to def list model --- .../mode/experimental/ASTGenerator.java | 41 ++++---- .../mode/experimental/CompletionPanel.java | 52 +++++----- .../mode/experimental/TextArea.java | 97 ++++++++++++++++--- 3 files changed, 135 insertions(+), 55 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 99c522ba4..2f1f3e03e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -27,6 +27,7 @@ import java.util.TreeMap; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; @@ -180,13 +181,13 @@ public class ASTGenerator { frmOccurenceList.add(sp2); //occurenceListFrame.setVisible(true); -// frameAutoComp = new JFrame(); -// frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); -// frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); + frameAutoComp = new JFrame(); + frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); tableAuto = new JTable(); -// JScrollPane sp2 = new JScrollPane(); -// sp2.setViewportView(tableAuto); -// frameAutoComp.add(sp2); + JScrollPane sp3 = new JScrollPane(); + sp3.setViewportView(tableAuto); + frameAutoComp.add(sp3); // jdocWindow = new JFrame(); // jdocWindow.setTitle("P5 InstaHelp"); @@ -240,11 +241,11 @@ public class ASTGenerator { if (!frame2.isVisible()) { frame2.setVisible(true); } -// if (!frameAutoComp.isVisible()) { -// -// frameAutoComp.setVisible(true); -// -// } + if (!frameAutoComp.isVisible()) { + + frameAutoComp.setVisible(true); + + } // if (!jdocWindow.isVisible()) { // long t = System.currentTimeMillis(); // loadJars(); @@ -772,9 +773,12 @@ public class ASTGenerator { Collections.sort(candidates); CompletionCandidate[][] candi = new CompletionCandidate[candidates .size()][1]; + + DefaultListModel defListModel = new DefaultListModel(); for (int i = 0; i < candi.length; i++) { candi[i][0] = candidates.get(i); + defListModel.addElement(candidates.get(i)); } System.out.println("K = " + candidates.size()); DefaultTableModel tm = new DefaultTableModel( @@ -783,11 +787,10 @@ public class ASTGenerator { tableAuto.setModel(tm); tableAuto.validate(); tableAuto.repaint(); - //String[] items = - CompletionCandidate[] candi2 = candidates - .toArray(new CompletionCandidate[candidates.size()]); - if (candidates.size() > 0) - errorCheckerService.getEditor().textArea().showSuggestion(candi2); +// CompletionCandidate[] candidatesArray = candidates +// .toArray(new CompletionCandidate[candidates.size()]); + errorCheckerService.getEditor().textArea() + .showSuggestion(defListModel); } }; @@ -859,7 +862,9 @@ public class ASTGenerator { } public void updateJavaDoc(final CompletionCandidate candidate) { - String methodmatch = candidate.toString(); + //TODO: Work on this later. + return; + /*String methodmatch = candidate.toString(); if (methodmatch.indexOf('(') != -1) { methodmatch = methodmatch.substring(0, methodmatch.indexOf('(')); } @@ -886,7 +891,7 @@ public class ASTGenerator { }); break; } - } + }*/ //jdocWindow.setVisible(false); } diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 3e0f7678d..1f62ecb6b 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -7,16 +7,18 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; +import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; +import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.text.BadLocationException; import processing.app.syntax.JEditTextArea; public class CompletionPanel { - private JList list; + private JList completionList; private JPopupMenu popupMenu; @@ -29,7 +31,7 @@ public class CompletionPanel { private JScrollPane scrollPane; public CompletionPanel(JEditTextArea textarea, int position, String subWord, - CompletionCandidate[] items, Point location) { + DefaultListModel items, Point location) { this.textarea = (TextArea) textarea; this.insertionPosition = position; if (subWord.indexOf('.') != -1) @@ -41,17 +43,13 @@ public class CompletionPanel { popupMenu.setOpaque(false); popupMenu.setBorder(null); scrollPane = new JScrollPane(); - scrollPane.setViewportView(list = createSuggestionList(position, items)); + scrollPane.setViewportView(completionList = createSuggestionList(position, items)); popupMenu.add(scrollPane, BorderLayout.CENTER); this.textarea.errorCheckerService.astGenerator - .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - - } - - public void hide() { - popupMenu.setVisible(false); + System.out.println("Suggestion shown"); } public boolean isVisible() { @@ -59,7 +57,7 @@ public class CompletionPanel { } public JList createSuggestionList(final int position, - final CompletionCandidate[] items) { + final DefaultListModel items) { JList list = new JList(items); list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); @@ -76,11 +74,18 @@ public class CompletionPanel { }); return list; } + + public boolean updateList(final CompletionCandidate[] items){ + ListModel lm = completionList.getModel(); + DefaultListModel dlm = new DefaultListModel(); + + return true; + } public boolean insertSelection() { - if (list.getSelectedValue() != null) { + if (completionList.getSelectedValue() != null) { try { - final String selectedSuggestion = ((CompletionCandidate) list + final String selectedSuggestion = ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString().substring(subWord.length()); textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null); @@ -96,44 +101,45 @@ public class CompletionPanel { } public void hideSuggestion() { - hide(); + popupMenu.setVisible(false); + System.out.println("Suggestion hidden"); //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); } public void moveUp() { - if (list.getSelectedIndex() == 0) { + if (completionList.getSelectedIndex() == 0) { scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); - selectIndex(list.getModel().getSize() - 1); + selectIndex(completionList.getModel().getSize() - 1); return; } else { - int index = Math.max(list.getSelectedIndex() - 1, 0); + int index = Math.max(completionList.getSelectedIndex() - 1, 0); selectIndex(index); } int step = scrollPane.getVerticalScrollBar().getMaximum() - / list.getModel().getSize(); + / completionList.getModel().getSize(); scrollPane.getVerticalScrollBar().setValue(scrollPane .getVerticalScrollBar() .getValue() - step); textarea.errorCheckerService.astGenerator - .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); } public void moveDown() { - if (list.getSelectedIndex() == list.getModel().getSize() - 1) { + if (completionList.getSelectedIndex() == completionList.getModel().getSize() - 1) { scrollPane.getVerticalScrollBar().setValue(0); selectIndex(0); return; } else { - int index = Math.min(list.getSelectedIndex() + 1, list.getModel() + int index = Math.min(completionList.getSelectedIndex() + 1, completionList.getModel() .getSize() - 1); selectIndex(index); } textarea.errorCheckerService.astGenerator - .updateJavaDoc((CompletionCandidate) list.getSelectedValue()); + .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); int step = scrollPane.getVerticalScrollBar().getMaximum() - / list.getModel().getSize(); + / completionList.getModel().getSize(); scrollPane.getVerticalScrollBar().setValue(scrollPane .getVerticalScrollBar() .getValue() @@ -141,7 +147,7 @@ public class CompletionPanel { } private void selectIndex(int index) { - list.setSelectedIndex(index); + completionList.setSelectedIndex(index); // final int position = textarea.getCaretPosition(); // SwingUtilities.invokeLater(new Runnable() { // @Override diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 1ec3c2ffc..77b054cdd 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -30,6 +30,7 @@ import java.awt.event.MouseMotionListener; import java.util.HashMap; import java.util.Map; +import javax.swing.DefaultListModel; import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; @@ -126,7 +127,65 @@ public class TextArea extends JEditTextArea { } public void processKeyEvent(KeyEvent evt) { + + if(evt.getKeyCode() == KeyEvent.VK_ESCAPE){ + if(suggestion != null){ + if(suggestion.isVisible()){ + System.out.println("esc key"); + hideSuggestion(); + return; + } + } + } + if (evt.getID() == KeyEvent.KEY_PRESSED) { + switch (evt.getKeyCode()) { + case KeyEvent.VK_DOWN: + if (suggestion != null) + if (suggestion.isVisible()) { + //System.out.println("KeyDown"); + suggestion.moveDown(); + return; + } + break; + case KeyEvent.VK_UP: + if (suggestion != null) + if (suggestion.isVisible()) { + //System.out.println("KeyUp"); + suggestion.moveUp(); + return; + } + break; + case KeyEvent.VK_ENTER: + if (suggestion != null) { + if (suggestion.isVisible()) { + if (suggestion.insertSelection()) { + //final int position = getCaretPosition(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + //getDocument().remove(position - 1, 1); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + return; + } + } + } + break; + case KeyEvent.VK_BACK_SPACE: + System.out.println("BK Key"); + break; + default: + break; + } + } + super.processKeyEvent(evt); + + /* if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { if (suggestion.isVisible()) { //System.out.println("KeyDown"); @@ -162,16 +221,17 @@ public class TextArea extends JEditTextArea { } else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) { System.out.println("BK Key"); } - } + + }*/ - super.processKeyEvent(evt); - if (evt.getID() == KeyEvent.KEY_TYPED) { - errorCheckerService.runManualErrorCheck(); - System.out.println(" Typing: " + fetchPhrase(evt) + " " - + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); + if (evt.getID() == KeyEvent.KEY_TYPED) { + errorCheckerService.runManualErrorCheck(); + System.out.println(" Typing: " + fetchPhrase(evt) + " " + + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); - } + } + } private String fetchPhrase(KeyEvent evt) { @@ -560,7 +620,8 @@ public class TextArea extends JEditTextArea { // } // // }); - } else if (Character.isWhitespace(e.getKeyChar())) { + } else if (Character.isWhitespace(e.getKeyChar()) + || e.getKeyChar() == KeyEvent.VK_ESCAPE) { hideSuggestion(); } } @@ -571,18 +632,22 @@ public class TextArea extends JEditTextArea { }); } - public void showSuggestionLater(final CompletionCandidate[] items) { + public void showSuggestionLater(final DefaultListModel defListModel) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - showSuggestion(items); + showSuggestion(defListModel); } }); } - protected void showSuggestion(CompletionCandidate[] items) { - hideSuggestion(); + protected void showSuggestion(DefaultListModel defListModel) { + if(defListModel.size() == 0){ + return; + } + + hideSuggestion(); final int position = getCaretPosition(); Point location = new Point(); try { @@ -594,6 +659,7 @@ public class TextArea extends JEditTextArea { e2.printStackTrace(); return; } + String text = getText(); int start = Math.max(0, position - 1); while (start > 0) { @@ -604,14 +670,17 @@ public class TextArea extends JEditTextArea { break; } } + if (start > position) { return; } + final String subWord = text.substring(start, position); if (subWord.length() < 2) { return; } - suggestion = new CompletionPanel(this, position, subWord, items, location); + + suggestion = new CompletionPanel(this, position, subWord, defListModel, location); // requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { @Override @@ -623,7 +692,7 @@ public class TextArea extends JEditTextArea { private void hideSuggestion() { if (suggestion != null) { - suggestion.hide(); + suggestion.hideSuggestion(); } } From 2cd97490f0dab0a5ecc4fda22779fe8076bc8d0a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 5 Jul 2013 21:29:43 +0530 Subject: [PATCH 090/608] work on completion list behaviour --- .../mode/experimental/CompletionPanel.java | 15 ++++-- .../mode/experimental/TextArea.java | 46 +++++++++++-------- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 1f62ecb6b..e3c8ec4ef 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -24,7 +24,7 @@ public class CompletionPanel { private String subWord; - private final int insertionPosition; + private int insertionPosition; private TextArea textarea; @@ -75,10 +75,15 @@ public class CompletionPanel { return list; } - public boolean updateList(final CompletionCandidate[] items){ - ListModel lm = completionList.getModel(); - DefaultListModel dlm = new DefaultListModel(); - + public boolean updateList(final DefaultListModel items, String newSubword, int position){ + completionList.setModel(items); + completionList.validate(); + completionList.repaint(); + completionList.setSelectedIndex(0); + this.subWord = new String(newSubword); + if (subWord.indexOf('.') != -1) + this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); + insertionPosition = position; return true; } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 77b054cdd..982d83e7b 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -100,7 +100,7 @@ public class TextArea extends JEditTextArea { MouseHandler mouseHandler = new MouseHandler(); painter.addMouseListener(mouseHandler); painter.addMouseMotionListener(mouseHandler); - addCompletionPopupListner(); + //addCompletionPopupListner(); add(CENTER, painter); // load settings from theme.txt @@ -600,6 +600,7 @@ public class TextArea extends JEditTextArea { //JEditTextArea textarea; + // worthless private void addCompletionPopupListner() { this.addKeyListener(new KeyListener() { @@ -646,19 +647,21 @@ public class TextArea extends JEditTextArea { if(defListModel.size() == 0){ return; } - - hideSuggestion(); - final int position = getCaretPosition(); - Point location = new Point(); - try { - location.x = offsetToX(getCaretLine(), position - - getLineStartOffset(getCaretLine())); - location.y = lineToY(getCaretLine()) - + getPainter().getFontMetrics().getHeight(); - } catch (Exception e2) { - e2.printStackTrace(); - return; - } + String subWord = null; + int position = getCaretPosition(); +// if (suggestion == null || !suggestion.isVisible()) { + Point location = new Point(); + try { + location.x = offsetToX(getCaretLine(), position + - getLineStartOffset(getCaretLine())); + location.y = lineToY(getCaretLine()) + + getPainter().getFontMetrics().getHeight(); + } catch (Exception e2) { + e2.printStackTrace(); + return; + } + +// } String text = getText(); int start = Math.max(0, position - 1); @@ -670,17 +673,21 @@ public class TextArea extends JEditTextArea { break; } } - + if (start > position) { return; } - - final String subWord = text.substring(start, position); + + subWord = text.substring(start, position); if (subWord.length() < 2) { return; } - - suggestion = new CompletionPanel(this, position, subWord, defListModel, location); + if(suggestion == null) + suggestion = new CompletionPanel(this, position, subWord, defListModel, + location); + else + suggestion.updateList(defListModel, subWord, position); + // requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { @Override @@ -693,6 +700,7 @@ public class TextArea extends JEditTextArea { private void hideSuggestion() { if (suggestion != null) { suggestion.hideSuggestion(); + suggestion = null; } } From f90f8b56f4c39ccf17f671c42b09e14af3259070 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 5 Jul 2013 23:55:35 +0530 Subject: [PATCH 091/608] completion list now hides better --- pdex/Todo, GSoC 2013.txt | 4 ++ .../mode/experimental/CompletionPanel.java | 20 +++++-- .../mode/experimental/TextArea.java | 60 ++++++++++++------- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2185b7af6..2f7dd80c8 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -27,6 +27,10 @@ Finer details * Reflection API - getMethods vs getDeclaredMethods. * Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement +Completion List +* Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) +* List should get hidden on hitting esc key + Offset Mapping ============== First major hurdle is offset mapping diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index e3c8ec4ef..b18b28d12 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -2,6 +2,7 @@ package processing.mode.experimental; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -45,18 +46,19 @@ public class CompletionPanel { scrollPane = new JScrollPane(); scrollPane.setViewportView(completionList = createSuggestionList(position, items)); popupMenu.add(scrollPane, BorderLayout.CENTER); + popupMenu.setPopupSize(200, 250); //TODO: Eradicate this evil this.textarea.errorCheckerService.astGenerator .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - System.out.println("Suggestion shown"); + System.out.println("Suggestion constructed" + System.nanoTime()); } public boolean isVisible() { return popupMenu.isVisible(); } - public JList createSuggestionList(final int position, + private JList createSuggestionList(final int position, final DefaultListModel items) { JList list = new JList(items); @@ -75,15 +77,21 @@ public class CompletionPanel { return list; } - public boolean updateList(final DefaultListModel items, String newSubword, int position){ + public boolean updateList(final DefaultListModel items, String newSubword, int position){ + scrollPane.getViewport().removeAll(); + Dimension dimen = popupMenu.getSize(); completionList.setModel(items); - completionList.validate(); - completionList.repaint(); + completionList.validate(); completionList.setSelectedIndex(0); + scrollPane.setViewportView(completionList); + scrollPane.validate(); + popupMenu.setSize(dimen); + this.subWord = new String(newSubword); if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); insertionPosition = position; + System.out.println("Suggestion updated" + System.nanoTime()); return true; } @@ -107,7 +115,7 @@ public class CompletionPanel { public void hideSuggestion() { popupMenu.setVisible(false); - System.out.println("Suggestion hidden"); + System.out.println("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 982d83e7b..808611f3c 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -133,10 +133,23 @@ public class TextArea extends JEditTextArea { if(suggestion.isVisible()){ System.out.println("esc key"); hideSuggestion(); + evt.consume(); return; } } } + if(evt.getKeyCode() == KeyEvent.VK_ENTER){ + if (suggestion != null) { + if (suggestion.isVisible()) { + if (suggestion.insertSelection()) { + hideSuggestion(); // Kill it! + evt.consume(); + return; + } + } + } + } + if (evt.getID() == KeyEvent.KEY_PRESSED) { switch (evt.getKeyCode()) { @@ -156,26 +169,27 @@ public class TextArea extends JEditTextArea { return; } break; - case KeyEvent.VK_ENTER: - if (suggestion != null) { - if (suggestion.isVisible()) { - if (suggestion.insertSelection()) { - //final int position = getCaretPosition(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - //getDocument().remove(position - 1, 1); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - return; - } - } - } - break; +// case KeyEvent.VK_ENTER: +// if (suggestion != null) { +// if (suggestion.isVisible()) { +// if (suggestion.insertSelection()) { +// hideSuggestion(); // Kill it! +// //final int position = getCaretPosition(); +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// try { +// //getDocument().remove(position - 1, 1); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// }); +// return; +// } +// } +// } +// break; case KeyEvent.VK_BACK_SPACE: System.out.println("BK Key"); break; @@ -227,7 +241,7 @@ public class TextArea extends JEditTextArea { if (evt.getID() == KeyEvent.KEY_TYPED) { errorCheckerService.runManualErrorCheck(); System.out.println(" Typing: " + fetchPhrase(evt) + " " - + (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE)); + + (evt.getKeyChar() == KeyEvent.VK_ENTER)); } @@ -256,6 +270,10 @@ public class TextArea extends JEditTextArea { System.out.print(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); char keyChar = evt.getKeyChar(); + if(keyChar == KeyEvent.VK_ENTER){ + System.out.println("Enter consumed."); + return null; + } if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) ; // accepted these keys else if (keyChar == KeyEvent.CHAR_UNDEFINED) From 2664668d2417c32d12faeb71306a6ba97553c432 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 6 Jul 2013 00:59:09 +0530 Subject: [PATCH 092/608] text insert bug fix --- .../mode/experimental/ASTGenerator.java | 4 +- .../mode/experimental/CompletionPanel.java | 3 +- .../mode/experimental/TextArea.java | 71 +++++++------------ 3 files changed, 30 insertions(+), 48 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 2f1f3e03e..87f7e8718 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -790,7 +790,7 @@ public class ASTGenerator { // CompletionCandidate[] candidatesArray = candidates // .toArray(new CompletionCandidate[candidates.size()]); errorCheckerService.getEditor().textArea() - .showSuggestion(defListModel); + .showSuggestion(defListModel,word); } }; @@ -1376,7 +1376,7 @@ public class ASTGenerator { worker.execute(); } }); - // TODO: Diable this listner at deployment + btnListOccurrence.addActionListener(new ActionListener() { @Override diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index b18b28d12..6b853e10d 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -98,8 +98,9 @@ public class CompletionPanel { public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { - final String selectedSuggestion = ((CompletionCandidate) completionList + String selectedSuggestion = ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString().substring(subWord.length()); + System.err.println(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null); textarea.setCaretPosition(insertionPosition diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 808611f3c..b51c522d8 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -249,6 +249,17 @@ public class TextArea extends JEditTextArea { } private String fetchPhrase(KeyEvent evt) { + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_ENTER) { + System.out.println("Enter consumed."); + return null; + } +// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) +// ; // accepted these keys + else if (keyChar == KeyEvent.CHAR_UNDEFINED) { + return null; + } + int off = getCaretPosition(); System.out.print("off " + off); if (off < 0) @@ -268,17 +279,7 @@ public class TextArea extends JEditTextArea { if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. System.out.print(" x char: " + s.charAt(x)); - //int xLS = off - getLineStartNonWhiteSpaceOffset(line); - char keyChar = evt.getKeyChar(); - if(keyChar == KeyEvent.VK_ENTER){ - System.out.println("Enter consumed."); - return null; - } - if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) - ; // accepted these keys - else if (keyChar == KeyEvent.CHAR_UNDEFINED) - - return null; + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; if (s.trim().length() == 1) { @@ -651,58 +652,38 @@ public class TextArea extends JEditTextArea { }); } - public void showSuggestionLater(final DefaultListModel defListModel) { + public void showSuggestionLater(final DefaultListModel defListModel, final String word) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - showSuggestion(defListModel); + showSuggestion(defListModel,word); } }); } - protected void showSuggestion(DefaultListModel defListModel) { - if(defListModel.size() == 0){ + protected void showSuggestion(DefaultListModel defListModel,String subWord) { + if (defListModel.size() == 0) { return; } - String subWord = null; int position = getCaretPosition(); -// if (suggestion == null || !suggestion.isVisible()) { - Point location = new Point(); - try { - location.x = offsetToX(getCaretLine(), position - - getLineStartOffset(getCaretLine())); - location.y = lineToY(getCaretLine()) - + getPainter().getFontMetrics().getHeight(); - } catch (Exception e2) { - e2.printStackTrace(); - return; - } - -// } - - String text = getText(); - int start = Math.max(0, position - 1); - while (start > 0) { - if (!Character.isWhitespace(text.charAt(start))) { - start--; - } else { - start++; - break; - } - } - - if (start > position) { + Point location = new Point(); + try { + location.x = offsetToX(getCaretLine(), position + - getLineStartOffset(getCaretLine())); + location.y = lineToY(getCaretLine()) + + getPainter().getFontMetrics().getHeight(); + } catch (Exception e2) { + e2.printStackTrace(); return; } - subWord = text.substring(start, position); if (subWord.length() < 2) { return; } - if(suggestion == null) + if (suggestion == null) suggestion = new CompletionPanel(this, position, subWord, defListModel, - location); + location); else suggestion.updateList(defListModel, subWord, position); From cf36b39de4c4b6283db47539a4cdd6296530910f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 6 Jul 2013 01:15:19 +0530 Subject: [PATCH 093/608] hide list on no matches --- pdex/src/processing/mode/experimental/TextArea.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index b51c522d8..e70e5fe57 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -664,6 +664,8 @@ public class TextArea extends JEditTextArea { protected void showSuggestion(DefaultListModel defListModel,String subWord) { if (defListModel.size() == 0) { + System.out.println("No suggestions to show."); + hideSuggestion(); return; } int position = getCaretPosition(); From 1f81485160be5bc6210f5c0c3cbd4f84da0e342a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 6 Jul 2013 01:50:10 +0530 Subject: [PATCH 094/608] a warning and todo updates --- pdex/Todo, GSoC 2013.txt | 6 +++--- .../mode/experimental/ASTGenerator.java | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2f7dd80c8..856ee76c8 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -20,7 +20,7 @@ x! Should I implement wrapper for ASTNode? - possibly needed for code completion x Differentiating between multiple statements on the same line. How to? Done with offset handling. Finer details -* Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. +x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? * Sorted list of completion candidates - fields, then methods. It's unsorted presently. *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. @@ -28,8 +28,8 @@ Finer details * Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement Completion List -* Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) -* List should get hidden on hitting esc key +x Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) +x List should get hidden on hitting esc key Offset Mapping ============== diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 87f7e8718..86f7ff2a5 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1751,8 +1751,18 @@ public class ASTGenerator { return null; } + /** + * Give this thing a {@link Name} instance - a {@link SimpleName} from the + * ASTNode for ex, and it tries its level best to locate its declaration in + * the AST. It really does. + * + * @param findMe + * @return + */ @SuppressWarnings("unchecked") private static ASTNode findDeclaration(Name findMe) { + // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. + // To debug this code, thou must take take the Recursive Leap of Faith. ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); ASTNode ret = null; @@ -1908,6 +1918,12 @@ public class ASTGenerator { return null; } + /** + * A variation of findDeclaration() but accepts an alternate parent ASTNode + * @param findMe + * @param alternateParent + * @return + */ private static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); From e6a0c1e8c423c9066828ae41c802e3d9fce37b73 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 6 Jul 2013 23:30:30 +0530 Subject: [PATCH 095/608] Begun work on 3rd party completions --- .../mode/experimental/ASTGenerator.java | 362 ++++++++++++++++-- 1 file changed, 323 insertions(+), 39 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 86f7ff2a5..e1dfd2c41 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -11,6 +11,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -511,6 +512,40 @@ public class ASTGenerator { return null; } + + /** + * Find the parent of the expression in a().b, this would give me the return + * type of a(), so that we can find all children of a() begininng with b + * This is the 3rd party variant, for .jar files. + * @param nearestNode + * @param expression + * @return + */ + public static ASTNode resolveExpression3rdParty(ASTNode nearestNode, + ASTNode expression) { +// ASTNode anode = null; + System.out.println("Resolving " + getNodeAsString(expression)); + if (expression instanceof SimpleName) { + return findDeclaration2(((SimpleName) expression), nearestNode); + } else if (expression instanceof MethodInvocation) { + return findDeclaration2(((MethodInvocation) expression).getName(), + nearestNode); + } else if (expression instanceof FieldAccess) { + System.out.println("2. Field access " + + getNodeAsString(((FieldAccess) expression).getExpression())); + return resolveExpression(nearestNode, + ((FieldAccess) expression).getExpression()); + //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); + } else if (expression instanceof QualifiedName) { + System.out.println("1. Resolving " + + ((QualifiedName) expression).getQualifier() + " ||| " + + ((QualifiedName) expression).getName()); + return findDeclaration2(((QualifiedName) expression).getQualifier(), + nearestNode); + } + + return null; + } /** * For a().abc.a123 this would return a123 @@ -817,49 +852,107 @@ public class ASTGenerator { for (String className : resources) { System.out.println("-> " + className); } - if (resources.length > 0) { //TODO: Multiple matched classes? What about 'em? - String matchedClass = resources[0]; - matchedClass = matchedClass.substring(0, matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - System.out.println("In GMFT(), Matched class: " + matchedClass); - System.out.println("Looking for match " + child.toString()); - try { - Class probableClass = Class.forName(matchedClass, false, - errorCheckerService.classLoader); - - for (Method method : probableClass.getMethods()) { - if (!Modifier.isStatic(method.getModifiers()) && staticOnly) - continue; - StringBuffer label = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) - label.append(","); - } - - label.append(")"); - if (noCompare) - candidates.add(new CompletionCandidate(method)); - else if (label.toString().startsWith(child.toString())) - candidates.add(new CompletionCandidate(method)); - } - for (Field field : probableClass.getFields()) { - if (!Modifier.isStatic(field.getModifiers()) && staticOnly) - continue; - if (noCompare) - candidates.add(new CompletionCandidate(field)); - else if (field.getName().startsWith(child.toString())) - candidates.add(new CompletionCandidate(field)); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - System.out.println("Couldn't load " + matchedClass); - } + if (resources.length == 0) { + System.out.println("In GMFT(), couldn't find class: " + typeName); + return candidates; } + //TODO: Multiple matched classes? What about 'em? + String matchedClass = resources[0]; + matchedClass = matchedClass.substring(0, matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + System.out.println("In GMFT(), Matched class: " + matchedClass); + System.out.println("Looking for match " + child.toString()); + try { + Class probableClass = Class.forName(matchedClass, false, + errorCheckerService.classLoader); + + for (Method method : probableClass.getMethods()) { + if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { + continue; + } + + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); + } + label.append(")"); + + if (noCompare) { + candidates.add(new CompletionCandidate(method)); + } + else if (label.toString().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(method)); + } + } + for (Field field : probableClass.getFields()) { + if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { + continue; + } + if (noCompare) { + candidates.add(new CompletionCandidate(field)); + } + else if (field.getName().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(field)); + } + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.out.println("Couldn't load " + matchedClass); + } + //updateJavaDoc(methodmatch) return candidates; } + + public ClassMember definedIn3rdPartyClass(String className,String memberName){ + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", className + ".class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String cn : resources) { + System.out.println("-> " + cn); + } + if (resources.length == 0) { + System.out.println("In GMFT(), couldn't find class: " + className); + return null; + } + //TODO: Multiple matched classes? What about 'em? + String matchedClass = resources[0]; + matchedClass = matchedClass.substring(0, matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + System.out.println("In GMFT(), Matched class: " + matchedClass); + System.out.println("Looking for match " + memberName.toString()); + try { + Class probableClass = Class.forName(matchedClass, false, + errorCheckerService.classLoader); + + for (Method method : probableClass.getMethods()) { + + + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); + } + label.append(")"); + if (label.toString().startsWith(memberName)) { + return new ClassMember(method); + } + } + for (Field field : probableClass.getFields()) { + if (field.getName().startsWith(memberName)) { + return new ClassMember(field); + } + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.out.println("Couldn't load " + matchedClass); + } + return null; + } public void updateJavaDoc(final CompletionCandidate candidate) { //TODO: Work on this later. @@ -1762,7 +1855,7 @@ public class ASTGenerator { @SuppressWarnings("unchecked") private static ASTNode findDeclaration(Name findMe) { // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. - // To debug this code, thou must take take the Recursive Leap of Faith. + // To debug this code, thou must take the Recursive Leap of Faith. ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); ASTNode ret = null; @@ -2084,6 +2177,197 @@ public class ASTGenerator { } return null; } + + /** + * A wrapper for java.lang.reflect types + * Will see if the usage turns out to be internal only here or not + * and then accordingly decide where to place this class. TODO + * @author quarkninja + * + */ + public class ClassMember { + private Field field; + private Method method; + private Constructor cons; + public ClassMember(Method m){ + method = m; + } + public ClassMember(Field m){ + field = m; + } + public ClassMember(Constructor m){ + cons = m; + } + public Field getField() { + return field; + } + public Method getMethod() { + return method; + } + public Constructor getCons() { + return cons; + } + } + + private CompletionCandidate findDeclaration3rdParty(Name findMe, String parentClass){ + CompletionCandidate declaringClass = null; + ASTNode parent = findMe.getParent(); + ArrayList constrains = new ArrayList(); + if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { + Expression exp = (Expression) ((MethodInvocation) parent) + .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); + //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); + // Possibly a bug here. Investigate later. + if (((MethodInvocation) parent).getName().toString() + .equals(findMe.toString())) { + constrains.add(ASTNode.METHOD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("MI EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + //declaringClass = findDeclaration(stp.getName()); +// return definedIn(declaringClass, ((MethodInvocation) parent) +// .getName().toString(), constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + //declaringClass = findDeclaration((stp.getName())); +// return definedIn(declaringClass, ((MethodInvocation) parent) +// .getName().toString(), constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + //declaringClass = findDeclaration(stp.getName()); + //System.out.println("MI.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); +// return definedIn(declaringClass, ((MethodInvocation) parent) +// .getName().toString(), constrains, declaringClass); + } + + } + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { + FieldAccess fa = (FieldAccess) parent; + Expression exp = fa.getExpression(); + if (fa.getName().toString().equals(findMe.toString())) { + constrains.add(ASTNode.FIELD_DECLARATION); + + if (exp != null) { + constrains.add(ASTNode.TYPE_DECLARATION); + System.out.println("FA EXP: " + exp.toString() + " of type " + + exp.getClass().getName() + " parent: " + exp.getParent()); + if (exp instanceof MethodInvocation) { + SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + .getName())); + if (stp == null) + return null; + //declaringClass = findDeclaration(stp.getName()); +// return definedIn(declaringClass, fa.getName().toString(), +// constrains, declaringClass); + } else if (exp instanceof FieldAccess) { + SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) + .getName())); + if (stp == null) + return null; + //declaringClass = findDeclaration((stp.getName())); + constrains.add(ASTNode.TYPE_DECLARATION); +// return definedIn(declaringClass, fa.getName().toString(), +// constrains, declaringClass); + } + if (exp instanceof SimpleName) { + SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); + if (stp == null) + return null; + //declaringClass = findDeclaration(stp.getName()); + // System.out.println("FA.SN " + getNodeAsString(declaringClass)); + constrains.add(ASTNode.METHOD_DECLARATION); +// return definedIn(declaringClass, fa.getName().toString(), +// constrains, declaringClass); + } + } + + } else { + parent = parent.getParent(); // Move one up the ast. V V IMP!! + } + } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { + + QualifiedName qn = (QualifiedName) parent; + if (!findMe.toString().equals(qn.getQualifier().toString())) { + + SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); + // declaringClass = findDeclaration(stp.getName()); + System.out.println(qn.getQualifier() + "->" + qn.getName()); + // System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); +// return definedIn(declaringClass, qn.getName().toString(), constrains, +// null); + } + } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) +// constrains.add(ASTNode.CLASS_INSTANCE_CREATION); + // If it's a simple type, simply locate it within the list of imports + ArrayList retList = getMembersForType(findMe.toString(), "", true, false); + if(retList.size() > 0) + return retList.get(0); + } else if(parent.getNodeType() == ASTNode.TYPE_DECLARATION){ + // The condition where we look up the name of a class decl +/* TypeDeclaration td = (TypeDeclaration) parent; + if(findMe.equals(td.getName())) + { + return parent; + } + } + else if (parent instanceof Expression) { +// constrains.add(ASTNode.TYPE_DECLARATION); +// constrains.add(ASTNode.METHOD_DECLARATION); +// constrains.add(ASTNode.FIELD_DECLARATION); + } + while (parent != null) { + System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); + for (Object oprop : parent.structuralPropertiesForType()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; + if (prop.isChildProperty() || prop.isSimpleProperty()) { + if (parent.getStructuralProperty(prop) instanceof ASTNode) { +// System.out.println(prop + " C/S Prop of -> " +// + getNodeAsString(parent)); + ret = definedIn((ASTNode) parent.getStructuralProperty(prop), + findMe.toString(), constrains, declaringClass); + if (ret != null) + return ret; + } + } else if (prop.isChildListProperty()) { +// System.out.println((prop) + " ChildList props of " +// + getNodeAsString(parent)); + List nodelist = (List) parent + .getStructuralProperty(prop); + for (ASTNode retNode : nodelist) { + ret = definedIn(retNode, findMe.toString(), constrains, + declaringClass); + if (ret != null) + return ret; + } + } + } + parent = parent.getParent(); + */ + } + return null; + } /** * Find the SimpleType from FD, SVD, VDS, etc From 993a2921ced877baff7e8bff72452a916aabeeb8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 6 Jul 2013 23:59:31 +0530 Subject: [PATCH 096/608] Further work on 3rd party completions --- .../mode/experimental/ASTGenerator.java | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index e1dfd2c41..6e9ba4057 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -915,44 +915,44 @@ public class ASTGenerator { System.out.println("-> " + cn); } if (resources.length == 0) { - System.out.println("In GMFT(), couldn't find class: " + className); + System.out.println("In defIn3rdPar(), couldn't find class: " + className); return null; } //TODO: Multiple matched classes? What about 'em? String matchedClass = resources[0]; matchedClass = matchedClass.substring(0, matchedClass.length() - 6); matchedClass = matchedClass.replace('/', '.'); - System.out.println("In GMFT(), Matched class: " + matchedClass); + System.out.println("In defIn3rdPar(), Matched class: " + matchedClass); System.out.println("Looking for match " + memberName.toString()); + try { Class probableClass = Class.forName(matchedClass, false, errorCheckerService.classLoader); - - for (Method method : probableClass.getMethods()) { - - - StringBuffer label = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) - label.append(","); - } - label.append(")"); - if (label.toString().startsWith(memberName)) { - return new ClassMember(method); - } - } - for (Field field : probableClass.getFields()) { - if (field.getName().startsWith(memberName)) { - return new ClassMember(field); - } + if(memberName.equals("THIS")){ + return new ClassMember(probableClass); } + return definedIn3rdPartyClass(new ClassMember(probableClass), memberName); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("Couldn't load " + matchedClass); } return null; } + + public ClassMember definedIn3rdPartyClass(ClassMember tehClass,String memberName){ + Class probableClass = tehClass.getClass_(); + for (Method method : probableClass.getMethods()) { + if (method.getName().equals(memberName)) { + return new ClassMember(method); + } + } + for (Field field : probableClass.getFields()) { + if (field.getName().equals(memberName)) { + return new ClassMember(field); + } + } + return null; + } public void updateJavaDoc(final CompletionCandidate candidate) { //TODO: Work on this later. @@ -2179,8 +2179,8 @@ public class ASTGenerator { } /** - * A wrapper for java.lang.reflect types - * Will see if the usage turns out to be internal only here or not + * A wrapper for java.lang.reflect types. + * Will have to see if the usage turns out to be internal only here or not * and then accordingly decide where to place this class. TODO * @author quarkninja * @@ -2189,6 +2189,10 @@ public class ASTGenerator { private Field field; private Method method; private Constructor cons; + private Class thisclass; + public ClassMember(Class m){ + thisclass = m; + } public ClassMember(Method m){ method = m; } @@ -2198,6 +2202,9 @@ public class ASTGenerator { public ClassMember(Constructor m){ cons = m; } + public Class getClass_(){ + return thisclass; + } public Field getField() { return field; } @@ -2209,8 +2216,8 @@ public class ASTGenerator { } } - private CompletionCandidate findDeclaration3rdParty(Name findMe, String parentClass){ - CompletionCandidate declaringClass = null; + private ClassMember findDeclaration3rdParty(Name findMe, String parentClass){ + ClassMember declaringClass = null; ASTNode parent = findMe.getParent(); ArrayList constrains = new ArrayList(); if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { @@ -2227,13 +2234,19 @@ public class ASTGenerator { System.out.println("MI EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { - SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) - .getName())); - if (stp == null) - return null; +// SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) +// .getName())); +// if (stp == null) +// return null; //declaringClass = findDeclaration(stp.getName()); + declaringClass = findDeclaration3rdParty(((MethodInvocation) exp) + .getName(), + parentClass); // return definedIn(declaringClass, ((MethodInvocation) parent) // .getName().toString(), constrains, declaringClass); + return definedIn3rdPartyClass(declaringClass, + ((MethodInvocation) parent).getName() + .toString()); } else if (exp instanceof FieldAccess) { SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) .getName())); @@ -2321,9 +2334,7 @@ public class ASTGenerator { // if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) // constrains.add(ASTNode.CLASS_INSTANCE_CREATION); // If it's a simple type, simply locate it within the list of imports - ArrayList retList = getMembersForType(findMe.toString(), "", true, false); - if(retList.size() > 0) - return retList.get(0); + return definedIn3rdPartyClass(findMe.toString(), "THIS"); } else if(parent.getNodeType() == ASTNode.TYPE_DECLARATION){ // The condition where we look up the name of a class decl /* TypeDeclaration td = (TypeDeclaration) parent; From 4b535a734d099f3410bd1503237bb96ae8d13b58 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 7 Jul 2013 02:00:55 +0530 Subject: [PATCH 097/608] bug fix in local completion involving qualified name/field access --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 134 +++++++++++++++--- 2 files changed, 119 insertions(+), 16 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 856ee76c8..2f39e818b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -20,6 +20,7 @@ x! Should I implement wrapper for ASTNode? - possibly needed for code completion x Differentiating between multiple statements on the same line. How to? Done with offset handling. Finer details +* - Multiple 3rd party classes found in various packages x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? * Sorted list of completion candidates - fields, then methods. It's unsorted presently. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 6e9ba4057..d778ecc56 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -940,6 +940,8 @@ public class ASTGenerator { } public ClassMember definedIn3rdPartyClass(ClassMember tehClass,String memberName){ + if(tehClass == null) + return null; Class probableClass = tehClass.getClass_(); for (Method method : probableClass.getMethods()) { if (method.getName().equals(memberName)) { @@ -1252,6 +1254,15 @@ public class ASTGenerator { System.err.println("null"); System.out.println(getNodeAsString(decl)); + + // - findDecl3 testing + + ClassMember cmem = findDeclaration3rdParty((SimpleName) simpName, null); + if(cmem != null){ + System.out.println("CMEM-> "+cmem); + } + else + System.out.println("CMEM-> null"); } } @@ -1856,6 +1867,8 @@ public class ASTGenerator { private static ASTNode findDeclaration(Name findMe) { // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. // To debug this code, thou must take the Recursive Leap of Faith. + + System.out.println("entering --findDeclaration1 -- " + findMe.toString()); ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); ASTNode ret = null; @@ -1954,8 +1967,9 @@ public class ASTGenerator { if (!findMe.toString().equals(qn.getQualifier().toString())) { SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); - declaringClass = findDeclaration(stp.getName()); System.out.println(qn.getQualifier() + "->" + qn.getName()); + declaringClass = findDeclaration(stp.getName()); + System.out.println("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); @@ -1963,6 +1977,27 @@ public class ASTGenerator { return definedIn(declaringClass, qn.getName().toString(), constrains, null); } + else{ + System.out.println("hereeee."); + if(findMe instanceof QualifiedName){ + QualifiedName qnn = (QualifiedName) findMe; + System.out.println("findMe is a QN, " + + (qnn.getQualifier().toString() + " other " + qnn.getName() + .toString())); + + SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); + System.out.println(qnn.getQualifier() + "->" + qnn.getName()); + declaringClass = findDeclaration(stp.getName()); + + System.out.println("QN decl class: " + + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qnn.getName().toString(), constrains, + null); + } + } } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { constrains.add(ASTNode.TYPE_DECLARATION); if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) @@ -1980,6 +2015,13 @@ public class ASTGenerator { // constrains.add(ASTNode.METHOD_DECLARATION); // constrains.add(ASTNode.FIELD_DECLARATION); } +// else if(findMe instanceof QualifiedName){ +// QualifiedName qn = (QualifiedName) findMe; +// System.out +// .println("findMe is a QN, " +// + (qn.getQualifier().toString() + " other " + qn.getName() +// .toString())); +// } while (parent != null) { System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); for (Object oprop : parent.structuralPropertiesForType()) { @@ -2187,36 +2229,61 @@ public class ASTGenerator { */ public class ClassMember { private Field field; + private Method method; + private Constructor cons; + private Class thisclass; - public ClassMember(Class m){ + + private String stringVal; + + public ClassMember(Class m) { thisclass = m; + stringVal = "Class " + m.getName(); } - public ClassMember(Method m){ + + public ClassMember(Method m) { method = m; + stringVal = "Method " + m.getReturnType().getName() + " | " + m.getName() + + " defined in " + m.getDeclaringClass().getName(); } - public ClassMember(Field m){ + + public ClassMember(Field m) { field = m; + stringVal = "Field " + m.getType().getName() + " | " + m.getName() + + " defined in " + m.getDeclaringClass().getName(); } - public ClassMember(Constructor m){ + + public ClassMember(Constructor m) { cons = m; + stringVal = "Cons " + " " + m.getName() + " defined in " + + m.getDeclaringClass().getName(); } - public Class getClass_(){ + + public Class getClass_() { return thisclass; } + public Field getField() { return field; } + public Method getMethod() { return method; } + public Constructor getCons() { return cons; } + + public String toString() { + return stringVal; + } } private ClassMember findDeclaration3rdParty(Name findMe, String parentClass){ + System.out.println("--findDec 3rd-- " + findMe + " , " + parentClass); ClassMember declaringClass = null; ASTNode parent = findMe.getParent(); ArrayList constrains = new ArrayList(); @@ -2248,10 +2315,16 @@ public class ASTGenerator { ((MethodInvocation) parent).getName() .toString()); } else if (exp instanceof FieldAccess) { - SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) - .getName())); - if (stp == null) - return null; +// SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) +// .getName())); +// if (stp == null) +// return null; + declaringClass = findDeclaration3rdParty(((FieldAccess) exp) + .getName(), + parentClass); + return definedIn3rdPartyClass(declaringClass, + ((MethodInvocation) parent).getName() + .toString()); //declaringClass = findDeclaration((stp.getName())); // return definedIn(declaringClass, ((MethodInvocation) parent) // .getName().toString(), constrains, declaringClass); @@ -2260,9 +2333,15 @@ public class ASTGenerator { SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); if (stp == null) return null; + System.out.println("3rdPa "+stp.getName()); + declaringClass = definedIn3rdPartyClass(stp.getName().toString(), + "THIS"); //declaringClass = findDeclaration(stp.getName()); //System.out.println("MI.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); + return definedIn3rdPartyClass(declaringClass, + ((MethodInvocation) parent).getName() + .toString()); // return definedIn(declaringClass, ((MethodInvocation) parent) // .getName().toString(), constrains, declaringClass); } @@ -2282,32 +2361,51 @@ public class ASTGenerator { System.out.println("FA EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { - SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) + + declaringClass = findDeclaration3rdParty(((MethodInvocation) exp) + .getName(), + parentClass); +// return definedIn(declaringClass, ((MethodInvocation) parent) +// .getName().toString(), constrains, declaringClass); + return definedIn3rdPartyClass(declaringClass, + fa.getName().toString()); + /*SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) .getName())); if (stp == null) - return null; + return null;*/ //declaringClass = findDeclaration(stp.getName()); // return definedIn(declaringClass, fa.getName().toString(), // constrains, declaringClass); } else if (exp instanceof FieldAccess) { - SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) - .getName())); - if (stp == null) - return null; +// SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) +// .getName())); +// if (stp == null) +// return null; //declaringClass = findDeclaration((stp.getName())); + declaringClass = findDeclaration3rdParty(((FieldAccess) exp) + .getName(), + parentClass); constrains.add(ASTNode.TYPE_DECLARATION); // return definedIn(declaringClass, fa.getName().toString(), // constrains, declaringClass); + return definedIn3rdPartyClass(declaringClass, + fa.getName().toString()); } if (exp instanceof SimpleName) { SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); if (stp == null) return null; + System.out.println("3rdPa "+stp.getName()); + declaringClass = definedIn3rdPartyClass(stp.getName().toString(), + "THIS"); //declaringClass = findDeclaration(stp.getName()); // System.out.println("FA.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); // return definedIn(declaringClass, fa.getName().toString(), // constrains, declaringClass); + return definedIn3rdPartyClass(declaringClass, + fa.getName() + .toString()); } } @@ -2320,14 +2418,18 @@ public class ASTGenerator { if (!findMe.toString().equals(qn.getQualifier().toString())) { SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); + // declaringClass = findDeclaration(stp.getName()); System.out.println(qn.getQualifier() + "->" + qn.getName()); // System.out.println("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); + declaringClass = definedIn3rdPartyClass(stp.getName().toString(), + "THIS"); // return definedIn(declaringClass, qn.getName().toString(), constrains, // null); + return definedIn3rdPartyClass(declaringClass, qn.getName().toString()); } } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { // constrains.add(ASTNode.TYPE_DECLARATION); From 6423ae6b9f65e4e27e5d88f110ae78eb8b5566b2 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 7 Jul 2013 12:47:57 +0530 Subject: [PATCH 098/608] bug fix in local completion involving qualified name/field access, fd2 --- .../mode/experimental/ASTGenerator.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index d778ecc56..0157773d5 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1865,6 +1865,7 @@ public class ASTGenerator { */ @SuppressWarnings("unchecked") private static ASTNode findDeclaration(Name findMe) { + // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. // To debug this code, thou must take the Recursive Leap of Faith. @@ -1978,7 +1979,6 @@ public class ASTGenerator { null); } else{ - System.out.println("hereeee."); if(findMe instanceof QualifiedName){ QualifiedName qnn = (QualifiedName) findMe; System.out.println("findMe is a QN, " @@ -2176,6 +2176,26 @@ public class ASTGenerator { return definedIn(declaringClass, qn.getName().toString(), constrains, null); } + else{ + if(findMe instanceof QualifiedName){ + QualifiedName qnn = (QualifiedName) findMe; + System.out.println("findMe is a QN, " + + (qnn.getQualifier().toString() + " other " + qnn.getName() + .toString())); + + SimpleType stp = extracTypeInfo(findDeclaration2((qnn.getQualifier()), alternateParent)); + System.out.println(qnn.getQualifier() + "->" + qnn.getName()); + declaringClass = findDeclaration2(stp.getName(), alternateParent); + + System.out.println("QN decl class: " + + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qnn.getName().toString(), constrains, + null); + } + } } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { constrains.add(ASTNode.TYPE_DECLARATION); if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) From c8683054af6215274bde1d4d0610abeadd5e3243 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 8 Jul 2013 00:53:50 +0530 Subject: [PATCH 099/608] stupid bug. took up the entire evening. squashed. bye. --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 73 ++++++++++++++++--- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2f39e818b..03b0cdbdd 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -10,6 +10,7 @@ Code Completion ============== The big stuff: x! Code competition for local code is working with recursive look up. +x Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. x Completion for external classes - ArrayList, HashMap, etc. *! Recursive lookup for compiled(library) code! diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 0157773d5..1a149baea 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -488,26 +488,58 @@ public class ASTGenerator { * @return */ public static ASTNode resolveExpression(ASTNode nearestNode, - ASTNode expression) { -// ASTNode anode = null; - System.out.println("Resolving " + getNodeAsString(expression)); + ASTNode expression, boolean noCompare) { + System.out.println("Resolving " + getNodeAsString(expression) + " noComp " + + noCompare); if (expression instanceof SimpleName) { return findDeclaration2(((SimpleName) expression), nearestNode); } else if (expression instanceof MethodInvocation) { + System.out.println("3. Method Invo " + + ((MethodInvocation) expression).getName()); return findDeclaration2(((MethodInvocation) expression).getName(), nearestNode); } else if (expression instanceof FieldAccess) { System.out.println("2. Field access " - + getNodeAsString(((FieldAccess) expression).getExpression())); - return resolveExpression(nearestNode, - ((FieldAccess) expression).getExpression()); + + getNodeAsString(((FieldAccess) expression).getExpression()) + "|||" + + getNodeAsString(((FieldAccess) expression).getName())); + if (noCompare) { + /* + * ASTNode ret = findDeclaration2(((FieldAccess) expression).getName(), + * nearestNode); System.out.println("Found as ->"+getNodeAsString(ret)); + * return ret; + */ + return findDeclaration2(((FieldAccess) expression).getName(), + nearestNode); + } else { + + /* + * Note how for the next recursion, noCompare is reversed. Let's say + * I've typed getABC().quark.nin where nin is incomplete(ninja being the + * field), when execution first enters here, it calls resolveExpr again + * for "getABC().quark" where we know that quark field must be complete, + * so we toggle noCompare. And kaboom. + */ + return resolveExpression(nearestNode, + ((FieldAccess) expression).getExpression(), + !noCompare); + } //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); } else if (expression instanceof QualifiedName) { + QualifiedName qn = (QualifiedName) expression; System.out.println("1. Resolving " + ((QualifiedName) expression).getQualifier() + " ||| " + ((QualifiedName) expression).getName()); - return findDeclaration2(((QualifiedName) expression).getQualifier(), - nearestNode); +// ASTNode declaringClass = null; +// if(qn.getQualifier() instanceof QualifiedName) +// declaringClass = resolveExpression(nearestNode, qn); + if (noCompare) { // no compare, as in "abc.hello." need to resolve hello here + return findDeclaration2(((QualifiedName) expression).getName(), + nearestNode); + } else { + //User typed "abc.hello.by" (bye being complete), so need to resolve "abc.hello." only + return findDeclaration2(((QualifiedName) expression).getQualifier(), + nearestNode); + } } return null; @@ -534,7 +566,7 @@ public class ASTGenerator { System.out.println("2. Field access " + getNodeAsString(((FieldAccess) expression).getExpression())); return resolveExpression(nearestNode, - ((FieldAccess) expression).getExpression()); + ((FieldAccess) expression).getExpression(),false); //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); } else if (expression instanceof QualifiedName) { System.out.println("1. Resolving " @@ -715,7 +747,7 @@ public class ASTGenerator { // Have to resolve it by carefully traversing AST of testNode System.err.println("Complex expression " + getNodeAsString(testnode)); - ASTNode det = resolveExpression(nearestNode, testnode); + ASTNode det = resolveExpression(nearestNode, testnode,noCompare); // Find the parent of the expression // in a().b, this would give me the return type of a(), so that we can // find all children of a() begininng with b @@ -2451,6 +2483,25 @@ public class ASTGenerator { // null); return definedIn3rdPartyClass(declaringClass, qn.getName().toString()); } + else{ + if(findMe instanceof QualifiedName){ + QualifiedName qnn = (QualifiedName) findMe; + System.out.println("findMe is a QN, " + + (qnn.getQualifier().toString() + " other " + qnn.getName() + .toString())); + + SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); + System.out.println(qnn.getQualifier() + "->" + qnn.getName()); + declaringClass = definedIn3rdPartyClass(stp.getName().toString(), + "THIS"); +// System.out.println("QN decl class: " +// + getNodeAsString(declaringClass)); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn3rdPartyClass(declaringClass, qnn.getName().toString()); + } + } } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { // constrains.add(ASTNode.TYPE_DECLARATION); // if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) @@ -2710,6 +2761,8 @@ public class ASTGenerator { value = ((SimpleName) node).getFullyQualifiedName() + " | " + className; else if (node instanceof QualifiedName) value = node.toString() + " | " + className; + else if(node instanceof FieldAccess) + value = node.toString() + " | "; else if (className.startsWith("Variable")) value = node.toString() + " | " + className; else if (className.endsWith("Type")) From 08feb4b0a563f466f17ec5151063f228b5e86be9 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 8 Jul 2013 15:39:05 +0530 Subject: [PATCH 100/608] And He said, Let there be light. --- .../mode/experimental/ASTGenerator.java | 223 ++++++++++++------ 1 file changed, 157 insertions(+), 66 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1a149baea..39147c97a 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -525,13 +525,9 @@ public class ASTGenerator { } //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); } else if (expression instanceof QualifiedName) { - QualifiedName qn = (QualifiedName) expression; System.out.println("1. Resolving " + ((QualifiedName) expression).getQualifier() + " ||| " + ((QualifiedName) expression).getName()); -// ASTNode declaringClass = null; -// if(qn.getQualifier() instanceof QualifiedName) -// declaringClass = resolveExpression(nearestNode, qn); if (noCompare) { // no compare, as in "abc.hello." need to resolve hello here return findDeclaration2(((QualifiedName) expression).getName(), nearestNode); @@ -550,32 +546,103 @@ public class ASTGenerator { * type of a(), so that we can find all children of a() begininng with b * This is the 3rd party variant, for .jar files. * @param nearestNode - * @param expression + * @param astNode * @return */ - public static ASTNode resolveExpression3rdParty(ASTNode nearestNode, - ASTNode expression) { + public ClassMember resolveExpression3rdParty(ASTNode nearestNode, + ASTNode astNode) { // ASTNode anode = null; - System.out.println("Resolving " + getNodeAsString(expression)); - if (expression instanceof SimpleName) { - return findDeclaration2(((SimpleName) expression), nearestNode); - } else if (expression instanceof MethodInvocation) { - return findDeclaration2(((MethodInvocation) expression).getName(), + /*System.out.println("Resolving " + getNodeAsString(astNode)); + if (astNode instanceof SimpleName) { + return findDeclaration2(((SimpleName) astNode), nearestNode); + } else if (astNode instanceof MethodInvocation) { + return findDeclaration2(((MethodInvocation) astNode).getName(), nearestNode); - } else if (expression instanceof FieldAccess) { + } else if (astNode instanceof FieldAccess) { System.out.println("2. Field access " - + getNodeAsString(((FieldAccess) expression).getExpression())); + + getNodeAsString(((FieldAccess) astNode).getExpression())); return resolveExpression(nearestNode, - ((FieldAccess) expression).getExpression(),false); + ((FieldAccess) astNode).getExpression(),false); //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); - } else if (expression instanceof QualifiedName) { + } else if (astNode instanceof QualifiedName) { System.out.println("1. Resolving " - + ((QualifiedName) expression).getQualifier() + " ||| " - + ((QualifiedName) expression).getName()); - return findDeclaration2(((QualifiedName) expression).getQualifier(), + + ((QualifiedName) astNode).getQualifier() + " ||| " + + ((QualifiedName) astNode).getName()); + return findDeclaration2(((QualifiedName) astNode).getQualifier(), nearestNode); - } + }*/ + + System.out.println("Resolve 3rdParty expr-- " + getNodeAsString(astNode) + + " nearest node " + getNodeAsString(nearestNode)); + + ClassMember scopeParent = null; + SimpleType stp = null; + if(astNode instanceof SimpleName) + astNode = astNode.getParent(); + switch (astNode.getNodeType()) { + + case ASTNode.FIELD_ACCESS: + FieldAccess fa = (FieldAccess) astNode; + if (fa.getExpression() == null) { + System.out.println("FA,Not implemented."); + return null; + } else { + if (fa.getExpression() instanceof SimpleName) { + stp = extracTypeInfo(findDeclaration2((SimpleName) fa.getExpression(), + nearestNode)); + System.out.println("FA, SN Type " + getNodeAsString(stp)); + scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + } else { + scopeParent = resolveExpression3rdParty(nearestNode, + fa.getExpression()); + } + System.out.println("FA, ScopeParent " + scopeParent); + return definedIn3rdPartyClass(scopeParent, fa.getName().toString()); + } + case ASTNode.METHOD_INVOCATION: + MethodInvocation mi = (MethodInvocation) astNode; + if (mi.getExpression() == null) { + System.out.println("MI,Not implemented."); + return null; + } else { + if (mi.getExpression() instanceof SimpleName) { + stp = extracTypeInfo(findDeclaration2((SimpleName) mi.getExpression(), + nearestNode)); + System.out.println("MI, SN Type " + getNodeAsString(stp)); + scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + } else { + System.out.println("MI EXP.."+getNodeAsString(mi.getExpression())); +// return null; + scopeParent = resolveExpression3rdParty(nearestNode, + mi.getExpression()); + } + System.out.println("MI, ScopeParent " + scopeParent); + return definedIn3rdPartyClass(scopeParent, mi.getName().toString()); + } + case ASTNode.QUALIFIED_NAME: + QualifiedName qn = (QualifiedName) astNode; + if (qn.getQualifier() == null) { + System.out.println("MI,Not implemented."); + return null; + } else { + + if (qn.getQualifier() instanceof SimpleName) { + stp = extracTypeInfo(findDeclaration2(qn.getQualifier(), nearestNode)); + System.out.println("QN, SN Type " + getNodeAsString(stp)); + scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + } else { + scopeParent = resolveExpression3rdParty(nearestNode, + qn.getQualifier()); + } + System.out.println("QN, ScopeParent " + scopeParent); + return definedIn3rdPartyClass(scopeParent, qn.getName().toString()); + } + default: + System.out.println("Unaccounted type " + getNodeAsString(astNode)); + break; + } + return null; } @@ -974,7 +1041,16 @@ public class ASTGenerator { public ClassMember definedIn3rdPartyClass(ClassMember tehClass,String memberName){ if(tehClass == null) return null; - Class probableClass = tehClass.getClass_(); + + Class probableClass = null; + if(tehClass.getClass_() != null){ + probableClass = tehClass.getClass_(); + } + else + { + probableClass = loadClass(tehClass.getTypeAsString()).getClass_(); + System.out.println("Loaded " + probableClass.toString()); + } for (Method method : probableClass.getMethods()) { if (method.getName().equals(memberName)) { return new ClassMember(method); @@ -987,6 +1063,34 @@ public class ASTGenerator { } return null; } + + private ClassMember loadClass(String className){ +// RegExpResourceFilter regExpResourceFilter; +// regExpResourceFilter = new RegExpResourceFilter(".*", className + ".class"); +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String cn : resources) { +// System.out.println("-> " + cn); +// } +// if (resources.length == 0) { +// System.out.println("In defIn3rdPar(), couldn't find class: " + className); +// return null; +// } +// //TODO: Multiple matched classes? What about 'em? +// String matchedClass = resources[0]; +// matchedClass = matchedClass.substring(0, matchedClass.length() - 6); +// matchedClass = matchedClass.replace('/', '.'); +// System.out.println("In defIn3rdPar(), Matched class: " + matchedClass); +// + try { + Class probableClass = Class.forName(className, false, + errorCheckerService.classLoader); + return new ClassMember(probableClass); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.out.println("Couldn't load " + className); + } + return null; + } public void updateJavaDoc(final CompletionCandidate candidate) { //TODO: Work on this later. @@ -1289,7 +1393,10 @@ public class ASTGenerator { // - findDecl3 testing - ClassMember cmem = findDeclaration3rdParty((SimpleName) simpName, null); + ASTNode nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + .get(0)); + ClassMember cmem = resolveExpression3rdParty(nearestNode, + (SimpleName) simpName); if(cmem != null){ System.out.println("CMEM-> "+cmem); } @@ -2289,22 +2396,27 @@ public class ASTGenerator { private Class thisclass; private String stringVal; + + private String classType; public ClassMember(Class m) { thisclass = m; stringVal = "Class " + m.getName(); + classType = m.getName(); } public ClassMember(Method m) { method = m; stringVal = "Method " + m.getReturnType().getName() + " | " + m.getName() + " defined in " + m.getDeclaringClass().getName(); + classType = m.getReturnType().getName(); } public ClassMember(Field m) { field = m; stringVal = "Field " + m.getType().getName() + " | " + m.getName() + " defined in " + m.getDeclaringClass().getName(); + classType = m.getType().getName(); } public ClassMember(Constructor m) { @@ -2332,6 +2444,10 @@ public class ASTGenerator { public String toString() { return stringVal; } + + public String getTypeAsString(){ + return classType; + } } private ClassMember findDeclaration3rdParty(Name findMe, String parentClass){ @@ -2350,7 +2466,7 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("MI EXP: " + exp.toString() + " of type " + System.out.println("3rd Par MI EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { // SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) @@ -2380,6 +2496,21 @@ public class ASTGenerator { //declaringClass = findDeclaration((stp.getName())); // return definedIn(declaringClass, ((MethodInvocation) parent) // .getName().toString(), constrains, declaringClass); + } else if (exp instanceof QualifiedName) { + QualifiedName qnn = (QualifiedName)exp; + System.out.println("exp is a QN, " + + (qnn.getQualifier().toString() + " other " + qnn.getName() + .toString())); + + SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); + System.out.println(qnn.getQualifier() + "->" + qnn.getName()); + declaringClass = findDeclaration3rdParty(stp.getName(), + parentClass); +// System.out.println("QN decl class: " +// + getNodeAsString(declaringClass)); + System.out.println("Decl class " + declaringClass); + return definedIn3rdPartyClass(declaringClass,((MethodInvocation) parent).getName() + .toString()); } if (exp instanceof SimpleName) { SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); @@ -2508,49 +2639,9 @@ public class ASTGenerator { // constrains.add(ASTNode.CLASS_INSTANCE_CREATION); // If it's a simple type, simply locate it within the list of imports return definedIn3rdPartyClass(findMe.toString(), "THIS"); - } else if(parent.getNodeType() == ASTNode.TYPE_DECLARATION){ - // The condition where we look up the name of a class decl -/* TypeDeclaration td = (TypeDeclaration) parent; - if(findMe.equals(td.getName())) - { - return parent; - } - } - else if (parent instanceof Expression) { -// constrains.add(ASTNode.TYPE_DECLARATION); -// constrains.add(ASTNode.METHOD_DECLARATION); -// constrains.add(ASTNode.FIELD_DECLARATION); - } - while (parent != null) { - System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); - for (Object oprop : parent.structuralPropertiesForType()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; - if (prop.isChildProperty() || prop.isSimpleProperty()) { - if (parent.getStructuralProperty(prop) instanceof ASTNode) { -// System.out.println(prop + " C/S Prop of -> " -// + getNodeAsString(parent)); - ret = definedIn((ASTNode) parent.getStructuralProperty(prop), - findMe.toString(), constrains, declaringClass); - if (ret != null) - return ret; - } - } else if (prop.isChildListProperty()) { -// System.out.println((prop) + " ChildList props of " -// + getNodeAsString(parent)); - List nodelist = (List) parent - .getStructuralProperty(prop); - for (ASTNode retNode : nodelist) { - ret = definedIn(retNode, findMe.toString(), constrains, - declaringClass); - if (ret != null) - return ret; - } - } - } - parent = parent.getParent(); - */ - } - return null; + } + + return definedIn3rdPartyClass(parentClass,findMe.toString()); } /** From 27a5eb73276f143838351d70dd71a7655d75c389 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 8 Jul 2013 17:13:45 +0530 Subject: [PATCH 101/608] Then IT happened. --- .../mode/experimental/ASTGenerator.java | 130 ++++++++++++++---- .../mode/experimental/TextArea.java | 2 +- 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 39147c97a..cd970418f 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -550,29 +550,7 @@ public class ASTGenerator { * @return */ public ClassMember resolveExpression3rdParty(ASTNode nearestNode, - ASTNode astNode) { -// ASTNode anode = null; - /*System.out.println("Resolving " + getNodeAsString(astNode)); - if (astNode instanceof SimpleName) { - return findDeclaration2(((SimpleName) astNode), nearestNode); - } else if (astNode instanceof MethodInvocation) { - return findDeclaration2(((MethodInvocation) astNode).getName(), - nearestNode); - } else if (astNode instanceof FieldAccess) { - System.out.println("2. Field access " - + getNodeAsString(((FieldAccess) astNode).getExpression())); - return resolveExpression(nearestNode, - ((FieldAccess) astNode).getExpression(),false); - //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); - } else if (astNode instanceof QualifiedName) { - System.out.println("1. Resolving " - + ((QualifiedName) astNode).getQualifier() + " ||| " - + ((QualifiedName) astNode).getName()); - return findDeclaration2(((QualifiedName) astNode).getQualifier(), - nearestNode); - }*/ - - + ASTNode astNode, boolean noCompare) { System.out.println("Resolve 3rdParty expr-- " + getNodeAsString(astNode) + " nearest node " + getNodeAsString(nearestNode)); @@ -591,11 +569,18 @@ public class ASTGenerator { if (fa.getExpression() instanceof SimpleName) { stp = extracTypeInfo(findDeclaration2((SimpleName) fa.getExpression(), nearestNode)); + if(stp == null){ + /*The type wasn't found in local code, so it might be something like + * System.out.println(), or maybe belonging to super class, etc. + */ + System.out.println("resolve 3rd par, Can't resolve " + fa.getExpression()); + return null; + } System.out.println("FA, SN Type " + getNodeAsString(stp)); scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); } else { scopeParent = resolveExpression3rdParty(nearestNode, - fa.getExpression()); + fa.getExpression(), noCompare); } System.out.println("FA, ScopeParent " + scopeParent); return definedIn3rdPartyClass(scopeParent, fa.getName().toString()); @@ -609,13 +594,20 @@ public class ASTGenerator { if (mi.getExpression() instanceof SimpleName) { stp = extracTypeInfo(findDeclaration2((SimpleName) mi.getExpression(), nearestNode)); + if(stp == null){ + /*The type wasn't found in local code, so it might be something like + * System.out.println(), or maybe belonging to super class, etc. + */ + System.out.println("resolve 3rd par, Can't resolve " + mi.getExpression()); + return null; + } System.out.println("MI, SN Type " + getNodeAsString(stp)); scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); } else { System.out.println("MI EXP.."+getNodeAsString(mi.getExpression())); // return null; scopeParent = resolveExpression3rdParty(nearestNode, - mi.getExpression()); + mi.getExpression(), noCompare); } System.out.println("MI, ScopeParent " + scopeParent); return definedIn3rdPartyClass(scopeParent, mi.getName().toString()); @@ -629,11 +621,18 @@ public class ASTGenerator { if (qn.getQualifier() instanceof SimpleName) { stp = extracTypeInfo(findDeclaration2(qn.getQualifier(), nearestNode)); + if(stp == null){ + /*The type wasn't found in local code, so it might be something like + * System.out.println(), or maybe belonging to super class, etc. + */ + System.out.println("resolve 3rd par, Can't resolve " + qn.getQualifier()); + return null; + } System.out.println("QN, SN Type " + getNodeAsString(stp)); scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); } else { scopeParent = resolveExpression3rdParty(nearestNode, - qn.getQualifier()); + qn.getQualifier(), noCompare); } System.out.println("QN, ScopeParent " + scopeParent); return definedIn3rdPartyClass(scopeParent, qn.getName().toString()); @@ -645,6 +644,16 @@ public class ASTGenerator { return null; } + + private ClassMember findDeclarationInSuperClasses(ASTNode astNode){ + while(astNode != null){ + astNode = astNode.getParent(); + if(astNode instanceof TypeDeclaration) + break; + } + + return null; + } /** * For a().abc.a123 this would return a123 @@ -901,9 +910,17 @@ public class ASTGenerator { true); } } - + if(candidates.size() == 0){ + System.out.println("candidates empty"); + ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, true); + candidates = getMembersForType(expr, + resolveChildExpression(testnode) + .toString(), true, false); + } } - + + + Collections.sort(candidates); CompletionCandidate[][] candi = new CompletionCandidate[candidates .size()][1]; @@ -996,6 +1013,7 @@ public class ASTGenerator { candidates.add(new CompletionCandidate(field)); } } + return candidates; } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("Couldn't load " + matchedClass); @@ -1003,7 +1021,59 @@ public class ASTGenerator { //updateJavaDoc(methodmatch) - return candidates; + return null; + } + + public ArrayList getMembersForType(ClassMember tehClass, String child,boolean noCompare, boolean staticOnly){ + ArrayList candidates = new ArrayList(); + System.out.println("Looking for match " + child.toString()); + try { + Class probableClass; + if(tehClass.getClass_() != null){ + probableClass = tehClass.getClass_(); + } + else + { + probableClass = loadClass(tehClass.getTypeAsString()).getClass_(); + System.out.println("Loaded " + probableClass.toString()); + } + for (Method method : probableClass.getMethods()) { + if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { + continue; + } + + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); + } + label.append(")"); + + if (noCompare) { + candidates.add(new CompletionCandidate(method)); + } + else if (label.toString().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(method)); + } + } + for (Field field : probableClass.getFields()) { + if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { + continue; + } + if (noCompare) { + candidates.add(new CompletionCandidate(field)); + } + else if (field.getName().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(field)); + } + } + return candidates; + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Couldn't load " + tehClass); + } + return null; } public ClassMember definedIn3rdPartyClass(String className,String memberName){ @@ -1396,7 +1466,7 @@ public class ASTGenerator { ASTNode nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); ClassMember cmem = resolveExpression3rdParty(nearestNode, - (SimpleName) simpName); + (SimpleName) simpName, false); if(cmem != null){ System.out.println("CMEM-> "+cmem); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index e70e5fe57..ef027771c 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -664,7 +664,7 @@ public class TextArea extends JEditTextArea { protected void showSuggestion(DefaultListModel defListModel,String subWord) { if (defListModel.size() == 0) { - System.out.println("No suggestions to show."); + System.out.println("TextArea: No suggestions to show."); hideSuggestion(); return; } From 6217be022727cd3c950c0bdbf2f4d01f0c56d5bb Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 8 Jul 2013 22:37:10 +0530 Subject: [PATCH 102/608] Was in a poetic mood and all, but this lame bug had to ruin it all. Nevertheless, fixed --- pdex/Todo, GSoC 2013.txt | 5 +- .../mode/experimental/ASTGenerator.java | 122 ++++++------------ .../mode/experimental/ASTNodeWrapper.java | 66 ++++++++++ .../mode/experimental/TextArea.java | 5 +- 4 files changed, 109 insertions(+), 89 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 03b0cdbdd..8ee9a09e6 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -11,11 +11,14 @@ Code Completion The big stuff: x! Code competition for local code is working with recursive look up. x Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed +x Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. +Ex - "s.substring(int(13.4))." fails. Thinking to just do the substitutions before sending it to updatePredictions(), coz offsets aren't really a concern here, right? Yup, fixed it! x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. x Completion for external classes - ArrayList, HashMap, etc. *! Recursive lookup for compiled(library) code! *! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. -*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. +*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. + - Making very good progress here. The elegance of recurion - Hats off! x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x Differentiating between multiple statements on the same line. How to? Done with offset handling. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index cd970418f..be1e636ad 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -669,11 +669,29 @@ public class ASTGenerator { return ((FieldAccess) expression).getName(); } else if (expression instanceof QualifiedName) { return ((QualifiedName) expression).getName(); + }else if (expression instanceof MethodInvocation) { + return ((MethodInvocation) expression).getName(); } System.out.println(" resolveChildExpression returning NULL for " + getNodeAsString(expression)); return null; } + + public static ASTNode resolveParentExpression(ASTNode expression) { +// ASTNode anode = null; + if (expression instanceof SimpleName) { + return expression; + } else if (expression instanceof FieldAccess) { + return ((FieldAccess) expression).getExpression(); + } else if (expression instanceof QualifiedName) { + return ((QualifiedName) expression).getQualifier(); + } else if (expression instanceof MethodInvocation) { + return ((MethodInvocation) expression).getExpression(); + } + System.out.println("resolveParentExpression returning NULL for " + + getNodeAsString(expression)); + return null; +} public static TypeDeclaration getDefiningNode(ASTNode node) { ASTNode parent = node.getParent(); @@ -685,7 +703,7 @@ public class ASTGenerator { return (TypeDeclaration) parent; } - public void updatePredictions(final String word, final int line) { + public void updatePredictions(final String word, final int line, final int lineStartNonWSOffset) { SwingWorker worker = new SwingWorker() { @Override @@ -695,16 +713,16 @@ public class ASTGenerator { protected void done() { - String word2 = word; + String word2 = ASTNodeWrapper.getJavaCode(word); //After typing 'arg.' all members of arg type are to be listed. This one is a flag for it boolean noCompare = false; if (word2.endsWith(".")) { // return all matches - word2 = word2.substring(0, word.length() - 1); + word2 = word2.substring(0, word2.length() - 1); noCompare = true; } - + int lineNumber = line; // Adjust line number for tabbed sketches if (errorCheckerService != null) { @@ -726,7 +744,7 @@ public class ASTGenerator { parser.setKind(ASTParser.K_EXPRESSION); parser.setSource(word2.toCharArray()); ASTNode testnode = parser.createAST(null); - + //System.err.println("PREDICTION PARSER PROBLEMS: " + parser); // Find closest ASTNode of the document to this word System.err.print("Typed: " + word2 + "|"); nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() @@ -912,10 +930,17 @@ public class ASTGenerator { } if(candidates.size() == 0){ System.out.println("candidates empty"); - ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, true); + String childExpr = resolveChildExpression(testnode) + .toString(); + System.out.println("Child expression : " + childExpr); + if(!noCompare){ + System.out.println("Original testnode " + getNodeAsString(testnode)); + testnode = resolveParentExpression(testnode); + System.out.println("Corrected testnode " + getNodeAsString(testnode)); + } + ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); candidates = getMembersForType(expr, - resolveChildExpression(testnode) - .toString(), true, false); + childExpr, noCompare, false); } } @@ -1201,7 +1226,7 @@ public class ASTGenerator { private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { Iterator it = node .structuralPropertiesForType().iterator(); - //System.err.println("Props of " + node.getClass().getName()); + System.err.println("Props of " + node.getClass().getName()); while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -1212,7 +1237,7 @@ public class ASTGenerator { // .println(node.getStructuralProperty(prop) + " -> " + (prop)); if (node.getStructuralProperty(prop) instanceof ASTNode) { ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); -// System.out.println("Looking at " + getNodeAsString(cnode)); +// System.out.println("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber); int cLineNum = ((CompilationUnit) cnode.getRoot()) .getLineNumber(cnode.getStartPosition() + cnode.getLength()); if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { @@ -1228,7 +1253,7 @@ public class ASTGenerator { for (ASTNode cnode : nodelist) { int cLineNum = ((CompilationUnit) cnode.getRoot()) .getLineNumber(cnode.getStartPosition() + cnode.getLength()); -// System.out.println("Looking at " + getNodeAsString(cnode)); +// System.out.println("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber); if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { return findClosestParentNode(lineNumber, cnode); } @@ -1272,81 +1297,6 @@ public class ASTGenerator { return null; } -// static DefaultMutableTreeNode findNodeBS(DefaultMutableTreeNode tree, -// int lineNumber, String name, -// int elementOffset) { -// if (tree.getUserObject() == null) -// return null; -// -// ASTNodeWrapper node = ((ASTNodeWrapper) tree.getUserObject()); -// -// if (node.getLineNumber() == lineNumber) { -// System.out.println("Located line " + lineNumber + " , " + tree); -// if (name == null) -// return tree; -// else -// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() -// .getStartPosition()); -// } -// -// int low = 0, high = tree.getChildCount() - 1, mid = (high + low) / 2; -// DefaultMutableTreeNode tnode = null; -// while (low <= high) { -// mid = (high + low) / 2; -// tnode = (DefaultMutableTreeNode) tree.getChildAt(mid); -// node = ((ASTNodeWrapper) tnode.getUserObject()); -// if (node.getLineNumber() == lineNumber) { -// System.out.println("Located line " + lineNumber + " , " + tnode); -// if (name == null) -// return tnode; -// else -// return findOnLine(tnode, lineNumber, name, elementOffset, node -// .getNode().getStartPosition()); -// } else if (lineNumber < node.getLineNumber()) { -// high = mid - 1; -// } else { -// if (high - mid <= 1) { -// if (lineNumber > ((ASTNodeWrapper) ((DefaultMutableTreeNode) tree -// .getChildAt(high)).getUserObject()).getLineNumber()) //high l no. -// low = mid + 1; -// else -// -// high = mid - 1; -// } -// low = mid + 1; -// } -// -// } -// -// if (!tnode.isLeaf()) -// return findNodeBS(tnode, lineNumber, name, elementOffset); -// else -// return tnode; -// -// //System.out.println("visiting: " + getNodeAsString(node.getNode()) + " on line "+node.getLineNumber()); -// if (node.getLineNumber() == lineNumber) { -// System.err.println("Located line: " + node.toString()); -// if (name == null) // name ==null, finds any node equal to line -// // number -// { -// System.out.println("Closest node at line: " + lineNumber); -// return tree; -// } else -// return findOnLine(tree, lineNumber, name, elementOffset, node.getNode() -// .getStartPosition()); -// -// } else if (!tree.isLeaf()) { -// for (int i = 0; i < tree.getChildCount(); i++) { -// .getChildAt(i), -// lineNumber, name, elementOffset); -// if (node2 != null) -// return node2; -// } -// } -// -// return null; -// } - public DefaultMutableTreeNode getAST() { return codeTree; } diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 359d3d4e2..31c902171 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -373,6 +373,72 @@ public class ASTNodeWrapper { public int getLineNumber() { return lineNumber; } + + /** + * Applies pde enhancements to code. + * TODO: Code reuse happening here. :\ + * @param source + * @return + */ + public static String getJavaCode(String source){ + System.out.println("Src:" + source); + String sourceAlt = new String(source); + + // Find all #[web color] + // Should be 6 digits only. + final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; + Pattern webPattern = Pattern.compile(webColorRegexp); + Matcher webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + // System.out.println("-> " + found); + } + + // Find all color data types + final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())"; + Pattern colorPattern = Pattern.compile(colorTypeRegex); + Matcher colorMatcher = colorPattern.matcher(sourceAlt); + while (colorMatcher.find()) { +// System.out.print("Start index: " + colorMatcher.start()); +// System.out.println(" End index: " + colorMatcher.end() + " "); +// System.out.println("-->" + colorMatcher.group() + "<--"); + } + + // Find all int(), char() + String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" }; + + for (String dataType : dataTypeFunc) { + String dataTypeRegexp = "\\b" + dataType + "\\s*\\("; + Pattern pattern = Pattern.compile(dataTypeRegexp); + Matcher matcher = pattern.matcher(sourceAlt); + + while (matcher.find()) { +// System.out.print("Start index: " + matcher.start()); +// System.out.println(" End index: " + matcher.end() + " "); +// System.out.println("-->" + matcher.group() + "<--"); + } + matcher.reset(); + sourceAlt = matcher.replaceAll("PApplet.parse" + + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) + + "("); + + } + // replace with 0xff[webcolor] and others + webMatcher = webPattern.matcher(sourceAlt); + while (webMatcher.find()) { + // System.out.println("Found at: " + webMatcher.start()); + String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); + // System.out.println("-> " + found); + sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); + webMatcher = webPattern.matcher(sourceAlt); + } + + colorMatcher = colorPattern.matcher(sourceAlt); + sourceAlt = colorMatcher.replaceAll("int"); + + System.out.println("Converted:"+sourceAlt); + return sourceAlt; + } private static int getLineNumber(ASTNode node) { return ((CompilationUnit) node.getRoot()).getLineNumber(node diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index ef027771c..2da36972f 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -290,7 +290,7 @@ public class TextArea extends JEditTextArea { if (word.endsWith(".")) word = word.substring(0, word.length() - 1); errorCheckerService.astGenerator.updatePredictions(word, line - + errorCheckerService.mainClassOffset); + + errorCheckerService.mainClassOffset,0); return word; } // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) @@ -353,8 +353,9 @@ public class TextArea extends JEditTextArea { word = word.trim(); // if (word.endsWith(".")) // word = word.substring(0, word.length() - 1); + int lineStartNonWSOffset = 0; errorCheckerService.astGenerator.updatePredictions(word, line - + errorCheckerService.mainClassOffset); + + errorCheckerService.mainClassOffset,lineStartNonWSOffset); //showSuggestionLater(); return word; From 9c1d788e4cd91f9bd396294e20d66f17636238e3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 8 Jul 2013 23:02:53 +0530 Subject: [PATCH 103/608] The unification --- .../mode/experimental/ASTGenerator.java | 58 +++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index be1e636ad..452b4fc86 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -628,14 +628,16 @@ public class ASTGenerator { System.out.println("resolve 3rd par, Can't resolve " + qn.getQualifier()); return null; } - System.out.println("QN, SN Type " + getNodeAsString(stp)); - scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + System.out.println("QN, SN Local Type " + getNodeAsString(stp)); + //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + return new ClassMember(qn.getName()); } else { scopeParent = resolveExpression3rdParty(nearestNode, qn.getQualifier(), noCompare); + System.out.println("QN, ScopeParent " + scopeParent); + return definedIn3rdPartyClass(scopeParent, qn.getName().toString()); } - System.out.println("QN, ScopeParent " + scopeParent); - return definedIn3rdPartyClass(scopeParent, qn.getName().toString()); + } default: System.out.println("Unaccounted type " + getNodeAsString(astNode)); @@ -712,7 +714,7 @@ public class ASTGenerator { } protected void done() { - + // If the parsed code contains pde enhancements, take 'em out. String word2 = ASTNodeWrapper.getJavaCode(word); //After typing 'arg.' all members of arg type are to be listed. This one is a flag for it @@ -1051,7 +1053,40 @@ public class ASTGenerator { public ArrayList getMembersForType(ClassMember tehClass, String child,boolean noCompare, boolean staticOnly){ ArrayList candidates = new ArrayList(); - System.out.println("Looking for match " + child.toString()); + System.out.println("getMemFoType-> Looking for match " + child.toString() + " inside " + tehClass); + + if(tehClass.getASTNode() instanceof TypeDeclaration){ + + TypeDeclaration td = (TypeDeclaration) tehClass.getASTNode(); + for (int i = 0; i < td.getFields().length; i++) { + List vdfs = td.getFields()[i] + .fragments(); + for (VariableDeclarationFragment vdf : vdfs) { + if (noCompare) { + candidates + .add(new CompletionCandidate(getNodeAsString2(vdf))); + } else if (vdf.getName().toString() + .startsWith(child.toString())) + candidates + .add(new CompletionCandidate(getNodeAsString2(vdf))); + } + + } + for (int i = 0; i < td.getMethods().length; i++) { + if (noCompare) { + candidates + .add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString(), "", + CompletionCandidate.METHOD)); + } else if (td.getMethods()[i].getName().toString() + .startsWith(child.toString())) + candidates + .add(new CompletionCandidate(getNodeAsString2(td + .getMethods()[i]), td.getName().toString(), "", + CompletionCandidate.METHOD)); + } + return candidates; + } try { Class probableClass; if(tehClass.getClass_() != null){ @@ -2418,6 +2453,8 @@ public class ASTGenerator { private String stringVal; private String classType; + + private ASTNode astNode; public ClassMember(Class m) { thisclass = m; @@ -2444,6 +2481,11 @@ public class ASTGenerator { stringVal = "Cons " + " " + m.getName() + " defined in " + m.getDeclaringClass().getName(); } + + public ClassMember(ASTNode node){ + astNode = node; + stringVal = getNodeAsString(node); + } public Class getClass_() { return thisclass; @@ -2460,6 +2502,10 @@ public class ASTGenerator { public Constructor getCons() { return cons; } + + public ASTNode getASTNode(){ + return astNode; + } public String toString() { return stringVal; From f912ed35a7ec4b11d8386ffe29f4adfc985c07ca Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 8 Jul 2013 23:31:01 +0530 Subject: [PATCH 104/608] And thus, THERE WAS LIGHT =D --- .../mode/experimental/ASTGenerator.java | 75 +++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 452b4fc86..759746eed 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -602,15 +602,17 @@ public class ASTGenerator { return null; } System.out.println("MI, SN Type " + getNodeAsString(stp)); - scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + return new ClassMember(findDeclaration2(stp.getName(),nearestNode)); } else { System.out.println("MI EXP.."+getNodeAsString(mi.getExpression())); // return null; scopeParent = resolveExpression3rdParty(nearestNode, mi.getExpression(), noCompare); + System.out.println("MI, ScopeParent " + scopeParent); + return definedIn3rdPartyClass(scopeParent, mi.getName().toString()); } - System.out.println("MI, ScopeParent " + scopeParent); - return definedIn3rdPartyClass(scopeParent, mi.getName().toString()); + } case ASTNode.QUALIFIED_NAME: QualifiedName qn = (QualifiedName) astNode; @@ -630,7 +632,7 @@ public class ASTGenerator { } System.out.println("QN, SN Local Type " + getNodeAsString(stp)); //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); - return new ClassMember(qn.getName()); + return new ClassMember(findDeclaration2(qn.getName(),nearestNode)); } else { scopeParent = resolveExpression3rdParty(nearestNode, qn.getQualifier(), noCompare); @@ -1171,6 +1173,31 @@ public class ASTGenerator { public ClassMember definedIn3rdPartyClass(ClassMember tehClass,String memberName){ if(tehClass == null) return null; + System.out.println("definedIn3rdPartyClass-> Looking for " + memberName + + " in " + tehClass); + if(tehClass.getASTNode() instanceof TypeDeclaration){ + + TypeDeclaration td = (TypeDeclaration) tehClass.getASTNode(); + for (int i = 0; i < td.getFields().length; i++) { + List vdfs = td.getFields()[i] + .fragments(); + for (VariableDeclarationFragment vdf : vdfs) { + if (vdf.getName().toString() + .startsWith(memberName)) + return new ClassMember(vdf); + } + + } + for (int i = 0; i < td.getMethods().length; i++) { + if (td.getMethods()[i].getName().toString() + .startsWith(memberName)) + return new ClassMember(td.getMethods()[i]); + } + return null; + } + else if (tehClass.getASTNode() instanceof FieldDeclaration){ + System.out.println(((FieldDeclaration)tehClass.getASTNode()).getType()); + } Class probableClass = null; if(tehClass.getClass_() != null){ @@ -1211,13 +1238,15 @@ public class ASTGenerator { // matchedClass = matchedClass.replace('/', '.'); // System.out.println("In defIn3rdPar(), Matched class: " + matchedClass); // + System.out.println("Trying to load class " + className); try { Class probableClass = Class.forName(className, false, errorCheckerService.classLoader); return new ClassMember(probableClass); } catch (ClassNotFoundException e) { - e.printStackTrace(); + System.out.println("Couldn't load " + className); + e.printStackTrace(); } return null; } @@ -2485,6 +2514,42 @@ public class ASTGenerator { public ClassMember(ASTNode node){ astNode = node; stringVal = getNodeAsString(node); + SimpleType stp = extracTypeInfo(node); + if(stp != null){ + if(findDeclaration(stp.getName()) == null){ + String typeName = stp.getName().toString(); + + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); + String[] resources = classPath.findResources("", regExpResourceFilter); + for (String className : resources) { + System.out.println("-> " + className); + } + if (resources.length == 0) { + System.out.println("In ClassMember(ASTNode), couldn't find class: " + typeName); + } + else{ + //TODO: Multiple matched classes? What about 'em? + String matchedClass = resources[0]; + matchedClass = matchedClass.substring(0, matchedClass.length() - 6); + matchedClass = matchedClass.replace('/', '.'); + System.out.println("In ClassMember(ASTNode), Matched class: " + matchedClass); + + try { + Class probableClass = Class.forName(matchedClass, false, + errorCheckerService.classLoader); + thisclass = probableClass; // Chzech out teh mutation! + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + } + } +// if(findDeclaration(findMe)extracTypeInfo(node) == null){ +// +// } } public Class getClass_() { From 1676dbdbcb05f72966ed80a1500c54a6511dad5e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 00:36:49 +0530 Subject: [PATCH 105/608] ImportStatement is now immutable --- .../mode/experimental/ASTGenerator.java | 18 +++++++++++--- .../experimental/ErrorCheckerService.java | 24 +++++++++++-------- .../mode/experimental/ImportStatement.java | 21 ++++++++++++---- .../mode/experimental/XQPreprocessor.java | 2 +- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 759746eed..ea1b23125 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -272,6 +272,9 @@ public class ASTGenerator { private ClassPathFactory factory; + /** + * Used for searching for package declaration of a class + */ private ClassPath classPath; private JFrame jdocWindow; @@ -563,6 +566,7 @@ public class ASTGenerator { case ASTNode.FIELD_ACCESS: FieldAccess fa = (FieldAccess) astNode; if (fa.getExpression() == null) { + // Local code or belongs to super class System.out.println("FA,Not implemented."); return null; } else { @@ -578,6 +582,7 @@ public class ASTGenerator { } System.out.println("FA, SN Type " + getNodeAsString(stp)); scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + } else { scopeParent = resolveExpression3rdParty(nearestNode, fa.getExpression(), noCompare); @@ -588,6 +593,7 @@ public class ASTGenerator { case ASTNode.METHOD_INVOCATION: MethodInvocation mi = (MethodInvocation) astNode; if (mi.getExpression() == null) { + //Local code or belongs to super class System.out.println("MI,Not implemented."); return null; } else { @@ -1001,6 +1007,7 @@ public class ASTGenerator { System.out.println("In GMFT(), couldn't find class: " + typeName); return candidates; } + // TODO: This method is getting redundant //TODO: Multiple matched classes? What about 'em? String matchedClass = resources[0]; matchedClass = matchedClass.substring(0, matchedClass.length() - 6); @@ -1138,6 +1145,14 @@ public class ASTGenerator { return null; } + private Class getClassIfExists(String className){ + ArrayList imports = errorCheckerService.getProgramImports(); + for (ImportStatement impS : imports) { + //impS. + } + return null; + } + public ClassMember definedIn3rdPartyClass(String className,String memberName){ RegExpResourceFilter regExpResourceFilter; regExpResourceFilter = new RegExpResourceFilter(".*", className + ".class"); @@ -1195,9 +1210,6 @@ public class ASTGenerator { } return null; } - else if (tehClass.getASTNode() instanceof FieldDeclaration){ - System.out.println(((FieldDeclaration)tehClass.getASTNode()).getType()); - } Class probableClass = null; if(tehClass.getClass_() != null){ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index d16b08f7b..89fe59d71 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -150,7 +150,7 @@ public class ErrorCheckerService implements Runnable{ * Stores the current import statements in the program. Used to compare for * changed import statements and update classpath if needed. */ - protected ArrayList programImports; + private ArrayList programImports; /** * List of imports when sketch was last checked. Used for checking for @@ -513,7 +513,7 @@ public class ErrorCheckerService implements Runnable{ String entry = ""; boolean codeFolderChecked = false; for (ImportStatement impstat : programImports) { - String item = impstat.importName; + String item = impstat.getImportName(); int dot = item.lastIndexOf('.'); entry = (dot == -1) ? item : item.substring(0, dot); @@ -557,9 +557,9 @@ public class ErrorCheckerService implements Runnable{ System.err.println("Experimental Mode: Yikes! Can't find \"" + entry + "\" library! Line: " - + impstat.lineNumber + + impstat.getLineNumber() + " in tab: " - + editor.getSketch().getCode(impstat.tab) + + editor.getSketch().getCode(impstat.getTab()) .getPrettyName()); System.out .println("Please make sure that the library is present in getProgramImports() { + return programImports; + } } diff --git a/pdex/src/processing/mode/experimental/ImportStatement.java b/pdex/src/processing/mode/experimental/ImportStatement.java index 26d2db7d1..9fea5f797 100755 --- a/pdex/src/processing/mode/experimental/ImportStatement.java +++ b/pdex/src/processing/mode/experimental/ImportStatement.java @@ -32,16 +32,17 @@ public class ImportStatement { /** * Ex: processing.opengl.*, java.util.* */ - String importName; - /** + private String importName; + + /** * Which tab does it belong to? */ - int tab; + private int tab; /** * Line number(pde code) of the import */ - int lineNumber; + private int lineNumber; /** * @@ -54,4 +55,16 @@ public class ImportStatement { this.tab = tab; this.lineNumber = lineNumber; } + + public String getImportName() { + return importName; + } + + public int getTab() { + return tab; + } + + public int getLineNumber() { + return lineNumber; + } } \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/XQPreprocessor.java b/pdex/src/processing/mode/experimental/XQPreprocessor.java index 34ee2a9a2..91b613521 100755 --- a/pdex/src/processing/mode/experimental/XQPreprocessor.java +++ b/pdex/src/processing/mode/experimental/XQPreprocessor.java @@ -128,7 +128,7 @@ public class XQPreprocessor { public String prepareImports() { imports = new ArrayList(); for (int i = 0; i < extraImports.size(); i++) { - imports.add(new String(extraImports.get(i).importName)); + imports.add(new String(extraImports.get(i).getImportName())); } imports.add(new String("// Default Imports")); for (int i = 0; i < coreImports.length; i++) { From 157e3fc7c49443a4f30ba10d803e591d7d55b89b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 01:59:48 +0530 Subject: [PATCH 106/608] class loading changes.. --- .../mode/experimental/ASTGenerator.java | 275 +++++++++++------- .../experimental/ErrorCheckerService.java | 4 + .../mode/experimental/ImportStatement.java | 9 + 3 files changed, 176 insertions(+), 112 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ea1b23125..573cc7a30 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -73,6 +73,7 @@ import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import processing.app.Base; import processing.app.SketchCode; +import processing.mode.java.preproc.PdePreprocessor; import com.google.classpath.ClassPath; import com.google.classpath.ClassPathFactory; @@ -948,9 +949,14 @@ public class ASTGenerator { testnode = resolveParentExpression(testnode); System.out.println("Corrected testnode " + getNodeAsString(testnode)); } - ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); - candidates = getMembersForType(expr, + ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); + if(expr == null){ + System.out.println("Expr is null"); + }else { + System.out.println("Expr is " + expr.toString()); + candidates = getMembersForType(expr, childExpr, noCompare, false); + } } } @@ -996,68 +1002,63 @@ public class ASTGenerator { String child, boolean noCompare, boolean staticOnly) { + ArrayList candidates = new ArrayList(); - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } - if (resources.length == 0) { - System.out.println("In GMFT(), couldn't find class: " + typeName); +// RegExpResourceFilter regExpResourceFilter; +// regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } +// if (resources.length == 0) { +// System.out.println("In GMFT(), couldn't find class: " + typeName); +// return candidates; +// } +// // TODO: This method is getting redundant +// //TODO: Multiple matched classes? What about 'em? +// String matchedClass = resources[0]; +// matchedClass = matchedClass.substring(0, matchedClass.length() - 6); +// matchedClass = matchedClass.replace('/', '.'); +// System.out.println("In GMFT(), Matched class: " + matchedClass); + System.out.println("In GMFT(), Looking for match " + child.toString() + + " in class " + typeName); + + Class probableClass = findClassIfExists(typeName); + if(probableClass == null){ + System.out.println("In GMFT(), class not found."); return candidates; } - // TODO: This method is getting redundant - //TODO: Multiple matched classes? What about 'em? - String matchedClass = resources[0]; - matchedClass = matchedClass.substring(0, matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - System.out.println("In GMFT(), Matched class: " + matchedClass); - System.out.println("Looking for match " + child.toString()); - try { - Class probableClass = Class.forName(matchedClass, false, - errorCheckerService.classLoader); + for (Method method : probableClass.getMethods()) { + if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { + continue; + } - for (Method method : probableClass.getMethods()) { - if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { - continue; - } - - StringBuffer label = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) - label.append(","); - } - label.append(")"); - - if (noCompare) { - candidates.add(new CompletionCandidate(method)); - } - else if (label.toString().startsWith(child.toString())) { - candidates.add(new CompletionCandidate(method)); - } + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); } - for (Field field : probableClass.getFields()) { - if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { - continue; - } - if (noCompare) { - candidates.add(new CompletionCandidate(field)); - } - else if (field.getName().startsWith(child.toString())) { - candidates.add(new CompletionCandidate(field)); - } + label.append(")"); + + if (noCompare) { + candidates.add(new CompletionCandidate(method)); + } else if (label.toString().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(method)); } - return candidates; - } catch (ClassNotFoundException e) { - e.printStackTrace(); - System.out.println("Couldn't load " + matchedClass); } - - //updateJavaDoc(methodmatch) - - return null; + for (Field field : probableClass.getFields()) { + if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { + continue; + } + if (noCompare) { + candidates.add(new CompletionCandidate(field)); + } else if (field.getName().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(field)); + } + } + return candidates; + } public ArrayList getMembersForType(ClassMember tehClass, String child,boolean noCompare, boolean staticOnly){ @@ -1145,44 +1146,99 @@ public class ASTGenerator { return null; } - private Class getClassIfExists(String className){ - ArrayList imports = errorCheckerService.getProgramImports(); - for (ImportStatement impS : imports) { - //impS. + /** + * Searches for the particular class in the default list of imports as well as + * the Sketch classpath + * @param className + * @return + */ + private Class findClassIfExists(String className){ + Class tehClass = null; + // First, see if the classname is a fully qualified name and loads straightaway + try { + tehClass = Class.forName(className, false, + errorCheckerService + .getSketchClassLoader()); + System.out.println(tehClass.getName() + " located straightaway"); + return tehClass; + } catch (ClassNotFoundException e) { + //System.out.println("Doesn't exist in package: "); } - return null; + + System.out.println("Looking in the classloader for " + className); + ArrayList imports = errorCheckerService + .getProgramImports(); + + for (ImportStatement impS : imports) { + String temp = impS.getPackageName(); + try { + if(temp.endsWith("*")){ + temp = temp.substring(0, temp.length()-1) + className; + } + else { + int x = temp.lastIndexOf('.'); + if(temp.substring(x).equals(className)){ + // Well, we've found the class. + } + } + tehClass = Class.forName(temp, false, + errorCheckerService + .getSketchClassLoader()); + System.out.println(tehClass.getName() + " located."); + return tehClass; + } catch (ClassNotFoundException e) { + // it does not exist on the classpath + System.out.println("Doesn't exist in package: " + impS.getImportName()); + } + } + + PdePreprocessor p = new PdePreprocessor(null); + for (String impS : p.getCoreImports()) { + try { + + tehClass = Class.forName(impS.substring(0,impS.length()-1) + className, false, + errorCheckerService + .getSketchClassLoader()); + System.out.println(tehClass.getName() + " located."); + return tehClass; + } catch (ClassNotFoundException e) { + // it does not exist on the classpath + System.out.println("Doesn't exist in package: " + impS); + } + } + + for (String impS : p.getDefaultImports()) { + try { + if(className.equals(impS) || impS.endsWith(className)){ + tehClass = Class.forName(className, false, errorCheckerService.getSketchClassLoader()); + System.out.println(tehClass.getName() + " located."); + return tehClass; + } +// else if(impS.endsWith(className)){ +// tehClass = Class.forName(impS, false, errorCheckerService.getSketchClassLoader()); +// System.out.println(tehClass.getName() + " located."); +// return tehClass; +// } + + } catch (ClassNotFoundException e) { + // it does not exist on the classpath + System.out.println("Doesn't exist in package: " + impS); + } + } + return tehClass; } public ClassMember definedIn3rdPartyClass(String className,String memberName){ - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", className + ".class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String cn : resources) { - System.out.println("-> " + cn); - } - if (resources.length == 0) { - System.out.println("In defIn3rdPar(), couldn't find class: " + className); + Class probableClass = findClassIfExists(className); + if (probableClass == null) { + System.out.println("Couldn't load " + className); return null; } - //TODO: Multiple matched classes? What about 'em? - String matchedClass = resources[0]; - matchedClass = matchedClass.substring(0, matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - System.out.println("In defIn3rdPar(), Matched class: " + matchedClass); - System.out.println("Looking for match " + memberName.toString()); - - try { - Class probableClass = Class.forName(matchedClass, false, - errorCheckerService.classLoader); - if(memberName.equals("THIS")){ - return new ClassMember(probableClass); - } + if (memberName.equals("THIS")) { + return new ClassMember(probableClass); + } else { return definedIn3rdPartyClass(new ClassMember(probableClass), memberName); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - System.out.println("Couldn't load " + matchedClass); } - return null; } public ClassMember definedIn3rdPartyClass(ClassMember tehClass,String memberName){ @@ -2530,33 +2586,28 @@ public class ASTGenerator { if(stp != null){ if(findDeclaration(stp.getName()) == null){ String typeName = stp.getName().toString(); - - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } - if (resources.length == 0) { - System.out.println("In ClassMember(ASTNode), couldn't find class: " + typeName); - } - else{ - //TODO: Multiple matched classes? What about 'em? - String matchedClass = resources[0]; - matchedClass = matchedClass.substring(0, matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - System.out.println("In ClassMember(ASTNode), Matched class: " + matchedClass); +// +// RegExpResourceFilter regExpResourceFilter; +// regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } +// if (resources.length == 0) { +// System.out.println("In ClassMember(ASTNode), couldn't find class: " + typeName); +// } +// else{ +// //TODO: Multiple matched classes? What about 'em? +// String matchedClass = resources[0]; +// matchedClass = matchedClass.substring(0, matchedClass.length() - 6); +// matchedClass = matchedClass.replace('/', '.'); +// System.out.println("In ClassMember(ASTNode), Matched class: " + matchedClass); +// + + Class probableClass = findClassIfExists(typeName); + thisclass = probableClass; // Czech out teh mutation! - try { - Class probableClass = Class.forName(matchedClass, false, - errorCheckerService.classLoader); - thisclass = probableClass; // Chzech out teh mutation! - } catch (ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } } } // if(findDeclaration(findMe)extracTypeInfo(node) == null){ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 89fe59d71..b1b04576f 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -496,6 +496,10 @@ public class ErrorCheckerService implements Runnable{ // System.out.println("Compilecheck, Done."); } + public URLClassLoader getSketchClassLoader() { + return classLoader; + } + /** * Processes import statements to obtain classpaths of contributed * libraries. This would be needed for compilation check. Also, adds diff --git a/pdex/src/processing/mode/experimental/ImportStatement.java b/pdex/src/processing/mode/experimental/ImportStatement.java index 9fea5f797..fb9e8eb8e 100755 --- a/pdex/src/processing/mode/experimental/ImportStatement.java +++ b/pdex/src/processing/mode/experimental/ImportStatement.java @@ -59,6 +59,15 @@ public class ImportStatement { public String getImportName() { return importName; } + + public String getPackageName(){ + String ret = new String(importName.trim()); + if(ret.startsWith("import ")) + ret = ret.substring(7); + if(ret.endsWith(";")) + ret = ret.substring(0, ret.length() - 1); + return ret; + } public int getTab() { return tab; From c79cfc7c79e56295311a9fab5b6a03ff44564df6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 02:11:28 +0530 Subject: [PATCH 107/608] resolve expression bug fix --- .../mode/experimental/ASTGenerator.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 573cc7a30..b07f1ec6b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -609,8 +609,13 @@ public class ASTGenerator { return null; } System.out.println("MI, SN Type " + getNodeAsString(stp)); + ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode); + if(typeDec == null){ + System.out.println(stp.getName() + " couldn't be found locally.."); + return new ClassMember(findClassIfExists(stp.getName().toString())); + } //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); - return new ClassMember(findDeclaration2(stp.getName(),nearestNode)); + return new ClassMember(typeDec); } else { System.out.println("MI EXP.."+getNodeAsString(mi.getExpression())); // return null; @@ -639,7 +644,14 @@ public class ASTGenerator { } System.out.println("QN, SN Local Type " + getNodeAsString(stp)); //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); - return new ClassMember(findDeclaration2(qn.getName(),nearestNode)); + ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode); + if(typeDec == null){ + System.out.println(stp.getName() + " couldn't be found locally.."); + return new ClassMember(findClassIfExists(stp.getName().toString())); + } + //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); + return new ClassMember(typeDec); + //return new ClassMember(findDeclaration2(qn.getName(),nearestNode)); } else { scopeParent = resolveExpression3rdParty(nearestNode, qn.getQualifier(), noCompare); From 4a68ea1c00d6f0b68369123b6c7bdc100dde199d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 03:16:26 +0530 Subject: [PATCH 108/608] even more completion stuff working now :) --- .../mode/experimental/ASTGenerator.java | 85 +++++++++---------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b07f1ec6b..38d7915c0 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -593,6 +593,12 @@ public class ASTGenerator { } case ASTNode.METHOD_INVOCATION: MethodInvocation mi = (MethodInvocation) astNode; + ASTNode temp = findDeclaration2(mi.getName(), nearestNode); + if(temp instanceof MethodDeclaration){ + // method is locally defined + System.out.println(mi.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp))); + return new ClassMember(extracTypeInfo(temp)); + } if (mi.getExpression() == null) { //Local code or belongs to super class System.out.println("MI,Not implemented."); @@ -649,9 +655,7 @@ public class ASTGenerator { System.out.println(stp.getName() + " couldn't be found locally.."); return new ClassMember(findClassIfExists(stp.getName().toString())); } - //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); return new ClassMember(typeDec); - //return new ClassMember(findDeclaration2(qn.getName(),nearestNode)); } else { scopeParent = resolveExpression3rdParty(nearestNode, qn.getQualifier(), noCompare); @@ -955,7 +959,9 @@ public class ASTGenerator { System.out.println("candidates empty"); String childExpr = resolveChildExpression(testnode) .toString(); + System.out.println("Parent expression : " + resolveParentExpression(testnode)); System.out.println("Child expression : " + childExpr); + if(!noCompare){ System.out.println("Original testnode " + getNodeAsString(testnode)); testnode = resolveParentExpression(testnode); @@ -1033,7 +1039,8 @@ public class ASTGenerator { // matchedClass = matchedClass.replace('/', '.'); // System.out.println("In GMFT(), Matched class: " + matchedClass); System.out.println("In GMFT(), Looking for match " + child.toString() - + " in class " + typeName); + + " in class " + typeName + " noCompare " + noCompare + " staticOnly " + + staticOnly); Class probableClass = findClassIfExists(typeName); if(probableClass == null){ @@ -1073,10 +1080,15 @@ public class ASTGenerator { } - public ArrayList getMembersForType(ClassMember tehClass, String child,boolean noCompare, boolean staticOnly){ + public ArrayList getMembersForType(ClassMember tehClass, + String child, + boolean noCompare, + boolean staticOnly) { ArrayList candidates = new ArrayList(); - System.out.println("getMemFoType-> Looking for match " + child.toString() + " inside " + tehClass); - + System.out.println("getMemFoType-> Looking for match " + child.toString() + + " inside " + tehClass + " noCompare " + noCompare + " staticOnly " + + staticOnly); + if(tehClass.getASTNode() instanceof TypeDeclaration){ TypeDeclaration td = (TypeDeclaration) tehClass.getASTNode(); @@ -1116,7 +1128,7 @@ public class ASTGenerator { } else { - probableClass = loadClass(tehClass.getTypeAsString()).getClass_(); + probableClass = findClassIfExists(tehClass.getTypeAsString()); System.out.println("Loaded " + probableClass.toString()); } for (Method method : probableClass.getMethods()) { @@ -1222,7 +1234,7 @@ public class ASTGenerator { for (String impS : p.getDefaultImports()) { try { if(className.equals(impS) || impS.endsWith(className)){ - tehClass = Class.forName(className, false, errorCheckerService.getSketchClassLoader()); + tehClass = Class.forName(impS, false, errorCheckerService.getSketchClassLoader()); System.out.println(tehClass.getName() + " located."); return tehClass; } @@ -1285,7 +1297,7 @@ public class ASTGenerator { } else { - probableClass = loadClass(tehClass.getTypeAsString()).getClass_(); + probableClass = findClassIfExists(tehClass.getTypeAsString()); System.out.println("Loaded " + probableClass.toString()); } for (Method method : probableClass.getMethods()) { @@ -1301,7 +1313,7 @@ public class ASTGenerator { return null; } - private ClassMember loadClass(String className){ +// private ClassMember loadClass(String className){ // RegExpResourceFilter regExpResourceFilter; // regExpResourceFilter = new RegExpResourceFilter(".*", className + ".class"); // String[] resources = classPath.findResources("", regExpResourceFilter); @@ -1318,18 +1330,18 @@ public class ASTGenerator { // matchedClass = matchedClass.replace('/', '.'); // System.out.println("In defIn3rdPar(), Matched class: " + matchedClass); // - System.out.println("Trying to load class " + className); - try { - Class probableClass = Class.forName(className, false, - errorCheckerService.classLoader); - return new ClassMember(probableClass); - } catch (ClassNotFoundException e) { - - System.out.println("Couldn't load " + className); - e.printStackTrace(); - } - return null; - } +// System.out.println("Trying to load class " + className); +// try { +// Class probableClass = Class.forName(className, false, +// errorCheckerService.classLoader); +// return new ClassMember(probableClass); +// } catch (ClassNotFoundException e) { +// +// System.out.println("Couldn't load " + className); +// e.printStackTrace(); +// } +// return null; +// } public void updateJavaDoc(final CompletionCandidate candidate) { //TODO: Work on this later. @@ -2594,32 +2606,15 @@ public class ASTGenerator { public ClassMember(ASTNode node){ astNode = node; stringVal = getNodeAsString(node); + if(node instanceof SimpleType){ + classType = ((SimpleType)node).getName().toString(); + } SimpleType stp = extracTypeInfo(node); if(stp != null){ if(findDeclaration(stp.getName()) == null){ - String typeName = stp.getName().toString(); -// -// RegExpResourceFilter regExpResourceFilter; -// regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); -// String[] resources = classPath.findResources("", regExpResourceFilter); -// for (String className : resources) { -// System.out.println("-> " + className); -// } -// if (resources.length == 0) { -// System.out.println("In ClassMember(ASTNode), couldn't find class: " + typeName); -// } -// else{ -// //TODO: Multiple matched classes? What about 'em? -// String matchedClass = resources[0]; -// matchedClass = matchedClass.substring(0, matchedClass.length() - 6); -// matchedClass = matchedClass.replace('/', '.'); -// System.out.println("In ClassMember(ASTNode), Matched class: " + matchedClass); -// - - Class probableClass = findClassIfExists(typeName); - thisclass = probableClass; // Czech out teh mutation! - - + classType = stp.getName().toString(); + Class probableClass = findClassIfExists(classType); + thisclass = probableClass; // Czech out teh mutation! } } // if(findDeclaration(findMe)extracTypeInfo(node) == null){ From 0a6fb26f09cc798596817b1c3d77a0c00e01a17e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 03:27:55 +0530 Subject: [PATCH 109/608] oops, left out this case --- pdex/src/processing/mode/experimental/ASTGenerator.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 38d7915c0..dbaaea0d3 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -634,6 +634,12 @@ public class ASTGenerator { } case ASTNode.QUALIFIED_NAME: QualifiedName qn = (QualifiedName) astNode; + ASTNode temp2 = findDeclaration2(qn.getName(), nearestNode); + if(temp2 instanceof FieldDeclaration){ + // field is locally defined + System.out.println(qn.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp2))); + return new ClassMember(extracTypeInfo(temp2)); + } if (qn.getQualifier() == null) { System.out.println("MI,Not implemented."); return null; From 14e87feb4083f62d966cf60dbf246b25b6ca2f2b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 04:09:54 +0530 Subject: [PATCH 110/608] shedding some load off.. removing redundancy --- .../mode/experimental/ASTGenerator.java | 84 +++++++++++++------ 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index dbaaea0d3..382113adf 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -560,8 +560,14 @@ public class ASTGenerator { ClassMember scopeParent = null; SimpleType stp = null; - if(astNode instanceof SimpleName) + if(astNode instanceof SimpleName){ + ASTNode decl = findDeclaration2(((SimpleName)astNode),nearestNode); + if(decl != null){ + System.out.println(getNodeAsString(astNode)+" found decl -> " + getNodeAsString(decl)); + return new ClassMember(extracTypeInfo(decl)); + } astNode = astNode.getParent(); + } switch (astNode.getNodeType()) { case ASTNode.FIELD_ACCESS: @@ -791,7 +797,7 @@ public class ASTGenerator { ArrayList candidates = new ArrayList(); // Determine the expression typed - + if (testnode instanceof SimpleName && !noCompare) { System.err .println("One word expression " + getNodeAsString(testnode)); @@ -873,15 +879,33 @@ public class ASTGenerator { // ==> Complex expression of type blah.blah2().doIt,etc // Have to resolve it by carefully traversing AST of testNode System.err.println("Complex expression " + getNodeAsString(testnode)); - - ASTNode det = resolveExpression(nearestNode, testnode,noCompare); + System.out.println("candidates empty"); + String childExpr = resolveChildExpression(testnode) + .toString(); + System.out.println("Parent expression : " + resolveParentExpression(testnode)); + System.out.println("Child expression : " + childExpr); + + if(!noCompare){ + System.out.println("Original testnode " + getNodeAsString(testnode)); + testnode = resolveParentExpression(testnode); + System.out.println("Corrected testnode " + getNodeAsString(testnode)); + } + ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); + if(expr == null){ + System.out.println("Expr is null"); + }else { + System.out.println("Expr is " + expr.toString()); + candidates = getMembersForType(expr, + childExpr, noCompare, false); + } + /*ASTNode det = resolveExpression(nearestNode, testnode,noCompare); // Find the parent of the expression // in a().b, this would give me the return type of a(), so that we can // find all children of a() begininng with b System.err.println("DET " + getNodeAsString(det)); if (det != null) { TypeDeclaration td = null; - SimpleType stp = null; + SimpleType stp = extracTypeInfo(det); if (det instanceof MethodDeclaration) { if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { stp = (SimpleType) (((MethodDeclaration) det).getReturnType2()); @@ -981,7 +1005,7 @@ public class ASTGenerator { candidates = getMembersForType(expr, childExpr, noCompare, false); } - } + }*/ } @@ -1095,9 +1119,9 @@ public class ASTGenerator { + " inside " + tehClass + " noCompare " + noCompare + " staticOnly " + staticOnly); - if(tehClass.getASTNode() instanceof TypeDeclaration){ + if(tehClass.getDeclaringNode() instanceof TypeDeclaration){ - TypeDeclaration td = (TypeDeclaration) tehClass.getASTNode(); + TypeDeclaration td = (TypeDeclaration) tehClass.getDeclaringNode(); for (int i = 0; i < td.getFields().length; i++) { List vdfs = td.getFields()[i] .fragments(); @@ -1276,9 +1300,9 @@ public class ASTGenerator { return null; System.out.println("definedIn3rdPartyClass-> Looking for " + memberName + " in " + tehClass); - if(tehClass.getASTNode() instanceof TypeDeclaration){ + if(tehClass.getDeclaringNode() instanceof TypeDeclaration){ - TypeDeclaration td = (TypeDeclaration) tehClass.getASTNode(); + TypeDeclaration td = (TypeDeclaration) tehClass.getDeclaringNode(); for (int i = 0; i < td.getFields().length; i++) { List vdfs = td.getFields()[i] .fragments(); @@ -2582,6 +2606,8 @@ public class ASTGenerator { private String classType; private ASTNode astNode; + + private ASTNode declaringNode; public ClassMember(Class m) { thisclass = m; @@ -2615,22 +2641,31 @@ public class ASTGenerator { if(node instanceof SimpleType){ classType = ((SimpleType)node).getName().toString(); } - SimpleType stp = extracTypeInfo(node); + SimpleType stp = (node instanceof SimpleType) ? (SimpleType) node + : extracTypeInfo(node); if(stp != null){ - if(findDeclaration(stp.getName()) == null){ + ASTNode decl =findDeclaration(stp.getName()); + // Czech out teh mutation + if(decl == null){ + // a predefined type classType = stp.getName().toString(); Class probableClass = findClassIfExists(classType); - thisclass = probableClass; // Czech out teh mutation! + thisclass = probableClass; + } + else{ + // a local type + declaringNode = decl; } } -// if(findDeclaration(findMe)extracTypeInfo(node) == null){ -// -// } } public Class getClass_() { return thisclass; } + + public ASTNode getDeclaringNode(){ + return declaringNode; + } public Field getField() { return field; @@ -2862,20 +2897,17 @@ public class ASTGenerator { return null; switch (node.getNodeType()) { case ASTNode.METHOD_DECLARATION: - return (SimpleType) ((MethodDeclaration) node) - .getStructuralProperty(MethodDeclaration.RETURN_TYPE2_PROPERTY); + return (SimpleType) ((MethodDeclaration) node).getReturnType2(); case ASTNode.FIELD_DECLARATION: - return (SimpleType) ((FieldDeclaration) node) - .getStructuralProperty(FieldDeclaration.TYPE_PROPERTY); + return (SimpleType) ((FieldDeclaration) node).getType(); case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - return (SimpleType) ((VariableDeclarationExpression) node) - .getStructuralProperty(VariableDeclarationExpression.TYPE_PROPERTY); + return (SimpleType) ((VariableDeclarationExpression) node).getType(); case ASTNode.VARIABLE_DECLARATION_STATEMENT: - return (SimpleType) ((VariableDeclarationStatement) node) - .getStructuralProperty(VariableDeclarationStatement.TYPE_PROPERTY); + return (SimpleType) ((VariableDeclarationStatement) node).getType(); case ASTNode.SINGLE_VARIABLE_DECLARATION: - return (SimpleType) ((SingleVariableDeclaration) node) - .getStructuralProperty(SingleVariableDeclaration.TYPE_PROPERTY); + return (SimpleType) ((SingleVariableDeclaration) node).getType(); + case ASTNode.VARIABLE_DECLARATION_FRAGMENT: + return extracTypeInfo(node.getParent()); } return null; } From 12fefba4792d88a7964dd8c053b6a3e2a7b56d67 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 05:00:30 +0530 Subject: [PATCH 111/608] further completion stuff, including System.out.println() --- pdex/Todo, GSoC 2013.txt | 7 ++-- .../mode/experimental/ASTGenerator.java | 34 ++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 8ee9a09e6..300bf8a73 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -15,10 +15,11 @@ x Discovered another major issue due to offset differences -> While looking for Ex - "s.substring(int(13.4))." fails. Thinking to just do the substitutions before sending it to updatePredictions(), coz offsets aren't really a concern here, right? Yup, fixed it! x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. x Completion for external classes - ArrayList, HashMap, etc. -*! Recursive lookup for compiled(library) code! -*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. +x! Recursive lookup for compiled(library) code! +x! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. *! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. - - Making very good progress here. The elegance of recurion - Hats off! + - Making very good progress here. The elegance of recurion - Hats off! + - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x Differentiating between multiple statements on the same line. How to? Done with offset handling. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 382113adf..b7161e9b9 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -563,9 +563,17 @@ public class ASTGenerator { if(astNode instanceof SimpleName){ ASTNode decl = findDeclaration2(((SimpleName)astNode),nearestNode); if(decl != null){ + // see if locally defined System.out.println(getNodeAsString(astNode)+" found decl -> " + getNodeAsString(decl)); return new ClassMember(extracTypeInfo(decl)); } + else { + // or in a predefined class? + Class tehClass = findClassIfExists(((SimpleName) astNode).toString()); + if (tehClass != null) { + return new ClassMember(tehClass); + } + } astNode = astNode.getParent(); } switch (astNode.getNodeType()) { @@ -585,6 +593,7 @@ public class ASTGenerator { * System.out.println(), or maybe belonging to super class, etc. */ System.out.println("resolve 3rd par, Can't resolve " + fa.getExpression()); + return null; } System.out.println("FA, SN Type " + getNodeAsString(stp)); @@ -657,6 +666,11 @@ public class ASTGenerator { /*The type wasn't found in local code, so it might be something like * System.out.println(), or maybe belonging to super class, etc. */ + Class tehClass = findClassIfExists(qn.getQualifier().toString()); + if (tehClass != null) { + return definedIn3rdPartyClass(new ClassMember(tehClass), qn + .getName().toString()); + } System.out.println("resolve 3rd par, Can't resolve " + qn.getQualifier()); return null; } @@ -1268,17 +1282,24 @@ public class ASTGenerator { System.out.println(tehClass.getName() + " located."); return tehClass; } -// else if(impS.endsWith(className)){ -// tehClass = Class.forName(impS, false, errorCheckerService.getSketchClassLoader()); -// System.out.println(tehClass.getName() + " located."); -// return tehClass; -// } } catch (ClassNotFoundException e) { // it does not exist on the classpath System.out.println("Doesn't exist in package: " + impS); } } + + // And finally, the daddy + String daddy = "java.lang." + className; + try { + tehClass = Class.forName(daddy, false, + errorCheckerService.getSketchClassLoader()); + System.out.println(tehClass.getName() + " located."); + return tehClass; + } catch (ClassNotFoundException e) { + // it does not exist on the classpath + System.out.println("Doesn't exist in package: " + daddy); + } return tehClass; } @@ -2512,6 +2533,8 @@ public class ASTGenerator { SimpleType stp = extracTypeInfo(findDeclaration2((qn.getQualifier()), alternateParent)); + if(stp == null) + return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); System.out.println(qn.getQualifier() + "->" + qn.getName()); System.out.println("QN decl class: " + getNodeAsString(declaringClass)); @@ -2909,6 +2932,7 @@ public class ASTGenerator { case ASTNode.VARIABLE_DECLARATION_FRAGMENT: return extracTypeInfo(node.getParent()); } + System.out.println("Unknown type info request " + getNodeAsString(node)); return null; } From 6de65b4f350169c24df29a64b125a76383136228 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 14:06:10 +0530 Subject: [PATCH 112/608] Superclass members in completion list, also removed redundant stuff --- .../mode/experimental/ASTGenerator.java | 359 ++---------------- 1 file changed, 27 insertions(+), 332 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b7161e9b9..3b90231e3 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -66,6 +66,7 @@ import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; @@ -358,48 +359,7 @@ public class ASTGenerator { public DefaultMutableTreeNode buildAST(CompilationUnit cu) { return buildAST(errorCheckerService.sourceCode, cu); } - - public String[] checkForTypes2(ASTNode node) { - - List vdfs = null; - switch (node.getNodeType()) { - case ASTNode.TYPE_DECLARATION: - return new String[] { ((TypeDeclaration) node).getName().toString() }; - - case ASTNode.METHOD_DECLARATION: - String[] ret1 = new String[] { ((MethodDeclaration) node).getName() - .toString() }; - return ret1; - - case ASTNode.SINGLE_VARIABLE_DECLARATION: - return new String[] { ((SingleVariableDeclaration) node).getName() - .toString() }; - - case ASTNode.FIELD_DECLARATION: - vdfs = ((FieldDeclaration) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - vdfs = ((VariableDeclarationStatement) node).fragments(); - break; - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - vdfs = ((VariableDeclarationExpression) node).fragments(); - break; - default: - break; - } - - if (vdfs != null) { - String ret[] = new String[vdfs.size()]; - int i = 0; - for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = vdf.getName().toString(); - } - return ret; - } - - return null; - } - + public static CompletionCandidate[] checkForTypes(ASTNode node) { List vdfs = null; @@ -457,32 +417,6 @@ public class ASTGenerator { return null; } - @SuppressWarnings("unchecked") - public ArrayList getNameIfType(ASTNode astnode) { - - ArrayList names = new ArrayList(); - List sprops = astnode - .structuralPropertiesForType(); - for (StructuralPropertyDescriptor sprop : sprops) { - ASTNode cnode = null; - if (!sprop.isChildListProperty()) { - if (astnode.getStructuralProperty(sprop) instanceof ASTNode) { - cnode = (ASTNode) astnode.getStructuralProperty(sprop); - //if(cnode) - } - } else { - // Childlist prop - List nodelist = (List) astnode - .getStructuralProperty(sprop); - for (ASTNode clnode : nodelist) { - - } - } - } - - return names; - } - /** * Find the parent of the expression in a().b, this would give me the return * type of a(), so that we can find all children of a() begininng with b @@ -546,9 +480,9 @@ public class ASTGenerator { } /** - * Find the parent of the expression in a().b, this would give me the return - * type of a(), so that we can find all children of a() begininng with b - * This is the 3rd party variant, for .jar files. + * Finds the type of the expression in foo.bar().a().b, this would give me the + * type of b if it exists in return type of a(). If noCompare is true, + * it'll return type of a() * @param nearestNode * @param astNode * @return @@ -668,6 +602,7 @@ public class ASTGenerator { */ Class tehClass = findClassIfExists(qn.getQualifier().toString()); if (tehClass != null) { + // note how similar thing is called on line 690. Check check. return definedIn3rdPartyClass(new ClassMember(tehClass), qn .getName().toString()); } @@ -698,16 +633,6 @@ public class ASTGenerator { return null; } - private ClassMember findDeclarationInSuperClasses(ASTNode astNode){ - while(astNode != null){ - astNode = astNode.getParent(); - if(astNode instanceof TypeDeclaration) - break; - } - - return null; - } - /** * For a().abc.a123 this would return a123 * @@ -746,16 +671,6 @@ public class ASTGenerator { return null; } - public static TypeDeclaration getDefiningNode(ASTNode node) { - ASTNode parent = node.getParent(); - while (!(parent instanceof TypeDeclaration)) { - parent = parent.getParent(); - if (parent instanceof CompilationUnit) - return null; - } - return (TypeDeclaration) parent; - } - public void updatePredictions(final String word, final int line, final int lineStartNonWSOffset) { SwingWorker worker = new SwingWorker() { @@ -1066,61 +981,15 @@ public class ASTGenerator { boolean staticOnly) { ArrayList candidates = new ArrayList(); -// RegExpResourceFilter regExpResourceFilter; -// regExpResourceFilter = new RegExpResourceFilter(".*", typeName + ".class"); -// String[] resources = classPath.findResources("", regExpResourceFilter); -// for (String className : resources) { -// System.out.println("-> " + className); -// } -// if (resources.length == 0) { -// System.out.println("In GMFT(), couldn't find class: " + typeName); -// return candidates; -// } -// // TODO: This method is getting redundant -// //TODO: Multiple matched classes? What about 'em? -// String matchedClass = resources[0]; -// matchedClass = matchedClass.substring(0, matchedClass.length() - 6); -// matchedClass = matchedClass.replace('/', '.'); -// System.out.println("In GMFT(), Matched class: " + matchedClass); System.out.println("In GMFT(), Looking for match " + child.toString() + " in class " + typeName + " noCompare " + noCompare + " staticOnly " + staticOnly); - Class probableClass = findClassIfExists(typeName); if(probableClass == null){ System.out.println("In GMFT(), class not found."); return candidates; } - for (Method method : probableClass.getMethods()) { - if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { - continue; - } - - StringBuffer label = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) - label.append(","); - } - label.append(")"); - - if (noCompare) { - candidates.add(new CompletionCandidate(method)); - } else if (label.toString().startsWith(child.toString())) { - candidates.add(new CompletionCandidate(method)); - } - } - for (Field field : probableClass.getFields()) { - if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { - continue; - } - if (noCompare) { - candidates.add(new CompletionCandidate(field)); - } else if (field.getName().startsWith(child.toString())) { - candidates.add(new CompletionCandidate(field)); - } - } - return candidates; + return getMembersForType(new ClassMember(probableClass), child, noCompare, staticOnly); } @@ -1133,6 +1002,7 @@ public class ASTGenerator { + " inside " + tehClass + " noCompare " + noCompare + " staticOnly " + staticOnly); + // tehClass will either be a TypeDecl defined locally if(tehClass.getDeclaringNode() instanceof TypeDeclaration){ TypeDeclaration td = (TypeDeclaration) tehClass.getDeclaringNode(); @@ -1163,8 +1033,26 @@ public class ASTGenerator { .getMethods()[i]), td.getName().toString(), "", CompletionCandidate.METHOD)); } + + ArrayList superClassCandidates = new ArrayList(); + if(td.getSuperclassType() instanceof Type){ + System.out.println(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); + superClassCandidates = getMembersForType(new ClassMember(td + .getSuperclassType()), + child, noCompare, staticOnly); + } + else + { + superClassCandidates = getMembersForType(new ClassMember(Object.class), + child, noCompare, staticOnly); + } + for (CompletionCandidate cc : superClassCandidates) { + candidates.add(cc); + } return candidates; } + + // Or tehClass will be a predefined class try { Class probableClass; if(tehClass.getClass_() != null){ @@ -2715,200 +2603,7 @@ public class ASTGenerator { } } - private ClassMember findDeclaration3rdParty(Name findMe, String parentClass){ - System.out.println("--findDec 3rd-- " + findMe + " , " + parentClass); - ClassMember declaringClass = null; - ASTNode parent = findMe.getParent(); - ArrayList constrains = new ArrayList(); - if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) { - Expression exp = (Expression) ((MethodInvocation) parent) - .getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY); - //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION); - // Possibly a bug here. Investigate later. - if (((MethodInvocation) parent).getName().toString() - .equals(findMe.toString())) { - constrains.add(ASTNode.METHOD_DECLARATION); - - if (exp != null) { - constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("3rd Par MI EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); - if (exp instanceof MethodInvocation) { -// SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) -// .getName())); -// if (stp == null) -// return null; - //declaringClass = findDeclaration(stp.getName()); - declaringClass = findDeclaration3rdParty(((MethodInvocation) exp) - .getName(), - parentClass); -// return definedIn(declaringClass, ((MethodInvocation) parent) -// .getName().toString(), constrains, declaringClass); - return definedIn3rdPartyClass(declaringClass, - ((MethodInvocation) parent).getName() - .toString()); - } else if (exp instanceof FieldAccess) { -// SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) -// .getName())); -// if (stp == null) -// return null; - declaringClass = findDeclaration3rdParty(((FieldAccess) exp) - .getName(), - parentClass); - return definedIn3rdPartyClass(declaringClass, - ((MethodInvocation) parent).getName() - .toString()); - //declaringClass = findDeclaration((stp.getName())); -// return definedIn(declaringClass, ((MethodInvocation) parent) -// .getName().toString(), constrains, declaringClass); - } else if (exp instanceof QualifiedName) { - QualifiedName qnn = (QualifiedName)exp; - System.out.println("exp is a QN, " - + (qnn.getQualifier().toString() + " other " + qnn.getName() - .toString())); - - SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); - System.out.println(qnn.getQualifier() + "->" + qnn.getName()); - declaringClass = findDeclaration3rdParty(stp.getName(), - parentClass); -// System.out.println("QN decl class: " -// + getNodeAsString(declaringClass)); - System.out.println("Decl class " + declaringClass); - return definedIn3rdPartyClass(declaringClass,((MethodInvocation) parent).getName() - .toString()); - } - if (exp instanceof SimpleName) { - SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); - if (stp == null) - return null; - System.out.println("3rdPa "+stp.getName()); - declaringClass = definedIn3rdPartyClass(stp.getName().toString(), - "THIS"); - //declaringClass = findDeclaration(stp.getName()); - //System.out.println("MI.SN " + getNodeAsString(declaringClass)); - constrains.add(ASTNode.METHOD_DECLARATION); - return definedIn3rdPartyClass(declaringClass, - ((MethodInvocation) parent).getName() - .toString()); -// return definedIn(declaringClass, ((MethodInvocation) parent) -// .getName().toString(), constrains, declaringClass); - } - - } - } else { - parent = parent.getParent(); // Move one up the ast. V V IMP!! - } - } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) { - FieldAccess fa = (FieldAccess) parent; - Expression exp = fa.getExpression(); - if (fa.getName().toString().equals(findMe.toString())) { - constrains.add(ASTNode.FIELD_DECLARATION); - - if (exp != null) { - constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("FA EXP: " + exp.toString() + " of type " - + exp.getClass().getName() + " parent: " + exp.getParent()); - if (exp instanceof MethodInvocation) { - - declaringClass = findDeclaration3rdParty(((MethodInvocation) exp) - .getName(), - parentClass); -// return definedIn(declaringClass, ((MethodInvocation) parent) -// .getName().toString(), constrains, declaringClass); - return definedIn3rdPartyClass(declaringClass, - fa.getName().toString()); - /*SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) - .getName())); - if (stp == null) - return null;*/ - //declaringClass = findDeclaration(stp.getName()); -// return definedIn(declaringClass, fa.getName().toString(), -// constrains, declaringClass); - } else if (exp instanceof FieldAccess) { -// SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp) -// .getName())); -// if (stp == null) -// return null; - //declaringClass = findDeclaration((stp.getName())); - declaringClass = findDeclaration3rdParty(((FieldAccess) exp) - .getName(), - parentClass); - constrains.add(ASTNode.TYPE_DECLARATION); -// return definedIn(declaringClass, fa.getName().toString(), -// constrains, declaringClass); - return definedIn3rdPartyClass(declaringClass, - fa.getName().toString()); - } - if (exp instanceof SimpleName) { - SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp))); - if (stp == null) - return null; - System.out.println("3rdPa "+stp.getName()); - declaringClass = definedIn3rdPartyClass(stp.getName().toString(), - "THIS"); - //declaringClass = findDeclaration(stp.getName()); - // System.out.println("FA.SN " + getNodeAsString(declaringClass)); - constrains.add(ASTNode.METHOD_DECLARATION); -// return definedIn(declaringClass, fa.getName().toString(), -// constrains, declaringClass); - return definedIn3rdPartyClass(declaringClass, - fa.getName() - .toString()); - } - } - - } else { - parent = parent.getParent(); // Move one up the ast. V V IMP!! - } - } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) { - - QualifiedName qn = (QualifiedName) parent; - if (!findMe.toString().equals(qn.getQualifier().toString())) { - - SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); - - // declaringClass = findDeclaration(stp.getName()); - System.out.println(qn.getQualifier() + "->" + qn.getName()); - // System.out.println("QN decl class: " + getNodeAsString(declaringClass)); - constrains.clear(); - constrains.add(ASTNode.TYPE_DECLARATION); - constrains.add(ASTNode.FIELD_DECLARATION); - declaringClass = definedIn3rdPartyClass(stp.getName().toString(), - "THIS"); -// return definedIn(declaringClass, qn.getName().toString(), constrains, -// null); - return definedIn3rdPartyClass(declaringClass, qn.getName().toString()); - } - else{ - if(findMe instanceof QualifiedName){ - QualifiedName qnn = (QualifiedName) findMe; - System.out.println("findMe is a QN, " - + (qnn.getQualifier().toString() + " other " + qnn.getName() - .toString())); - - SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); - System.out.println(qnn.getQualifier() + "->" + qnn.getName()); - declaringClass = definedIn3rdPartyClass(stp.getName().toString(), - "THIS"); -// System.out.println("QN decl class: " -// + getNodeAsString(declaringClass)); - constrains.clear(); - constrains.add(ASTNode.TYPE_DECLARATION); - constrains.add(ASTNode.FIELD_DECLARATION); - return definedIn3rdPartyClass(declaringClass, qnn.getName().toString()); - } - } - } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { -// constrains.add(ASTNode.TYPE_DECLARATION); -// if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) -// constrains.add(ASTNode.CLASS_INSTANCE_CREATION); - // If it's a simple type, simply locate it within the list of imports - return definedIn3rdPartyClass(findMe.toString(), "THIS"); - } - - return definedIn3rdPartyClass(parentClass,findMe.toString()); - } - + /** * Find the SimpleType from FD, SVD, VDS, etc * From 9403318f6751ff92b717f012b542ac187cf42eef Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 14:16:36 +0530 Subject: [PATCH 113/608] adding more cases to resolveExp3rdParty --- .../mode/experimental/ASTGenerator.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 3b90231e3..6b950018f 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -511,7 +511,7 @@ public class ASTGenerator { astNode = astNode.getParent(); } switch (astNode.getNodeType()) { - + //TODO: Notice the redundancy in the 3 cases, you can simplify things even more. case ASTNode.FIELD_ACCESS: FieldAccess fa = (FieldAccess) astNode; if (fa.getExpression() == null) { @@ -526,7 +526,14 @@ public class ASTGenerator { /*The type wasn't found in local code, so it might be something like * System.out.println(), or maybe belonging to super class, etc. */ - System.out.println("resolve 3rd par, Can't resolve " + fa.getExpression()); + Class tehClass = findClassIfExists(((SimpleName)fa.getExpression()).toString()); + if (tehClass != null) { + // Method Expression is a simple name and wasn't located locally, but found in a class + // so look for method in this class. + return definedIn3rdPartyClass(new ClassMember(tehClass), fa + .getName().toString()); + } + System.out.println("FA resolve 3rd par, Can't resolve " + fa.getExpression()); return null; } @@ -558,9 +565,16 @@ public class ASTGenerator { nearestNode)); if(stp == null){ /*The type wasn't found in local code, so it might be something like - * System.out.println(), or maybe belonging to super class, etc. + * System.console()., or maybe belonging to super class, etc. */ - System.out.println("resolve 3rd par, Can't resolve " + mi.getExpression()); + Class tehClass = findClassIfExists(((SimpleName)mi.getExpression()).toString()); + if (tehClass != null) { + // Method Expression is a simple name and wasn't located locally, but found in a class + // so look for method in this class. + return definedIn3rdPartyClass(new ClassMember(tehClass), mi + .getName().toString()); + } + System.out.println("MI resolve 3rd par, Can't resolve " + mi.getExpression()); return null; } System.out.println("MI, SN Type " + getNodeAsString(stp)); @@ -606,7 +620,7 @@ public class ASTGenerator { return definedIn3rdPartyClass(new ClassMember(tehClass), qn .getName().toString()); } - System.out.println("resolve 3rd par, Can't resolve " + qn.getQualifier()); + System.out.println("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); return null; } System.out.println("QN, SN Local Type " + getNodeAsString(stp)); From ced2eae3cd596ab5574d5f2c5458ca4a4383e37d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 14:43:10 +0530 Subject: [PATCH 114/608] adding more cases to resolveExp3rdParty.. --- .../mode/experimental/ASTGenerator.java | 102 +++++++++--------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 6b950018f..cdc01b930 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -581,7 +581,14 @@ public class ASTGenerator { ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode); if(typeDec == null){ System.out.println(stp.getName() + " couldn't be found locally.."); - return new ClassMember(findClassIfExists(stp.getName().toString())); + Class tehClass = findClassIfExists(stp.getName().toString()); + if (tehClass != null) { + // Method Expression is a simple name and wasn't located locally, but found in a class + // so look for method in this class. + return definedIn3rdPartyClass(new ClassMember(tehClass), mi + .getName().toString()); + } + //return new ClassMember(findClassIfExists(stp.getName().toString())); } //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); return new ClassMember(typeDec); @@ -653,7 +660,7 @@ public class ASTGenerator { * @param expression * @return */ - public static ASTNode resolveChildExpression(ASTNode expression) { + public static ASTNode getChildExpression(ASTNode expression) { // ASTNode anode = null; if (expression instanceof SimpleName) { return expression; @@ -664,12 +671,12 @@ public class ASTGenerator { }else if (expression instanceof MethodInvocation) { return ((MethodInvocation) expression).getName(); } - System.out.println(" resolveChildExpression returning NULL for " + System.out.println(" getChildExpression returning NULL for " + getNodeAsString(expression)); return null; } - public static ASTNode resolveParentExpression(ASTNode expression) { + public static ASTNode getParentExpression(ASTNode expression) { // ASTNode anode = null; if (expression instanceof SimpleName) { return expression; @@ -680,7 +687,7 @@ public class ASTGenerator { } else if (expression instanceof MethodInvocation) { return ((MethodInvocation) expression).getExpression(); } - System.out.println("resolveParentExpression returning NULL for " + System.out.println("getParentExpression returning NULL for " + getNodeAsString(expression)); return null; } @@ -823,14 +830,14 @@ public class ASTGenerator { // Have to resolve it by carefully traversing AST of testNode System.err.println("Complex expression " + getNodeAsString(testnode)); System.out.println("candidates empty"); - String childExpr = resolveChildExpression(testnode) + String childExpr = getChildExpression(testnode) .toString(); - System.out.println("Parent expression : " + resolveParentExpression(testnode)); + System.out.println("Parent expression : " + getParentExpression(testnode)); System.out.println("Child expression : " + childExpr); if(!noCompare){ System.out.println("Original testnode " + getNodeAsString(testnode)); - testnode = resolveParentExpression(testnode); + testnode = getParentExpression(testnode); System.out.println("Corrected testnode " + getNodeAsString(testnode)); } ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); @@ -1089,7 +1096,6 @@ public class ASTGenerator { label.append(","); } label.append(")"); - if (noCompare) { candidates.add(new CompletionCandidate(method)); } @@ -1125,14 +1131,10 @@ public class ASTGenerator { private Class findClassIfExists(String className){ Class tehClass = null; // First, see if the classname is a fully qualified name and loads straightaway - try { - tehClass = Class.forName(className, false, - errorCheckerService - .getSketchClassLoader()); + tehClass = loadClass(className); + if(tehClass instanceof Class){ System.out.println(tehClass.getName() + " located straightaway"); return tehClass; - } catch (ClassNotFoundException e) { - //System.out.println("Doesn't exist in package: "); } System.out.println("Looking in the classloader for " + className); @@ -1141,66 +1143,66 @@ public class ASTGenerator { for (ImportStatement impS : imports) { String temp = impS.getPackageName(); - try { - if(temp.endsWith("*")){ - temp = temp.substring(0, temp.length()-1) + className; + + if (temp.endsWith("*")) { + temp = temp.substring(0, temp.length() - 1) + className; + } else { + int x = temp.lastIndexOf('.'); + if (temp.substring(x).equals(className)) { + // Well, we've found the class. } - else { - int x = temp.lastIndexOf('.'); - if(temp.substring(x).equals(className)){ - // Well, we've found the class. - } - } - tehClass = Class.forName(temp, false, - errorCheckerService - .getSketchClassLoader()); + } + tehClass = loadClass(temp); + if (tehClass instanceof Class) { System.out.println(tehClass.getName() + " located."); return tehClass; - } catch (ClassNotFoundException e) { - // it does not exist on the classpath - System.out.println("Doesn't exist in package: " + impS.getImportName()); } + + System.out.println("Doesn't exist in package: " + impS.getImportName()); + } PdePreprocessor p = new PdePreprocessor(null); for (String impS : p.getCoreImports()) { - try { - - tehClass = Class.forName(impS.substring(0,impS.length()-1) + className, false, - errorCheckerService - .getSketchClassLoader()); + tehClass = loadClass(impS.substring(0,impS.length()-1) + className); + if (tehClass instanceof Class) { System.out.println(tehClass.getName() + " located."); return tehClass; - } catch (ClassNotFoundException e) { - // it does not exist on the classpath - System.out.println("Doesn't exist in package: " + impS); } + System.out.println("Doesn't exist in package: " + impS); } for (String impS : p.getDefaultImports()) { - try { - if(className.equals(impS) || impS.endsWith(className)){ - tehClass = Class.forName(impS, false, errorCheckerService.getSketchClassLoader()); + if(className.equals(impS) || impS.endsWith(className)){ + tehClass = loadClass(impS); + if (tehClass instanceof Class) { System.out.println(tehClass.getName() + " located."); return tehClass; } - - } catch (ClassNotFoundException e) { - // it does not exist on the classpath System.out.println("Doesn't exist in package: " + impS); } } // And finally, the daddy String daddy = "java.lang." + className; - try { - tehClass = Class.forName(daddy, false, - errorCheckerService.getSketchClassLoader()); + tehClass = loadClass(daddy); + if (tehClass instanceof Class) { System.out.println(tehClass.getName() + " located."); return tehClass; + } + System.out.println("Doesn't exist in java.lang"); + + return tehClass; + } + + private Class loadClass(String className){ + Class tehClass = null; + try { + tehClass = Class.forName(className, false, + errorCheckerService + .getSketchClassLoader()); } catch (ClassNotFoundException e) { - // it does not exist on the classpath - System.out.println("Doesn't exist in package: " + daddy); + //System.out.println("Doesn't exist in package: "); } return tehClass; } @@ -2536,7 +2538,7 @@ public class ASTGenerator { public ClassMember(Class m) { thisclass = m; - stringVal = "Class " + m.getName(); + stringVal = "Predefined Class " + m.getName(); classType = m.getName(); } From 0a6748d466509c3944d79c52ab5c92a282894b50 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 14:53:32 +0530 Subject: [PATCH 115/608] forget this fella always..lol --- .../src/processing/mode/experimental/ASTGenerator.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index cdc01b930..cb1157699 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -635,7 +635,15 @@ public class ASTGenerator { ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode); if(typeDec == null){ System.out.println(stp.getName() + " couldn't be found locally.."); - return new ClassMember(findClassIfExists(stp.getName().toString())); + + Class tehClass = findClassIfExists(stp.getName().toString()); + if (tehClass != null) { + // note how similar thing is called on line 690. Check check. + return definedIn3rdPartyClass(new ClassMember(tehClass), qn + .getName().toString()); + } + System.out.println("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); + return null; } return new ClassMember(typeDec); } else { From 87750410e96ce4005c38860995e7f44f5e20e4ac Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 15:35:53 +0530 Subject: [PATCH 116/608] phew.. will this insanity shall ever end? --- .../mode/experimental/ASTGenerator.java | 60 ++++++++++++++----- .../experimental/CompletionCandidate.java | 22 ++++++- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index cb1157699..24036eaf6 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -379,17 +379,14 @@ public class ASTGenerator { CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1]; cand[0] = new CompletionCandidate(md); for (int i = 0; i < params.size(); i++) { - cand[i + 1] = new CompletionCandidate(params.get(i).toString(), "", "", - CompletionCandidate.LOCAL_VAR); +// cand[i + 1] = new CompletionCandidate(params.get(i).toString(), "", "", +// CompletionCandidate.LOCAL_VAR); + cand[i + 1] = new CompletionCandidate((SingleVariableDeclaration)params.get(i)); } return cand; case ASTNode.SINGLE_VARIABLE_DECLARATION: - return new CompletionCandidate[] { new CompletionCandidate( - getNodeAsString2(node), - "", - "", - CompletionCandidate.LOCAL_VAR) }; + return new CompletionCandidate[] { new CompletionCandidate((SingleVariableDeclaration)node) }; case ASTNode.FIELD_DECLARATION: vdfs = ((FieldDeclaration) node).fragments(); @@ -408,8 +405,9 @@ public class ASTGenerator { CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()]; int i = 0; for (VariableDeclarationFragment vdf : vdfs) { - ret[i++] = new CompletionCandidate(getNodeAsString2(vdf), "", "", - CompletionCandidate.LOCAL_VAR); +// ret[i++] = new CompletionCandidate(getNodeAsString2(vdf), "", "", +// CompletionCandidate.LOCAL_VAR); + ret[i++] = new CompletionCandidate(vdf); } return ret; } @@ -591,7 +589,8 @@ public class ASTGenerator { //return new ClassMember(findClassIfExists(stp.getName().toString())); } //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); - return new ClassMember(typeDec); + return definedIn3rdPartyClass(new ClassMember(typeDec), mi + .getName().toString()); } else { System.out.println("MI EXP.."+getNodeAsString(mi.getExpression())); // return null; @@ -611,7 +610,7 @@ public class ASTGenerator { return new ClassMember(extracTypeInfo(temp2)); } if (qn.getQualifier() == null) { - System.out.println("MI,Not implemented."); + System.out.println("QN,Not implemented."); return null; } else { @@ -645,7 +644,8 @@ public class ASTGenerator { System.out.println("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); return null; } - return new ClassMember(typeDec); + return definedIn3rdPartyClass(new ClassMember(typeDec), qn + .getName().toString()); } else { scopeParent = resolveExpression3rdParty(nearestNode, qn.getQualifier(), noCompare); @@ -1251,7 +1251,15 @@ public class ASTGenerator { .startsWith(memberName)) return new ClassMember(td.getMethods()[i]); } - return null; + if(td.getSuperclassType() instanceof Type){ + System.out.println(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); + return definedIn3rdPartyClass(new ClassMember(td + .getSuperclassType()),memberName); + } + else + { + return definedIn3rdPartyClass(new ClassMember(Object.class),memberName); + } } Class probableClass = null; @@ -2573,6 +2581,9 @@ public class ASTGenerator { public ClassMember(ASTNode node){ astNode = node; stringVal = getNodeAsString(node); + if(node instanceof TypeDeclaration){ + declaringNode = node; + } if(node instanceof SimpleType){ classType = ((SimpleType)node).getName().toString(); } @@ -2634,7 +2645,7 @@ public class ASTGenerator { * @param node * @return */ - private static SimpleType extracTypeInfo(ASTNode node) { + public static SimpleType extracTypeInfo(ASTNode node) { if (node == null) return null; switch (node.getNodeType()) { @@ -2654,6 +2665,27 @@ public class ASTGenerator { System.out.println("Unknown type info request " + getNodeAsString(node)); return null; } + + public static Type extracTypeInfo2(ASTNode node) { + if (node == null) + return null; + switch (node.getNodeType()) { + case ASTNode.METHOD_DECLARATION: + return ((MethodDeclaration) node).getReturnType2(); + case ASTNode.FIELD_DECLARATION: + return ((FieldDeclaration) node).getType(); + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + return ((VariableDeclarationExpression) node).getType(); + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + return ((VariableDeclarationStatement) node).getType(); + case ASTNode.SINGLE_VARIABLE_DECLARATION: + return ((SingleVariableDeclaration) node).getType(); + case ASTNode.VARIABLE_DECLARATION_FRAGMENT: + return extracTypeInfo2(node.getParent()); + } + System.out.println("Unknown type info request " + getNodeAsString(node)); + return null; + } @SuppressWarnings("unchecked") private static ASTNode definedIn(ASTNode node, String name, diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 4ff73400f..dcf7da4cc 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -6,6 +6,8 @@ import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; public class CompletionCandidate implements Comparable{ @@ -51,11 +53,26 @@ public class CompletionCandidate implements Comparable{ } label.append(")"); + label.append(" : "+method.getReturnType().getSimpleName()); cstr.append(")"); this.label = label.toString(); this.completionString = cstr.toString(); } - + + public CompletionCandidate(SingleVariableDeclaration svd) { + completionString = svd.getName().toString(); + elementName = svd.getName().toString(); + type = LOCAL_VAR; + label = svd.getName() + " : " + svd.getType(); + } + + public CompletionCandidate(VariableDeclarationFragment vdf) { + completionString = vdf.getName().toString(); + elementName = vdf.getName().toString(); + type = LOCAL_VAR; + label = vdf.getName() + " : " + ASTGenerator.extracTypeInfo2(vdf); + } + public CompletionCandidate(MethodDeclaration method) { definingClass = ""; elementName = method.getName().toString(); @@ -72,6 +89,7 @@ public class CompletionCandidate implements Comparable{ } } label.append(")"); + label.append(" : "+method.getReturnType2()); cstr.append(")"); this.label = label.toString(); this.completionString = cstr.toString(); @@ -81,7 +99,7 @@ public class CompletionCandidate implements Comparable{ definingClass = f.getDeclaringClass().getName(); elementName = f.getName(); type = FIELD; - label = f.getName(); + label = f.getName() + " : " + f.getType().getSimpleName(); completionString = elementName; } From d083e2eee006ba782efb8ecf6bfe1c44063bf8ab Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 13 Jul 2013 15:39:12 +0530 Subject: [PATCH 117/608] updated todo, code completion lookin good now, types are also displayed now btw --- pdex/Todo, GSoC 2013.txt | 5 +++- .../mode/experimental/ASTGenerator.java | 30 ------------------- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 300bf8a73..4c2bcd119 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -19,7 +19,10 @@ x! Recursive lookup for compiled(library) code! x! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. *! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. - Making very good progress here. The elegance of recurion - Hats off! - - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step + - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step + - Looks almost complete now, nearly all cases covered(July 13th) +* Scope handling? Static/non static scope? +x Display the type of Completion(method return type, variable type) in the popup. x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x Differentiating between multiple statements on the same line. How to? Done with offset handling. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 24036eaf6..1401dedc7 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1284,36 +1284,6 @@ public class ASTGenerator { return null; } -// private ClassMember loadClass(String className){ -// RegExpResourceFilter regExpResourceFilter; -// regExpResourceFilter = new RegExpResourceFilter(".*", className + ".class"); -// String[] resources = classPath.findResources("", regExpResourceFilter); -// for (String cn : resources) { -// System.out.println("-> " + cn); -// } -// if (resources.length == 0) { -// System.out.println("In defIn3rdPar(), couldn't find class: " + className); -// return null; -// } -// //TODO: Multiple matched classes? What about 'em? -// String matchedClass = resources[0]; -// matchedClass = matchedClass.substring(0, matchedClass.length() - 6); -// matchedClass = matchedClass.replace('/', '.'); -// System.out.println("In defIn3rdPar(), Matched class: " + matchedClass); -// -// System.out.println("Trying to load class " + className); -// try { -// Class probableClass = Class.forName(className, false, -// errorCheckerService.classLoader); -// return new ClassMember(probableClass); -// } catch (ClassNotFoundException e) { -// -// System.out.println("Couldn't load " + className); -// e.printStackTrace(); -// } -// return null; -// } - public void updateJavaDoc(final CompletionCandidate candidate) { //TODO: Work on this later. return; From 3e5a552402057bec3cdd5b1e3ace66b7905b75ed Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 00:13:00 +0530 Subject: [PATCH 118/608] ironing out the creases --- .../mode/experimental/ASTGenerator.java | 163 +++++++++--------- .../mode/experimental/CompletionPanel.java | 6 +- .../mode/experimental/TextArea.java | 2 +- 3 files changed, 87 insertions(+), 84 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1401dedc7..3827b1bc8 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -61,6 +61,7 @@ import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; @@ -838,23 +839,31 @@ public class ASTGenerator { // Have to resolve it by carefully traversing AST of testNode System.err.println("Complex expression " + getNodeAsString(testnode)); System.out.println("candidates empty"); - String childExpr = getChildExpression(testnode) - .toString(); + ASTNode childExpr = getChildExpression(testnode); System.out.println("Parent expression : " + getParentExpression(testnode)); System.out.println("Child expression : " + childExpr); - - if(!noCompare){ - System.out.println("Original testnode " + getNodeAsString(testnode)); - testnode = getParentExpression(testnode); - System.out.println("Corrected testnode " + getNodeAsString(testnode)); + if (childExpr instanceof ASTNode) { + if (!noCompare) { + System.out.println("Original testnode " + + getNodeAsString(testnode)); + testnode = getParentExpression(testnode); + System.out.println("Corrected testnode " + + getNodeAsString(testnode)); + } + ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, + noCompare); + if (expr == null) { + System.out.println("Expr is null"); + } else { + System.out.println("Expr is " + expr.toString()); + + candidates = getMembersForType(expr, childExpr.toString(), + noCompare, false); + } } - ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); - if(expr == null){ - System.out.println("Expr is null"); - }else { - System.out.println("Expr is " + expr.toString()); - candidates = getMembersForType(expr, - childExpr, noCompare, false); + else + { + System.out.println("ChildExpr is null"); } /*ASTNode det = resolveExpression(nearestNode, testnode,noCompare); // Find the parent of the expression @@ -1030,7 +1039,9 @@ public class ASTGenerator { System.out.println("getMemFoType-> Looking for match " + child.toString() + " inside " + tehClass + " noCompare " + noCompare + " staticOnly " + staticOnly); - + if(tehClass == null){ + return candidates; + } // tehClass will either be a TypeDecl defined locally if(tehClass.getDeclaringNode() instanceof TypeDeclaration){ @@ -1082,52 +1093,48 @@ public class ASTGenerator { } // Or tehClass will be a predefined class - try { - Class probableClass; - if(tehClass.getClass_() != null){ - probableClass = tehClass.getClass_(); + + Class probableClass; + if (tehClass.getClass_() != null) { + probableClass = tehClass.getClass_(); + } else { + probableClass = findClassIfExists(tehClass.getTypeAsString()); + if (probableClass == null) { + System.out.println("Couldn't find class " + tehClass.getTypeAsString()); + return candidates; } - else - { - probableClass = findClassIfExists(tehClass.getTypeAsString()); - System.out.println("Loaded " + probableClass.toString()); - } - for (Method method : probableClass.getMethods()) { - if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { - continue; - } - - StringBuffer label = new StringBuffer(method.getName() + "("); - for (int i = 0; i < method.getParameterTypes().length; i++) { - label.append(method.getParameterTypes()[i].getSimpleName()); - if (i < method.getParameterTypes().length - 1) - label.append(","); - } - label.append(")"); - if (noCompare) { - candidates.add(new CompletionCandidate(method)); - } - else if (label.toString().startsWith(child.toString())) { - candidates.add(new CompletionCandidate(method)); - } - } - for (Field field : probableClass.getFields()) { - if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { - continue; - } - if (noCompare) { - candidates.add(new CompletionCandidate(field)); - } - else if (field.getName().startsWith(child.toString())) { - candidates.add(new CompletionCandidate(field)); - } - } - return candidates; - } catch (Exception e) { - e.printStackTrace(); - System.out.println("Couldn't load " + tehClass); + System.out.println("Loaded " + probableClass.toString()); } - return null; + for (Method method : probableClass.getMethods()) { + if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { + continue; + } + + StringBuffer label = new StringBuffer(method.getName() + "("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + label.append(method.getParameterTypes()[i].getSimpleName()); + if (i < method.getParameterTypes().length - 1) + label.append(","); + } + label.append(")"); + if (noCompare) { + candidates.add(new CompletionCandidate(method)); + } else if (label.toString().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(method)); + } + } + for (Field field : probableClass.getFields()) { + if (!Modifier.isStatic(field.getModifiers()) && staticOnly) { + continue; + } + if (noCompare) { + candidates.add(new CompletionCandidate(field)); + } else if (field.getName().startsWith(child.toString())) { + candidates.add(new CompletionCandidate(field)); + } + } + return candidates; + } /** @@ -1137,6 +1144,9 @@ public class ASTGenerator { * @return */ private Class findClassIfExists(String className){ + if(className == null){ + return null; + } Class tehClass = null; // First, see if the classname is a fully qualified name and loads straightaway tehClass = loadClass(className); @@ -1205,12 +1215,13 @@ public class ASTGenerator { private Class loadClass(String className){ Class tehClass = null; - try { - tehClass = Class.forName(className, false, - errorCheckerService - .getSketchClassLoader()); - } catch (ClassNotFoundException e) { - //System.out.println("Doesn't exist in package: "); + if(className instanceof String){ + try { + tehClass = Class.forName(className, false, + errorCheckerService.getSketchClassLoader()); + } catch (ClassNotFoundException e) { + //System.out.println("Doesn't exist in package: "); + } } return tehClass; } @@ -1323,7 +1334,7 @@ public class ASTGenerator { private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { Iterator it = node .structuralPropertiesForType().iterator(); - System.err.println("Props of " + node.getClass().getName()); + // System.err.println("Props of " + node.getClass().getName()); while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -2618,22 +2629,10 @@ public class ASTGenerator { public static SimpleType extracTypeInfo(ASTNode node) { if (node == null) return null; - switch (node.getNodeType()) { - case ASTNode.METHOD_DECLARATION: - return (SimpleType) ((MethodDeclaration) node).getReturnType2(); - case ASTNode.FIELD_DECLARATION: - return (SimpleType) ((FieldDeclaration) node).getType(); - case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - return (SimpleType) ((VariableDeclarationExpression) node).getType(); - case ASTNode.VARIABLE_DECLARATION_STATEMENT: - return (SimpleType) ((VariableDeclarationStatement) node).getType(); - case ASTNode.SINGLE_VARIABLE_DECLARATION: - return (SimpleType) ((SingleVariableDeclaration) node).getType(); - case ASTNode.VARIABLE_DECLARATION_FRAGMENT: - return extracTypeInfo(node.getParent()); - } - System.out.println("Unknown type info request " + getNodeAsString(node)); - return null; + Type t = extracTypeInfo2(node); + if (t instanceof PrimitiveType) + return null; + return (SimpleType) t; } public static Type extracTypeInfo2(ASTNode node) { diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 6b853e10d..4fd04bbb9 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -46,7 +46,7 @@ public class CompletionPanel { scrollPane = new JScrollPane(); scrollPane.setViewportView(completionList = createSuggestionList(position, items)); popupMenu.add(scrollPane, BorderLayout.CENTER); - popupMenu.setPopupSize(200, 250); //TODO: Eradicate this evil + popupMenu.setPopupSize(280, 250); //TODO: Eradicate this evil this.textarea.errorCheckerService.astGenerator .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) @@ -57,6 +57,10 @@ public class CompletionPanel { public boolean isVisible() { return popupMenu.isVisible(); } + + public void setVisible(boolean v){ + popupMenu.setVisible(v); + } private JList createSuggestionList(final int position, final DefaultListModel items) { diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 2da36972f..e87827154 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -689,7 +689,7 @@ public class TextArea extends JEditTextArea { location); else suggestion.updateList(defListModel, subWord, position); - + suggestion.setVisible(true); // requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { @Override From 1903896f9d992efb887127ee3a6d54dddfe27b29 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 01:30:20 +0530 Subject: [PATCH 119/608] beginning with adding finer details, cursor placement --- pdex/Todo, GSoC 2013.txt | 10 ++++--- .../mode/experimental/ASTGenerator.java | 28 +++++++++---------- .../experimental/CompletionCandidate.java | 7 ++++- .../mode/experimental/CompletionPanel.java | 15 ++++++++-- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 4c2bcd119..3e1af0643 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -21,8 +21,7 @@ x! Library CC for nested would be tricky. Need to jump from local->compiled code - Making very good progress here. The elegance of recurion - Hats off! - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) -* Scope handling? Static/non static scope? -x Display the type of Completion(method return type, variable type) in the popup. +* Scope handling? Static/non static scope? x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x Differentiating between multiple statements on the same line. How to? Done with offset handling. @@ -31,10 +30,13 @@ Finer details * - Multiple 3rd party classes found in various packages x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? +x Cursor positioning should be after the first ( if arguments present, else after () +* Display the type of Completion(method return type, variable type) in the popup. + - facing some issues for local types * Sorted list of completion candidates - fields, then methods. It's unsorted presently. *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. -* Reflection API - getMethods vs getDeclaredMethods. -* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement +x Reflection API - getMethods vs getDeclaredMethods. declared. +x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement Completion List x Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 3827b1bc8..7235d6fbd 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -242,14 +242,14 @@ public class ASTGenerator { return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) { - frame2.setVisible(true); - } - if (!frameAutoComp.isVisible()) { - - frameAutoComp.setVisible(true); - - } +// if (!frame2.isVisible()) { +// frame2.setVisible(true); +// } +// if (!frameAutoComp.isVisible()) { +// +// frameAutoComp.setVisible(true); +// +// } // if (!jdocWindow.isVisible()) { // long t = System.currentTimeMillis(); // loadJars(); @@ -764,7 +764,7 @@ public class ASTGenerator { // Bottom up traversal of the AST to look for possible definitions at // higher levels. - nearestNode = nearestNode.getParent(); + //nearestNode = nearestNode.getParent(); while (nearestNode != null) { // If the current class has a super class, look inside it for // definitions. @@ -991,11 +991,11 @@ public class ASTGenerator { DefaultTableModel tm = new DefaultTableModel( candi, new String[] { "Suggestions" }); - tableAuto.setModel(tm); - tableAuto.validate(); - tableAuto.repaint(); -// CompletionCandidate[] candidatesArray = candidates -// .toArray(new CompletionCandidate[candidates.size()]); + if(tableAuto.isVisible()){ + tableAuto.setModel(tm); + tableAuto.validate(); + tableAuto.repaint(); + } errorCheckerService.getEditor().textArea() .showSuggestion(defListModel,word); } diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index dcf7da4cc..3c8b76481 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -51,7 +51,9 @@ public class CompletionCandidate implements Comparable{ cstr.append(","); } } - + if(method.getParameterTypes().length == 1) { + cstr.append(' '); + } label.append(")"); label.append(" : "+method.getReturnType().getSimpleName()); cstr.append(")"); @@ -88,6 +90,9 @@ public class CompletionCandidate implements Comparable{ cstr.append(","); } } + if(params.size() == 1) { + cstr.append(' '); + } label.append(")"); label.append(" : "+method.getReturnType2()); cstr.append(")"); diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 4fd04bbb9..b3e4fe363 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -107,8 +107,19 @@ public class CompletionPanel { System.err.println(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); textarea.getDocument().insertString(insertionPosition, selectedSuggestion, null); - textarea.setCaretPosition(insertionPosition - + selectedSuggestion.length()); + if(selectedSuggestion.endsWith(")")) + { + if(!selectedSuggestion.endsWith("()")){ + int x = selectedSuggestion.indexOf('('); + if(x != -1){ + //System.out.println("X................... " + x); + textarea.setCaretPosition(insertionPosition + (x+1)); + } + } + } + else { + textarea.setCaretPosition(insertionPosition + selectedSuggestion.length()); + } return true; } catch (BadLocationException e1) { e1.printStackTrace(); From 28afea1c893461f3eeac571c179b39c3a90a45fa Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 18:37:46 +0530 Subject: [PATCH 120/608] ignore case while matching, cmd+click on os x --- pdex/Todo, GSoC 2013.txt | 3 + .../mode/experimental/ASTGenerator.java | 58 +++++++++---------- .../experimental/CompletionCandidate.java | 1 + .../mode/experimental/TextAreaPainter.java | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 3e1af0643..17238b399 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -27,6 +27,7 @@ x! Should I implement wrapper for ASTNode? - possibly needed for code completion x Differentiating between multiple statements on the same line. How to? Done with offset handling. Finer details +*! - Ignore String case while finding completion candidates * - Multiple 3rd party classes found in various packages x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? @@ -35,6 +36,7 @@ x Cursor positioning should be after the first ( if arguments present, else afte - facing some issues for local types * Sorted list of completion candidates - fields, then methods. It's unsorted presently. *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. +* - Diamond opertaor isn't supported for now. Bummer. x Reflection API - getMethods vs getDeclaredMethods. declared. x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement @@ -76,5 +78,6 @@ x Local Methods x Local Classes x Recursive lookup, a.b().c() x Now highlihgting the declaration name, rather than the whole declaration. +* On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? *+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 7235d6fbd..653a46982 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1032,9 +1032,10 @@ public class ASTGenerator { } public ArrayList getMembersForType(ClassMember tehClass, - String child, + String childToLookFor, boolean noCompare, boolean staticOnly) { + String child = childToLookFor.toLowerCase(); ArrayList candidates = new ArrayList(); System.out.println("getMemFoType-> Looking for match " + child.toString() + " inside " + tehClass + " noCompare " + noCompare + " staticOnly " @@ -1052,26 +1053,20 @@ public class ASTGenerator { for (VariableDeclarationFragment vdf : vdfs) { if (noCompare) { candidates - .add(new CompletionCandidate(getNodeAsString2(vdf))); - } else if (vdf.getName().toString() - .startsWith(child.toString())) + .add(new CompletionCandidate(vdf)); + } else if (vdf.getName().toString().toLowerCase() + .startsWith(child)) candidates - .add(new CompletionCandidate(getNodeAsString2(vdf))); + .add(new CompletionCandidate(vdf)); } } for (int i = 0; i < td.getMethods().length; i++) { if (noCompare) { - candidates - .add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString(), "", - CompletionCandidate.METHOD)); - } else if (td.getMethods()[i].getName().toString() - .startsWith(child.toString())) - candidates - .add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString(), "", - CompletionCandidate.METHOD)); + candidates.add(new CompletionCandidate(td.getMethods()[i])); + } else if (td.getMethods()[i].getName().toString().toLowerCase() + .startsWith(child)) + candidates.add(new CompletionCandidate(td.getMethods()[i])); } ArrayList superClassCandidates = new ArrayList(); @@ -1079,12 +1074,12 @@ public class ASTGenerator { System.out.println(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); superClassCandidates = getMembersForType(new ClassMember(td .getSuperclassType()), - child, noCompare, staticOnly); + childToLookFor, noCompare, staticOnly); } else { superClassCandidates = getMembersForType(new ClassMember(Object.class), - child, noCompare, staticOnly); + childToLookFor, noCompare, staticOnly); } for (CompletionCandidate cc : superClassCandidates) { candidates.add(cc); @@ -1119,7 +1114,7 @@ public class ASTGenerator { label.append(")"); if (noCompare) { candidates.add(new CompletionCandidate(method)); - } else if (label.toString().startsWith(child.toString())) { + } else if (label.toString().toLowerCase().startsWith(child)) { candidates.add(new CompletionCandidate(method)); } } @@ -1129,7 +1124,7 @@ public class ASTGenerator { } if (noCompare) { candidates.add(new CompletionCandidate(field)); - } else if (field.getName().startsWith(child.toString())) { + } else if (field.getName().toLowerCase().startsWith(child)) { candidates.add(new CompletionCandidate(field)); } } @@ -1244,6 +1239,7 @@ public class ASTGenerator { return null; System.out.println("definedIn3rdPartyClass-> Looking for " + memberName + " in " + tehClass); + String memberNameL = memberName.toLowerCase(); if(tehClass.getDeclaringNode() instanceof TypeDeclaration){ TypeDeclaration td = (TypeDeclaration) tehClass.getDeclaringNode(); @@ -1251,15 +1247,15 @@ public class ASTGenerator { List vdfs = td.getFields()[i] .fragments(); for (VariableDeclarationFragment vdf : vdfs) { - if (vdf.getName().toString() - .startsWith(memberName)) + if (vdf.getName().toString().toLowerCase() + .startsWith(memberNameL)) return new ClassMember(vdf); } } for (int i = 0; i < td.getMethods().length; i++) { - if (td.getMethods()[i].getName().toString() - .startsWith(memberName)) + if (td.getMethods()[i].getName().toString().toLowerCase() + .startsWith(memberNameL)) return new ClassMember(td.getMethods()[i]); } if(td.getSuperclassType() instanceof Type){ @@ -1283,12 +1279,12 @@ public class ASTGenerator { System.out.println("Loaded " + probableClass.toString()); } for (Method method : probableClass.getMethods()) { - if (method.getName().equals(memberName)) { + if (method.getName().equalsIgnoreCase(memberName)) { return new ClassMember(method); } } for (Field field : probableClass.getFields()) { - if (field.getName().equals(memberName)) { + if (field.getName().equalsIgnoreCase(memberName)) { return new ClassMember(field); } } @@ -2686,7 +2682,7 @@ public class ASTGenerator { // look for constructor; MethodDeclaration[] methods = td.getMethods(); for (MethodDeclaration md : methods) { - if (md.getName().toString().equals(name)) { + if (md.getName().toString().equalsIgnoreCase(name)) { System.out.println("Found a constructor."); return md; } @@ -2702,7 +2698,7 @@ public class ASTGenerator { for (FieldDeclaration fd : fields) { List fragments = fd.fragments(); for (VariableDeclarationFragment vdf : fragments) { - if (vdf.getName().toString().equals(name)) + if (vdf.getName().toString().equalsIgnoreCase(name)) return fd; } } @@ -2710,7 +2706,7 @@ public class ASTGenerator { // look for methods MethodDeclaration[] methods = td.getMethods(); for (MethodDeclaration md : methods) { - if (md.getName().toString().equals(name)) { + if (md.getName().toString().equalsIgnoreCase(name)) { return md; } } @@ -2719,12 +2715,12 @@ public class ASTGenerator { break; case ASTNode.METHOD_DECLARATION: System.err.println(getNodeAsString(node)); - if (((MethodDeclaration) node).getName().toString().equals(name)) + if (((MethodDeclaration) node).getName().toString().equalsIgnoreCase(name)) return node; break; case ASTNode.SINGLE_VARIABLE_DECLARATION: System.err.println(getNodeAsString(node)); - if (((SingleVariableDeclaration) node).getName().toString().equals(name)) + if (((SingleVariableDeclaration) node).getName().toString().equalsIgnoreCase(name)) return node; break; case ASTNode.FIELD_DECLARATION: @@ -2745,7 +2741,7 @@ public class ASTGenerator { } if (vdfList != null) { for (VariableDeclarationFragment vdf : vdfList) { - if (vdf.getName().toString().equals(name)) + if (vdf.getName().toString().equalsIgnoreCase(name)) return node; } } diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 3c8b76481..8dab29c6b 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -76,6 +76,7 @@ public class CompletionCandidate implements Comparable{ } public CompletionCandidate(MethodDeclaration method) { + System.out.println("ComCan " + method.getName()); definingClass = ""; elementName = method.getName().toString(); type = METHOD; diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 9ee6b9539..2a1599c56 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -75,7 +75,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { // System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); - if (evt.isControlDown()) + if (evt.isControlDown() || evt.isMetaDown()) handleCtrlClick(evt); } }); From eeaa204cacf83c6597a0638a74480604cf53a3ce Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 19:49:28 +0530 Subject: [PATCH 121/608] improved completion sorting, fixes to ignore case completion --- pdex/Todo, GSoC 2013.txt | 8 +- .../mode/experimental/ASTGenerator.java | 50 ++++++------ .../experimental/CompletionCandidate.java | 77 ++++++++++--------- .../mode/experimental/CompletionPanel.java | 6 +- 4 files changed, 75 insertions(+), 66 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 17238b399..75653d4d0 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -27,13 +27,13 @@ x! Should I implement wrapper for ASTNode? - possibly needed for code completion x Differentiating between multiple statements on the same line. How to? Done with offset handling. Finer details -*! - Ignore String case while finding completion candidates -* - Multiple 3rd party classes found in various packages +x! - Ignore String case while finding completion candidates +x - Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? x Cursor positioning should be after the first ( if arguments present, else after () -* Display the type of Completion(method return type, variable type) in the popup. - - facing some issues for local types +x Display the type of Completion(method return type, variable type) in the popup. + - facing some issues for local types. Fixed. * Sorted list of completion candidates - fields, then methods. It's unsorted presently. *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * - Diamond opertaor isn't supported for now. Bummer. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 653a46982..76aa69879 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; import java.util.TreeMap; +import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.Box; @@ -366,11 +367,7 @@ public class ASTGenerator { List vdfs = null; switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: - return new CompletionCandidate[] { new CompletionCandidate( - getNodeAsString2(node), - ((TypeDeclaration) node) - .getName() - .toString()) }; + return new CompletionCandidate[] { new CompletionCandidate((TypeDeclaration) node) }; case ASTNode.METHOD_DECLARATION: MethodDeclaration md = (MethodDeclaration) node; @@ -793,7 +790,7 @@ public class ASTGenerator { CompletionCandidate[] types = checkForTypes(cnode); if (types != null) { for (int i = 0; i < types.length; i++) { - if (types[i].getElementName().startsWith(word2)) + if (types[i].getElementName().toLowerCase().startsWith(word2.toLowerCase())) candidates.add(types[i]); } } @@ -806,7 +803,7 @@ public class ASTGenerator { CompletionCandidate[] types = checkForTypes(clnode); if (types != null) { for (int i = 0; i < types.length; i++) { - if (types[i].getElementName().startsWith(word2)) + if (types[i].getElementName().toLowerCase().startsWith(word2.toLowerCase())) candidates.add(types[i]); } } @@ -815,22 +812,29 @@ public class ASTGenerator { } nearestNode = nearestNode.getParent(); } - if(candidates.isEmpty()){ - // We're seeing a simple name that's not defined locally or in - // the parent class. So most probably a pre-defined type. - System.out.println("Empty can. " + word2); - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter(".*", word2 + "[a-zA-Z_0-9]*.class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String matchedClass : resources) { - matchedClass = matchedClass.substring(0, - matchedClass.length() - 6); - matchedClass = matchedClass.replace('/', '.'); - int d = matchedClass.lastIndexOf('.'); - matchedClass = matchedClass.substring(d + 1); - candidates.add(new CompletionCandidate(matchedClass)); - //System.out.println("-> " + className); - } + // We're seeing a simple name that's not defined locally or in + // the parent class. So most probably a pre-defined type. + System.out.println("Empty can. " + word2); + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter( + Pattern.compile(".*"), + Pattern + .compile(word2 + + "[a-zA-Z_0-9]*.class", + Pattern.CASE_INSENSITIVE)); + String[] resources = classPath + .findResources("", regExpResourceFilter); + for (String matchedClass2 : resources) { + matchedClass2 = matchedClass2.replace('/', '.'); + String matchedClass = matchedClass2.substring(0, matchedClass2 + .length() - 6); + int d = matchedClass.lastIndexOf('.'); + matchedClass = matchedClass.substring(d + 1); + candidates + .add(new CompletionCandidate(matchedClass, matchedClass + " : " + + matchedClass2.substring(0, d), matchedClass, + CompletionCandidate.PREDEF_CLASS)); + //System.out.println("-> " + className); } } else { diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 8dab29c6b..6fed141c1 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -7,12 +7,11 @@ import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; public class CompletionCandidate implements Comparable{ - private String definingClass; - private String elementName; // private String label; // the toString value @@ -21,27 +20,28 @@ public class CompletionCandidate implements Comparable{ private int type; - public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3; + public static final int PREDEF_CLASS = 0, PREDEF_FIELD = 1, + PREDEF_METHOD = 2, LOCAL_CLASS = 3, LOCAL_METHOD = 4, LOCAL_FIELD = 5, + LOCAL_VAR = 6; - public CompletionCandidate(String name, String className, String label, - int TYPE) { - definingClass = className; - elementName = name; - if (label.length() > 0) - this.label = label; - else - this.label = name; - this.type = TYPE; - if (type == METHOD) { - this.label += "()"; - } - completionString = this.label; - } +// public CompletionCandidate(String name, String className, String label, +// int TYPE) { +// elementName = name; +// if (label.length() > 0) +// this.label = label; +// else +// this.label = name; +// this.type = TYPE; +// if (type == LOCAL_METHOD) { +// this.label += "()"; +// } +// completionString = this.label; +// } public CompletionCandidate(Method method) { - definingClass = method.getDeclaringClass().getName(); + method.getDeclaringClass().getName(); elementName = method.getName(); - type = METHOD; + type = LOCAL_METHOD; StringBuffer label = new StringBuffer(method.getName() + "("); StringBuffer cstr = new StringBuffer(method.getName() + "("); for (int i = 0; i < method.getParameterTypes().length; i++) { @@ -59,13 +59,14 @@ public class CompletionCandidate implements Comparable{ cstr.append(")"); this.label = label.toString(); this.completionString = cstr.toString(); + type = PREDEF_METHOD; } public CompletionCandidate(SingleVariableDeclaration svd) { completionString = svd.getName().toString(); elementName = svd.getName().toString(); type = LOCAL_VAR; - label = svd.getName() + " : " + svd.getType(); + label = svd.getName() + " : " + svd.getType(); } public CompletionCandidate(VariableDeclarationFragment vdf) { @@ -77,9 +78,8 @@ public class CompletionCandidate implements Comparable{ public CompletionCandidate(MethodDeclaration method) { System.out.println("ComCan " + method.getName()); - definingClass = ""; elementName = method.getName().toString(); - type = METHOD; + type = LOCAL_METHOD; List params = (List) method .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); StringBuffer label = new StringBuffer(elementName + "("); @@ -100,31 +100,34 @@ public class CompletionCandidate implements Comparable{ this.label = label.toString(); this.completionString = cstr.toString(); } + + public CompletionCandidate(TypeDeclaration td){ + type = LOCAL_CLASS; + elementName = td.getName().toString(); + label = elementName; + completionString = elementName; + } public CompletionCandidate(Field f) { - definingClass = f.getDeclaringClass().getName(); + f.getDeclaringClass().getName(); elementName = f.getName(); - type = FIELD; + type = PREDEF_FIELD; label = f.getName() + " : " + f.getType().getSimpleName(); completionString = elementName; } - public CompletionCandidate(String name, String className) { - definingClass = className; + public CompletionCandidate(String name, String labelStr, String completionStr, int type) { + elementName = name; + label = labelStr; + completionString = completionStr; + this.type = type; + } + + public CompletionCandidate(String name, int type) { elementName = name; label = name; completionString = name; - } - - public CompletionCandidate(String name) { - definingClass = ""; - elementName = name; - label = name; - completionString = name; - } - - public String getDefiningClass() { - return definingClass; + this.type = type; } public String getElementName() { diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index b3e4fe363..9f6d5d6b6 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -105,8 +105,10 @@ public class CompletionPanel { String selectedSuggestion = ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString().substring(subWord.length()); System.err.println(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); - textarea.getDocument().insertString(insertionPosition, - selectedSuggestion, null); + textarea.getDocument().remove(insertionPosition-subWord.length(), subWord.length()); + textarea.getDocument().insertString(insertionPosition-subWord.length(), + ((CompletionCandidate) completionList + .getSelectedValue()).getCompletionString(), null); if(selectedSuggestion.endsWith(")")) { if(!selectedSuggestion.endsWith("()")){ From 8466cf084a0b4875641c70253d03b1051837b84b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 20:04:09 +0530 Subject: [PATCH 122/608] updated todo --- pdex/Todo, GSoC 2013.txt | 10 +++++++--- .../mode/experimental/CompletionCandidate.java | 15 --------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 75653d4d0..2159156ae 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -25,20 +25,24 @@ x! Library CC for nested would be tricky. Need to jump from local->compiled code x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x Differentiating between multiple statements on the same line. How to? Done with offset handling. +* - Add a static debug field, disable debugging info on console. +* - update build.xml to produce dists +* - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc Finer details x! - Ignore String case while finding completion candidates x - Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! -* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible? +* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? x Cursor positioning should be after the first ( if arguments present, else after () x Display the type of Completion(method return type, variable type) in the popup. - facing some issues for local types. Fixed. -* Sorted list of completion candidates - fields, then methods. It's unsorted presently. +x Sorted list of completion candidates - fields, then methods. It's unsorted presently. *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. -* - Diamond opertaor isn't supported for now. Bummer. +* - Diamond operator isn't supported for now. Bummer. x Reflection API - getMethods vs getDeclaredMethods. declared. x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement +* - Icons for completions? Or overkill right now? Completion List x Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 6fed141c1..f6bf99633 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -24,20 +24,6 @@ public class CompletionCandidate implements Comparable{ PREDEF_METHOD = 2, LOCAL_CLASS = 3, LOCAL_METHOD = 4, LOCAL_FIELD = 5, LOCAL_VAR = 6; -// public CompletionCandidate(String name, String className, String label, -// int TYPE) { -// elementName = name; -// if (label.length() > 0) -// this.label = label; -// else -// this.label = name; -// this.type = TYPE; -// if (type == LOCAL_METHOD) { -// this.label += "()"; -// } -// completionString = this.label; -// } - public CompletionCandidate(Method method) { method.getDeclaringClass().getName(); elementName = method.getName(); @@ -150,7 +136,6 @@ public class CompletionCandidate implements Comparable{ if(type != cc.getType()){ return cc.getType() - type; } - return (elementName.compareTo(cc.getElementName())); } From 10755992a4a387906cbb239a5d941fed33ab2c26 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 21:37:06 +0530 Subject: [PATCH 123/608] added import suggestion --- pdex/Todo, GSoC 2013.txt | 5 ++ .../mode/experimental/ASTGenerator.java | 73 +++++++++++++++++++ .../experimental/ErrorCheckerService.java | 17 ++++- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2159156ae..6b8bb497a 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -85,3 +85,8 @@ x Now highlihgting the declaration name, rather than the whole declaration. * On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? *+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. +Suggestion for missing imports +============================== +1. In compileCheck() in ECS, check if error message is of the type "__" cannot be resolved to a type. +2. Find the class name via astGen, and suggest import as a popup. + diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 76aa69879..b0d0af25f 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -34,17 +34,20 @@ import javax.swing.JButton; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JTree; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.table.DefaultTableModel; +import javax.swing.text.BadLocationException; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -2751,6 +2754,76 @@ public class ASTGenerator { } return null; } + JFrame frmImportSuggest; + public void suggestImports(final String className){ + if(frmImportSuggest != null) + return; + System.out.println("Looking for class " + className); + RegExpResourceFilter regf = new RegExpResourceFilter( + Pattern.compile(".*"), + Pattern + .compile(className + + ".class", + Pattern.CASE_INSENSITIVE)); + String[] resources = classPath + .findResources("", regf); + if(resources.length == 0){ + System.out.println("Couldn't find import for class " + className); + return; + } + for (int i = 0; i < resources.length; i++) { + resources[i] = resources[i].replace('/', '.') + .substring(0, resources[i].length() - 6); + } + if(resources.length == 1){ + System.out.println("Found import: " + resources[0]); + String impS = resources[0].substring(0, resources[0] + .length() - 6); + String impString = "import " + impS.replace('/','.') + ";\n"; + try { + editor.textArea().getDocument().insertString(0, impString, null); + } catch (BadLocationException e) { + System.out.println("Failed to insert import for " + className); + e.printStackTrace(); + } + } + else if(resources.length > 1){ + final JList classList = new JList(resources); + classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + frmImportSuggest = new JFrame(); + frmImportSuggest.setBounds(300, 300, 400, 300); + frmImportSuggest.setLayout(new BoxLayout(frmImportSuggest.getContentPane(), BoxLayout.Y_AXIS)); + JLabel lbl = new JLabel( + "The class \"" + + className + + "\" couldn't be found.
    Choose the import you want."); + JScrollPane jsp = new JScrollPane(); + jsp.setViewportView(classList); + JButton btnInsertImport = new JButton("Insert import"); + btnInsertImport.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + if(classList.getSelectedValue() != null){ + try { + String impString = "import " + classList.getSelectedValue() + ";\n"; + editor.textArea().getDocument().insertString(0, impString, null); + frmImportSuggest.setVisible(false); + frmImportSuggest = null; + } catch (BadLocationException e) { + System.out.println("Failed to insert import for " + className); + e.printStackTrace(); + } + } + } + }); + + frmImportSuggest.add(lbl); + frmImportSuggest.add(jsp); + frmImportSuggest.add(btnInsertImport); + frmImportSuggest.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmImportSuggest.setVisible(true); + } + + } public static boolean isAddableASTNode(ASTNode node) { switch (node.getNodeType()) { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index b1b04576f..3c082d1ca 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -250,16 +250,31 @@ public class ErrorCheckerService implements Runnable{ updatePaintedThingys(); updateEditorStatus(); + if (pauseThread) continue; if(textModified.get() == 0) continue; // Check every x seconds checkCode(); - + checkForMissingImports(); } } + private void checkForMissingImports() { + for (Problem p : problemsList) { + if(p.getMessage().endsWith(" cannot be resolved to a type"));{ + int idx = p.getMessage().indexOf(" cannot be resolved to a type"); + if(idx > 1){ + String missingClass = p.getMessage().substring(0, idx); + System.out.println("Will suggest for type:" + missingClass); + astGenerator.suggestImports(missingClass); + runManualErrorCheck(); + } + } + } + } + protected ASTGenerator astGenerator; private AtomicInteger textModified = new AtomicInteger(); From 8c06d26e0e8373b8174b444793738bcd7e3c7137 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 22:15:01 +0530 Subject: [PATCH 124/608] improving import suggestion window --- .../mode/experimental/ASTGenerator.java | 54 ++++++++++--------- .../experimental/ErrorCheckerService.java | 3 +- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b0d0af25f..dc3f7c3b6 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -31,6 +31,7 @@ import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultListModel; import javax.swing.JButton; +import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; @@ -2757,6 +2758,7 @@ public class ASTGenerator { JFrame frmImportSuggest; public void suggestImports(final String className){ if(frmImportSuggest != null) + if(frmImportSuggest.isVisible()) return; System.out.println("Looking for class " + className); RegExpResourceFilter regf = new RegExpResourceFilter( @@ -2775,37 +2777,41 @@ public class ASTGenerator { resources[i] = resources[i].replace('/', '.') .substring(0, resources[i].length() - 6); } - if(resources.length == 1){ - System.out.println("Found import: " + resources[0]); - String impS = resources[0].substring(0, resources[0] - .length() - 6); - String impString = "import " + impS.replace('/','.') + ";\n"; - try { - editor.textArea().getDocument().insertString(0, impString, null); - } catch (BadLocationException e) { - System.out.println("Failed to insert import for " + className); - e.printStackTrace(); - } - } - else if(resources.length > 1){ +// if(resources.length == 1){ +// System.out.println("Found import: " + resources[0]); +// String impS = resources[0].substring(0, resources[0] +// .length() - 6); +// String impString = "import " + impS.replace('/','.') + ";\n"; +// try { +// editor.textArea().getDocument().insertString(0, impString, null); +// errorCheckerService.runManualErrorCheck(); +// } catch (BadLocationException e) { +// System.out.println("Failed to insert import for " + className); +// e.printStackTrace(); +// } +// } else + if (resources.length >= 1) { final JList classList = new JList(resources); - classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); frmImportSuggest = new JFrame(); frmImportSuggest.setBounds(300, 300, 400, 300); - frmImportSuggest.setLayout(new BoxLayout(frmImportSuggest.getContentPane(), BoxLayout.Y_AXIS)); - JLabel lbl = new JLabel( - "The class \"" - + className - + "\" couldn't be found.
    Choose the import you want."); + frmImportSuggest.setLayout(new BoxLayout(frmImportSuggest + .getContentPane(), BoxLayout.Y_AXIS)); + ((JComponent) frmImportSuggest.getContentPane()).setBorder(BorderFactory + .createEmptyBorder(5, 5, 5, 5)); + JLabel lbl = new JLabel("The class \"" + className + + "\" couldn't be determined, choose the import you need from the following list."); JScrollPane jsp = new JScrollPane(); jsp.setViewportView(classList); JButton btnInsertImport = new JButton("Insert import"); btnInsertImport.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - if(classList.getSelectedValue() != null){ + if (classList.getSelectedValue() != null) { try { - String impString = "import " + classList.getSelectedValue() + ";\n"; + String impString = "import " + classList.getSelectedValue() + + ";\n"; editor.textArea().getDocument().insertString(0, impString, null); + errorCheckerService.runManualErrorCheck(); frmImportSuggest.setVisible(false); frmImportSuggest = null; } catch (BadLocationException e) { @@ -2815,14 +2821,14 @@ public class ASTGenerator { } } }); - + frmImportSuggest.add(lbl); frmImportSuggest.add(jsp); frmImportSuggest.add(btnInsertImport); - frmImportSuggest.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmImportSuggest.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frmImportSuggest.setVisible(true); } - + } public static boolean isAddableASTNode(ASTNode node) { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 3c082d1ca..2827f98b6 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -267,9 +267,8 @@ public class ErrorCheckerService implements Runnable{ int idx = p.getMessage().indexOf(" cannot be resolved to a type"); if(idx > 1){ String missingClass = p.getMessage().substring(0, idx); - System.out.println("Will suggest for type:" + missingClass); + //System.out.println("Will suggest for type:" + missingClass); astGenerator.suggestImports(missingClass); - runManualErrorCheck(); } } } From 54fc25e314c5bd465eb76ac6d4536d952f5bd208 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 23:23:04 +0530 Subject: [PATCH 125/608] TIL rt.jar doesn't exist in Java for OS X --- .../mode/experimental/ASTGenerator.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index dc3f7c3b6..f0f838402 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -308,9 +308,17 @@ public class ASTGenerator { StringBuffer tehPath = new StringBuffer(System .getProperty("java.class.path")); + if(Base.isMacOS()){ + // rt.jar equivalent on OS X is JAVA_HOME/bundle/Classes/classes.jar + tehPath.append(File.pathSeparatorChar + + System.getProperty("java.home") + File.separator + "bundle" + + File.separator + "Classes" + File.separator + "classes.jar" + + File.pathSeparatorChar); + }else{ tehPath.append(File.pathSeparatorChar - + System.getProperty("java.home") + "/lib/rt.jar" - + File.pathSeparatorChar); + + System.getProperty("java.home") + File.separator + "lib" + + File.separator + "rt.jar" + File.pathSeparatorChar); + } if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { //System.out.println(jarPath.getPath()); @@ -338,6 +346,18 @@ public class ASTGenerator { System.out.println("-> " + className); } System.out.println("jars loaded."); + if (Base.isMacOS()) { + File f = new File(System.getProperty("java.home") + File.separator + "bundle" + + File.separator + "Classes" + File.separator + "classes.jar"); + System.out.println(f.getAbsolutePath() + " | classes.jar found?" + + f.exists()); + } else { + File f = new File(System.getProperty("java.home") + File.separator + + "lib" + File.separator + "rt.jar" + File.separator); + System.out.println(f.getAbsolutePath() + " | rt.jar found?" + + f.exists()); + } + } catch (Exception e) { e.printStackTrace(); } From db69ba25a947975e804750bfe474c569443b8403 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 23:40:10 +0530 Subject: [PATCH 126/608] findClass bugfix --- pdex/src/processing/mode/experimental/ASTGenerator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index f0f838402..5123c6d49 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1189,8 +1189,9 @@ public class ASTGenerator { temp = temp.substring(0, temp.length() - 1) + className; } else { int x = temp.lastIndexOf('.'); - if (temp.substring(x).equals(className)) { - // Well, we've found the class. + //System.out.println("fclife " + temp.substring(x + 1)); + if (!temp.substring(x + 1).equals(className)) { + continue; } } tehClass = loadClass(temp); From 78fee12dd6e687a34d5a19ad30ffd22de5b72a37 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 14 Jul 2013 23:57:41 +0530 Subject: [PATCH 127/608] minor fixes --- .../mode/experimental/ASTGenerator.java | 18 ++++-------------- .../mode/experimental/TextAreaPainter.java | 6 ++++-- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 5123c6d49..9a7bfc28f 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -2798,20 +2798,7 @@ public class ASTGenerator { resources[i] = resources[i].replace('/', '.') .substring(0, resources[i].length() - 6); } -// if(resources.length == 1){ -// System.out.println("Found import: " + resources[0]); -// String impS = resources[0].substring(0, resources[0] -// .length() - 6); -// String impString = "import " + impS.replace('/','.') + ";\n"; -// try { -// editor.textArea().getDocument().insertString(0, impString, null); -// errorCheckerService.runManualErrorCheck(); -// } catch (BadLocationException e) { -// System.out.println("Failed to insert import for " + className); -// e.printStackTrace(); -// } -// } else - if (resources.length >= 1) { + if (resources.length >= 1) { final JList classList = new JList(resources); classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); frmImportSuggest = new JFrame(); @@ -2831,7 +2818,10 @@ public class ASTGenerator { try { String impString = "import " + classList.getSelectedValue() + ";\n"; + int ct = editor.getSketch().getCurrentCodeIndex(), coff = editor.textArea().getCaretPosition(); + editor.getSketch().setCurrentCode(0); editor.textArea().getDocument().insertString(0, impString, null); + editor.getSketch().setCurrentCode(ct); errorCheckerService.runManualErrorCheck(); frmImportSuggest.setVisible(false); frmImportSuggest = null; diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 2a1599c56..6a06e4d9b 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -75,8 +75,10 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { // System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); - if (evt.isControlDown() || evt.isMetaDown()) - handleCtrlClick(evt); + if (evt.getButton() == MouseEvent.BUTTON1) { + if (evt.isControlDown() || evt.isMetaDown()) + handleCtrlClick(evt); + } } }); From e928a0f37ce23a098a4ed05047fe0526c2dd1abf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 15 Jul 2013 00:16:16 +0530 Subject: [PATCH 128/608] todo updates --- pdex/Todo, GSoC 2013.txt | 6 +++++- pdex/src/processing/mode/experimental/ASTGenerator.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 6b8bb497a..3ef1036bd 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -28,8 +28,10 @@ x Differentiating between multiple statements on the same line. How to? Done wit * - Add a static debug field, disable debugging info on console. * - update build.xml to produce dists * - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc +* - Parameterized type support is broken. Finer details + x! - Ignore String case while finding completion candidates x - Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! @@ -89,4 +91,6 @@ Suggestion for missing imports ============================== 1. In compileCheck() in ECS, check if error message is of the type "__" cannot be resolved to a type. 2. Find the class name via astGen, and suggest import as a popup. - +x Barebones functionality done. +* Find a more subtle way to suggest for imports. The current method is too troublesome. +x Add imports only to beginning of first tab. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9a7bfc28f..7183f6755 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -2818,7 +2818,7 @@ public class ASTGenerator { try { String impString = "import " + classList.getSelectedValue() + ";\n"; - int ct = editor.getSketch().getCurrentCodeIndex(), coff = editor.textArea().getCaretPosition(); + int ct = editor.getSketch().getCurrentCodeIndex(); editor.getSketch().setCurrentCode(0); editor.textArea().getDocument().insertString(0, impString, null); editor.getSketch().setCurrentCode(ct); From 588303e7f0a706cea1df237f1b033bd2dd8bcd06 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 15 Jul 2013 01:51:56 +0530 Subject: [PATCH 129/608] support for few more types and also completion for array access --- pdex/Todo, GSoC 2013.txt | 4 +- .../mode/experimental/ASTGenerator.java | 44 ++++++++++++++++--- .../mode/experimental/TextArea.java | 19 ++++++-- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 3ef1036bd..dc1461ecd 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -28,7 +28,9 @@ x Differentiating between multiple statements on the same line. How to? Done wit * - Add a static debug field, disable debugging info on console. * - update build.xml to produce dists * - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc -* - Parameterized type support is broken. +x - Parameterized type support is broken. +x - Array types, all all other types support broken. :\ +x - Completion for array access, strings[0]. Finer details diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 7183f6755..e4dd06482 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -56,6 +56,8 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ArrayAccess; +import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; @@ -66,6 +68,7 @@ import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NodeFinder; +import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; @@ -247,9 +250,9 @@ public class ASTGenerator { return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if (!frame2.isVisible()) { + frame2.setVisible(true); + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -676,6 +679,9 @@ public class ASTGenerator { } } + case ASTNode.ARRAY_ACCESS: + ArrayAccess arac = (ArrayAccess)astNode; + return resolveExpression3rdParty(nearestNode, arac.getArray(), noCompare); default: System.out.println("Unaccounted type " + getNodeAsString(astNode)); break; @@ -700,6 +706,8 @@ public class ASTGenerator { return ((QualifiedName) expression).getName(); }else if (expression instanceof MethodInvocation) { return ((MethodInvocation) expression).getName(); + }else if(expression instanceof ArrayAccess){ + return ((ArrayAccess)expression).getArray(); } System.out.println(" getChildExpression returning NULL for " + getNodeAsString(expression)); @@ -716,6 +724,8 @@ public class ASTGenerator { return ((QualifiedName) expression).getQualifier(); } else if (expression instanceof MethodInvocation) { return ((MethodInvocation) expression).getExpression(); + }else if(expression instanceof ArrayAccess){ + return ((ArrayAccess)expression).getArray(); } System.out.println("getParentExpression returning NULL for " + getNodeAsString(expression)); @@ -2652,11 +2662,31 @@ public class ASTGenerator { * @return */ public static SimpleType extracTypeInfo(ASTNode node) { - if (node == null) + if (node == null) { return null; - Type t = extracTypeInfo2(node); - if (t instanceof PrimitiveType) - return null; + } + Type t = extracTypeInfo2(node); + if (t instanceof PrimitiveType) { + return null; + } else if (t instanceof ArrayType) { + ArrayType at = (ArrayType) t; + System.out.println(at.getComponentType() + " <-comp type, ele type-> " + + at.getElementType() + ", " + + at.getElementType().getClass().getName()); + if (at.getElementType() instanceof PrimitiveType) { + return null; + } else if (at.getElementType() instanceof SimpleType) { + return (SimpleType) at.getElementType(); + } else + return null; + } else if (t instanceof ParameterizedType) { + ParameterizedType pmt = (ParameterizedType) t; + System.out.println(pmt.getType() + ", " + pmt.getType().getClass()); + if (pmt.getType() instanceof SimpleType) { + return (SimpleType) pmt.getType(); + } else + return null; + } return (SimpleType) t; } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index e87827154..58ebf5311 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -251,7 +251,7 @@ public class TextArea extends JEditTextArea { private String fetchPhrase(KeyEvent evt) { char keyChar = evt.getKeyChar(); if (keyChar == KeyEvent.VK_ENTER) { - System.out.println("Enter consumed."); + //System.out.println("Enter keypress."); return null; } // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) @@ -306,7 +306,7 @@ public class TextArea extends JEditTextArea { if (x1 >= 0) { // if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' - || s.charAt(x1) == '.' || s.charAt(x1) == ')') { + || s.charAt(x1) == '.' || s.charAt(x1) == ')' || s.charAt(x1) == ']') { if (s.charAt(x1) == ')') { word = s.charAt(x1--) + word; @@ -319,7 +319,20 @@ public class TextArea extends JEditTextArea { closeB++; x1--; } - } else { + } + else if (s.charAt(x1) == ']') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '[') + closeB--; + if (s.charAt(x1) == ']') + closeB++; + x1--; + } + } + else { word = s.charAt(x1--) + word; } } else { From 2f36493da15b1a314d5ca1bbb5c196ed719b17be Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 16 Jul 2013 00:52:14 +0530 Subject: [PATCH 130/608] p5 icon in jframes --- .../processing/mode/experimental/ASTGenerator.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index e4dd06482..bd0ebd33c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -83,6 +83,7 @@ import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import processing.app.Base; import processing.app.SketchCode; +import processing.app.Toolkit; import processing.mode.java.preproc.PdePreprocessor; import com.google.classpath.ClassPath; @@ -160,6 +161,7 @@ public class ASTGenerator { frmRename.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frmRename.setBounds(new Rectangle(680, 50, 250, 130)); frmRename.setLayout(new BoxLayout(frmRename.getContentPane(), BoxLayout.Y_AXIS)); + Toolkit.setIcon(frmRename); JPanel panelTop = new JPanel(), panelBottom = new JPanel(); panelTop.setLayout(new BoxLayout(panelTop, BoxLayout.Y_AXIS)); panelTop.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); @@ -186,7 +188,7 @@ public class ASTGenerator { frmOccurenceList = new JFrame(); frmOccurenceList.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frmOccurenceList.setBounds(new Rectangle(1100, 50, 350, 500)); - + Toolkit.setIcon(frmOccurenceList); JScrollPane sp2 = new JScrollPane(); treeRename = new JTree(); sp2.setViewportView(treeRename); @@ -196,6 +198,7 @@ public class ASTGenerator { frameAutoComp = new JFrame(); frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); + Toolkit.setIcon(frameAutoComp); tableAuto = new JTable(); JScrollPane sp3 = new JScrollPane(); sp3.setViewportView(tableAuto); @@ -250,9 +253,9 @@ public class ASTGenerator { return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) { - frame2.setVisible(true); - } +// if (!frame2.isVisible()) { +// frame2.setVisible(true); +// } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); From f5b792e9df3c557c87189232e6730044152e7a39 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 18 Jul 2013 12:17:11 +0530 Subject: [PATCH 131/608] ignoring unnecessary imports, fixes #6 --- .../mode/experimental/ASTGenerator.java | 42 ++++++++++++++----- .../experimental/ErrorCheckerService.java | 1 + 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index bd0ebd33c..90de29374 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -17,6 +17,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -198,7 +199,7 @@ public class ASTGenerator { frameAutoComp = new JFrame(); frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); - Toolkit.setIcon(frameAutoComp); + Toolkit.setIcon(frameAutoComp); tableAuto = new JTable(); JScrollPane sp3 = new JScrollPane(); sp3.setViewportView(tableAuto); @@ -344,14 +345,14 @@ public class ASTGenerator { // for (String packageName : classPath.listPackages("")) { // System.out.println(packageName); // } - RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( - ".*", - "ArrayList.class"); - String[] resources = classPath.findResources("", regExpResourceFilter); - for (String className : resources) { - System.out.println("-> " + className); - } - System.out.println("jars loaded."); +// RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( +// ".*", +// "ArrayList.class"); +// String[] resources = classPath.findResources("", regExpResourceFilter); +// for (String className : resources) { +// System.out.println("-> " + className); +// } + System.out.println("Sketch classpath jars loaded."); if (Base.isMacOS()) { File f = new File(System.getProperty("java.home") + File.separator + "bundle" + File.separator + "Classes" + File.separator + "classes.jar"); @@ -864,7 +865,9 @@ public class ASTGenerator { for (String matchedClass2 : resources) { matchedClass2 = matchedClass2.replace('/', '.'); String matchedClass = matchedClass2.substring(0, matchedClass2 - .length() - 6); + .length() - 6); + if(ignorableImport(matchedClass2)) + continue; int d = matchedClass.lastIndexOf('.'); matchedClass = matchedClass.substring(d + 1); candidates @@ -1632,7 +1635,7 @@ public class ASTGenerator { * @param node * @return */ - private static int getLineNumber(ASTNode node) { + public static int getLineNumber(ASTNode node) { return ((CompilationUnit) node.getRoot()).getLineNumber(node .getStartPosition()); } @@ -2875,6 +2878,23 @@ public class ASTGenerator { } + public static final String ignoredImports[] = { + "com.oracle.", "sun.", "sunw.", "com.sun.", "javax.", "sunw.", "org.ietf.", + "org.jcp.", "org.omg.", "org.w3c.", "org.xml.", "org.eclipse.", "com.ibm.", + "org.netbeans.", "org.jsoup.", "org.junit.", "org.apache.", "antlr." }; + private boolean ignorableImport(String impName) { + //TODO: Trie man. + for (ImportStatement impS : errorCheckerService.getProgramImports()) { + if(impName.startsWith(impS.getPackageName())) + return false; + } + for (String impS : ignoredImports) { + if(impName.startsWith(impS)) + return true; + } + return false; + } + public static boolean isAddableASTNode(ASTNode node) { switch (node.getNodeType()) { // case ASTNode.STRING_LITERAL: diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 2827f98b6..7c4e04a93 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -352,6 +352,7 @@ public class ErrorCheckerService implements Runnable{ JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); parser.setCompilerOptions(options); cu = (CompilationUnit) parser.createAST(null); From 8a2a64bf6c363dbe6769468e624731cada122d0c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 00:45:06 +0530 Subject: [PATCH 132/608] completion caching for efficiency --- pdex/Todo, GSoC 2013.txt | 3 + .../mode/experimental/ASTGenerator.java | 113 ++++++++++++------ .../experimental/CompletionCandidate.java | 6 +- .../mode/experimental/TextArea.java | 4 +- 4 files changed, 83 insertions(+), 43 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index dc1461ecd..aff776f5e 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -25,6 +25,8 @@ x! Library CC for nested would be tricky. Need to jump from local->compiled code x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x Differentiating between multiple statements on the same line. How to? Done with offset handling. +x - Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. +* - Disable completions on comment line * - Add a static debug field, disable debugging info on console. * - update build.xml to produce dists * - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc @@ -42,6 +44,7 @@ x Cursor positioning should be after the first ( if arguments present, else afte x Display the type of Completion(method return type, variable type) in the popup. - facing some issues for local types. Fixed. x Sorted list of completion candidates - fields, then methods. It's unsorted presently. +* - Show declaring class for completions *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * - Diamond operator isn't supported for now. Bummer. x Reflection API - getMethods vs getDeclaredMethods. declared. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 90de29374..b271bf074 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -720,23 +720,41 @@ public class ASTGenerator { public static ASTNode getParentExpression(ASTNode expression) { // ASTNode anode = null; - if (expression instanceof SimpleName) { - return expression; - } else if (expression instanceof FieldAccess) { - return ((FieldAccess) expression).getExpression(); - } else if (expression instanceof QualifiedName) { - return ((QualifiedName) expression).getQualifier(); - } else if (expression instanceof MethodInvocation) { - return ((MethodInvocation) expression).getExpression(); - }else if(expression instanceof ArrayAccess){ - return ((ArrayAccess)expression).getArray(); + if (expression instanceof SimpleName) { + return expression; + } else if (expression instanceof FieldAccess) { + return ((FieldAccess) expression).getExpression(); + } else if (expression instanceof QualifiedName) { + return ((QualifiedName) expression).getQualifier(); + } else if (expression instanceof MethodInvocation) { + return ((MethodInvocation) expression).getExpression(); + } else if (expression instanceof ArrayAccess) { + return ((ArrayAccess) expression).getArray(); + } + System.out.println("getParentExpression returning NULL for " + + getNodeAsString(expression)); + return null; } - System.out.println("getParentExpression returning NULL for " - + getNodeAsString(expression)); - return null; -} - public void updatePredictions(final String word, final int line, final int lineStartNonWSOffset) { + private void trimCandidates(String newWord){ + ArrayList newCandidate = new ArrayList(); + newWord = newWord.toLowerCase(); + for (CompletionCandidate comp : candidates) { + if(comp.toString().toLowerCase().startsWith(newWord)){ + System.out.println("Adding " + comp); + newCandidate.add(comp); + } + } + candidates = newCandidate; + } + + /** + * List of CompletionCandidates + */ + private ArrayList candidates; + private String lastPredictedWord = " "; + + public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { SwingWorker worker = new SwingWorker() { @Override @@ -756,6 +774,23 @@ public class ASTGenerator { noCompare = true; } + if (word2.length() > 2 && !noCompare + && word2.length() > lastPredictedWord.length()) { + if (word2.startsWith(lastPredictedWord)) { + System.out.println(word + " starts with " + lastPredictedWord); + System.out.println("Don't recalc"); + if (word2.contains(".")) { + int x = word2.lastIndexOf('.'); + trimCandidates(word2.substring(x + 1)); + } else { + trimCandidates(word2); + } + updatePredictions(word); + lastPredictedWord = word2; + return; + } + } + int lineNumber = line; // Adjust line number for tabbed sketches if (errorCheckerService != null) { @@ -788,8 +823,8 @@ public class ASTGenerator { System.err.println(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(nearestNode)); - ArrayList candidates = new ArrayList(); - + candidates = new ArrayList(); + lastPredictedWord = word2; // Determine the expression typed if (testnode instanceof SimpleName && !noCompare) { @@ -1019,35 +1054,35 @@ public class ASTGenerator { }*/ } + updatePredictions(word); - - Collections.sort(candidates); - CompletionCandidate[][] candi = new CompletionCandidate[candidates - .size()][1]; - - DefaultListModel defListModel = new DefaultListModel(); - - for (int i = 0; i < candi.length; i++) { - candi[i][0] = candidates.get(i); - defListModel.addElement(candidates.get(i)); - } - System.out.println("K = " + candidates.size()); - DefaultTableModel tm = new DefaultTableModel( - candi, - new String[] { "Suggestions" }); - if(tableAuto.isVisible()){ - tableAuto.setModel(tm); - tableAuto.validate(); - tableAuto.repaint(); - } - errorCheckerService.getEditor().textArea() - .showSuggestion(defListModel,word); } }; worker.execute(); } + + private void updatePredictions(final String word) { + Collections.sort(candidates); + CompletionCandidate[][] candi = new CompletionCandidate[candidates.size()][1]; + DefaultListModel defListModel = new DefaultListModel(); + + for (int i = 0; i < candi.length; i++) { + candi[i][0] = candidates.get(i); + defListModel.addElement(candidates.get(i)); + } + System.out.println("Total preds = " + candidates.size()); + DefaultTableModel tm = new DefaultTableModel(candi, + new String[] { "Suggestions" }); + if (tableAuto.isVisible()) { + tableAuto.setModel(tm); + tableAuto.validate(); + tableAuto.repaint(); + } + errorCheckerService.getEditor().textArea() + .showSuggestion(defListModel, word); + } /** * Loads classes from .jar files in sketch classpath diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index f6bf99633..b8c69aa3c 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -41,7 +41,8 @@ public class CompletionCandidate implements Comparable{ cstr.append(' '); } label.append(")"); - label.append(" : "+method.getReturnType().getSimpleName()); + label.append(" : " + method.getReturnType().getSimpleName() + " - " + + method.getDeclaringClass().getSimpleName()); cstr.append(")"); this.label = label.toString(); this.completionString = cstr.toString(); @@ -98,7 +99,8 @@ public class CompletionCandidate implements Comparable{ f.getDeclaringClass().getName(); elementName = f.getName(); type = PREDEF_FIELD; - label = f.getName() + " : " + f.getType().getSimpleName(); + label = f.getName() + " : " + f.getType().getSimpleName() + + f.getDeclaringClass().getSimpleName(); completionString = elementName; } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 58ebf5311..bbacebc1d 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -289,7 +289,7 @@ public class TextArea extends JEditTextArea { word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); - errorCheckerService.astGenerator.updatePredictions(word, line + errorCheckerService.astGenerator.preparePredictions(word, line + errorCheckerService.mainClassOffset,0); return word; } @@ -367,7 +367,7 @@ public class TextArea extends JEditTextArea { // if (word.endsWith(".")) // word = word.substring(0, word.length() - 1); int lineStartNonWSOffset = 0; - errorCheckerService.astGenerator.updatePredictions(word, line + errorCheckerService.astGenerator.preparePredictions(word, line + errorCheckerService.mainClassOffset,lineStartNonWSOffset); //showSuggestionLater(); return word; From 7ceb04b003ea11c98631cfa22fa43a1295947c37 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 00:49:36 +0530 Subject: [PATCH 133/608] bye bye defunct code --- pdex/Todo, GSoC 2013.txt | 11 +- .../mode/experimental/ASTGenerator.java | 113 +----------------- 2 files changed, 8 insertions(+), 116 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index aff776f5e..90d0f1a1c 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -36,20 +36,21 @@ x - Completion for array access, strings[0]. Finer details +* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? +* - Show declaring class for completions +*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. +* - Diamond operator isn't supported for now. Bummer. +* - Icons for completions? Or overkill right now? x! - Ignore String case while finding completion candidates x - Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! -* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? x Cursor positioning should be after the first ( if arguments present, else after () x Display the type of Completion(method return type, variable type) in the popup. - facing some issues for local types. Fixed. x Sorted list of completion candidates - fields, then methods. It's unsorted presently. -* - Show declaring class for completions -*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. -* - Diamond operator isn't supported for now. Bummer. x Reflection API - getMethods vs getDeclaredMethods. declared. x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement -* - Icons for completions? Or overkill right now? + Completion List x Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b271bf074..79975f006 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -944,123 +944,14 @@ public class ASTGenerator { { System.out.println("ChildExpr is null"); } - /*ASTNode det = resolveExpression(nearestNode, testnode,noCompare); - // Find the parent of the expression - // in a().b, this would give me the return type of a(), so that we can - // find all children of a() begininng with b - System.err.println("DET " + getNodeAsString(det)); - if (det != null) { - TypeDeclaration td = null; - SimpleType stp = extracTypeInfo(det); - if (det instanceof MethodDeclaration) { - if (((MethodDeclaration) det).getReturnType2() instanceof SimpleType) { - stp = (SimpleType) (((MethodDeclaration) det).getReturnType2()); - td = (TypeDeclaration) findDeclaration(stp.getName()); - } - } else if (det instanceof FieldDeclaration) { - if (((FieldDeclaration) det).getType() instanceof SimpleType) { - stp = (SimpleType) (((FieldDeclaration) det).getType()); - td = (TypeDeclaration) findDeclaration(stp.getName()); - } - } else if (det instanceof VariableDeclarationStatement) { - stp = (SimpleType) (((VariableDeclarationStatement) det) - .getType()); - td = (TypeDeclaration) findDeclaration(stp.getName()); - } - System.out.println("ST is " + stp.getName()); - // Now td contains the type returned by a() - System.err.println(getNodeAsString(det) + " defined in " - + getNodeAsString(td)); - ASTNode child = resolveChildExpression(testnode); - if (td != null) { - - System.out.println("Completion candidate: " - + getNodeAsString(child)); - for (int i = 0; i < td.getFields().length; i++) { - List vdfs = td.getFields()[i] - .fragments(); - for (VariableDeclarationFragment vdf : vdfs) { - if (noCompare) { - candidates - .add(new CompletionCandidate(getNodeAsString2(vdf))); - } else if (vdf.getName().toString() - .startsWith(child.toString())) - candidates - .add(new CompletionCandidate(getNodeAsString2(vdf))); - } - - } - for (int i = 0; i < td.getMethods().length; i++) { - if (noCompare) { - candidates - .add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString(), "", - CompletionCandidate.METHOD)); - } else if (td.getMethods()[i].getName().toString() - .startsWith(child.toString())) - candidates - .add(new CompletionCandidate(getNodeAsString2(td - .getMethods()[i]), td.getName().toString(), "", - CompletionCandidate.METHOD)); - } - } else { - if (stp != null) { - candidates = getMembersForType(stp.getName().toString(), - child.toString(), noCompare, - false); - } - } - - } else if (word.length() - word2.length() == 1) { - System.out.println(word + " w2 " + word2); -// int dC = 0; -// for (int i = 0; i < word.length(); i++) { -// if(word.charAt(i) == '.') -// dC++; -// } -// if(dC == 1 && word.charAt(word.length() - 1) == '.'){ - System.out.println("All members of " + word2); - candidates = getMembersForType(word2, "", true, true); -// } - } else { - System.out.println("Some members of " + word2); - int x = word2.indexOf('.'); - if (x != -1) { - candidates = getMembersForType(word2.substring(0, x), - word2.substring(x + 1), false, - true); - } - } - if(candidates.size() == 0){ - System.out.println("candidates empty"); - String childExpr = resolveChildExpression(testnode) - .toString(); - System.out.println("Parent expression : " + resolveParentExpression(testnode)); - System.out.println("Child expression : " + childExpr); - - if(!noCompare){ - System.out.println("Original testnode " + getNodeAsString(testnode)); - testnode = resolveParentExpression(testnode); - System.out.println("Corrected testnode " + getNodeAsString(testnode)); - } - ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); - if(expr == null){ - System.out.println("Expr is null"); - }else { - System.out.println("Expr is " + expr.toString()); - candidates = getMembersForType(expr, - childExpr, noCompare, false); - } - }*/ } - updatePredictions(word); - + updatePredictions(word); + } }; worker.execute(); - } private void updatePredictions(final String word) { From 9f51e7c2481041a19e886d5eb0f7803b24682298 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 00:58:09 +0530 Subject: [PATCH 134/608] cleaning up todo --- pdex/Todo, GSoC 2013.txt | 57 ++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 90d0f1a1c..0f66b343b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -8,7 +8,18 @@ Manindra Moharana (me@mkmoharana.com) Code Completion ============== + The big stuff: + +*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. + - Making very good progress here. The elegance of recurion - Hats off! + - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step + - Looks almost complete now, nearly all cases covered(July 13th) +* Scope handling? Static/non static scope? +* - Disable completions on comment line +* - Add a static debug field, disable debugging info on console. +* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. + x! Code competition for local code is working with recursive look up. x Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed x Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. @@ -17,19 +28,9 @@ x! Code completion with library code, non-nested seems to be broken, fix it. Fix x Completion for external classes - ArrayList, HashMap, etc. x! Recursive lookup for compiled(library) code! x! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. -*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two. - - Making very good progress here. The elegance of recurion - Hats off! - - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - - Looks almost complete now, nearly all cases covered(July 13th) -* Scope handling? Static/non static scope? -x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. -* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. +x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. x Differentiating between multiple statements on the same line. How to? Done with offset handling. x - Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. -* - Disable completions on comment line -* - Add a static debug field, disable debugging info on console. -* - update build.xml to produce dists -* - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc x - Parameterized type support is broken. x - Array types, all all other types support broken. :\ x - Completion for array access, strings[0]. @@ -41,6 +42,7 @@ Finer details *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * - Diamond operator isn't supported for now. Bummer. * - Icons for completions? Or overkill right now? + x! - Ignore String case while finding completion candidates x - Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! @@ -50,24 +52,25 @@ x Display the type of Completion(method return type, variable type) in the popup x Sorted list of completion candidates - fields, then methods. It's unsorted presently. x Reflection API - getMethods vs getDeclaredMethods. declared. x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement - - -Completion List -x Dynamically update the list instead of recreating on every keystroke(new list data, pos, etc.) -x List should get hidden on hitting esc key +x Completion List should get hidden on hitting esc key Offset Mapping ============== + First major hurdle is offset mapping *! pde<->java code offset : precise conversion needed +* W.r.t PDE specific enhancements, things are almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. x This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. x Edge case - multiple statements in a single line x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. -* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. Refactoring =========== + +* Undo misbehaves here, handle carefully. +* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully + Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. 2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. @@ -76,27 +79,35 @@ x Renaming any constructor is equivalent to renaming the TD 3. Find corresponding PDE offsets of the SimpleNames, rename in each line. x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. -* Undo misbehaves here, handle carefully. -* Handle saving. If sketch closed after renaming w/o saving find bugs. x Refactoring ui x For now, user needs to highlight the name of the var, and then right-click -> Rename.. -* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully +x Handle saving. If sketch closed after renaming w/o saving find bugs. Done, marking the sketch as modified after renaming. Quick Navigation ================ + +*+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. + +x On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? x Ctrl + Click on an element to scroll to its definition in code x Local Vars x Local Methods x Local Classes x Recursive lookup, a.b().c() x Now highlihgting the declaration name, rather than the whole declaration. -* On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? -*+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. Suggestion for missing imports ============================== +* Find a more subtle way to suggest for imports. The current method is too troublesome. Randomly pops up offering suggestions. May intimidate beginners. + 1. In compileCheck() in ECS, check if error message is of the type "__" cannot be resolved to a type. 2. Find the class name via astGen, and suggest import as a popup. x Barebones functionality done. -* Find a more subtle way to suggest for imports. The current method is too troublesome. x Add imports only to beginning of first tab. + +General Stuff +============= + +* - Add option for toggling debug output +* - update build.xml to produce dists +* - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc \ No newline at end of file From 2c6c72aa754a45f8bdd69acf6a079f85fd0072ee Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 01:00:04 +0530 Subject: [PATCH 135/608] attention to stupid details, coz formatting matters. --- pdex/Todo, GSoC 2013.txt | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 0f66b343b..0cea39895 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -16,8 +16,8 @@ The big stuff: - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) * Scope handling? Static/non static scope? -* - Disable completions on comment line -* - Add a static debug field, disable debugging info on console. +* Disable completions on comment line +* Add a static debug field, disable debugging info on console. * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x! Code competition for local code is working with recursive look up. @@ -31,20 +31,20 @@ x! Library CC for nested would be tricky. Need to jump from local->compiled code x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. x Differentiating between multiple statements on the same line. How to? Done with offset handling. x - Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. -x - Parameterized type support is broken. -x - Array types, all all other types support broken. :\ -x - Completion for array access, strings[0]. +x Parameterized type support is broken. +x Array types, all all other types support broken. :\ +x Completion for array access, strings[0]. Finer details * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? -* - Show declaring class for completions +* Show declaring class for completions *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. -* - Diamond operator isn't supported for now. Bummer. -* - Icons for completions? Or overkill right now? +* Diamond operator isn't supported for now. Bummer. +* Icons for completions? Or overkill right now? -x! - Ignore String case while finding completion candidates -x - Multiple 3rd party classes found in various packages. Not a chance no more. +x! Ignore String case while finding completion candidates +x Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! x Cursor positioning should be after the first ( if arguments present, else after () x Display the type of Completion(method return type, variable type) in the popup. @@ -98,6 +98,7 @@ x Now highlihgting the declaration name, rather than the whole declaration. Suggestion for missing imports ============================== + * Find a more subtle way to suggest for imports. The current method is too troublesome. Randomly pops up offering suggestions. May intimidate beginners. 1. In compileCheck() in ECS, check if error message is of the type "__" cannot be resolved to a type. @@ -108,6 +109,6 @@ x Add imports only to beginning of first tab. General Stuff ============= -* - Add option for toggling debug output -* - update build.xml to produce dists -* - Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc \ No newline at end of file +* Add option for toggling debug output +* update build.xml to produce dists +* Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc From 252f79a639b4da0de05a14cf458efc00df4caaff Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 01:20:23 +0530 Subject: [PATCH 136/608] organizing stuff a bit more.. --- pdex/Todo, GSoC 2013.txt | 5 +- .../mode/experimental/ASTGenerator.java | 101 +++++++++--------- 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 0cea39895..44353a5ff 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -7,7 +7,7 @@ Manindra Moharana (me@mkmoharana.com) * : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo Code Completion -============== +=============== The big stuff: @@ -16,8 +16,7 @@ The big stuff: - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) * Scope handling? Static/non static scope? -* Disable completions on comment line -* Add a static debug field, disable debugging info on console. +* Disable completions on comment line * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. x! Code competition for local code is working with recursive look up. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 79975f006..4193cced4 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1660,55 +1660,7 @@ public class ASTGenerator { } protected void done() { - - String newName = txtRenameField.getText(); - DefaultMutableTreeNode defCU = findAllOccurrences(); - treeRename.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) treeRename.getModel()).reload(); - frmOccurenceList.setVisible(true); - int lineOffsetDisplacementConst = newName.length() - - editor.ta.getSelectedText().length(); - HashMap lineOffsetDisplacement = new HashMap(); - - // I need to store the pde and java offsets beforehand because once - // the replace starts, all offsets returned are affected - int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; - for (int i = defCU.getChildCount() - 1; i >= 0; i--) { - ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU - .getChildAt(i))).getUserObject(); - offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); - offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); - } - - for (int i = defCU.getChildCount() - 1; i >= 0; i--) { - int pdeoffsets[] = offsetsMap[i][0]; - int javaoffsets[] = offsetsMap[i][1]; - // correction for pde enhancements related displacement on a line - int off = 0; - if (lineOffsetDisplacement.get(javaoffsets[0]) != null) { - off = lineOffsetDisplacement.get(javaoffsets[0]); - - lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst + off); - } else { - lineOffsetDisplacement.put(javaoffsets[0], - lineOffsetDisplacementConst); - } - - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], - pdeoffsets[1], - javaoffsets[1] + off, - javaoffsets[2]); - editor.ta.setSelectedText(newName); - } - for (Integer lineNum : lineOffsetDisplacement.keySet()) { - System.out.println(lineNum + "line, disp" - + lineOffsetDisplacement.get(lineNum)); - } - editor.getSketch().setModified(true); - errorCheckerService.runManualErrorCheck(); - frmOccurenceList.setVisible(false); - frmRename.setVisible(false); + handleRename(); } }; worker.execute(); @@ -1771,6 +1723,57 @@ public class ASTGenerator { }); } + private void handleRename(){ + String newName = txtRenameField.getText(); + DefaultMutableTreeNode defCU = findAllOccurrences(); + treeRename.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) treeRename.getModel()).reload(); + frmOccurenceList.setVisible(true); + int lineOffsetDisplacementConst = newName.length() + - editor.ta.getSelectedText().length(); + HashMap lineOffsetDisplacement = new HashMap(); + + // I need to store the pde and java offsets beforehand because once + // the replace starts, all offsets returned are affected + int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; + for (int i = defCU.getChildCount() - 1; i >= 0; i--) { + ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU + .getChildAt(i))).getUserObject(); + offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); + offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); + } + + for (int i = defCU.getChildCount() - 1; i >= 0; i--) { + int pdeoffsets[] = offsetsMap[i][0]; + int javaoffsets[] = offsetsMap[i][1]; + // correction for pde enhancements related displacement on a line + int off = 0; + if (lineOffsetDisplacement.get(javaoffsets[0]) != null) { + off = lineOffsetDisplacement.get(javaoffsets[0]); + + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst + off); + } else { + lineOffsetDisplacement.put(javaoffsets[0], + lineOffsetDisplacementConst); + } + + ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], + pdeoffsets[1], + javaoffsets[1] + off, + javaoffsets[2]); + editor.ta.setSelectedText(newName); + } + for (Integer lineNum : lineOffsetDisplacement.keySet()) { + System.out.println(lineNum + "line, disp" + + lineOffsetDisplacement.get(lineNum)); + } + editor.getSketch().setModified(true); + errorCheckerService.runManualErrorCheck(); + frmOccurenceList.setVisible(false); + frmRename.setVisible(false); + } + private DefaultMutableTreeNode findAllOccurrences(){ String selText = editor.ta.getSelectedText(); int line = editor.ta.getSelectionStartLine(); From bead77d045a1fe2dd369ed2290de95be23961a5e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 21:08:52 +0530 Subject: [PATCH 137/608] some work for ignoring comments and testing IProblem stuff.. --- .../mode/experimental/ASTGenerator.java | 85 ++++++++++++++++--- .../experimental/ErrorCheckerService.java | 22 ++++- 2 files changed, 92 insertions(+), 15 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 4193cced4..784eb2516 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,7 +1,6 @@ package processing.mode.experimental; import java.awt.Dimension; -import java.awt.GridLayout; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -17,7 +16,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -54,12 +52,14 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ArrayAccess; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.Comment; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ExpressionStatement; @@ -81,6 +81,7 @@ import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; import processing.app.SketchCode; @@ -237,6 +238,7 @@ public class ASTGenerator { } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); + calculateComments(); codeTree = new DefaultMutableTreeNode( getNodeAsString((ASTNode) compilationUnit .types().get(0))); @@ -254,9 +256,9 @@ public class ASTGenerator { return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if (!frame2.isVisible()) { + frame2.setVisible(true); + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -785,7 +787,7 @@ public class ASTGenerator { } else { trimCandidates(word2); } - updatePredictions(word); + showPredictions(word); lastPredictedWord = word2; return; } @@ -935,7 +937,6 @@ public class ASTGenerator { System.out.println("Expr is null"); } else { System.out.println("Expr is " + expr.toString()); - candidates = getMembersForType(expr, childExpr.toString(), noCompare, false); } @@ -946,7 +947,7 @@ public class ASTGenerator { } } - updatePredictions(word); + showPredictions(word); } }; @@ -954,7 +955,7 @@ public class ASTGenerator { worker.execute(); } - private void updatePredictions(final String word) { + private void showPredictions(final String word) { Collections.sort(candidates); CompletionCandidate[][] candi = new CompletionCandidate[candidates.size()][1]; DefaultListModel defListModel = new DefaultListModel(); @@ -1099,7 +1100,6 @@ public class ASTGenerator { } } return candidates; - } /** @@ -1567,7 +1567,19 @@ public class ASTGenerator { } public static void main(String[] args) { - traversal2(); + //traversal2(); + Class probClass = DefaultProblem.class; + Field f[] = probClass.getFields(); + DefaultProblem def = new DefaultProblem(null, null, 0, null, 0, 0, 0, 0, 0); + for (Field field : f) { + if(Modifier.isStatic(field.getModifiers())) + try { + System.out.println(field.getName() + " :" + field.get(null)); + } catch (Exception e) { + e.printStackTrace(); + break; + } + } } public static void traversal2() { @@ -1893,6 +1905,45 @@ public class ASTGenerator { } } + public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ + // Find the first node with this line number, return its offset - jOffset + line = PdeToJavaLineNumber(line); + System.out.println("Looking for line: " + line + ", jOff " + jOffset); + Stack temp = new Stack(); + temp.push(codeTree); + + while (!temp.isEmpty()) { + DefaultMutableTreeNode cnode = (DefaultMutableTreeNode) temp.pop(); + for (int i = 0; i < cnode.getChildCount(); i++) { + temp.push(cnode.getChildAt(i)); + } + + if (!(cnode.getUserObject() instanceof ASTNodeWrapper)) + continue; + ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); +// System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); + if (awnode.getLineNumber() == line) { + System.out.println("First element with this line no is: " + awnode + + "LSO: " + (jOffset - awnode.getNode().getStartPosition())); + return (jOffset - awnode.getNode().getStartPosition()); + } + } + return -1; + } + + private int PdeToJavaLineNumber(int lineNum){ + int lineNumber = lineNum + errorCheckerService.getPdeImportsCount(); + // Adjust line number for tabbed sketches + int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); + if (codeIndex > 0) + for (int i = 0; i < codeIndex; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + lineNumber += len; + } + return lineNumber; + } + private boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ if(node instanceof SimpleName){ SimpleName sn = (SimpleName) node; @@ -2479,6 +2530,18 @@ public class ASTGenerator { return null; } + + private void calculateComments(){ + List commentList = compilationUnit.getCommentList(); + System.out.println("Total comments: " + commentList.size()); +// int i = 0; +// for (Comment comment : commentList) { +// System.out.println(++i + ": "+comment + " Line:" +// + compilationUnit.getLineNumber(comment.getStartPosition()) + ", " +// + comment.getLength()); +// } + } + /** * A wrapper for java.lang.reflect types. * Will have to see if the usage turns out to be internal only here or not diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 7c4e04a93..0bb04cade 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -365,7 +365,11 @@ public class ErrorCheckerService implements Runnable{ int a[] = calculateTabIndexAndLineNumber(problems[i]); Problem p = new Problem(problems[i], a[0], a[1] + 1); //TODO: ^Why do cheeky stuff? - problemsList.add(p); + problemsList.add(p); + System.out.println(problems[i].getMessage()); + for (String j : problems[i].getArguments()) { + System.out.println("arg " + j); + } // System.out.println(p.toString()); } @@ -472,7 +476,10 @@ public class ErrorCheckerService implements Runnable{ // + problems[i].isWarning()); IProblem problem = problems[i]; - + System.out.println(problem.getMessage()); + for (String j : problem.getArguments()) { + System.out.println("arg " + j); + } int a[] = calculateTabIndexAndLineNumber(problem); Problem p = new Problem(problem, a[0], a[1]); if ((Boolean) errorList[i][8]) { @@ -1212,6 +1219,12 @@ public class ErrorCheckerService implements Runnable{ // System.out.println("load..? " + loadCompClass); } + private int pdeImportsCount; + + public int getPdeImportsCount() { + return pdeImportsCount; + } + /** * Removes import statements from tabSource, replaces each with white spaces * and adds the import to the list of program imports @@ -1223,7 +1236,8 @@ public class ErrorCheckerService implements Runnable{ * @return String - Tab code with imports replaced with white spaces */ private String scrapImportStatements(String tabProgram, int tabNumber) { - //TODO: Commented out imports are still detected as main imports. + //TODO: Commented out imports are still detected as main imports. + pdeImportsCount = 0; String tabSource = new String(tabProgram); do { // System.out.println("-->\n" + sourceAlt + "\n<--"); @@ -1255,7 +1269,7 @@ public class ErrorCheckerService implements Runnable{ } tabSource = tabSource.substring(0, idx) + whiteSpace + tabSource.substring(idx + len); - + pdeImportsCount++; } while (true); // System.out.println(tabSource); return tabSource; From e5fc86807204eb7b6e8bd6992aa07887b1891403 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 21:47:07 +0530 Subject: [PATCH 138/608] now displaying IProblem constant names, it's a temporary thing ya know. --- .../processing/mode/experimental/ASTGenerator.java | 12 ------------ .../mode/experimental/ErrorCheckerService.java | 13 ++++++++++--- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 784eb2516..caba60172 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1568,18 +1568,6 @@ public class ASTGenerator { public static void main(String[] args) { //traversal2(); - Class probClass = DefaultProblem.class; - Field f[] = probClass.getFields(); - DefaultProblem def = new DefaultProblem(null, null, 0, null, 0, 0, 0, 0, 0); - for (Field field : f) { - if(Modifier.isStatic(field.getModifiers())) - try { - System.out.println(field.getName() + " :" + field.get(null)); - } catch (Exception e) { - e.printStackTrace(); - break; - } - } } public static void traversal2() { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 0bb04cade..1508412ba 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -176,6 +176,8 @@ public class ErrorCheckerService implements Runnable{ + "(void|int|float|double|String|char|byte)" + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(", Pattern.MULTILINE); + private ErrorMessageSimplifier errorMsgSimplifier; + public ErrorCheckerService(DebugEditor debugEditor) { this.editor = debugEditor; initParser(); @@ -186,6 +188,7 @@ public class ErrorCheckerService implements Runnable{ pdePrepoc.getDefaultImports().length + 1; astGenerator = new ASTGenerator(this); syntaxErrors = true; + errorMsgSimplifier = new ErrorMessageSimplifier(); } /** @@ -692,7 +695,8 @@ public class ErrorCheckerService implements Runnable{ try { String[][] errorData = new String[problemsList.size()][3]; for (int i = 0; i < problemsList.size(); i++) { - errorData[i][0] = problemsList.get(i).message; + errorData[i][0] = problemsList.get(i).message ////TODO: this is temporary + + " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); errorData[i][1] = editor.getSketch() .getCode(problemsList.get(i).tabIndex).getPrettyName(); errorData[i][2] = problemsList.get(i).lineNumber + ""; @@ -761,10 +765,13 @@ public class ErrorCheckerService implements Runnable{ if (emarker.problem.lineNumber == editor.getTextArea() .getCaretLine() + 1) { if (emarker.type == ErrorMarker.Warning) { - editor.statusNotice(emarker.problem.message); + editor.statusNotice(emarker.problem.message + + " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); + //TODO: this is temporary } else { - editor.statusError(emarker.problem.message); + editor.statusError(emarker.problem.message + + " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); } return; } From 2f4d40d523c36729b14a853fe1861ebeda87f03b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 20 Jul 2013 22:12:29 +0530 Subject: [PATCH 139/608] Adding new class.. --- .../experimental/ErrorMessageSimplifier.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java diff --git a/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java b/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java new file mode 100644 index 000000000..7ac5c594f --- /dev/null +++ b/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java @@ -0,0 +1,58 @@ +package processing.mode.experimental; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.TreeMap; + +import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; + +public class ErrorMessageSimplifier { + +// private ErrorCheckerService errorCheckerService; + + /** + * Mapping between ProblemID constant and the constant name. Holds about 650 + * of them. Also, this is just temporary, will be used to find the common + * error types, cos you know, identifying String names is easier than + * identifying 8 digit int constants! + * TODO: this is temporary + */ + private TreeMap constantsMap; + + public ErrorMessageSimplifier() { + + new Thread() { + public void run() { + prepareConstantsList(); + } + }.start(); + } + + private void prepareConstantsList() { + constantsMap = new TreeMap(); + Class probClass = DefaultProblem.class; + Field f[] = probClass.getFields(); + for (Field field : f) { + if (Modifier.isStatic(field.getModifiers())) + try { + //System.out.println(field.getName() + " :" + field.get(null)); + Object val = field.get(null); + if (val instanceof Integer) { + constantsMap.put((Integer) (val), field.getName()); + } + } catch (Exception e) { + System.out.println("Here"); + e.printStackTrace(); + break; + } + } + System.out.println("Total items: " + constantsMap.size()); + } + + public String getIDName(int id) { + if (constantsMap == null) + return null; + return constantsMap.get(id); + } + +} From 658433a6f5425c486c019b1b50a8f8ccbd6c24ba Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 23 Jul 2013 01:38:35 +0530 Subject: [PATCH 140/608] Improving element labels. --- pdex/Todo, GSoC 2013.txt | 7 ++ .../mode/experimental/ASTGenerator.java | 73 +++++++++++++++++-- .../mode/experimental/ASTNodeWrapper.java | 17 +++++ 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 44353a5ff..945daaff4 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -105,6 +105,13 @@ Suggestion for missing imports x Barebones functionality done. x Add imports only to beginning of first tab. +Labels for Java elements +======================== +x Working for local code +* Need to modify getASTNodeAt to also fetch the type for predefined classes. +* Labels for predefined class objects +* Chaining support for labels + General Stuff ============= diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index caba60172..a04265296 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1377,16 +1377,74 @@ public class ASTGenerator { } public String getLabelForASTNode(int lineNumber, String name, int offset) { - retLabelString = ""; - getASTNodeAt(lineNumber, name, offset, false); - return retLabelString; + return getASTNodeAt(lineNumber, name, offset, false).getLabel(); + //return ""; + } + + private String getLabelIfType(ASTNodeWrapper node, SimpleName sn){ + String label = ""; + ASTNode current = node.getNode().getParent(); + String type = ""; + StringBuffer fullName = new StringBuffer(); + Stack parents = new Stack(); + switch (node.getNodeType()) { + case ASTNode.TYPE_DECLARATION: + case ASTNode.METHOD_DECLARATION: + case ASTNode.FIELD_DECLARATION: + while (current != null) { + if (current instanceof TypeDeclaration) { + parents.push(((TypeDeclaration) current).getName().toString()); + } + current = current.getParent(); + } + while (parents.size() > 0) { + fullName.append(parents.pop() + "."); + } + fullName.append(sn.toString()); + if (node.getNode() instanceof MethodDeclaration) { + MethodDeclaration md = (MethodDeclaration) node.getNode(); + type = md.getReturnType2().toString(); + fullName.append('('); + if (!md.parameters().isEmpty()) { + List params = md.parameters(); + for (ASTNode par : params) { + if (par instanceof SingleVariableDeclaration) { + SingleVariableDeclaration svd = (SingleVariableDeclaration) par; + fullName.append(svd.getType() + " " + svd.getName() + ","); + } + } + } + if(fullName.charAt(fullName.length() - 1) == ',') + fullName.deleteCharAt(fullName.length() - 1); + fullName.append(')'); + } + else if(node.getNode() instanceof FieldDeclaration){ + type = ((FieldDeclaration) node.getNode()).getType().toString(); + } + int x = fullName.indexOf("."); + fullName.delete(0, x + 1); + return type + " " + fullName; + + case ASTNode.SINGLE_VARIABLE_DECLARATION: + SingleVariableDeclaration svd = (SingleVariableDeclaration)node.getNode(); + return svd.getType() + " " + svd.getName(); + + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + return ((VariableDeclarationStatement)node.getNode()).getType() + " " + sn; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + return ((VariableDeclarationExpression)node.getNode()).getType() + " " + sn; + default: + break; + } + + + return ""; } public void scrollToDeclaration(int lineNumber, String name, int offset) { getASTNodeAt(lineNumber, name, offset, true); } - String retLabelString; /** * @@ -1417,6 +1475,7 @@ public class ASTGenerator { System.out.println("+> " + lineNode); ASTNode decl = null; + String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to if (lineNode != null) { @@ -1474,13 +1533,15 @@ public class ASTGenerator { ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); System.out.println("+++> " + simpName); + if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); System.out.println(getNodeAsString(simpName)); decl = findDeclaration((SimpleName) simpName); if (decl != null) { System.err.println("DECLA: " + decl.getClass().getName()); - retLabelString = getNodeAsString(decl); + nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), (SimpleName) simpName); + //retLabelString = getNodeAsString(decl); } else System.err.println("null"); @@ -1513,7 +1574,7 @@ public class ASTGenerator { errorCheckerService.highlightNode(simpName2); } - return new ASTNodeWrapper(decl); + return new ASTNodeWrapper(decl,nodeLabel); } /** diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 31c902171..201b2b58d 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -48,6 +48,23 @@ public class ASTNodeWrapper { label += " | Line " + lineNumber; //apiLevel = 0; } + + public ASTNodeWrapper(ASTNode node, String label){ + if (node == null){ + return; + } + this.Node = node; + if(label != null) + this.label = label; + else{ + label = getNodeAsString(node); + if (label == null) + label = node.toString(); + + label += " | Line " + lineNumber; + } + lineNumber = getLineNumber(node); + } /** * For this node, finds various offsets (java code). From 704395f886ad77b7dd0de685f3145f29929919ca Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 26 Jul 2013 18:30:30 +0530 Subject: [PATCH 141/608] minor fixes: completion lables, and esc key handling --- .../mode/experimental/CompletionCandidate.java | 2 +- .../mode/experimental/CompletionPanel.java | 1 + .../src/processing/mode/experimental/TextArea.java | 14 +++++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index b8c69aa3c..36791e518 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -100,7 +100,7 @@ public class CompletionCandidate implements Comparable{ elementName = f.getName(); type = PREDEF_FIELD; label = f.getName() + " : " + f.getType().getSimpleName() - + f.getDeclaringClass().getSimpleName(); + + " - " + f.getDeclaringClass().getSimpleName(); completionString = elementName; } diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 9f6d5d6b6..e9a07b01d 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -59,6 +59,7 @@ public class CompletionPanel { } public void setVisible(boolean v){ + System.out.println("Pred popup visible."); popupMenu.setVisible(v); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index bbacebc1d..41d4115ec 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -238,12 +238,12 @@ public class TextArea extends JEditTextArea { }*/ - if (evt.getID() == KeyEvent.KEY_TYPED) { - errorCheckerService.runManualErrorCheck(); - System.out.println(" Typing: " + fetchPhrase(evt) + " " - + (evt.getKeyChar() == KeyEvent.VK_ENTER)); + if (evt.getID() == KeyEvent.KEY_TYPED) { + errorCheckerService.runManualErrorCheck(); + System.out.println(" Typing: " + fetchPhrase(evt) + " " + + (evt.getKeyChar() == KeyEvent.VK_ENTER)); - } + } } @@ -256,6 +256,10 @@ public class TextArea extends JEditTextArea { } // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) // ; // accepted these keys + else if (keyChar == KeyEvent.VK_ESCAPE) { + //System.out.println("ESC keypress. fetchPhrase()"); + return null; + } else if (keyChar == KeyEvent.CHAR_UNDEFINED) { return null; } From d871c187108d158198fbfbe6fe5bcf822a412592 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 26 Jul 2013 20:13:59 +0530 Subject: [PATCH 142/608] no completions in single line comments --- pdex/Todo, GSoC 2013.txt | 2 +- .../mode/experimental/ASTGenerator.java | 43 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 945daaff4..2b70df518 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -37,11 +37,11 @@ x Completion for array access, strings[0]. Finer details * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? -* Show declaring class for completions *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * Diamond operator isn't supported for now. Bummer. * Icons for completions? Or overkill right now? +x Show declaring class for completions x! Ignore String case while finding completion candidates x Multiple 3rd party classes found in various packages. Not a chance no more. x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index a04265296..cd82b12d1 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -238,7 +238,7 @@ public class ASTGenerator { } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); - calculateComments(); + getCodeComments(); codeTree = new DefaultMutableTreeNode( getNodeAsString((ASTNode) compilationUnit .types().get(0))); @@ -757,6 +757,10 @@ public class ASTGenerator { private String lastPredictedWord = " "; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { + if(caretWithinLineComment()){ + System.out.println("No predictions."); + return; + } SwingWorker worker = new SwingWorker() { @Override @@ -807,6 +811,21 @@ public class ASTGenerator { } } + + // Ensure that we're not inside a comment. TODO: Binary search + + /*for (Comment comm : getCodeComments()) { + int commLineNo = PdeToJavaLineNumber(compilationUnit + .getLineNumber(comm.getStartPosition())); + if(commLineNo == lineNumber){ + System.out.println("Found a comment line " + comm); + System.out.println("Comment LSO " + + javaCodeOffsetToLineStartOffset(compilationUnit + .getLineNumber(comm.getStartPosition()), + comm.getStartPosition())); + break; + } + }*/ // Now parse the expression into an ASTNode object ASTNode nearestNode = null; @@ -2580,15 +2599,33 @@ public class ASTGenerator { } - private void calculateComments(){ + private List getCodeComments(){ List commentList = compilationUnit.getCommentList(); - System.out.println("Total comments: " + commentList.size()); +// System.out.println("Total comments: " + commentList.size()); // int i = 0; // for (Comment comment : commentList) { // System.out.println(++i + ": "+comment + " Line:" // + compilationUnit.getLineNumber(comment.getStartPosition()) + ", " // + comment.getLength()); // } + return commentList; + } + + protected boolean caretWithinLineComment(){ + String pdeLine = editor.getLineText(editor.textArea().getCaretLine()).trim(); + int caretPos = editor.textArea().getCaretPosition() + - editor.textArea() + .getLineStartNonWhiteSpaceOffset(editor.textArea().getCaretLine()); + int x = pdeLine.indexOf("//"); + System.out.println(x + " , " + caretPos + ", Checking line for comment " + pdeLine); + //lineStartOffset = editor.textArea(). + + if (x >= 0 && caretPos > x) { + System.out.println("INSIDE a comment"); + return true; + } + System.out.println("not within comment"); + return false; } /** From 9bc0aadce3aa224ddc1b660c98c1fe4f95af81a1 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 26 Jul 2013 21:22:48 +0530 Subject: [PATCH 143/608] improving show usage labels --- .../mode/experimental/ASTGenerator.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index cd82b12d1..99e23419b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -158,7 +158,7 @@ public class ASTGenerator { frame2.add(sp); btnRename = new JButton("Rename"); - btnListOccurrence = new JButton("Find All"); + btnListOccurrence = new JButton("Show Usage"); frmRename = new JFrame(); frmRename.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frmRename.setBounds(new Rectangle(680, 50, 250, 130)); @@ -1401,11 +1401,11 @@ public class ASTGenerator { } private String getLabelIfType(ASTNodeWrapper node, SimpleName sn){ - String label = ""; ASTNode current = node.getNode().getParent(); String type = ""; StringBuffer fullName = new StringBuffer(); Stack parents = new Stack(); + String simpleName = (sn == null) ? node.getNode().toString() : sn.toString(); switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: case ASTNode.METHOD_DECLARATION: @@ -1419,7 +1419,7 @@ public class ASTGenerator { while (parents.size() > 0) { fullName.append(parents.pop() + "."); } - fullName.append(sn.toString()); + fullName.append(simpleName); if (node.getNode() instanceof MethodDeclaration) { MethodDeclaration md = (MethodDeclaration) node.getNode(); type = md.getReturnType2().toString(); @@ -1449,9 +1449,11 @@ public class ASTGenerator { return svd.getType() + " " + svd.getName(); case ASTNode.VARIABLE_DECLARATION_STATEMENT: - return ((VariableDeclarationStatement)node.getNode()).getType() + " " + sn; + return ((VariableDeclarationStatement) node.getNode()).getType() + " " + + simpleName; case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - return ((VariableDeclarationExpression)node.getNode()).getType() + " " + sn; + return ((VariableDeclarationExpression) node.getNode()).getType() + " " + + simpleName; default: break; } @@ -1740,7 +1742,7 @@ public class ASTGenerator { } protected void done() { - handleRename(); + refactorIt(); } }; worker.execute(); @@ -1762,6 +1764,7 @@ public class ASTGenerator { DefaultMutableTreeNode defCU = findAllOccurrences(); treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); + frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); frmOccurenceList.setVisible(true); } }; @@ -1803,11 +1806,12 @@ public class ASTGenerator { }); } - private void handleRename(){ + private void refactorIt(){ String newName = txtRenameField.getText(); DefaultMutableTreeNode defCU = findAllOccurrences(); treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); + frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); frmOccurenceList.setVisible(true); int lineOffsetDisplacementConst = newName.length() - editor.ta.getSelectedText().length(); @@ -1967,7 +1971,8 @@ public class ASTGenerator { ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); // System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); if(isInstanceOfType(awnode.getNode(), decl, name)){ - tnode.add(new DefaultMutableTreeNode(awnode)); + tnode.add(new DefaultMutableTreeNode(new ASTNodeWrapper(awnode + .getNode(), name + " | Line " + awnode.getLineNumber()))); } } From 202ae14c73131fe5dfec8fe953f12dc0d2d28ddf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 26 Jul 2013 21:49:47 +0530 Subject: [PATCH 144/608] added show usage menu item --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 47 +++++++++++++++---- .../mode/experimental/DebugEditor.java | 18 ++++++- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2b70df518..8a2d2fe73 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -36,6 +36,7 @@ x Completion for array access, strings[0]. Finer details +* findDeclarations should support 3rd party classes too. It's about time. ;) * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * Diamond operator isn't supported for now. Bummer. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 99e23419b..8e0450d6e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1422,7 +1422,8 @@ public class ASTGenerator { fullName.append(simpleName); if (node.getNode() instanceof MethodDeclaration) { MethodDeclaration md = (MethodDeclaration) node.getNode(); - type = md.getReturnType2().toString(); + if (!md.isConstructor()) + type = md.getReturnType2().toString(); fullName.append('('); if (!md.parameters().isEmpty()) { List params = md.parameters(); @@ -1761,11 +1762,7 @@ public class ASTGenerator { } protected void done() { - DefaultMutableTreeNode defCU = findAllOccurrences(); - treeRename.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) treeRename.getModel()).reload(); - frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); - frmOccurenceList.setVisible(true); + handleShowUsage(); } }; worker.execute(); @@ -1809,6 +1806,10 @@ public class ASTGenerator { private void refactorIt(){ String newName = txtRenameField.getText(); DefaultMutableTreeNode defCU = findAllOccurrences(); + if(defCU == null){ + editor.statusError("Can't locate definition of " + editor.ta.getSelectedText()); + return; + } treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); @@ -1858,6 +1859,27 @@ public class ASTGenerator { frmRename.setVisible(false); } + public void handleShowUsage(){ + if(editor.ta.getSelectedText() == null){ + editor.statusError("Highlight the class/function/variable name first"); + return; + } + + if(errorCheckerService.hasSyntaxErrors()){ + editor.statusError("Can't perform action until syntax errors are fixed :("); + return; + } + DefaultMutableTreeNode defCU = findAllOccurrences(); + if(defCU == null){ + editor.statusError("Can't locate definition of " + editor.ta.getSelectedText()); + return; + } + treeRename.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) treeRename.getModel()).reload(); + frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); + frmOccurenceList.setVisible(true); + } + private DefaultMutableTreeNode findAllOccurrences(){ String selText = editor.ta.getSelectedText(); int line = editor.ta.getSelectionStartLine(); @@ -1877,6 +1899,9 @@ public class ASTGenerator { selText, editor.ta.getSelectionStart() - offwhitespace, false); + if(wnode.getNode() == null){ + return null; + } System.err.println("Gonna find all occurrences of " + getNodeAsString(wnode.getNode())); @@ -1900,7 +1925,11 @@ public class ASTGenerator { } } - DefaultMutableTreeNode defCU = new DefaultMutableTreeNode(wnode); + DefaultMutableTreeNode defCU = new DefaultMutableTreeNode( + new ASTNodeWrapper( + wnode + .getNode(), + selText)); dfsNameOnly(defCU, wnode.getNode(), selText); System.out.println(wnode); return defCU; @@ -1972,7 +2001,7 @@ public class ASTGenerator { // System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); if(isInstanceOfType(awnode.getNode(), decl, name)){ tnode.add(new DefaultMutableTreeNode(new ASTNodeWrapper(awnode - .getNode(), name + " | Line " + awnode.getLineNumber()))); + .getNode(), "Line " + awnode.getLineNumber()))); } } @@ -2055,7 +2084,7 @@ public class ASTGenerator { } if(errorCheckerService.hasSyntaxErrors()){ - editor.statusError("Can't rename until syntax errors are fixed :("); + editor.statusError("Can't perform action until syntax errors are fixed :("); return; } if (!frmRename.isVisible()){ diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 099e90d1a..055108067 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -156,13 +156,23 @@ public class DebugEditor extends JavaEditor implements ActionListener { // access to customized (i.e. subclassed) text area ta = (TextArea) textarea; + // Add show usage option + JMenuItem showUsageItem = new JMenuItem("Show Usage.."); + showUsageItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleShowUsage(); + } + }); + ta.getRightClickPopup().add(showUsageItem); + // add refactor option JMenuItem renameItem = new JMenuItem("Rename.."); renameItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleRefactor(); } - }); + }); + // TODO: Add support for word select on right click and rename. // ta.customPainter.addMouseListener(new MouseAdapter() { // public void mouseClicked(MouseEvent evt) { @@ -1144,6 +1154,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { errorCheckerService.astGenerator.handleRefactor(); } + private void handleShowUsage() { + System.out.println("Caret at:"); + System.out.println(ta.getLineText(ta.getCaretLine())); + errorCheckerService.astGenerator.handleShowUsage(); + } + /** * Checks if the sketch contains java tabs. If it does, XQMode ain't built * for it, yet. Also, user should really start looking at Eclipse. Disable From 6cbb9eaac01f1531cd186900d0752fc176a0ef23 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 26 Jul 2013 22:18:16 +0530 Subject: [PATCH 145/608] tab and line info in show usage labels --- pdex/src/processing/mode/experimental/ASTGenerator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 8e0450d6e..1a81009c2 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -2000,8 +2000,10 @@ public class ASTGenerator { ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); // System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); if(isInstanceOfType(awnode.getNode(), decl, name)){ + int val[] = errorCheckerService.JavaToPdeOffsets(awnode.getLineNumber(), 0); tnode.add(new DefaultMutableTreeNode(new ASTNodeWrapper(awnode - .getNode(), "Line " + awnode.getLineNumber()))); + .getNode(), "Line " + (val[1] + 1) + " | Tab: " + + editor.getSketch().getCode(val[0]).getPrettyName()))); } } From b61e736be9539ad92017c04f66c4980b75026429 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 27 Jul 2013 01:05:07 +0530 Subject: [PATCH 146/608] right click on an element to rename/show usage --- pdex/Todo, GSoC 2013.txt | 4 +- .../mode/experimental/ASTGenerator.java | 62 ++++++++--- .../mode/experimental/TextArea.java | 102 +++++++++++++++--- .../mode/experimental/TextAreaPainter.java | 1 + 4 files changed, 135 insertions(+), 34 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 8a2d2fe73..70980f35b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -42,6 +42,7 @@ Finer details * Diamond operator isn't supported for now. Bummer. * Icons for completions? Or overkill right now? +x 'Show Usage' menu item added x Show declaring class for completions x! Ignore String case while finding completion candidates x Multiple 3rd party classes found in various packages. Not a chance no more. @@ -69,7 +70,8 @@ Refactoring =========== * Undo misbehaves here, handle carefully. -* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully + +x Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1a81009c2..0d68ada2b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1805,17 +1805,19 @@ public class ASTGenerator { private void refactorIt(){ String newName = txtRenameField.getText(); + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; DefaultMutableTreeNode defCU = findAllOccurrences(); if(defCU == null){ - editor.statusError("Can't locate definition of " + editor.ta.getSelectedText()); + editor.statusError("Can't locate definition of " + selText); return; } treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); - frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); + frmOccurenceList.setTitle("Usage of " + selText); frmOccurenceList.setVisible(true); int lineOffsetDisplacementConst = newName.length() - - editor.ta.getSelectedText().length(); + - selText.length(); HashMap lineOffsetDisplacement = new HashMap(); // I need to store the pde and java offsets beforehand because once @@ -1857,10 +1859,13 @@ public class ASTGenerator { errorCheckerService.runManualErrorCheck(); frmOccurenceList.setVisible(false); frmRename.setVisible(false); + lastClickedWord = null; + lastClickedWordNode = null; } public void handleShowUsage(){ - if(editor.ta.getSelectedText() == null){ + System.out.println("Last clicked word:" + lastClickedWord); + if(lastClickedWord == null && editor.ta.getSelectedText() == null){ editor.statusError("Highlight the class/function/variable name first"); return; } @@ -1870,20 +1875,39 @@ public class ASTGenerator { return; } DefaultMutableTreeNode defCU = findAllOccurrences(); + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; if(defCU == null){ - editor.statusError("Can't locate definition of " + editor.ta.getSelectedText()); + editor.statusError("Can't locate definition of " + selText); return; } treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); - frmOccurenceList.setTitle("Usage of " + editor.ta.getSelectedText()); + frmOccurenceList.setTitle("Usage of " + selText); frmOccurenceList.setVisible(true); + lastClickedWord = null; + lastClickedWordNode = null; } + protected String lastClickedWord = null; + protected ASTNodeWrapper lastClickedWordNode = null; + + public String getLastClickedWord() { + return lastClickedWord; + } + + public void setLastClickedWord(int lineNumber, String lastClickedWord, int offset) { + this.lastClickedWord = lastClickedWord; + lastClickedWordNode = getASTNodeAt(lineNumber, lastClickedWord, offset, false); + System.out.println("Last clicked node: " + lastClickedWordNode); + } + private DefaultMutableTreeNode findAllOccurrences(){ - String selText = editor.ta.getSelectedText(); + System.out.println("Last clicked word:" + lastClickedWord); + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; int line = editor.ta.getSelectionStartLine(); - System.out.println(editor.ta.getSelectedText() + System.out.println(selText + "<- offsets " + (line) + ", " @@ -1894,11 +1918,14 @@ public class ASTGenerator { .getLineStartOffset(line))); int offwhitespace = editor.ta .getLineStartNonWhiteSpaceOffset(line); - ASTNodeWrapper wnode = getASTNodeAt(line - + errorCheckerService.mainClassOffset, - selText, - editor.ta.getSelectionStart() - - offwhitespace, false); + ASTNodeWrapper wnode; + if (lastClickedWord == null) { + wnode = getASTNodeAt(line + errorCheckerService.mainClassOffset, selText, + editor.ta.getSelectionStart() - offwhitespace, false); + } + else{ + wnode = lastClickedWordNode; + } if(wnode.getNode() == null){ return null; } @@ -2080,7 +2107,8 @@ public class ASTGenerator { } public void handleRefactor(){ - if(editor.ta.getSelectedText() == null){ + System.out.println("Last clicked word:" + lastClickedWord); + if(lastClickedWord == null && editor.ta.getSelectedText() == null){ editor.statusError("Highlight the class/function/variable name first"); return; } @@ -2094,10 +2122,12 @@ public class ASTGenerator { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; frmOccurenceList.setTitle("All occurrences of " - + editor.ta.getSelectedText()); + + selText); lblRefactorOldName.setText("Current name: " - + editor.ta.getSelectedText()); + + selText); txtRenameField.requestFocus(); } }); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 41d4115ec..40feea600 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -247,23 +247,85 @@ public class TextArea extends JEditTextArea { } - - private String fetchPhrase(KeyEvent evt) { - char keyChar = evt.getKeyChar(); - if (keyChar == KeyEvent.VK_ENTER) { - //System.out.println("Enter keypress."); + + + private String fetchPhrase(MouseEvent evt) { + System.out.println("--handle Mouse Right Click--"); + int off = xyToOffset(evt.getX(), evt.getY()); + if (off < 0) return null; + int line = getLineOfOffset(off); + if (line < 0) + return null; + String s = getLineText(line); + if (s == null) + return null; + else if (s.length() == 0) + return null; + else { + int x = xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + int xLS = off - getLineStartNonWhiteSpaceOffset(line); + System.out.println("x=" + x); + if (x < 0 || x >= s.length()) + return null; + String word = s.charAt(x) + ""; + if (s.charAt(x) == ' ') + return null; + if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s + .charAt(x) == '$')) + return null; + int i = 0; + while (true) { + i++; + if (x1 >= 0 && x1 < s.length()) { + if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { + word = s.charAt(x1--) + word; + } else + x1 = -1; + } else + x1 = -1; + + if (x2 >= 0 && x2 < s.length()) { + if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + || s.charAt(x2) == '$') + word = word + s.charAt(x2++); + else + x2 = -1; + } else + x2 = -1; + + if (x1 < 0 && x2 < 0) + break; + if (i > 200) { + // time out! + System.err.println("Whoopsy! :P"); + break; + } + } + if (Character.isDigit(word.charAt(0))) + return null; + System.out.println("Mouse click, word: " + word.trim()); + errorCheckerService.astGenerator.setLastClickedWord(line + + errorCheckerService.mainClassOffset, word, xLS); + return word.trim(); } + } + private String fetchPhrase(KeyEvent evt) { + if (evt != null) { + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_ENTER) { + //System.out.println("Enter keypress."); + return null; + } // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) // ; // accepted these keys - else if (keyChar == KeyEvent.VK_ESCAPE) { - //System.out.println("ESC keypress. fetchPhrase()"); - return null; + else if (keyChar == KeyEvent.VK_ESCAPE) { + //System.out.println("ESC keypress. fetchPhrase()"); + return null; + } else if (keyChar == KeyEvent.CHAR_UNDEFINED) { + return null; + } } - else if (keyChar == KeyEvent.CHAR_UNDEFINED) { - return null; - } - int off = getCaretPosition(); System.out.print("off " + off); if (off < 0) @@ -579,12 +641,18 @@ public class TextArea extends JEditTextArea { editor.gutterDblClicked(line); } } - } else { - // forward to standard listeners - for (MouseListener ml : mouseListeners) { - ml.mousePressed(me); - } + return; } + + if (me.getButton() == MouseEvent.BUTTON3) { + fetchPhrase(me); + } + + // forward to standard listeners + for (MouseListener ml : mouseListeners) { + ml.mousePressed(me); + } + } @Override diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 6a06e4d9b..b1ab4a029 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -103,6 +103,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { return; else { int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; + System.out.println("x="+x); int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); if (x < 0 || x >= s.length()) return; From 11a04c634bcb4615e6800cdacde34ab48208f5fc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 27 Jul 2013 01:20:34 +0530 Subject: [PATCH 147/608] sprucing things up --- .../mode/experimental/ASTGenerator.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 0d68ada2b..d48b04fe7 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -50,6 +50,7 @@ import javax.swing.table.DefaultTableModel; import javax.swing.text.BadLocationException; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.MutableTreeNode; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -1881,9 +1882,12 @@ public class ASTGenerator { editor.statusError("Can't locate definition of " + selText); return; } + if(defCU.getChildCount() == 0) + return; treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); - frmOccurenceList.setTitle("Usage of " + selText); + treeRename.setRootVisible(false); + frmOccurenceList.setTitle("Usage of \"" + selText+ "\""); frmOccurenceList.setVisible(true); lastClickedWord = null; lastClickedWordNode = null; @@ -1919,7 +1923,7 @@ public class ASTGenerator { int offwhitespace = editor.ta .getLineStartNonWhiteSpaceOffset(line); ASTNodeWrapper wnode; - if (lastClickedWord == null) { + if (lastClickedWord == null || lastClickedWordNode.getNode() == null) { wnode = getASTNodeAt(line + errorCheckerService.mainClassOffset, selText, editor.ta.getSelectionStart() - offwhitespace, false); } @@ -1958,7 +1962,18 @@ public class ASTGenerator { .getNode(), selText)); dfsNameOnly(defCU, wnode.getNode(), selText); + + // Reverse the list obtained via dfs + Stack tempS = new Stack(); + for (int i = 0; i < defCU.getChildCount(); i++) { + tempS.push(defCU.getChildAt(i)); + } + defCU.removeAllChildren(); + while (!tempS.isEmpty()) { + defCU.add((MutableTreeNode) tempS.pop()); + } System.out.println(wnode); + return defCU; } From 7de693ab95627292d071299ae078d48da3e96920 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 27 Jul 2013 01:26:27 +0530 Subject: [PATCH 148/608] syntax error flag is now thread safe --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ErrorCheckerService.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 70980f35b..6268ef55f 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -71,6 +71,7 @@ Refactoring * Undo misbehaves here, handle carefully. +x Ordered list in 'Show Usage' window x Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 1508412ba..e1dd641dc 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -10,6 +10,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -187,7 +188,7 @@ public class ErrorCheckerService implements Runnable{ defaultImportsOffset = pdePrepoc.getCoreImports().length + pdePrepoc.getDefaultImports().length + 1; astGenerator = new ASTGenerator(this); - syntaxErrors = true; + syntaxErrors = new AtomicBoolean(true); errorMsgSimplifier = new ErrorMessageSimplifier(); } @@ -340,13 +341,14 @@ public class ErrorCheckerService implements Runnable{ return false; } - private boolean syntaxErrors; + private AtomicBoolean syntaxErrors; public boolean hasSyntaxErrors(){ - return syntaxErrors; + return syntaxErrors.get(); } private void syntaxCheck() { + syntaxErrors.set(true); parser.setSource(sourceCode.toCharArray()); parser.setKind(ASTParser.K_COMPILATION_UNIT); @@ -376,7 +378,10 @@ public class ErrorCheckerService implements Runnable{ // System.out.println(p.toString()); } - syntaxErrors = problems.length == 0 ? false : true; + if (problems.length == 0) + syntaxErrors.set(false); + else + syntaxErrors.set(true); } protected URLClassLoader classLoader; private void compileCheck() { From 46eb2d290e87c8daee02f05b496bd239443dece8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 27 Jul 2013 03:22:31 +0530 Subject: [PATCH 149/608] added temporary error logging for duration of testing --- .../mode/experimental/ASTGenerator.java | 6 +-- .../mode/experimental/DebugEditor.java | 50 +++++++++++++++++++ .../experimental/ErrorCheckerService.java | 12 ++++- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index d48b04fe7..8e51afa59 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -257,9 +257,9 @@ public class ASTGenerator { return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) { - frame2.setVisible(true); - } +// if (!frame2.isVisible()) { +// frame2.setVisible(true); +// } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 055108067..7b9be9916 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -27,8 +27,11 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; @@ -44,6 +47,9 @@ import javax.swing.JScrollPane; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; + +import org.eclipse.jdt.core.compiler.IProblem; + import processing.app.*; import processing.app.syntax.JEditTextArea; import processing.app.syntax.PdeTextAreaDefaults; @@ -286,9 +292,53 @@ public class DebugEditor extends JavaEditor implements ActionListener { dbg.stopDebug(); // remove var.inspector vi.dispose(); + // original dispose super.dispose(); } + + // Added temporarily to dump error log. TODO: Remove this later + public void internalCloseRunner(){ + writeErrorsToFile(); + super.internalCloseRunner(); + } + + private void writeErrorsToFile(){ + if (errorCheckerService.tempErrorLog.size() == 0) + return; + try { + System.out.println("Writing errors"); + StringBuffer sbuff = new StringBuffer(); + sbuff.append("Sketch: " + getSketch().getFolder() + ", " + + new java.sql.Timestamp(new java.util.Date().getTime())+"\n\n"); + sbuff.append("ERROR ID, ERROR ARGS, ERROR MSG\n"); + for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { + IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); + if(ip != null){ + sbuff.append(errorCheckerService.errorMsgSimplifier.getIDName(ip.getID())); + sbuff.append(','); + sbuff.append("{"); + for (int i = 0; i < ip.getArguments().length; i++) { + sbuff.append(ip.getArguments()[i]); + if(i < ip.getArguments().length - 1) + sbuff.append('|'); + } + sbuff.append("}"); + sbuff.append(','); + sbuff.append(ip.getMessage().replace(',', ' ')); + sbuff.append("\n"); + } + } + System.out.println(sbuff); + File opFile = new File(getSketch().getFolder(), "ErrorLogs" + + File.separator + "ErrorLog_" + System.currentTimeMillis() + ".csv"); + PApplet.saveStream(opFile, new ByteArrayInputStream(sbuff.toString() + .getBytes(Charset.defaultCharset()))); + } catch (Exception e) { + System.err.println("Failed to save log file for sketch " + getSketch().getName()); + e.printStackTrace(); + } + } /** * Overrides sketch menu creation to change keyboard shortcuts from "Run". diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index e1dd641dc..0401ed974 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -10,6 +10,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; @@ -177,7 +178,7 @@ public class ErrorCheckerService implements Runnable{ + "(void|int|float|double|String|char|byte)" + "(\\s*\\[\\s*\\])?\\s+[a-zA-Z0-9]+\\s*\\(", Pattern.MULTILINE); - private ErrorMessageSimplifier errorMsgSimplifier; + protected ErrorMessageSimplifier errorMsgSimplifier; public ErrorCheckerService(DebugEditor debugEditor) { this.editor = debugEditor; @@ -190,6 +191,7 @@ public class ErrorCheckerService implements Runnable{ astGenerator = new ASTGenerator(this); syntaxErrors = new AtomicBoolean(true); errorMsgSimplifier = new ErrorMessageSimplifier(); + tempErrorLog = new TreeMap(); } /** @@ -346,6 +348,8 @@ public class ErrorCheckerService implements Runnable{ public boolean hasSyntaxErrors(){ return syntaxErrors.get(); } + + protected TreeMap tempErrorLog; private void syntaxCheck() { syntaxErrors.set(true); @@ -705,8 +709,12 @@ public class ErrorCheckerService implements Runnable{ errorData[i][1] = editor.getSketch() .getCode(problemsList.get(i).tabIndex).getPrettyName(); errorData[i][2] = problemsList.get(i).lineNumber + ""; + + //TODO: This is temporary + if(tempErrorLog.size() < 200) + tempErrorLog.put(problemsList.get(i).message,problemsList.get(i).getIProblem()); } - + if (errorWindow != null) { DefaultTableModel tm = new DefaultTableModel(errorData, XQErrorTable.columnNames); From 38567eda2ed38685c211b19cad947978619e7742 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 27 Jul 2013 03:45:46 +0530 Subject: [PATCH 150/608] changes to error log format --- pdex/src/processing/mode/experimental/DebugEditor.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 7b9be9916..83ffd719c 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -310,8 +310,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { System.out.println("Writing errors"); StringBuffer sbuff = new StringBuffer(); sbuff.append("Sketch: " + getSketch().getFolder() + ", " - + new java.sql.Timestamp(new java.util.Date().getTime())+"\n\n"); - sbuff.append("ERROR ID, ERROR ARGS, ERROR MSG\n"); + + new java.sql.Timestamp(new java.util.Date().getTime()) + + "\nComma in error msg is substituted with ^ symbol\nFor separating arguments in error args | symbol is used\n"); + sbuff.append("ERROR TYPE, ERROR ARGS, ERROR MSG\n"); for (String errMsg : errorCheckerService.tempErrorLog.keySet()) { IProblem ip = errorCheckerService.tempErrorLog.get(errMsg); if(ip != null){ @@ -325,7 +326,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } sbuff.append("}"); sbuff.append(','); - sbuff.append(ip.getMessage().replace(',', ' ')); + sbuff.append(ip.getMessage().replace(',', '^')); sbuff.append("\n"); } } From 93aaa83ad69d87a4f57890d6c02715b5da9f0939 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 17:28:11 +0530 Subject: [PATCH 151/608] started work on toggling console o/p. Shoulda done this at the start --- .../mode/experimental/ASTGenerator.java | 340 +++++++++--------- .../mode/experimental/DebugEditor.java | 17 +- .../experimental/ErrorCheckerService.java | 123 ++++--- .../mode/experimental/ExperimentalMode.java | 20 +- 4 files changed, 272 insertions(+), 228 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 8e51afa59..7bfda7b3a 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,5 +1,7 @@ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; + import java.awt.Dimension; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -53,7 +55,6 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; @@ -82,7 +83,6 @@ import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; import processing.app.SketchCode; @@ -235,7 +235,7 @@ public class ASTGenerator { compilationUnit = (CompilationUnit) parser.createAST(null); } else { compilationUnit = cu; - System.out.println("Other cu"); + log("Other cu"); } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); @@ -269,7 +269,7 @@ public class ASTGenerator { // long t = System.currentTimeMillis(); // loadJars(); // loadJavaDoc(); -// System.out.println("Time taken: " +// log("Time taken: " // + (System.currentTimeMillis() - t)); // jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() // .getX() + errorCheckerService.getEditor().getWidth(), @@ -283,8 +283,8 @@ public class ASTGenerator { }; worker.execute(); // System.err.println("++>" + System.getProperty("java.class.path")); -// System.out.println(System.getProperty("java.class.path")); -// System.out.println("-------------------------------"); +// log(System.getProperty("java.class.path")); +// log("-------------------------------"); return codeTree; } @@ -331,7 +331,7 @@ public class ASTGenerator { } if (errorCheckerService.classpathJars != null) { for (URL jarPath : errorCheckerService.classpathJars) { - //System.out.println(jarPath.getPath()); + //log(jarPath.getPath()); tehPath.append(jarPath.getPath() + File.pathSeparatorChar); } } @@ -341,30 +341,30 @@ public class ASTGenerator { // File.pathSeparatorChar + ""); // while (st.hasMoreElements()) { // String sstr = (String) st.nextElement(); -// System.out.println(sstr); +// log(sstr); // } classPath = factory.createFromPath(tehPath.toString()); // for (String packageName : classPath.listPackages("")) { -// System.out.println(packageName); +// log(packageName); // } // RegExpResourceFilter regExpResourceFilter = new RegExpResourceFilter( // ".*", // "ArrayList.class"); // String[] resources = classPath.findResources("", regExpResourceFilter); // for (String className : resources) { -// System.out.println("-> " + className); +// log("-> " + className); // } - System.out.println("Sketch classpath jars loaded."); + log("Sketch classpath jars loaded."); if (Base.isMacOS()) { File f = new File(System.getProperty("java.home") + File.separator + "bundle" + File.separator + "Classes" + File.separator + "classes.jar"); - System.out.println(f.getAbsolutePath() + " | classes.jar found?" + log(f.getAbsolutePath() + " | classes.jar found?" + f.exists()); } else { File f = new File(System.getProperty("java.home") + File.separator + "lib" + File.separator + "rt.jar" + File.separator); - System.out.println(f.getAbsolutePath() + " | rt.jar found?" + log(f.getAbsolutePath() + " | rt.jar found?" + f.exists()); } @@ -405,7 +405,7 @@ public class ASTGenerator { case ASTNode.METHOD_DECLARATION: MethodDeclaration md = (MethodDeclaration) node; - System.out.println(getNodeAsString(md)); + log(getNodeAsString(md)); List params = (List) md .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY); CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1]; @@ -457,23 +457,23 @@ public class ASTGenerator { */ public static ASTNode resolveExpression(ASTNode nearestNode, ASTNode expression, boolean noCompare) { - System.out.println("Resolving " + getNodeAsString(expression) + " noComp " + log("Resolving " + getNodeAsString(expression) + " noComp " + noCompare); if (expression instanceof SimpleName) { return findDeclaration2(((SimpleName) expression), nearestNode); } else if (expression instanceof MethodInvocation) { - System.out.println("3. Method Invo " + log("3. Method Invo " + ((MethodInvocation) expression).getName()); return findDeclaration2(((MethodInvocation) expression).getName(), nearestNode); } else if (expression instanceof FieldAccess) { - System.out.println("2. Field access " + log("2. Field access " + getNodeAsString(((FieldAccess) expression).getExpression()) + "|||" + getNodeAsString(((FieldAccess) expression).getName())); if (noCompare) { /* * ASTNode ret = findDeclaration2(((FieldAccess) expression).getName(), - * nearestNode); System.out.println("Found as ->"+getNodeAsString(ret)); + * nearestNode); log("Found as ->"+getNodeAsString(ret)); * return ret; */ return findDeclaration2(((FieldAccess) expression).getName(), @@ -493,7 +493,7 @@ public class ASTGenerator { } //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode); } else if (expression instanceof QualifiedName) { - System.out.println("1. Resolving " + log("1. Resolving " + ((QualifiedName) expression).getQualifier() + " ||| " + ((QualifiedName) expression).getName()); if (noCompare) { // no compare, as in "abc.hello." need to resolve hello here @@ -519,7 +519,7 @@ public class ASTGenerator { */ public ClassMember resolveExpression3rdParty(ASTNode nearestNode, ASTNode astNode, boolean noCompare) { - System.out.println("Resolve 3rdParty expr-- " + getNodeAsString(astNode) + log("Resolve 3rdParty expr-- " + getNodeAsString(astNode) + " nearest node " + getNodeAsString(nearestNode)); ClassMember scopeParent = null; @@ -528,7 +528,7 @@ public class ASTGenerator { ASTNode decl = findDeclaration2(((SimpleName)astNode),nearestNode); if(decl != null){ // see if locally defined - System.out.println(getNodeAsString(astNode)+" found decl -> " + getNodeAsString(decl)); + log(getNodeAsString(astNode)+" found decl -> " + getNodeAsString(decl)); return new ClassMember(extracTypeInfo(decl)); } else { @@ -546,7 +546,7 @@ public class ASTGenerator { FieldAccess fa = (FieldAccess) astNode; if (fa.getExpression() == null) { // Local code or belongs to super class - System.out.println("FA,Not implemented."); + log("FA,Not implemented."); return null; } else { if (fa.getExpression() instanceof SimpleName) { @@ -554,7 +554,7 @@ public class ASTGenerator { nearestNode)); if(stp == null){ /*The type wasn't found in local code, so it might be something like - * System.out.println(), or maybe belonging to super class, etc. + * log(), or maybe belonging to super class, etc. */ Class tehClass = findClassIfExists(((SimpleName)fa.getExpression()).toString()); if (tehClass != null) { @@ -563,18 +563,18 @@ public class ASTGenerator { return definedIn3rdPartyClass(new ClassMember(tehClass), fa .getName().toString()); } - System.out.println("FA resolve 3rd par, Can't resolve " + fa.getExpression()); + log("FA resolve 3rd par, Can't resolve " + fa.getExpression()); return null; } - System.out.println("FA, SN Type " + getNodeAsString(stp)); + log("FA, SN Type " + getNodeAsString(stp)); scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); } else { scopeParent = resolveExpression3rdParty(nearestNode, fa.getExpression(), noCompare); } - System.out.println("FA, ScopeParent " + scopeParent); + log("FA, ScopeParent " + scopeParent); return definedIn3rdPartyClass(scopeParent, fa.getName().toString()); } case ASTNode.METHOD_INVOCATION: @@ -582,12 +582,12 @@ public class ASTGenerator { ASTNode temp = findDeclaration2(mi.getName(), nearestNode); if(temp instanceof MethodDeclaration){ // method is locally defined - System.out.println(mi.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp))); + log(mi.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp))); return new ClassMember(extracTypeInfo(temp)); } if (mi.getExpression() == null) { //Local code or belongs to super class - System.out.println("MI,Not implemented."); + log("MI,Not implemented."); return null; } else { if (mi.getExpression() instanceof SimpleName) { @@ -604,13 +604,13 @@ public class ASTGenerator { return definedIn3rdPartyClass(new ClassMember(tehClass), mi .getName().toString()); } - System.out.println("MI resolve 3rd par, Can't resolve " + mi.getExpression()); + log("MI resolve 3rd par, Can't resolve " + mi.getExpression()); return null; } - System.out.println("MI, SN Type " + getNodeAsString(stp)); + log("MI, SN Type " + getNodeAsString(stp)); ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode); if(typeDec == null){ - System.out.println(stp.getName() + " couldn't be found locally.."); + log(stp.getName() + " couldn't be found locally.."); Class tehClass = findClassIfExists(stp.getName().toString()); if (tehClass != null) { // Method Expression is a simple name and wasn't located locally, but found in a class @@ -624,11 +624,11 @@ public class ASTGenerator { return definedIn3rdPartyClass(new ClassMember(typeDec), mi .getName().toString()); } else { - System.out.println("MI EXP.."+getNodeAsString(mi.getExpression())); + log("MI EXP.."+getNodeAsString(mi.getExpression())); // return null; scopeParent = resolveExpression3rdParty(nearestNode, mi.getExpression(), noCompare); - System.out.println("MI, ScopeParent " + scopeParent); + log("MI, ScopeParent " + scopeParent); return definedIn3rdPartyClass(scopeParent, mi.getName().toString()); } @@ -638,11 +638,11 @@ public class ASTGenerator { ASTNode temp2 = findDeclaration2(qn.getName(), nearestNode); if(temp2 instanceof FieldDeclaration){ // field is locally defined - System.out.println(qn.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp2))); + log(qn.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp2))); return new ClassMember(extracTypeInfo(temp2)); } if (qn.getQualifier() == null) { - System.out.println("QN,Not implemented."); + log("QN,Not implemented."); return null; } else { @@ -650,7 +650,7 @@ public class ASTGenerator { stp = extracTypeInfo(findDeclaration2(qn.getQualifier(), nearestNode)); if(stp == null){ /*The type wasn't found in local code, so it might be something like - * System.out.println(), or maybe belonging to super class, etc. + * log(), or maybe belonging to super class, etc. */ Class tehClass = findClassIfExists(qn.getQualifier().toString()); if (tehClass != null) { @@ -658,14 +658,14 @@ public class ASTGenerator { return definedIn3rdPartyClass(new ClassMember(tehClass), qn .getName().toString()); } - System.out.println("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); + log("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); return null; } - System.out.println("QN, SN Local Type " + getNodeAsString(stp)); + log("QN, SN Local Type " + getNodeAsString(stp)); //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS"); ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode); if(typeDec == null){ - System.out.println(stp.getName() + " couldn't be found locally.."); + log(stp.getName() + " couldn't be found locally.."); Class tehClass = findClassIfExists(stp.getName().toString()); if (tehClass != null) { @@ -673,7 +673,7 @@ public class ASTGenerator { return definedIn3rdPartyClass(new ClassMember(tehClass), qn .getName().toString()); } - System.out.println("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); + log("QN resolve 3rd par, Can't resolve " + qn.getQualifier()); return null; } return definedIn3rdPartyClass(new ClassMember(typeDec), qn @@ -681,7 +681,7 @@ public class ASTGenerator { } else { scopeParent = resolveExpression3rdParty(nearestNode, qn.getQualifier(), noCompare); - System.out.println("QN, ScopeParent " + scopeParent); + log("QN, ScopeParent " + scopeParent); return definedIn3rdPartyClass(scopeParent, qn.getName().toString()); } @@ -690,7 +690,7 @@ public class ASTGenerator { ArrayAccess arac = (ArrayAccess)astNode; return resolveExpression3rdParty(nearestNode, arac.getArray(), noCompare); default: - System.out.println("Unaccounted type " + getNodeAsString(astNode)); + log("Unaccounted type " + getNodeAsString(astNode)); break; } @@ -716,7 +716,7 @@ public class ASTGenerator { }else if(expression instanceof ArrayAccess){ return ((ArrayAccess)expression).getArray(); } - System.out.println(" getChildExpression returning NULL for " + log(" getChildExpression returning NULL for " + getNodeAsString(expression)); return null; } @@ -734,7 +734,7 @@ public class ASTGenerator { } else if (expression instanceof ArrayAccess) { return ((ArrayAccess) expression).getArray(); } - System.out.println("getParentExpression returning NULL for " + log("getParentExpression returning NULL for " + getNodeAsString(expression)); return null; } @@ -744,7 +744,7 @@ public class ASTGenerator { newWord = newWord.toLowerCase(); for (CompletionCandidate comp : candidates) { if(comp.toString().toLowerCase().startsWith(newWord)){ - System.out.println("Adding " + comp); + log("Adding " + comp); newCandidate.add(comp); } } @@ -759,7 +759,7 @@ public class ASTGenerator { public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { if(caretWithinLineComment()){ - System.out.println("No predictions."); + log("No predictions."); return; } SwingWorker worker = new SwingWorker() { @@ -784,8 +784,8 @@ public class ASTGenerator { if (word2.length() > 2 && !noCompare && word2.length() > lastPredictedWord.length()) { if (word2.startsWith(lastPredictedWord)) { - System.out.println(word + " starts with " + lastPredictedWord); - System.out.println("Don't recalc"); + log(word + " starts with " + lastPredictedWord); + log("Don't recalc"); if (word2.contains(".")) { int x = word2.lastIndexOf('.'); trimCandidates(word2.substring(x + 1)); @@ -819,8 +819,8 @@ public class ASTGenerator { int commLineNo = PdeToJavaLineNumber(compilationUnit .getLineNumber(comm.getStartPosition())); if(commLineNo == lineNumber){ - System.out.println("Found a comment line " + comm); - System.out.println("Comment LSO " + log("Found a comment line " + comm); + log("Comment LSO " + javaCodeOffsetToLineStartOffset(compilationUnit .getLineNumber(comm.getStartPosition()), comm.getStartPosition())); @@ -866,7 +866,7 @@ public class ASTGenerator { .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) { SimpleType st = (SimpleType) td .getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY); - System.out.println("Superclass " + st.getName()); + log("Superclass " + st.getName()); for (CompletionCandidate can : getMembersForType(st.getName() .toString(), word2, noCompare, false)) { candidates.add(can); @@ -909,7 +909,7 @@ public class ASTGenerator { } // We're seeing a simple name that's not defined locally or in // the parent class. So most probably a pre-defined type. - System.out.println("Empty can. " + word2); + log("Empty can. " + word2); RegExpResourceFilter regExpResourceFilter; regExpResourceFilter = new RegExpResourceFilter( Pattern.compile(".*"), @@ -931,7 +931,7 @@ public class ASTGenerator { .add(new CompletionCandidate(matchedClass, matchedClass + " : " + matchedClass2.substring(0, d), matchedClass, CompletionCandidate.PREDEF_CLASS)); - //System.out.println("-> " + className); + //log("-> " + className); } } else { @@ -939,31 +939,31 @@ public class ASTGenerator { // ==> Complex expression of type blah.blah2().doIt,etc // Have to resolve it by carefully traversing AST of testNode System.err.println("Complex expression " + getNodeAsString(testnode)); - System.out.println("candidates empty"); + log("candidates empty"); ASTNode childExpr = getChildExpression(testnode); - System.out.println("Parent expression : " + getParentExpression(testnode)); - System.out.println("Child expression : " + childExpr); + log("Parent expression : " + getParentExpression(testnode)); + log("Child expression : " + childExpr); if (childExpr instanceof ASTNode) { if (!noCompare) { - System.out.println("Original testnode " + log("Original testnode " + getNodeAsString(testnode)); testnode = getParentExpression(testnode); - System.out.println("Corrected testnode " + log("Corrected testnode " + getNodeAsString(testnode)); } ClassMember expr = resolveExpression3rdParty(nearestNode, testnode, noCompare); if (expr == null) { - System.out.println("Expr is null"); + log("Expr is null"); } else { - System.out.println("Expr is " + expr.toString()); + log("Expr is " + expr.toString()); candidates = getMembersForType(expr, childExpr.toString(), noCompare, false); } } else { - System.out.println("ChildExpr is null"); + log("ChildExpr is null"); } } @@ -984,7 +984,7 @@ public class ASTGenerator { candi[i][0] = candidates.get(i); defListModel.addElement(candidates.get(i)); } - System.out.println("Total preds = " + candidates.size()); + log("Total preds = " + candidates.size()); DefaultTableModel tm = new DefaultTableModel(candi, new String[] { "Suggestions" }); if (tableAuto.isVisible()) { @@ -1010,12 +1010,12 @@ public class ASTGenerator { boolean staticOnly) { ArrayList candidates = new ArrayList(); - System.out.println("In GMFT(), Looking for match " + child.toString() + log("In GMFT(), Looking for match " + child.toString() + " in class " + typeName + " noCompare " + noCompare + " staticOnly " + staticOnly); Class probableClass = findClassIfExists(typeName); if(probableClass == null){ - System.out.println("In GMFT(), class not found."); + log("In GMFT(), class not found."); return candidates; } return getMembersForType(new ClassMember(probableClass), child, noCompare, staticOnly); @@ -1028,7 +1028,7 @@ public class ASTGenerator { boolean staticOnly) { String child = childToLookFor.toLowerCase(); ArrayList candidates = new ArrayList(); - System.out.println("getMemFoType-> Looking for match " + child.toString() + log("getMemFoType-> Looking for match " + child.toString() + " inside " + tehClass + " noCompare " + noCompare + " staticOnly " + staticOnly); if(tehClass == null){ @@ -1062,7 +1062,7 @@ public class ASTGenerator { ArrayList superClassCandidates = new ArrayList(); if(td.getSuperclassType() instanceof Type){ - System.out.println(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); + log(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); superClassCandidates = getMembersForType(new ClassMember(td .getSuperclassType()), childToLookFor, noCompare, staticOnly); @@ -1086,10 +1086,10 @@ public class ASTGenerator { } else { probableClass = findClassIfExists(tehClass.getTypeAsString()); if (probableClass == null) { - System.out.println("Couldn't find class " + tehClass.getTypeAsString()); + log("Couldn't find class " + tehClass.getTypeAsString()); return candidates; } - System.out.println("Loaded " + probableClass.toString()); + log("Loaded " + probableClass.toString()); } for (Method method : probableClass.getMethods()) { if (!Modifier.isStatic(method.getModifiers()) && staticOnly) { @@ -1136,11 +1136,11 @@ public class ASTGenerator { // First, see if the classname is a fully qualified name and loads straightaway tehClass = loadClass(className); if(tehClass instanceof Class){ - System.out.println(tehClass.getName() + " located straightaway"); + log(tehClass.getName() + " located straightaway"); return tehClass; } - System.out.println("Looking in the classloader for " + className); + log("Looking in the classloader for " + className); ArrayList imports = errorCheckerService .getProgramImports(); @@ -1151,18 +1151,18 @@ public class ASTGenerator { temp = temp.substring(0, temp.length() - 1) + className; } else { int x = temp.lastIndexOf('.'); - //System.out.println("fclife " + temp.substring(x + 1)); + //log("fclife " + temp.substring(x + 1)); if (!temp.substring(x + 1).equals(className)) { continue; } } tehClass = loadClass(temp); if (tehClass instanceof Class) { - System.out.println(tehClass.getName() + " located."); + log(tehClass.getName() + " located."); return tehClass; } - System.out.println("Doesn't exist in package: " + impS.getImportName()); + log("Doesn't exist in package: " + impS.getImportName()); } @@ -1170,20 +1170,20 @@ public class ASTGenerator { for (String impS : p.getCoreImports()) { tehClass = loadClass(impS.substring(0,impS.length()-1) + className); if (tehClass instanceof Class) { - System.out.println(tehClass.getName() + " located."); + log(tehClass.getName() + " located."); return tehClass; } - System.out.println("Doesn't exist in package: " + impS); + log("Doesn't exist in package: " + impS); } for (String impS : p.getDefaultImports()) { if(className.equals(impS) || impS.endsWith(className)){ tehClass = loadClass(impS); if (tehClass instanceof Class) { - System.out.println(tehClass.getName() + " located."); + log(tehClass.getName() + " located."); return tehClass; } - System.out.println("Doesn't exist in package: " + impS); + log("Doesn't exist in package: " + impS); } } @@ -1191,10 +1191,10 @@ public class ASTGenerator { String daddy = "java.lang." + className; tehClass = loadClass(daddy); if (tehClass instanceof Class) { - System.out.println(tehClass.getName() + " located."); + log(tehClass.getName() + " located."); return tehClass; } - System.out.println("Doesn't exist in java.lang"); + log("Doesn't exist in java.lang"); return tehClass; } @@ -1206,7 +1206,7 @@ public class ASTGenerator { tehClass = Class.forName(className, false, errorCheckerService.getSketchClassLoader()); } catch (ClassNotFoundException e) { - //System.out.println("Doesn't exist in package: "); + //log("Doesn't exist in package: "); } } return tehClass; @@ -1215,7 +1215,7 @@ public class ASTGenerator { public ClassMember definedIn3rdPartyClass(String className,String memberName){ Class probableClass = findClassIfExists(className); if (probableClass == null) { - System.out.println("Couldn't load " + className); + log("Couldn't load " + className); return null; } if (memberName.equals("THIS")) { @@ -1228,7 +1228,7 @@ public class ASTGenerator { public ClassMember definedIn3rdPartyClass(ClassMember tehClass,String memberName){ if(tehClass == null) return null; - System.out.println("definedIn3rdPartyClass-> Looking for " + memberName + log("definedIn3rdPartyClass-> Looking for " + memberName + " in " + tehClass); String memberNameL = memberName.toLowerCase(); if(tehClass.getDeclaringNode() instanceof TypeDeclaration){ @@ -1250,7 +1250,7 @@ public class ASTGenerator { return new ClassMember(td.getMethods()[i]); } if(td.getSuperclassType() instanceof Type){ - System.out.println(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); + log(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass); return definedIn3rdPartyClass(new ClassMember(td .getSuperclassType()),memberName); } @@ -1267,7 +1267,7 @@ public class ASTGenerator { else { probableClass = findClassIfExists(tehClass.getTypeAsString()); - System.out.println("Loaded " + probableClass.toString()); + log("Loaded " + probableClass.toString()); } for (Method method : probableClass.getMethods()) { if (method.getName().equalsIgnoreCase(memberName)) { @@ -1290,17 +1290,17 @@ public class ASTGenerator { methodmatch = methodmatch.substring(0, methodmatch.indexOf('(')); } - //System.out.println("jdoc match " + methodmatch); + //log("jdoc match " + methodmatch); for (final String key : jdocMap.keySet()) { if (key.startsWith(methodmatch) && key.length() > 3) { - System.out.println("Matched jdoc " + key); + log("Matched jdoc " + key); //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - System.out.println("Class: " + candidate.getDefiningClass()); + log("Class: " + candidate.getDefiningClass()); if (candidate.getDefiningClass().equals("processing.core.PApplet")) { javadocPane.setText(jdocMap.get(key)); //jdocWindow.setVisible(true); @@ -1332,7 +1332,7 @@ public class ASTGenerator { // .println(node.getStructuralProperty(prop) + " -> " + (prop)); if (node.getStructuralProperty(prop) instanceof ASTNode) { ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); -// System.out.println("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber); +// log("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber); int cLineNum = ((CompilationUnit) cnode.getRoot()) .getLineNumber(cnode.getStartPosition() + cnode.getLength()); if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { @@ -1348,7 +1348,7 @@ public class ASTGenerator { for (ASTNode cnode : nodelist) { int cLineNum = ((CompilationUnit) cnode.getRoot()) .getLineNumber(cnode.getStartPosition() + cnode.getLength()); -// System.out.println("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber); +// log("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber); if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) { return findClosestParentNode(lineNumber, cnode); } @@ -1480,7 +1480,7 @@ public class ASTGenerator { public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - System.out.println("----getASTNodeAt----"); + log("----getASTNodeAt----"); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -1493,10 +1493,10 @@ public class ASTGenerator { } } - System.out.println("FLON: " + lineNumber); + log("FLON: " + lineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); - System.out.println("+> " + lineNode); + log("+> " + lineNode); ASTNode decl = null; String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to @@ -1516,7 +1516,7 @@ public class ASTGenerator { } } } - System.out.println("FLON2: " + lineNumber + " LN spos " + log("FLON2: " + lineNumber + " LN spos " + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); /* * Now I need to see if multiple statements exist with this same line number @@ -1540,7 +1540,7 @@ public class ASTGenerator { + altOff && cnode.getStartPosition() + cnode.getLength() > lineNode .getStartPosition() + altOff) { - System.out.println(cnode); + log(cnode); offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); lineNode = cnode; altOff -= offAdjust; @@ -1552,14 +1552,14 @@ public class ASTGenerator { } } } - System.out.println("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + log("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); - System.out.println("+++> " + simpName); + log("+++> " + simpName); if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); - System.out.println(getNodeAsString(simpName)); + log(getNodeAsString(simpName)); decl = findDeclaration((SimpleName) simpName); if (decl != null) { System.err.println("DECLA: " + decl.getClass().getName()); @@ -1568,7 +1568,7 @@ public class ASTGenerator { } else System.err.println("null"); - System.out.println(getNodeAsString(decl)); + log(getNodeAsString(decl)); // - findDecl3 testing @@ -1577,10 +1577,10 @@ public class ASTGenerator { ClassMember cmem = resolveExpression3rdParty(nearestNode, (SimpleName) simpName, false); if(cmem != null){ - System.out.println("CMEM-> "+cmem); + log("CMEM-> "+cmem); } else - System.out.println("CMEM-> null"); + log("CMEM-> null"); } } @@ -1668,13 +1668,13 @@ public class ASTGenerator { parser.setCompilerOptions(options); CompilationUnit cu = (CompilationUnit) parser.createAST(null); - System.out.println(CompilationUnit.propertyDescriptors(AST.JLS4).size()); + log(CompilationUnit.propertyDescriptors(AST.JLS4).size()); DefaultMutableTreeNode astTree = new DefaultMutableTreeNode( "CompilationUnit"); System.err.println("Errors: " + cu.getProblems().length); visitRecur(cu, astTree); - System.out.println(astTree.getChildCount()); + log(astTree.getChildCount()); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); @@ -1692,7 +1692,7 @@ public class ASTGenerator { ASTNode found = NodeFinder.perform(cu, 468, 5); if (found != null) { - System.out.println(found); + log(found); } } @@ -1701,7 +1701,7 @@ public class ASTGenerator { @Override public void valueChanged(TreeSelectionEvent e) { - System.out.println(e); + log(e); SwingWorker worker = new SwingWorker() { @Override @@ -1774,7 +1774,7 @@ public class ASTGenerator { @Override public void valueChanged(TreeSelectionEvent e) { - System.out.println(e); + log(e); SwingWorker worker = new SwingWorker() { @Override @@ -1853,7 +1853,7 @@ public class ASTGenerator { editor.ta.setSelectedText(newName); } for (Integer lineNum : lineOffsetDisplacement.keySet()) { - System.out.println(lineNum + "line, disp" + log(lineNum + "line, disp" + lineOffsetDisplacement.get(lineNum)); } editor.getSketch().setModified(true); @@ -1865,7 +1865,7 @@ public class ASTGenerator { } public void handleShowUsage(){ - System.out.println("Last clicked word:" + lastClickedWord); + log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ editor.statusError("Highlight the class/function/variable name first"); return; @@ -1903,15 +1903,15 @@ public class ASTGenerator { public void setLastClickedWord(int lineNumber, String lastClickedWord, int offset) { this.lastClickedWord = lastClickedWord; lastClickedWordNode = getASTNodeAt(lineNumber, lastClickedWord, offset, false); - System.out.println("Last clicked node: " + lastClickedWordNode); + log("Last clicked node: " + lastClickedWordNode); } private DefaultMutableTreeNode findAllOccurrences(){ - System.out.println("Last clicked word:" + lastClickedWord); + log("Last clicked word:" + lastClickedWord); String selText = lastClickedWord == null ? editor.ta.getSelectedText() : lastClickedWord; int line = editor.ta.getSelectionStartLine(); - System.out.println(selText + log(selText + "<- offsets " + (line) + ", " @@ -1942,7 +1942,7 @@ public class ASTGenerator { ASTNode node = md.getParent(); while (node != null) { if (node instanceof TypeDeclaration) { - // System.out.println("Parent class " + getNodeAsString(node)); + // log("Parent class " + getNodeAsString(node)); break; } node = node.getParent(); @@ -1972,7 +1972,7 @@ public class ASTGenerator { while (!tempS.isEmpty()) { defCU.add((MutableTreeNode) tempS.pop()); } - System.out.println(wnode); + log(wnode); return defCU; } @@ -2040,7 +2040,7 @@ public class ASTGenerator { if(!(cnode.getUserObject() instanceof ASTNodeWrapper)) continue; ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); -// System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); +// log("Visiting: " + getNodeAsString(awnode.getNode())); if(isInstanceOfType(awnode.getNode(), decl, name)){ int val[] = errorCheckerService.JavaToPdeOffsets(awnode.getLineNumber(), 0); tnode.add(new DefaultMutableTreeNode(new ASTNodeWrapper(awnode @@ -2054,7 +2054,7 @@ public class ASTGenerator { public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ // Find the first node with this line number, return its offset - jOffset line = PdeToJavaLineNumber(line); - System.out.println("Looking for line: " + line + ", jOff " + jOffset); + log("Looking for line: " + line + ", jOff " + jOffset); Stack temp = new Stack(); temp.push(codeTree); @@ -2067,9 +2067,9 @@ public class ASTGenerator { if (!(cnode.getUserObject() instanceof ASTNodeWrapper)) continue; ASTNodeWrapper awnode = (ASTNodeWrapper) cnode.getUserObject(); -// System.out.println("Visiting: " + getNodeAsString(awnode.getNode())); +// log("Visiting: " + getNodeAsString(awnode.getNode())); if (awnode.getLineNumber() == line) { - System.out.println("First element with this line no is: " + awnode + log("First element with this line no is: " + awnode + "LSO: " + (jOffset - awnode.getNode().getStartPosition())); return (jOffset - awnode.getNode().getStartPosition()); } @@ -2098,7 +2098,7 @@ public class ASTGenerator { ArrayList nodesToBeMatched = new ArrayList(); nodesToBeMatched.add(decl); if(decl instanceof TypeDeclaration){ - System.out.println("decl is a TD"); + log("decl is a TD"); TypeDeclaration td = (TypeDeclaration)decl; MethodDeclaration[] mlist = td.getMethods(); for (MethodDeclaration md : mlist) { @@ -2107,10 +2107,10 @@ public class ASTGenerator { } } } - System.out.println("Visiting: " + getNodeAsString(node)); + log("Visiting: " + getNodeAsString(node)); ASTNode decl2 = findDeclaration(sn); System.err.println("It's decl: " + getNodeAsString(decl2)); - System.out.println("But we need: "+getNodeAsString(decl)); + log("But we need: "+getNodeAsString(decl)); for (ASTNode astNode : nodesToBeMatched) { if(astNode.equals(decl2)){ return true; @@ -2122,7 +2122,7 @@ public class ASTGenerator { } public void handleRefactor(){ - System.out.println("Last clicked word:" + lastClickedWord); + log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ editor.statusError("Highlight the class/function/variable name first"); return; @@ -2165,7 +2165,7 @@ public class ASTGenerator { // .println(node.getStructuralProperty(prop) + " -> " + (prop)); if (node.getStructuralProperty(prop) instanceof ASTNode) { ASTNode cnode = (ASTNode) node.getStructuralProperty(prop); - System.out.println(getNodeAsString(cnode)); + log(getNodeAsString(cnode)); printRecur(cnode); } } @@ -2175,7 +2175,7 @@ public class ASTGenerator { List nodelist = (List) node .getStructuralProperty(prop); for (ASTNode cnode : nodelist) { - System.out.println(getNodeAsString(cnode)); + log(getNodeAsString(cnode)); printRecur(cnode); } } @@ -2187,7 +2187,7 @@ public class ASTGenerator { int offset, String name) { CompilationUnit root = (CompilationUnit) node.getRoot(); -// System.out.println("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); +// log("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); if (root.getLineNumber(node.getStartPosition()) == lineNumber) { System.err .println(3 + getNodeAsString(node) + " len " + node.getLength()); @@ -2247,7 +2247,7 @@ public class ASTGenerator { if (node instanceof SimpleName) { SimpleName sn = (SimpleName) node; - System.out.println(offset+ "off,pol " + getNodeAsString(sn)); + log(offset+ "off,pol " + getNodeAsString(sn)); if ((lineStartOffset + offset) >= sn.getStartPosition() && (lineStartOffset + offset) <= sn.getStartPosition() + sn.getLength()) { @@ -2306,7 +2306,7 @@ public class ASTGenerator { // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. // To debug this code, thou must take the Recursive Leap of Faith. - System.out.println("entering --findDeclaration1 -- " + findMe.toString()); + log("entering --findDeclaration1 -- " + findMe.toString()); ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); ASTNode ret = null; @@ -2322,7 +2322,7 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("MI EXP: " + exp.toString() + " of type " + log("MI EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) @@ -2346,7 +2346,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration(stp.getName()); - System.out.println("MI.SN " + getNodeAsString(declaringClass)); + log("MI.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, ((MethodInvocation) parent) .getName().toString(), constrains, declaringClass); @@ -2364,7 +2364,7 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("FA EXP: " + exp.toString() + " of type " + log("FA EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp) @@ -2389,7 +2389,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration(stp.getName()); - System.out.println("FA.SN " + getNodeAsString(declaringClass)); + log("FA.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, fa.getName().toString(), constrains, declaringClass); @@ -2405,10 +2405,10 @@ public class ASTGenerator { if (!findMe.toString().equals(qn.getQualifier().toString())) { SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); - System.out.println(qn.getQualifier() + "->" + qn.getName()); + log(qn.getQualifier() + "->" + qn.getName()); declaringClass = findDeclaration(stp.getName()); - System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + log("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); @@ -2418,15 +2418,15 @@ public class ASTGenerator { else{ if(findMe instanceof QualifiedName){ QualifiedName qnn = (QualifiedName) findMe; - System.out.println("findMe is a QN, " + log("findMe is a QN, " + (qnn.getQualifier().toString() + " other " + qnn.getName() .toString())); SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); - System.out.println(qnn.getQualifier() + "->" + qnn.getName()); + log(qnn.getQualifier() + "->" + qnn.getName()); declaringClass = findDeclaration(stp.getName()); - System.out.println("QN decl class: " + log("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); @@ -2460,12 +2460,12 @@ public class ASTGenerator { // .toString())); // } while (parent != null) { - System.out.println("findDeclaration1 -> " + getNodeAsString(parent)); + log("findDeclaration1 -> " + getNodeAsString(parent)); for (Object oprop : parent.structuralPropertiesForType()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; if (prop.isChildProperty() || prop.isSimpleProperty()) { if (parent.getStructuralProperty(prop) instanceof ASTNode) { -// System.out.println(prop + " C/S Prop of -> " +// log(prop + " C/S Prop of -> " // + getNodeAsString(parent)); ret = definedIn((ASTNode) parent.getStructuralProperty(prop), findMe.toString(), constrains, declaringClass); @@ -2473,7 +2473,7 @@ public class ASTGenerator { return ret; } } else if (prop.isChildListProperty()) { -// System.out.println((prop) + " ChildList props of " +// log((prop) + " ChildList props of " // + getNodeAsString(parent)); List nodelist = (List) parent .getStructuralProperty(prop); @@ -2512,7 +2512,7 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("MI EXP: " + exp.toString() + " of type " + log("MI EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) @@ -2539,7 +2539,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println("MI.SN " + getNodeAsString(declaringClass)); + log("MI.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, ((MethodInvocation) parent) .getName().toString(), constrains, declaringClass); @@ -2558,7 +2558,7 @@ public class ASTGenerator { if (exp != null) { constrains.add(ASTNode.TYPE_DECLARATION); - System.out.println("FA EXP: " + exp.toString() + " of type " + log("FA EXP: " + exp.toString() + " of type " + exp.getClass().getName() + " parent: " + exp.getParent()); if (exp instanceof MethodInvocation) { SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp) @@ -2586,7 +2586,7 @@ public class ASTGenerator { if (stp == null) return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println("FA.SN " + getNodeAsString(declaringClass)); + log("FA.SN " + getNodeAsString(declaringClass)); constrains.add(ASTNode.METHOD_DECLARATION); return definedIn(declaringClass, fa.getName().toString(), constrains, declaringClass); @@ -2607,8 +2607,8 @@ public class ASTGenerator { if(stp == null) return null; declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println(qn.getQualifier() + "->" + qn.getName()); - System.out.println("QN decl class: " + getNodeAsString(declaringClass)); + log(qn.getQualifier() + "->" + qn.getName()); + log("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); constrains.add(ASTNode.FIELD_DECLARATION); @@ -2618,15 +2618,15 @@ public class ASTGenerator { else{ if(findMe instanceof QualifiedName){ QualifiedName qnn = (QualifiedName) findMe; - System.out.println("findMe is a QN, " + log("findMe is a QN, " + (qnn.getQualifier().toString() + " other " + qnn.getName() .toString())); SimpleType stp = extracTypeInfo(findDeclaration2((qnn.getQualifier()), alternateParent)); - System.out.println(qnn.getQualifier() + "->" + qnn.getName()); + log(qnn.getQualifier() + "->" + qnn.getName()); declaringClass = findDeclaration2(stp.getName(), alternateParent); - System.out.println("QN decl class: " + log("QN decl class: " + getNodeAsString(declaringClass)); constrains.clear(); constrains.add(ASTNode.TYPE_DECLARATION); @@ -2645,15 +2645,15 @@ public class ASTGenerator { // constrains.add(ASTNode.FIELD_DECLARATION); } // TODO: in findDec, we also have a case where parent of type TD is handled. // Figure out if needed here as well. - System.out.println("Alternate parent: " + getNodeAsString(alternateParent)); + log("Alternate parent: " + getNodeAsString(alternateParent)); while (alternateParent != null) { -// System.out.println("findDeclaration2 -> " +// log("findDeclaration2 -> " // + getNodeAsString(alternateParent)); for (Object oprop : alternateParent.structuralPropertiesForType()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop; if (prop.isChildProperty() || prop.isSimpleProperty()) { if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) { -// System.out.println(prop + " C/S Prop of -> " +// log(prop + " C/S Prop of -> " // + getNodeAsString(alternateParent)); ret = definedIn((ASTNode) alternateParent .getStructuralProperty(prop), @@ -2662,7 +2662,7 @@ public class ASTGenerator { return ret; } } else if (prop.isChildListProperty()) { -// System.out.println((prop) + " ChildList props of " +// log((prop) + " ChildList props of " // + getNodeAsString(alternateParent)); List nodelist = (List) alternateParent .getStructuralProperty(prop); @@ -2682,10 +2682,10 @@ public class ASTGenerator { private List getCodeComments(){ List commentList = compilationUnit.getCommentList(); -// System.out.println("Total comments: " + commentList.size()); +// log("Total comments: " + commentList.size()); // int i = 0; // for (Comment comment : commentList) { -// System.out.println(++i + ": "+comment + " Line:" +// log(++i + ": "+comment + " Line:" // + compilationUnit.getLineNumber(comment.getStartPosition()) + ", " // + comment.getLength()); // } @@ -2698,14 +2698,14 @@ public class ASTGenerator { - editor.textArea() .getLineStartNonWhiteSpaceOffset(editor.textArea().getCaretLine()); int x = pdeLine.indexOf("//"); - System.out.println(x + " , " + caretPos + ", Checking line for comment " + pdeLine); + log(x + " , " + caretPos + ", Checking line for comment " + pdeLine); //lineStartOffset = editor.textArea(). if (x >= 0 && caretPos > x) { - System.out.println("INSIDE a comment"); + log("INSIDE a comment"); return true; } - System.out.println("not within comment"); + log("not within comment"); return false; } @@ -2835,7 +2835,7 @@ public class ASTGenerator { return null; } else if (t instanceof ArrayType) { ArrayType at = (ArrayType) t; - System.out.println(at.getComponentType() + " <-comp type, ele type-> " + log(at.getComponentType() + " <-comp type, ele type-> " + at.getElementType() + ", " + at.getElementType().getClass().getName()); if (at.getElementType() instanceof PrimitiveType) { @@ -2846,7 +2846,7 @@ public class ASTGenerator { return null; } else if (t instanceof ParameterizedType) { ParameterizedType pmt = (ParameterizedType) t; - System.out.println(pmt.getType() + ", " + pmt.getType().getClass()); + log(pmt.getType() + ", " + pmt.getType().getClass()); if (pmt.getType() instanceof SimpleType) { return (SimpleType) pmt.getType(); } else @@ -2872,7 +2872,7 @@ public class ASTGenerator { case ASTNode.VARIABLE_DECLARATION_FRAGMENT: return extracTypeInfo2(node.getParent()); } - System.out.println("Unknown type info request " + getNodeAsString(node)); + log("Unknown type info request " + getNodeAsString(node)); return null; } @@ -2883,14 +2883,14 @@ public class ASTGenerator { if (node == null) return null; if (constrains != null) { -// System.out.println("Looking at " + getNodeAsString(node) + " for " + name +// log("Looking at " + getNodeAsString(node) + " for " + name // + " in definedIn"); if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) { // System.err.print("definedIn -1 " + " But constrain was "); // for (Integer integer : constrains) { // System.out.print(ASTNode.nodeClassForType(integer) + ","); // } -// System.out.println(); +// log(); return null; } } @@ -2899,7 +2899,7 @@ public class ASTGenerator { switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: - System.err.println(getNodeAsString(node)); + //System.err.println(getNodeAsString(node)); TypeDeclaration td = (TypeDeclaration) node; if (td.getName().toString().equals(name)) { if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) { @@ -2907,7 +2907,7 @@ public class ASTGenerator { MethodDeclaration[] methods = td.getMethods(); for (MethodDeclaration md : methods) { if (md.getName().toString().equalsIgnoreCase(name)) { - System.out.println("Found a constructor."); + log("Found a constructor."); return md; } } @@ -2938,25 +2938,25 @@ public class ASTGenerator { } break; case ASTNode.METHOD_DECLARATION: - System.err.println(getNodeAsString(node)); + //System.err.println(getNodeAsString(node)); if (((MethodDeclaration) node).getName().toString().equalsIgnoreCase(name)) return node; break; case ASTNode.SINGLE_VARIABLE_DECLARATION: - System.err.println(getNodeAsString(node)); + //System.err.println(getNodeAsString(node)); if (((SingleVariableDeclaration) node).getName().toString().equalsIgnoreCase(name)) return node; break; case ASTNode.FIELD_DECLARATION: - System.err.println("FD" + node); + //System.err.println("FD" + node); vdfList = ((FieldDeclaration) node).fragments(); break; case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - System.err.println("VDE" + node); + //System.err.println("VDE" + node); vdfList = ((VariableDeclarationExpression) node).fragments(); break; case ASTNode.VARIABLE_DECLARATION_STATEMENT: - System.err.println("VDS" + node); + //System.err.println("VDS" + node); vdfList = ((VariableDeclarationStatement) node).fragments(); break; @@ -2976,7 +2976,7 @@ public class ASTGenerator { if(frmImportSuggest != null) if(frmImportSuggest.isVisible()) return; - System.out.println("Looking for class " + className); + log("Looking for class " + className); RegExpResourceFilter regf = new RegExpResourceFilter( Pattern.compile(".*"), Pattern @@ -2986,7 +2986,7 @@ public class ASTGenerator { String[] resources = classPath .findResources("", regf); if(resources.length == 0){ - System.out.println("Couldn't find import for class " + className); + log("Couldn't find import for class " + className); return; } for (int i = 0; i < resources.length; i++) { @@ -3021,7 +3021,7 @@ public class ASTGenerator { frmImportSuggest.setVisible(false); frmImportSuggest = null; } catch (BadLocationException e) { - System.out.println("Failed to insert import for " + className); + log("Failed to insert import for " + className); e.printStackTrace(); } } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 83ffd719c..30d3ab616 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -147,6 +147,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ public JCheckBoxMenuItem problemWindowMenuCB; + /** + * Enable/Disable debug ouput + */ + protected JCheckBoxMenuItem debugMessagesEnabled; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -322,7 +327,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { for (int i = 0; i < ip.getArguments().length; i++) { sbuff.append(ip.getArguments()[i]); if(i < ip.getArguments().length - 1) - sbuff.append('|'); + sbuff.append("| "); } sbuff.append("}"); sbuff.append(','); @@ -497,6 +502,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { }); debugMenu.add(showWarnings); + debugMessagesEnabled = new JCheckBoxMenuItem("Show Debug Messages"); + debugMessagesEnabled.setSelected(ExperimentalMode.DEBUG); + debugMessagesEnabled.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ExperimentalMode.DEBUG = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); + } + }); + debugMenu.add(debugMessagesEnabled); return debugMenu; } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 0401ed974..3a73b03c5 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1,5 +1,7 @@ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; + import java.awt.EventQueue; import java.io.File; import java.io.FileFilter; @@ -250,7 +252,7 @@ public class ErrorCheckerService implements Runnable{ // Take a nap. Thread.sleep(sleepTime); } catch (Exception e) { - System.out.println("Oops! [ErrorCheckerThreaded]: " + e); + log("Oops! [ErrorCheckerThreaded]: " + e); // e.printStackTrace(); } @@ -273,7 +275,7 @@ public class ErrorCheckerService implements Runnable{ int idx = p.getMessage().indexOf(" cannot be resolved to a type"); if(idx > 1){ String missingClass = p.getMessage().substring(0, idx); - //System.out.println("Will suggest for type:" + missingClass); + //log("Will suggest for type:" + missingClass); astGenerator.suggestImports(missingClass); } } @@ -291,13 +293,14 @@ public class ErrorCheckerService implements Runnable{ } private boolean checkCode() { - System.out.println("checkCode() " + textModified.get() ); + //log("checkCode() " + textModified.get() ); + log("checkCode() " + textModified.get()); lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); syntaxCheck(); - System.out.println(editor.getSketch().getName() + "1 MCO " + log(editor.getSketch().getName() + "1 MCO " + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. @@ -311,10 +314,10 @@ public class ErrorCheckerService implements Runnable{ // if (staticMode) { // mainClassOffset++; // Extra line for setup() decl. // } - // System.out.println(sourceCode); - // System.out.println("--------------------------"); + // log(sourceCode); + // log("--------------------------"); compileCheck(); - System.out.println(editor.getSketch().getName() + "2 MCO " + log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } @@ -324,7 +327,7 @@ public class ErrorCheckerService implements Runnable{ editor.getTextArea().repaint(); updatePaintedThingys(); int x = textModified.get(); - //System.out.println("TM " + x); + //log("TM " + x); if(x>=3){ textModified.set(3); x = 3; @@ -337,7 +340,7 @@ public class ErrorCheckerService implements Runnable{ return true; } catch (Exception e) { - System.out.println("Oops! [ErrorCheckerService.checkCode]: " + e); + log("Oops! [ErrorCheckerService.checkCode]: " + e); e.printStackTrace(); } return false; @@ -367,7 +370,7 @@ public class ErrorCheckerService implements Runnable{ // Store errors returned by the ast parser problems = cu.getProblems(); - // System.out.println("Problem Count: " + problems.length); + // log("Problem Count: " + problems.length); // Populate the probList problemsList = new ArrayList(); for (int i = 0; i < problems.length; i++) { @@ -375,11 +378,11 @@ public class ErrorCheckerService implements Runnable{ Problem p = new Problem(problems[i], a[0], a[1] + 1); //TODO: ^Why do cheeky stuff? problemsList.add(p); - System.out.println(problems[i].getMessage()); + log(problems[i].getMessage()); for (String j : problems[i].getArguments()) { - System.out.println("arg " + j); + log("arg " + j); } - // System.out.println(p.toString()); + // log(p.toString()); } if (problems.length == 0) @@ -426,7 +429,7 @@ public class ErrorCheckerService implements Runnable{ }; File[] jarFiles = f.listFiles(fileFilter); - // System.out.println( "Jar files found? " + (jarFiles != null)); + // log( "Jar files found? " + (jarFiles != null)); //for (File jarFile : jarFiles) { //classpathJars.add(jarFile.toURI().toURL()); //} @@ -440,12 +443,12 @@ public class ErrorCheckerService implements Runnable{ classpath[ii++] = jarFiles[i].toURI().toURL(); } - // System.out.println("CP Len -- " + classpath.length); + // log("CP Len -- " + classpath.length); classLoader = new URLClassLoader(classpath); - // System.out.println("1."); + // log("1."); checkerClass = Class.forName("CompilationChecker", true, classLoader); - // System.out.println("2."); + // log("2."); compilationChecker = checkerClass.newInstance(); astGenerator.loadJars(); // Update jar files for completition list @@ -488,9 +491,9 @@ public class ErrorCheckerService implements Runnable{ // + problems[i].isWarning()); IProblem problem = problems[i]; - System.out.println(problem.getMessage()); + log(problem.getMessage()); for (String j : problem.getArguments()) { - System.out.println("arg " + j); + log("arg " + j); } int a[] = calculateTabIndexAndLineNumber(problem); Problem p = new Problem(problem, a[0], a[1]); @@ -527,7 +530,7 @@ public class ErrorCheckerService implements Runnable{ + " compileCheck() problem. Somebody tried to mess with Experimental Mode files."); stopThread(); } - // System.out.println("Compilecheck, Done."); + // log("Compilecheck, Done."); } public URLClassLoader getSketchClassLoader() { @@ -546,7 +549,7 @@ public class ErrorCheckerService implements Runnable{ return; } - // System.out.println("1.."); + // log("1.."); classpathJars = new ArrayList(); String entry = ""; boolean codeFolderChecked = false; @@ -556,9 +559,9 @@ public class ErrorCheckerService implements Runnable{ entry = (dot == -1) ? item : item.substring(0, dot); entry = entry.substring(6).trim(); - // System.out.println("Entry--" + entry); + // log("Entry--" + entry); if (ignorableImport(entry)) { - // System.out.println("Ignoring: " + entry); + // log("Ignoring: " + entry); continue; } Library library = null; @@ -566,22 +569,22 @@ public class ErrorCheckerService implements Runnable{ // Try to get the library classpath and add it to the list try { library = editor.getMode().getLibrary(entry); - // System.out.println("lib->" + library.getClassPath() + "<-"); + // log("lib->" + library.getClassPath() + "<-"); String libraryPath[] = PApplet.split(library.getClassPath() .substring(1).trim(), File.pathSeparatorChar); for (int i = 0; i < libraryPath.length; i++) { - // System.out.println(entry + " ::" + // log(entry + " ::" // + new File(libraryPath[i]).toURI().toURL()); classpathJars.add(new File(libraryPath[i]).toURI().toURL()); } - // System.out.println("-- "); + // log("-- "); // classpath[count] = (new File(library.getClassPath() // .substring(1))).toURI().toURL(); - // System.out.println(" found "); - // System.out.println(library.getClassPath().substring(1)); + // log(" found "); + // log(library.getClassPath().substring(1)); } catch (Exception e) { if (library == null && !codeFolderChecked) { - // System.out.println(1); + // log(1); // Look around in the code folder for jar files if (editor.getSketch().hasCodeFolder()) { File codeFolder = editor.getSketch().getCodeFolder(); @@ -742,7 +745,7 @@ public class ErrorCheckerService implements Runnable{ } } catch (Exception e) { - System.out.println("Exception at updateErrorTable() " + e); + log("Exception at updateErrorTable() " + e); e.printStackTrace(); stopThread(); } @@ -755,7 +758,7 @@ public class ErrorCheckerService implements Runnable{ public void updatePaintedThingys() { currentTab = editor.getSketch().getCodeIndex( editor.getSketch().getCurrentCode()); - //System.out.println("Tab changed " + currentTab + " LT " + lastTab); + //log("Tab changed " + currentTab + " LT " + lastTab); if (currentTab != lastTab) { textModified.set(5); lastTab = currentTab; @@ -810,13 +813,13 @@ public class ErrorCheckerService implements Runnable{ int x = line - mainClassOffset; if (x < 0) { - // System.out.println("Negative line number " + // log("Negative line number " // + problem.getSourceLineNumber() + " , offset " // + mainClassOffset); x = line - 2; // Another -1 for 0 index if (x < programImports.size() && x >= 0) { ImportStatement is = programImports.get(x); - // System.out.println(is.importName + ", " + is.tab + ", " + // log(is.importName + ", " + is.tab + ", " // + is.lineNumber); return new int[] { is.getTab(), is.getLineNumber() }; } else { @@ -839,7 +842,7 @@ public class ErrorCheckerService implements Runnable{ len = Base.countLines(sc.getProgram()) + 1; } - // System.out.println("x,len, CI: " + x + "," + len + "," + // log("x,len, CI: " + x + "," + len + "," // + codeIndex); if (x >= len) { @@ -848,7 +851,7 @@ public class ErrorCheckerService implements Runnable{ // than the no. // of lines in the tab, if (codeIndex >= editor.getSketch().getCodeCount() - 1) { - // System.out.println("Exceeds lc " + x + "," + len + // log("Exceeds lc " + x + "," + len // + problem.toString()); // x = len x = editor.getSketch().getCode(codeIndex) @@ -896,13 +899,13 @@ public class ErrorCheckerService implements Runnable{ int x = problem.getSourceLineNumber() - mainClassOffset; if (x < 0) { - // System.out.println("Negative line number " + // log("Negative line number " // + problem.getSourceLineNumber() + " , offset " // + mainClassOffset); x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index if (x < programImports.size() && x >= 0) { ImportStatement is = programImports.get(x); - // System.out.println(is.importName + ", " + is.tab + ", " + // log(is.importName + ", " + is.tab + ", " // + is.lineNumber); return new int[] { is.getTab(), is.getLineNumber() }; } else { @@ -925,7 +928,7 @@ public class ErrorCheckerService implements Runnable{ len = Base.countLines(sc.getProgram()) + 1; } - // System.out.println("x,len, CI: " + x + "," + len + "," + // log("x,len, CI: " + x + "," + len + "," // + codeIndex); if (x >= len) { @@ -934,7 +937,7 @@ public class ErrorCheckerService implements Runnable{ // than the no. // of lines in the tab, if (codeIndex >= editor.getSketch().getCodeCount() - 1) { - // System.out.println("Exceeds lc " + x + "," + len + // log("Exceeds lc " + x + "," + len // + problem.toString()); // x = len x = editor.getSketch().getCode(codeIndex) @@ -1015,7 +1018,7 @@ public class ErrorCheckerService implements Runnable{ } } catch (Exception e) { - System.out.println("Exception in preprocessCode()"); + log("Exception in preprocessCode()"); } String sourceAlt = rawCode.toString(); // Replace comments with whitespaces @@ -1034,8 +1037,8 @@ public class ErrorCheckerService implements Runnable{ // while (matcher.find()) { // System.out.print("Start index: " + matcher.start()); - // System.out.println(" End index: " + matcher.end() + " "); - // System.out.println("-->" + matcher.group() + "<--"); + // log(" End index: " + matcher.end() + " "); + // log("-->" + matcher.group() + "<--"); // } sourceAlt = matcher.replaceAll("PApplet.parse" + Character.toUpperCase(dataType.charAt(0)) @@ -1049,10 +1052,10 @@ public class ErrorCheckerService implements Runnable{ Pattern webPattern = Pattern.compile(webColorRegexp); Matcher webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); + // log("Found at: " + webMatcher.start()); String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); - // System.out.println("-> " + found); + // log("-> " + found); sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); webMatcher = webPattern.matcher(sourceAlt); } @@ -1099,8 +1102,8 @@ public class ErrorCheckerService implements Runnable{ // Handle unicode characters sourceAlt = substituteUnicode(sourceAlt); -// System.out.println("-->\n" + sourceAlt + "\n<--"); -// System.out.println("PDE code processed - " +// log("-->\n" + sourceAlt + "\n<--"); +// log("PDE code processed - " // + editor.getSketch().getName()); sourceCode = sourceAlt; return sourceAlt; @@ -1174,7 +1177,7 @@ public class ErrorCheckerService implements Runnable{ + " : Error while selecting text in scrollToErrorLine()"); e.printStackTrace(); } - // System.out.println("---"); + // log("---"); } /** @@ -1203,7 +1206,7 @@ public class ErrorCheckerService implements Runnable{ edt.setSelection(lsno, lsno + length); edt.getTextArea().scrollTo(lineNoInTab - 1, 0); edt.repaint(); - System.out.println(lineStartOffset + " LSO,len " + length); + log(lineStartOffset + " LSO,len " + length); } catch (Exception e) { System.err.println(e + " : Error while selecting text in static scrollToErrorLine()"); @@ -1218,25 +1221,25 @@ public class ErrorCheckerService implements Runnable{ * compiler classpath needs to be updated. */ private void checkForChangedImports() { - // System.out.println("Imports: " + programImports.size() + + // log("Imports: " + programImports.size() + // " Prev Imp: " // + previousImports.size()); if (programImports.size() != previousImports.size()) { - // System.out.println(1); + // log(1); loadCompClass = true; previousImports = programImports; } else { for (int i = 0; i < programImports.size(); i++) { if (!programImports.get(i).getImportName().equals(previousImports .get(i).getImportName())) { - // System.out.println(2); + // log(2); loadCompClass = true; previousImports = programImports; break; } } } - // System.out.println("load..? " + loadCompClass); + // log("load..? " + loadCompClass); } private int pdeImportsCount; @@ -1260,7 +1263,7 @@ public class ErrorCheckerService implements Runnable{ pdeImportsCount = 0; String tabSource = new String(tabProgram); do { - // System.out.println("-->\n" + sourceAlt + "\n<--"); + // log("-->\n" + sourceAlt + "\n<--"); String[] pieces = PApplet.match(tabSource, importRegexp); // Stop the loop if we've removed all the import lines @@ -1276,7 +1279,7 @@ public class ErrorCheckerService implements Runnable{ // find index of this import in the program int idx = tabSource.indexOf(piece); // System.out.print("Import -> " + piece); - // System.out.println(" - " + // log(" - " // + Base.countLines(tabSource.substring(0, idx)) + " tab " // + tabNumber); programImports.add(new ImportStatement(piece, tabNumber, Base @@ -1291,7 +1294,7 @@ public class ErrorCheckerService implements Runnable{ + tabSource.substring(idx + len); pdeImportsCount++; } while (true); - // System.out.println(tabSource); + // log(tabSource); return tabSource; } @@ -1368,6 +1371,16 @@ public class ErrorCheckerService implements Runnable{ return editor; } +// public static void log(String message){ +// if(ExperimentalMode.DEBUG) +// log(message); +// } +// +// public static void log2(String message){ +// if(ExperimentalMode.DEBUG) +// System.out.print(message); +// } + public ArrayList getProgramImports() { return programImports; } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 50d7ce4b3..d40c0346f 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -43,7 +43,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - + public static boolean DEBUG = true; public ExperimentalMode(Base base, File folder) { super(base, folder); @@ -101,7 +101,7 @@ public class ExperimentalMode extends JavaMode { @Override public String getTitle() { - return "Experimental"; + return "PDE X"; } @@ -168,4 +168,20 @@ public class ExperimentalMode extends JavaMode { // badness return null; } + + /* + * System.out.println + */ + public static final void log(Object message){ + if(ExperimentalMode.DEBUG) + System.out.println(message); + } + + /* + * System.out.print + */ + public static final void log2(String message){ + if(ExperimentalMode.DEBUG) + System.out.print(message); + } } From 145206f6172b3cf35dd059c6e4fd6cc63b09f678 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 17:50:58 +0530 Subject: [PATCH 152/608] more of toggling console o/p --- .../mode/experimental/ASTNodeWrapper.java | 65 ++++++++++--------- .../experimental/CompletionCandidate.java | 4 +- .../mode/experimental/CompletionPanel.java | 12 ++-- .../mode/experimental/ExperimentalMode.java | 6 +- .../mode/experimental/TextArea.java | 37 +++++------ .../mode/experimental/TextAreaPainter.java | 27 ++++---- 6 files changed, 74 insertions(+), 77 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 201b2b58d..6201bdcd0 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -1,5 +1,6 @@ package processing.mode.experimental; - +import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.log2; import java.util.Iterator; import java.util.List; import java.util.TreeMap; @@ -110,7 +111,7 @@ public class ASTNodeWrapper { if (getLineNumber(cnode) == lineNumber) { if (flag) { altStartPos = cnode.getStartPosition(); - // System.out.println("multi..."); + // log("multi..."); flag = false; } else { @@ -128,7 +129,7 @@ public class ASTNodeWrapper { } } } - System.out.println("Altspos " + altStartPos); + log("Altspos " + altStartPos); int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); @@ -170,7 +171,7 @@ public class ASTNodeWrapper { pi++; int startoffDif = pi - pj; int stopindex = javaCodeMap[pj + nodeLen - 1]; - System.out.println(startIndex + "SI,St" + stopindex + "sod " + startoffDif); + log(startIndex + "SI,St" + stopindex + "sod " + startoffDif); // count till stopindex while (pdeCodeMap[pi] < stopindex && pi < pdeCodeMap.length) { @@ -178,9 +179,9 @@ public class ASTNodeWrapper { count++; } -// System.out.println("PDE maps from " + pdeeCodeMap[pi]); +// log("PDE maps from " + pdeeCodeMap[pi]); - System.out.println("pde len " + count); + log("pde len " + count); return new int[] { startoffDif, count }; } @@ -220,7 +221,7 @@ public class ASTNodeWrapper { * TODO: This is a work in progress. There may be more bugs here in hiding. */ - System.out.println("Src:" + source); + log("Src:" + source); String sourceAlt = new String(source); TreeMap offsetmap = new TreeMap(); @@ -230,8 +231,8 @@ public class ASTNodeWrapper { Pattern webPattern = Pattern.compile(webColorRegexp); Matcher webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - // System.out.println("-> " + found); + // log("Found at: " + webMatcher.start()); + // log("-> " + found); offsetmap.put(webMatcher.end() - 1, 3); } @@ -241,8 +242,8 @@ public class ASTNodeWrapper { Matcher colorMatcher = colorPattern.matcher(sourceAlt); while (colorMatcher.find()) { // System.out.print("Start index: " + colorMatcher.start()); -// System.out.println(" End index: " + colorMatcher.end() + " "); -// System.out.println("-->" + colorMatcher.group() + "<--"); +// log(" End index: " + colorMatcher.end() + " "); +// log("-->" + colorMatcher.group() + "<--"); offsetmap.put(colorMatcher.end() - 1, -2); } @@ -256,8 +257,8 @@ public class ASTNodeWrapper { while (matcher.find()) { // System.out.print("Start index: " + matcher.start()); -// System.out.println(" End index: " + matcher.end() + " "); -// System.out.println("-->" + matcher.group() + "<--"); +// log(" End index: " + matcher.end() + " "); +// log("-->" + matcher.group() + "<--"); offsetmap.put(matcher.end() - 1, ("PApplet.parse").length()); } matcher.reset(); @@ -267,15 +268,15 @@ public class ASTNodeWrapper { } if(offsetmap.isEmpty()){ - System.out.println("No offset matching needed."); + log("No offset matching needed."); return null; } // replace with 0xff[webcolor] and others webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); + // log("Found at: " + webMatcher.start()); String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); - // System.out.println("-> " + found); + // log("-> " + found); sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); webMatcher = webPattern.matcher(sourceAlt); } @@ -283,7 +284,7 @@ public class ASTNodeWrapper { colorMatcher = colorPattern.matcher(sourceAlt); sourceAlt = colorMatcher.replaceAll("int"); - System.out.println(sourceAlt); + log(sourceAlt); // Create code map. Beware! Dark magic ahead. int javaCodeMap[] = new int[source.length() * 2]; @@ -298,7 +299,7 @@ public class ASTNodeWrapper { pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; } - System.out.println(key + ":" + offsetmap.get(key)); + log(key + ":" + offsetmap.get(key)); int kval = offsetmap.get(key); if (kval > 0) { @@ -341,14 +342,14 @@ public class ASTNodeWrapper { if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { if (i < source.length()) System.out.print(source.charAt(i)); - System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]); + log2(pdeCodeMap[i] + " - " + javaCodeMap[i]); if (i < sourceAlt.length()) System.out.print(sourceAlt.charAt(i)); - System.out.print(" <-[" + i + "]"); - System.out.println(); + log2(" <-[" + i + "]"); + log(""); } } - System.out.println(); + log(""); return new int[][]{javaCodeMap,pdeCodeMap}; } @@ -398,7 +399,7 @@ public class ASTNodeWrapper { * @return */ public static String getJavaCode(String source){ - System.out.println("Src:" + source); + log("Src:" + source); String sourceAlt = new String(source); // Find all #[web color] @@ -407,8 +408,8 @@ public class ASTNodeWrapper { Pattern webPattern = Pattern.compile(webColorRegexp); Matcher webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); - // System.out.println("-> " + found); + // log("Found at: " + webMatcher.start()); + // log("-> " + found); } // Find all color data types @@ -417,8 +418,8 @@ public class ASTNodeWrapper { Matcher colorMatcher = colorPattern.matcher(sourceAlt); while (colorMatcher.find()) { // System.out.print("Start index: " + colorMatcher.start()); -// System.out.println(" End index: " + colorMatcher.end() + " "); -// System.out.println("-->" + colorMatcher.group() + "<--"); +// log(" End index: " + colorMatcher.end() + " "); +// log("-->" + colorMatcher.group() + "<--"); } // Find all int(), char() @@ -431,8 +432,8 @@ public class ASTNodeWrapper { while (matcher.find()) { // System.out.print("Start index: " + matcher.start()); -// System.out.println(" End index: " + matcher.end() + " "); -// System.out.println("-->" + matcher.group() + "<--"); +// log(" End index: " + matcher.end() + " "); +// log("-->" + matcher.group() + "<--"); } matcher.reset(); sourceAlt = matcher.replaceAll("PApplet.parse" @@ -443,9 +444,9 @@ public class ASTNodeWrapper { // replace with 0xff[webcolor] and others webMatcher = webPattern.matcher(sourceAlt); while (webMatcher.find()) { - // System.out.println("Found at: " + webMatcher.start()); + // log("Found at: " + webMatcher.start()); String found = sourceAlt.substring(webMatcher.start(), webMatcher.end()); - // System.out.println("-> " + found); + // log("-> " + found); sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1)); webMatcher = webPattern.matcher(sourceAlt); } @@ -453,7 +454,7 @@ public class ASTNodeWrapper { colorMatcher = colorPattern.matcher(sourceAlt); sourceAlt = colorMatcher.replaceAll("int"); - System.out.println("Converted:"+sourceAlt); + log("Converted:"+sourceAlt); return sourceAlt; } diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 36791e518..6fa6fb096 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -1,5 +1,5 @@ package processing.mode.experimental; - +import static processing.mode.experimental.ExperimentalMode.log; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; @@ -64,7 +64,7 @@ public class CompletionCandidate implements Comparable{ } public CompletionCandidate(MethodDeclaration method) { - System.out.println("ComCan " + method.getName()); + // log("ComCan " + method.getName()); elementName = method.getName().toString(); type = LOCAL_METHOD; List params = (List) method diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index e9a07b01d..b5c795078 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -1,4 +1,5 @@ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; import java.awt.BorderLayout; import java.awt.Color; @@ -12,7 +13,6 @@ import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; -import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.text.BadLocationException; @@ -51,7 +51,7 @@ public class CompletionPanel { .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - System.out.println("Suggestion constructed" + System.nanoTime()); + log("Suggestion constructed" + System.nanoTime()); } public boolean isVisible() { @@ -59,7 +59,7 @@ public class CompletionPanel { } public void setVisible(boolean v){ - System.out.println("Pred popup visible."); + log("Pred popup visible."); popupMenu.setVisible(v); } @@ -96,7 +96,7 @@ public class CompletionPanel { if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); insertionPosition = position; - System.out.println("Suggestion updated" + System.nanoTime()); + log("Suggestion updated" + System.nanoTime()); return true; } @@ -115,7 +115,7 @@ public class CompletionPanel { if(!selectedSuggestion.endsWith("()")){ int x = selectedSuggestion.indexOf('('); if(x != -1){ - //System.out.println("X................... " + x); + //log("X................... " + x); textarea.setCaretPosition(insertionPosition + (x+1)); } } @@ -134,7 +134,7 @@ public class CompletionPanel { public void hideSuggestion() { popupMenu.setVisible(false); - System.out.println("Suggestion hidden" + System.nanoTime()); + log("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index d40c0346f..f47005fb7 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -94,7 +94,7 @@ public class ExperimentalMode extends JavaMode { // // output version from manifest file // Package p = ExperimentalMode.class.getPackage(); // String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; -// //System.out.println(titleAndVersion); +// //log(titleAndVersion); // Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); } @@ -152,7 +152,7 @@ public class ExperimentalMode extends JavaMode { if (newColor != null) { return newColor; } - System.out.println("error loading color: " + attribute); + log("error loading color: " + attribute); Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); return defaultValue; } @@ -170,7 +170,7 @@ public class ExperimentalMode extends JavaMode { } /* - * System.out.println + * log */ public static final void log(Object message){ if(ExperimentalMode.DEBUG) diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 40feea600..c7a3693ab 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -16,6 +16,7 @@ * Place - Suite 330, Boston, MA 02111-1307, USA. */ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; import java.awt.Color; import java.awt.Cursor; @@ -32,11 +33,9 @@ import java.util.Map; import javax.swing.DefaultListModel; import javax.swing.SwingUtilities; -import javax.swing.text.BadLocationException; import processing.app.syntax.JEditTextArea; import processing.app.syntax.TextAreaDefaults; - /** * Customized text area. Adds support for line background colors. * @@ -131,7 +130,7 @@ public class TextArea extends JEditTextArea { if(evt.getKeyCode() == KeyEvent.VK_ESCAPE){ if(suggestion != null){ if(suggestion.isVisible()){ - System.out.println("esc key"); + log("esc key"); hideSuggestion(); evt.consume(); return; @@ -156,7 +155,7 @@ public class TextArea extends JEditTextArea { case KeyEvent.VK_DOWN: if (suggestion != null) if (suggestion.isVisible()) { - //System.out.println("KeyDown"); + //log("KeyDown"); suggestion.moveDown(); return; } @@ -164,7 +163,7 @@ public class TextArea extends JEditTextArea { case KeyEvent.VK_UP: if (suggestion != null) if (suggestion.isVisible()) { - //System.out.println("KeyUp"); + //log("KeyUp"); suggestion.moveUp(); return; } @@ -191,7 +190,7 @@ public class TextArea extends JEditTextArea { // } // break; case KeyEvent.VK_BACK_SPACE: - System.out.println("BK Key"); + log("BK Key"); break; default: break; @@ -202,13 +201,13 @@ public class TextArea extends JEditTextArea { /* if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { if (suggestion.isVisible()) { - //System.out.println("KeyDown"); + //log("KeyDown"); suggestion.moveDown(); return; } } else if (evt.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { if (suggestion.isVisible()) { - //System.out.println("KeyUp"); + //log("KeyUp"); suggestion.moveUp(); return; } @@ -233,14 +232,14 @@ public class TextArea extends JEditTextArea { } } } else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) { - System.out.println("BK Key"); + log("BK Key"); } }*/ if (evt.getID() == KeyEvent.KEY_TYPED) { errorCheckerService.runManualErrorCheck(); - System.out.println(" Typing: " + fetchPhrase(evt) + " " + log(" Typing: " + fetchPhrase(evt) + " " + (evt.getKeyChar() == KeyEvent.VK_ENTER)); } @@ -250,7 +249,7 @@ public class TextArea extends JEditTextArea { private String fetchPhrase(MouseEvent evt) { - System.out.println("--handle Mouse Right Click--"); + log("--handle Mouse Right Click--"); int off = xyToOffset(evt.getX(), evt.getY()); if (off < 0) return null; @@ -265,7 +264,7 @@ public class TextArea extends JEditTextArea { else { int x = xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; int xLS = off - getLineStartNonWhiteSpaceOffset(line); - System.out.println("x=" + x); + log("x=" + x); if (x < 0 || x >= s.length()) return null; String word = s.charAt(x) + ""; @@ -304,7 +303,7 @@ public class TextArea extends JEditTextArea { } if (Character.isDigit(word.charAt(0))) return null; - System.out.println("Mouse click, word: " + word.trim()); + log("Mouse click, word: " + word.trim()); errorCheckerService.astGenerator.setLastClickedWord(line + errorCheckerService.mainClassOffset, word, xLS); return word.trim(); @@ -314,13 +313,13 @@ public class TextArea extends JEditTextArea { if (evt != null) { char keyChar = evt.getKeyChar(); if (keyChar == KeyEvent.VK_ENTER) { - //System.out.println("Enter keypress."); + //log("Enter keypress."); return null; } // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) // ; // accepted these keys else if (keyChar == KeyEvent.VK_ESCAPE) { - //System.out.println("ESC keypress. fetchPhrase()"); + //log("ESC keypress. fetchPhrase()"); return null; } else if (keyChar == KeyEvent.CHAR_UNDEFINED) { return null; @@ -448,9 +447,9 @@ public class TextArea extends JEditTextArea { */ protected int getGutterWidth() { FontMetrics fm = painter.getFontMetrics(); -// System.out.println("fm: " + (fm == null)); -// System.out.println("editor: " + (editor == null)); - //System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null)); +// log("fm: " + (fm == null)); +// log("editor: " + (editor == null)); + //log("BPBPBPBPB: " + (editor.breakpointMarker == null)); int textWidth = Math.max(fm.stringWidth(breakpointMarker), fm.stringWidth(currentLineMarker)); @@ -750,7 +749,7 @@ public class TextArea extends JEditTextArea { protected void showSuggestion(DefaultListModel defListModel,String subWord) { if (defListModel.size() == 0) { - System.out.println("TextArea: No suggestions to show."); + log("TextArea: No suggestions to show."); hideSuggestion(); return; } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index b1ab4a029..d2e58ebb7 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -16,16 +16,13 @@ * Place - Suite 330, Boston, MA 02111-1307, USA. */ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; import java.awt.Color; import java.awt.Graphics; import java.awt.Toolkit; -import java.awt.event.InputEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; import javax.swing.text.BadLocationException; import javax.swing.text.Segment; @@ -74,7 +71,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { ta = textArea; addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { -// System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); +// log( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask)); if (evt.getButton() == MouseEvent.BUTTON1) { if (evt.isControlDown() || evt.isMetaDown()) handleCtrlClick(evt); @@ -85,11 +82,11 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } // public void processKeyEvent(KeyEvent evt) { -// System.out.println(evt); +// log(evt); // } void handleCtrlClick(MouseEvent evt) { - System.out.println("--handleCtrlClick--"); + log("--handleCtrlClick--"); int off = ta.xyToOffset(evt.getX(), evt.getY()); if (off < 0) return; @@ -103,7 +100,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { return; else { int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; - System.out.println("x="+x); + log("x="+x); int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); if (x < 0 || x >= s.length()) return; @@ -144,8 +141,8 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { if (Character.isDigit(word.charAt(0))) return; - System.out.print(errorCheckerService.mainClassOffset + line); - System.out.print("|" + line + "| offset " + xLS + word + " <= \n"); + log(errorCheckerService.mainClassOffset + line + + "|" + line + "| offset " + xLS + word + " <= \n"); errorCheckerService.astGenerator.scrollToDeclaration(line + errorCheckerService.mainClassOffset, word, xLS); } @@ -280,7 +277,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { //System.out.print("bg line " + line + ": "); // no need to paint anything if (col == null) { - //System.out.println("none"); + //log("none"); return; } // paint line background @@ -328,7 +325,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } // Determine co-ordinates - // System.out.println("Hoff " + ta.getHorizontalOffset() + ", " + + // log("Hoff " + ta.getHorizontalOffset() + ", " + // horizontalAdjustment); int y = ta.lineToY(line); y += fm.getLeading() + fm.getMaxDescent(); @@ -346,7 +343,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // Error in the import statements or end of code. // System.out.print("BL caught. " + ta.getLineCount() + " ," // + line + " ,"); - // System.out.println((ta.getLineStopOffset(line) - start - 1)); + // log((ta.getLineStopOffset(line) - start - 1)); return; } @@ -479,8 +476,8 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, xLS); - System.out.print(errorCheckerService.mainClassOffset + " MCO "); - System.out.print("|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); + log(errorCheckerService.mainClassOffset + " MCO " + + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n"); if (tooltipText != null) return tooltipText; return word; From 314fec83db35b164e6f3d0e87cd62f74b9d6ab29 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 18:26:47 +0530 Subject: [PATCH 153/608] getting rid of the last ones.. --- .../mode/experimental/ASTGenerator.java | 65 +++++++++---------- .../mode/experimental/ASTNodeWrapper.java | 4 +- .../mode/experimental/CompletionPanel.java | 3 +- .../experimental/ErrorMessageSimplifier.java | 2 +- .../mode/experimental/ExperimentalMode.java | 18 +++-- .../mode/experimental/TextArea.java | 11 ++-- .../mode/experimental/TextAreaPainter.java | 4 +- 7 files changed, 57 insertions(+), 50 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 7bfda7b3a..c64d9037c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1,6 +1,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.Dimension; import java.awt.Rectangle; @@ -282,7 +283,7 @@ public class ASTGenerator { } }; worker.execute(); -// System.err.println("++>" + System.getProperty("java.class.path")); +// logE("++>" + System.getProperty("java.class.path")); // log(System.getProperty("java.class.path")); // log("-------------------------------"); return codeTree; @@ -834,15 +835,15 @@ public class ASTGenerator { parser.setKind(ASTParser.K_EXPRESSION); parser.setSource(word2.toCharArray()); ASTNode testnode = parser.createAST(null); - //System.err.println("PREDICTION PARSER PROBLEMS: " + parser); + //logE("PREDICTION PARSER PROBLEMS: " + parser); // Find closest ASTNode of the document to this word - System.err.print("Typed: " + word2 + "|"); + logE("Typed: " + word2 + "|"); nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); if (nearestNode == null) //Make sure nearestNode is not NULL if couldn't find a closeset node nearestNode = (ASTNode) compilationUnit.types().get(0); - System.err.println(lineNumber + " Nearest ASTNode to PRED " + logE(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(nearestNode)); candidates = new ArrayList(); @@ -850,8 +851,7 @@ public class ASTGenerator { // Determine the expression typed if (testnode instanceof SimpleName && !noCompare) { - System.err - .println("One word expression " + getNodeAsString(testnode)); + logE("One word expression " + getNodeAsString(testnode)); //==> Simple one word exprssion - so is just an identifier // Bottom up traversal of the AST to look for possible definitions at @@ -938,7 +938,7 @@ public class ASTGenerator { // ==> Complex expression of type blah.blah2().doIt,etc // Have to resolve it by carefully traversing AST of testNode - System.err.println("Complex expression " + getNodeAsString(testnode)); + logE("Complex expression " + getNodeAsString(testnode)); log("candidates empty"); ASTNode childExpr = getChildExpression(testnode); log("Parent expression : " + getParentExpression(testnode)); @@ -1321,7 +1321,7 @@ public class ASTGenerator { private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { Iterator it = node .structuralPropertiesForType().iterator(); - // System.err.println("Props of " + node.getClass().getName()); + // logE("Props of " + node.getClass().getName()); while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -1562,11 +1562,11 @@ public class ASTGenerator { log(getNodeAsString(simpName)); decl = findDeclaration((SimpleName) simpName); if (decl != null) { - System.err.println("DECLA: " + decl.getClass().getName()); + logE("DECLA: " + decl.getClass().getName()); nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), (SimpleName) simpName); //retLabelString = getNodeAsString(decl); } else - System.err.println("null"); + logE("null"); log(getNodeAsString(decl)); @@ -1592,8 +1592,8 @@ public class ASTGenerator { * This is important since it contains all the properties. */ ASTNode simpName2 = getNodeName(decl,nameOfNode); - System.err.println("FINAL String decl: " + getNodeAsString(decl)); - System.err.println("FINAL String label: " + getNodeAsString(simpName2)); + logE("FINAL String decl: " + getNodeAsString(decl)); + logE("FINAL String label: " + getNodeAsString(simpName2)); errorCheckerService.highlightNode(simpName2); } @@ -1672,7 +1672,7 @@ public class ASTGenerator { DefaultMutableTreeNode astTree = new DefaultMutableTreeNode( "CompilationUnit"); - System.err.println("Errors: " + cu.getProblems().length); + logE("Errors: " + cu.getProblems().length); visitRecur(cu, astTree); log(astTree.getChildCount()); @@ -1933,7 +1933,7 @@ public class ASTGenerator { if(wnode.getNode() == null){ return null; } - System.err.println("Gonna find all occurrences of " + logE("Gonna find all occurrences of " + getNodeAsString(wnode.getNode())); //If wnode is a constructor, find the TD instead. @@ -1950,7 +1950,7 @@ public class ASTGenerator { if(node != null && node instanceof TypeDeclaration){ TypeDeclaration td = (TypeDeclaration) node; if(td.getName().toString().equals(md.getName().toString())){ - System.err.println("Renaming constructor of " + getNodeAsString(td)); + logE("Renaming constructor of " + getNodeAsString(td)); wnode = new ASTNodeWrapper(td); } } @@ -1986,7 +1986,7 @@ public class ASTGenerator { public static void visitRecur(ASTNode node, DefaultMutableTreeNode tnode) { Iterator it = node .structuralPropertiesForType().iterator(); - //System.err.println("Props of " + node.getClass().getName()); + //logE("Props of " + node.getClass().getName()); DefaultMutableTreeNode ctnode = null; while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it @@ -2109,7 +2109,7 @@ public class ASTGenerator { } log("Visiting: " + getNodeAsString(node)); ASTNode decl2 = findDeclaration(sn); - System.err.println("It's decl: " + getNodeAsString(decl2)); + logE("It's decl: " + getNodeAsString(decl2)); log("But we need: "+getNodeAsString(decl)); for (ASTNode astNode : nodesToBeMatched) { if(astNode.equals(decl2)){ @@ -2154,7 +2154,7 @@ public class ASTGenerator { public static void printRecur(ASTNode node) { Iterator it = node .structuralPropertiesForType().iterator(); - //System.err.println("Props of " + node.getClass().getName()); + //logE("Props of " + node.getClass().getName()); while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -2189,13 +2189,12 @@ public class ASTGenerator { CompilationUnit root = (CompilationUnit) node.getRoot(); // log("Inside "+getNodeAsString(node) + " | " + root.getLineNumber(node.getStartPosition())); if (root.getLineNumber(node.getStartPosition()) == lineNumber) { - System.err - .println(3 + getNodeAsString(node) + " len " + node.getLength()); + logE(3 + getNodeAsString(node) + " len " + node.getLength()); return node; // if (offset < node.getLength()) // return node; // else { -// System.err.println(-11); +// logE(-11); // return null; // } } @@ -2208,7 +2207,7 @@ public class ASTGenerator { .getStructuralProperty(prop), lineNumber, offset, name); if (retNode != null) { -// System.err.println(11 + getNodeAsString(retNode)); +// logE(11 + getNodeAsString(retNode)); return retNode; } } @@ -2220,13 +2219,13 @@ public class ASTGenerator { ASTNode rr = findLineOfNode(retNode, lineNumber, offset, name); if (rr != null) { -// System.err.println(12 + getNodeAsString(rr)); +// logE(12 + getNodeAsString(rr)); return rr; } } } } -// System.err.println("-1"); +// logE("-1"); return null; } @@ -2270,7 +2269,7 @@ public class ASTGenerator { .getStructuralProperty(prop), offset, lineStartOffset, name); if (retNode != null) { -// System.err.println(11 + getNodeAsString(retNode)); +// logE(11 + getNodeAsString(retNode)); return retNode; } } @@ -2282,13 +2281,13 @@ public class ASTGenerator { ASTNode rr = pinpointOnLine(retNode, offset, lineStartOffset, name); if (rr != null) { -// System.err.println(12 + getNodeAsString(rr)); +// logE(12 + getNodeAsString(rr)); return rr; } } } } -// System.err.println("-1"); +// logE("-1"); return null; } @@ -2899,7 +2898,7 @@ public class ASTGenerator { switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: - //System.err.println(getNodeAsString(node)); + //logE(getNodeAsString(node)); TypeDeclaration td = (TypeDeclaration) node; if (td.getName().toString().equals(name)) { if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) { @@ -2938,25 +2937,25 @@ public class ASTGenerator { } break; case ASTNode.METHOD_DECLARATION: - //System.err.println(getNodeAsString(node)); + //logE(getNodeAsString(node)); if (((MethodDeclaration) node).getName().toString().equalsIgnoreCase(name)) return node; break; case ASTNode.SINGLE_VARIABLE_DECLARATION: - //System.err.println(getNodeAsString(node)); + //logE(getNodeAsString(node)); if (((SingleVariableDeclaration) node).getName().toString().equalsIgnoreCase(name)) return node; break; case ASTNode.FIELD_DECLARATION: - //System.err.println("FD" + node); + //logE("FD" + node); vdfList = ((FieldDeclaration) node).fragments(); break; case ASTNode.VARIABLE_DECLARATION_EXPRESSION: - //System.err.println("VDE" + node); + //logE("VDE" + node); vdfList = ((VariableDeclarationExpression) node).fragments(); break; case ASTNode.VARIABLE_DECLARATION_STATEMENT: - //System.err.println("VDS" + node); + //logE("VDS" + node); vdfList = ((VariableDeclarationStatement) node).fragments(); break; diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 6201bdcd0..9e99ad5fd 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -341,10 +341,10 @@ public class ASTNodeWrapper { for (int i = 0; i < pdeCodeMap.length; i++) { if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { if (i < source.length()) - System.out.print(source.charAt(i)); + log2(source.charAt(i)); log2(pdeCodeMap[i] + " - " + javaCodeMap[i]); if (i < sourceAlt.length()) - System.out.print(sourceAlt.charAt(i)); + log2(sourceAlt.charAt(i)); log2(" <-[" + i + "]"); log(""); } diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index b5c795078..f054ccfd2 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -1,5 +1,6 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; import java.awt.Color; @@ -105,7 +106,7 @@ public class CompletionPanel { try { String selectedSuggestion = ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString().substring(subWord.length()); - System.err.println(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); + logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); textarea.getDocument().remove(insertionPosition-subWord.length(), subWord.length()); textarea.getDocument().insertString(insertionPosition-subWord.length(), ((CompletionCandidate) completionList diff --git a/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java b/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java index 7ac5c594f..8edf56591 100644 --- a/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java +++ b/pdex/src/processing/mode/experimental/ErrorMessageSimplifier.java @@ -46,7 +46,7 @@ public class ErrorMessageSimplifier { break; } } - System.out.println("Total items: " + constantsMap.size()); + //System.out.println("Total items: " + constantsMap.size()); } public String getIDName(int id) { diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index f47005fb7..8619af055 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -43,7 +43,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = true; + public static boolean DEBUG = !true; public ExperimentalMode(Base base, File folder) { super(base, folder); @@ -169,18 +169,26 @@ public class ExperimentalMode extends JavaMode { return null; } - /* - * log + /** + * System.out.println() */ public static final void log(Object message){ if(ExperimentalMode.DEBUG) System.out.println(message); } - /* + /** + * System.err.println() + */ + public static final void logE(Object message){ + if(ExperimentalMode.DEBUG) + System.err.println(message); + } + + /** * System.out.print */ - public static final void log2(String message){ + public static final void log2(Object message){ if(ExperimentalMode.DEBUG) System.out.print(message); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index c7a3693ab..39282d3ef 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -17,6 +17,7 @@ */ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.log2; import java.awt.Color; import java.awt.Cursor; @@ -297,7 +298,6 @@ public class TextArea extends JEditTextArea { break; if (i > 200) { // time out! - System.err.println("Whoopsy! :P"); break; } } @@ -326,24 +326,24 @@ public class TextArea extends JEditTextArea { } } int off = getCaretPosition(); - System.out.print("off " + off); + log2("off " + off); if (off < 0) return null; int line = getCaretLine(); if (line < 0) return null; String s = getLineText(line); - System.out.print("lin " + line); + log2("lin " + line); /* * if (s == null) return null; else if (s.length() == 0) return null; */ // else { - //System.out.print(s + " len " + s.length()); + //log2(s + " len " + s.length()); int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. - System.out.print(" x char: " + s.charAt(x)); + log2(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; @@ -420,7 +420,6 @@ public class TextArea extends JEditTextArea { // break; if (i > 200) { // time out! - System.err.println("Whoopsy! :P"); break; } } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index d2e58ebb7..89170edbe 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -134,7 +134,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { break; if (i > 200) { // time out! - System.err.println("Whoopsy! :P"); + // System.err.println("Whoopsy! :P"); break; } } @@ -466,7 +466,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { break; if (i > 200) { // time out! - System.err.println("Whoopsy! :P"); + // System.err.println("Whoopsy! :P"); break; } } From e51c376038d3d476316ceba3b54fe84f201c609f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 18:39:40 +0530 Subject: [PATCH 154/608] cleaning up XQConsoleToggle --- .../processing/mode/experimental/DebugEditor.java | 12 ++++++------ .../mode/experimental/XQConsoleToggle.java | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 30d3ab616..01e4241ec 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -246,9 +246,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { JPanel lineStatusPanel = new JPanel(); lineStatusPanel.setLayout(new BorderLayout()); btnShowConsole = new XQConsoleToggle(this, - XQConsoleToggle.text[0], lineStatus.getHeight()); + XQConsoleToggle.CONSOLE, lineStatus.getHeight()); btnShowErrors = new XQConsoleToggle(this, - XQConsoleToggle.text[1], lineStatus.getHeight()); + XQConsoleToggle.ERRORSLIST, lineStatus.getHeight()); btnShowConsole.addMouseListener(btnShowConsole); // lineStatusPanel.add(btnShowConsole, BorderLayout.EAST); @@ -268,8 +268,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Adding JPanel with CardLayout for Console/Problems Toggle consolePanel.remove(1); consoleProblemsPane = new JPanel(new CardLayout()); - consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.text[1]); - consoleProblemsPane.add(console, XQConsoleToggle.text[0]); + consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.ERRORSLIST); + consoleProblemsPane.add(console, XQConsoleToggle.CONSOLE); consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); } @@ -485,7 +485,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { .setVisible(((JCheckBoxMenuItem) e.getSource()) .isSelected()); // switch to console, now that Error Window is open - toggleView(XQConsoleToggle.text[0]); + showProblemListView(XQConsoleToggle.CONSOLE); } }); debugMenu.add(problemWindowMenuCB); @@ -1200,7 +1200,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { * @param buttonName * - Button Label */ - public void toggleView(String buttonName) { + public void showProblemListView(String buttonName) { CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); cl.show(consoleProblemsPane, buttonName); } diff --git a/pdex/src/processing/mode/experimental/XQConsoleToggle.java b/pdex/src/processing/mode/experimental/XQConsoleToggle.java index 7d4ea9032..c30ae5b99 100755 --- a/pdex/src/processing/mode/experimental/XQConsoleToggle.java +++ b/pdex/src/processing/mode/experimental/XQConsoleToggle.java @@ -41,7 +41,7 @@ import javax.swing.JPanel; */ public class XQConsoleToggle extends JPanel implements MouseListener { - public static final String[] text = { "Console", "Errors" }; + public static final String CONSOLE = "Console", ERRORSLIST = "Errors" ; private boolean toggleText = true; private boolean toggleBG = true; @@ -101,7 +101,7 @@ public class XQConsoleToggle extends JPanel implements MouseListener { this.repaint(); try { - editor.toggleView(buttonName); + editor.showProblemListView(buttonName); } catch (Exception e) { System.out.println(e); // e.printStackTrace(); From d640d6407050b3877bbde5cf8f83233b5ac5e902 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 18:42:53 +0530 Subject: [PATCH 155/608] auto switch to console on Run --- pdex/src/processing/mode/experimental/DebugToolbar.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdex/src/processing/mode/experimental/DebugToolbar.java b/pdex/src/processing/mode/experimental/DebugToolbar.java index e094176ad..3738b9db9 100755 --- a/pdex/src/processing/mode/experimental/DebugToolbar.java +++ b/pdex/src/processing/mode/experimental/DebugToolbar.java @@ -160,6 +160,7 @@ public class DebugToolbar extends JavaToolbar { break; case DEBUG: deditor.handleStop(); // Close any running sketches + deditor.showProblemListView(XQConsoleToggle.CONSOLE); if (shift) { Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button"); deditor.handleRun(); From f49066264fd58cfd5f8a91a2dc16de57b4ec287b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 20:54:05 +0530 Subject: [PATCH 156/608] refactor bug fix --- pdex/Todo, GSoC 2013.txt | 3 ++- .../mode/experimental/ASTGenerator.java | 10 +++++++--- .../mode/experimental/ErrorCheckerService.java | 16 ++++++++-------- .../mode/experimental/ExperimentalMode.java | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 6268ef55f..cd2025c60 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -119,6 +119,7 @@ x Working for local code General Stuff ============= -* Add option for toggling debug output +x Add option for toggling debug output +x On Run/Debug Console is visible(ProblemsList hidden) * update build.xml to produce dists * Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index c64d9037c..9073a4d70 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -38,6 +38,7 @@ import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; @@ -1813,6 +1814,7 @@ public class ASTGenerator { editor.statusError("Can't locate definition of " + selText); return; } + errorCheckerService.pauseThread(); treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); frmOccurenceList.setTitle("Usage of " + selText); @@ -1824,14 +1826,14 @@ public class ASTGenerator { // I need to store the pde and java offsets beforehand because once // the replace starts, all offsets returned are affected int offsetsMap[][][] = new int[defCU.getChildCount()][2][]; - for (int i = defCU.getChildCount() - 1; i >= 0; i--) { + for (int i = 0; i < defCU.getChildCount(); i++) { ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) (defCU .getChildAt(i))).getUserObject(); offsetsMap[i][0] = awrap.getPDECodeOffsets(errorCheckerService); offsetsMap[i][1] = awrap.getJavaCodeOffsets(errorCheckerService); } - for (int i = defCU.getChildCount() - 1; i >= 0; i--) { + for (int i = 0; i < defCU.getChildCount(); i++) { int pdeoffsets[] = offsetsMap[i][0]; int javaoffsets[] = offsetsMap[i][1]; // correction for pde enhancements related displacement on a line @@ -1845,13 +1847,15 @@ public class ASTGenerator { lineOffsetDisplacement.put(javaoffsets[0], lineOffsetDisplacementConst); } - ErrorCheckerService.scrollToErrorLine(editor, pdeoffsets[0], pdeoffsets[1], javaoffsets[1] + off, javaoffsets[2]); + //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.OK_OPTION)); editor.ta.setSelectedText(newName); } + errorCheckerService.resumeThread(); + errorCheckerService.runManualErrorCheck(); for (Integer lineNum : lineOffsetDisplacement.keySet()) { log(lineNum + "line, disp" + lineOffsetDisplacement.get(lineNum)); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 3a73b03c5..3853a367d 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -378,10 +378,10 @@ public class ErrorCheckerService implements Runnable{ Problem p = new Problem(problems[i], a[0], a[1] + 1); //TODO: ^Why do cheeky stuff? problemsList.add(p); - log(problems[i].getMessage()); - for (String j : problems[i].getArguments()) { - log("arg " + j); - } +// log(problems[i].getMessage()); +// for (String j : problems[i].getArguments()) { +// log("arg " + j); +// } // log(p.toString()); } @@ -491,10 +491,10 @@ public class ErrorCheckerService implements Runnable{ // + problems[i].isWarning()); IProblem problem = problems[i]; - log(problem.getMessage()); - for (String j : problem.getArguments()) { - log("arg " + j); - } +// log(problem.getMessage()); +// for (String j : problem.getArguments()) { +// log("arg " + j); +// } int a[] = calculateTabIndexAndLineNumber(problem); Problem p = new Problem(problem, a[0], a[1]); if ((Boolean) errorList[i][8]) { diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 8619af055..61d93d498 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -43,7 +43,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = !true; + public static boolean DEBUG = true; public ExperimentalMode(Base base, File folder) { super(base, folder); From a5917514b6208d0c13cbdaa2df989c512e09735f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 17 Aug 2013 21:11:26 +0530 Subject: [PATCH 157/608] validate new name before refactor --- pdex/Todo, GSoC 2013.txt | 1 + .../processing/mode/experimental/ASTGenerator.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index cd2025c60..b8583482d 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -71,6 +71,7 @@ Refactoring * Undo misbehaves here, handle carefully. +x New Name is validated. x Ordered list in 'Show Usage' window x Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9073a4d70..025b17a18 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1806,7 +1806,7 @@ public class ASTGenerator { } private void refactorIt(){ - String newName = txtRenameField.getText(); + String newName = txtRenameField.getText().trim(); String selText = lastClickedWord == null ? editor.ta.getSelectedText() : lastClickedWord; DefaultMutableTreeNode defCU = findAllOccurrences(); @@ -1814,6 +1814,14 @@ public class ASTGenerator { editor.statusError("Can't locate definition of " + selText); return; } + + if(!newName.matches("([a-zA-Z][a-zA-Z0-9_]*)|([_][a-zA-Z0-9_]+)")) + { + JOptionPane.showConfirmDialog(new JFrame(), newName + " isn't a valid name.","Uh oh..", JOptionPane.PLAIN_MESSAGE); + return; + } + //else log("New name looks K."); + errorCheckerService.pauseThread(); treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); @@ -1851,7 +1859,7 @@ public class ASTGenerator { pdeoffsets[1], javaoffsets[1] + off, javaoffsets[2]); - //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.OK_OPTION)); + //int k = JOptionPane.showConfirmDialog(new JFrame(), "Rename?","", JOptionPane.INFORMATION_MESSAGE)); editor.ta.setSelectedText(newName); } errorCheckerService.resumeThread(); From c6cd952e1dfd46440672b5e4a30b697496a0a889 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 00:29:47 +0530 Subject: [PATCH 158/608] starting work on integrated SketchOutline tree --- .../mode/experimental/ASTGenerator.java | 117 +++++++++++++++++- .../mode/experimental/DebugEditor.java | 26 +++- 2 files changed, 135 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 025b17a18..eb98bf474 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -4,9 +4,13 @@ import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.Dimension; +import java.awt.Point; import java.awt.Rectangle; +import java.awt.ScrollPane; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -22,6 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; @@ -45,6 +50,7 @@ import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ListSelectionModel; +import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; @@ -242,8 +248,7 @@ public class ASTGenerator { // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); getCodeComments(); - codeTree = new DefaultMutableTreeNode( - getNodeAsString((ASTNode) compilationUnit + codeTree = new DefaultMutableTreeNode(new ASTNodeWrapper((ASTNode) compilationUnit .types().get(0))); visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); SwingWorker worker = new SwingWorker() { @@ -1817,7 +1822,8 @@ public class ASTGenerator { if(!newName.matches("([a-zA-Z][a-zA-Z0-9_]*)|([_][a-zA-Z0-9_]+)")) { - JOptionPane.showConfirmDialog(new JFrame(), newName + " isn't a valid name.","Uh oh..", JOptionPane.PLAIN_MESSAGE); + JOptionPane.showConfirmDialog(new JFrame(), newName + + " isn't a valid name.", "Uh oh..", JOptionPane.PLAIN_MESSAGE); return; } //else log("New name looks K."); @@ -2063,6 +2069,111 @@ public class ASTGenerator { } } + protected JFrame frmOutlineView; + protected void showSketchOutline(){ + frmOutlineView = new JFrame(); + frmOutlineView.setAlwaysOnTop(true); + frmOutlineView.setUndecorated(true); + Point tp = editor.ta.getLocationOnScreen(); + log("TA Co " + tp); + frmOutlineView.setBounds(tp.x + editor.ta.getWidth() - 300, tp.y, 300, editor.ta.getHeight()); + JScrollPane jsp = new JScrollPane(); + DefaultMutableTreeNode soNode = new DefaultMutableTreeNode(); + generateSketchOutlineTree(soNode, codeTree); + final JTree soTree = new JTree(soNode); + soTree.setRootVisible(false); + for (int i = 0; i < soTree.getRowCount(); i++) { + soTree.expandRow(i); + } + + jsp.setViewportView(soTree); + jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + frmOutlineView.add(jsp); + frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmOutlineView.setVisible(true); + frmOutlineView.addWindowFocusListener(new WindowFocusListener() { + public void windowLostFocus(WindowEvent e) { + frmOutlineView.setVisible(false); + frmOutlineView.dispose(); + } + public void windowGainedFocus(WindowEvent e) { + } + }); + + soTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + log(e); + SwingWorker worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + return null; + } + protected void done() { + if (soTree.getLastSelectedPathComponent() == null) { + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree + .getLastSelectedPathComponent(); + if (tnode.getUserObject() == null) { + return; + } + + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + errorCheckerService.highlightNode(awrap); + } + } + }; + worker.execute(); + } + }); + + } + + protected void generateSketchOutlineTree(DefaultMutableTreeNode node, DefaultMutableTreeNode codetree){ + if (codetree == null) + return; + //log("Visi " + codetree + codetree.getUserObject().getClass().getSimpleName()); + if(!(codetree.getUserObject() instanceof ASTNodeWrapper)) + return; + ASTNodeWrapper awnode = (ASTNodeWrapper) codetree.getUserObject(), aw2 = null; + + if (awnode.getNode() instanceof TypeDeclaration) { + aw2 = new ASTNodeWrapper(awnode.getNode(), + ((TypeDeclaration) awnode.getNode()).getName() + .toString()); + } else if (awnode.getNode() instanceof MethodDeclaration) { + aw2 = new ASTNodeWrapper( + ((MethodDeclaration) awnode + .getNode()).getName(), + new CompletionCandidate( + ((MethodDeclaration) awnode + .getNode())) + .toString()); + } + else if (awnode.getNode() instanceof FieldDeclaration) { + FieldDeclaration fd = (FieldDeclaration)awnode.getNode(); + for (VariableDeclarationFragment vdf : (List)fd.fragments()) { + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( + new ASTNodeWrapper( + vdf.getName(), + new CompletionCandidate( + vdf) + .toString())); + node.add(newNode); + } + return; + } + if(aw2 == null) return; + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(aw2); + node.add(newNode); + for (int i = 0; i < codetree.getChildCount(); i++) { + generateSketchOutlineTree(newNode, + (DefaultMutableTreeNode) codetree + .getChildAt(i)); + } + } + public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ // Find the first node with this line number, return its offset - jOffset line = PdeToJavaLineNumber(line); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 01e4241ec..3649a6dc3 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -16,6 +16,7 @@ * Place - Suite 330, Boston, MA 02111-1307, USA. */ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; import java.awt.BorderLayout; import java.awt.CardLayout; @@ -25,12 +26,9 @@ import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.io.StringReader; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -50,7 +48,13 @@ import javax.swing.text.Document; import org.eclipse.jdt.core.compiler.IProblem; -import processing.app.*; +import processing.app.Base; +import processing.app.EditorState; +import processing.app.EditorToolbar; +import processing.app.Mode; +import processing.app.Sketch; +import processing.app.SketchCode; +import processing.app.Toolkit; import processing.app.syntax.JEditTextArea; import processing.app.syntax.PdeTextAreaDefaults; import processing.core.PApplet; @@ -152,6 +156,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected JCheckBoxMenuItem debugMessagesEnabled; + /** + * Show outline view + */ + protected JMenuItem showOutline; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -511,7 +520,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { .getSource()).isSelected(); } }); - debugMenu.add(debugMessagesEnabled); + debugMenu.add(debugMessagesEnabled); + + showOutline = Toolkit.newJMenuItem("Show Outline", KeyEvent.VK_L); + showOutline.addActionListener(this); + debugMenu.add(showOutline); return debugMenu; } @@ -576,6 +589,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { } else if (source == toggleVariableInspectorMenuItem) { Logger.getLogger(DebugEditor.class.getName()).log(Level.INFO, "Invoked 'Toggle Variable Inspector' menu item"); toggleVariableInspector(); + } else if (source.equals(showOutline)){ + log("Show Outline :D"); + errorCheckerService.astGenerator.showSketchOutline(); } } From aec4d27caf7af894746617e7cbc5462f2af52d6c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 02:32:49 +0530 Subject: [PATCH 159/608] zomg, made it work in first attempt *tears of joy* --- .../mode/experimental/ASTGenerator.java | 105 +----------------- 1 file changed, 3 insertions(+), 102 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index eb98bf474..a9609315b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -2069,109 +2069,10 @@ public class ASTGenerator { } } - protected JFrame frmOutlineView; + protected SketchOutline sko; protected void showSketchOutline(){ - frmOutlineView = new JFrame(); - frmOutlineView.setAlwaysOnTop(true); - frmOutlineView.setUndecorated(true); - Point tp = editor.ta.getLocationOnScreen(); - log("TA Co " + tp); - frmOutlineView.setBounds(tp.x + editor.ta.getWidth() - 300, tp.y, 300, editor.ta.getHeight()); - JScrollPane jsp = new JScrollPane(); - DefaultMutableTreeNode soNode = new DefaultMutableTreeNode(); - generateSketchOutlineTree(soNode, codeTree); - final JTree soTree = new JTree(soNode); - soTree.setRootVisible(false); - for (int i = 0; i < soTree.getRowCount(); i++) { - soTree.expandRow(i); - } - - jsp.setViewportView(soTree); - jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - frmOutlineView.add(jsp); - frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frmOutlineView.setVisible(true); - frmOutlineView.addWindowFocusListener(new WindowFocusListener() { - public void windowLostFocus(WindowEvent e) { - frmOutlineView.setVisible(false); - frmOutlineView.dispose(); - } - public void windowGainedFocus(WindowEvent e) { - } - }); - - soTree.addTreeSelectionListener(new TreeSelectionListener() { - public void valueChanged(TreeSelectionEvent e) { - log(e); - SwingWorker worker = new SwingWorker() { - protected Object doInBackground() throws Exception { - return null; - } - protected void done() { - if (soTree.getLastSelectedPathComponent() == null) { - return; - } - DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree - .getLastSelectedPathComponent(); - if (tnode.getUserObject() == null) { - return; - } - - if (tnode.getUserObject() instanceof ASTNodeWrapper) { - ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - errorCheckerService.highlightNode(awrap); - } - } - }; - worker.execute(); - } - }); - - } - - protected void generateSketchOutlineTree(DefaultMutableTreeNode node, DefaultMutableTreeNode codetree){ - if (codetree == null) - return; - //log("Visi " + codetree + codetree.getUserObject().getClass().getSimpleName()); - if(!(codetree.getUserObject() instanceof ASTNodeWrapper)) - return; - ASTNodeWrapper awnode = (ASTNodeWrapper) codetree.getUserObject(), aw2 = null; - - if (awnode.getNode() instanceof TypeDeclaration) { - aw2 = new ASTNodeWrapper(awnode.getNode(), - ((TypeDeclaration) awnode.getNode()).getName() - .toString()); - } else if (awnode.getNode() instanceof MethodDeclaration) { - aw2 = new ASTNodeWrapper( - ((MethodDeclaration) awnode - .getNode()).getName(), - new CompletionCandidate( - ((MethodDeclaration) awnode - .getNode())) - .toString()); - } - else if (awnode.getNode() instanceof FieldDeclaration) { - FieldDeclaration fd = (FieldDeclaration)awnode.getNode(); - for (VariableDeclarationFragment vdf : (List)fd.fragments()) { - DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( - new ASTNodeWrapper( - vdf.getName(), - new CompletionCandidate( - vdf) - .toString())); - node.add(newNode); - } - return; - } - if(aw2 == null) return; - DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(aw2); - node.add(newNode); - for (int i = 0; i < codetree.getChildCount(); i++) { - generateSketchOutlineTree(newNode, - (DefaultMutableTreeNode) codetree - .getChildAt(i)); - } + sko = new SketchOutline(codeTree, errorCheckerService); + sko.show(); } public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ From ea11ae5a2c4e4a27ec25755ec3b2236d4377f69e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 02:34:22 +0530 Subject: [PATCH 160/608] added SO --- .../mode/experimental/SketchOutline.java | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 pdex/src/processing/mode/experimental/SketchOutline.java diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java new file mode 100644 index 000000000..fb74f8086 --- /dev/null +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -0,0 +1,226 @@ +package processing.mode.experimental; + +import static processing.mode.experimental.ExperimentalMode.log; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.TextField; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.util.List; + +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingWorker; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; + +public class SketchOutline { + protected JFrame frmOutlineView; + + protected ErrorCheckerService errorCheckerService; + + protected JScrollPane jsp; + + protected DefaultMutableTreeNode soNode, tempNode; + + protected final JTree soTree; + + protected JTextField searchField; + + public SketchOutline(DefaultMutableTreeNode codeTree, ErrorCheckerService ecs) { + errorCheckerService = ecs; + frmOutlineView = new JFrame(); + frmOutlineView.setAlwaysOnTop(true); + frmOutlineView.setUndecorated(true); + Point tp = errorCheckerService.getEditor().ta.getLocationOnScreen(); + frmOutlineView.setBounds(tp.x + + errorCheckerService.getEditor().ta + .getWidth() - 300, tp.y, 300, + errorCheckerService.getEditor().ta.getHeight()); + //TODO: ^Absolute dimensions are bad bro + + frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), + BoxLayout.Y_AXIS)); + JPanel panelTop = new JPanel(), panelBottom = new JPanel(); + searchField = new JTextField(); + searchField.setPreferredSize(new Dimension(frmOutlineView.getWidth(), 25)); + panelTop.add(searchField); + frmOutlineView.add(panelTop); + + jsp = new JScrollPane(); + soNode = new DefaultMutableTreeNode(); + generateSketchOutlineTree(soNode, codeTree); + soNode = (DefaultMutableTreeNode) soNode.getChildAt(0); + soTree = new JTree(soNode); + soTree.getSelectionModel() + .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + soTree.setRootVisible(false); + for (int i = 0; i < soTree.getRowCount(); i++) { + soTree.expandRow(i); + } + soTree.setSelectionRow(0); + jsp.setViewportView(soTree); + jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + panelBottom.add(jsp); + frmOutlineView.add(jsp); + frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + addListeners(); + + } + + protected void addListeners() { + + searchField.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent evt) { + if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + if (soTree.getLastSelectedPathComponent() != null) { + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree + .getLastSelectedPathComponent(); + if (tnode.getUserObject() != null) { + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + errorCheckerService.highlightNode(awrap); + } + } + } + return; + } else if (evt.getKeyCode() == KeyEvent.VK_UP) { + if (soTree.getLastSelectedPathComponent() == null) { + soTree.setSelectionRow(0); + } + int x = soTree.getLeadSelectionRow(); + x = (x - 1) % soTree.getRowCount(); + soTree.setSelectionRow(x); + return; + } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { + if (soTree.getLastSelectedPathComponent() == null) { + soTree.setSelectionRow(0); + } + int x = soTree.getLeadSelectionRow(); + x = (x + 1) % soTree.getRowCount(); + soTree.setSelectionRow(x); + return; + } + + SwingWorker worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + String text = searchField.getText().toLowerCase(); + tempNode = new DefaultMutableTreeNode(); + filterTree(text, tempNode, soNode); + soTree.setModel(new DefaultTreeModel(tempNode)); + ((DefaultTreeModel) soTree.getModel()).reload(); + for (int i = 0; i < soTree.getRowCount(); i++) { + soTree.expandRow(i); + } + soTree.setSelectionRow(0); + } + }; + worker.execute(); + + } + }); + + frmOutlineView.addWindowFocusListener(new WindowFocusListener() { + public void windowLostFocus(WindowEvent e) { + frmOutlineView.setVisible(false); + frmOutlineView.dispose(); + } + + public void windowGainedFocus(WindowEvent e) { + } + }); + } + + protected boolean filterTree(String prefix, DefaultMutableTreeNode tree, + DefaultMutableTreeNode mainTree) { + if(mainTree.isLeaf()){ + return (mainTree.getUserObject().toString().toLowerCase().startsWith(prefix)); + } + + boolean found = false; + for (int i = 0; i < mainTree.getChildCount(); i++) { + DefaultMutableTreeNode tNode = new DefaultMutableTreeNode( + ((DefaultMutableTreeNode) mainTree + .getChildAt(i)) + .getUserObject()); + if (filterTree(prefix, tNode, + (DefaultMutableTreeNode) mainTree.getChildAt(i))) { + found = true; + tree.add(tNode); + } + } + return found; + } + + protected void generateSketchOutlineTree(DefaultMutableTreeNode node, + DefaultMutableTreeNode codetree) { + if (codetree == null) + return; + //log("Visi " + codetree + codetree.getUserObject().getClass().getSimpleName()); + if (!(codetree.getUserObject() instanceof ASTNodeWrapper)) + return; + ASTNodeWrapper awnode = (ASTNodeWrapper) codetree.getUserObject(), aw2 = null; + + if (awnode.getNode() instanceof TypeDeclaration) { + aw2 = new ASTNodeWrapper(awnode.getNode(), + ((TypeDeclaration) awnode.getNode()).getName() + .toString()); + } else if (awnode.getNode() instanceof MethodDeclaration) { + aw2 = new ASTNodeWrapper( + ((MethodDeclaration) awnode.getNode()).getName(), + new CompletionCandidate( + ((MethodDeclaration) awnode + .getNode())) + .toString()); + } else if (awnode.getNode() instanceof FieldDeclaration) { + FieldDeclaration fd = (FieldDeclaration) awnode.getNode(); + for (VariableDeclarationFragment vdf : (List) fd + .fragments()) { + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( + new ASTNodeWrapper( + vdf.getName(), + new CompletionCandidate( + vdf) + .toString())); + node.add(newNode); + } + return; + } + if (aw2 == null) + return; + DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(aw2); + node.add(newNode); + for (int i = 0; i < codetree.getChildCount(); i++) { + generateSketchOutlineTree(newNode, + (DefaultMutableTreeNode) codetree.getChildAt(i)); + } + } + + public void show() { + frmOutlineView.setVisible(true); + } +} From 78b82135ef01d73e07f9b8d69f9ab3861c6734e7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 04:18:00 +0530 Subject: [PATCH 161/608] fighting with popup size --- pdex/Todo, GSoC 2013.txt | 7 +++ .../mode/experimental/SketchOutline.java | 52 +++++++++++++------ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index b8583482d..8bd19699b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -100,6 +100,12 @@ x Local Classes x Recursive lookup, a.b().c() x Now highlihgting the declaration name, rather than the whole declaration. +Sketch Outline +============== + +x Show Sketch Outline Tree +x Filter stuff in text field + Suggestion for missing imports ============================== @@ -112,6 +118,7 @@ x Add imports only to beginning of first tab. Labels for Java elements ======================== + x Working for local code * Need to modify getASTNodeAt to also fetch the type for predefined classes. * Labels for predefined class objects diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index fb74f8086..0228e655b 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -1,10 +1,7 @@ package processing.mode.experimental; -import static processing.mode.experimental.ExperimentalMode.log; - import java.awt.Dimension; import java.awt.Point; -import java.awt.TextField; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; @@ -19,13 +16,8 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ScrollPaneConstants; import javax.swing.SwingWorker; -import javax.swing.event.TreeModelListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import org.eclipse.jdt.core.dom.FieldDeclaration; @@ -45,26 +37,34 @@ public class SketchOutline { protected final JTree soTree; protected JTextField searchField; + + protected DebugEditor editor; public SketchOutline(DefaultMutableTreeNode codeTree, ErrorCheckerService ecs) { errorCheckerService = ecs; + editor = ecs.getEditor(); frmOutlineView = new JFrame(); frmOutlineView.setAlwaysOnTop(true); frmOutlineView.setUndecorated(true); Point tp = errorCheckerService.getEditor().ta.getLocationOnScreen(); - frmOutlineView.setBounds(tp.x - + errorCheckerService.getEditor().ta - .getWidth() - 300, tp.y, 300, - errorCheckerService.getEditor().ta.getHeight()); +// frmOutlineView.setBounds(tp.x +// + errorCheckerService.getEditor().ta +// .getWidth() - 300, tp.y, 300, +// errorCheckerService.getEditor().ta.getHeight()); + //TODO: ^Absolute dimensions are bad bro + int minWidth = 200; frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), BoxLayout.Y_AXIS)); JPanel panelTop = new JPanel(), panelBottom = new JPanel(); + panelTop.setLayout(new BoxLayout(panelTop, + BoxLayout.Y_AXIS)); + panelBottom.setLayout(new BoxLayout(panelBottom, + BoxLayout.Y_AXIS)); searchField = new JTextField(); - searchField.setPreferredSize(new Dimension(frmOutlineView.getWidth(), 25)); - panelTop.add(searchField); - frmOutlineView.add(panelTop); + searchField.setMinimumSize(new Dimension(minWidth, 25)); + panelTop.add(searchField); jsp = new JScrollPane(); soNode = new DefaultMutableTreeNode(); @@ -80,10 +80,28 @@ public class SketchOutline { soTree.setSelectionRow(0); jsp.setViewportView(soTree); jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + jsp.setMinimumSize(new Dimension(minWidth, 100)); panelBottom.add(jsp); - frmOutlineView.add(jsp); + frmOutlineView.add(panelTop); + frmOutlineView.add(panelBottom); frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); +// frmOutlineView.setLocation(tp.x +// + errorCheckerService.getEditor().ta +// .getWidth() - minWidth, tp.y); + frmOutlineView.setBounds(tp.x + + errorCheckerService.getEditor().ta + .getWidth() - minWidth, tp.y, minWidth,Math + .min(editor.ta.getHeight(), 150)); + frmOutlineView.setMinimumSize(new Dimension(minWidth, Math + .min(errorCheckerService.getEditor().ta.getHeight(), 150))); + frmOutlineView.pack(); + frmOutlineView.setLocation(tp.x + + errorCheckerService.getEditor().ta + .getWidth() - frmOutlineView.getWidth(), + frmOutlineView.getY() + + (editor.ta.getHeight() - frmOutlineView + .getHeight()) / 2); addListeners(); } From 3b7fbc292d947f1e444eca4a38341ab6119857fa Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 05:11:51 +0530 Subject: [PATCH 162/608] fighting with popup scroll panes --- .../mode/experimental/SketchOutline.java | 109 +++++++++++++++--- 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 0228e655b..666c7ffcd 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -1,12 +1,16 @@ package processing.mode.experimental; +import static processing.mode.experimental.ExperimentalMode.log; + import java.awt.Dimension; import java.awt.Point; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.BoxLayout; import javax.swing.JFrame; @@ -16,6 +20,8 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ScrollPaneConstants; import javax.swing.SwingWorker; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; @@ -37,7 +43,7 @@ public class SketchOutline { protected final JTree soTree; protected JTextField searchField; - + protected DebugEditor editor; public SketchOutline(DefaultMutableTreeNode codeTree, ErrorCheckerService ecs) { @@ -51,25 +57,24 @@ public class SketchOutline { // + errorCheckerService.getEditor().ta // .getWidth() - 300, tp.y, 300, // errorCheckerService.getEditor().ta.getHeight()); - + //TODO: ^Absolute dimensions are bad bro int minWidth = 200; frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), BoxLayout.Y_AXIS)); JPanel panelTop = new JPanel(), panelBottom = new JPanel(); - panelTop.setLayout(new BoxLayout(panelTop, - BoxLayout.Y_AXIS)); - panelBottom.setLayout(new BoxLayout(panelBottom, - BoxLayout.Y_AXIS)); + panelTop.setLayout(new BoxLayout(panelTop, BoxLayout.Y_AXIS)); + panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.Y_AXIS)); searchField = new JTextField(); searchField.setMinimumSize(new Dimension(minWidth, 25)); - panelTop.add(searchField); + panelTop.add(searchField); jsp = new JScrollPane(); soNode = new DefaultMutableTreeNode(); generateSketchOutlineTree(soNode, codeTree); soNode = (DefaultMutableTreeNode) soNode.getChildAt(0); + tempNode = soNode; soTree = new JTree(soNode); soTree.getSelectionModel() .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); @@ -91,8 +96,8 @@ public class SketchOutline { // .getWidth() - minWidth, tp.y); frmOutlineView.setBounds(tp.x + errorCheckerService.getEditor().ta - .getWidth() - minWidth, tp.y, minWidth,Math - .min(editor.ta.getHeight(), 150)); + .getWidth() - minWidth, tp.y, minWidth, + Math.min(editor.ta.getHeight(), 150)); frmOutlineView.setMinimumSize(new Dimension(minWidth, Math .min(errorCheckerService.getEditor().ta.getHeight(), 150))); frmOutlineView.pack(); @@ -106,10 +111,13 @@ public class SketchOutline { } + protected AtomicBoolean internalSelection = new AtomicBoolean(); + protected void addListeners() { searchField.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent evt) { + internalSelection.set(true); if (evt.getKeyCode() == KeyEvent.VK_ENTER) { if (soTree.getLastSelectedPathComponent() != null) { DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree @@ -124,18 +132,45 @@ public class SketchOutline { return; } else if (evt.getKeyCode() == KeyEvent.VK_UP) { if (soTree.getLastSelectedPathComponent() == null) { + internalSelection.set(true); soTree.setSelectionRow(0); } - int x = soTree.getLeadSelectionRow(); - x = (x - 1) % soTree.getRowCount(); - soTree.setSelectionRow(x); + int x = soTree.getLeadSelectionRow() - 1; + internalSelection.set(true); + + int step = jsp.getVerticalScrollBar().getMaximum() + / soTree.getRowCount(); + log("ss " + step); + if (x == -1) { + x = tempNode.getChildCount() - 1; + soTree.setSelectionRow(x); + jsp.getVerticalScrollBar().setValue(step*soTree.getRowCount()); + } else { + soTree.setSelectionRow(x); + jsp.getVerticalScrollBar().setValue((jsp.getVerticalScrollBar() + .getValue() - step)); + //jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getValue() - jsp.getVerticalScrollBar().getBlockIncrement()); + } return; } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { if (soTree.getLastSelectedPathComponent() == null) { + internalSelection.set(true); soTree.setSelectionRow(0); } - int x = soTree.getLeadSelectionRow(); - x = (x + 1) % soTree.getRowCount(); + int x = soTree.getLeadSelectionRow() + 1; + internalSelection.set(true); + + int step = jsp.getVerticalScrollBar().getMaximum() + / soTree.getRowCount(); + log("ss" + step); + if (x == tempNode.getChildCount()) { + x = 0; + jsp.getVerticalScrollBar().setValue(0); + } else { + jsp.getVerticalScrollBar().setValue((jsp.getVerticalScrollBar() + .getValue() + step)); + } +// jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getValue() + jsp.getVerticalScrollBar().getBlockIncrement()); soTree.setSelectionRow(x); return; } @@ -154,6 +189,7 @@ public class SketchOutline { for (int i = 0; i < soTree.getRowCount(); i++) { soTree.expandRow(i); } + internalSelection.set(true); soTree.setSelectionRow(0); } }; @@ -171,12 +207,53 @@ public class SketchOutline { public void windowGainedFocus(WindowEvent e) { } }); + + soTree.addTreeSelectionListener(new TreeSelectionListener() { + + public void valueChanged(TreeSelectionEvent e) { + + if (internalSelection.get()) { + internalSelection.set(false); + return; + } + log(e); + SwingWorker worker = new SwingWorker() { + + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + if (soTree.getLastSelectedPathComponent() == null) { + return; + } + DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree + .getLastSelectedPathComponent(); + if (tnode.getUserObject() == null) { + return; + } + + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + // log(awrap); + errorCheckerService.highlightNode(awrap); + } + } + }; + worker.execute(); + } + }); + + soTree.addMouseListener(new MouseAdapter() { + + }); } protected boolean filterTree(String prefix, DefaultMutableTreeNode tree, DefaultMutableTreeNode mainTree) { - if(mainTree.isLeaf()){ - return (mainTree.getUserObject().toString().toLowerCase().startsWith(prefix)); + if (mainTree.isLeaf()) { + return (mainTree.getUserObject().toString().toLowerCase() + .startsWith(prefix)); } boolean found = false; From c8a3c8d294937b9b52a97804959ceddcdc374f59 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 11:31:28 +0530 Subject: [PATCH 163/608] Silly typo leads to chaos --- .../mode/experimental/SketchOutline.java | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 666c7ffcd..62aba64b1 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -10,7 +10,6 @@ import java.awt.event.MouseAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.BoxLayout; import javax.swing.JFrame; @@ -111,66 +110,63 @@ public class SketchOutline { } - protected AtomicBoolean internalSelection = new AtomicBoolean(); + protected boolean internalSelection = false; protected void addListeners() { searchField.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent evt) { - internalSelection.set(true); + if (soTree.getRowCount() == 0) + return; + + internalSelection = true; if (evt.getKeyCode() == KeyEvent.VK_ENTER) { if (soTree.getLastSelectedPathComponent() != null) { DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree .getLastSelectedPathComponent(); - if (tnode.getUserObject() != null) { - if (tnode.getUserObject() instanceof ASTNodeWrapper) { - ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); - errorCheckerService.highlightNode(awrap); - } + if (tnode.getUserObject() instanceof ASTNodeWrapper) { + ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); + errorCheckerService.highlightNode(awrap); } + } return; - } else if (evt.getKeyCode() == KeyEvent.VK_UP) { + } + else if (evt.getKeyCode() == KeyEvent.VK_UP) { if (soTree.getLastSelectedPathComponent() == null) { - internalSelection.set(true); soTree.setSelectionRow(0); + return; } + int x = soTree.getLeadSelectionRow() - 1; - internalSelection.set(true); - int step = jsp.getVerticalScrollBar().getMaximum() / soTree.getRowCount(); - log("ss " + step); if (x == -1) { - x = tempNode.getChildCount() - 1; - soTree.setSelectionRow(x); - jsp.getVerticalScrollBar().setValue(step*soTree.getRowCount()); + x = soTree.getRowCount() - 1; + jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getMaximum()); } else { - soTree.setSelectionRow(x); jsp.getVerticalScrollBar().setValue((jsp.getVerticalScrollBar() .getValue() - step)); - //jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getValue() - jsp.getVerticalScrollBar().getBlockIncrement()); } + soTree.setSelectionRow(x); return; - } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { + } + else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { if (soTree.getLastSelectedPathComponent() == null) { - internalSelection.set(true); soTree.setSelectionRow(0); + return; } int x = soTree.getLeadSelectionRow() + 1; - internalSelection.set(true); int step = jsp.getVerticalScrollBar().getMaximum() / soTree.getRowCount(); - log("ss" + step); - if (x == tempNode.getChildCount()) { + if (x == soTree.getRowCount()) { x = 0; - jsp.getVerticalScrollBar().setValue(0); + jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getMinimum()); } else { jsp.getVerticalScrollBar().setValue((jsp.getVerticalScrollBar() .getValue() + step)); } -// jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getValue() + jsp.getVerticalScrollBar().getBlockIncrement()); soTree.setSelectionRow(x); return; } @@ -189,12 +185,11 @@ public class SketchOutline { for (int i = 0; i < soTree.getRowCount(); i++) { soTree.expandRow(i); } - internalSelection.set(true); + internalSelection = true; soTree.setSelectionRow(0); } }; worker.execute(); - } }); @@ -212,8 +207,8 @@ public class SketchOutline { public void valueChanged(TreeSelectionEvent e) { - if (internalSelection.get()) { - internalSelection.set(false); + if (internalSelection) { + internalSelection = (false); return; } log(e); From 91bb7f43c72f55c7ff1f16ecdc20e835daf3614b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 11:54:30 +0530 Subject: [PATCH 164/608] who doesn't like some icons? --- .../mode/experimental/SketchOutline.java | 76 ++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 62aba64b1..e76591520 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -2,16 +2,18 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; +import java.io.File; import java.util.List; import javax.swing.BoxLayout; +import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -22,14 +24,18 @@ import javax.swing.SwingWorker; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import processing.app.Base; + public class SketchOutline { protected JFrame frmOutlineView; @@ -78,21 +84,21 @@ public class SketchOutline { soTree.getSelectionModel() .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); soTree.setRootVisible(false); + soTree.setCellRenderer(new CustomCellRenderer()); for (int i = 0; i < soTree.getRowCount(); i++) { soTree.expandRow(i); } soTree.setSelectionRow(0); + jsp.setViewportView(soTree); jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); jsp.setMinimumSize(new Dimension(minWidth, 100)); + panelBottom.add(jsp); frmOutlineView.add(panelTop); frmOutlineView.add(panelBottom); frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); -// frmOutlineView.setLocation(tp.x -// + errorCheckerService.getEditor().ta -// .getWidth() - minWidth, tp.y); frmOutlineView.setBounds(tp.x + errorCheckerService.getEditor().ta .getWidth() - minWidth, tp.y, minWidth, @@ -238,10 +244,6 @@ public class SketchOutline { worker.execute(); } }); - - soTree.addMouseListener(new MouseAdapter() { - - }); } protected boolean filterTree(String prefix, DefaultMutableTreeNode tree, @@ -276,7 +278,7 @@ public class SketchOutline { ASTNodeWrapper awnode = (ASTNodeWrapper) codetree.getUserObject(), aw2 = null; if (awnode.getNode() instanceof TypeDeclaration) { - aw2 = new ASTNodeWrapper(awnode.getNode(), + aw2 = new ASTNodeWrapper( ((TypeDeclaration) awnode.getNode()).getName(), ((TypeDeclaration) awnode.getNode()).getName() .toString()); } else if (awnode.getNode() instanceof MethodDeclaration) { @@ -313,4 +315,60 @@ public class SketchOutline { public void show() { frmOutlineView.setVisible(true); } + + protected class CustomCellRenderer extends DefaultTreeCellRenderer { + + // ImageIcon icons[]; + protected final ImageIcon classIcon, fieldIcon, methodIcon; + + public CustomCellRenderer() { + String iconPath = "data" + File.separator + "icons"; + if (editor != null) { + iconPath = (Base.getSketchbookFolder().getAbsolutePath()) + + + File.separator + "modes" + File.separator + "ExperimentalMode" + + File.separator + "data" + File.separator + "icons"; + ; + } + + classIcon = new ImageIcon(iconPath + File.separator + + "class_obj.png"); + methodIcon = new ImageIcon(iconPath + File.separator + + "methpub_obj.png"); + fieldIcon = new ImageIcon(iconPath + File.separator + + "field_protected_obj.png"); + } + + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean sel, boolean expanded, boolean leaf, int row, + boolean hasFocus) { + + super.getTreeCellRendererComponent(tree, value, sel, expanded, + leaf, row, hasFocus); + if (value instanceof DefaultMutableTreeNode) + setIcon(getTreeIcon(value)); + + return this; + } + + public javax.swing.Icon getTreeIcon(Object o) { + if (o instanceof DefaultMutableTreeNode) { + + if(((DefaultMutableTreeNode) o) + .getUserObject() instanceof ASTNodeWrapper){ + + ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) o) + .getUserObject(); + int type = awrap.getNode().getParent().getNodeType(); + if (type == ASTNode.METHOD_DECLARATION) + return methodIcon; + if (type == ASTNode.TYPE_DECLARATION) + return classIcon; + if (type == ASTNode.VARIABLE_DECLARATION_FRAGMENT) + return fieldIcon; + } + } + return null; + } + } } From 3f7efd4da54a3de5abb47e17d2e7a912cff58716 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 11:57:04 +0530 Subject: [PATCH 165/608] constructors edge case --- .../mode/experimental/CompletionCandidate.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 6fa6fb096..5c3761db4 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -41,8 +41,9 @@ public class CompletionCandidate implements Comparable{ cstr.append(' '); } label.append(")"); - label.append(" : " + method.getReturnType().getSimpleName() + " - " - + method.getDeclaringClass().getSimpleName()); + if(method.getReturnType() != null) + label.append(" : " + method.getReturnType().getSimpleName()); + label.append(" - " + method.getDeclaringClass().getSimpleName()); cstr.append(")"); this.label = label.toString(); this.completionString = cstr.toString(); @@ -73,21 +74,22 @@ public class CompletionCandidate implements Comparable{ StringBuffer cstr = new StringBuffer(method.getName() + "("); for (int i = 0; i < params.size(); i++) { label.append(params.get(i).toString()); - if (i < params.size() - 1){ + if (i < params.size() - 1) { label.append(","); cstr.append(","); } } - if(params.size() == 1) { + if (params.size() == 1) { cstr.append(' '); } label.append(")"); - label.append(" : "+method.getReturnType2()); + if (method.getReturnType2() != null) + label.append(" : " + method.getReturnType2()); cstr.append(")"); this.label = label.toString(); this.completionString = cstr.toString(); } - + public CompletionCandidate(TypeDeclaration td){ type = LOCAL_CLASS; elementName = td.getName().toString(); From a6af2cf54a6c19cb49ea1705777a6ae858f6c29c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 12:20:24 +0530 Subject: [PATCH 166/608] minor tweaks --- .../mode/experimental/ASTGenerator.java | 7 ++- .../experimental/ErrorCheckerService.java | 10 ++-- .../mode/experimental/SketchOutline.java | 59 +++++++++++-------- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index a9609315b..bb9ac4de4 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -982,6 +982,7 @@ public class ASTGenerator { } private void showPredictions(final String word) { + if(sketchOutline.isVisible()) return; Collections.sort(candidates); CompletionCandidate[][] candi = new CompletionCandidate[candidates.size()][1]; DefaultListModel defListModel = new DefaultListModel(); @@ -2069,10 +2070,10 @@ public class ASTGenerator { } } - protected SketchOutline sko; + protected SketchOutline sketchOutline; protected void showSketchOutline(){ - sko = new SketchOutline(codeTree, errorCheckerService); - sko.show(); + sketchOutline = new SketchOutline(codeTree, errorCheckerService); + sketchOutline.show(); } public int javaCodeOffsetToLineStartOffset(int line, int jOffset){ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 3853a367d..e565b11c4 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1,6 +1,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.EventQueue; import java.io.File; @@ -881,6 +882,7 @@ public class ErrorCheckerService implements Runnable{ } public String getPDECodeAtLine(int tab, int linenumber){ + if(linenumber < 0) return null; editor.getSketch().setCurrentCode(tab); return editor.ta.getLineText(linenumber); } @@ -1116,16 +1118,16 @@ public class ErrorCheckerService implements Runnable{ * @return true - if highlighting happened correctly. */ public boolean highlightNode(ASTNodeWrapper awrap){ - int pdeoffsets[] = awrap.getPDECodeOffsets(this); - int javaoffsets[] = awrap.getJavaCodeOffsets(this); try { + int pdeoffsets[] = awrap.getPDECodeOffsets(this); + int javaoffsets[] = awrap.getJavaCodeOffsets(this); scrollToErrorLine(editor, pdeoffsets[0], pdeoffsets[1],javaoffsets[1], javaoffsets[2]); return true; } catch (Exception e) { - - e.printStackTrace(); + logE("Scrolling failed for " + awrap); + // e.printStackTrace(); } return false; } diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index e76591520..527c85c88 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -126,17 +126,20 @@ public class SketchOutline { return; internalSelection = true; - if (evt.getKeyCode() == KeyEvent.VK_ENTER) { + + if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) { + close(); + } + else if (evt.getKeyCode() == KeyEvent.VK_ENTER) { if (soTree.getLastSelectedPathComponent() != null) { DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree .getLastSelectedPathComponent(); if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); errorCheckerService.highlightNode(awrap); + close(); } - } - return; } else if (evt.getKeyCode() == KeyEvent.VK_UP) { if (soTree.getLastSelectedPathComponent() == null) { @@ -155,7 +158,6 @@ public class SketchOutline { .getValue() - step)); } soTree.setSelectionRow(x); - return; } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { if (soTree.getLastSelectedPathComponent() == null) { @@ -174,28 +176,28 @@ public class SketchOutline { .getValue() + step)); } soTree.setSelectionRow(x); - return; } - - SwingWorker worker = new SwingWorker() { - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - String text = searchField.getText().toLowerCase(); - tempNode = new DefaultMutableTreeNode(); - filterTree(text, tempNode, soNode); - soTree.setModel(new DefaultTreeModel(tempNode)); - ((DefaultTreeModel) soTree.getModel()).reload(); - for (int i = 0; i < soTree.getRowCount(); i++) { - soTree.expandRow(i); + else { + SwingWorker worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + return null; } - internalSelection = true; - soTree.setSelectionRow(0); - } - }; - worker.execute(); + + protected void done() { + String text = searchField.getText().toLowerCase(); + tempNode = new DefaultMutableTreeNode(); + filterTree(text, tempNode, soNode); + soTree.setModel(new DefaultTreeModel(tempNode)); + ((DefaultTreeModel) soTree.getModel()).reload(); + for (int i = 0; i < soTree.getRowCount(); i++) { + soTree.expandRow(i); + } + internalSelection = true; + soTree.setSelectionRow(0); + } + }; + worker.execute(); + } } }); @@ -316,6 +318,15 @@ public class SketchOutline { frmOutlineView.setVisible(true); } + public void close(){ + frmOutlineView.setVisible(false); + frmOutlineView.dispose(); + } + + public boolean isVisible(){ + return frmOutlineView.isVisible(); + } + protected class CustomCellRenderer extends DefaultTreeCellRenderer { // ImageIcon icons[]; From bc5eff6141b55bf89dbf4fd7ced7cebf9f46509c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 12:30:38 +0530 Subject: [PATCH 167/608] refresh stuff --- pdex/src/processing/mode/experimental/DebugEditor.java | 2 ++ pdex/src/processing/mode/experimental/SketchOutline.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 3649a6dc3..b4d8f6abc 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -476,6 +476,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { errorCheckerService.resumeThread(); System.out.println(thisEditor.getSketch().getName() + " - Error Checker resumed."); + errorCheckerService.runManualErrorCheck(); } } }); @@ -507,6 +508,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void actionPerformed(ActionEvent e) { errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e .getSource()).isSelected(); + errorCheckerService.runManualErrorCheck(); } }); debugMenu.add(showWarnings); diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 527c85c88..460dadbb0 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -337,7 +337,7 @@ public class SketchOutline { if (editor != null) { iconPath = (Base.getSketchbookFolder().getAbsolutePath()) - + File.separator + "modes" + File.separator + "ExperimentalMode" + + File.separator + "modes" + File.separator + editor.getMode().getClass().getSimpleName() + File.separator + "data" + File.separator + "icons"; ; } From 76cfe9fc1402e9e55237cd181e302d1ec2feb7a2 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 12:37:44 +0530 Subject: [PATCH 168/608] SO cleanup --- .../mode/experimental/SketchOutline.java | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 460dadbb0..df99e1da8 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -203,8 +203,7 @@ public class SketchOutline { frmOutlineView.addWindowFocusListener(new WindowFocusListener() { public void windowLostFocus(WindowEvent e) { - frmOutlineView.setVisible(false); - frmOutlineView.dispose(); + close(); } public void windowGainedFocus(WindowEvent e) { @@ -219,7 +218,7 @@ public class SketchOutline { internalSelection = (false); return; } - log(e); + // log(e); SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { @@ -329,21 +328,17 @@ public class SketchOutline { protected class CustomCellRenderer extends DefaultTreeCellRenderer { - // ImageIcon icons[]; protected final ImageIcon classIcon, fieldIcon, methodIcon; public CustomCellRenderer() { String iconPath = "data" + File.separator + "icons"; - if (editor != null) { - iconPath = (Base.getSketchbookFolder().getAbsolutePath()) + iconPath = (Base.getSketchbookFolder().getAbsolutePath()) + + File.separator + "modes" + File.separator + + editor.getMode().getClass().getSimpleName() + File.separator + + "data" + File.separator + "icons"; + ; - + File.separator + "modes" + File.separator + editor.getMode().getClass().getSimpleName() - + File.separator + "data" + File.separator + "icons"; - ; - } - - classIcon = new ImageIcon(iconPath + File.separator - + "class_obj.png"); + classIcon = new ImageIcon(iconPath + File.separator + "class_obj.png"); methodIcon = new ImageIcon(iconPath + File.separator + "methpub_obj.png"); fieldIcon = new ImageIcon(iconPath + File.separator @@ -363,11 +358,8 @@ public class SketchOutline { } public javax.swing.Icon getTreeIcon(Object o) { - if (o instanceof DefaultMutableTreeNode) { + if (((DefaultMutableTreeNode) o).getUserObject() instanceof ASTNodeWrapper) { - if(((DefaultMutableTreeNode) o) - .getUserObject() instanceof ASTNodeWrapper){ - ASTNodeWrapper awrap = (ASTNodeWrapper) ((DefaultMutableTreeNode) o) .getUserObject(); int type = awrap.getNode().getParent().getNodeType(); @@ -377,7 +369,6 @@ public class SketchOutline { return classIcon; if (type == ASTNode.VARIABLE_DECLARATION_FRAGMENT) return fieldIcon; - } } return null; } From fdd42b4544c6b538df372d848faa328061a9f868 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 13:02:58 +0530 Subject: [PATCH 169/608] todo update --- pdex/Todo, GSoC 2013.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 8bd19699b..8bee7b5f4 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -105,6 +105,7 @@ Sketch Outline x Show Sketch Outline Tree x Filter stuff in text field +x Add icons - custom cell renderer Suggestion for missing imports ============================== From a5a9f1417b9d3101ed1fc00575d732ca23560515 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 13:51:27 +0530 Subject: [PATCH 170/608] document listener added --- .../mode/experimental/ASTGenerator.java | 3 +- .../mode/experimental/DebugEditor.java | 20 ++++++- .../mode/experimental/SketchOutline.java | 56 ++++++++++++------- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index bb9ac4de4..adfd923d1 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -982,7 +982,8 @@ public class ASTGenerator { } private void showPredictions(final String word) { - if(sketchOutline.isVisible()) return; + if (sketchOutline != null) + if (sketchOutline.isVisible()) return; Collections.sort(candidates); CompletionCandidate[][] candi = new CompletionCandidate[candidates.size()][1]; DefaultListModel defListModel = new DefaultListModel(); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index b4d8f6abc..0f9cc92cb 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -161,6 +161,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected JMenuItem showOutline; + /** + * Enable/Disable error logging + */ + protected JCheckBoxMenuItem writeErrorLog; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -313,10 +318,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ - writeErrorsToFile(); + if(enableErrorLogging) writeErrorsToFile(); super.internalCloseRunner(); } + protected boolean enableErrorLogging = false; + private void writeErrorsToFile(){ if (errorCheckerService.tempErrorLog.size() == 0) return; @@ -528,6 +535,17 @@ public class DebugEditor extends JavaEditor implements ActionListener { showOutline.addActionListener(this); debugMenu.add(showOutline); + writeErrorLog = new JCheckBoxMenuItem("Write Errors to Log"); + writeErrorLog.setSelected(enableErrorLogging); + writeErrorLog.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + enableErrorLogging = !enableErrorLogging; + } + }); + debugMenu.add(writeErrorLog); + + return debugMenu; } diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index df99e1da8..b135a6fbc 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -21,6 +21,8 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ScrollPaneConstants; import javax.swing.SwingWorker; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; @@ -177,27 +179,43 @@ public class SketchOutline { } soTree.setSelectionRow(x); } - else { - SwingWorker worker = new SwingWorker() { - protected Object doInBackground() throws Exception { - return null; - } + } + }); + + searchField.getDocument().addDocumentListener(new DocumentListener() { - protected void done() { - String text = searchField.getText().toLowerCase(); - tempNode = new DefaultMutableTreeNode(); - filterTree(text, tempNode, soNode); - soTree.setModel(new DefaultTreeModel(tempNode)); - ((DefaultTreeModel) soTree.getModel()).reload(); - for (int i = 0; i < soTree.getRowCount(); i++) { - soTree.expandRow(i); - } - internalSelection = true; - soTree.setSelectionRow(0); + public void insertUpdate(DocumentEvent e) { + updateSelection(); + } + + public void removeUpdate(DocumentEvent e) { + updateSelection(); + } + + public void changedUpdate(DocumentEvent e) { + updateSelection(); + } + + private void updateSelection(){ + SwingWorker worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + return null; + } + + protected void done() { + String text = searchField.getText().toLowerCase(); + tempNode = new DefaultMutableTreeNode(); + filterTree(text, tempNode, soNode); + soTree.setModel(new DefaultTreeModel(tempNode)); + ((DefaultTreeModel) soTree.getModel()).reload(); + for (int i = 0; i < soTree.getRowCount(); i++) { + soTree.expandRow(i); } - }; - worker.execute(); - } + internalSelection = true; + soTree.setSelectionRow(0); + } + }; + worker.execute(); } }); From 8a9704b35a224b918e2e050bfcf9ae940c9f976d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 15:46:47 +0530 Subject: [PATCH 171/608] find closest node bug fix --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 16 +++-- .../experimental/ErrorCheckerService.java | 5 +- .../mode/experimental/TextArea.java | 62 +------------------ 4 files changed, 17 insertions(+), 67 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 8bee7b5f4..3866a19b4 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -15,6 +15,7 @@ The big stuff: - Making very good progress here. The elegance of recurion - Hats off! - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) +* Ensure that a compilation unit is created at startup! * Scope handling? Static/non static scope? * Disable completions on comment line * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index adfd923d1..9302e910e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -264,9 +264,9 @@ public class ASTGenerator { return; jtree.setModel(new DefaultTreeModel(codeTree)); ((DefaultTreeModel) jtree.getModel()).reload(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if (!frame2.isVisible()) { + frame2.setVisible(true); + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -1389,7 +1389,9 @@ public class ASTGenerator { if (nodes.size() > 0) { ASTNode retNode = nodes.get(0); for (ASTNode cNode : nodes) { - if (getLineNumber(cNode) <= lineNumber) + if (getLineNumber(cNode) <= lineNumber + && lineNumber <= getLineNumber(cNode, cNode.getStartPosition() + + cNode.getLength())) retNode = cNode; else break; @@ -1397,7 +1399,7 @@ public class ASTGenerator { return retNode; } - return null; + return parent; } public DefaultMutableTreeNode getAST() { @@ -1657,6 +1659,10 @@ public class ASTGenerator { return ((CompilationUnit) node.getRoot()).getLineNumber(node .getStartPosition()); } + + public static int getLineNumber(ASTNode node, int pos) { + return ((CompilationUnit) node.getRoot()).getLineNumber(pos); + } public static void main(String[] args) { //traversal2(); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index e565b11c4..6d5d24e36 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -248,6 +248,8 @@ public class ErrorCheckerService implements Runnable{ stopThread = false; checkCode(); + if(!hasSyntaxErrors()) + editor.showProblemListView(XQConsoleToggle.CONSOLE); while (!stopThread) { try { // Take a nap. @@ -778,6 +780,7 @@ public class ErrorCheckerService implements Runnable{ // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); boolean notFound = true; + //if(notFound) return; for (ErrorMarker emarker : editor.errorBar.errorPoints) { if (emarker.problem.lineNumber == editor.getTextArea() .getCaretLine() + 1) { @@ -794,7 +797,7 @@ public class ErrorCheckerService implements Runnable{ } } if (notFound) { - editor.statusEmpty(); + //editor.statusEmpty(); } } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 39282d3ef..35c3378ae 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -169,27 +169,6 @@ public class TextArea extends JEditTextArea { return; } break; -// case KeyEvent.VK_ENTER: -// if (suggestion != null) { -// if (suggestion.isVisible()) { -// if (suggestion.insertSelection()) { -// hideSuggestion(); // Kill it! -// //final int position = getCaretPosition(); -// SwingUtilities.invokeLater(new Runnable() { -// @Override -// public void run() { -// try { -// //getDocument().remove(position - 1, 1); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// }); -// return; -// } -// } -// } -// break; case KeyEvent.VK_BACK_SPACE: log("BK Key"); break; @@ -199,45 +178,6 @@ public class TextArea extends JEditTextArea { } super.processKeyEvent(evt); - /* - if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) { - if (suggestion.isVisible()) { - //log("KeyDown"); - suggestion.moveDown(); - return; - } - } else if (evt.getKeyCode() == KeyEvent.VK_UP && suggestion != null) { - if (suggestion.isVisible()) { - //log("KeyUp"); - suggestion.moveUp(); - return; - } - } - if (evt.getKeyChar() == KeyEvent.VK_ENTER) { - if (suggestion != null) { - if (suggestion.isVisible()){ - if (suggestion.insertSelection()) { - final int position = getCaretPosition(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - //getDocument().remove(position - 1, 1); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - return; - } - } - } - } else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) { - log("BK Key"); - } - - }*/ - if (evt.getID() == KeyEvent.KEY_TYPED) { errorCheckerService.runManualErrorCheck(); log(" Typing: " + fetchPhrase(evt) + " " @@ -321,7 +261,7 @@ public class TextArea extends JEditTextArea { else if (keyChar == KeyEvent.VK_ESCAPE) { //log("ESC keypress. fetchPhrase()"); return null; - } else if (keyChar == KeyEvent.CHAR_UNDEFINED) { + } else if (keyChar == KeyEvent.VK_TAB || keyChar == KeyEvent.CHAR_UNDEFINED) { return null; } } From 432331e1a635a48403d3ee5874fff3998e457097 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 15:58:18 +0530 Subject: [PATCH 172/608] fixes #2 --- .../mode/experimental/ErrorCheckerService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 6d5d24e36..72b8851af 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -771,7 +771,7 @@ public class ErrorCheckerService implements Runnable{ } } - + protected int lastCaretLine = -1; /** * Updates editor status bar, depending on whether the caret is on an error * line or not @@ -779,8 +779,6 @@ public class ErrorCheckerService implements Runnable{ public void updateEditorStatus() { // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); - boolean notFound = true; - //if(notFound) return; for (ErrorMarker emarker : editor.errorBar.errorPoints) { if (emarker.problem.lineNumber == editor.getTextArea() .getCaretLine() + 1) { @@ -796,8 +794,9 @@ public class ErrorCheckerService implements Runnable{ return; } } - if (notFound) { - //editor.statusEmpty(); + if (editor.ta.getCaretLine() != lastCaretLine) { + editor.statusEmpty(); + lastCaretLine = editor.ta.getCaretLine(); } } From a66681fb8243ed0b04de94d334f66bf85007f846 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 16:03:23 +0530 Subject: [PATCH 173/608] uncomment error id names --- .../mode/experimental/ErrorCheckerService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 72b8851af..2a446997c 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -710,8 +710,8 @@ public class ErrorCheckerService implements Runnable{ try { String[][] errorData = new String[problemsList.size()][3]; for (int i = 0; i < problemsList.size(); i++) { - errorData[i][0] = problemsList.get(i).message ////TODO: this is temporary - + " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); + errorData[i][0] = problemsList.get(i).message; ////TODO: this is temporary + //+ " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); errorData[i][1] = editor.getSketch() .getCode(problemsList.get(i).tabIndex).getPrettyName(); errorData[i][2] = problemsList.get(i).lineNumber + ""; @@ -783,13 +783,13 @@ public class ErrorCheckerService implements Runnable{ if (emarker.problem.lineNumber == editor.getTextArea() .getCaretLine() + 1) { if (emarker.type == ErrorMarker.Warning) { - editor.statusNotice(emarker.problem.message - + " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); + editor.statusNotice(emarker.problem.message); + //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); //TODO: this is temporary } else { - editor.statusError(emarker.problem.message - + " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); + editor.statusError(emarker.problem.message); + //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); } return; } From e307fed1b5296d979b174cd354db921ab65c6b24 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 18:05:04 +0530 Subject: [PATCH 174/608] these tiny tiny bugs.. grr --- .../mode/experimental/ASTGenerator.java | 65 ++++++++++--------- .../experimental/ErrorCheckerService.java | 6 +- .../mode/experimental/TextArea.java | 2 + 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9302e910e..3ca76702d 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -250,6 +250,10 @@ public class ASTGenerator { getCodeComments(); codeTree = new DefaultMutableTreeNode(new ASTNodeWrapper((ASTNode) compilationUnit .types().get(0))); + log("Total CU " + compilationUnit.types().size()); + if(compilationUnit.types() == null || compilationUnit.types().isEmpty()){ + logE("No CU found!"); + } visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); SwingWorker worker = new SwingWorker() { @@ -352,6 +356,7 @@ public class ASTGenerator { // } classPath = factory.createFromPath(tehPath.toString()); + log("Classpath created " + (classPath != null)); // for (String packageName : classPath.listPackages("")) { // log(packageName); // } @@ -916,30 +921,32 @@ public class ASTGenerator { // We're seeing a simple name that's not defined locally or in // the parent class. So most probably a pre-defined type. log("Empty can. " + word2); - RegExpResourceFilter regExpResourceFilter; - regExpResourceFilter = new RegExpResourceFilter( - Pattern.compile(".*"), - Pattern - .compile(word2 - + "[a-zA-Z_0-9]*.class", - Pattern.CASE_INSENSITIVE)); - String[] resources = classPath - .findResources("", regExpResourceFilter); - for (String matchedClass2 : resources) { - matchedClass2 = matchedClass2.replace('/', '.'); - String matchedClass = matchedClass2.substring(0, matchedClass2 - .length() - 6); - if(ignorableImport(matchedClass2)) - continue; - int d = matchedClass.lastIndexOf('.'); - matchedClass = matchedClass.substring(d + 1); - candidates - .add(new CompletionCandidate(matchedClass, matchedClass + " : " - + matchedClass2.substring(0, d), matchedClass, - CompletionCandidate.PREDEF_CLASS)); - //log("-> " + className); + if (classPath != null) { + RegExpResourceFilter regExpResourceFilter; + regExpResourceFilter = new RegExpResourceFilter( + Pattern + .compile(".*"), + Pattern + .compile(word2 + + "[a-zA-Z_0-9]*.class", + Pattern.CASE_INSENSITIVE)); + String[] resources = classPath.findResources("", + regExpResourceFilter); + for (String matchedClass2 : resources) { + matchedClass2 = matchedClass2.replace('/', '.'); + String matchedClass = matchedClass2.substring(0, matchedClass2 + .length() - 6); + if (ignorableImport(matchedClass2)) + continue; + int d = matchedClass.lastIndexOf('.'); + matchedClass = matchedClass.substring(d + 1); + candidates + .add(new CompletionCandidate(matchedClass, matchedClass + + " : " + matchedClass2.substring(0, d), matchedClass, + CompletionCandidate.PREDEF_CLASS)); + //log("-> " + className); + } } - } else { // ==> Complex expression of type blah.blah2().doIt,etc @@ -1366,7 +1373,6 @@ public class ASTGenerator { return node; } - @SuppressWarnings("unchecked") private static ASTNode findClosestNode(int lineNumber, ASTNode node) { ASTNode parent = findClosestParentNode(lineNumber, node); if (parent == null) @@ -1387,14 +1393,15 @@ public class ASTGenerator { } if (nodes.size() > 0) { - ASTNode retNode = nodes.get(0); - for (ASTNode cNode : nodes) { - if (getLineNumber(cNode) <= lineNumber + ASTNode retNode = parent; + for (int i = nodes.size() - 1; i >= 0; i--) { + ASTNode cNode = nodes.get(i); + if (getLineNumber(cNode) == lineNumber) + return cNode; + else if (getLineNumber(cNode) <= lineNumber && lineNumber <= getLineNumber(cNode, cNode.getStartPosition() + cNode.getLength())) retNode = cNode; - else - break; } return retNode; diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 2a446997c..f13cd237b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -306,10 +306,11 @@ public class ErrorCheckerService implements Runnable{ log(editor.getSketch().getName() + "1 MCO " + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. - + + astGenerator.buildAST(cu); if (problems.length == 0 && editor.compilationCheckEnabled) { //mainClassOffset++; // just a hack. - astGenerator.buildAST(cu); + sourceCode = xqpreproc.doYourThing(sourceCode, programImports); prepareCompilerClasspath(); // mainClassOffset = xqpreproc.mainClassOffset; // tiny, but @@ -392,6 +393,7 @@ public class ErrorCheckerService implements Runnable{ syntaxErrors.set(false); else syntaxErrors.set(true); + astGenerator.loadJars(); } protected URLClassLoader classLoader; private void compileCheck() { diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 35c3378ae..00e1282d5 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -294,6 +294,7 @@ public class TextArea extends JEditTextArea { word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); + if(word.length() > 1) errorCheckerService.astGenerator.preparePredictions(word, line + errorCheckerService.mainClassOffset,0); return word; @@ -371,6 +372,7 @@ public class TextArea extends JEditTextArea { // if (word.endsWith(".")) // word = word.substring(0, word.length() - 1); int lineStartNonWSOffset = 0; + if(word.length() > 1) errorCheckerService.astGenerator.preparePredictions(word, line + errorCheckerService.mainClassOffset,lineStartNonWSOffset); //showSuggestionLater(); From 662877487d752d1907380c53f08c7279ccb0cce3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 18:26:58 +0530 Subject: [PATCH 175/608] fix one thing, break the other, rinse, repeat. --- .../src/processing/mode/experimental/ASTGenerator.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 3ca76702d..a12b417b0 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1394,13 +1394,9 @@ public class ASTGenerator { if (nodes.size() > 0) { ASTNode retNode = parent; - for (int i = nodes.size() - 1; i >= 0; i--) { - ASTNode cNode = nodes.get(i); - if (getLineNumber(cNode) == lineNumber) - return cNode; - else if (getLineNumber(cNode) <= lineNumber - && lineNumber <= getLineNumber(cNode, cNode.getStartPosition() - + cNode.getLength())) + for (int i = 0; i < nodes.size(); i++) { + ASTNode cNode = nodes.get(i); + if (getLineNumber(cNode) <= lineNumber) retNode = cNode; } From c3c2a29289aacbcbe9eb68d89c4f4e2d2e7b5dd1 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 18:37:59 +0530 Subject: [PATCH 176/608] notes on text modified --- .../mode/experimental/ASTGenerator.java | 16 ++++++++-------- .../mode/experimental/ErrorCheckerService.java | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index a12b417b0..6a71610f8 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -264,13 +264,13 @@ public class ASTGenerator { protected void done() { if (codeTree != null) { - if (jtree.hasFocus() || frame2.hasFocus()) - return; - jtree.setModel(new DefaultTreeModel(codeTree)); - ((DefaultTreeModel) jtree.getModel()).reload(); - if (!frame2.isVisible()) { - frame2.setVisible(true); - } +// if (jtree.hasFocus() || frame2.hasFocus()) +// return; +// jtree.setModel(new DefaultTreeModel(codeTree)); +// ((DefaultTreeModel) jtree.getModel()).reload(); +// if (!frame2.isVisible()) { +// frame2.setVisible(true); +// } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -288,7 +288,7 @@ public class ASTGenerator { // .getY(), 450, 600)); // jdocWindow.setVisible(true); // } - jtree.validate(); +// jtree.validate(); } } }; diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index f13cd237b..89c9266be 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -286,7 +286,13 @@ public class ErrorCheckerService implements Runnable{ } protected ASTGenerator astGenerator; - private AtomicInteger textModified = new AtomicInteger(); + /** + * This thing acts as an event queue counter of sort. + * Since error checking happens on demand, anytime this counter + * goes above 0, error check is triggered, and counter reset. + * It's thread safe to avoid any mess. + */ + protected AtomicInteger textModified = new AtomicInteger(); /** * Triggers error check @@ -332,12 +338,12 @@ public class ErrorCheckerService implements Runnable{ updatePaintedThingys(); int x = textModified.get(); //log("TM " + x); - if(x>=3){ - textModified.set(3); - x = 3; + if (x >= 2) { + textModified.set(2); + x = 2; } - - if(x>0) + + if (x > 0) textModified.set(x - 1); else textModified.set(0); From a06f27656ee18d6ba70852bcf5ffd2c40e13edf0 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 18:48:03 +0530 Subject: [PATCH 177/608] Ctrl + J was broken, so switched to Ctrl + H. :P --- pdex/src/processing/mode/experimental/DebugEditor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 0f9cc92cb..ce341b7fb 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -416,11 +416,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { listBreakpointsMenuItem = new JMenuItem("List Breakpoints"); listBreakpointsMenuItem.addActionListener(this); - stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_J); + stepOverMenuItem = Toolkit.newJMenuItem("Step", KeyEvent.VK_H); stepOverMenuItem.addActionListener(this); - stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_J); + stepIntoMenuItem = Toolkit.newJMenuItemShift("Step Into", KeyEvent.VK_H); stepIntoMenuItem.addActionListener(this); - stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_J); + stepOutMenuItem = Toolkit.newJMenuItemAlt("Step Out", KeyEvent.VK_H); stepOutMenuItem.addActionListener(this); printStackTraceMenuItem = new JMenuItem("Print Stack Trace"); From 6384d548ec9bf1a3c07ff4286fc3391c6ff66f10 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 18:49:46 +0530 Subject: [PATCH 178/608] Workaround for #5, todo updates --- pdex/Todo, GSoC 2013.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 3866a19b4..83602d2ad 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -15,11 +15,11 @@ The big stuff: - Making very good progress here. The elegance of recurion - Hats off! - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) -* Ensure that a compilation unit is created at startup! * Scope handling? Static/non static scope? * Disable completions on comment line * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. +x Ensure that a compilation unit is created at startup! x! Code competition for local code is working with recursive look up. x Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed x Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. @@ -131,5 +131,6 @@ General Stuff x Add option for toggling debug output x On Run/Debug Console is visible(ProblemsList hidden) +* Update wiki for Ctrl + H instead of Ctrl + J shortcuts * update build.xml to produce dists * Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc From 6f224eb7b3999eb42a787db31f4553d32e6a28ea Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 19:16:16 +0530 Subject: [PATCH 179/608] minor fixes --- .../mode/experimental/ErrorCheckerService.java | 3 +-- .../processing/mode/experimental/SketchOutline.java | 10 +++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 89c9266be..f25a08854 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -424,8 +424,7 @@ public class ErrorCheckerService implements Runnable{ // .println("Experimental Mode: Loading contributed libraries referenced by import statements."); // The folder SketchBook/modes/ExperimentalMode/mode - File f = new File(Base.getSketchbookModesFolder().getAbsolutePath() + File.separator + "ExperimentalMode" - + File.separator + "mode"); + File f = editor.getMode().getContentFile("mode"); if(!f.exists()) { System.err.println("Could not locate the files required for on-the-fly error checking. Bummer."); diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index b135a6fbc..f753d15d0 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -349,13 +349,9 @@ public class SketchOutline { protected final ImageIcon classIcon, fieldIcon, methodIcon; public CustomCellRenderer() { - String iconPath = "data" + File.separator + "icons"; - iconPath = (Base.getSketchbookFolder().getAbsolutePath()) - + File.separator + "modes" + File.separator - + editor.getMode().getClass().getSimpleName() + File.separator - + "data" + File.separator + "icons"; - ; - + String iconPath = editor.getMode().getContentFile("data") + .getAbsolutePath() + + File.separator + "icons"; classIcon = new ImageIcon(iconPath + File.separator + "class_obj.png"); methodIcon = new ImageIcon(iconPath + File.separator + "methpub_obj.png"); From 19e53fd6ba50227f5705218d823ab90f6a789feb Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 19:23:36 +0530 Subject: [PATCH 180/608] adding icons and application files --- .../Contents/MacOS/JavaApplicationStub | Bin 0 -> 61376 bytes .../application/template.app/Contents/PkgInfo | 1 + .../Contents/Resources/sketch.icns | Bin 0 -> 174666 bytes pdex/application/template.exe | Bin 0 -> 57156 bytes pdex/application/template.plist | 77 ++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 pdex/application/template.app/Contents/MacOS/JavaApplicationStub create mode 100644 pdex/application/template.app/Contents/PkgInfo create mode 100644 pdex/application/template.app/Contents/Resources/sketch.icns create mode 100644 pdex/application/template.exe create mode 100644 pdex/application/template.plist diff --git a/pdex/application/template.app/Contents/MacOS/JavaApplicationStub b/pdex/application/template.app/Contents/MacOS/JavaApplicationStub new file mode 100644 index 0000000000000000000000000000000000000000..56ec300e5ebd8616cd4652e7da35bccc0cba002d GIT binary patch literal 61376 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 M21E_~n`_|z0F=8<$^ZZW literal 0 HcmV?d00001 diff --git a/pdex/application/template.app/Contents/PkgInfo b/pdex/application/template.app/Contents/PkgInfo new file mode 100644 index 000000000..bd04210fb --- /dev/null +++ b/pdex/application/template.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/pdex/application/template.app/Contents/Resources/sketch.icns b/pdex/application/template.app/Contents/Resources/sketch.icns new file mode 100644 index 0000000000000000000000000000000000000000..2bdb4dfc22bf16a82544999627970c89d7d63939 GIT binary patch literal 174666 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�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

    QXfc16$dVbe$MlV15l4Yvr8~)<% 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 z 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 aVE8LnRiZ + + + + CFBundleName + @@sketch@@ + CFBundleVersion + 1.0 + CFBundleAllowMixedLocalizations + true + CFBundleExecutable + JavaApplicationStub + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIconFile + sketch.icns + CFBundleIdentifier + @@sketch@@ + + + LSUIPresentationMode + @@lsuipresentationmode@@ + + LSArchitecturePriority + + @@lsarchitecturepriority@@ + + + Java + + VMOptions + @@vmoptions@@ + + MainClass + @@sketch@@ + + + JVMVersion + 1.6* + + ClassPath + @@classpath@@ + + + Properties + + apple.laf.useScreenMenuBar + true + apple.awt.showGrowBox + false + com.apple.smallTabs + true + apple.awt.Antialiasing + false + apple.awt.TextAntialiasing + true + com.apple.hwaccel + true + + apple.awt.use-file-dialog-packages + true + + + + From c639748e8728cacfbbc8ed588142c60e5847c168 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 18 Aug 2013 21:20:37 +0530 Subject: [PATCH 181/608] working on build.xml --- pdex/.gitignore | 2 +- pdex/build.properties | 4 +- pdex/build.xml | 136 ++++++++++++++++++++++++++---------------- 3 files changed, 87 insertions(+), 55 deletions(-) diff --git a/pdex/.gitignore b/pdex/.gitignore index d86e35085..60f681921 100644 --- a/pdex/.gitignore +++ b/pdex/.gitignore @@ -4,4 +4,4 @@ *~ bin mode/ExperimentalMode.jar - +dist diff --git a/pdex/build.properties b/pdex/build.properties index ab648798d..84f97d75f 100644 --- a/pdex/build.properties +++ b/pdex/build.properties @@ -2,4 +2,6 @@ sketchbook.location=${user.home}/Documents/Processing classpath.local.location=${user.home}/Documents/workspace/libs core.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/core/library app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/ -java.target.version=1.6 \ No newline at end of file +java.target.version=1.6 +lib.name=ExperimentalMode +dist=dist \ No newline at end of file diff --git a/pdex/build.xml b/pdex/build.xml index f0ddbdd74..522c7f8b3 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -2,67 +2,97 @@ - - - - - - - - - - + + + + - + + + + + - - - - - + + + + - - - - - - - - - + + + + + + + + + - - - - + + + + - - - - + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From caf990c0ad692d910bb840340c9f79370e118a18 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 00:06:28 +0530 Subject: [PATCH 182/608] version stuff --- pdex/build.properties | 4 +++- pdex/build.xml | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pdex/build.properties b/pdex/build.properties index 84f97d75f..2c812c995 100644 --- a/pdex/build.properties +++ b/pdex/build.properties @@ -4,4 +4,6 @@ core.library.location=/home/quarkninja/Workspaces/processing-workspace/processin app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/ java.target.version=1.6 lib.name=ExperimentalMode -dist=dist \ No newline at end of file +dist=dist +release=2 +prettyVersion=1.1 \ No newline at end of file diff --git a/pdex/build.xml b/pdex/build.xml index 522c7f8b3..1f06d8b14 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -85,6 +85,12 @@ + + + + + + From c341eff5a864584108e274131bd130990d302be6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 00:54:30 +0530 Subject: [PATCH 183/608] attention to detail :P --- pdex/Todo, GSoC 2013.txt | 4 ++-- .../mode/experimental/ASTGenerator.java | 20 +++++++++++++++---- .../mode/experimental/DebugEditor.java | 8 ++++---- .../mode/experimental/ExperimentalMode.java | 2 +- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 83602d2ad..05384a011 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -132,5 +132,5 @@ General Stuff x Add option for toggling debug output x On Run/Debug Console is visible(ProblemsList hidden) * Update wiki for Ctrl + H instead of Ctrl + J shortcuts -* update build.xml to produce dists -* Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc +x update build.xml to produce dists +x Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 6a71610f8..810b9a985 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -170,7 +170,7 @@ public class ASTGenerator { btnListOccurrence = new JButton("Show Usage"); frmRename = new JFrame(); frmRename.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - frmRename.setBounds(new Rectangle(680, 50, 250, 130)); + frmRename.setSize(250, 130); frmRename.setLayout(new BoxLayout(frmRename.getContentPane(), BoxLayout.Y_AXIS)); Toolkit.setIcon(frmRename); JPanel panelTop = new JPanel(), panelBottom = new JPanel(); @@ -192,13 +192,18 @@ public class ASTGenerator { panelTop.add(Box.createRigidArea(new Dimension(0, 10))); panelTop.add(lblRefactorOldName); frmRename.add(panelTop); - frmRename.add(panelBottom); - + frmRename.add(panelBottom); frmRename.setMinimumSize(frmRename.getSize()); + frmRename.setLocation(editor.getX() + + (editor.getWidth() - frmRename.getWidth()) / 2, + editor.getY() + + (editor.getHeight() - frmRename.getHeight()) + / 2); + frmOccurenceList = new JFrame(); frmOccurenceList.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - frmOccurenceList.setBounds(new Rectangle(1100, 50, 350, 500)); + frmOccurenceList.setSize(300, 400); Toolkit.setIcon(frmOccurenceList); JScrollPane sp2 = new JScrollPane(); treeRename = new JTree(); @@ -1843,6 +1848,7 @@ public class ASTGenerator { treeRename.setModel(new DefaultTreeModel(defCU)); ((DefaultTreeModel) treeRename.getModel()).reload(); frmOccurenceList.setTitle("Usage of " + selText); + frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); frmOccurenceList.setVisible(true); int lineOffsetDisplacementConst = newName.length() - selText.length(); @@ -1917,6 +1923,7 @@ public class ASTGenerator { ((DefaultTreeModel) treeRename.getModel()).reload(); treeRename.setRootVisible(false); frmOccurenceList.setTitle("Usage of \"" + selText+ "\""); + frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); frmOccurenceList.setVisible(true); lastClickedWord = null; lastClickedWordNode = null; @@ -2168,6 +2175,11 @@ public class ASTGenerator { return; } if (!frmRename.isVisible()){ + frmRename.setLocation(editor.getX() + + (editor.getWidth() - frmRename.getWidth()) / 2, + editor.getY() + + (editor.getHeight() - frmRename.getHeight()) + / 2); frmRename.setVisible(true); SwingUtilities.invokeLater(new Runnable() { @Override diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index ce341b7fb..aea75af9d 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1251,14 +1251,14 @@ public class DebugEditor extends JavaEditor implements ActionListener { } private void handleRefactor() { - System.out.println("Caret at:"); - System.out.println(ta.getLineText(ta.getCaretLine())); + log("Caret at:"); + log(ta.getLineText(ta.getCaretLine())); errorCheckerService.astGenerator.handleRefactor(); } private void handleShowUsage() { - System.out.println("Caret at:"); - System.out.println(ta.getLineText(ta.getCaretLine())); + log("Caret at:"); + log(ta.getLineText(ta.getCaretLine())); errorCheckerService.astGenerator.handleShowUsage(); } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 61d93d498..8619af055 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -43,7 +43,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = true; + public static boolean DEBUG = !true; public ExperimentalMode(Base base, File folder) { super(base, folder); From 98ad15b9b4b77ee88d092013d264f505ba9e8828 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 01:06:36 +0530 Subject: [PATCH 184/608] missed out the import frame --- .../src/processing/mode/experimental/ASTGenerator.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 810b9a985..034522b01 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -3017,7 +3017,7 @@ public class ASTGenerator { } return null; } - JFrame frmImportSuggest; + protected JFrame frmImportSuggest; public void suggestImports(final String className){ if(frmImportSuggest != null) if(frmImportSuggest.isVisible()) @@ -3043,7 +3043,8 @@ public class ASTGenerator { final JList classList = new JList(resources); classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); frmImportSuggest = new JFrame(); - frmImportSuggest.setBounds(300, 300, 400, 300); + frmImportSuggest.setSize(350, 200); + Toolkit.setIcon(frmImportSuggest); frmImportSuggest.setLayout(new BoxLayout(frmImportSuggest .getContentPane(), BoxLayout.Y_AXIS)); ((JComponent) frmImportSuggest.getContentPane()).setBorder(BorderFactory @@ -3078,6 +3079,11 @@ public class ASTGenerator { frmImportSuggest.add(jsp); frmImportSuggest.add(btnInsertImport); frmImportSuggest.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + frmImportSuggest.setLocation(editor.getX() + + (editor.getWidth() - frmImportSuggest.getWidth()) / 2, + editor.getY() + + (editor.getHeight() - frmImportSuggest.getHeight()) + / 2); frmImportSuggest.setVisible(true); } From 4d62508f9bc1f92803a1d8b327c201e9d62e1b58 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 15:57:30 +0530 Subject: [PATCH 185/608] improving old code in ErrorBar/Error Marker --- .../mode/experimental/ErrorBar.java | 178 ++++++------------ .../experimental/ErrorCheckerService.java | 8 +- .../mode/experimental/ErrorMarker.java | 31 ++- .../mode/experimental/TextAreaPainter.java | 4 +- 4 files changed, 92 insertions(+), 129 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index 24d552ae5..d6b64f9bf 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -35,6 +35,7 @@ import java.util.ArrayList; import javax.swing.JPanel; import javax.swing.SwingWorker; +import javax.swing.text.BadLocationException; import processing.app.Base; import processing.app.SketchCode; @@ -109,12 +110,12 @@ public class ErrorBar extends JPanel { g.fillRect(0, 0, getWidth(), getHeight()); for (ErrorMarker emarker : errorPoints) { - if (emarker.type == ErrorMarker.Error) { + if (emarker.getType() == ErrorMarker.Error) { g.setColor(errorColor); } else { g.setColor(warningColor); } - g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight); + g.fillRect(2, emarker.getY(), (getWidth() - 3), errorMarkerHeight); } } @@ -152,56 +153,46 @@ public class ErrorBar extends JPanel { final int fheight = this.getHeight(); SwingWorker worker = new SwingWorker() { - protected Object doInBackground() throws Exception { - return null; - } + protected Object doInBackground() throws Exception { + SketchCode sc = editor.getSketch().getCurrentCode(); + int totalLines = 0, currentTab = editor.getSketch() + .getCurrentCodeIndex(); + try { + totalLines = Base.countLines(sc.getDocument() + .getText(0, sc.getDocument().getLength())) + 1; + } catch (BadLocationException e) { + e.printStackTrace(); + } + // System.out.println("Total lines: " + totalLines); - protected void done() { - int totalLines = 0; - int currentTab = 0; - for (SketchCode sc : editor.getSketch().getCode()) { - if (sc.isExtension("pde")) { - try { - if (editor.getSketch().getCurrentCode().equals(sc)) { - // Adding + 1 to len because \n gets appended - // for each - // sketchcode extracted during processPDECode() - totalLines = Base.countLines(sc.getDocument() - .getText(0, - sc.getDocument().getLength())) + 1; - break; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - currentTab++; - } - // System.out.println("Total lines: " + totalLines); + errorPointsOld.clear(); + for (ErrorMarker marker : errorPoints) { + errorPointsOld.add(marker); + } + errorPoints.clear(); - errorPointsOld.clear(); - for (ErrorMarker marker : errorPoints) { - errorPointsOld.add(marker); - } - errorPoints.clear(); - - // Each problem.getSourceLine() will have an extra line added - // because of - // class declaration in the beginning as well as default imports - for (Problem problem : problems) { - if (problem.tabIndex == currentTab) { - // Ratio of error line to total lines + // Each problem.getSourceLine() will have an extra line added + // because of + // class declaration in the beginning as well as default imports + for (Problem problem : problems) { + if (problem.tabIndex == currentTab) { + // Ratio of error line to total lines float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset) / ((float) totalLines); - // Ratio multiplied by height of the error bar - y *= fheight - 15; // -15 is just a vertical offset - errorPoints.add(new ErrorMarker(problem, (int) y, - problem.isError() ? ErrorMarker.Error - : ErrorMarker.Warning)); - // System.out.println("Y: " + y); - } - } + // Ratio multiplied by height of the error bar + y *= fheight - 15; // -15 is just a vertical offset + errorPoints + .add(new ErrorMarker(problem, (int) y, + problem.isError() ? ErrorMarker.Error + : ErrorMarker.Warning)); + // System.out.println("Y: " + y); + } + } + return null; + } + + protected void done() { repaint(); } }; @@ -229,7 +220,7 @@ public class ErrorBar extends JPanel { else { for (int i = 0; i < errorPoints.size(); i++) { - if (errorPoints.get(i).y != errorPointsOld.get(i).y) { + if (errorPoints.get(i).getY() != errorPointsOld.get(i).getY()) { editor.getTextArea().repaint(); // System.out.println("3 Repaint " + // System.currentTimeMillis()); @@ -262,36 +253,14 @@ public class ErrorBar extends JPanel { for (ErrorMarker eMarker : errorPoints) { // -2 and +2 are extra allowance, clicks in the // vicinity of the markers register that way - if (e.getY() >= eMarker.y - 2 - && e.getY() <= eMarker.y + 2 + if (e.getY() >= eMarker.getY() - 2 + && e.getY() <= eMarker.getY() + 2 + errorMarkerHeight) { - int currentTabErrorIndex = errorPoints - .indexOf(eMarker); - // System.out.println("Index: " + - // currentTabErrorIndex); - int currentTab = editor.getSketch() - .getCodeIndex( - editor.getSketch() - .getCurrentCode()); - - int totalErrorIndex = currentTabErrorIndex; - - for (int i = 0; i < errorCheckerService.problemsList - .size(); i++) { - Problem p = errorCheckerService.problemsList - .get(i); - if (p.tabIndex < currentTab) { - totalErrorIndex++; - } - if (p.tabIndex == currentTab) { - break; - } - } errorCheckerService - .scrollToErrorLine(totalErrorIndex); + .scrollToErrorLine(eMarker.getProblem()); + return; } } - } }; @@ -311,7 +280,7 @@ public class ErrorBar extends JPanel { @SuppressWarnings("rawtypes") @Override - public void mouseMoved(final MouseEvent e) { + public void mouseMoved(final MouseEvent evt) { // System.out.println(e); SwingWorker worker = new SwingWorker() { @@ -319,51 +288,22 @@ public class ErrorBar extends JPanel { return null; } - protected void done() { - - for (ErrorMarker eMarker : errorPoints) { - if (e.getY() >= eMarker.y - 2 - && e.getY() <= eMarker.y + 2 - + errorMarkerHeight) { - // System.out.println("Index: " + - // errorPoints.indexOf(y)); - int currentTab = editor.getSketch() - .getCodeIndex( - editor.getSketch() - .getCurrentCode()); - int currentTabErrorCount = 0; - - for (int i = 0; i < errorPoints.size(); i++) { - Problem p = errorPoints.get(i).problem; - if (p.tabIndex == currentTab) { - if (currentTabErrorCount == errorPoints - .indexOf(eMarker)) { - // System.out.println("Roger that."); - String msg = (p.isError() ? "Error: " - : "Warning: ") - + p.message; - setToolTipText(msg); - setCursor(Cursor - .getPredefinedCursor(Cursor.HAND_CURSOR)); - return; - } else { - currentTabErrorCount++; - // System.out.println("Still looking.."); - } - } - - } - } - // Reset cursor and tooltip - else { - setToolTipText(""); - setCursor(Cursor - .getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - - } + protected void done() { + for (ErrorMarker eMarker : errorPoints) { + if (evt.getY() >= eMarker.getY() - 2 + && evt.getY() <= eMarker.getY() + 2 + errorMarkerHeight) { + Problem p = eMarker.getProblem(); + String msg = (p.isError() ? "Error: " : "Warning: ") + + p.message; + setToolTipText(msg); + setCursor(Cursor + .getPredefinedCursor(Cursor.HAND_CURSOR)); + break; + } + } + } }; + try { worker.execute(); } catch (Exception exp) { diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index f25a08854..da498bdf5 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -787,15 +787,15 @@ public class ErrorCheckerService implements Runnable{ // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); for (ErrorMarker emarker : editor.errorBar.errorPoints) { - if (emarker.problem.lineNumber == editor.getTextArea() + if (emarker.getProblem().lineNumber == editor.getTextArea() .getCaretLine() + 1) { - if (emarker.type == ErrorMarker.Warning) { - editor.statusNotice(emarker.problem.message); + if (emarker.getType() == ErrorMarker.Warning) { + editor.statusNotice(emarker.getProblem().message); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); //TODO: this is temporary } else { - editor.statusError(emarker.problem.message); + editor.statusError(emarker.getProblem().message); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); } return; diff --git a/pdex/src/processing/mode/experimental/ErrorMarker.java b/pdex/src/processing/mode/experimental/ErrorMarker.java index 0a10cff4b..a3eab8ceb 100755 --- a/pdex/src/processing/mode/experimental/ErrorMarker.java +++ b/pdex/src/processing/mode/experimental/ErrorMarker.java @@ -6,14 +6,14 @@ package processing.mode.experimental; * */ public class ErrorMarker { - /** + /** * y co-ordinate of the marker */ - public int y; + private int y; /** * Type of marker: Error or Warning? */ - public int type = -1; + private int type = -1; /** * Error Type constant */ @@ -26,11 +26,34 @@ package processing.mode.experimental; * Problem that the error marker represents * @see Problem */ - public Problem problem; + private Problem problem; public ErrorMarker(Problem problem, int y, int type) { this.problem = problem; this.y = y; this.type = type; } + + /** + * y co-ordinate of the marker + */ + public int getY() { + return y; + } + + /** + * Type of marker: ErrorMarker.Error or ErrorMarker.Warning? + */ + public int getType() { + return type; + } + + /** + * Problem that the error marker represents + * @see Problem + */ + public Problem getProblem() { + return problem; + } + } \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 89170edbe..b5d174038 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -311,9 +311,9 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // Check if current line contains an error. If it does, find if it's an // error or warning for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { - if (emarker.problem.lineNumber == line + 1) { + if (emarker.getProblem().lineNumber == line + 1) { notFound = false; - if (emarker.type == ErrorMarker.Warning) { + if (emarker.getType() == ErrorMarker.Warning) { isWarning = true; } break; From a8cd6d598ba8fb7166613eade779ad8372fd0b4d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 16:02:45 +0530 Subject: [PATCH 186/608] improving old code in Problem --- .../mode/experimental/ErrorBar.java | 6 ++--- .../experimental/ErrorCheckerService.java | 24 +++++++++---------- .../processing/mode/experimental/Problem.java | 16 +++++++++---- .../mode/experimental/TextAreaPainter.java | 2 +- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index d6b64f9bf..9670df68f 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -175,9 +175,9 @@ public class ErrorBar extends JPanel { // because of // class declaration in the beginning as well as default imports for (Problem problem : problems) { - if (problem.tabIndex == currentTab) { + if (problem.getTabIndex() == currentTab) { // Ratio of error line to total lines - float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset) + float y = (problem.getLineNumber() - errorCheckerService.defaultImportsOffset) / ((float) totalLines); // Ratio multiplied by height of the error bar y *= fheight - 15; // -15 is just a vertical offset @@ -294,7 +294,7 @@ public class ErrorBar extends JPanel { && evt.getY() <= eMarker.getY() + 2 + errorMarkerHeight) { Problem p = eMarker.getProblem(); String msg = (p.isError() ? "Error: " : "Warning: ") - + p.message; + + p.getMessage(); setToolTipText(msg); setCursor(Cursor .getPredefinedCursor(Cursor.HAND_CURSOR)); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index da498bdf5..2f1d168e4 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -717,15 +717,15 @@ public class ErrorCheckerService implements Runnable{ try { String[][] errorData = new String[problemsList.size()][3]; for (int i = 0; i < problemsList.size(); i++) { - errorData[i][0] = problemsList.get(i).message; ////TODO: this is temporary + errorData[i][0] = problemsList.get(i).getMessage(); ////TODO: this is temporary //+ " : " + errorMsgSimplifier.getIDName(problemsList.get(i).getIProblem().getID()); errorData[i][1] = editor.getSketch() - .getCode(problemsList.get(i).tabIndex).getPrettyName(); - errorData[i][2] = problemsList.get(i).lineNumber + ""; + .getCode(problemsList.get(i).getTabIndex()).getPrettyName(); + errorData[i][2] = problemsList.get(i).getLineNumber() + ""; //TODO: This is temporary if(tempErrorLog.size() < 200) - tempErrorLog.put(problemsList.get(i).message,problemsList.get(i).getIProblem()); + tempErrorLog.put(problemsList.get(i).getMessage(),problemsList.get(i).getIProblem()); } if (errorWindow != null) { @@ -787,15 +787,15 @@ public class ErrorCheckerService implements Runnable{ // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); for (ErrorMarker emarker : editor.errorBar.errorPoints) { - if (emarker.getProblem().lineNumber == editor.getTextArea() + if (emarker.getProblem().getLineNumber() == editor.getTextArea() .getCaretLine() + 1) { if (emarker.getType() == ErrorMarker.Warning) { - editor.statusNotice(emarker.getProblem().message); + editor.statusNotice(emarker.getProblem().getMessage()); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); //TODO: this is temporary } else { - editor.statusError(emarker.getProblem().message); + editor.statusError(emarker.getProblem().getMessage()); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); } return; @@ -1172,16 +1172,16 @@ public class ErrorCheckerService implements Runnable{ return; try { editor.toFront(); - editor.getSketch().setCurrentCode(p.tabIndex); + editor.getSketch().setCurrentCode(p.getTabIndex()); editor .setSelection(editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1) + .getLineStartNonWhiteSpaceOffset(p.getLineNumber() - 1) + editor.getTextArea() - .getLineText(p.lineNumber - 1).trim().length(), + .getLineText(p.getLineNumber() - 1).trim().length(), editor.getTextArea() - .getLineStartNonWhiteSpaceOffset(p.lineNumber - 1)); - editor.getTextArea().scrollTo(p.lineNumber - 1, 0); + .getLineStartNonWhiteSpaceOffset(p.getLineNumber() - 1)); + editor.getTextArea().scrollTo(p.getLineNumber() - 1, 0); editor.repaint(); } catch (Exception e) { System.err.println(e diff --git a/pdex/src/processing/mode/experimental/Problem.java b/pdex/src/processing/mode/experimental/Problem.java index 56cc0e833..e7c907ae9 100644 --- a/pdex/src/processing/mode/experimental/Problem.java +++ b/pdex/src/processing/mode/experimental/Problem.java @@ -44,21 +44,21 @@ public class Problem { /** * The tab number to which the error belongs to */ - public int tabIndex; + private int tabIndex; /** * Line number(pde code) of the error */ - public int lineNumber; + private int lineNumber; /** * Error Message. Processed form of IProblem.getMessage() */ - public String message; + private String message; /** * The type of error - WARNING or ERROR. */ - public int type; + private int type; public static final int ERROR = 1, WARNING = 2; @@ -101,6 +101,14 @@ public class Problem { public IProblem getIProblem(){ return iProblem; } + + public int getTabIndex(){ + return tabIndex; + } + + public int getLineNumber(){ + return lineNumber; + } public void setType(int ProblemType){ if(ProblemType == ERROR) diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index b5d174038..f8db484bb 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -311,7 +311,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // Check if current line contains an error. If it does, find if it's an // error or warning for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { - if (emarker.getProblem().lineNumber == line + 1) { + if (emarker.getProblem().getLineNumber() == line + 1) { notFound = false; if (emarker.getType() == ErrorMarker.Warning) { isWarning = true; From e869e1bfac7ffa6f24e431b9f23c56d12b554b81 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 19:52:10 +0530 Subject: [PATCH 187/608] icons in completion list, loading icons only once --- .../mode/experimental/CompletionPanel.java | 49 ++++++++++++++++++- .../mode/experimental/ExperimentalMode.java | 19 ++++++- .../mode/experimental/SketchOutline.java | 19 ++----- .../mode/experimental/TextArea.java | 2 +- 4 files changed, 70 insertions(+), 19 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index f054ccfd2..0336c72e9 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -4,13 +4,18 @@ import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.File; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; @@ -31,10 +36,13 @@ public class CompletionPanel { private TextArea textarea; private JScrollPane scrollPane; + + protected DebugEditor editor; public CompletionPanel(JEditTextArea textarea, int position, String subWord, - DefaultListModel items, Point location) { + DefaultListModel items, Point location, DebugEditor dedit) { this.textarea = (TextArea) textarea; + editor = dedit; this.insertionPosition = position; if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); @@ -80,6 +88,7 @@ public class CompletionPanel { } } }); + list.setCellRenderer(new CustomListRenderer()); return list; } @@ -189,4 +198,42 @@ public class CompletionPanel { // }; // }); } + + protected class CustomListRenderer extends + javax.swing.DefaultListCellRenderer { + //protected final ImageIcon classIcon, fieldIcon, methodIcon; + + public Component getListCellRendererComponent(JList list, Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, + index, + isSelected, + cellHasFocus); + if (value instanceof CompletionCandidate) { + CompletionCandidate cc = (CompletionCandidate) value; + switch (cc.getType()) { + case CompletionCandidate.LOCAL_FIELD: + case CompletionCandidate.PREDEF_FIELD: + label.setIcon(editor.dmode.fieldIcon); + break; + case CompletionCandidate.LOCAL_METHOD: + case CompletionCandidate.PREDEF_METHOD: + label.setIcon(editor.dmode.methodIcon); + break; + case CompletionCandidate.LOCAL_CLASS: + case CompletionCandidate.PREDEF_CLASS: + label.setIcon(editor.dmode.classIcon); + break; + + default: + break; + } + + } + return label; + } + } + } \ No newline at end of file diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 8619af055..783eeeba9 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -28,6 +28,9 @@ import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; + +import javax.swing.ImageIcon; + import processing.app.Base; import processing.app.Editor; import processing.app.EditorState; @@ -43,7 +46,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = !true; + public static boolean DEBUG = true; public ExperimentalMode(Base base, File folder) { super(base, folder); @@ -96,6 +99,7 @@ public class ExperimentalMode extends JavaMode { // String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; // //log(titleAndVersion); // Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); + loadIcons(); } @@ -156,6 +160,19 @@ public class ExperimentalMode extends JavaMode { Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute); return defaultValue; } + + protected ImageIcon classIcon, fieldIcon, methodIcon; + protected void loadIcons(){ + String iconPath = getContentFile("data") + .getAbsolutePath() + + File.separator + "icons"; + classIcon = new ImageIcon(iconPath + File.separator + "class_obj.png"); + methodIcon = new ImageIcon(iconPath + File.separator + + "methpub_obj.png"); + fieldIcon = new ImageIcon(iconPath + File.separator + + "field_protected_obj.png"); + log("Icons loaded"); + } public ClassLoader getJavaModeClassLoader() { diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index f753d15d0..a78a66f03 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -346,19 +346,6 @@ public class SketchOutline { protected class CustomCellRenderer extends DefaultTreeCellRenderer { - protected final ImageIcon classIcon, fieldIcon, methodIcon; - - public CustomCellRenderer() { - String iconPath = editor.getMode().getContentFile("data") - .getAbsolutePath() - + File.separator + "icons"; - classIcon = new ImageIcon(iconPath + File.separator + "class_obj.png"); - methodIcon = new ImageIcon(iconPath + File.separator - + "methpub_obj.png"); - fieldIcon = new ImageIcon(iconPath + File.separator - + "field_protected_obj.png"); - } - public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { @@ -378,11 +365,11 @@ public class SketchOutline { .getUserObject(); int type = awrap.getNode().getParent().getNodeType(); if (type == ASTNode.METHOD_DECLARATION) - return methodIcon; + return editor.dmode.methodIcon; if (type == ASTNode.TYPE_DECLARATION) - return classIcon; + return editor.dmode.classIcon; if (type == ASTNode.VARIABLE_DECLARATION_FRAGMENT) - return fieldIcon; + return editor.dmode.fieldIcon; } return null; } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 00e1282d5..576b58eaf 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -711,7 +711,7 @@ public class TextArea extends JEditTextArea { } if (suggestion == null) suggestion = new CompletionPanel(this, position, subWord, defListModel, - location); + location,editor); else suggestion.updateList(defListModel, subWord, position); suggestion.setVisible(true); From 3c9709886ff86cf3811d042bcbbbc4dc1e7ecd10 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 20:04:54 +0530 Subject: [PATCH 188/608] completion panel type bugfix --- .../mode/experimental/CompletionCandidate.java | 12 +++++++++--- .../mode/experimental/CompletionPanel.java | 7 +++++++ .../mode/experimental/ExperimentalMode.java | 4 +++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index 5c3761db4..bc2973785 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -5,6 +5,7 @@ import java.lang.reflect.Method; import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.TypeDeclaration; @@ -27,7 +28,6 @@ public class CompletionCandidate implements Comparable{ public CompletionCandidate(Method method) { method.getDeclaringClass().getName(); elementName = method.getName(); - type = LOCAL_METHOD; StringBuffer label = new StringBuffer(method.getName() + "("); StringBuffer cstr = new StringBuffer(method.getName() + "("); for (int i = 0; i < method.getParameterTypes().length; i++) { @@ -53,14 +53,20 @@ public class CompletionCandidate implements Comparable{ public CompletionCandidate(SingleVariableDeclaration svd) { completionString = svd.getName().toString(); elementName = svd.getName().toString(); - type = LOCAL_VAR; + if(svd.getParent() instanceof FieldDeclaration) + type = LOCAL_FIELD; + else + type = LOCAL_VAR; label = svd.getName() + " : " + svd.getType(); } public CompletionCandidate(VariableDeclarationFragment vdf) { completionString = vdf.getName().toString(); elementName = vdf.getName().toString(); - type = LOCAL_VAR; + if(vdf.getParent() instanceof FieldDeclaration) + type = LOCAL_FIELD; + else + type = LOCAL_VAR; label = vdf.getName() + " : " + ASTGenerator.extracTypeInfo2(vdf); } diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 0336c72e9..55e66c430 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -214,6 +214,9 @@ public class CompletionPanel { if (value instanceof CompletionCandidate) { CompletionCandidate cc = (CompletionCandidate) value; switch (cc.getType()) { + case CompletionCandidate.LOCAL_VAR: + label.setIcon(editor.dmode.localVarIcon); + break; case CompletionCandidate.LOCAL_FIELD: case CompletionCandidate.PREDEF_FIELD: label.setIcon(editor.dmode.fieldIcon); @@ -228,10 +231,14 @@ public class CompletionPanel { break; default: + log("(CustomListRenderer)Unknown CompletionCandidate type " + cc.getType()); break; } } + else + log("(CustomListRenderer)Unknown CompletionCandidate object " + value); + return label; } } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 783eeeba9..d5f07395a 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -161,7 +161,7 @@ public class ExperimentalMode extends JavaMode { return defaultValue; } - protected ImageIcon classIcon, fieldIcon, methodIcon; + protected ImageIcon classIcon, fieldIcon, methodIcon, localVarIcon; protected void loadIcons(){ String iconPath = getContentFile("data") .getAbsolutePath() @@ -171,6 +171,8 @@ public class ExperimentalMode extends JavaMode { + "methpub_obj.png"); fieldIcon = new ImageIcon(iconPath + File.separator + "field_protected_obj.png"); + localVarIcon = new ImageIcon(iconPath + File.separator + + "field_default_obj.png"); log("Icons loaded"); } From 02196dfaebb3da605a25ac4b798293270ccd0df7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 20:16:31 +0530 Subject: [PATCH 189/608] jars loaded only on demand --- pdex/src/processing/mode/experimental/ErrorCheckerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 2f1d168e4..99fb31515 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -399,7 +399,6 @@ public class ErrorCheckerService implements Runnable{ syntaxErrors.set(false); else syntaxErrors.set(true); - astGenerator.loadJars(); } protected URLClassLoader classLoader; private void compileCheck() { @@ -1250,6 +1249,8 @@ public class ErrorCheckerService implements Runnable{ } } } + if(loadCompClass) + astGenerator.loadJars(); // log("load..? " + loadCompClass); } From 74618473526e417bc879f22a668cf89ac8695d4f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 20:43:19 +0530 Subject: [PATCH 190/608] fixing regression --- .../mode/experimental/ASTGenerator.java | 29 ++++++++++--------- .../experimental/ErrorCheckerService.java | 8 ++++- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 034522b01..24ca2befc 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -269,13 +269,14 @@ public class ASTGenerator { protected void done() { if (codeTree != null) { -// if (jtree.hasFocus() || frame2.hasFocus()) -// return; -// jtree.setModel(new DefaultTreeModel(codeTree)); -// ((DefaultTreeModel) jtree.getModel()).reload(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if (jtree.hasFocus() || frame2.hasFocus()) + return; + jtree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) jtree.getModel()).reload(); + jtree.validate(); + if (!frame2.isVisible()) { + frame2.setVisible(true); + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -293,7 +294,6 @@ public class ASTGenerator { // .getY(), 450, 600)); // jdocWindow.setVisible(true); // } -// jtree.validate(); } } }; @@ -1379,18 +1379,20 @@ public class ASTGenerator { } private static ASTNode findClosestNode(int lineNumber, ASTNode node) { + log("findClosestNode to line " + lineNumber); ASTNode parent = findClosestParentNode(lineNumber, node); + log("findClosestParentNode returned " + getNodeAsString(parent)); if (parent == null) return null; - if (getLineNumber(parent) == lineNumber) + if (getLineNumber(parent) == lineNumber){ + log(parent + "|PNode " + getLineNumber(parent) + ", lfor " + lineNumber ); return parent; + } List nodes = null; if (parent instanceof TypeDeclaration) { - nodes = (List) ((TypeDeclaration) parent) - .getStructuralProperty(TypeDeclaration.BODY_DECLARATIONS_PROPERTY); + nodes = (List) ((TypeDeclaration) parent).bodyDeclarations(); } else if (parent instanceof Block) { - nodes = (List) ((Block) parent) - .getStructuralProperty(Block.STATEMENTS_PROPERTY); + nodes = (List) ((Block) parent).statements(); } else { System.err.println("THIS CONDITION SHOULD NOT OCCUR - findClosestNode " + getNodeAsString(parent)); @@ -1401,6 +1403,7 @@ public class ASTGenerator { ASTNode retNode = parent; for (int i = 0; i < nodes.size(); i++) { ASTNode cNode = nodes.get(i); + log(cNode + "|cNode " + getLineNumber(cNode) + ", lfor " + lineNumber ); if (getLineNumber(cNode) <= lineNumber) retNode = cNode; } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 99fb31515..237cafce5 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -250,6 +250,11 @@ public class ErrorCheckerService implements Runnable{ checkCode(); if(!hasSyntaxErrors()) editor.showProblemListView(XQConsoleToggle.CONSOLE); + // Make sure astGen has at least one CU to start with + // This is when the loaded sketch already has syntax errors. + // Completion wouldn't be complete, but it'd be still something + // better than nothing + astGenerator.buildAST(cu); while (!stopThread) { try { // Take a nap. @@ -313,7 +318,7 @@ public class ErrorCheckerService implements Runnable{ + mainClassOffset); // No syntax errors, proceed for compilation check, Stage 2. - astGenerator.buildAST(cu); + //if(hasSyntaxErrors()) astGenerator.buildAST(null); if (problems.length == 0 && editor.compilationCheckEnabled) { //mainClassOffset++; // just a hack. @@ -327,6 +332,7 @@ public class ErrorCheckerService implements Runnable{ // log(sourceCode); // log("--------------------------"); compileCheck(); + astGenerator.buildAST(cu); log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } From 1035618665b7b5c2f28696b35d9c7da6a01241b9 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 20:46:09 +0530 Subject: [PATCH 191/608] updated todo --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 16 ++++++++-------- .../mode/experimental/ExperimentalMode.java | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 05384a011..97c1fb201 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -129,6 +129,7 @@ x Working for local code General Stuff ============= +* Ensure all editor windows are closed when editor is closed. x Add option for toggling debug output x On Run/Debug Console is visible(ProblemsList hidden) * Update wiki for Ctrl + H instead of Ctrl + J shortcuts diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 24ca2befc..4ede16a7b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -269,14 +269,14 @@ public class ASTGenerator { protected void done() { if (codeTree != null) { - if (jtree.hasFocus() || frame2.hasFocus()) - return; - jtree.setModel(new DefaultTreeModel(codeTree)); - ((DefaultTreeModel) jtree.getModel()).reload(); - jtree.validate(); - if (!frame2.isVisible()) { - frame2.setVisible(true); - } +// if (jtree.hasFocus() || frame2.hasFocus()) +// return; +// jtree.setModel(new DefaultTreeModel(codeTree)); +// ((DefaultTreeModel) jtree.getModel()).reload(); +// jtree.validate(); +// if (!frame2.isVisible()) { +// frame2.setVisible(true); +// } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index d5f07395a..db5f793b6 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -46,7 +46,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = true; + public static boolean DEBUG = !true; public ExperimentalMode(Base base, File folder) { super(base, folder); From acbba41984d765120d05694e071217adf3d3cb75 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 21:51:40 +0530 Subject: [PATCH 192/608] forgot to remove this line --- pdex/src/processing/mode/experimental/DebugEditor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index aea75af9d..f134e506b 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -232,7 +232,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); //TODO: Remove this later - setBounds(160, 300, getWidth(), getHeight()); + if(ExperimentalMode.DEBUG) + setBounds(160, 300, getWidth(), getHeight()); } private void addXQModeUI(){ From 0a2f2662cf89226962ddf3fb1fe700b5095cb731 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 22:07:47 +0530 Subject: [PATCH 193/608] updated todo --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ErrorCheckerService.java | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 97c1fb201..6c583fef4 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -130,6 +130,7 @@ General Stuff ============= * Ensure all editor windows are closed when editor is closed. +* Add a red marker near Errors label in console toggle, to indicate errors present in sketch. x Add option for toggling debug output x On Run/Debug Console is visible(ProblemsList hidden) * Update wiki for Ctrl + H instead of Ctrl + J shortcuts diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 237cafce5..fb582af53 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -362,12 +362,22 @@ public class ErrorCheckerService implements Runnable{ return false; } - private AtomicBoolean syntaxErrors; + protected AtomicBoolean syntaxErrors; public boolean hasSyntaxErrors(){ return syntaxErrors.get(); } + public boolean hasErrors(){ + synchronized (problemsList) { + for (Problem p : problemsList) { + if (p.isError()) + return false; + } + return false; + } + } + protected TreeMap tempErrorLog; private void syntaxCheck() { From c8ed54686149197819ad9856ad18d13a3bb67fd8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 19 Aug 2013 22:56:28 +0530 Subject: [PATCH 194/608] indicator near error toggle button, dunno if a good idea. --- pdex/Todo, GSoC 2013.txt | 2 +- .../processing/mode/experimental/DebugEditor.java | 5 +++++ .../mode/experimental/ErrorCheckerService.java | 6 ++++-- .../mode/experimental/XQConsoleToggle.java | 14 +++++++++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 6c583fef4..4c8abef07 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -130,7 +130,7 @@ General Stuff ============= * Ensure all editor windows are closed when editor is closed. -* Add a red marker near Errors label in console toggle, to indicate errors present in sketch. +x Add a red marker near Errors label in console toggle, to indicate errors present in sketch. x Add option for toggling debug output x On Run/Debug Console is visible(ProblemsList hidden) * Update wiki for Ctrl + H instead of Ctrl + J shortcuts diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index f134e506b..8f17f9494 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1251,6 +1251,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { return errorTable.updateTable(tableModel); } + public void updateErrorToggle(){ + btnShowErrors.updateMarker(errorCheckerService.hasErrors(), + errorBar.errorColor); + } + private void handleRefactor() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index fb582af53..afc54b8cd 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -342,6 +342,7 @@ public class ErrorCheckerService implements Runnable{ updateEditorStatus(); editor.getTextArea().repaint(); updatePaintedThingys(); + editor.updateErrorToggle(); int x = textModified.get(); //log("TM " + x); if (x >= 2) { @@ -371,8 +372,9 @@ public class ErrorCheckerService implements Runnable{ public boolean hasErrors(){ synchronized (problemsList) { for (Problem p : problemsList) { - if (p.isError()) - return false; + if (p.isError()){ + return true; + } } return false; } diff --git a/pdex/src/processing/mode/experimental/XQConsoleToggle.java b/pdex/src/processing/mode/experimental/XQConsoleToggle.java index c30ae5b99..279099825 100755 --- a/pdex/src/processing/mode/experimental/XQConsoleToggle.java +++ b/pdex/src/processing/mode/experimental/XQConsoleToggle.java @@ -90,10 +90,22 @@ public class XQConsoleToggle extends JPanel implements MouseListener { g.fillRect(0, 0, 4, this.getHeight()); g.setColor(Color.WHITE); } - + g.drawString(buttonName, getWidth() / 2 + 2 // + 2 is a offset - getFontMetrics(getFont()).stringWidth(buttonName) / 2, this.getHeight() - 6); + if(drawMarker){ + g.setColor(markerColor); + g.fillRect(4, 0, 2, this.getHeight()); + } + } + + boolean drawMarker = false; + protected Color markerColor; + public void updateMarker(boolean value, Color color){ + drawMarker = value; + markerColor = color; + repaint(); } @Override From 01dfe8c34401ab436d7586d4bc2b90113957ecbc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 20 Aug 2013 02:30:56 +0530 Subject: [PATCH 195/608] added swingworker in processkeyevent --- pdex/build.properties | 4 ++-- .../processing/mode/experimental/TextArea.java | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pdex/build.properties b/pdex/build.properties index 2c812c995..bdda74bb2 100644 --- a/pdex/build.properties +++ b/pdex/build.properties @@ -5,5 +5,5 @@ app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing java.target.version=1.6 lib.name=ExperimentalMode dist=dist -release=2 -prettyVersion=1.1 \ No newline at end of file +release=3 +prettyVersion=1.1.1 diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 576b58eaf..d5caef4d7 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -34,6 +34,7 @@ import java.util.Map; import javax.swing.DefaultListModel; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import processing.app.syntax.JEditTextArea; import processing.app.syntax.TextAreaDefaults; @@ -179,10 +180,16 @@ public class TextArea extends JEditTextArea { super.processKeyEvent(evt); if (evt.getID() == KeyEvent.KEY_TYPED) { - errorCheckerService.runManualErrorCheck(); - log(" Typing: " + fetchPhrase(evt) + " " - + (evt.getKeyChar() == KeyEvent.VK_ENTER)); - + final KeyEvent evt2 = evt; + SwingWorker worker = new SwingWorker() { + protected Object doInBackground() throws Exception { + errorCheckerService.runManualErrorCheck(); + log(" Typing: " + fetchPhrase(evt2) + " " + + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); + return null; + } + }; + worker.execute(); } From 2daff10f5e6a780a2a8a71cc69041140d7885dfe Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 20 Aug 2013 02:39:32 +0530 Subject: [PATCH 196/608] removing swingworker in astgen showPred --- .../mode/experimental/ASTGenerator.java | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 4ede16a7b..b934b755c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -211,14 +211,14 @@ public class ASTGenerator { frmOccurenceList.add(sp2); //occurenceListFrame.setVisible(true); - frameAutoComp = new JFrame(); - frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); - Toolkit.setIcon(frameAutoComp); - tableAuto = new JTable(); - JScrollPane sp3 = new JScrollPane(); - sp3.setViewportView(tableAuto); - frameAutoComp.add(sp3); +// frameAutoComp = new JFrame(); +// frameAutoComp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); +// frameAutoComp.setBounds(new Rectangle(1280, 100, 460, 620)); +// Toolkit.setIcon(frameAutoComp); +// tableAuto = new JTable(); +// JScrollPane sp3 = new JScrollPane(); +// sp3.setViewportView(tableAuto); +// frameAutoComp.add(sp3); // jdocWindow = new JFrame(); // jdocWindow.setTitle("P5 InstaHelp"); @@ -779,14 +779,15 @@ public class ASTGenerator { log("No predictions."); return; } - SwingWorker worker = new SwingWorker() { - - @Override - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { +// SwingWorker worker = new SwingWorker() { +// +// @Override +// protected Object doInBackground() throws Exception { +// return null; +// } +// +// protected void done() { + // If the parsed code contains pde enhancements, take 'em out. String word2 = ASTNodeWrapper.getJavaCode(word); @@ -987,31 +988,31 @@ public class ASTGenerator { showPredictions(word); - } - }; - - worker.execute(); +// } +// }; +// +// worker.execute(); } private void showPredictions(final String word) { if (sketchOutline != null) if (sketchOutline.isVisible()) return; Collections.sort(candidates); - CompletionCandidate[][] candi = new CompletionCandidate[candidates.size()][1]; +// CompletionCandidate[][] candi = new CompletionCandidate[candidates.size()][1]; DefaultListModel defListModel = new DefaultListModel(); - for (int i = 0; i < candi.length; i++) { - candi[i][0] = candidates.get(i); + for (int i = 0; i < candidates.size(); i++) { +// candi[i][0] = candidates.get(i); defListModel.addElement(candidates.get(i)); } log("Total preds = " + candidates.size()); - DefaultTableModel tm = new DefaultTableModel(candi, - new String[] { "Suggestions" }); - if (tableAuto.isVisible()) { - tableAuto.setModel(tm); - tableAuto.validate(); - tableAuto.repaint(); - } +// DefaultTableModel tm = new DefaultTableModel(candi, +// new String[] { "Suggestions" }); +// if (tableAuto.isVisible()) { +// tableAuto.setModel(tm); +// tableAuto.validate(); +// tableAuto.repaint(); +// } errorCheckerService.getEditor().textArea() .showSuggestion(defListModel, word); } From 956724b41f499336c5c8cfaa8da316be160f0a09 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 20 Aug 2013 02:50:13 +0530 Subject: [PATCH 197/608] further swingworker stuff --- .../mode/experimental/ASTGenerator.java | 2 + .../mode/experimental/ErrorBar.java | 49 ++++++++----------- .../mode/experimental/SketchOutline.java | 12 ++--- 3 files changed, 26 insertions(+), 37 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b934b755c..ae5c2720d 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -775,6 +775,8 @@ public class ASTGenerator { private String lastPredictedWord = " "; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { + // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance + // in TextArea.processKeyEvent if(caretWithinLineComment()){ log("No predictions."); return; diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index 9670df68f..7c3d701cc 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -243,26 +243,21 @@ public class ErrorBar extends JPanel { @SuppressWarnings("rawtypes") @Override public void mouseClicked(final MouseEvent e) { - SwingWorker worker = new SwingWorker() { + SwingWorker worker = new SwingWorker() { - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { - for (ErrorMarker eMarker : errorPoints) { - // -2 and +2 are extra allowance, clicks in the - // vicinity of the markers register that way - if (e.getY() >= eMarker.getY() - 2 - && e.getY() <= eMarker.getY() + 2 - + errorMarkerHeight) { - errorCheckerService - .scrollToErrorLine(eMarker.getProblem()); - return; - } - } - } - }; + protected Object doInBackground() throws Exception { + for (ErrorMarker eMarker : errorPoints) { + // -2 and +2 are extra allowance, clicks in the + // vicinity of the markers register that way + if (e.getY() >= eMarker.getY() - 2 + && e.getY() <= eMarker.getY() + 2 + errorMarkerHeight) { + errorCheckerService.scrollToErrorLine(eMarker.getProblem()); + return null; + } + } + return null; + } + }; try { worker.execute(); @@ -281,14 +276,10 @@ public class ErrorBar extends JPanel { @SuppressWarnings("rawtypes") @Override public void mouseMoved(final MouseEvent evt) { - // System.out.println(e); - SwingWorker worker = new SwingWorker() { + // System.out.println(e); + SwingWorker worker = new SwingWorker() { - protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { + protected Object doInBackground() throws Exception { for (ErrorMarker eMarker : errorPoints) { if (evt.getY() >= eMarker.getY() - 2 && evt.getY() <= eMarker.getY() + 2 + errorMarkerHeight) { @@ -296,13 +287,13 @@ public class ErrorBar extends JPanel { String msg = (p.isError() ? "Error: " : "Warning: ") + p.getMessage(); setToolTipText(msg); - setCursor(Cursor - .getPredefinedCursor(Cursor.HAND_CURSOR)); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); break; } } + return null; } - }; + }; try { worker.execute(); diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index a78a66f03..6577adfc5 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -199,13 +199,13 @@ public class SketchOutline { private void updateSelection(){ SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { - return null; - } - - protected void done() { String text = searchField.getText().toLowerCase(); tempNode = new DefaultMutableTreeNode(); filterTree(text, tempNode, soNode); + return null; + } + + protected void done() { soTree.setModel(new DefaultTreeModel(tempNode)); ((DefaultTreeModel) soTree.getModel()).reload(); for (int i = 0; i < soTree.getRowCount(); i++) { @@ -249,10 +249,6 @@ public class SketchOutline { } DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) soTree .getLastSelectedPathComponent(); - if (tnode.getUserObject() == null) { - return; - } - if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); // log(awrap); From 5e537f8bb85097d9c5332d5221b76052a8133b13 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 20 Aug 2013 02:57:50 +0530 Subject: [PATCH 198/608] some code cleanup --- .../mode/experimental/ASTGenerator.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ae5c2720d..fd72de45e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1744,10 +1744,6 @@ public class ASTGenerator { } DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) jtree .getLastSelectedPathComponent(); - if(tnode.getUserObject() == null){ - return; - } - if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); errorCheckerService.highlightNode(awrap); @@ -1817,9 +1813,6 @@ public class ASTGenerator { } DefaultMutableTreeNode tnode = (DefaultMutableTreeNode) treeRename .getLastSelectedPathComponent(); - if(tnode.getUserObject() == null){ - return; - } if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); @@ -1851,8 +1844,10 @@ public class ASTGenerator { //else log("New name looks K."); errorCheckerService.pauseThread(); - treeRename.setModel(new DefaultTreeModel(defCU)); - ((DefaultTreeModel) treeRename.getModel()).reload(); + if(treeRename.isVisible()){ + treeRename.setModel(new DefaultTreeModel(defCU)); + ((DefaultTreeModel) treeRename.getModel()).reload(); + } frmOccurenceList.setTitle("Usage of " + selText); frmOccurenceList.setLocation(editor.getX() + editor.getWidth(),editor.getY()); frmOccurenceList.setVisible(true); @@ -1892,11 +1887,10 @@ public class ASTGenerator { editor.ta.setSelectedText(newName); } errorCheckerService.resumeThread(); - errorCheckerService.runManualErrorCheck(); - for (Integer lineNum : lineOffsetDisplacement.keySet()) { - log(lineNum + "line, disp" - + lineOffsetDisplacement.get(lineNum)); - } +// for (Integer lineNum : lineOffsetDisplacement.keySet()) { +// log(lineNum + "line, disp" +// + lineOffsetDisplacement.get(lineNum)); +// } editor.getSketch().setModified(true); errorCheckerService.runManualErrorCheck(); frmOccurenceList.setVisible(false); From 36741a46227c3315c7cad63cae6216943e521ddb Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 15:23:00 +0530 Subject: [PATCH 199/608] added mode.properties, and minor changes in ECS --- pdex/mode.properties | 7 ++++ .../experimental/ErrorCheckerService.java | 42 ++++++++++++------- 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 pdex/mode.properties diff --git a/pdex/mode.properties b/pdex/mode.properties new file mode 100644 index 000000000..5029f1941 --- /dev/null +++ b/pdex/mode.properties @@ -0,0 +1,7 @@ +name=ExperimentalMode +authorList=[The Processing Foundation](http://processing.org) +url=https://github.com/processing/processing-experimental +sentence=The next generation of PDE +paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. +version=@@version@@ +prettyVersion=@@pretty-version@@ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index afc54b8cd..e1da5938b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -193,6 +193,7 @@ public class ErrorCheckerService implements Runnable{ pdePrepoc.getDefaultImports().length + 1; astGenerator = new ASTGenerator(this); syntaxErrors = new AtomicBoolean(true); + containsErrors = new AtomicBoolean(true); errorMsgSimplifier = new ErrorMessageSimplifier(); tempErrorLog = new TreeMap(); } @@ -337,6 +338,15 @@ public class ErrorCheckerService implements Runnable{ + mainClassOffset); } + // Update error flag + containsErrors.set(false); + for (Problem p : problemsList) { + if (p.isError()){ + containsErrors.set(true); + break; + } + } + updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); @@ -363,31 +373,24 @@ public class ErrorCheckerService implements Runnable{ return false; } - protected AtomicBoolean syntaxErrors; + protected AtomicBoolean syntaxErrors, containsErrors; public boolean hasSyntaxErrors(){ return syntaxErrors.get(); } public boolean hasErrors(){ - synchronized (problemsList) { - for (Problem p : problemsList) { - if (p.isError()){ - return true; - } - } - return false; - } + return containsErrors.get(); } protected TreeMap tempErrorLog; private void syntaxCheck() { syntaxErrors.set(true); + containsErrors.set(true); parser.setSource(sourceCode.toCharArray()); parser.setKind(ASTParser.K_COMPILATION_UNIT); - @SuppressWarnings("unchecked") Map options = JavaCore.getOptions(); JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); @@ -413,25 +416,31 @@ public class ErrorCheckerService implements Runnable{ // log(p.toString()); } - if (problems.length == 0) + if (problems.length == 0) { syntaxErrors.set(false); - else + containsErrors.set(false); + } else { syntaxErrors.set(true); + containsErrors.set(true); + } } + protected URLClassLoader classLoader; + private void compileCheck() { // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the - // Eclispe JDT compiler and call its getErrorsAsObj method to obtain + // Eclispe JDT compiler, and call its getErrorsAsObj method to obtain // errors. This way, I'm able to add the paths of contributed libraries // to the classpath of CompilationChecker, dynamically. The eclipse compiler - // needs all referenced libraries in the classpath. + // needs all referenced libraries in the classpath. Totally a hack. If you find + // a better method, do let me know. try { // NOTE TO SELF: If classpath contains null Strings - // URLClassLoader gets angry. Drops NPE bombs. + // URLClassLoader shoots NPE bullets. // If imports have changed, reload classes with new classpath. if (loadCompClass) { @@ -451,7 +460,7 @@ public class ErrorCheckerService implements Runnable{ FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return (file.getName().endsWith(".jar") && !file - .getName().startsWith("ExperimentalMode")); + .getName().startsWith(editor.getMode().getClass().getSimpleName())); } }; @@ -526,6 +535,7 @@ public class ErrorCheckerService implements Runnable{ Problem p = new Problem(problem, a[0], a[1]); if ((Boolean) errorList[i][8]) { p.setType(Problem.ERROR); + containsErrors.set(true); // set flag } if ((Boolean) errorList[i][9]) { From e9c09225b8b0157eb5f6c6f3382488242148a84d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 16:32:57 +0530 Subject: [PATCH 200/608] thread synchronization stuff, kinda important --- .../mode/experimental/ASTGenerator.java | 8 +- .../mode/experimental/DebugEditor.java | 2 +- .../experimental/ErrorCheckerService.java | 250 +++++++++--------- 3 files changed, 134 insertions(+), 126 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index fd72de45e..7bbcf32de 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -346,9 +346,11 @@ public class ASTGenerator { + File.separator + "rt.jar" + File.pathSeparatorChar); } if (errorCheckerService.classpathJars != null) { - for (URL jarPath : errorCheckerService.classpathJars) { - //log(jarPath.getPath()); - tehPath.append(jarPath.getPath() + File.pathSeparatorChar); + synchronized (errorCheckerService.classpathJars) { + for (URL jarPath : errorCheckerService.classpathJars) { + //log(jarPath.getPath()); + tehPath.append(jarPath.getPath() + File.pathSeparatorChar); + } } } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 8f17f9494..ad0936e52 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -312,7 +312,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { dbg.stopDebug(); // remove var.inspector vi.dispose(); - + errorCheckerService.stopThread(); // original dispose super.dispose(); } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index e1da5938b..55de1db99 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -53,12 +53,12 @@ public class ErrorCheckerService implements Runnable{ /** * Used to indirectly stop the Error Checker Thread */ - public boolean stopThread = false; + protected AtomicBoolean stopThread; /** * If true, Error Checking is paused. Calls to checkCode() become useless. */ - private boolean pauseThread = false; + protected AtomicBoolean pauseThread; protected ErrorWindow errorWindow; @@ -185,6 +185,12 @@ public class ErrorCheckerService implements Runnable{ public ErrorCheckerService(DebugEditor debugEditor) { this.editor = debugEditor; + stopThread = new AtomicBoolean(false); + pauseThread = new AtomicBoolean(false); + + problemsList = new ArrayList(); + classpathJars = new ArrayList(); + initParser(); initializeErrorWindow(); xqpreproc = new XQPreprocessor(); @@ -246,7 +252,7 @@ public class ErrorCheckerService implements Runnable{ } public void run() { - stopThread = false; + stopThread.set(false); checkCode(); if(!hasSyntaxErrors()) @@ -256,7 +262,7 @@ public class ErrorCheckerService implements Runnable{ // Completion wouldn't be complete, but it'd be still something // better than nothing astGenerator.buildAST(cu); - while (!stopThread) { + while (!stopThread.get()) { try { // Take a nap. Thread.sleep(sleepTime); @@ -268,7 +274,7 @@ public class ErrorCheckerService implements Runnable{ updatePaintedThingys(); updateEditorStatus(); - if (pauseThread) + if (pauseThread.get()) continue; if(textModified.get() == 0) continue; @@ -337,16 +343,7 @@ public class ErrorCheckerService implements Runnable{ log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } - - // Update error flag - containsErrors.set(false); - for (Problem p : problemsList) { - if (p.isError()){ - containsErrors.set(true); - break; - } - } - + updateErrorTable(); editor.updateErrorBar(problemsList); updateEditorStatus(); @@ -397,31 +394,41 @@ public class ErrorCheckerService implements Runnable{ options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); parser.setCompilerOptions(options); - cu = (CompilationUnit) parser.createAST(null); - - // Store errors returned by the ast parser - problems = cu.getProblems(); - // log("Problem Count: " + problems.length); - // Populate the probList - problemsList = new ArrayList(); - for (int i = 0; i < problems.length; i++) { - int a[] = calculateTabIndexAndLineNumber(problems[i]); - Problem p = new Problem(problems[i], a[0], a[1] + 1); - //TODO: ^Why do cheeky stuff? - problemsList.add(p); + + if (cu == null) + cu = (CompilationUnit) parser.createAST(null); + else { + synchronized (cu) { + cu = (CompilationUnit) parser.createAST(null); + } + } + + synchronized (problemsList) { + + // Store errors returned by the ast parser + problems = cu.getProblems(); + // log("Problem Count: " + problems.length); + // Populate the probList + problemsList = new ArrayList(); + for (int i = 0; i < problems.length; i++) { + int a[] = calculateTabIndexAndLineNumber(problems[i]); + Problem p = new Problem(problems[i], a[0], a[1] + 1); + //TODO: ^Why do cheeky stuff? + problemsList.add(p); // log(problems[i].getMessage()); // for (String j : problems[i].getArguments()) { // log("arg " + j); // } - // log(p.toString()); - } - - if (problems.length == 0) { - syntaxErrors.set(false); - containsErrors.set(false); - } else { - syntaxErrors.set(true); - containsErrors.set(true); + // log(p.toString()); + } + + if (problems.length == 0) { + syntaxErrors.set(false); + containsErrors.set(false); + } else { + syntaxErrors.set(true); + containsErrors.set(true); + } } } @@ -487,7 +494,6 @@ public class ErrorCheckerService implements Runnable{ // log("2."); compilationChecker = checkerClass.newInstance(); - astGenerator.loadJars(); // Update jar files for completition list loadCompClass = false; } @@ -586,52 +592,80 @@ public class ErrorCheckerService implements Runnable{ return; } - // log("1.."); - classpathJars = new ArrayList(); - String entry = ""; - boolean codeFolderChecked = false; - for (ImportStatement impstat : programImports) { - String item = impstat.getImportName(); - int dot = item.lastIndexOf('.'); - entry = (dot == -1) ? item : item.substring(0, dot); - - entry = entry.substring(6).trim(); - // log("Entry--" + entry); - if (ignorableImport(entry)) { - // log("Ignoring: " + entry); - continue; - } - Library library = null; - - // Try to get the library classpath and add it to the list - try { - library = editor.getMode().getLibrary(entry); - // log("lib->" + library.getClassPath() + "<-"); - String libraryPath[] = PApplet.split(library.getClassPath() - .substring(1).trim(), File.pathSeparatorChar); - for (int i = 0; i < libraryPath.length; i++) { - // log(entry + " ::" - // + new File(libraryPath[i]).toURI().toURL()); - classpathJars.add(new File(libraryPath[i]).toURI().toURL()); + synchronized (classpathJars) { + // log("1.."); + classpathJars = new ArrayList(); + String entry = ""; + boolean codeFolderChecked = false; + for (ImportStatement impstat : programImports) { + String item = impstat.getImportName(); + int dot = item.lastIndexOf('.'); + entry = (dot == -1) ? item : item.substring(0, dot); + + entry = entry.substring(6).trim(); + // log("Entry--" + entry); + if (ignorableImport(entry)) { + // log("Ignoring: " + entry); + continue; } - // log("-- "); - // classpath[count] = (new File(library.getClassPath() - // .substring(1))).toURI().toURL(); - // log(" found "); - // log(library.getClassPath().substring(1)); - } catch (Exception e) { - if (library == null && !codeFolderChecked) { - // log(1); - // Look around in the code folder for jar files - if (editor.getSketch().hasCodeFolder()) { - File codeFolder = editor.getSketch().getCodeFolder(); - - // get a list of .jar files in the "code" folder - // (class files in subfolders should also be picked up) - String codeFolderClassPath = Base - .contentsToClassPath(codeFolder); - codeFolderChecked = true; - if (codeFolderClassPath.equalsIgnoreCase("")) { + Library library = null; + + // Try to get the library classpath and add it to the list + try { + library = editor.getMode().getLibrary(entry); + // log("lib->" + library.getClassPath() + "<-"); + String libraryPath[] = PApplet.split(library.getClassPath() + .substring(1).trim(), File.pathSeparatorChar); + for (int i = 0; i < libraryPath.length; i++) { + // log(entry + " ::" + // + new File(libraryPath[i]).toURI().toURL()); + classpathJars.add(new File(libraryPath[i]).toURI().toURL()); + } + // log("-- "); + // classpath[count] = (new File(library.getClassPath() + // .substring(1))).toURI().toURL(); + // log(" found "); + // log(library.getClassPath().substring(1)); + } catch (Exception e) { + if (library == null && !codeFolderChecked) { + // log(1); + // Look around in the code folder for jar files + if (editor.getSketch().hasCodeFolder()) { + File codeFolder = editor.getSketch().getCodeFolder(); + + // get a list of .jar files in the "code" folder + // (class files in subfolders should also be picked up) + String codeFolderClassPath = Base + .contentsToClassPath(codeFolder); + codeFolderChecked = true; + if (codeFolderClassPath.equalsIgnoreCase("")) { + System.err.println("Experimental Mode: Yikes! Can't find \"" + + entry + + "\" library! Line: " + + impstat.getLineNumber() + + " in tab: " + + editor.getSketch().getCode(impstat.getTab()) + .getPrettyName()); + System.out + .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); + + } + String codeFolderPath[] = PApplet.split( + codeFolderClassPath.substring(1).trim(), + File.pathSeparatorChar); + try { + for (int i = 0; i < codeFolderPath.length; i++) { + classpathJars.add(new File(codeFolderPath[i]) + .toURI().toURL()); + } + + } catch (Exception e2) { + System.out + .println("Yikes! codefolder, prepareImports(): " + + e2); + } + } else { System.err.println("Experimental Mode: Yikes! Can't find \"" + entry + "\" library! Line: " @@ -642,47 +676,21 @@ public class ErrorCheckerService implements Runnable{ System.out .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); - - } - String codeFolderPath[] = PApplet.split( - codeFolderClassPath.substring(1).trim(), - File.pathSeparatorChar); - try { - for (int i = 0; i < codeFolderPath.length; i++) { - classpathJars.add(new File(codeFolderPath[i]) - .toURI().toURL()); - } - - } catch (Exception e2) { - System.out - .println("Yikes! codefolder, prepareImports(): " - + e2); } + } else { - System.err.println("Experimental Mode: Yikes! Can't find \"" - + entry - + "\" library! Line: " - + impstat.getLineNumber() - + " in tab: " - + editor.getSketch().getCode(impstat.getTab()) - .getPrettyName()); - System.out - .println("Please make sure that the library is present in /libraries folder or in the code folder of your sketch"); + System.err + .println("Yikes! There was some problem in prepareImports(): " + + e); + System.err.println("I was processing: " + entry); + + // e.printStackTrace(); } - - } else { - System.err - .println("Yikes! There was some problem in prepareImports(): " - + e); - System.err.println("I was processing: " + entry); - - // e.printStackTrace(); } + } - } - + astGenerator.loadJars(); // update jar file for completion lookup } /** @@ -1277,8 +1285,6 @@ public class ErrorCheckerService implements Runnable{ } } } - if(loadCompClass) - astGenerator.loadJars(); // log("load..? " + loadCompClass); } @@ -1390,21 +1396,21 @@ public class ErrorCheckerService implements Runnable{ * Stops the Error Checker Service thread */ public void stopThread() { - stopThread = true; + stopThread.set(true); } /** * Pauses the Error Checker Service thread */ public void pauseThread() { - pauseThread = true; + pauseThread.set(true); } /** * Resumes the Error Checker Service thread */ public void resumeThread() { - pauseThread = false; + pauseThread.set(false); } public DebugEditor getEditor() { From 904bfcd005b806494f2bd8ec6dcc8404b32c7b4e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 16:57:47 +0530 Subject: [PATCH 201/608] more synchronization --- pdex/Todo, GSoC 2013.txt | 13 +++ .../mode/experimental/ErrorBar.java | 27 +++--- .../experimental/ErrorCheckerService.java | 91 ++++++++++--------- .../mode/experimental/ExperimentalMode.java | 2 +- 4 files changed, 74 insertions(+), 59 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 4c8abef07..56d855234 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -126,6 +126,19 @@ x Working for local code * Labels for predefined class objects * Chaining support for labels +Synchronization +=============== + +Gotta do it carefully between main thread, ECS Thread, and SwingWorker threads +Fields that are concurrently accessed: + +ECS members: +ArrayList problems - updated in ECS, accessed by ErrorBar.update() +ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() +hasErrors, syntaxErrors - Atomic Boolean +CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( + + General Stuff ============= diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index 7c3d701cc..34c75904a 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -174,21 +174,22 @@ public class ErrorBar extends JPanel { // Each problem.getSourceLine() will have an extra line added // because of // class declaration in the beginning as well as default imports - for (Problem problem : problems) { - if (problem.getTabIndex() == currentTab) { - // Ratio of error line to total lines - float y = (problem.getLineNumber() - errorCheckerService.defaultImportsOffset) - / ((float) totalLines); - // Ratio multiplied by height of the error bar - y *= fheight - 15; // -15 is just a vertical offset - errorPoints - .add(new ErrorMarker(problem, (int) y, - problem.isError() ? ErrorMarker.Error - : ErrorMarker.Warning)); - // System.out.println("Y: " + y); + synchronized (problems) { + for (Problem problem : problems) { + if (problem.getTabIndex() == currentTab) { + // Ratio of error line to total lines + float y = (problem.getLineNumber() - errorCheckerService.defaultImportsOffset) + / ((float) totalLines); + // Ratio multiplied by height of the error bar + y *= fheight - 15; // -15 is just a vertical offset + errorPoints + .add(new ErrorMarker(problem, (int) y, + problem.isError() ? ErrorMarker.Error + : ErrorMarker.Warning)); + // System.out.println("Y: " + y); + } } } - return null; } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 55de1db99..9716c160f 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -510,51 +510,52 @@ public class ErrorCheckerService implements Runnable{ if (errorList == null) { return; } - - problems = new DefaultProblem[errorList.length]; - - for (int i = 0; i < errorList.length; i++) { - - // for (int j = 0; j < errorList[i].length; j++) - // System.out.print(errorList[i][j] + ", "); - - problems[i] = new DefaultProblem((char[]) errorList[i][0], - (String) errorList[i][1], - ((Integer) errorList[i][2]).intValue(), - (String[]) errorList[i][3], - ((Integer) errorList[i][4]).intValue(), - ((Integer) errorList[i][5]).intValue(), - ((Integer) errorList[i][6]).intValue(), - ((Integer) errorList[i][7]).intValue(), 0); - - // System.out - // .println("ECS: " + problems[i].getMessage() + "," - // + problems[i].isError() + "," - // + problems[i].isWarning()); - - IProblem problem = problems[i]; -// log(problem.getMessage()); -// for (String j : problem.getArguments()) { -// log("arg " + j); -// } - int a[] = calculateTabIndexAndLineNumber(problem); - Problem p = new Problem(problem, a[0], a[1]); - if ((Boolean) errorList[i][8]) { - p.setType(Problem.ERROR); - containsErrors.set(true); // set flag + + synchronized (problemsList) { + problems = new DefaultProblem[errorList.length]; + + for (int i = 0; i < errorList.length; i++) { + + // for (int j = 0; j < errorList[i].length; j++) + // System.out.print(errorList[i][j] + ", "); + + problems[i] = new DefaultProblem((char[]) errorList[i][0], + (String) errorList[i][1], + ((Integer) errorList[i][2]).intValue(), + (String[]) errorList[i][3], + ((Integer) errorList[i][4]).intValue(), + ((Integer) errorList[i][5]).intValue(), + ((Integer) errorList[i][6]).intValue(), + ((Integer) errorList[i][7]).intValue(), 0); + + // System.out + // .println("ECS: " + problems[i].getMessage() + "," + // + problems[i].isError() + "," + // + problems[i].isWarning()); + + IProblem problem = problems[i]; + // log(problem.getMessage()); + // for (String j : problem.getArguments()) { + // log("arg " + j); + // } + int a[] = calculateTabIndexAndLineNumber(problem); + Problem p = new Problem(problem, a[0], a[1]); + if ((Boolean) errorList[i][8]) { + p.setType(Problem.ERROR); + containsErrors.set(true); // set flag + } + + if ((Boolean) errorList[i][9]) { + p.setType(Problem.WARNING); + } + + // If warnings are disabled, skip 'em + if (p.isWarning() && !warningsEnabled) { + continue; + } + problemsList.add(p); } - - if ((Boolean) errorList[i][9]) { - p.setType(Problem.WARNING); - } - - // If warnings are disabled, skip 'em - if (p.isWarning() && !warningsEnabled) { - continue; - } - problemsList.add(p); } - } catch (ClassNotFoundException e) { System.err.println("Compiltation Checker files couldn't be found! " + e + " compileCheck() problem."); @@ -717,7 +718,7 @@ public class ErrorCheckerService implements Runnable{ /** * Enable/Disable warnings from being shown */ - public boolean warningsEnabled = true; + volatile public boolean warningsEnabled = true; /** * Sets compiler options for JDT Compiler @@ -747,7 +748,7 @@ public class ErrorCheckerService implements Runnable{ /** * Updates the error table in the Error Window. */ - synchronized public void updateErrorTable() { + public void updateErrorTable() { try { String[][] errorData = new String[problemsList.size()][3]; diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index db5f793b6..d5f07395a 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -46,7 +46,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = !true; + public static boolean DEBUG = true; public ExperimentalMode(Base base, File folder) { super(base, folder); From 05e69b4e41bf441c18c798e919095ae6b8299766 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 17:24:54 +0530 Subject: [PATCH 202/608] bit more work on threads, making sure all windows quite --- pdex/Todo, GSoC 2013.txt | 9 +++++---- .../mode/experimental/ASTGenerator.java | 13 +++++++++++++ .../mode/experimental/ErrorCheckerService.java | 15 ++++++++++----- .../processing/mode/experimental/ErrorWindow.java | 4 ++-- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 56d855234..54ca3a00b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -133,10 +133,11 @@ Gotta do it carefully between main thread, ECS Thread, and SwingWorker threads Fields that are concurrently accessed: ECS members: -ArrayList problems - updated in ECS, accessed by ErrorBar.update() -ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() -hasErrors, syntaxErrors - Atomic Boolean -CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( +x ArrayList problems - updated in ECS, accessed by ErrorBar.update() +x ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() +x hasErrors, syntaxErrors - Atomic Boolean +x boolean warningsEnabled - made it volatile +* CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( General Stuff diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 7bbcf32de..ff155444d 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -3090,6 +3090,19 @@ public class ASTGenerator { } } + + public void disposeAllWindows(){ + disposeWindow(frame2); + disposeWindow(frameAutoComp); + disposeWindow(frmImportSuggest); + disposeWindow(frmOccurenceList); + disposeWindow(frmRename); + } + + public static void disposeWindow(JFrame f) { + if(f != null) + f.dispose(); + } public static final String ignoredImports[] = { "com.oracle.", "sun.", "sunw.", "com.sun.", "javax.", "sunw.", "org.ietf.", diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 9716c160f..5f6d1479a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -282,6 +282,10 @@ public class ErrorCheckerService implements Runnable{ checkCode(); checkForMissingImports(); } + checkerClass = null; + astGenerator.disposeAllWindows(); + astGenerator = null; + logE("Thread stopped: " + editor.getSketch().getName()); } private void checkForMissingImports() { @@ -559,20 +563,20 @@ public class ErrorCheckerService implements Runnable{ } catch (ClassNotFoundException e) { System.err.println("Compiltation Checker files couldn't be found! " + e + " compileCheck() problem."); - stopThread(); + pauseThread(); } catch (MalformedURLException e) { System.err.println("Compiltation Checker files couldn't be found! " + e + " compileCheck() problem."); - stopThread(); + pauseThread(); } catch (Exception e) { System.err.println("compileCheck() problem." + e); e.printStackTrace(); - stopThread(); + pauseThread(); } catch (NoClassDefFoundError e) { System.err .println(e + " compileCheck() problem. Somebody tried to mess with Experimental Mode files."); - stopThread(); + pauseThread(); } // log("Compilecheck, Done."); } @@ -793,7 +797,7 @@ public class ErrorCheckerService implements Runnable{ } catch (Exception e) { log("Exception at updateErrorTable() " + e); e.printStackTrace(); - stopThread(); + pauseThread(); } } @@ -1397,6 +1401,7 @@ public class ErrorCheckerService implements Runnable{ * Stops the Error Checker Service thread */ public void stopThread() { + logE("Stopping thread: " + editor.getSketch().getName()); stopThread.set(true); } diff --git a/pdex/src/processing/mode/experimental/ErrorWindow.java b/pdex/src/processing/mode/experimental/ErrorWindow.java index 6494b58ed..4e7db2e36 100755 --- a/pdex/src/processing/mode/experimental/ErrorWindow.java +++ b/pdex/src/processing/mode/experimental/ErrorWindow.java @@ -183,7 +183,7 @@ public class ErrorWindow extends JFrame { return; } - thisEditor.addWindowListener(new WindowAdapter() { + /*thisEditor.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { @@ -207,7 +207,7 @@ public class ErrorWindow extends JFrame { thisErrorWindow.setExtendedState(Frame.NORMAL); } - }); + });*/ thisEditor.addComponentListener(new ComponentListener() { From b6362d48a5de17960701ab89a0530b5b97c73759 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 20:30:39 +0530 Subject: [PATCH 203/608] Getter for astgen --- .../src/processing/mode/experimental/CompletionPanel.java | 8 ++++---- pdex/src/processing/mode/experimental/DebugEditor.java | 6 +++--- .../processing/mode/experimental/ErrorCheckerService.java | 5 +++++ pdex/src/processing/mode/experimental/TextArea.java | 6 +++--- .../src/processing/mode/experimental/TextAreaPainter.java | 4 ++-- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 55e66c430..ff2b7384a 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -56,7 +56,7 @@ public class CompletionPanel { scrollPane.setViewportView(completionList = createSuggestionList(position, items)); popupMenu.add(scrollPane, BorderLayout.CENTER); popupMenu.setPopupSize(280, 250); //TODO: Eradicate this evil - this.textarea.errorCheckerService.astGenerator + this.textarea.errorCheckerService.getASTGenerator() .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); @@ -145,7 +145,7 @@ public class CompletionPanel { public void hideSuggestion() { popupMenu.setVisible(false); log("Suggestion hidden" + System.nanoTime()); - //textarea.errorCheckerService.astGenerator.jdocWindowVisible(false); + //textarea.errorCheckerService.getASTGenerator().jdocWindowVisible(false); } public void moveUp() { @@ -163,7 +163,7 @@ public class CompletionPanel { .getVerticalScrollBar() .getValue() - step); - textarea.errorCheckerService.astGenerator + textarea.errorCheckerService.getASTGenerator() .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); } @@ -178,7 +178,7 @@ public class CompletionPanel { .getSize() - 1); selectIndex(index); } - textarea.errorCheckerService.astGenerator + textarea.errorCheckerService.getASTGenerator() .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); int step = scrollPane.getVerticalScrollBar().getMaximum() / completionList.getModel().getSize(); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index ad0936e52..34e02d598 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -612,7 +612,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { toggleVariableInspector(); } else if (source.equals(showOutline)){ log("Show Outline :D"); - errorCheckerService.astGenerator.showSketchOutline(); + errorCheckerService.getASTGenerator().showSketchOutline(); } } @@ -1259,13 +1259,13 @@ public class DebugEditor extends JavaEditor implements ActionListener { private void handleRefactor() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); - errorCheckerService.astGenerator.handleRefactor(); + errorCheckerService.getASTGenerator().handleRefactor(); } private void handleShowUsage() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); - errorCheckerService.astGenerator.handleShowUsage(); + errorCheckerService.getASTGenerator().handleShowUsage(); } /** diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 5f6d1479a..1d04be341 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -302,6 +302,11 @@ public class ErrorCheckerService implements Runnable{ } protected ASTGenerator astGenerator; + + public ASTGenerator getASTGenerator() { + return astGenerator; + } + /** * This thing acts as an event queue counter of sort. * Since error checking happens on demand, anytime this counter diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index d5caef4d7..4468951dd 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -251,7 +251,7 @@ public class TextArea extends JEditTextArea { if (Character.isDigit(word.charAt(0))) return null; log("Mouse click, word: " + word.trim()); - errorCheckerService.astGenerator.setLastClickedWord(line + errorCheckerService.getASTGenerator().setLastClickedWord(line + errorCheckerService.mainClassOffset, word, xLS); return word.trim(); } @@ -302,7 +302,7 @@ public class TextArea extends JEditTextArea { if (word.endsWith(".")) word = word.substring(0, word.length() - 1); if(word.length() > 1) - errorCheckerService.astGenerator.preparePredictions(word, line + errorCheckerService.getASTGenerator().preparePredictions(word, line + errorCheckerService.mainClassOffset,0); return word; } @@ -380,7 +380,7 @@ public class TextArea extends JEditTextArea { // word = word.substring(0, word.length() - 1); int lineStartNonWSOffset = 0; if(word.length() > 1) - errorCheckerService.astGenerator.preparePredictions(word, line + errorCheckerService.getASTGenerator().preparePredictions(word, line + errorCheckerService.mainClassOffset,lineStartNonWSOffset); //showSuggestionLater(); return word; diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index f8db484bb..382501202 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -143,7 +143,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { log(errorCheckerService.mainClassOffset + line + "|" + line + "| offset " + xLS + word + " <= \n"); - errorCheckerService.astGenerator.scrollToDeclaration(line + errorCheckerService.getASTGenerator().scrollToDeclaration(line + errorCheckerService.mainClassOffset, word, xLS); } } @@ -472,7 +472,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } if (Character.isDigit(word.charAt(0))) return null; - String tooltipText = errorCheckerService.astGenerator + String tooltipText = errorCheckerService.getASTGenerator() .getLabelForASTNode(line + errorCheckerService.mainClassOffset, word, xLS); From 737062ff4333fdfefec8f60774551de082270890 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 20:34:10 +0530 Subject: [PATCH 204/608] access is now protected --- .../experimental/ErrorCheckerService.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 1d04be341..cec61813b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -39,7 +39,7 @@ import processing.mode.java.preproc.PdePreprocessor; public class ErrorCheckerService implements Runnable{ - private DebugEditor editor; + protected DebugEditor editor; /** * Error check happens every sleepTime milliseconds */ @@ -48,7 +48,7 @@ public class ErrorCheckerService implements Runnable{ /** * The amazing eclipse ast parser */ - private ASTParser parser; + protected ASTParser parser; /** * Used to indirectly stop the Error Checker Thread @@ -65,7 +65,7 @@ public class ErrorCheckerService implements Runnable{ /** * IProblem[] returned by parser stored in here */ - private IProblem[] problems; + protected IProblem[] problems; /** * Class name of current sketch @@ -114,7 +114,7 @@ public class ErrorCheckerService implements Runnable{ * If true, compilation checker will be reloaded with updated classpath * items. */ - private boolean loadCompClass = true; + protected boolean loadCompClass = true; /** * Compiler Checker class. Note that methods for compilation checking are @@ -136,14 +136,14 @@ public class ErrorCheckerService implements Runnable{ /** * Timestamp - for measuring total overhead */ - private long lastTimeStamp = System.currentTimeMillis(); + protected long lastTimeStamp = System.currentTimeMillis(); /** * Used for displaying the rotating slash on the Problem Window title bar */ - private String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--", + protected String[] slashAnimation = { "|", "/", "--", "\\", "|", "/", "--", "\\" }; - private int slashAnimationIndex = 0; + protected int slashAnimationIndex = 0; /** * Used to detect if the current tab index has changed and thus repaint the @@ -155,7 +155,7 @@ public class ErrorCheckerService implements Runnable{ * Stores the current import statements in the program. Used to compare for * changed import statements and update classpath if needed. */ - private ArrayList programImports; + protected ArrayList programImports; /** * List of imports when sketch was last checked. Used for checking for @@ -207,7 +207,7 @@ public class ErrorCheckerService implements Runnable{ /** * Initializes ASTParser */ - private void initParser() { + protected void initParser() { try { parser = ASTParser.newParser(AST.JLS4); } catch (Exception e) { @@ -288,7 +288,7 @@ public class ErrorCheckerService implements Runnable{ logE("Thread stopped: " + editor.getSketch().getName()); } - private void checkForMissingImports() { + protected void checkForMissingImports() { for (Problem p : problemsList) { if(p.getMessage().endsWith(" cannot be resolved to a type"));{ int idx = p.getMessage().indexOf(" cannot be resolved to a type"); @@ -322,7 +322,7 @@ public class ErrorCheckerService implements Runnable{ textModified.incrementAndGet(); } - private boolean checkCode() { + protected boolean checkCode() { //log("checkCode() " + textModified.get() ); log("checkCode() " + textModified.get()); lastTimeStamp = System.currentTimeMillis(); @@ -391,7 +391,7 @@ public class ErrorCheckerService implements Runnable{ protected TreeMap tempErrorLog; - private void syntaxCheck() { + protected void syntaxCheck() { syntaxErrors.set(true); containsErrors.set(true); parser.setSource(sourceCode.toCharArray()); @@ -443,7 +443,7 @@ public class ErrorCheckerService implements Runnable{ protected URLClassLoader classLoader; - private void compileCheck() { + protected void compileCheck() { // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the @@ -597,7 +597,7 @@ public class ErrorCheckerService implements Runnable{ * messed up. * */ - private void prepareCompilerClasspath() { + protected void prepareCompilerClasspath() { if (!loadCompClass) { return; } @@ -1037,7 +1037,7 @@ public class ErrorCheckerService implements Runnable{ * code is not yet compile ready. */ - private String preprocessCode(String pdeCode) { + protected String preprocessCode(String pdeCode) { programImports = new ArrayList(); @@ -1276,7 +1276,7 @@ public class ErrorCheckerService implements Runnable{ * Checks if import statements in the sketch have changed. If they have, * compiler classpath needs to be updated. */ - private void checkForChangedImports() { + protected void checkForChangedImports() { // log("Imports: " + programImports.size() + // " Prev Imp: " // + previousImports.size()); @@ -1298,7 +1298,7 @@ public class ErrorCheckerService implements Runnable{ // log("load..? " + loadCompClass); } - private int pdeImportsCount; + protected int pdeImportsCount; public int getPdeImportsCount() { return pdeImportsCount; @@ -1314,7 +1314,7 @@ public class ErrorCheckerService implements Runnable{ * - index of the tab * @return String - Tab code with imports replaced with white spaces */ - private String scrapImportStatements(String tabProgram, int tabNumber) { + protected String scrapImportStatements(String tabProgram, int tabNumber) { //TODO: Commented out imports are still detected as main imports. pdeImportsCount = 0; String tabSource = new String(tabProgram); From 1b4a4aaa4f847ad309eb56e46dcc2d2deb3304e6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 24 Aug 2013 20:36:58 +0530 Subject: [PATCH 205/608] also for astGen --- .../mode/experimental/ASTGenerator.java | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ff155444d..9ba2d3e53 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -109,44 +109,44 @@ public class ASTGenerator { public DefaultMutableTreeNode codeTree = new DefaultMutableTreeNode(); - private DefaultMutableTreeNode currentParent = null; + protected DefaultMutableTreeNode currentParent = null; /** * AST Window */ - private JFrame frame2; + protected JFrame frame2; - private JFrame frameAutoComp; + protected JFrame frameAutoComp; /** * Swing component wrapper for AST, used for internal testing */ - private JTree jtree; + protected JTree jtree; /** * JTree used for testing refactoring operations */ - private JTree treeRename; + protected JTree treeRename; - private CompilationUnit compilationUnit; + protected CompilationUnit compilationUnit; - private JTable tableAuto; + protected JTable tableAuto; - private JEditorPane javadocPane; + protected JEditorPane javadocPane; - private JScrollPane scrollPane; + protected JScrollPane scrollPane; - private JFrame frmRename; + protected JFrame frmRename; - private JButton btnRename; + protected JButton btnRename; - private JButton btnListOccurrence; + protected JButton btnListOccurrence; - private JTextField txtRenameField; + protected JTextField txtRenameField; - private JFrame frmOccurenceList; + protected JFrame frmOccurenceList; - private JLabel lblRefactorOldName; + protected JLabel lblRefactorOldName; public ASTGenerator(ErrorCheckerService ecs) { this.errorCheckerService = ecs; @@ -156,7 +156,7 @@ public class ASTGenerator { addListeners(); } - private void setupGUI(){ + protected void setupGUI(){ frame2 = new JFrame(); jtree = new JTree(); @@ -234,7 +234,7 @@ public class ASTGenerator { //// loadJars(); } - private DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { + protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { ASTParser parser = ASTParser.newParser(AST.JLS4); parser.setSource(source.toCharArray()); @@ -304,14 +304,14 @@ public class ASTGenerator { return codeTree; } - private ClassPathFactory factory; + protected ClassPathFactory factory; /** * Used for searching for package declaration of a class */ - private ClassPath classPath; + protected ClassPath classPath; - private JFrame jdocWindow; + protected JFrame jdocWindow; /** * Loads up .jar files and classes defined in it for completion lookup @@ -395,9 +395,9 @@ public class ASTGenerator { t.start(); } - private TreeMap jdocMap; + protected TreeMap jdocMap; - private void loadJavaDoc() { + protected void loadJavaDoc() { // presently loading only p5 reference for PApplet Thread t = new Thread(new Runnable() { @@ -758,7 +758,7 @@ public class ASTGenerator { return null; } - private void trimCandidates(String newWord){ + protected void trimCandidates(String newWord){ ArrayList newCandidate = new ArrayList(); newWord = newWord.toLowerCase(); for (CompletionCandidate comp : candidates) { @@ -773,8 +773,8 @@ public class ASTGenerator { /** * List of CompletionCandidates */ - private ArrayList candidates; - private String lastPredictedWord = " "; + protected ArrayList candidates; + protected String lastPredictedWord = " "; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance @@ -998,7 +998,7 @@ public class ASTGenerator { // worker.execute(); } - private void showPredictions(final String word) { + protected void showPredictions(final String word) { if (sketchOutline != null) if (sketchOutline.isVisible()) return; Collections.sort(candidates); @@ -1153,7 +1153,7 @@ public class ASTGenerator { * @param className * @return */ - private Class findClassIfExists(String className){ + protected Class findClassIfExists(String className){ if(className == null){ return null; } @@ -1224,7 +1224,7 @@ public class ASTGenerator { return tehClass; } - private Class loadClass(String className){ + protected Class loadClass(String className){ Class tehClass = null; if(className instanceof String){ try { @@ -1343,7 +1343,7 @@ public class ASTGenerator { } @SuppressWarnings("unchecked") - private static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { + protected static ASTNode findClosestParentNode(int lineNumber, ASTNode node) { Iterator it = node .structuralPropertiesForType().iterator(); // logE("Props of " + node.getClass().getName()); @@ -1383,7 +1383,7 @@ public class ASTGenerator { return node; } - private static ASTNode findClosestNode(int lineNumber, ASTNode node) { + protected static ASTNode findClosestNode(int lineNumber, ASTNode node) { log("findClosestNode to line " + lineNumber); ASTNode parent = findClosestParentNode(lineNumber, node); log("findClosestParentNode returned " + getNodeAsString(parent)); @@ -1427,7 +1427,7 @@ public class ASTGenerator { //return ""; } - private String getLabelIfType(ASTNodeWrapper node, SimpleName sn){ + protected String getLabelIfType(ASTNodeWrapper node, SimpleName sn){ ASTNode current = node.getNode().getParent(); String type = ""; StringBuffer fullName = new StringBuffer(); @@ -1633,7 +1633,7 @@ public class ASTGenerator { * @param name - The name we're looking for. * @return SimpleName */ - private static ASTNode getNodeName(ASTNode node, String name){ + protected static ASTNode getNodeName(ASTNode node, String name){ List vdfs = null; switch (node.getNodeType()) { case ASTNode.TYPE_DECLARATION: @@ -1726,7 +1726,7 @@ public class ASTGenerator { } } - private void addListeners(){ + protected void addListeners(){ jtree.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -1827,7 +1827,7 @@ public class ASTGenerator { }); } - private void refactorIt(){ + protected void refactorIt(){ String newName = txtRenameField.getText().trim(); String selText = lastClickedWord == null ? editor.ta.getSelectedText() : lastClickedWord; @@ -1944,7 +1944,7 @@ public class ASTGenerator { log("Last clicked node: " + lastClickedWordNode); } - private DefaultMutableTreeNode findAllOccurrences(){ + protected DefaultMutableTreeNode findAllOccurrences(){ log("Last clicked word:" + lastClickedWord); String selText = lastClickedWord == null ? editor.ta.getSelectedText() : lastClickedWord; @@ -2121,7 +2121,7 @@ public class ASTGenerator { return -1; } - private int PdeToJavaLineNumber(int lineNum){ + protected int PdeToJavaLineNumber(int lineNum){ int lineNumber = lineNum + errorCheckerService.getPdeImportsCount(); // Adjust line number for tabbed sketches int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -2134,7 +2134,7 @@ public class ASTGenerator { return lineNumber; } - private boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ + protected boolean isInstanceOfType(ASTNode node,ASTNode decl, String name){ if(node instanceof SimpleName){ SimpleName sn = (SimpleName) node; @@ -2232,7 +2232,7 @@ public class ASTGenerator { } @SuppressWarnings("unchecked") - private static ASTNode findLineOfNode(ASTNode node, int lineNumber, + protected static ASTNode findLineOfNode(ASTNode node, int lineNumber, int offset, String name) { CompilationUnit root = (CompilationUnit) node.getRoot(); @@ -2349,7 +2349,7 @@ public class ASTGenerator { * @return */ @SuppressWarnings("unchecked") - private static ASTNode findDeclaration(Name findMe) { + protected static ASTNode findDeclaration(Name findMe) { // WARNING: You're entering the Rube Goldberg territory of Experimental Mode. // To debug this code, thou must take the Recursive Leap of Faith. @@ -2544,7 +2544,7 @@ public class ASTGenerator { * @param alternateParent * @return */ - private static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { + protected static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) { ASTNode declaringClass = null; ASTNode parent = findMe.getParent(); ASTNode ret = null; @@ -2728,7 +2728,7 @@ public class ASTGenerator { } - private List getCodeComments(){ + protected List getCodeComments(){ List commentList = compilationUnit.getCommentList(); // log("Total comments: " + commentList.size()); // int i = 0; @@ -2925,7 +2925,7 @@ public class ASTGenerator { } @SuppressWarnings("unchecked") - private static ASTNode definedIn(ASTNode node, String name, + protected static ASTNode definedIn(ASTNode node, String name, ArrayList constrains, ASTNode declaringClass) { if (node == null) @@ -3108,7 +3108,7 @@ public class ASTGenerator { "com.oracle.", "sun.", "sunw.", "com.sun.", "javax.", "sunw.", "org.ietf.", "org.jcp.", "org.omg.", "org.w3c.", "org.xml.", "org.eclipse.", "com.ibm.", "org.netbeans.", "org.jsoup.", "org.junit.", "org.apache.", "antlr." }; - private boolean ignorableImport(String impName) { + protected boolean ignorableImport(String impName) { //TODO: Trie man. for (ImportStatement impS : errorCheckerService.getProgramImports()) { if(impName.startsWith(impS.getPackageName())) @@ -3172,7 +3172,7 @@ public class ASTGenerator { - static private String getNodeAsString(ASTNode node) { + static protected String getNodeAsString(ASTNode node) { if (node == null) return "NULL"; String className = node.getClass().getName(); @@ -3224,7 +3224,7 @@ public class ASTGenerator { * @param node * @return */ - static private String getNodeAsString2(ASTNode node) { + static protected String getNodeAsString2(ASTNode node) { if (node == null) return "NULL"; String className = node.getClass().getName(); From d0d3648c2d91c3ab900cf8ed80ef0b51cb1d2dd8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 18:06:50 +0530 Subject: [PATCH 206/608] did and then undid javadoc pane work. doesn't seem right. --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/ASTGenerator.java | 80 ++++++++++--------- .../experimental/CompletionCandidate.java | 8 ++ 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 54ca3a00b..10415a8ec 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -15,6 +15,7 @@ The big stuff: - Making very good progress here. The elegance of recurion - Hats off! - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) +* After popup appears, the popup location is fixed for the current line. So if editor window is moved while staying in the same line, popup appears at the prev location. Need to ensure editor is still at last know location * Scope handling? Static/non static scope? * Disable completions on comment line * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9ba2d3e53..d20b6fc1a 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -153,7 +153,7 @@ public class ASTGenerator { this.editor = ecs.getEditor(); setupGUI(); //addCompletionPopupListner(); - addListeners(); + addListeners(); loadJavaDoc(); } protected void setupGUI(){ @@ -220,18 +220,20 @@ public class ASTGenerator { // sp3.setViewportView(tableAuto); // frameAutoComp.add(sp3); -// jdocWindow = new JFrame(); -// jdocWindow.setTitle("P5 InstaHelp"); +// frmJavaDoc = new JFrame(); +// frmJavaDoc.setTitle("P5 InstaHelp"); // //jdocWindow.setUndecorated(true); -// jdocWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); +// frmJavaDoc.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); // javadocPane = new JEditorPane(); // javadocPane.setContentType("text/html"); +// javadocPane.setText(" "); // javadocPane.setEditable(false); // scrollPane = new JScrollPane(); // scrollPane.setViewportView(javadocPane); -// jdocWindow.add(scrollPane); -// jdocMap = new TreeMap(); -//// loadJars(); +// frmJavaDoc.add(scrollPane); + //frmJavaDoc.setUndecorated(true); + + } protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { @@ -282,17 +284,16 @@ public class ASTGenerator { // frameAutoComp.setVisible(true); // // } -// if (!jdocWindow.isVisible()) { +// if (!frmJavaDoc.isVisible()) { // long t = System.currentTimeMillis(); -// loadJars(); // loadJavaDoc(); // log("Time taken: " // + (System.currentTimeMillis() - t)); -// jdocWindow.setBounds(new Rectangle(errorCheckerService.getEditor() +// frmJavaDoc.setBounds(new Rectangle(errorCheckerService.getEditor() // .getX() + errorCheckerService.getEditor().getWidth(), // errorCheckerService.getEditor() // .getY(), 450, 600)); -// jdocWindow.setVisible(true); +// frmJavaDoc.setVisible(true); // } } } @@ -311,7 +312,7 @@ public class ASTGenerator { */ protected ClassPath classPath; - protected JFrame jdocWindow; + //protected JFrame frmJavaDoc; /** * Loads up .jar files and classes defined in it for completion lookup @@ -398,7 +399,7 @@ public class ASTGenerator { protected TreeMap jdocMap; protected void loadJavaDoc() { - + jdocMap = new TreeMap(); // presently loading only p5 reference for PApplet Thread t = new Thread(new Runnable() { @@ -763,7 +764,7 @@ public class ASTGenerator { newWord = newWord.toLowerCase(); for (CompletionCandidate comp : candidates) { if(comp.toString().toLowerCase().startsWith(newWord)){ - log("Adding " + comp); + // log("Adding " + comp); newCandidate.add(comp); } } @@ -1309,37 +1310,44 @@ public class ASTGenerator { public void updateJavaDoc(final CompletionCandidate candidate) { //TODO: Work on this later. - return; - /*String methodmatch = candidate.toString(); + return; + /* String methodmatch = candidate.toString(); if (methodmatch.indexOf('(') != -1) { methodmatch = methodmatch.substring(0, methodmatch.indexOf('(')); } //log("jdoc match " + methodmatch); + String temp = " "; for (final String key : jdocMap.keySet()) { if (key.startsWith(methodmatch) && key.length() > 3) { log("Matched jdoc " + key); - - //visitRecur((ASTNode) compilationUnit.types().get(0), codeTree); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - log("Class: " + candidate.getDefiningClass()); - if (candidate.getDefiningClass().equals("processing.core.PApplet")) { - javadocPane.setText(jdocMap.get(key)); - //jdocWindow.setVisible(true); - //editor.textArea().requestFocus() - } else - javadocPane.setText(""); - javadocPane.setCaretPosition(0); + if (candidate.getWrappedObject() != null) { + String definingClass = ""; + if (candidate.getWrappedObject() instanceof Field) + definingClass = ((Field) candidate.getWrappedObject()) + .getDeclaringClass().getName(); + else if (candidate.getWrappedObject() instanceof Method) + definingClass = ((Method) candidate.getWrappedObject()) + .getDeclaringClass().getName(); + if (definingClass.equals("processing.core.PApplet")) { + temp = (jdocMap.get(key)); + break; } - }); - break; + } } - }*/ - //jdocWindow.setVisible(false); - + } + + final String jdocString = temp; + SwingUtilities.invokeLater(new Runnable() { + public void run() { + javadocPane.setText(jdocString); + scrollPane.getVerticalScrollBar().setValue(0); + //frmJavaDoc.setVisible(!jdocString.equals(" ")); + editor.toFront(); + editor.ta.requestFocus(); + } + }); +*/ } @SuppressWarnings("unchecked") @@ -3271,7 +3279,7 @@ public class ASTGenerator { } public void jdocWindowVisible(boolean visible) { - jdocWindow.setVisible(visible); + // frmJavaDoc.setVisible(visible); } public static String readFile(String path) { diff --git a/pdex/src/processing/mode/experimental/CompletionCandidate.java b/pdex/src/processing/mode/experimental/CompletionCandidate.java index bc2973785..ef29d5963 100644 --- a/pdex/src/processing/mode/experimental/CompletionCandidate.java +++ b/pdex/src/processing/mode/experimental/CompletionCandidate.java @@ -18,6 +18,8 @@ public class CompletionCandidate implements Comparable{ private String label; // the toString value private String completionString; + + private Object wrappedObject; private int type; @@ -48,8 +50,13 @@ public class CompletionCandidate implements Comparable{ this.label = label.toString(); this.completionString = cstr.toString(); type = PREDEF_METHOD; + wrappedObject = method; } + public Object getWrappedObject() { + return wrappedObject; + } + public CompletionCandidate(SingleVariableDeclaration svd) { completionString = svd.getName().toString(); elementName = svd.getName().toString(); @@ -110,6 +117,7 @@ public class CompletionCandidate implements Comparable{ label = f.getName() + " : " + f.getType().getSimpleName() + " - " + f.getDeclaringClass().getSimpleName(); completionString = elementName; + wrappedObject = f; } public CompletionCandidate(String name, String labelStr, String completionStr, int type) { From 285f81db65dfd39783cfbeb25528823bf88c646c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 18:36:37 +0530 Subject: [PATCH 207/608] adding option for disabling completions, fixes #10 --- .../mode/experimental/ASTGenerator.java | 4 ++++ .../mode/experimental/DebugEditor.java | 16 ++++++++++++++++ .../processing/mode/experimental/TextArea.java | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index d20b6fc1a..ba6e3301e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import javax.swing.BorderFactory; @@ -154,6 +155,7 @@ public class ASTGenerator { setupGUI(); //addCompletionPopupListner(); addListeners(); loadJavaDoc(); + predictionsEnabled = new AtomicBoolean(true); } protected void setupGUI(){ @@ -776,8 +778,10 @@ public class ASTGenerator { */ protected ArrayList candidates; protected String lastPredictedWord = " "; + protected AtomicBoolean predictionsEnabled; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { + if(!predictionsEnabled.get()) return; // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance // in TextArea.processKeyEvent if(caretWithinLineComment()){ diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 34e02d598..6506b6e8f 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -166,6 +166,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected JCheckBoxMenuItem writeErrorLog; + /** + * Enable/Disable code completion + */ + protected JCheckBoxMenuItem completionsEnabled; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -521,6 +526,17 @@ public class DebugEditor extends JavaEditor implements ActionListener { }); debugMenu.add(showWarnings); + completionsEnabled = new JCheckBoxMenuItem("Code Completion Enabled"); + completionsEnabled.setSelected(true); + completionsEnabled.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + errorCheckerService.getASTGenerator().predictionsEnabled + .set(((JCheckBoxMenuItem) e.getSource()).isSelected()); + } + }); + debugMenu.add(completionsEnabled); + debugMessagesEnabled = new JCheckBoxMenuItem("Show Debug Messages"); debugMessagesEnabled.setSelected(ExperimentalMode.DEBUG); debugMessagesEnabled.addActionListener(new ActionListener() { diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 4468951dd..0d54ecd5c 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -179,7 +179,7 @@ public class TextArea extends JEditTextArea { } super.processKeyEvent(evt); - if (evt.getID() == KeyEvent.KEY_TYPED) { + if (evt.getID() == KeyEvent.KEY_TYPED && editor.errorCheckerService.getASTGenerator().predictionsEnabled.get()) { final KeyEvent evt2 = evt; SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { From aac15c0a8e5d7bd1be1bd32e96a8b2d96642d886 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 18:38:09 +0530 Subject: [PATCH 208/608] thread sync bug fix, again. '-_- --- .../mode/experimental/ErrorBar.java | 47 ++++++++++--------- .../experimental/ErrorCheckerService.java | 26 +++++----- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorBar.java b/pdex/src/processing/mode/experimental/ErrorBar.java index 34c75904a..9ab47395b 100755 --- a/pdex/src/processing/mode/experimental/ErrorBar.java +++ b/pdex/src/processing/mode/experimental/ErrorBar.java @@ -164,29 +164,30 @@ public class ErrorBar extends JPanel { e.printStackTrace(); } // System.out.println("Total lines: " + totalLines); - - errorPointsOld.clear(); - for (ErrorMarker marker : errorPoints) { - errorPointsOld.add(marker); - } - errorPoints.clear(); - - // Each problem.getSourceLine() will have an extra line added - // because of - // class declaration in the beginning as well as default imports - synchronized (problems) { - for (Problem problem : problems) { - if (problem.getTabIndex() == currentTab) { - // Ratio of error line to total lines - float y = (problem.getLineNumber() - errorCheckerService.defaultImportsOffset) - / ((float) totalLines); - // Ratio multiplied by height of the error bar - y *= fheight - 15; // -15 is just a vertical offset - errorPoints - .add(new ErrorMarker(problem, (int) y, - problem.isError() ? ErrorMarker.Error - : ErrorMarker.Warning)); - // System.out.println("Y: " + y); + synchronized (errorPoints) { + errorPointsOld.clear(); + for (ErrorMarker marker : errorPoints) { + errorPointsOld.add(marker); + } + errorPoints.clear(); + + // Each problem.getSourceLine() will have an extra line added + // because of + // class declaration in the beginning as well as default imports + synchronized (problems) { + for (Problem problem : problems) { + if (problem.getTabIndex() == currentTab) { + // Ratio of error line to total lines + float y = (problem.getLineNumber() - errorCheckerService.defaultImportsOffset) + / ((float) totalLines); + // Ratio multiplied by height of the error bar + y *= fheight - 15; // -15 is just a vertical offset + errorPoints + .add(new ErrorMarker(problem, (int) y, + problem.isError() ? ErrorMarker.Error + : ErrorMarker.Warning)); + // System.out.println("Y: " + y); + } } } } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index cec61813b..94baf0ede 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -831,19 +831,21 @@ public class ErrorCheckerService implements Runnable{ public void updateEditorStatus() { // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); - for (ErrorMarker emarker : editor.errorBar.errorPoints) { - if (emarker.getProblem().getLineNumber() == editor.getTextArea() - .getCaretLine() + 1) { - if (emarker.getType() == ErrorMarker.Warning) { - editor.statusNotice(emarker.getProblem().getMessage()); - //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); - //TODO: this is temporary + synchronized (editor.errorBar.errorPoints) { + for (ErrorMarker emarker : editor.errorBar.errorPoints) { + if (emarker.getProblem().getLineNumber() == editor.getTextArea() + .getCaretLine() + 1) { + if (emarker.getType() == ErrorMarker.Warning) { + editor.statusNotice(emarker.getProblem().getMessage()); + //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); + //TODO: this is temporary + } + else { + editor.statusError(emarker.getProblem().getMessage()); + //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); + } + return; } - else { - editor.statusError(emarker.getProblem().getMessage()); - //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); - } - return; } } if (editor.ta.getCaretLine() != lastCaretLine) { From 146423b3b466a80570ca0f49c36eb0c15b561b54 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 20:09:17 +0530 Subject: [PATCH 209/608] attempting something crazy. --- .../mode/experimental/DebugEditor.java | 32 +++++++++-- .../mode/experimental/DebugToolbar.java | 54 ++++++++++++++++++- .../mode/experimental/Debugger.java | 28 ++++++---- 3 files changed, 99 insertions(+), 15 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 6506b6e8f..fc3d8ee6b 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -373,7 +373,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { * * @return the sketch menu */ - @Override + /*@Override public JMenu buildSketchMenu() { JMenuItem runItem = Toolkit.newJMenuItemShift(DebugToolbar.getTitle(DebugToolbar.RUN, false), KeyEvent.VK_R); runItem.addActionListener(new ActionListener() { @@ -399,6 +399,19 @@ public class DebugEditor extends JavaEditor implements ActionListener { } }); return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); + }*/ + + boolean debugToolbarShown = false; + protected EditorToolbar javaToolbar, debugToolbar; + protected void switchToolbars(){ + if(debugToolbarShown){ + // switch to java + } + else{ + // switch to debug + if(debugToolbar == null) + debugToolbar = new DebugToolbar(this, getBase()); + } } /** @@ -410,7 +423,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { protected JMenu buildDebugMenu() { debugMenu = new JMenu("Debug"); - debugMenuItem = Toolkit.newJMenuItem("Debug", KeyEvent.VK_R); + JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem("Show Debug Toolbar"); + toggleDebugger.setSelected(false); + toggleDebugger.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) { + + } + }); + debugMenu.add(toggleDebugger); + debugMenuItem = Toolkit.newJMenuItemAlt("Debug", KeyEvent.VK_R); debugMenuItem.addActionListener(this); continueMenuItem = Toolkit.newJMenuItem("Continue", KeyEvent.VK_U); continueMenuItem.addActionListener(this); @@ -921,7 +943,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { } public DebugToolbar toolbar() { + if(toolbar instanceof DebugToolbar) return (DebugToolbar) toolbar; + return null; } /** @@ -1191,10 +1215,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { * * @return the toolbar */ - @Override + /*@Override public EditorToolbar createToolbar() { return new DebugToolbar(this, base); - } + }*/ /** * Event Handler for double clicking in the left hand gutter area. diff --git a/pdex/src/processing/mode/experimental/DebugToolbar.java b/pdex/src/processing/mode/experimental/DebugToolbar.java index 3738b9db9..67af28774 100755 --- a/pdex/src/processing/mode/experimental/DebugToolbar.java +++ b/pdex/src/processing/mode/experimental/DebugToolbar.java @@ -17,12 +17,16 @@ */ package processing.mode.experimental; +import java.awt.Graphics; import java.awt.Image; import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; import java.util.logging.Level; import java.util.logging.Logger; import processing.app.Base; import processing.app.Editor; +import processing.app.Preferences; +import processing.app.Toolkit; import processing.mode.java.JavaToolbar; /** @@ -64,7 +68,55 @@ public class DebugToolbar extends JavaToolbar { public DebugToolbar(Editor editor, Base base) { super(editor, base); } - + public Image[][] loadImages() { + int res = Toolkit.highResDisplay() ? 2 : 1; + + String suffix = null; + Image allButtons = null; + // Some modes may not have a 2x version. If a mode doesn't have a 1x + // version, this will cause an error... they should always have 1x. + if (res == 2) { + suffix = "-2x.png"; + allButtons = mode.loadImage("theme/buttons-debug" + suffix); + if (allButtons == null) { + res = 1; // take him down a notch + } + } + if (res == 1) { + suffix = ".png"; + allButtons = mode.loadImage("theme/buttons-debug" + suffix); + if (allButtons == null) { + // use the old (pre-2.0b9) file name + suffix = ".gif"; + allButtons = mode.loadImage("theme/buttons-debug" + suffix); + } + } + /** Width of each toolbar button. */ + final int BUTTON_WIDTH = 27; + /** Height of each toolbar button. */ +// static final int BUTTON_HEIGHT = 32; + /** The amount of space between groups of buttons on the toolbar. */ + final int BUTTON_GAP = 5; + /** Size (both width and height) of the buttons in the source image. */ + final int BUTTON_IMAGE_SIZE = 33; + int count = allButtons.getWidth(this) / BUTTON_WIDTH*res; + final int GRID_SIZE = 32; + Image[][] buttonImages = new Image[count][3]; + + for (int i = 0; i < count; i++) { + for (int state = 0; state < 3; state++) { + Image image = new BufferedImage(BUTTON_WIDTH*res, GRID_SIZE*res, BufferedImage.TYPE_INT_ARGB); + Graphics g = image.getGraphics(); + g.drawImage(allButtons, + -(i*BUTTON_IMAGE_SIZE*res) - 3, + (state-2)*BUTTON_IMAGE_SIZE*res, null); + g.dispose(); + buttonImages[i][state] = image; + } + } + + return buttonImages; + } /** * Initialize buttons. Loads images and adds the buttons to the toolbar. diff --git a/pdex/src/processing/mode/experimental/Debugger.java b/pdex/src/processing/mode/experimental/Debugger.java index 758f6cfae..50b5d9846 100755 --- a/pdex/src/processing/mode/experimental/Debugger.java +++ b/pdex/src/processing/mode/experimental/Debugger.java @@ -168,7 +168,7 @@ public class Debugger implements VMEventListener { // load edits into sketch obj, etc... editor.prepareRun(); - + if(editor.toolbar() != null) editor.toolbar().activate(DebugToolbar.DEBUG); // after prepareRun, since this removes highlights try { @@ -236,9 +236,11 @@ public class Debugger implements VMEventListener { } stopTrackingLineChanges(); started = false; - editor.toolbar().deactivate(DebugToolbar.DEBUG); - editor.toolbar().deactivate(DebugToolbar.CONTINUE); - editor.toolbar().deactivate(DebugToolbar.STEP); + if(editor.toolbar() != null){ + editor.toolbar().deactivate(DebugToolbar.DEBUG); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + editor.toolbar().deactivate(DebugToolbar.STEP); + } editor.statusEmpty(); } @@ -246,7 +248,8 @@ public class Debugger implements VMEventListener { * Resume paused debugging session. Resumes VM. */ public synchronized void continueDebug() { - editor.toolbar().activate(DebugToolbar.CONTINUE); + if(editor.toolbar() != null) + editor.toolbar().activate(DebugToolbar.CONTINUE); editor.variableInspector().lock(); //editor.clearSelection(); //clearHighlight(); @@ -271,7 +274,8 @@ public class Debugger implements VMEventListener { startDebug(); } else if (isPaused()) { editor.variableInspector().lock(); - editor.toolbar().activate(DebugToolbar.STEP); + if(editor.toolbar() != null) + editor.toolbar().activate(DebugToolbar.STEP); // use global to mark that there is a step request pending requestedStep = runtime.vm().eventRequestManager().createStepRequest(currentThread, StepRequest.STEP_LINE, stepDepth); @@ -588,8 +592,10 @@ public class Debugger implements VMEventListener { @Override public void run() { editor.setCurrentLine(newCurrentLine); - editor.toolbar().deactivate(DebugToolbar.STEP); - editor.toolbar().deactivate(DebugToolbar.CONTINUE); + if(editor.toolbar() != null){ + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + } } }); @@ -616,8 +622,10 @@ public class Debugger implements VMEventListener { @Override public void run() { editor.setCurrentLine(newCurrentLine); - editor.toolbar().deactivate(DebugToolbar.STEP); - editor.toolbar().deactivate(DebugToolbar.CONTINUE); + if(editor.toolbar() != null){ + editor.toolbar().deactivate(DebugToolbar.STEP); + editor.toolbar().deactivate(DebugToolbar.CONTINUE); + } } }); From 0ab94f58df04f43275b7740f230c8316d83bc6f3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 20:44:48 +0530 Subject: [PATCH 210/608] well now, that was easy. --- .../mode/experimental/DebugEditor.java | 28 +++++++++++++++++-- .../mode/experimental/DebugToolbar.java | 12 ++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index fc3d8ee6b..bf2f464ea 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -21,6 +21,7 @@ import static processing.mode.experimental.ExperimentalMode.log; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; +import java.awt.Component; import java.awt.EventQueue; import java.awt.Frame; import java.awt.event.ActionEvent; @@ -42,6 +43,7 @@ import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -403,15 +405,36 @@ public class DebugEditor extends JavaEditor implements ActionListener { boolean debugToolbarShown = false; protected EditorToolbar javaToolbar, debugToolbar; + protected void switchToolbars(){ + final EditorToolbar nextToolbar; if(debugToolbarShown){ // switch to java + if(javaToolbar == null) + javaToolbar = createToolbar(); + nextToolbar = javaToolbar; + debugToolbarShown = false; + log("Switching to Java Mode Toolbar"); } else{ // switch to debug if(debugToolbar == null) debugToolbar = new DebugToolbar(this, getBase()); + nextToolbar = debugToolbar; + debugToolbarShown = true; + log("Switching to Debugger Toolbar"); } + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Box upper = (Box)splitPane.getComponent(0); + upper.remove(0); + upper.add(nextToolbar, 0); + upper.validate(); + nextToolbar.repaint(); + toolbar = nextToolbar; + } + }); } /** @@ -425,10 +448,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem("Show Debug Toolbar"); toggleDebugger.setSelected(false); - toggleDebugger.addActionListener(new ActionListener() { - + toggleDebugger.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - + switchToolbars(); } }); debugMenu.add(toggleDebugger); diff --git a/pdex/src/processing/mode/experimental/DebugToolbar.java b/pdex/src/processing/mode/experimental/DebugToolbar.java index 67af28774..c9616e179 100755 --- a/pdex/src/processing/mode/experimental/DebugToolbar.java +++ b/pdex/src/processing/mode/experimental/DebugToolbar.java @@ -68,7 +68,7 @@ public class DebugToolbar extends JavaToolbar { public DebugToolbar(Editor editor, Base base) { super(editor, base); } - public Image[][] loadImages() { + public Image[][] loadDebugImages() { int res = Toolkit.highResDisplay() ? 2 : 1; String suffix = null; @@ -91,16 +91,16 @@ public class DebugToolbar extends JavaToolbar { allButtons = mode.loadImage("theme/buttons-debug" + suffix); } } + + // The following three final fields were not accessible, so just copied the values here + // for the time being. TODO: inform Ben, make these fields public /** Width of each toolbar button. */ final int BUTTON_WIDTH = 27; - /** Height of each toolbar button. */ -// static final int BUTTON_HEIGHT = 32; - /** The amount of space between groups of buttons on the toolbar. */ - final int BUTTON_GAP = 5; /** Size (both width and height) of the buttons in the source image. */ final int BUTTON_IMAGE_SIZE = 33; int count = allButtons.getWidth(this) / BUTTON_WIDTH*res; final int GRID_SIZE = 32; + Image[][] buttonImages = new Image[count][3]; for (int i = 0; i < count; i++) { @@ -123,7 +123,7 @@ public class DebugToolbar extends JavaToolbar { */ @Override public void init() { - Image[][] images = loadImages(); + Image[][] images = loadDebugImages(); for (int idx = 0; idx < buttonSequence.length; idx++) { int id = buttonId(idx); addButton(getTitle(id, false), getTitle(id, true), images[idx], id == NEW || id == TOGGLE_BREAKPOINT); From 8b8504d4f4fee93406208b27fd0f0b6d31df0ebf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 21:06:10 +0530 Subject: [PATCH 211/608] updating keylistener too --- .../processing/mode/experimental/DebugEditor.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index bf2f464ea..bf62fa78d 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -27,6 +27,7 @@ import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -433,6 +434,17 @@ public class DebugEditor extends JavaEditor implements ActionListener { upper.validate(); nextToolbar.repaint(); toolbar = nextToolbar; + // The toolbar responds to shift down/up events + // in order to show the alt version of toolbar buttons. + // With toolbar switch, KeyListener has to be changed as well + for (KeyListener kl : textarea.getKeyListeners()) { + if(kl instanceof EditorToolbar) + { + textarea.removeKeyListener(kl); + textarea.addKeyListener(toolbar); + break; + } + } } }); } From e961d882b9d39b32bdfcaee9f0f9bc0dfc088738 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 25 Aug 2013 21:32:44 +0530 Subject: [PATCH 212/608] forgot to add the images --- pdex/src/processing/mode/experimental/ASTGenerator.java | 3 ++- pdex/src/processing/mode/experimental/ExperimentalMode.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ba6e3301e..f933ba106 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -154,7 +154,8 @@ public class ASTGenerator { this.editor = ecs.getEditor(); setupGUI(); //addCompletionPopupListner(); - addListeners(); loadJavaDoc(); + addListeners(); + //loadJavaDoc(); predictionsEnabled = new AtomicBoolean(true); } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index d5f07395a..db5f793b6 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -46,7 +46,7 @@ public class ExperimentalMode extends JavaMode { public static final boolean VERBOSE_LOGGING = true; //public static final boolean VERBOSE_LOGGING = false; public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes) - public static boolean DEBUG = true; + public static boolean DEBUG = !true; public ExperimentalMode(Base base, File folder) { super(base, folder); From 6e1c6da2c3a6973261a080fe38d9fc5224f89127 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 30 Aug 2013 15:26:33 +0530 Subject: [PATCH 213/608] Adding some pacakages to be ignored by code completion --- .../mode/experimental/ASTGenerator.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index f933ba106..c8ae6795b 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -952,9 +952,10 @@ public class ASTGenerator { matchedClass2 = matchedClass2.replace('/', '.'); String matchedClass = matchedClass2.substring(0, matchedClass2 .length() - 6); - if (ignorableImport(matchedClass2)) - continue; int d = matchedClass.lastIndexOf('.'); + if (ignorableImport(matchedClass2,matchedClass.substring(d + 1))) + continue; + matchedClass = matchedClass.substring(d + 1); candidates .add(new CompletionCandidate(matchedClass, matchedClass @@ -3121,17 +3122,19 @@ public class ASTGenerator { "com.oracle.", "sun.", "sunw.", "com.sun.", "javax.", "sunw.", "org.ietf.", "org.jcp.", "org.omg.", "org.w3c.", "org.xml.", "org.eclipse.", "com.ibm.", "org.netbeans.", "org.jsoup.", "org.junit.", "org.apache.", "antlr." }; - protected boolean ignorableImport(String impName) { + public static final String allowedImports[] = {"java.lang.", "java.util.", "java.io.", + "java.math.", "processing.core.", "processing.data.", "processing.event.", "processing.opengl."}; + protected boolean ignorableImport(String impName, String className) { //TODO: Trie man. for (ImportStatement impS : errorCheckerService.getProgramImports()) { if(impName.startsWith(impS.getPackageName())) return false; } - for (String impS : ignoredImports) { - if(impName.startsWith(impS)) - return true; + for (String impS : allowedImports) { + if(impName.startsWith(impS) && className.indexOf('.') == -1) + return false; } - return false; + return true; } public static boolean isAddableASTNode(ASTNode node) { From 2b82bf2eb4b1b7dde1dc3e362a2ad12347510fdf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 30 Aug 2013 15:30:13 +0530 Subject: [PATCH 214/608] lol, I'd really done this --- pdex/src/processing/mode/experimental/TextArea.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 0d54ecd5c..7c1c5c42d 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -179,13 +179,15 @@ public class TextArea extends JEditTextArea { } super.processKeyEvent(evt); - if (evt.getID() == KeyEvent.KEY_TYPED && editor.errorCheckerService.getASTGenerator().predictionsEnabled.get()) { + if (evt.getID() == KeyEvent.KEY_TYPED) { final KeyEvent evt2 = evt; SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { errorCheckerService.runManualErrorCheck(); - log(" Typing: " + fetchPhrase(evt2) + " " - + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); + // Provide completions only if it's enabled + if(editor.errorCheckerService.getASTGenerator().predictionsEnabled.get()) + log(" Typing: " + fetchPhrase(evt2) + " " + + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); return null; } }; From 6eb903f665c7e7637da0e65fae019789d62383dc Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 1 Sep 2013 20:35:51 +0530 Subject: [PATCH 215/608] renaming mode menu, todo updates --- pdex/Todo, GSoC 2013.txt | 4 ++-- pdex/src/processing/mode/experimental/DebugEditor.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 10415a8ec..ca0338e23 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -42,8 +42,8 @@ Finer details * printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * Diamond operator isn't supported for now. Bummer. -* Icons for completions? Or overkill right now? +x Icons for completions? Or overkill right now? x 'Show Usage' menu item added x Show declaring class for completions x! Ignore String case while finding completion candidates @@ -144,7 +144,7 @@ x boolean warningsEnabled - made it volatile General Stuff ============= -* Ensure all editor windows are closed when editor is closed. +x Ensure all editor windows are closed when editor is closed. x Add a red marker near Errors label in console toggle, to indicate errors present in sketch. x Add option for toggling debug output x On Run/Debug Console is visible(ProblemsList hidden) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index bf62fa78d..a2f07efbe 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -456,7 +456,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { * @return The debug menu */ protected JMenu buildDebugMenu() { - debugMenu = new JMenu("Debug"); + //debugMenu = new JMenu("Debug"); + debugMenu = new JMenu("PDE X"); JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem("Show Debug Toolbar"); toggleDebugger.setSelected(false); From 4dceb7dda773ca4206f22e06cc6fba399a2529b6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 1 Sep 2013 21:21:05 +0530 Subject: [PATCH 216/608] breakpoint markers hidden when Debugger not active --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/DebugEditor.java | 14 ++++----- .../mode/experimental/TextArea.java | 6 ++++ .../mode/experimental/TextAreaPainter.java | 29 +++++++++---------- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index ca0338e23..0b772dda4 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -144,6 +144,7 @@ x boolean warningsEnabled - made it volatile General Stuff ============= +x Hide breakpoint markers when Debugger isn't active x Ensure all editor windows are closed when editor is closed. x Add a red marker near Errors label in console toggle, to indicate errors present in sketch. x Add option for toggling debug output diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index a2f07efbe..663b27896 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -239,9 +240,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { initializeErrorChecker(); ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); - //TODO: Remove this later - if(ExperimentalMode.DEBUG) - setBounds(160, 300, getWidth(), getHeight()); + debugToolbarEnabled = new AtomicBoolean(false); } private void addXQModeUI(){ @@ -404,17 +403,17 @@ public class DebugEditor extends JavaEditor implements ActionListener { return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); }*/ - boolean debugToolbarShown = false; + AtomicBoolean debugToolbarEnabled; protected EditorToolbar javaToolbar, debugToolbar; protected void switchToolbars(){ final EditorToolbar nextToolbar; - if(debugToolbarShown){ + if(debugToolbarEnabled.get()){ // switch to java if(javaToolbar == null) javaToolbar = createToolbar(); nextToolbar = javaToolbar; - debugToolbarShown = false; + debugToolbarEnabled.set(false); log("Switching to Java Mode Toolbar"); } else{ @@ -422,7 +421,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { if(debugToolbar == null) debugToolbar = new DebugToolbar(this, getBase()); nextToolbar = debugToolbar; - debugToolbarShown = true; + debugToolbarEnabled.set(true); log("Switching to Debugger Toolbar"); } @@ -445,6 +444,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { break; } } + ta.repaint(); } }); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 7c1c5c42d..77e26b5cc 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -396,6 +396,9 @@ public class TextArea extends JEditTextArea { * @return gutter width in pixels */ protected int getGutterWidth() { + if(editor.debugToolbarEnabled == null || !editor.debugToolbarEnabled.get()){ + return 0; + } FontMetrics fm = painter.getFontMetrics(); // log("fm: " + (fm == null)); // log("editor: " + (editor == null)); @@ -413,6 +416,9 @@ public class TextArea extends JEditTextArea { * @return margins in pixels */ protected int getGutterMargins() { + if(editor.debugToolbarEnabled == null || !editor.debugToolbarEnabled.get()){ + return 0; + } return gutterPadding; } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 382501202..07c04ab61 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -172,19 +172,19 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { @Override protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, int x) { - - // paint gutter - paintGutterBg(gfx, line, x); - - paintLineBgColor(gfx, line, x + ta.getGutterWidth()); - - paintGutterLine(gfx, line, x); - - // paint gutter symbol - paintGutterText(gfx, line, x); - + if(ta.editor.debugToolbarEnabled != null && ta.editor.debugToolbarEnabled.get()){ + // paint gutter + paintGutterBg(gfx, line, x); + + paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + + paintGutterLine(gfx, line, x); + + // paint gutter symbol + paintGutterText(gfx, line, x); + } + paintErrorLine(gfx, line, x); - super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); } @@ -296,7 +296,6 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { * @param x */ protected void paintErrorLine(Graphics gfx, int line, int x) { - if (errorCheckerService == null) { return; } @@ -354,8 +353,8 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { int rw = fm.stringWidth(linetext.trim()); // real width int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw; // Adding offsets for the gutter - x1 += 20; - x2 += 20; + x1 += ta.getGutterWidth(); + x2 += ta.getGutterWidth(); // gfx.fillRect(x1, y, rw, height); From df69195be74e950649ea3a225f8731304616b05a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 15 Sep 2013 02:42:47 +0530 Subject: [PATCH 217/608] prediction length added --- pdex/src/processing/mode/experimental/ASTGenerator.java | 4 +++- pdex/src/processing/mode/experimental/TextArea.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index c8ae6795b..ede894eca 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -780,9 +780,11 @@ public class ASTGenerator { protected ArrayList candidates; protected String lastPredictedWord = " "; protected AtomicBoolean predictionsEnabled; + protected int predictionMinLength = 3; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { if(!predictionsEnabled.get()) return; + if(word.length() < predictionMinLength) return; // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance // in TextArea.processKeyEvent if(caretWithinLineComment()){ @@ -809,7 +811,7 @@ public class ASTGenerator { noCompare = true; } - if (word2.length() > 2 && !noCompare + if (word2.length() >= predictionMinLength && !noCompare && word2.length() > lastPredictedWord.length()) { if (word2.startsWith(lastPredictedWord)) { log(word + " starts with " + lastPredictedWord); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 77e26b5cc..6b2dd7a19 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -303,7 +303,7 @@ public class TextArea extends JEditTextArea { word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); - if(word.length() > 1) + errorCheckerService.getASTGenerator().preparePredictions(word, line + errorCheckerService.mainClassOffset,0); return word; From 307051dfb0c415586d431dc59049614ce88dafa6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 15 Sep 2013 03:18:03 +0530 Subject: [PATCH 218/608] todo updates --- pdex/Todo, GSoC 2013.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 0b772dda4..a22e4c02f 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -16,6 +16,7 @@ The big stuff: - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) * After popup appears, the popup location is fixed for the current line. So if editor window is moved while staying in the same line, popup appears at the prev location. Need to ensure editor is still at last know location +* Keyboard Shortcut for completion popup - Ctrl + Space * Scope handling? Static/non static scope? * Disable completions on comment line * Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. @@ -144,7 +145,9 @@ x boolean warningsEnabled - made it volatile General Stuff ============= +* Consult Ben on where to save preferences - main preferences.txt or custom one x Hide breakpoint markers when Debugger isn't active +x Ensure gutter mouse handler is taken care of when hiding Debugger breakpoint bar. x Ensure all editor windows are closed when editor is closed. x Add a red marker near Errors label in console toggle, to indicate errors present in sketch. x Add option for toggling debug output From 69405772a8cd0f4ebad7f0a42fe785c635b67323 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 15 Sep 2013 21:14:45 +0530 Subject: [PATCH 219/608] prefs work --- .../mode/experimental/ASTGenerator.java | 4 +- .../mode/experimental/DebugEditor.java | 20 +++++----- .../experimental/ErrorCheckerService.java | 7 +--- .../mode/experimental/ExperimentalMode.java | 39 +++++++++++++++++++ .../mode/experimental/TextArea.java | 1 - 5 files changed, 51 insertions(+), 20 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ede894eca..b0a47eb88 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -779,11 +779,11 @@ public class ASTGenerator { */ protected ArrayList candidates; protected String lastPredictedWord = " "; - protected AtomicBoolean predictionsEnabled; + //protected AtomicBoolean predictionsEnabled; protected int predictionMinLength = 3; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { - if(!predictionsEnabled.get()) return; + if(!ExperimentalMode.codeCompletionsEnabled) return; if(word.length() < predictionMinLength) return; // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance // in TextArea.processKeyEvent diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 663b27896..23d42fae9 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -326,12 +326,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ - if(enableErrorLogging) writeErrorsToFile(); + if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); super.internalCloseRunner(); } - protected boolean enableErrorLogging = false; - private void writeErrorsToFile(){ if (errorCheckerService.tempErrorLog.size() == 0) return; @@ -525,12 +523,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { JCheckBoxMenuItem item; final DebugEditor thisEditor = this; item = new JCheckBoxMenuItem("Error Checker Enabled"); - item.setSelected(true); + item.setSelected(ExperimentalMode.errorCheckEnabled); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - + ExperimentalMode.errorCheckEnabled = ((JCheckBoxMenuItem) e.getSource()).isSelected(); if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { // unticked Menu Item errorCheckerService.pauseThread(); @@ -571,12 +569,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { debugMenu.add(problemWindowMenuCB); showWarnings = new JCheckBoxMenuItem("Warnings Enabled"); - showWarnings.setSelected(true); + showWarnings.setSelected(ExperimentalMode.warningsEnabled); showWarnings.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - errorCheckerService.warningsEnabled = ((JCheckBoxMenuItem) e + ExperimentalMode.warningsEnabled = ((JCheckBoxMenuItem) e .getSource()).isSelected(); errorCheckerService.runManualErrorCheck(); } @@ -588,8 +586,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { completionsEnabled.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - errorCheckerService.getASTGenerator().predictionsEnabled - .set(((JCheckBoxMenuItem) e.getSource()).isSelected()); + ExperimentalMode.codeCompletionsEnabled = (((JCheckBoxMenuItem) e + .getSource()).isSelected()); } }); debugMenu.add(completionsEnabled); @@ -610,11 +608,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { debugMenu.add(showOutline); writeErrorLog = new JCheckBoxMenuItem("Write Errors to Log"); - writeErrorLog.setSelected(enableErrorLogging); + writeErrorLog.setSelected(ExperimentalMode.errorLogsEnabled); writeErrorLog.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - enableErrorLogging = !enableErrorLogging; + ExperimentalMode.errorLogsEnabled = !ExperimentalMode.errorLogsEnabled; } }); debugMenu.add(writeErrorLog); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 94baf0ede..7ca5ba89f 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -559,7 +559,7 @@ public class ErrorCheckerService implements Runnable{ } // If warnings are disabled, skip 'em - if (p.isWarning() && !warningsEnabled) { + if (p.isWarning() && !ExperimentalMode.warningsEnabled) { continue; } problemsList.add(p); @@ -724,11 +724,6 @@ public class ErrorCheckerService implements Runnable{ @SuppressWarnings("rawtypes") protected Map compilerSettings; - /** - * Enable/Disable warnings from being shown - */ - volatile public boolean warningsEnabled = true; - /** * Sets compiler options for JDT Compiler */ diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index db5f793b6..b530782fb 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -35,6 +35,7 @@ import processing.app.Base; import processing.app.Editor; import processing.app.EditorState; import processing.app.Mode; +import processing.app.Preferences; import processing.mode.java.JavaMode; @@ -114,6 +115,44 @@ public class ExperimentalMode extends JavaMode { Base.getContentFile("modes/java/keywords.txt") }; } + + volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, + codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; + + public final String prefErrorCheck = "pdex.errorCheckEnabled", + prefWarnings = "pdex.warningsEnabled", + prefCodeCompletionEnabled = "pdex.ccEnabled", + prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs"; + + public void loadPreferences(){ + ensurePrefsExist(); + errorCheckEnabled = Preferences.getBoolean(prefErrorCheck); + warningsEnabled = Preferences.getBoolean(prefWarnings); + codeCompletionsEnabled = Preferences.getBoolean(prefCodeCompletionEnabled); + debugOutputEnabled = Preferences.getBoolean(prefDebugOP); + errorCheckEnabled = Preferences.getBoolean(prefErrorLogs); + } + + public void savePreferences(){ + Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); + Preferences.setBoolean(prefWarnings, warningsEnabled); + Preferences.setBoolean(prefCodeCompletionEnabled, codeCompletionsEnabled); + Preferences.setBoolean(prefDebugOP, debugOutputEnabled); + Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); + } + + public void ensurePrefsExist(){ + if(Preferences.get(prefErrorCheck) == null) + Preferences.setBoolean(prefErrorCheck,errorCheckEnabled); + if(Preferences.get(prefWarnings) == null) + Preferences.setBoolean(prefWarnings,warningsEnabled); + if(Preferences.get(prefCodeCompletionEnabled) == null) + Preferences.setBoolean(prefCodeCompletionEnabled,codeCompletionsEnabled); + if(Preferences.get(prefDebugOP) == null) + Preferences.setBoolean(prefDebugOP,debugOutputEnabled); + if(Preferences.get(prefErrorLogs) == null) + Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); + } /** diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 6b2dd7a19..4a083e60c 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -185,7 +185,6 @@ public class TextArea extends JEditTextArea { protected Object doInBackground() throws Exception { errorCheckerService.runManualErrorCheck(); // Provide completions only if it's enabled - if(editor.errorCheckerService.getASTGenerator().predictionsEnabled.get()) log(" Typing: " + fetchPhrase(evt2) + " " + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); return null; From 96c4fc18460812bda7bea63aabb67b3f06a39414 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 15 Sep 2013 21:56:02 +0530 Subject: [PATCH 220/608] pde x prefs now saved to the main preferences.txt --- pdex/Todo, GSoC 2013.txt | 3 ++- .../mode/experimental/ASTGenerator.java | 1 - .../mode/experimental/DebugEditor.java | 25 ++++--------------- .../experimental/ErrorCheckerService.java | 22 ++++++++++++++++ .../mode/experimental/ExperimentalMode.java | 11 +++++--- .../mode/experimental/TextArea.java | 1 + 6 files changed, 37 insertions(+), 26 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index a22e4c02f..94f0d757f 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -145,7 +145,8 @@ x boolean warningsEnabled - made it volatile General Stuff ============= -* Consult Ben on where to save preferences - main preferences.txt or custom one +x Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file +x Save preferences to main preference.txt x Hide breakpoint markers when Debugger isn't active x Ensure gutter mouse handler is taken care of when hiding Debugger breakpoint bar. x Ensure all editor windows are closed when editor is closed. diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b0a47eb88..62b4e908a 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -156,7 +156,6 @@ public class ASTGenerator { //addCompletionPopupListner(); addListeners(); //loadJavaDoc(); - predictionsEnabled = new AtomicBoolean(true); } protected void setupGUI(){ diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 23d42fae9..af738e75e 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -326,6 +326,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ + dmode.savePreferences(); if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); super.internalCloseRunner(); } @@ -521,7 +522,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { // XQMode menu items JCheckBoxMenuItem item; - final DebugEditor thisEditor = this; item = new JCheckBoxMenuItem("Error Checker Enabled"); item.setSelected(ExperimentalMode.errorCheckEnabled); item.addActionListener(new ActionListener() { @@ -529,23 +529,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { @Override public void actionPerformed(ActionEvent e) { ExperimentalMode.errorCheckEnabled = ((JCheckBoxMenuItem) e.getSource()).isSelected(); - if (!((JCheckBoxMenuItem) e.getSource()).isSelected()) { - // unticked Menu Item - errorCheckerService.pauseThread(); - System.out.println(thisEditor.getSketch().getName() - + " - Error Checker paused."); - errorBar.errorPoints.clear(); - errorCheckerService.problemsList.clear(); - errorCheckerService.updateErrorTable(); - errorCheckerService.updateEditorStatus(); - getTextArea().repaint(); - errorBar.repaint(); - } else { - errorCheckerService.resumeThread(); - System.out.println(thisEditor.getSketch().getName() - + " - Error Checker resumed."); - errorCheckerService.runManualErrorCheck(); - } + errorCheckerService.handleErrorCheckingToggle(); } }); debugMenu.add(item); @@ -582,7 +566,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { debugMenu.add(showWarnings); completionsEnabled = new JCheckBoxMenuItem("Code Completion Enabled"); - completionsEnabled.setSelected(true); + completionsEnabled.setSelected(ExperimentalMode.codeCompletionsEnabled); completionsEnabled.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -612,7 +596,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { writeErrorLog.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ExperimentalMode.errorLogsEnabled = !ExperimentalMode.errorLogsEnabled; + ExperimentalMode.errorLogsEnabled = ((JCheckBoxMenuItem) e + .getSource()).isSelected(); } }); debugMenu.add(writeErrorLog); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 7ca5ba89f..34a0e302f 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -19,6 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.swing.JCheckBoxMenuItem; import javax.swing.table.DefaultTableModel; import org.eclipse.jdt.core.JavaCore; @@ -262,6 +263,7 @@ public class ErrorCheckerService implements Runnable{ // Completion wouldn't be complete, but it'd be still something // better than nothing astGenerator.buildAST(cu); + handleErrorCheckingToggle(); while (!stopThread.get()) { try { // Take a nap. @@ -1399,6 +1401,26 @@ public class ErrorCheckerService implements Runnable{ return new String(p2, 0, index); } + public void handleErrorCheckingToggle(){ + if (!ExperimentalMode.errorCheckEnabled) { + // unticked Menu Item + pauseThread(); + log(editor.getSketch().getName() + + " - Error Checker paused."); + editor.errorBar.errorPoints.clear(); + problemsList.clear(); + updateErrorTable(); + updateEditorStatus(); + editor.getTextArea().repaint(); + editor.errorBar.repaint(); + } else { + resumeThread(); + log(editor.getSketch().getName() + + " - Error Checker resumed."); + runManualErrorCheck(); + } + } + /** * Stops the Error Checker Service thread */ diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index b530782fb..9417f94c0 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -100,6 +100,7 @@ public class ExperimentalMode extends JavaMode { // String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")"; // //log(titleAndVersion); // Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion); + loadPreferences(); loadIcons(); } @@ -125,19 +126,21 @@ public class ExperimentalMode extends JavaMode { prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs"; public void loadPreferences(){ + log("Load PDEX prefs"); ensurePrefsExist(); errorCheckEnabled = Preferences.getBoolean(prefErrorCheck); warningsEnabled = Preferences.getBoolean(prefWarnings); codeCompletionsEnabled = Preferences.getBoolean(prefCodeCompletionEnabled); - debugOutputEnabled = Preferences.getBoolean(prefDebugOP); - errorCheckEnabled = Preferences.getBoolean(prefErrorLogs); + DEBUG = Preferences.getBoolean(prefDebugOP); + errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); } public void savePreferences(){ + log("Saving PDEX prefs"); Preferences.setBoolean(prefErrorCheck, errorCheckEnabled); Preferences.setBoolean(prefWarnings, warningsEnabled); Preferences.setBoolean(prefCodeCompletionEnabled, codeCompletionsEnabled); - Preferences.setBoolean(prefDebugOP, debugOutputEnabled); + Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); } @@ -149,7 +152,7 @@ public class ExperimentalMode extends JavaMode { if(Preferences.get(prefCodeCompletionEnabled) == null) Preferences.setBoolean(prefCodeCompletionEnabled,codeCompletionsEnabled); if(Preferences.get(prefDebugOP) == null) - Preferences.setBoolean(prefDebugOP,debugOutputEnabled); + Preferences.setBoolean(prefDebugOP,DEBUG); if(Preferences.get(prefErrorLogs) == null) Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 4a083e60c..beb084683 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -185,6 +185,7 @@ public class TextArea extends JEditTextArea { protected Object doInBackground() throws Exception { errorCheckerService.runManualErrorCheck(); // Provide completions only if it's enabled + if(ExperimentalMode.codeCompletionsEnabled) log(" Typing: " + fetchPhrase(evt2) + " " + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); return null; From 919015c22aab20c97852a5ec5747168a7d386dfd Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 16 Sep 2013 21:01:59 +0530 Subject: [PATCH 221/608] this should get rid of the TA paint line errors, hopefully --- .../processing/mode/experimental/TextAreaPainter.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 07c04ab61..aab49e9ba 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -182,10 +182,14 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // paint gutter symbol paintGutterText(gfx, line, x); + + paintErrorLine(gfx, line, x); + super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); + } + else { + paintErrorLine(gfx, line, x); + super.paintLine(gfx, tokenMarker, line, x); } - - paintErrorLine(gfx, line, x); - super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); } /** From 495ed6856b30705cece2d18a9fd78013c33ce7a4 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 16 Sep 2013 21:16:09 +0530 Subject: [PATCH 222/608] completion list now hidden on hitting space --- .../mode/experimental/CompletionPanel.java | 6 ++-- .../mode/experimental/TextArea.java | 33 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index ff2b7384a..a8f44d190 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -84,7 +84,7 @@ public class CompletionPanel { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { insertSelection(); - hideSuggestion(); + hide(); } } }); @@ -137,12 +137,12 @@ public class CompletionPanel { } catch (BadLocationException e1) { e1.printStackTrace(); } - hideSuggestion(); + hide(); } return false; } - public void hideSuggestion() { + public void hide() { popupMenu.setVisible(false); log("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.getASTGenerator().jdocWindowVisible(false); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index beb084683..940267395 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -173,11 +173,18 @@ public class TextArea extends JEditTextArea { case KeyEvent.VK_BACK_SPACE: log("BK Key"); break; + case KeyEvent.VK_SPACE: + if (suggestion != null) + if (suggestion.isVisible()) { + log("Space bar, hide completion list"); + suggestion.hide(); + } + break; default: break; } } - super.processKeyEvent(evt); + super.processKeyEvent(evt); if (evt.getID() == KeyEvent.KEY_TYPED) { final KeyEvent evt2 = evt; @@ -259,20 +266,14 @@ public class TextArea extends JEditTextArea { } } private String fetchPhrase(KeyEvent evt) { - if (evt != null) { - char keyChar = evt.getKeyChar(); - if (keyChar == KeyEvent.VK_ENTER) { - //log("Enter keypress."); - return null; - } -// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) -// ; // accepted these keys - else if (keyChar == KeyEvent.VK_ESCAPE) { - //log("ESC keypress. fetchPhrase()"); - return null; - } else if (keyChar == KeyEvent.VK_TAB || keyChar == KeyEvent.CHAR_UNDEFINED) { - return null; - } + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_ENTER) { + return null; + } else if (keyChar == KeyEvent.VK_ESCAPE) { + return null; + } else if (keyChar == KeyEvent.VK_SPACE || keyChar == KeyEvent.VK_TAB + || keyChar == KeyEvent.CHAR_UNDEFINED) { + return null; } int off = getCaretPosition(); log2("off " + off); @@ -741,7 +742,7 @@ public class TextArea extends JEditTextArea { private void hideSuggestion() { if (suggestion != null) { - suggestion.hideSuggestion(); + suggestion.hide(); suggestion = null; } } From 4fce0cad014013b84f1c961ea1c84d34c90d004e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 16 Sep 2013 21:21:25 +0530 Subject: [PATCH 223/608] also hide completions when ctrl or other modifiers pressed --- .../mode/experimental/TextArea.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 940267395..38f891dc4 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -187,7 +187,18 @@ public class TextArea extends JEditTextArea { super.processKeyEvent(evt); if (evt.getID() == KeyEvent.KEY_TYPED) { - final KeyEvent evt2 = evt; + + char keyChar = evt.getKeyChar(); + if (keyChar == KeyEvent.VK_ENTER || keyChar == KeyEvent.VK_ESCAPE) { + return; + } else if (keyChar == KeyEvent.VK_SPACE || keyChar == KeyEvent.VK_TAB + || keyChar == KeyEvent.CHAR_UNDEFINED) { + return; + } + if(evt.isAltDown() || evt.isControlDown() || evt.isMetaDown()){ + return; + } + final KeyEvent evt2 = evt; SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { errorCheckerService.runManualErrorCheck(); @@ -266,15 +277,7 @@ public class TextArea extends JEditTextArea { } } private String fetchPhrase(KeyEvent evt) { - char keyChar = evt.getKeyChar(); - if (keyChar == KeyEvent.VK_ENTER) { - return null; - } else if (keyChar == KeyEvent.VK_ESCAPE) { - return null; - } else if (keyChar == KeyEvent.VK_SPACE || keyChar == KeyEvent.VK_TAB - || keyChar == KeyEvent.CHAR_UNDEFINED) { - return null; - } + int off = getCaretPosition(); log2("off " + off); if (off < 0) From 82a3bfc6e695cbc9ac39dbe0df6a1aa7d0720c44 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 16 Sep 2013 21:35:40 +0530 Subject: [PATCH 224/608] completion screen location update bug fix --- pdex/src/processing/mode/experimental/ASTGenerator.java | 2 +- pdex/src/processing/mode/experimental/CompletionPanel.java | 4 ++-- pdex/src/processing/mode/experimental/TextArea.java | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 62b4e908a..c563c43fb 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -779,7 +779,7 @@ public class ASTGenerator { protected ArrayList candidates; protected String lastPredictedWord = " "; //protected AtomicBoolean predictionsEnabled; - protected int predictionMinLength = 3; + protected int predictionMinLength = 2; public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { if(!ExperimentalMode.codeCompletionsEnabled) return; diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index a8f44d190..6e1f36e61 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -92,7 +92,7 @@ public class CompletionPanel { return list; } - public boolean updateList(final DefaultListModel items, String newSubword, int position){ + public boolean updateList(final DefaultListModel items, String newSubword, Point location, int position){ scrollPane.getViewport().removeAll(); Dimension dimen = popupMenu.getSize(); completionList.setModel(items); @@ -101,7 +101,7 @@ public class CompletionPanel { scrollPane.setViewportView(completionList); scrollPane.validate(); popupMenu.setSize(dimen); - + popupMenu.setLocation(location); this.subWord = new String(newSubword); if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 38f891dc4..9183d9855 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -720,6 +720,7 @@ public class TextArea extends JEditTextArea { - getLineStartOffset(getCaretLine())); location.y = lineToY(getCaretLine()) + getPainter().getFontMetrics().getHeight(); + log("TA position: " + location); } catch (Exception e2) { e2.printStackTrace(); return; @@ -732,7 +733,9 @@ public class TextArea extends JEditTextArea { suggestion = new CompletionPanel(this, position, subWord, defListModel, location,editor); else - suggestion.updateList(defListModel, subWord, position); + suggestion.updateList(defListModel, subWord, + new Point(getLocationOnScreen().x + location.x, + getLocationOnScreen().y + location.y), position); suggestion.setVisible(true); // requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { From 46d74909c24d02b2befe19bf606b2e284aaddba7 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 16 Sep 2013 21:39:42 +0530 Subject: [PATCH 225/608] use show() instead --- pdex/src/processing/mode/experimental/CompletionPanel.java | 4 +++- pdex/src/processing/mode/experimental/TextArea.java | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 6e1f36e61..39ce00d58 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -101,12 +101,14 @@ public class CompletionPanel { scrollPane.setViewportView(completionList); scrollPane.validate(); popupMenu.setSize(dimen); - popupMenu.setLocation(location); + //popupMenu.setLocation(location); this.subWord = new String(newSubword); if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); insertionPosition = position; log("Suggestion updated" + System.nanoTime()); + popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + + location.y); return true; } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 9183d9855..806e61389 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -733,9 +733,8 @@ public class TextArea extends JEditTextArea { suggestion = new CompletionPanel(this, position, subWord, defListModel, location,editor); else - suggestion.updateList(defListModel, subWord, - new Point(getLocationOnScreen().x + location.x, - getLocationOnScreen().y + location.y), position); + suggestion.updateList(defListModel, subWord, location, position); + suggestion.setVisible(true); // requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { From 60bf5cf41d2d357af481613811192938c97a71dd Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 01:02:14 +0530 Subject: [PATCH 226/608] giving up and adding try catch block. --- pdex/Todo, GSoC 2013.txt | 2 +- .../processing/mode/experimental/TextAreaPainter.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 94f0d757f..2079b1b75 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -15,7 +15,7 @@ The big stuff: - Making very good progress here. The elegance of recurion - Hats off! - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) -* After popup appears, the popup location is fixed for the current line. So if editor window is moved while staying in the same line, popup appears at the prev location. Need to ensure editor is still at last know location +x After popup appears, the popup location is fixed for the current line. So if editor window is moved while staying in the same line, popup appears at the prev location. Need to ensure editor is still at last know location. Fixed. * Keyboard Shortcut for completion popup - Ctrl + Space * Scope handling? Static/non static scope? * Disable completions on comment line diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index aab49e9ba..065fcbf8e 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -183,12 +183,14 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // paint gutter symbol paintGutterText(gfx, line, x); - paintErrorLine(gfx, line, x); - super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); } - else { - paintErrorLine(gfx, line, x); + paintErrorLine(gfx, line, x); + try { + //TODO: This line is causing NPE's randomly ever since I added the toggle for + //Java Mode/Debugger toolbar. super.paintLine(gfx, tokenMarker, line, x); + } catch (NullPointerException e) { + log(e.getMessage()); } } From d67bcf0bf4387e7b71e8013ff43964ea8762a49e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 01:18:10 +0530 Subject: [PATCH 227/608] updated version. --- pdex/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/build.properties b/pdex/build.properties index bdda74bb2..656dbd7c9 100644 --- a/pdex/build.properties +++ b/pdex/build.properties @@ -6,4 +6,4 @@ java.target.version=1.6 lib.name=ExperimentalMode dist=dist release=3 -prettyVersion=1.1.1 +prettyVersion=1.0.0b From 79b85b8c9a5f7de227bbfad6cc981633fa5ef257 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 04:53:21 +0530 Subject: [PATCH 228/608] another shot at paintLine bug, adding keywords.txt --- pdex/build.xml | 3 + pdex/keywords.txt | 890 ++++++++++++++++++ .../mode/experimental/TextArea.java | 14 +- .../mode/experimental/TextAreaPainter.java | 4 +- 4 files changed, 902 insertions(+), 9 deletions(-) create mode 100644 pdex/keywords.txt diff --git a/pdex/build.xml b/pdex/build.xml index 1f06d8b14..a3988d3a6 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -85,6 +85,9 @@ + + + diff --git a/pdex/keywords.txt b/pdex/keywords.txt new file mode 100644 index 000000000..5ba33d3ab --- /dev/null +++ b/pdex/keywords.txt @@ -0,0 +1,890 @@ +# For an explanation of these tags, see Token.java +# trunk/processing/app/src/processing/app/syntax/Token.java + +ADD LITERAL2 blend_ +ALIGN_CENTER LITERAL2 +ALIGN_LEFT LITERAL2 +ALIGN_RIGHT LITERAL2 +ALPHA LITERAL2 +ALPHA_MASK LITERAL2 +ALT LITERAL2 +AMBIENT LITERAL2 +ARC LITERAL2 createShape_ +ARROW LITERAL2 cursor_ +ARGB LITERAL2 +BACKSPACE LITERAL2 keyCode +BASELINE LITERAL2 textAlign_ +BEVEL LITERAL2 strokeJoin_ +BLEND LITERAL2 blend_ +BLUE_MASK LITERAL2 +BLUR LITERAL2 filter_ +BOTTOM LITERAL2 textAlign_ +BOX LITERAL2 createShape_ +BURN LITERAL2 blend_ +CENTER LITERAL2 +CHATTER LITERAL2 +CHORD LITERAL2 arc_ +CLAMP LITERAL2 +CLICK LITERAL2 +CLOSE LITERAL2 +CMYK LITERAL2 +CODED LITERAL2 key +COMPLAINT LITERAL2 +COMPOSITE LITERAL2 +COMPONENT LITERAL2 +CONCAVE_POLYGON LITERAL2 +CONTROL LITERAL2 +CONVEX_POLYGON LITERAL2 +CORNER LITERAL2 textAlign_ +CORNERS LITERAL2 +CROSS LITERAL2 cursor_ +CUSTOM LITERAL2 +DARKEST LITERAL2 blend_ +DEGREES LITERAL2 +DEG_TO_RAD LITERAL2 +DELETE LITERAL2 +DIAMETER LITERAL2 +DIFFERENCE LITERAL2 blend_ +DIFFUSE LITERAL2 +DILATE LITERAL2 filter_ +DIRECTIONAL LITERAL2 +DISABLE_ACCURATE_2D LITERAL2 +DISABLE_DEPTH_MASK LITERAL2 +DISABLE_DEPTH_SORT LITERAL2 +DISABLE_DEPTH_TEST LITERAL2 +DISABLE_NATIVE_FONTS LITERAL2 +DISABLE_OPENGL_ERRORS LITERAL2 +DISABLE_PURE_STROKE LITERAL2 +DISABLE_TEXTURE_MIPMAPS LITERAL2 +DISABLE_TRANSFORM_CACHE LITERAL2 +DISABLE_STROKE_PERSPECTIVE LITERAL2 +DISABLED LITERAL2 +DODGE LITERAL2 blend_ +DOWN LITERAL2 keyCode +DRAG LITERAL2 +DXF LITERAL2 size_ +ELLIPSE LITERAL2 createShape_ +ENABLE_ACCURATE_2D LITERAL2 +ENABLE_DEPTH_MASK LITERAL2 +ENABLE_DEPTH_SORT LITERAL2 +ENABLE_DEPTH_TEST LITERAL2 +ENABLE_NATIVE_FONTS LITERAL2 +ENABLE_OPENGL_ERRORS LITERAL2 +ENABLE_PURE_STROKE LITERAL2 +ENABLE_TEXTURE_MIPMAPS LITERAL2 +ENABLE_TRANSFORM_CACHE LITERAL2 +ENABLE_STROKE_PERSPECTIVE LITERAL2 +ENTER LITERAL2 keyCode +EPSILON LITERAL2 +ERODE LITERAL2 filter_ +ESC LITERAL2 keyCode +EXCLUSION LITERAL2 blend_ +EXIT LITERAL2 +GIF LITERAL2 +GRAY LITERAL2 filter_ +GREEN_MASK LITERAL2 +GROUP LITERAL2 +HALF LITERAL2 +HALF_PI LITERAL2 HALF_PI +HAND LITERAL2 cursor_ +HARD_LIGHT LITERAL2 blend_ +HINT_COUNT LITERAL2 +HSB LITERAL2 colorMode_ +IMAGE LITERAL2 textureMode_ +INVERT LITERAL2 filter_ +JPEG LITERAL2 +LEFT LITERAL2 keyCode +LIGHTEST LITERAL2 blend_ +LINE LITERAL2 createShape_ +LINES LITERAL2 beginShape_ +LINUX LITERAL2 +MACOSX LITERAL2 +MAX_FLOAT LITERAL2 +MAX_INT LITERAL2 +MIN_FLOAT LITERAL2 +MIN_INT LITERAL2 +MITER LITERAL2 stokeJoin_ +MODEL LITERAL2 textMode_ +MOVE LITERAL2 cursor_ +MULTIPLY LITERAL2 blend_ +NORMAL LITERAL2 +NORMALIZED LITERAL2 textureMode_ +NO_DEPTH_TEST LITERAL2 +NTSC LITERAL2 +ONE LITERAL2 +OPAQUE LITERAL2 filter_ +OPEN LITERAL2 +ORTHOGRAPHIC LITERAL2 +OVERLAY LITERAL2 blend_ +PAL LITERAL2 +PDF LITERAL2 size_ +P2D LITERAL2 size_ +P3D LITERAL2 size_ +PERSPECTIVE LITERAL2 +PI LITERAL2 PI +PIE LITERAL2 +PIXEL_CENTER LITERAL2 +POINT LITERAL2 +POINTS LITERAL2 +POSTERIZE LITERAL2 filter_ +PRESS LITERAL2 +PROBLEM LITERAL2 +PROJECT LITERAL2 strokeCap_ +QUAD LITERAL2 createShape_ +QUAD_STRIP LITERAL2 beginShape_ +QUADS LITERAL2 beginShape_ +QUARTER_PI LITERAL2 QUARTER_PI +RAD_TO_DEG LITERAL2 +RADIUS LITERAL2 +RADIANS LITERAL2 +RECT LITERAL2 +RED_MASK LITERAL2 +RELEASE LITERAL2 +REPEAT LITERAL2 +REPLACE LITERAL2 +RETURN LITERAL2 +RGB LITERAL2 colorMode_ +RIGHT LITERAL2 keyCode +ROUND LITERAL2 strokeCap_ +SCREEN LITERAL2 blend_ +SECAM LITERAL2 +SHAPE LITERAL2 textMode_ +SHIFT LITERAL2 +SPECULAR LITERAL2 +SPHERE LITERAL2 createShape_ +SOFT_LIGHT LITERAL2 blend_ +SQUARE LITERAL2 strokeCap_ +SUBTRACT LITERAL2 blend_ +SVIDEO LITERAL2 +TAB LITERAL2 keyCode +TARGA LITERAL2 +TAU LITERAL2 TAU +TEXT LITERAL2 cursor_ +TFF LITERAL2 +THIRD_PI LITERAL2 +THRESHOLD LITERAL2 filter_ +TIFF LITERAL2 +TOP LITERAL2 textAlign_ +TRIANGLE LITERAL2 createShape_ +TRIANGLE_FAN LITERAL2 beginShape_ +TRIANGLES LITERAL2 beginShape_ +TRIANGLE_STRIP LITERAL2 beginShape_ +TUNER LITERAL2 +TWO LITERAL2 +TWO_PI LITERAL2 TWO_PI +UP LITERAL2 keyCode +WAIT LITERAL2 cursor_ +WHITESPACE LITERAL2 + + +# Java keywords (void, import, , etc.) + +abstract KEYWORD1 +assert KEYWORD1 +break KEYWORD1 break +case KEYWORD1 case +class KEYWORD1 class +continue KEYWORD1 continue +default KEYWORD1 default +enum KEYWORD1 +extends KEYWORD1 extends +false KEYWORD1 false +final KEYWORD1 final +finally KEYWORD1 +implements KEYWORD1 implements +import KEYWORD1 import +instanceof KEYWORD1 +interface KEYWORD1 +native KEYWORD1 +new KEYWORD1 new +null KEYWORD1 null +package KEYWORD1 +private KEYWORD1 private +protected KEYWORD1 +public KEYWORD1 public +return KEYWORD1 return +static KEYWORD1 static +strictfp KEYWORD1 +super KEYWORD1 super +this KEYWORD1 this +throw KEYWORD1 +throws KEYWORD1 +transient KEYWORD1 +true KEYWORD1 true +void KEYWORD1 void +volatile KEYWORD1 + + +# Datatypes + +Array KEYWORD5 Array +ArrayList KEYWORD5 ArrayList +Boolean KEYWORD5 +Byte KEYWORD5 +BufferedReader KEYWORD5 BufferedReader +Character KEYWORD5 +Class KEYWORD5 class +Double KEYWORD5 +Float KEYWORD5 +Integer KEYWORD5 +HashMap KEYWORD5 HashMap +PrintWriter KEYWORD5 PrintWriter +String KEYWORD5 String +StringBuffer KEYWORD5 +Thread KEYWORD5 +boolean KEYWORD5 boolean +byte KEYWORD5 byte +char KEYWORD5 char +color KEYWORD5 color_datatype +double KEYWORD5 double +float KEYWORD5 float +int KEYWORD5 int +long KEYWORD5 long +short KEYWORD5 + + +# Flow structures + +catch KEYWORD3 catch +do KEYWORD3 +for KEYWORD3 for +if KEYWORD3 if +else KEYWORD3 else +switch KEYWORD3 switch +synchronized KEYWORD3 +while KEYWORD3 while +try KEYWORD3 try + +catch FUNCTION3 catch +do FUNCTION3 +for FUNCTION3 for +if FUNCTION3 if +#else FUNCTION3 else +switch FUNCTION3 switch +synchronized FUNCTION3 +while FUNCTION3 while +#try FUNCTION3 try + + +# These items are a part of Processing but, but pages don't generate + +boolean FUNCTION1 booleanconvert_ +byte FUNCTION1 byteconvert_ +cache FUNCTION2 +char FUNCTION1 charconvert_ +start FUNCTION1 +stop FUNCTION1 +breakShape FUNCTION1 +createPath FUNCTION1 +float FUNCTION1 floatconvert_ +int FUNCTION1 intconvert_ +str FUNCTION1 strconvert_ +loadMatrix FUNCTION1 +parseBoolean FUNCTION1 +parseByte FUNCTION1 +parseChar FUNCTION1 +parseFloat FUNCTION1 +parseInt FUNCTION1 +saveFile FUNCTION1 +savePath FUNCTION1 +sketchFile FUNCTION1 +sketchPath FUNCTION1 + +readLine FUNCTION2 BufferedReader_readLine_ +close FUNCTION2 PrintWriter_close_ +flush FUNCTION2 PrintWriter_flush_ +print FUNCTION2 PrintWriter_print_ +println FUNCTION2 PrintWriter_println_ +charAt FUNCTION2 String_charAt_ +equals FUNCTION2 String_equals_ +indexOf FUNCTION2 String_indexOf_ +length FUNCTION2 String_length_ +substring FUNCTION2 String_substring_ +toLowerCase FUNCTION2 String_toLowerCase_ +toUpperCase FUNCTION2 String_toUpperCase_ + +length KEYWORD2 String + + +# Temporary additions 3 September 2012 as the reference is getting updated + +end FUNCTION1 +addChild FUNCTION1 + +# Operators are without KEYWORDS + ++= addassign ++ addition +[] arrayaccess += assign +& bitwiseAND +| bitwiseOR +, comma +// comment +? conditional +{} curlybraces +-- decrement +/ divide +/= divideassign +/** doccomment +. dot +== equality +> greaterthan +>= greaterthanorequalto +++ increment +!= inequality +<< leftshift +< lessthan +<= lessthanorequalto +&& logicalAND +! logicalNOT +|| logicalOR +- minus +% modulo +/* multilinecomment +* multiply +*= multiplyassign +() parentheses +>> rightshift +; semicolon +-= subtractassign + +# Suppressed from Generate to avoid conflicts with variables inside methods + +width KEYWORD4 width_ +height KEYWORD4 height_ + +PVector FUNCTION1 PVector +ArrayList FUNCTION1 ArrayList +HashMap FUNCTION1 HashMap + + +# THE TEXT ABOVE IS HAND-WRITTEN AND FOUND IN THE FILE "keywords_base.txt" +# THE TEXT BELOW IS AUTO-GENERATED +# +# SO DON'T +# TOUCH IT + + +abs FUNCTION1 abs_ +acos FUNCTION1 acos_ +alpha FUNCTION1 alpha_ +ambient FUNCTION1 ambient_ +ambientLight FUNCTION1 ambientLight_ +append FUNCTION1 append_ +applyMatrix FUNCTION1 applyMatrix_ +arc FUNCTION1 arc_ +arrayCopy FUNCTION1 arrayCopy_ +asin FUNCTION1 asin_ +atan FUNCTION1 atan_ +atan2 FUNCTION1 atan2_ +background FUNCTION1 background_ +beginCamera FUNCTION1 beginCamera_ +beginContour FUNCTION1 beginContour_ +beginRaw FUNCTION1 beginRaw_ +beginRecord FUNCTION1 beginRecord_ +beginShape FUNCTION1 beginShape_ +bezier FUNCTION1 bezier_ +bezierDetail FUNCTION1 bezierDetail_ +bezierPoint FUNCTION1 bezierPoint_ +bezierTangent FUNCTION1 bezierTangent_ +bezierVertex FUNCTION1 bezierVertex_ +binary FUNCTION1 binary_ +blend FUNCTION1 blend_ +blendColor FUNCTION1 blendColor_ +blendMode FUNCTION1 blendMode_ +blue FUNCTION1 blue_ +box FUNCTION1 box_ +brightness FUNCTION1 brightness_ +camera FUNCTION1 camera_ +ceil FUNCTION1 ceil_ +clear FUNCTION1 clear_ +clip FUNCTION1 clip_ +color FUNCTION1 color_ +colorMode FUNCTION1 colorMode_ +concat FUNCTION1 concat_ +constrain FUNCTION1 constrain_ +copy FUNCTION1 copy_ +cos FUNCTION1 cos_ +createFont FUNCTION1 createFont_ +createGraphics FUNCTION1 createGraphics_ +createImage FUNCTION1 createImage_ +createInput FUNCTION1 createInput_ +createOutput FUNCTION1 createOutput_ +createReader FUNCTION1 createReader_ +createShape FUNCTION1 createShape_ +createWriter FUNCTION1 createWriter_ +cursor FUNCTION1 cursor_ +curve FUNCTION1 curve_ +curveDetail FUNCTION1 curveDetail_ +curvePoint FUNCTION1 curvePoint_ +curveTangent FUNCTION1 curveTangent_ +curveTightness FUNCTION1 curveTightness_ +curveVertex FUNCTION1 curveVertex_ +day FUNCTION1 day_ +degrees FUNCTION1 degrees_ +directionalLight FUNCTION1 directionalLight_ +displayHeight KEYWORD4 displayHeight +displayWidth KEYWORD4 displayWidth +dist FUNCTION1 dist_ +draw FUNCTION4 draw +ellipse FUNCTION1 ellipse_ +ellipseMode FUNCTION1 ellipseMode_ +emissive FUNCTION1 emissive_ +endCamera FUNCTION1 endCamera_ +endContour FUNCTION1 endContour_ +endRaw FUNCTION1 endRaw_ +endRecord FUNCTION1 endRecord_ +endShape FUNCTION1 endShape_ +exit FUNCTION1 exit_ +exp FUNCTION1 exp_ +expand FUNCTION1 expand_ +fill FUNCTION1 fill_ +filter FUNCTION1 filter_ +FloatDict KEYWORD5 FloatDict +add FUNCTION2 FloatDict_add_ +clear FUNCTION2 FloatDict_clear_ +div FUNCTION2 FloatDict_div_ +get FUNCTION2 FloatDict_get_ +hasKey FUNCTION2 FloatDict_hasKey_ +keyArray FUNCTION2 FloatDict_keyArray_ +keys FUNCTION2 FloatDict_keys_ +mult FUNCTION2 FloatDict_mult_ +remove FUNCTION2 FloatDict_remove_ +set FUNCTION2 FloatDict_set_ +size FUNCTION2 FloatDict_size_ +sortKeys FUNCTION2 FloatDict_sortKeys_ +sortKeysReverse FUNCTION2 FloatDict_sortKeysReverse_ +sortValues FUNCTION2 FloatDict_sortValues_ +sortValuesReverse FUNCTION2 FloatDict_sortValuesReverse_ +sub FUNCTION2 FloatDict_sub_ +valueArray FUNCTION2 FloatDict_valueArray_ +values FUNCTION2 FloatDict_values_ +FloatList KEYWORD5 FloatList +add FUNCTION2 FloatList_add_ +append FUNCTION2 FloatList_append_ +array FUNCTION2 FloatList_array_ +clear FUNCTION2 FloatList_clear_ +div FUNCTION2 FloatList_div_ +get FUNCTION2 FloatList_get_ +hasValue FUNCTION2 FloatList_hasValue_ +max FUNCTION2 FloatList_max_ +min FUNCTION2 FloatList_min_ +mult FUNCTION2 FloatList_mult_ +remove FUNCTION2 FloatList_remove_ +reverse FUNCTION2 FloatList_reverse_ +set FUNCTION2 FloatList_set_ +shuffle FUNCTION2 FloatList_shuffle_ +size FUNCTION2 FloatList_size_ +sort FUNCTION2 FloatList_sort_ +sortReverse FUNCTION2 FloatList_sortReverse_ +sub FUNCTION2 FloatList_sub_ +floor FUNCTION1 floor_ +focused KEYWORD4 focused +frameCount KEYWORD4 frameCount +frameRate KEYWORD4 frameRate +frameRate FUNCTION1 frameRate_ +frustum FUNCTION1 frustum_ +get FUNCTION1 get_ +green FUNCTION1 green_ +HALF_PI LITERAL2 HALF_PI +hex FUNCTION1 hex_ +hint FUNCTION1 hint_ +hour FUNCTION1 hour_ +hue FUNCTION1 hue_ +image FUNCTION1 image_ +imageMode FUNCTION1 imageMode_ +IntDict KEYWORD5 IntDict +add FUNCTION2 IntDict_add_ +clear FUNCTION2 IntDict_clear_ +div FUNCTION2 IntDict_div_ +get FUNCTION2 IntDict_get_ +hasKey FUNCTION2 IntDict_hasKey_ +increment FUNCTION2 IntDict_increment_ +keyArray FUNCTION2 IntDict_keyArray_ +keys FUNCTION2 IntDict_keys_ +mult FUNCTION2 IntDict_mult_ +remove FUNCTION2 IntDict_remove_ +set FUNCTION2 IntDict_set_ +size FUNCTION2 IntDict_size_ +sortKeys FUNCTION2 IntDict_sortKeys_ +sortKeysReverse FUNCTION2 IntDict_sortKeysReverse_ +sortValues FUNCTION2 IntDict_sortValues_ +sortValuesReverse FUNCTION2 IntDict_sortValuesReverse_ +sub FUNCTION2 IntDict_sub_ +valueArray FUNCTION2 IntDict_valueArray_ +values FUNCTION2 IntDict_values_ +IntList KEYWORD5 IntList +add FUNCTION2 IntList_add_ +append FUNCTION2 IntList_append_ +array FUNCTION2 IntList_array_ +clear FUNCTION2 IntList_clear_ +div FUNCTION2 IntList_div_ +get FUNCTION2 IntList_get_ +hasValue FUNCTION2 IntList_hasValue_ +increment FUNCTION2 IntList_increment_ +max FUNCTION2 IntList_max_ +min FUNCTION2 IntList_min_ +mult FUNCTION2 IntList_mult_ +remove FUNCTION2 IntList_remove_ +reverse FUNCTION2 IntList_reverse_ +set FUNCTION2 IntList_set_ +shuffle FUNCTION2 IntList_shuffle_ +size FUNCTION2 IntList_size_ +sort FUNCTION2 IntList_sort_ +sortReverse FUNCTION2 IntList_sortReverse_ +sub FUNCTION2 IntList_sub_ +join FUNCTION1 join_ +JSONArray KEYWORD5 JSONArray +append FUNCTION2 JSONArray_append_ +getBoolean FUNCTION2 JSONArray_getBoolean_ +getFloat FUNCTION2 JSONArray_getFloat_ +getInt FUNCTION2 JSONArray_getInt_ +getIntArray FUNCTION2 JSONArray_getIntArray_ +getJSONArray FUNCTION2 JSONArray_getJSONArray_ +getJSONObject FUNCTION2 JSONArray_getJSONObject_ +getString FUNCTION2 JSONArray_getString_ +getStringArray FUNCTION2 JSONArray_getStringArray_ +remove FUNCTION2 JSONArray_remove_ +setBoolean FUNCTION2 JSONArray_setBoolean_ +setFloat FUNCTION2 JSONArray_setFloat_ +setInt FUNCTION2 JSONArray_setInt_ +getJSONArray FUNCTION2 JSONArray_setJSONArray_ +getJSONObject FUNCTION2 JSONArray_setJSONObject_ +setString FUNCTION2 JSONArray_setString_ +size FUNCTION2 JSONArray_size_ +JSONObject KEYWORD5 JSONObject +getBoolean FUNCTION2 JSONObject_getBoolean_ +getFloat FUNCTION2 JSONObject_getFloat_ +getInt FUNCTION2 JSONObject_getInt_ +getJSONArray FUNCTION2 JSONObject_getJSONArray_ +getJSONObject FUNCTION2 JSONObject_getJSONObject_ +getString FUNCTION2 JSONObject_getString_ +setBoolean FUNCTION2 JSONObject_setBoolean_ +setFloat FUNCTION2 JSONObject_setFloat_ +setInt FUNCTION2 JSONObject_setInt_ +setJSONArray FUNCTION2 JSONObject_setJSONArray_ +setJSONObject FUNCTION2 JSONObject_setJSONObject_ +setString FUNCTION2 JSONObject_setString_ +key KEYWORD4 key +keyCode KEYWORD4 keyCode +keyPressed FUNCTION4 keyPressed +keyPressed KEYWORD4 keyPressed +keyReleased FUNCTION4 keyReleased +keyTyped FUNCTION4 keyTyped +lerp FUNCTION1 lerp_ +lerpColor FUNCTION1 lerpColor_ +lightFalloff FUNCTION1 lightFalloff_ +lights FUNCTION1 lights_ +lightSpecular FUNCTION1 lightSpecular_ +line FUNCTION1 line_ +loadBytes FUNCTION1 loadBytes_ +loadFont FUNCTION1 loadFont_ +loadImage FUNCTION1 loadImage_ +loadJSONArray FUNCTION1 loadJSONArray_ +loadJSONObject FUNCTION1 loadJSONObject_ +loadPixels FUNCTION1 loadPixels_ +loadShader FUNCTION1 loadShader_ +loadShape FUNCTION1 loadShape_ +loadStrings FUNCTION1 loadStrings_ +loadTable FUNCTION1 loadTable_ +loadXML FUNCTION1 loadXML_ +log FUNCTION1 log_ +loop FUNCTION1 loop_ +mag FUNCTION1 mag_ +map FUNCTION1 map_ +match FUNCTION1 match_ +matchAll FUNCTION1 matchAll_ +max FUNCTION1 max_ +millis FUNCTION1 millis_ +min FUNCTION1 min_ +minute FUNCTION1 minute_ +modelX FUNCTION1 modelX_ +modelY FUNCTION1 modelY_ +modelZ FUNCTION1 modelZ_ +month FUNCTION1 month_ +mouseButton KEYWORD4 mouseButton +mouseClicked FUNCTION4 mouseClicked +mouseDragged FUNCTION4 mouseDragged +mouseMoved FUNCTION4 mouseMoved +mousePressed FUNCTION4 mousePressed +mousePressed KEYWORD4 mousePressed +mouseReleased FUNCTION1 mouseReleased_ +mouseWheel FUNCTION4 mouseWheel +mouseX KEYWORD4 mouseX +mouseY KEYWORD4 mouseY +nf FUNCTION1 nf_ +nfc FUNCTION1 nfc_ +nfp FUNCTION1 nfp_ +nfs FUNCTION1 nfs_ +noClip FUNCTION1 noClip_ +noCursor FUNCTION1 noCursor_ +noFill FUNCTION1 noFill_ +noise FUNCTION1 noise_ +noiseDetail FUNCTION1 noiseDetail_ +noiseSeed FUNCTION1 noiseSeed_ +noLights FUNCTION1 noLights_ +noLoop FUNCTION1 noLoop_ +norm FUNCTION1 norm_ +normal FUNCTION1 normal_ +noSmooth FUNCTION1 noSmooth_ +noStroke FUNCTION1 noStroke_ +noTint FUNCTION1 noTint_ +open FUNCTION1 open_ +ortho FUNCTION1 ortho_ +parseXML FUNCTION1 parseXML_ +perspective FUNCTION1 perspective_ +PFont KEYWORD5 PFont +list FUNCTION1 PFont_list_ +PGraphics KEYWORD5 PGraphics +beginDraw FUNCTION2 PGraphics_beginDraw_ +endDraw FUNCTION2 PGraphics_endDraw_ +PI LITERAL2 PI +PImage KEYWORD5 PImage +blend FUNCTION2 PImage_blend_ +copy FUNCTION2 PImage_copy_ +filter FUNCTION2 PImage_filter_ +get FUNCTION2 PImage_get_ +loadPixels FUNCTION2 PImage_loadPixels_ +mask FUNCTION2 PImage_mask_ +pixels KEYWORD2 PImage_pixels +resize FUNCTION2 PImage_resize_ +save FUNCTION2 PImage_save_ +set FUNCTION2 PImage_set_ +updatePixels FUNCTION2 PImage_updatePixels_ +pixels KEYWORD4 pixels +pmouseX KEYWORD4 pmouseX +pmouseY KEYWORD4 pmouseY +point FUNCTION1 point_ +pointLight FUNCTION1 pointLight_ +popMatrix FUNCTION1 popMatrix_ +popStyle FUNCTION1 popStyle_ +pow FUNCTION1 pow_ +print FUNCTION1 print_ +printCamera FUNCTION1 printCamera_ +println FUNCTION1 println_ +printMatrix FUNCTION1 printMatrix_ +printProjection FUNCTION1 printProjection_ +PShader KEYWORD5 PShader +PShader FUNCTION2 PShader_set_ +PShape KEYWORD5 PShape +addChild FUNCTION2 PShape_addChild_ +beginContour FUNCTION2 PShape_beginContour_ +disableStyle FUNCTION2 PShape_disableStyle_ +enableStyle FUNCTION2 PShape_enableStyle_ +endContour FUNCTION2 PShape_endContour_ +endShape FUNCTION2 PShape_endShape_ +getChild FUNCTION2 PShape_getChild_ +getChildCount FUNCTION2 PShape_getChildCount_ +getVertex FUNCTION2 PShape_getVertex_ +getVertexCount FUNCTION2 PShape_getVertexCount_ +isVisible FUNCTION2 PShape_isVisible_ +resetMatrix FUNCTION2 PShape_resetMatrix_ +rotate FUNCTION2 PShape_rotate_ +rotateX FUNCTION2 PShape_rotateX_ +rotateY FUNCTION2 PShape_rotateY_ +rotateZ FUNCTION2 PShape_rotateZ_ +scale FUNCTION2 PShape_scale_ +setVertex FUNCTION2 PShape_setVertex_ +setVisible FUNCTION2 PShape_setVisible_ +translate FUNCTION2 PShape_translate_ +pushMatrix FUNCTION1 pushMatrix_ +pushStyle FUNCTION1 pushStyle_ +PVector KEYWORD5 PVector +add FUNCTION2 PVector_add_ +angleBetween FUNCTION2 PVector_angleBetween_ +array FUNCTION2 PVector_array_ +copy FUNCTION2 PVector_copy_ +cross FUNCTION2 PVector_cross_ +dist FUNCTION2 PVector_dist_ +div FUNCTION2 PVector_div_ +dot FUNCTION2 PVector_dot_ +fromAngle FUNCTION2 PVector_fromAngle_ +get FUNCTION2 PVector_get_ +heading FUNCTION2 PVector_heading_ +lerp FUNCTION2 PVector_lerp_ +limit FUNCTION2 PVector_limit_ +mag FUNCTION2 PVector_mag_ +magSq FUNCTION2 PVector_magSq_ +mult FUNCTION2 PVector_mult_ +normalize FUNCTION2 PVector_normalize_ +random2D FUNCTION2 PVector_random2D_ +random3D FUNCTION2 PVector_random3D_ +rotate FUNCTION2 PVector_rotate_ +set FUNCTION2 PVector_set_ +setMag FUNCTION2 PVector_setMag_ +sub FUNCTION2 PVector_sub_ +quad FUNCTION1 quad_ +quadraticVertex FUNCTION1 quadraticVertex_ +QUARTER_PI LITERAL2 QUARTER_PI +radians FUNCTION1 radians_ +random FUNCTION1 random_ +randomGaussian FUNCTION1 randomGaussian_ +randomSeed FUNCTION1 randomSeed_ +rect FUNCTION1 rect_ +rectMode FUNCTION1 rectMode_ +red FUNCTION1 red_ +redraw FUNCTION1 redraw_ +requestImage FUNCTION1 requestImage_ +resetMatrix FUNCTION1 resetMatrix_ +resetShader FUNCTION1 resetShader_ +reverse FUNCTION1 reverse_ +rotate FUNCTION1 rotate_ +rotateX FUNCTION1 rotateX_ +rotateY FUNCTION1 rotateY_ +rotateZ FUNCTION1 rotateZ_ +round FUNCTION1 round_ +saturation FUNCTION1 saturation_ +save FUNCTION1 save_ +saveBytes FUNCTION1 saveBytes_ +saveFrame FUNCTION1 saveFrame_ +saveJSONArray FUNCTION1 saveJSONArray_ +saveJSONObject FUNCTION1 saveJSONObject_ +saveStream FUNCTION1 saveStream_ +saveStrings FUNCTION1 saveStrings_ +loadTable FUNCTION1 saveTable_ +saveXML FUNCTION1 saveXML_ +scale FUNCTION1 scale_ +screenX FUNCTION1 screenX_ +screenY FUNCTION1 screenY_ +screenZ FUNCTION1 screenZ_ +second FUNCTION1 second_ +selectFolder FUNCTION1 selectFolder_ +selectInput FUNCTION1 selectInput_ +selectOutput FUNCTION1 selectOutput_ +set FUNCTION1 set_ +setup FUNCTION4 setup +shader FUNCTION1 shader_ +shape FUNCTION1 shape_ +shapeMode FUNCTION1 shapeMode_ +shearX FUNCTION1 shearX_ +shearY FUNCTION1 shearY_ +shininess FUNCTION1 shininess_ +shorten FUNCTION1 shorten_ +sin FUNCTION1 sin_ +size FUNCTION1 size_ +smooth FUNCTION1 smooth_ +sort FUNCTION1 sort_ +specular FUNCTION1 specular_ +sphere FUNCTION1 sphere_ +sphereDetail FUNCTION1 sphereDetail_ +splice FUNCTION1 splice_ +split FUNCTION1 split_ +splitTokens FUNCTION1 splitTokens_ +spotLight FUNCTION1 spotLight_ +sq FUNCTION1 sq_ +sqrt FUNCTION1 sqrt_ +StringDict KEYWORD5 StringDict +clear FUNCTION2 StringDict_clear_ +get FUNCTION2 StringDict_get_ +hasKey FUNCTION2 StringDict_hasKey_ +keyArray FUNCTION2 StringDict_keyArray_ +keys FUNCTION2 StringDict_keys_ +remove FUNCTION2 StringDict_remove_ +set FUNCTION2 StringDict_set_ +size FUNCTION2 StringDict_size_ +sortKeys FUNCTION2 StringDict_sortKeys_ +sortKeysReverse FUNCTION2 StringDict_sortKeysReverse_ +sortValues FUNCTION2 StringDict_sortValues_ +sortValuesReverse FUNCTION2 StringDict_sortValuesReverse_ +valueArray FUNCTION2 StringDict_valueArray_ +values FUNCTION2 StringDict_values_ +StringList KEYWORD5 StringList +append FUNCTION2 StringList_append_ +array FUNCTION2 StringList_array_ +clear FUNCTION2 StringList_clear_ +get FUNCTION2 StringList_get_ +hasValue FUNCTION2 StringList_hasValue_ +lower FUNCTION2 StringList_lower_ +remove FUNCTION2 StringList_remove_ +reverse FUNCTION2 StringList_reverse_ +set FUNCTION2 StringList_set_ +shuffle FUNCTION2 StringList_shuffle_ +size FUNCTION2 StringList_size_ +sort FUNCTION2 StringList_sort_ +sortReverse FUNCTION2 StringList_sortReverse_ +upper FUNCTION2 StringList_upper_ +stroke FUNCTION1 stroke_ +strokeCap FUNCTION1 strokeCap_ +strokeJoin FUNCTION1 strokeJoin_ +strokeWeight FUNCTION1 strokeWeight_ +subset FUNCTION1 subset_ +Table KEYWORD5 Table +addColumn FUNCTION2 Table_addColumn_ +addRow FUNCTION2 Table_addRow_ +clearRows FUNCTION2 Table_clearRows_ +findRow FUNCTION2 Table_findRow_ +findRows FUNCTION2 Table_findRows_ +getColumnCount FUNCTION2 Table_getColumnCount_ +getFloat FUNCTION2 Table_getFloat_ +getInt FUNCTION2 Table_getInt_ +getRow FUNCTION2 Table_getRow_ +getRowCount FUNCTION2 Table_getRowCount_ +getString FUNCTION2 Table_getString_ +getStringColumn FUNCTION2 Table_getStringColumn_ +matchRow FUNCTION2 Table_matchRow_ +matchRows FUNCTION2 Table_matchRows_ +removeColumn FUNCTION2 Table_removeColumn_ +removeRow FUNCTION2 Table_removeRow_ +removeTokens FUNCTION2 Table_removeTokens_ +rows FUNCTION2 Table_rows_ +setFloat FUNCTION2 Table_setFloat_ +setInt FUNCTION2 Table_setInt_ +setString FUNCTION2 Table_setString_ +trim FUNCTION2 Table_trim_ +TableRow KEYWORD5 TableRow +getFloat FUNCTION2 TableRow_getFloat_ +getFloat FUNCTION2 TableRow_getInt_ +getString FUNCTION2 TableRow_getString_ +setFloat FUNCTION2 TableRow_setFloat_ +setInt FUNCTION2 TableRow_setInt_ +setString FUNCTION2 TableRow_setString_ +tan FUNCTION1 tan_ +TAU LITERAL2 TAU +text FUNCTION1 text_ +textAlign FUNCTION1 textAlign_ +textAscent FUNCTION1 textAscent_ +textDescent FUNCTION1 textDescent_ +textFont FUNCTION1 textFont_ +textLeading FUNCTION1 textLeading_ +textMode FUNCTION1 textMode_ +textSize FUNCTION1 textSize_ +texture FUNCTION1 texture_ +textureMode FUNCTION1 textureMode_ +textureWrap FUNCTION1 textureWrap_ +textWidth FUNCTION1 textWidth_ +tint FUNCTION1 tint_ +translate FUNCTION1 translate_ +triangle FUNCTION1 triangle_ +trim FUNCTION1 trim_ +TWO_PI LITERAL2 TWO_PI +unbinary FUNCTION1 unbinary_ +unhex FUNCTION1 unhex_ +updatePixels FUNCTION1 updatePixels_ +vertex FUNCTION1 vertex_ +XML KEYWORD5 XML +addChild FUNCTION2 XML_addChild_ +format FUNCTION2 XML_format_ +getAttributeCount FUNCTION2 XML_getAttributeCount_ +getChild FUNCTION2 XML_getChild_ +getChildren FUNCTION2 XML_getChildren_ +getContent FUNCTION2 XML_getContent_ +getFloat FUNCTION2 XML_getFloat_ +getContent FUNCTION2 XML_getFloatContent_ +getInt FUNCTION2 XML_getInt_ +getContent FUNCTION2 XML_getIntContent_ +getName FUNCTION2 XML_getName_ +getParent FUNCTION2 XML_getParent_ +getString FUNCTION2 XML_getString_ +hasAttribute FUNCTION2 XML_hasAttribute_ +hasChildren FUNCTION2 XML_hasChildren_ +listAttributes FUNCTION2 XML_listAttributes_ +listChildren FUNCTION2 XML_listChildren_ +removeChild FUNCTION2 XML_removeChild_ +setContent FUNCTION2 XML_setContent_ +setFloat FUNCTION2 XML_setFloat_ +setInt FUNCTION2 XML_setInt_ +setName FUNCTION2 XML_setName_ +setString FUNCTION2 XML_setString_ +toString FUNCTION2 XML_toString_ +year FUNCTION1 year_ diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 806e61389..b7ba615d9 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -736,13 +736,13 @@ public class TextArea extends JEditTextArea { suggestion.updateList(defListModel, subWord, location, position); suggestion.setVisible(true); -// requestFocusInWindow(); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - requestFocusInWindow(); - } - }); + requestFocusInWindow(); +// SwingUtilities.invokeLater(new Runnable() { +// @Override +// public void run() { +// requestFocusInWindow(); +// } +// }); } private void hideSuggestion() { diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 065fcbf8e..12fec475f 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -188,8 +188,8 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { try { //TODO: This line is causing NPE's randomly ever since I added the toggle for //Java Mode/Debugger toolbar. - super.paintLine(gfx, tokenMarker, line, x); - } catch (NullPointerException e) { + super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); + } catch (Exception e) { log(e.getMessage()); } } From 7d1ee09a4ebf9afe2bb5f9fdb4324fe9e496f0aa Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 04:54:58 +0530 Subject: [PATCH 229/608] save preferences everytime --- pdex/src/processing/mode/experimental/DebugEditor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index af738e75e..ead797567 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -326,7 +326,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ - dmode.savePreferences(); if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); super.internalCloseRunner(); } @@ -530,6 +529,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void actionPerformed(ActionEvent e) { ExperimentalMode.errorCheckEnabled = ((JCheckBoxMenuItem) e.getSource()).isSelected(); errorCheckerService.handleErrorCheckingToggle(); + dmode.savePreferences(); } }); debugMenu.add(item); @@ -561,6 +561,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { ExperimentalMode.warningsEnabled = ((JCheckBoxMenuItem) e .getSource()).isSelected(); errorCheckerService.runManualErrorCheck(); + dmode.savePreferences(); } }); debugMenu.add(showWarnings); @@ -572,6 +573,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void actionPerformed(ActionEvent e) { ExperimentalMode.codeCompletionsEnabled = (((JCheckBoxMenuItem) e .getSource()).isSelected()); + dmode.savePreferences(); } }); debugMenu.add(completionsEnabled); @@ -583,6 +585,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void actionPerformed(ActionEvent e) { ExperimentalMode.DEBUG = ((JCheckBoxMenuItem) e .getSource()).isSelected(); + dmode.savePreferences(); } }); debugMenu.add(debugMessagesEnabled); @@ -598,6 +601,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void actionPerformed(ActionEvent e) { ExperimentalMode.errorLogsEnabled = ((JCheckBoxMenuItem) e .getSource()).isSelected(); + dmode.savePreferences(); } }); debugMenu.add(writeErrorLog); From fc2633306b93aa63505f495371a2e65d4648d90e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 05:30:06 +0530 Subject: [PATCH 230/608] search for missing imports in contrib libs --- .../mode/experimental/ASTGenerator.java | 24 +++++++++++++++---- .../experimental/ErrorCheckerService.java | 6 ++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index c563c43fb..ce466f723 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -94,6 +94,7 @@ import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import processing.app.Base; +import processing.app.Library; import processing.app.SketchCode; import processing.app.Toolkit; import processing.mode.java.preproc.PdePreprocessor; @@ -3048,13 +3049,26 @@ public class ASTGenerator { Pattern.CASE_INSENSITIVE)); String[] resources = classPath .findResources("", regf); - if(resources.length == 0){ - log("Couldn't find import for class " + className); - return; + ArrayList candidates = new ArrayList(); + for (String res : resources) { + candidates.add(res); } + + // log("Couldn't find import for class " + className); + + for (Library lib : editor.dmode.contribLibraries) { + ClassPath cp = factory.createFromPath(lib.getClassPath()); + resources = cp.findResources("", regf); + for (String res : resources) { + candidates.add(res); + log("Res: " + res); + } + } + + resources = new String[candidates.size()]; for (int i = 0; i < resources.length; i++) { - resources[i] = resources[i].replace('/', '.') - .substring(0, resources[i].length() - 6); + resources[i] = candidates.get(i).replace('/', '.') + .substring(0, candidates.get(i).length() - 6); } if (resources.length >= 1) { final JList classList = new JList(resources); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 34a0e302f..896cd9da5 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1276,9 +1276,9 @@ public class ErrorCheckerService implements Runnable{ * compiler classpath needs to be updated. */ protected void checkForChangedImports() { - // log("Imports: " + programImports.size() + - // " Prev Imp: " - // + previousImports.size()); + log("Imports: " + programImports.size() + + " Prev Imp: " + + previousImports.size()); if (programImports.size() != previousImports.size()) { // log(1); loadCompClass = true; From 081095146a565d6039b27506034f247b91c38d7e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 12:03:35 +0530 Subject: [PATCH 231/608] added doc listener finally. --- pdex/Todo, GSoC 2013.txt | 4 ++ .../experimental/ErrorCheckerService.java | 52 ++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 2079b1b75..da4776a3b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -119,6 +119,8 @@ Suggestion for missing imports 2. Find the class name via astGen, and suggest import as a popup. x Barebones functionality done. x Add imports only to beginning of first tab. +x Search within contributed libraries folder +* Search within code folder of sketch Labels for Java elements ======================== @@ -145,6 +147,8 @@ x boolean warningsEnabled - made it volatile General Stuff ============= +* Disabling Error Checking disables predictions as well! +x Added doc listener for text area updates x Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file x Save preferences to main preference.txt x Hide breakpoint markers when Debugger isn't active diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 896cd9da5..833a53818 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -20,7 +20,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JCheckBoxMenuItem; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; +import javax.swing.text.AbstractDocument; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -35,6 +38,7 @@ import processing.app.Base; import processing.app.Editor; import processing.app.Library; import processing.app.SketchCode; +import processing.app.syntax.SyntaxDocument; import processing.core.PApplet; import processing.mode.java.preproc.PdePreprocessor; @@ -203,6 +207,10 @@ public class ErrorCheckerService implements Runnable{ containsErrors = new AtomicBoolean(true); errorMsgSimplifier = new ErrorMessageSimplifier(); tempErrorLog = new TreeMap(); + sketchChangedListener = new SketchChangedListener(); +// for (final SketchCode sc : editor.getSketch().getCode()) { +// sc.getDocument().addDocumentListener(sketchChangedListener); +// } } /** @@ -275,7 +283,7 @@ public class ErrorCheckerService implements Runnable{ updatePaintedThingys(); updateEditorStatus(); - + updateSketchCodeListeners(); if (pauseThread.get()) continue; if(textModified.get() == 0) @@ -290,6 +298,22 @@ public class ErrorCheckerService implements Runnable{ logE("Thread stopped: " + editor.getSketch().getName()); } + protected void updateSketchCodeListeners() { + for (final SketchCode sc : editor.getSketch().getCode()) { + boolean flag = false; + for (DocumentListener dl : ((SyntaxDocument)sc.getDocument()).getDocumentListeners()) { + if(dl.equals(sketchChangedListener)){ + flag = true; + break; + } + } + if(!flag){ + log("Adding doc listener to " + sc.getPrettyName()); + sc.getDocument().addDocumentListener(sketchChangedListener); + } + } + } + protected void checkForMissingImports() { for (Problem p : problemsList) { if(p.getMessage().endsWith(" cannot be resolved to a type"));{ @@ -323,6 +347,32 @@ public class ErrorCheckerService implements Runnable{ public void runManualErrorCheck() { textModified.incrementAndGet(); } + + protected SketchChangedListener sketchChangedListener; + protected class SketchChangedListener implements DocumentListener{ + + private SketchChangedListener(){ + } + + @Override + public void insertUpdate(DocumentEvent e) { + runManualErrorCheck(); + log("doc insert update, man error check.."); + } + + @Override + public void removeUpdate(DocumentEvent e) { + runManualErrorCheck(); + log("doc remove update, man error check.."); + } + + @Override + public void changedUpdate(DocumentEvent e) { + runManualErrorCheck(); + log("doc changed update, man error check.."); + } + + } protected boolean checkCode() { //log("checkCode() " + textModified.get() ); From 1becbe7960d896ccf5228549350686e6e3fc69d3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 12:18:21 +0530 Subject: [PATCH 232/608] fixed error check toggle. --- pdex/Todo, GSoC 2013.txt | 2 +- .../experimental/ErrorCheckerService.java | 43 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index da4776a3b..67638bbc4 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -147,7 +147,7 @@ x boolean warningsEnabled - made it volatile General Stuff ============= -* Disabling Error Checking disables predictions as well! +x Disabling Error Checking disables predictions as well! Fixed. x Added doc listener for text area updates x Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file x Save preferences to main preference.txt diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 833a53818..0b509c191 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -345,6 +345,7 @@ public class ErrorCheckerService implements Runnable{ * Triggers error check */ public void runManualErrorCheck() { + log("Error Check."); textModified.incrementAndGet(); } @@ -356,20 +357,26 @@ public class ErrorCheckerService implements Runnable{ @Override public void insertUpdate(DocumentEvent e) { - runManualErrorCheck(); - log("doc insert update, man error check.."); + if (ExperimentalMode.errorCheckEnabled){ + runManualErrorCheck(); + log("doc insert update, man error check.."); + } } @Override public void removeUpdate(DocumentEvent e) { - runManualErrorCheck(); - log("doc remove update, man error check.."); + if (ExperimentalMode.errorCheckEnabled){ + runManualErrorCheck(); + log("doc remove update, man error check.."); + } } @Override public void changedUpdate(DocumentEvent e) { - runManualErrorCheck(); - log("doc changed update, man error check.."); + if (ExperimentalMode.errorCheckEnabled){ + runManualErrorCheck(); + log("doc changed update, man error check.."); + } } } @@ -404,13 +411,18 @@ public class ErrorCheckerService implements Runnable{ log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } - - updateErrorTable(); - editor.updateErrorBar(problemsList); - updateEditorStatus(); - editor.getTextArea().repaint(); - updatePaintedThingys(); - editor.updateErrorToggle(); + if(ExperimentalMode.errorCheckEnabled){ + updateErrorTable(); + editor.updateErrorBar(problemsList); + updateEditorStatus(); + editor.getTextArea().repaint(); + updatePaintedThingys(); + editor.updateErrorToggle(); + } + else + { + log("Error Check disabled, so not updating UI."); + } int x = textModified.get(); //log("TM " + x); if (x >= 2) { @@ -878,6 +890,7 @@ public class ErrorCheckerService implements Runnable{ public void updateEditorStatus() { // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); + if(ExperimentalMode.errorCheckEnabled) synchronized (editor.errorBar.errorPoints) { for (ErrorMarker emarker : editor.errorBar.errorPoints) { if (emarker.getProblem().getLineNumber() == editor.getTextArea() @@ -1454,7 +1467,7 @@ public class ErrorCheckerService implements Runnable{ public void handleErrorCheckingToggle(){ if (!ExperimentalMode.errorCheckEnabled) { // unticked Menu Item - pauseThread(); + // pauseThread(); log(editor.getSketch().getName() + " - Error Checker paused."); editor.errorBar.errorPoints.clear(); @@ -1464,7 +1477,7 @@ public class ErrorCheckerService implements Runnable{ editor.getTextArea().repaint(); editor.errorBar.repaint(); } else { - resumeThread(); + //resumeThread(); log(editor.getSketch().getName() + " - Error Checker resumed."); runManualErrorCheck(); From fa5346f8a8228002d7556b4e822378bb522c7b18 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 17:44:22 +0530 Subject: [PATCH 233/608] updated build.xml to produce dist zips --- pdex/build.properties | 1 + pdex/build.xml | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/pdex/build.properties b/pdex/build.properties index 656dbd7c9..3fbad5f25 100644 --- a/pdex/build.properties +++ b/pdex/build.properties @@ -4,6 +4,7 @@ core.library.location=/home/quarkninja/Workspaces/processing-workspace/processin app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/ java.target.version=1.6 lib.name=ExperimentalMode +prettyName=PDE X dist=dist release=3 prettyVersion=1.0.0b diff --git a/pdex/build.xml b/pdex/build.xml index a3988d3a6..3feee8a7a 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -94,6 +94,14 @@ + + + + + From a3b94b7218dbfba6b86daddf4916edc90edb9d3f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 20:07:11 +0530 Subject: [PATCH 234/608] completion popup height now dynamic. --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/CompletionPanel.java | 51 +++++++++++-------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 67638bbc4..f1752b2bc 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -44,6 +44,7 @@ Finer details *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. * Diamond operator isn't supported for now. Bummer. +x Completion popup height is now dynamic, decreases to fit. x Icons for completions? Or overkill right now? x 'Show Usage' menu item added x Show declaring class for completions diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 39ce00d58..3b32a713b 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -5,21 +5,19 @@ import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; -import java.awt.Dimension; +import java.awt.FontMetrics; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.io.File; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; -import javax.swing.Icon; -import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import processing.app.syntax.JEditTextArea; @@ -39,8 +37,8 @@ public class CompletionPanel { protected DebugEditor editor; - public CompletionPanel(JEditTextArea textarea, int position, String subWord, - DefaultListModel items, Point location, DebugEditor dedit) { + public CompletionPanel(final JEditTextArea textarea, int position, String subWord, + DefaultListModel items, final Point location, DebugEditor dedit) { this.textarea = (TextArea) textarea; editor = dedit; this.insertionPosition = position; @@ -55,7 +53,7 @@ public class CompletionPanel { scrollPane = new JScrollPane(); scrollPane.setViewportView(completionList = createSuggestionList(position, items)); popupMenu.add(scrollPane, BorderLayout.CENTER); - popupMenu.setPopupSize(280, 250); //TODO: Eradicate this evil + popupMenu.setPopupSize(280, setHeight(items.getSize())); //TODO: Eradicate this evil this.textarea.errorCheckerService.getASTGenerator() .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) @@ -71,6 +69,14 @@ public class CompletionPanel { log("Pred popup visible."); popupMenu.setVisible(v); } + + protected int setHeight(int itemCount){ + if(scrollPane.getHorizontalScrollBar().isVisible()) itemCount++; + FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); + float h = (fm.getHeight() + fm.getDescent()*0.5f) * (itemCount + 1); + log("popup height " + Math.min(250,h)); + return Math.min(250,(int)h); // popup menu height + } private JList createSuggestionList(final int position, final DefaultListModel items) { @@ -92,23 +98,28 @@ public class CompletionPanel { return list; } - public boolean updateList(final DefaultListModel items, String newSubword, Point location, int position){ - scrollPane.getViewport().removeAll(); - Dimension dimen = popupMenu.getSize(); - completionList.setModel(items); - completionList.validate(); - completionList.setSelectedIndex(0); - scrollPane.setViewportView(completionList); - scrollPane.validate(); - popupMenu.setSize(dimen); - //popupMenu.setLocation(location); + public boolean updateList(final DefaultListModel items, String newSubword, + final Point location, int position) { this.subWord = new String(newSubword); if (subWord.indexOf('.') != -1) this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1); insertionPosition = position; - log("Suggestion updated" + System.nanoTime()); - popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) - + location.y); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + scrollPane.getViewport().removeAll(); + completionList.setModel(items); + completionList.setSelectedIndex(0); + scrollPane.setViewportView(completionList); + popupMenu.setPopupSize(popupMenu.getSize().width, setHeight(items.getSize())); + log("Suggestion updated" + System.nanoTime()); + popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + + location.y); + completionList.validate(); + scrollPane.validate(); + popupMenu.validate(); + } + }); return true; } From b2997f5f08b308de2c8d6a22f4869aadd62ffa8e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 17 Sep 2013 23:45:04 +0530 Subject: [PATCH 235/608] Add GitHub link to PDE X Menu --- pdex/Todo, GSoC 2013.txt | 1 + .../src/processing/mode/experimental/DebugEditor.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index f1752b2bc..91c8af92b 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -161,3 +161,4 @@ x On Run/Debug Console is visible(ProblemsList hidden) * Update wiki for Ctrl + H instead of Ctrl + J shortcuts x update build.xml to produce dists x Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc +x Add GitHub link to PDE X Menu diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index ead797567..644c67a99 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -606,7 +606,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { }); debugMenu.add(writeErrorLog); - + debugMenu.addSeparator(); + JMenuItem jitem = new JMenuItem("PDE X on GitHub"); + jitem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Base.openURL("https://github.com/processing/processing-experimental"); + } + }); + debugMenu.add(jitem); + return debugMenu; } From 80ed45442952a5c2f2d5798272782b5dab29e43b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 01:30:02 +0530 Subject: [PATCH 236/608] fix focus bug for Windows --- pdex/src/processing/mode/experimental/CompletionPanel.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 3b32a713b..62c367d3a 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -56,6 +56,7 @@ public class CompletionPanel { popupMenu.setPopupSize(280, setHeight(items.getSize())); //TODO: Eradicate this evil this.textarea.errorCheckerService.getASTGenerator() .updateJavaDoc((CompletionCandidate) completionList.getSelectedValue()); + textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); log("Suggestion constructed" + System.nanoTime()); @@ -82,7 +83,7 @@ public class CompletionPanel { final DefaultListModel items) { JList list = new JList(items); - list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); + //list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1)); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); list.setSelectedIndex(0); list.addMouseListener(new MouseAdapter() { @@ -95,6 +96,7 @@ public class CompletionPanel { } }); list.setCellRenderer(new CustomListRenderer()); + list.setFocusable(false); return list; } @@ -113,6 +115,7 @@ public class CompletionPanel { scrollPane.setViewportView(completionList); popupMenu.setPopupSize(popupMenu.getSize().width, setHeight(items.getSize())); log("Suggestion updated" + System.nanoTime()); + textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); completionList.validate(); From fbe29ce2dccf7896be567c0781ef4b7ba8004aa4 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 01:31:10 +0530 Subject: [PATCH 237/608] lower suggestion window slightly --- pdex/src/processing/mode/experimental/TextArea.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index b7ba615d9..4abec789b 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -719,7 +719,7 @@ public class TextArea extends JEditTextArea { location.x = offsetToX(getCaretLine(), position - getLineStartOffset(getCaretLine())); location.y = lineToY(getCaretLine()) - + getPainter().getFontMetrics().getHeight(); + + getPainter().getFontMetrics().getHeight() + getPainter().getFontMetrics().getDescent(); log("TA position: " + location); } catch (Exception e2) { e2.printStackTrace(); From 6ab71c1558e426a60bba20bda2ff1d93eb94cd1b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 02:04:35 +0530 Subject: [PATCH 238/608] completion popup width dynamic fail --- pdex/Todo, GSoC 2013.txt | 1 + .../mode/experimental/CompletionPanel.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index 91c8af92b..a9cd7c736 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -45,6 +45,7 @@ Finer details * Diamond operator isn't supported for now. Bummer. x Completion popup height is now dynamic, decreases to fit. +* Completion width can be dynamic, if really needed.. x Icons for completions? Or overkill right now? x 'Show Usage' menu item added x Show declaring class for completions diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 62c367d3a..08fc06ac4 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -9,6 +9,7 @@ import java.awt.FontMetrics; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.Iterator; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; @@ -78,6 +79,20 @@ public class CompletionPanel { log("popup height " + Math.min(250,h)); return Math.min(250,(int)h); // popup menu height } + + /*TODO: Make width dynamic + protected int setWidth(){ + if(scrollPane.getVerticalScrollBar().isVisible()) return 280; + float min = 280; + FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); + for (int i = 0; i < completionList.getModel().getSize(); i++) { + float h = fm.stringWidth(completionList.getModel().getElementAt(i).toString()); + min = Math.min(min, h); + } + min += fm.stringWidth(" "); + log("popup width " + Math.min(280,min)); + return Math.min(280,(int)min); // popup menu height + }*/ private JList createSuggestionList(final int position, final DefaultListModel items) { From e4968890d7899f5140a962d149b9713899b82302 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 02:21:35 +0530 Subject: [PATCH 239/608] updated readme --- pdex/README.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pdex/README.md b/pdex/README.md index 4b944dedf..5f75d9e59 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -1,10 +1,23 @@ -Experimental Mode for the PDE -========================= +PDE X +===== -This project is in the process of being moved out of the main project so that it can be developed in parallel with the PDE. Right now, it's in a messy state and not stable, forking isn't recommened. +PDE X is a [Processing](http://processing.org/) Mode that brings along powerful new features to the Processing Development Environment: -Stay tuned for updates. +* Intelligent Code Completion +* Quick Renaming(Refactoring) +* Quick Navigation +* Import Suggestions +* Live Error Checker +* Integrated Debugger + +Find out more at [Getting Started!](https://github.com/processing/processing-experimental/wiki/Getting-Started) + +####How to Install + +![Mode Button](http://i.imgur.com/cag1y10.png) + +Click on the down arrow besides the mode switch button, and select Add Mode. In the Mode Manager window, select PDE X and click 'Install'. Manindra Moharana -29 June 2013 +18 September 2013 From fb31177e5fc39428e5933cf2631c03e3870b1b0b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 02:23:35 +0530 Subject: [PATCH 240/608] updated readme. --- pdex/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdex/README.md b/pdex/README.md index 5f75d9e59..7aca28b91 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -21,3 +21,6 @@ Click on the down arrow besides the mode switch button, and select Add Mode. In Manindra Moharana 18 September 2013 + +-- +PDE X is supported by [Google Summer of Code 2013](http://www.google-melange.com/gsoc/homepage/google/gsoc2013) \ No newline at end of file From 8c3e962cb163968a4eac16a70b0bd2e04020e95c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 03:06:23 +0530 Subject: [PATCH 241/608] readme update --- pdex/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/README.md b/pdex/README.md index 7aca28b91..c4a28b867 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -10,13 +10,13 @@ PDE X is a [Processing](http://processing.org/) Mode that brings along powerful * Live Error Checker * Integrated Debugger -Find out more at [Getting Started!](https://github.com/processing/processing-experimental/wiki/Getting-Started) +Find out more at [Getting Started](https://github.com/processing/processing-experimental/wiki/Getting-Started) ####How to Install ![Mode Button](http://i.imgur.com/cag1y10.png) -Click on the down arrow besides the mode switch button, and select Add Mode. In the Mode Manager window, select PDE X and click 'Install'. +Click on the down arrow besides the mode switch button, and select Add Mode. In the Mode Manager window, select PDE X and click 'Install'. You'll need Processing 2.0.2 or higher. Manindra Moharana From 31c2d96b9cc7f42cbce1516dd9c12308a16aa922 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 15:23:04 +0530 Subject: [PATCH 242/608] a bit more work on import suggestions --- pdex/Todo, GSoC 2013.txt | 3 ++- pdex/mode.properties | 2 +- .../processing/mode/experimental/ASTGenerator.java | 14 ++++++++++++++ .../src/processing/mode/experimental/TextArea.java | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index a9cd7c736..f599eb465 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -122,7 +122,8 @@ Suggestion for missing imports x Barebones functionality done. x Add imports only to beginning of first tab. x Search within contributed libraries folder -* Search within code folder of sketch +x Hide suggestion list before showing import suggestions +x Search within code folder of sketch Labels for Java elements ======================== diff --git a/pdex/mode.properties b/pdex/mode.properties index 5029f1941..b5ac00702 100644 --- a/pdex/mode.properties +++ b/pdex/mode.properties @@ -1,4 +1,4 @@ -name=ExperimentalMode +name=PDE X authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ce466f723..5e82877ca 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -3064,6 +3064,19 @@ public class ASTGenerator { log("Res: " + res); } } + + if (editor.getSketch().hasCodeFolder()) { + File codeFolder = editor.getSketch().getCodeFolder(); + // get a list of .jar files in the "code" folder + // (class files in subfolders should also be picked up) + ClassPath cp = factory.createFromPath(Base + .contentsToClassPath(codeFolder)); + resources = cp.findResources("", regf); + for (String res : resources) { + candidates.add(res); + log("Res: " + res); + } + } resources = new String[candidates.size()]; for (int i = 0; i < resources.length; i++) { @@ -3115,6 +3128,7 @@ public class ASTGenerator { editor.getY() + (editor.getHeight() - frmImportSuggest.getHeight()) / 2); + editor.ta.hideSuggestion(); frmImportSuggest.setVisible(true); } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 4abec789b..3e2a36f28 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -745,7 +745,7 @@ public class TextArea extends JEditTextArea { // }); } - private void hideSuggestion() { + protected void hideSuggestion() { if (suggestion != null) { suggestion.hide(); suggestion = null; From d9765faee92f9dc08657a07ed9f12d28a73138b6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 16:07:17 +0530 Subject: [PATCH 243/608] improvements to import suggestions window --- pdex/Todo, GSoC 2013.txt | 2 +- .../mode/experimental/ASTGenerator.java | 45 ++++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index f599eb465..cdd5026ba 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -75,7 +75,7 @@ Refactoring =========== * Undo misbehaves here, handle carefully. - +* Fails to rename the first defined global variable, if a javadoc comment precedes it. But owrds for single/multiline comments. Wth! x New Name is validated. x Ordered list in 'Show Usage' window x Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 5e82877ca..00ea002b8 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -3,14 +3,11 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.logE; +import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.Point; import java.awt.Rectangle; -import java.awt.ScrollPane; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.WindowEvent; -import java.awt.event.WindowFocusListener; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -26,12 +23,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import javax.swing.BorderFactory; @@ -51,13 +46,11 @@ import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; -import javax.swing.table.DefaultTableModel; import javax.swing.text.BadLocationException; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; @@ -2208,6 +2201,7 @@ public class ASTGenerator { + selText); lblRefactorOldName.setText("Current name: " + selText); + txtRenameField.setText(""); txtRenameField.requestFocus(); } }); @@ -3094,7 +3088,7 @@ public class ASTGenerator { ((JComponent) frmImportSuggest.getContentPane()).setBorder(BorderFactory .createEmptyBorder(5, 5, 5, 5)); JLabel lbl = new JLabel("The class \"" + className - + "\" couldn't be determined, choose the import you need from the following list."); + + "\" couldn't be determined. You are probably missing one of the following imports:"); JScrollPane jsp = new JScrollPane(); jsp.setViewportView(classList); JButton btnInsertImport = new JButton("Insert import"); @@ -3118,11 +3112,38 @@ public class ASTGenerator { } } }); + + JButton btnCancel = new JButton("Cancel"); + btnCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + frmImportSuggest.setVisible(false); + } + }); + + JPanel panelTop = new JPanel(), panelBottom = new JPanel(), panelLabel = new JPanel(); + panelTop.setLayout(new BoxLayout(panelTop, BoxLayout.Y_AXIS)); + panelTop.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + panelLabel.setLayout(new BorderLayout()); + panelLabel.add(lbl,BorderLayout.CENTER); + panelTop.add(panelLabel); + panelTop.add(Box.createRigidArea(new Dimension(1, 5))); + panelTop.add(jsp); + panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.X_AXIS)); + panelBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + panelBottom .setLayout(new BoxLayout(panelBottom, BoxLayout.X_AXIS)); + panelBottom.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + panelBottom.add(Box.createHorizontalGlue()); + panelBottom.add(btnInsertImport); + panelBottom.add(Box.createRigidArea(new Dimension(15, 0))); + panelBottom.add(btnCancel); - frmImportSuggest.add(lbl); - frmImportSuggest.add(jsp); - frmImportSuggest.add(btnInsertImport); +// frmImportSuggest.add(lbl); +// frmImportSuggest.add(jsp); +// frmImportSuggest.add(btnInsertImport); + frmImportSuggest.add(panelTop); + frmImportSuggest.add(panelBottom); frmImportSuggest.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + frmImportSuggest.setTitle("Import Suggestion"); frmImportSuggest.setLocation(editor.getX() + (editor.getWidth() - frmImportSuggest.getWidth()) / 2, editor.getY() From 18334ee20dde4bd977639bcee7a00abc38827d39 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 16:08:16 +0530 Subject: [PATCH 244/608] updated mode.props --- pdex/mode.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/mode.properties b/pdex/mode.properties index b5ac00702..e70030c59 100644 --- a/pdex/mode.properties +++ b/pdex/mode.properties @@ -2,6 +2,6 @@ name=PDE X authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE -paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. +paragraph=Intelligent Code Completion, Quick Navigation, Refactoring, Live Error Checker, Debugger, etc. version=@@version@@ prettyVersion=@@pretty-version@@ From 3054ee50b6ece81a282dbdafb0d4136ededbb0b9 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 23:29:44 +0530 Subject: [PATCH 245/608] reseting build props --- pdex/build.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pdex/build.properties b/pdex/build.properties index 3fbad5f25..4dfc0023d 100644 --- a/pdex/build.properties +++ b/pdex/build.properties @@ -1,7 +1,7 @@ -sketchbook.location=${user.home}/Documents/Processing -classpath.local.location=${user.home}/Documents/workspace/libs -core.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/core/library -app.library.location=/home/quarkninja/Workspaces/processing-workspace/processing/app/ +sketchbook.location= +classpath.local.location= +core.library.location= +app.library.location= java.target.version=1.6 lib.name=ExperimentalMode prettyName=PDE X From a03b1a0f3aaa594a2082cfbd02ac4e3763477491 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 23:30:33 +0530 Subject: [PATCH 246/608] ignoring build props --- pdex/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/pdex/.gitignore b/pdex/.gitignore index 60f681921..e79cb3191 100644 --- a/pdex/.gitignore +++ b/pdex/.gitignore @@ -5,3 +5,4 @@ bin mode/ExperimentalMode.jar dist +build.properties \ No newline at end of file From d55553fd74451cdc1703839941362816ac7bf155 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 18 Sep 2013 23:37:25 +0530 Subject: [PATCH 247/608] adding pdeX.txt --- pdex/pdeX.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 pdex/pdeX.txt diff --git a/pdex/pdeX.txt b/pdex/pdeX.txt new file mode 100644 index 000000000..08f2a6112 --- /dev/null +++ b/pdex/pdeX.txt @@ -0,0 +1,7 @@ +name=PDE X +authorList=[The Processing Foundation](http://processing.org) +url=https://github.com/processing/processing-experimental +sentence=The next generation of PDE +paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. +version=3 +prettyVersion=1.0.0b From 5d684228138e4ecd594eabe82da7ec00b4e8195e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 25 Sep 2013 00:16:36 +0530 Subject: [PATCH 248/608] added FAQ link to readme --- pdex/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdex/README.md b/pdex/README.md index c4a28b867..af8f5efd1 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -1,7 +1,7 @@ PDE X ===== -PDE X is a [Processing](http://processing.org/) Mode that brings along powerful new features to the Processing Development Environment: +PDE X is a [Processing](http://processing.org/) Mode that brings powerful new features to the Processing Development Environment: * Intelligent Code Completion * Quick Renaming(Refactoring) @@ -10,7 +10,7 @@ PDE X is a [Processing](http://processing.org/) Mode that brings along powerful * Live Error Checker * Integrated Debugger -Find out more at [Getting Started](https://github.com/processing/processing-experimental/wiki/Getting-Started) +Find out more at [Getting Started](https://github.com/processing/processing-experimental/wiki/Getting-Started). Or checkout the [FAQ](https://github.com/processing/processing-experimental/wiki/FAQ) ####How to Install @@ -20,7 +20,7 @@ Click on the down arrow besides the mode switch button, and select Add Mode. In Manindra Moharana -18 September 2013 +25 September 2013 -- PDE X is supported by [Google Summer of Code 2013](http://www.google-melange.com/gsoc/homepage/google/gsoc2013) \ No newline at end of file From 72b1077a13f1880f35ee7c5e24f1fd098f7de7d1 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 25 Sep 2013 02:42:12 +0530 Subject: [PATCH 249/608] Completion list now always recreated, fixes #19 --- .../mode/experimental/CompletionPanel.java | 1 + .../processing/mode/experimental/TextArea.java | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 08fc06ac4..a7fd9bbc5 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -115,6 +115,7 @@ public class CompletionPanel { return list; } + // possibly defunct public boolean updateList(final DefaultListModel items, String newSubword, final Point location, int position) { this.subWord = new String(newSubword); diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 3e2a36f28..8025f96b3 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -708,9 +708,9 @@ public class TextArea extends JEditTextArea { } protected void showSuggestion(DefaultListModel defListModel,String subWord) { + hideSuggestion(); if (defListModel.size() == 0) { log("TextArea: No suggestions to show."); - hideSuggestion(); return; } int position = getCaretPosition(); @@ -729,13 +729,13 @@ public class TextArea extends JEditTextArea { if (subWord.length() < 2) { return; } - if (suggestion == null) - suggestion = new CompletionPanel(this, position, subWord, defListModel, - location,editor); - else - suggestion.updateList(defListModel, subWord, location, position); - - suggestion.setVisible(true); + //if (suggestion == null) + suggestion = new CompletionPanel(this, position, subWord, defListModel, + location,editor); +// else +// suggestion.updateList(defListModel, subWord, location, position); +// +// suggestion.setVisible(true); requestFocusInWindow(); // SwingUtilities.invokeLater(new Runnable() { // @Override @@ -748,6 +748,7 @@ public class TextArea extends JEditTextArea { protected void hideSuggestion() { if (suggestion != null) { suggestion.hide(); + log("Suggestion hidden."); suggestion = null; } } From f5384ba4be9f83849f7c8988a83ee3f6e58a8934 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 25 Sep 2013 02:44:08 +0530 Subject: [PATCH 250/608] this should help in debugging --- pdex/src/processing/mode/experimental/DebugEditor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 644c67a99..16d635011 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -241,6 +241,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); + log("Sketch Path: " + path); } private void addXQModeUI(){ From b4573323f7edd7e54311bd3cb5c6ec834f3256cf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 25 Sep 2013 02:47:57 +0530 Subject: [PATCH 251/608] disabling those tiny rects, don't like 'em anymore --- .../mode/experimental/TextAreaPainter.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 12fec475f..2e28125d5 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -365,12 +365,15 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // gfx.fillRect(x1, y, rw, height); // Let the painting begin! - gfx.setColor(errorMarkerColor); - if (isWarning) { - gfx.setColor(warningMarkerColor); - } - gfx.fillRect(1, y + 2, 3, height - 2); + + // Little rect at starting of a line containing errors - disabling it for now +// gfx.setColor(errorMarkerColor); +// if (isWarning) { +// gfx.setColor(warningMarkerColor); +// } +// gfx.fillRect(1, y + 2, 3, height - 2); + gfx.setColor(errorColor); if (isWarning) { gfx.setColor(warningColor); From edea7bb30b761a2a7e411b0b5f972527fdacec88 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 25 Sep 2013 03:06:45 +0530 Subject: [PATCH 252/608] Adding a revisions file, to keep track of progress. --- pdex/revisions.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 pdex/revisions.txt diff --git a/pdex/revisions.txt b/pdex/revisions.txt new file mode 100644 index 000000000..8d680125b --- /dev/null +++ b/pdex/revisions.txt @@ -0,0 +1,17 @@ +PDE X v1.0.1b - 25 September, 2013 + +Bug fix + ++ Fixed a major issue where completion list was going blank. + https://github.com/processing/processing-experimental/issues/19 + +Changes + +- Removed the tiny markers shown at the start of error lines. Too. Much. Red. + + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + +PDE X v1.0.0b - 22 September, 2013 + +Boom! First Public Beta Release! + From 97f4fa684294d3db143976e3d281a3e8d90d063c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 25 Sep 2013 03:10:03 +0530 Subject: [PATCH 253/608] updated version no. --- pdex/pdeX.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/pdeX.txt b/pdex/pdeX.txt index 08f2a6112..0b988f675 100644 --- a/pdex/pdeX.txt +++ b/pdex/pdeX.txt @@ -3,5 +3,5 @@ authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. -version=3 -prettyVersion=1.0.0b +version=4 +prettyVersion=1.0.1b From 2641a2fa3ea967d225e444a33cde8d1f77796894 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 12 Oct 2013 11:09:42 +0530 Subject: [PATCH 254/608] Trying to solve the permgen out of memory problem --- pdex/Todo, GSoC 2013.txt | 4 ++++ .../experimental/ErrorCheckerService.java | 22 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index cdd5026ba..d2e577745 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -150,6 +150,10 @@ x boolean warningsEnabled - made it volatile General Stuff ============= +* [Critical] PermGen out of memory bug. Manually triggering GC after making the classloader null ensures permgen memory is reclaimed on editor exit. Max open window still limited by max permgen size. Also, added a classloadcounter in ECS to trigger GC periodically. +https://github.com/processing/processing-experimental/issues/1 +See: http://stackoverflow.com/questions/2095974/how-to-unload-a-already-loaded-class-in-java +I'm making the classLoader null, but what about the classes loaded by ASTGen? Investigate. x Disabling Error Checking disables predictions as well! Fixed. x Added doc listener for text area updates x Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 0b509c191..62ccf3ae4 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -292,10 +292,14 @@ public class ErrorCheckerService implements Runnable{ checkCode(); checkForMissingImports(); } - checkerClass = null; + astGenerator.disposeAllWindows(); - astGenerator = null; + compilationChecker = null; + checkerClass = null; + classLoader = null; + System.gc(); logE("Thread stopped: " + editor.getSketch().getName()); + System.gc(); } protected void updateSketchCodeListeners() { @@ -558,7 +562,11 @@ public class ErrorCheckerService implements Runnable{ for (int i = 0; i < jarFiles.length; i++) { classpath[ii++] = jarFiles[i].toURI().toURL(); } - + + compilationChecker = null; + checkerClass = null; + classLoader = null; + System.gc(); // log("CP Len -- " + classpath.length); classLoader = new URLClassLoader(classpath); // log("1."); @@ -650,7 +658,15 @@ public class ErrorCheckerService implements Runnable{ // log("Compilecheck, Done."); } + private int loadClassCounter = 0; public URLClassLoader getSketchClassLoader() { + loadClassCounter++; + if(loadClassCounter > 100){ + loadClassCounter = 0; + classLoader = null; + System.gc(); + classLoader = new URLClassLoader(classpath); + } return classLoader; } From 5401574f34cd58559ada886a97037944ef9c7532 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 12 Oct 2013 11:21:50 +0530 Subject: [PATCH 255/608] completion gets hidden on editor losing focus. Fixes #21 --- .../processing/mode/experimental/DebugEditor.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 16d635011..953a4bffc 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -28,6 +28,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -294,6 +296,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.ERRORSLIST); consoleProblemsPane.add(console, XQConsoleToggle.CONSOLE); consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); + + // ensure completion gets hidden on editor losing focus + addWindowFocusListener(new WindowFocusListener() { + public void windowLostFocus(WindowEvent e) { + ta.hideSuggestion(); + } + public void windowGainedFocus(WindowEvent e) { + + } + }); } // /** From dcab7a85e1d31ca5deae9c318d0ef4296f8e22a5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 12 Oct 2013 11:29:09 +0530 Subject: [PATCH 256/608] updated revisions.txt --- pdex/revisions.txt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pdex/revisions.txt b/pdex/revisions.txt index 8d680125b..6068571a6 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -1,3 +1,19 @@ + +PDE X v1.0.2b - October, 2013 + +Bug fixes + ++ Code completion window gets stuck when Processing loses focus + https://github.com/processing/processing-experimental/issues/21 + ++ Live-error checker in the experimental mode is inefficient with memory. + https://github.com/processing/processing-experimental/issues/1 + ++ Cmd + Left Click should be working again in OS X with Processing 2.1 + https://github.com/processing/processing-experimental/issues/11 + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + PDE X v1.0.1b - 25 September, 2013 Bug fix @@ -9,7 +25,7 @@ Changes - Removed the tiny markers shown at the start of error lines. Too. Much. Red. - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PDE X v1.0.0b - 22 September, 2013 From 315952bef640a09acd366417bf6b8ac57a833328 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 21 Oct 2013 11:56:41 +0530 Subject: [PATCH 257/608] updated painter to be 2.1 compatible --- pdex/revisions.txt | 2 ++ .../mode/experimental/TextAreaPainter.java | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/pdex/revisions.txt b/pdex/revisions.txt index 6068571a6..7f9f65443 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -12,6 +12,8 @@ Bug fixes + Cmd + Left Click should be working again in OS X with Processing 2.1 https://github.com/processing/processing-experimental/issues/11 ++ TextAreaPainter updated for Processing 2.1 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PDE X v1.0.1b - 25 September, 2013 diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 2e28125d5..4e8b8882c 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -172,19 +172,6 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { @Override protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, int x) { - if(ta.editor.debugToolbarEnabled != null && ta.editor.debugToolbarEnabled.get()){ - // paint gutter - paintGutterBg(gfx, line, x); - - paintLineBgColor(gfx, line, x + ta.getGutterWidth()); - - paintGutterLine(gfx, line, x); - - // paint gutter symbol - paintGutterText(gfx, line, x); - - } - paintErrorLine(gfx, line, x); try { //TODO: This line is causing NPE's randomly ever since I added the toggle for //Java Mode/Debugger toolbar. @@ -192,6 +179,20 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } catch (Exception e) { log(e.getMessage()); } + if(ta.editor.debugToolbarEnabled != null && ta.editor.debugToolbarEnabled.get()){ + // paint gutter + paintGutterBg(gfx, line, x); + + // disabled line background after P5 2.1, since it adds highlight by default + //paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + + paintGutterLine(gfx, line, x); + + // paint gutter symbol + paintGutterText(gfx, line, x); + + } + paintErrorLine(gfx, line, x); } /** From 5d245fadddba905291138d588a2633b10f331720 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 21 Oct 2013 12:50:54 +0530 Subject: [PATCH 258/608] release 1.0.2b --- pdex/build.xml | 2 +- pdex/pdeX.txt | 4 ++-- pdex/revisions.txt | 5 +++-- .../processing/mode/experimental/ErrorCheckerService.java | 5 +++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pdex/build.xml b/pdex/build.xml index 3feee8a7a..2fdfc8b74 100644 --- a/pdex/build.xml +++ b/pdex/build.xml @@ -100,7 +100,7 @@ basedir="${dist}/" excludes="**/.DS_Store" /> - + diff --git a/pdex/pdeX.txt b/pdex/pdeX.txt index 0b988f675..803ecd069 100644 --- a/pdex/pdeX.txt +++ b/pdex/pdeX.txt @@ -3,5 +3,5 @@ authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. -version=4 -prettyVersion=1.0.1b +version=5 +prettyVersion=1.0.2b diff --git a/pdex/revisions.txt b/pdex/revisions.txt index 7f9f65443..ba37e8de1 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -1,12 +1,13 @@ -PDE X v1.0.2b - October, 2013 +PDE X v1.0.2b - October 21, 2013 Bug fixes + Code completion window gets stuck when Processing loses focus https://github.com/processing/processing-experimental/issues/21 -+ Live-error checker in the experimental mode is inefficient with memory. ++ Live-error checker in the experimental mode is a bit more efficient with memory now. + You can have upto 7 editor windows open at a time with PDE X. https://github.com/processing/processing-experimental/issues/1 + Cmd + Left Click should be working again in OS X with Processing 2.1 diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 62ccf3ae4..325f09f2c 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -654,7 +654,12 @@ public class ErrorCheckerService implements Runnable{ .println(e + " compileCheck() problem. Somebody tried to mess with Experimental Mode files."); pauseThread(); + } catch(OutOfMemoryError e) { + System.err.println("Processing has used up its maximum alloted memory. Please close some Processing " + + " windows and then reopen this sketch."); + pauseThread(); } + // log("Compilecheck, Done."); } From ddee3b7c63f5feaa282338095e4ebae600b18812 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 21 Oct 2013 15:04:47 +0530 Subject: [PATCH 259/608] added manual installation steps to ReadMe. --- pdex/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pdex/README.md b/pdex/README.md index af8f5efd1..b53624921 100644 --- a/pdex/README.md +++ b/pdex/README.md @@ -18,9 +18,11 @@ Find out more at [Getting Started](https://github.com/processing/processing-expe Click on the down arrow besides the mode switch button, and select Add Mode. In the Mode Manager window, select PDE X and click 'Install'. You'll need Processing 2.0.2 or higher. +For installing it manually, download the latest version from [here](http://download.processing.org/pdeX.zip). Extract the zip contents into `/modes` folder. Restart Processing. + Manindra Moharana -25 September 2013 +21 October 2013 -- PDE X is supported by [Google Summer of Code 2013](http://www.google-melange.com/gsoc/homepage/google/gsoc2013) \ No newline at end of file From dee4149ec64f8152ee9e1b275d86d482aed90239 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 21 Oct 2013 15:08:58 +0530 Subject: [PATCH 260/608] improved description --- pdex/revisions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/revisions.txt b/pdex/revisions.txt index ba37e8de1..5581f04e5 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -6,7 +6,7 @@ Bug fixes + Code completion window gets stuck when Processing loses focus https://github.com/processing/processing-experimental/issues/21 -+ Live-error checker in the experimental mode is a bit more efficient with memory now. ++ Live-error checker is more efficient with memory now. You can have upto 7 editor windows open at a time with PDE X. https://github.com/processing/processing-experimental/issues/1 From ceb59def375005d3fa83ce8e0bf60e47dea01858 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 4 Dec 2013 02:05:44 +0530 Subject: [PATCH 261/608] Updated application folder, fixes #33 --- pdex/application/Info.plist.tmpl | 75 +++++++++++++++++++++++++++++++ pdex/application/sketch.icns | Bin 0 -> 174666 bytes 2 files changed, 75 insertions(+) create mode 100644 pdex/application/Info.plist.tmpl create mode 100644 pdex/application/sketch.icns diff --git a/pdex/application/Info.plist.tmpl b/pdex/application/Info.plist.tmpl new file mode 100644 index 000000000..787f56ed2 --- /dev/null +++ b/pdex/application/Info.plist.tmpl @@ -0,0 +1,75 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + @@sketch@@ + CFBundleIconFile + sketch.icns + CFBundleIdentifier + @@sketch@@ + CFBundleDisplayName + @@sketch@@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + @@sketch@@ + CFBundlePackageType + APPL + + + CFBundleShortVersionString + 1 + CFBundleVersion + 1 + CFBundleSignature + ???? + NSHumanReadableCopyright + Your copyright here + CFBundleGetInfoString + Created with Processing + + + JVMRuntime + @@jdk_folder@@ + + JVMMainClassName + @@sketch@@ + + LSMinimumSystemVersion + 10.7.3 + + NSHighResolutionCapable + + + LSArchitecturePriority + + x86_64 + + + LSEnvironment + + LC_CTYPE + UTF-8 + + + LSUIPresentationMode + @@lsuipresentationmode@@ + + JVMOptions + + @@jvm_options_list@@ + -Xdock:icon=Contents/Resources/sketch.icns + -Dapple.laf.useScreenMenuBar=true + -Dcom.apple.macos.use-file-dialog-packages=true + -Dcom.apple.macos.useScreenMenuBar=true + -Dcom.apple.mrj.application.apple.menu.about.name=@@sketch@@ + -Dcom.apple.smallTabs=true + + JVMArguments + + + + diff --git a/pdex/application/sketch.icns b/pdex/application/sketch.icns new file mode 100644 index 0000000000000000000000000000000000000000..2bdb4dfc22bf16a82544999627970c89d7d63939 GIT binary patch literal 174666 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�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

    QXfc16$dVbe$MlV15l4Yvr8~)<% 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 z Date: Sat, 7 Dec 2013 02:56:12 +0530 Subject: [PATCH 262/608] bit of refactoring and tidying things up --- .../mode/experimental/ASTGenerator.java | 33 +++++++++++-------- .../mode/experimental/CompletionPanel.java | 6 ++-- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 00ea002b8..b026fb51c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -109,7 +109,7 @@ public class ASTGenerator { /** * AST Window */ - protected JFrame frame2; + protected JFrame frmASTView; protected JFrame frameAutoComp; @@ -153,14 +153,15 @@ public class ASTGenerator { } protected void setupGUI(){ - frame2 = new JFrame(); + frmASTView = new JFrame(); jtree = new JTree(); - frame2.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - frame2.setBounds(new Rectangle(680, 100, 460, 620)); + frmASTView.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + frmASTView.setBounds(new Rectangle(680, 100, 460, 620)); + frmASTView.setTitle("AST View - " + editor.getSketch().getName()); JScrollPane sp = new JScrollPane(); sp.setViewportView(jtree); - frame2.add(sp); + frmASTView.add(sp); btnRename = new JButton("Rename"); btnListOccurrence = new JButton("Show Usage"); @@ -231,6 +232,8 @@ public class ASTGenerator { } + + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -267,14 +270,16 @@ public class ASTGenerator { protected void done() { if (codeTree != null) { -// if (jtree.hasFocus() || frame2.hasFocus()) -// return; -// jtree.setModel(new DefaultTreeModel(codeTree)); -// ((DefaultTreeModel) jtree.getModel()).reload(); -// jtree.validate(); -// if (!frame2.isVisible()) { -// frame2.setVisible(true); -// } + if(SHOWAST){ + if (jtree.hasFocus() || frmASTView.hasFocus()) + return; + jtree.setModel(new DefaultTreeModel(codeTree)); + ((DefaultTreeModel) jtree.getModel()).reload(); + jtree.validate(); + if (!frmASTView.isVisible()) { + frmASTView.setVisible(true); + } + } // if (!frameAutoComp.isVisible()) { // // frameAutoComp.setVisible(true); @@ -3156,7 +3161,7 @@ public class ASTGenerator { } public void disposeAllWindows(){ - disposeWindow(frame2); + disposeWindow(frmASTView); disposeWindow(frameAutoComp); disposeWindow(frmImportSuggest); disposeWindow(frmOccurenceList); diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index a7fd9bbc5..7973b7610 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -60,7 +60,7 @@ public class CompletionPanel { textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - log("Suggestion constructed" + System.nanoTime()); + //log("Suggestion constructed" + System.nanoTime()); } public boolean isVisible() { @@ -130,7 +130,7 @@ public class CompletionPanel { completionList.setSelectedIndex(0); scrollPane.setViewportView(completionList); popupMenu.setPopupSize(popupMenu.getSize().width, setHeight(items.getSize())); - log("Suggestion updated" + System.nanoTime()); + //log("Suggestion updated" + System.nanoTime()); textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); @@ -176,7 +176,7 @@ public class CompletionPanel { public void hide() { popupMenu.setVisible(false); - log("Suggestion hidden" + System.nanoTime()); + //log("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.getASTGenerator().jdocWindowVisible(false); } From b1107812336ab350f6c91213b08657164e638e4d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 7 Dec 2013 03:22:16 +0530 Subject: [PATCH 263/608] Isolated the problem --- .../src/processing/mode/experimental/ASTGenerator.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index b026fb51c..25a260f53 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -566,6 +566,9 @@ public class ASTGenerator { case ASTNode.FIELD_ACCESS: FieldAccess fa = (FieldAccess) astNode; if (fa.getExpression() == null) { + + // TODO: Check for existence of 'new' keyword. Could be a ClassInstanceCreation + // Local code or belongs to super class log("FA,Not implemented."); return null; @@ -607,6 +610,7 @@ public class ASTGenerator { return new ClassMember(extracTypeInfo(temp)); } if (mi.getExpression() == null) { +// if() //Local code or belongs to super class log("MI,Not implemented."); return null; @@ -864,7 +868,11 @@ public class ASTGenerator { ASTNode testnode = parser.createAST(null); //logE("PREDICTION PARSER PROBLEMS: " + parser); // Find closest ASTNode of the document to this word - logE("Typed: " + word2 + "|"); + logE("Typed: " + word2 + "|" + " temp Node type: " + testnode.getClass().getSimpleName()); + if(testnode instanceof MethodInvocation){ + MethodInvocation mi = (MethodInvocation)testnode; + System.out.println(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size()); + } nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); if (nearestNode == null) From 5fdfc88f3d72446f5ac144ba28be4350b2e72863 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 2 Jan 2014 11:33:48 +0530 Subject: [PATCH 264/608] Outline window width fixed. Fixes #31 --- .../processing/mode/experimental/ASTGenerator.java | 2 +- .../processing/mode/experimental/SketchOutline.java | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 25a260f53..03343de33 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -233,7 +233,7 @@ public class ASTGenerator { } - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/pdex/src/processing/mode/experimental/SketchOutline.java b/pdex/src/processing/mode/experimental/SketchOutline.java index 6577adfc5..13cb72949 100644 --- a/pdex/src/processing/mode/experimental/SketchOutline.java +++ b/pdex/src/processing/mode/experimental/SketchOutline.java @@ -67,7 +67,8 @@ public class SketchOutline { //TODO: ^Absolute dimensions are bad bro - int minWidth = 200; + int minWidth = (int) (editor.getMinimumSize().width * 0.7f), + maxWidth = (int) (editor.getMinimumSize().width * 0.9f); frmOutlineView.setLayout(new BoxLayout(frmOutlineView.getContentPane(), BoxLayout.Y_AXIS)); JPanel panelTop = new JPanel(), panelBottom = new JPanel(); @@ -95,19 +96,20 @@ public class SketchOutline { jsp.setViewportView(soTree); jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - jsp.setMinimumSize(new Dimension(minWidth, 100)); + jsp.setMinimumSize(new Dimension(minWidth, editor.ta.getHeight() - 10)); + jsp.setMaximumSize(new Dimension(maxWidth, editor.ta.getHeight() - 10)); panelBottom.add(jsp); frmOutlineView.add(panelTop); frmOutlineView.add(panelBottom); frmOutlineView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frmOutlineView.pack(); frmOutlineView.setBounds(tp.x + errorCheckerService.getEditor().ta .getWidth() - minWidth, tp.y, minWidth, - Math.min(editor.ta.getHeight(), 150)); + Math.min(editor.ta.getHeight(), frmOutlineView.getHeight())); frmOutlineView.setMinimumSize(new Dimension(minWidth, Math - .min(errorCheckerService.getEditor().ta.getHeight(), 150))); - frmOutlineView.pack(); + .min(errorCheckerService.getEditor().ta.getHeight(), frmOutlineView.getHeight()))); frmOutlineView.setLocation(tp.x + errorCheckerService.getEditor().ta .getWidth() - frmOutlineView.getWidth(), From 22d5216fc49958a55c2b9bc983b3102078e9d378 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 20:28:31 +0530 Subject: [PATCH 265/608] Beginning auto save impl --- .../mode/experimental/AutoSaveUtil.java | 50 +++++++++++++++++++ .../mode/experimental/DebugEditor.java | 4 ++ 2 files changed, 54 insertions(+) create mode 100644 pdex/src/processing/mode/experimental/AutoSaveUtil.java diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java new file mode 100644 index 000000000..6e36c3595 --- /dev/null +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -0,0 +1,50 @@ +package processing.mode.experimental; + +import java.util.Timer; +import java.util.TimerTask; + +public class AutoSaveUtil { + + private DebugEditor editor; + + private Timer timer; + + private int saveTime; + + /** + * + * @param dedit + * @param timeOut - in minutes + */ + public AutoSaveUtil(DebugEditor dedit, int timeOut){ + editor = dedit; + if (timeOut < 5) { + saveTime = -1; + throw new IllegalArgumentException(""); + } + else{ + saveTime = timeOut * 60 * 1000; + } + } + + public void init(){ + if(saveTime < 1000) return; + saveTime = 1000; + timer = new Timer(); + timer.schedule(new SaveTask(), saveTime, saveTime); + } + + private class SaveTask extends TimerTask{ + + @Override + public void run() { + ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + } + + } + + public static void main(String[] args) { + + } + +} diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 953a4bffc..dcbfa4d47 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -177,6 +177,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ protected JCheckBoxMenuItem completionsEnabled; + protected AutoSaveUtil autosaver; + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -244,6 +246,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); log("Sketch Path: " + path); + autosaver = new AutoSaveUtil(this, 5); + autosaver.init(); } private void addXQModeUI(){ From e2717780683d9f690bac74e9708ebae840a26385 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:01:37 +0530 Subject: [PATCH 266/608] added save funtion --- .../mode/experimental/AutoSaveUtil.java | 146 +++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 6e36c3595..d5a72858e 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -1,8 +1,14 @@ package processing.mode.experimental; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; import java.util.Timer; import java.util.TimerTask; +import processing.app.Base; +import processing.app.Sketch; + public class AutoSaveUtil { private DebugEditor editor; @@ -29,16 +35,152 @@ public class AutoSaveUtil { public void init(){ if(saveTime < 1000) return; - saveTime = 1000; + saveTime = 3000; timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); } + private boolean saveSketch() throws IOException{ + + Sketch sc = editor.getSketch(); + File autosaveDir = new File(sc.getFolder().getAbsolutePath() + File.separator + ".autosave"); + if(!autosaveDir.exists()){ + autosaveDir = new File(sc.getFolder().getAbsolutePath(), ".autosave"); + autosaveDir.mkdir(); + } + String newParentDir = autosaveDir + File.separator + sc.getName() + System.currentTimeMillis(); + String newName = sc.getName(); + + + // check on the sanity of the name + String sanitaryName = Sketch.checkName(newName); + File newFolder = new File(newParentDir, sanitaryName); + if (!sanitaryName.equals(newName) && newFolder.exists()) { + Base.showMessage("Cannot Save", + "A sketch with the cleaned name\n" + + "“" + sanitaryName + "†already exists."); + return false; + } + newName = sanitaryName; + +// String newPath = newFolder.getAbsolutePath(); +// String oldPath = folder.getAbsolutePath(); + +// if (newPath.equals(oldPath)) { +// return false; // Can't save a sketch over itself +// } + + // make sure there doesn't exist a tab with that name already + // but ignore this situation for the first tab, since it's probably being + // resaved (with the same name) to another location/folder. + for (int i = 1; i < sc.getCodeCount(); i++) { + if (newName.equalsIgnoreCase(sc.getCode()[i].getPrettyName())) { + Base.showMessage("Nope", + "You can't save the sketch as \"" + newName + "\"\n" + + "because the sketch already has a tab with that name."); + return false; + } + } + + + + // if the new folder already exists, then first remove its contents before + // copying everything over (user will have already been warned). + if (newFolder.exists()) { + Base.removeDir(newFolder); + } + // in fact, you can't do this on Windows because the file dialog + // will instead put you inside the folder, but it happens on OS X a lot. + + // now make a fresh copy of the folder + newFolder.mkdirs(); + + // grab the contents of the current tab before saving + // first get the contents of the editor text area + if (sc.getCurrentCode().isModified()) { + sc.getCurrentCode().setProgram(editor.getText()); + } + + File[] copyItems = sc.getFolder().listFiles(new FileFilter() { + public boolean accept(File file) { + String name = file.getName(); + // just in case the OS likes to return these as if they're legit + if (name.equals(".") || name.equals("..")) { + return false; + } + // list of files/folders to be ignored during "save as" + for (String ignorable : editor.getMode().getIgnorable()) { + if (name.equals(ignorable)) { + return false; + } + } + // ignore the extensions for code, since that'll be copied below + for (String ext : editor.getMode().getExtensions()) { + if (name.endsWith(ext)) { + return false; + } + } + // don't do screen captures, since there might be thousands. kind of + // a hack, but seems harmless. hm, where have i heard that before... + if (name.startsWith("screen-")) { + return false; + } + return true; + } + }); + // now copy over the items that make sense + for (File copyable : copyItems) { + if (copyable.isDirectory()) { + Base.copyDir(copyable, new File(newFolder, copyable.getName())); + } else { + Base.copyFile(copyable, new File(newFolder, copyable.getName())); + } + } + + // save the other tabs to their new location + for (int i = 1; i < sc.getCodeCount(); i++) { + File newFile = new File(newFolder, sc.getCode()[i].getFileName()); + sc.getCode()[i].saveAs(newFile); + } + + // While the old path to the main .pde is still set, remove the entry from + // the Recent menu so that it's not sticking around after the rename. + // If untitled, it won't be in the menu, so there's no point. +// if (!isUntitled()) { +// editor.removeRecent(); +// } + + // save the main tab with its new name + File newFile = new File(newFolder, newName + ".pde"); + sc.getCode()[0].saveAs(newFile); + +// updateInternal(newName, newFolder); +// +// // Make sure that it's not an untitled sketch +// setUntitled(false); +// +// // Add this sketch back using the new name +// editor.addRecent(); + + // let Editor know that the save was successful + return true; + } + private class SaveTask extends TimerTask{ @Override public void run() { - ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + try { + saveSketch(); + ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + //editor + + } } From 3e82b2051e917b42a8a4e9632e98536e67de1bf9 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:02:38 +0530 Subject: [PATCH 267/608] updated ignorable files --- .../processing/mode/experimental/ExperimentalMode.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 9417f94c0..2ac6ad394 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -253,4 +253,14 @@ public class ExperimentalMode extends JavaMode { if(ExperimentalMode.DEBUG) System.out.print(message); } + + public String[] getIgnorable() { + return new String[] { + "applet", + "application.macosx", + "application.windows", + "application.linux", + ".autosave" + }; + } } From 31f09637240e607474997d4dcb021f4d04cac908 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:14:25 +0530 Subject: [PATCH 268/608] only single backup remains --- .../mode/experimental/AutoSaveUtil.java | 21 ++++++++++++++++++- .../mode/experimental/DebugEditor.java | 3 ++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index d5a72858e..6eacf7902 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -40,15 +40,30 @@ public class AutoSaveUtil { timer.schedule(new SaveTask(), saveTime, saveTime); } + public void shutDown(){ + timer.cancel(); + } + private boolean saveSketch() throws IOException{ Sketch sc = editor.getSketch(); File autosaveDir = new File(sc.getFolder().getAbsolutePath() + File.separator + ".autosave"); + boolean deleteOldSave = false; + String oldSave = null; if(!autosaveDir.exists()){ autosaveDir = new File(sc.getFolder().getAbsolutePath(), ".autosave"); autosaveDir.mkdir(); } - String newParentDir = autosaveDir + File.separator + sc.getName() + System.currentTimeMillis(); + else + { + // delete the previous backup after saving current one. + String prevSaves[] = Base.listFiles(autosaveDir, false); + if(prevSaves.length > 0){ + deleteOldSave = true; + oldSave = prevSaves[0]; + } + } + String newParentDir = autosaveDir + File.separator + System.currentTimeMillis(); String newName = sc.getName(); @@ -163,6 +178,10 @@ public class AutoSaveUtil { // editor.addRecent(); // let Editor know that the save was successful + + if(deleteOldSave) + Base.removeDir(new File(oldSave)); + return true; } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index dcbfa4d47..c949225e8 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -331,9 +331,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ @Override public void dispose() { + autosaver.shutDown(); //System.out.println("window dispose"); // quit running debug session - dbg.stopDebug(); + dbg.stopDebug(); // remove var.inspector vi.dispose(); errorCheckerService.stopThread(); From 3730031c25937d12b1cc5895ec031f3520c096e8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 11 Jan 2014 21:34:28 +0530 Subject: [PATCH 269/608] further work on auto save --- .../mode/experimental/AutoSaveUtil.java | 21 +++++++++++++------ .../mode/experimental/DebugEditor.java | 2 +- .../mode/experimental/ExperimentalMode.java | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 6eacf7902..5ed6f7751 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -17,6 +17,9 @@ public class AutoSaveUtil { private int saveTime; + private File autosaveDir; + + private boolean isSaving; /** * * @param dedit @@ -31,27 +34,31 @@ public class AutoSaveUtil { else{ saveTime = timeOut * 60 * 1000; } + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } public void init(){ if(saveTime < 1000) return; - saveTime = 3000; + saveTime = 10 * 1000; timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); + isSaving = false; } - public void shutDown(){ + public void stop(){ + while(isSaving); // save operation mustn't be interrupted timer.cancel(); + Base.removeDir(autosaveDir); } private boolean saveSketch() throws IOException{ - + isSaving = true; Sketch sc = editor.getSketch(); - File autosaveDir = new File(sc.getFolder().getAbsolutePath() + File.separator + ".autosave"); + boolean deleteOldSave = false; String oldSave = null; if(!autosaveDir.exists()){ - autosaveDir = new File(sc.getFolder().getAbsolutePath(), ".autosave"); + autosaveDir = new File(sc.getFolder().getAbsolutePath(), "_autosave"); autosaveDir.mkdir(); } else @@ -74,6 +81,7 @@ public class AutoSaveUtil { Base.showMessage("Cannot Save", "A sketch with the cleaned name\n" + "“" + sanitaryName + "†already exists."); + isSaving = false; return false; } newName = sanitaryName; @@ -93,6 +101,7 @@ public class AutoSaveUtil { Base.showMessage("Nope", "You can't save the sketch as \"" + newName + "\"\n" + "because the sketch already has a tab with that name."); + isSaving = false; return false; } } @@ -181,7 +190,7 @@ public class AutoSaveUtil { if(deleteOldSave) Base.removeDir(new File(oldSave)); - + isSaving = false; return true; } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index c949225e8..2fdfab086 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -331,7 +331,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ @Override public void dispose() { - autosaver.shutDown(); //System.out.println("window dispose"); // quit running debug session dbg.stopDebug(); @@ -345,6 +344,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); + autosaver.stop(); super.internalCloseRunner(); } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 2ac6ad394..faccbd060 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -260,7 +260,7 @@ public class ExperimentalMode extends JavaMode { "application.macosx", "application.windows", "application.linux", - ".autosave" + "_autosave" }; } } From 47a11b2f790761e44a48853a419cb46817648253 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 12 Jan 2014 19:23:03 +0530 Subject: [PATCH 270/608] load prev save if found --- .../mode/experimental/AutoSaveUtil.java | 17 +++++++++++++- .../mode/experimental/DebugEditor.java | 22 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 5ed6f7751..35e783534 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -17,7 +17,7 @@ public class AutoSaveUtil { private int saveTime; - private File autosaveDir; + private File autosaveDir, pastSave; private boolean isSaving; /** @@ -37,6 +37,21 @@ public class AutoSaveUtil { autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } + public boolean checkForPastSave(){ + if(autosaveDir.exists()){ + String prevSaves[] = Base.listFiles(autosaveDir, false); + if(prevSaves.length > 0){ + pastSave = new File(prevSaves[0]); + return true; + } + } + return false; + } + + public File getPastSave(){ + return pastSave; + } + public void init(){ if(saveTime < 1000) return; saveTime = 10 * 1000; diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 2fdfab086..2cd201bff 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -246,8 +246,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); log("Sketch Path: " + path); - autosaver = new AutoSaveUtil(this, 5); - autosaver.init(); + loadAutoSaver(); } private void addXQModeUI(){ @@ -870,6 +869,25 @@ public class DebugEditor extends JavaEditor implements ActionListener { } return saved; } + + public void loadAutoSaver(){ + autosaver = new AutoSaveUtil(this, 5); + if(!autosaver.checkForPastSave()) { + autosaver.init(); + return; + } + + File pastSave = autosaver.getPastSave(); + int response = Base.showYesNoQuestion(this, "Unsaved backup found!", "An automatic backup of this " + + "sketch has been found. This may mean Processing quit unexpectedly last time.", + "Select YES to view it or NO to delete the backup."); + if(response == JOptionPane.YES_OPTION){ + handleOpenInternal(pastSave.getAbsolutePath()); + } + else{ + autosaver.init(); + } + } /** * Set text contents of a specific tab. Updates underlying document and text From 7cb301e3b007298856c0c2d55c3d375bdb11c3f6 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 12 Jan 2014 19:52:33 +0530 Subject: [PATCH 271/608] load prev save better --- pdex/src/processing/mode/experimental/AutoSaveUtil.java | 7 ++++--- pdex/src/processing/mode/experimental/DebugEditor.java | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 35e783534..7120144f7 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -41,7 +41,8 @@ public class AutoSaveUtil { if(autosaveDir.exists()){ String prevSaves[] = Base.listFiles(autosaveDir, false); if(prevSaves.length > 0){ - pastSave = new File(prevSaves[0]); + File t = new File(Base.listFiles(new File(prevSaves[0]), false)[0]); + pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); return true; } } @@ -62,8 +63,8 @@ public class AutoSaveUtil { public void stop(){ while(isSaving); // save operation mustn't be interrupted - timer.cancel(); - Base.removeDir(autosaveDir); + if(timer != null) timer.cancel(); + //Base.removeDir(autosaveDir); } private boolean saveSketch() throws IOException{ diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 2cd201bff..c4a16a586 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -883,10 +883,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); + //log(getSketch().getMainFilePath()); + autosaver = new AutoSaveUtil(this, 5); } - else{ - autosaver.init(); - } + autosaver.init(); } /** From ebaab69e2aa50620931123427a610ca9aa5fc01b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 12 Jan 2014 20:04:03 +0530 Subject: [PATCH 272/608] loading prev save and restore too? Decisions --- .../processing/mode/experimental/AutoSaveUtil.java | 6 +++--- .../processing/mode/experimental/DebugEditor.java | 13 +++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 7120144f7..954097c6c 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -55,7 +55,7 @@ public class AutoSaveUtil { public void init(){ if(saveTime < 1000) return; - saveTime = 10 * 1000; + saveTime = 10 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; @@ -64,7 +64,7 @@ public class AutoSaveUtil { public void stop(){ while(isSaving); // save operation mustn't be interrupted if(timer != null) timer.cancel(); - //Base.removeDir(autosaveDir); + Base.removeDir(autosaveDir); } private boolean saveSketch() throws IOException{ @@ -216,7 +216,7 @@ public class AutoSaveUtil { public void run() { try { saveSketch(); - ExperimentalMode.log("Saved " + editor.getSketch().getMainFilePath()); + ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index c4a16a586..8bdfb9249 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -245,8 +245,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); - log("Sketch Path: " + path); - loadAutoSaver(); + log("Sketch Path: " + path); } private void addXQModeUI(){ @@ -735,6 +734,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { clearBreakpointedLines(); // force clear breakpoint highlights variableInspector().reset(); // clear contents of variable inspector } + if(autosaver != null) + autosaver.stop(); + loadAutoSaver(); + //System.out.println("LOADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"); return didOpen; } @@ -884,9 +887,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); //log(getSketch().getMainFilePath()); - autosaver = new AutoSaveUtil(this, 5); + return; + } + else{ + autosaver.init(); } - autosaver.init(); } /** From dd1c65e1d4e18cf6a60ecfcdf965685a9a61ce5e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 13 Jan 2014 20:12:08 +0530 Subject: [PATCH 273/608] auto saver work done, i guess. --- .../mode/experimental/AutoSaveUtil.java | 10 +++++++--- .../processing/mode/experimental/DebugEditor.java | 15 ++++++++++----- .../mode/experimental/ExperimentalMode.java | 7 ++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 954097c6c..f2e2ae427 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -33,6 +33,7 @@ public class AutoSaveUtil { } else{ saveTime = timeOut * 60 * 1000; + ExperimentalMode.log("AutoSaver Interval(mins): " + timeOut); } autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } @@ -42,7 +43,8 @@ public class AutoSaveUtil { String prevSaves[] = Base.listFiles(autosaveDir, false); if(prevSaves.length > 0){ File t = new File(Base.listFiles(new File(prevSaves[0]), false)[0]); - pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); + pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); + if(pastSave.exists()) return true; } } @@ -55,10 +57,11 @@ public class AutoSaveUtil { public void init(){ if(saveTime < 1000) return; - saveTime = 10 * 1000; //TODO: remove + //saveTime = 10 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; + ExperimentalMode.log("AutoSaver started"); } public void stop(){ @@ -204,8 +207,9 @@ public class AutoSaveUtil { // let Editor know that the save was successful - if(deleteOldSave) + if(deleteOldSave){ Base.removeDir(new File(oldSave)); + } isSaving = false; return true; } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 8bdfb9249..a0336a4a9 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -342,7 +342,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); - autosaver.stop(); + if(autosaver != null) autosaver.stop(); super.internalCloseRunner(); } @@ -874,18 +874,23 @@ public class DebugEditor extends JavaEditor implements ActionListener { } public void loadAutoSaver(){ - autosaver = new AutoSaveUtil(this, 5); + autosaver = new AutoSaveUtil(this, dmode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; } File pastSave = autosaver.getPastSave(); - int response = Base.showYesNoQuestion(this, "Unsaved backup found!", "An automatic backup of this " + - "sketch has been found. This may mean Processing quit unexpectedly last time.", - "Select YES to view it or NO to delete the backup."); + int response = Base + .showYesNoQuestion(this, + "Unsaved backup found!", + "An automatic backup of " + + pastSave.getParentFile().getName() + + "sketch has been found. This may mean Processing quit unexpectedly last time.", + "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); + Base.showMessage("Save it", "Remember to save the backup to a specific location if you want to."); //log(getSketch().getMainFilePath()); return; } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index faccbd060..464598459 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -119,11 +119,12 @@ public class ExperimentalMode extends JavaMode { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; + public int autoSaveInterval = 5; //in minutes public final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", - prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs"; + prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval"; public void loadPreferences(){ log("Load PDEX prefs"); @@ -133,6 +134,7 @@ public class ExperimentalMode extends JavaMode { codeCompletionsEnabled = Preferences.getBoolean(prefCodeCompletionEnabled); DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); + autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); } public void savePreferences(){ @@ -142,6 +144,7 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefCodeCompletionEnabled, codeCompletionsEnabled); Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); + Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); } public void ensurePrefsExist(){ @@ -155,6 +158,8 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefDebugOP,DEBUG); if(Preferences.get(prefErrorLogs) == null) Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); + if(Preferences.get(prefAutoSaveInterval) == null) + Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); } From 507e3ca765b2db6ad90348f20c8b3c040cb6d501 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 13 Jan 2014 20:18:22 +0530 Subject: [PATCH 274/608] oops, missed that case --- pdex/src/processing/mode/experimental/AutoSaveUtil.java | 5 +++++ pdex/src/processing/mode/experimental/DebugEditor.java | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index f2e2ae427..8811ed1d2 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -51,6 +51,11 @@ public class AutoSaveUtil { return false; } + public void reloadAutosaveDir(){ + while(isSaving); + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); + } + public File getPastSave(){ return pastSave; } diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index a0336a4a9..5bcafd126 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -842,6 +842,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { }); } } + // if file location has changed, update autosaver + autosaver.reloadAutosaveDir(); return saved; } @@ -870,10 +872,15 @@ public class DebugEditor extends JavaEditor implements ActionListener { // set new name of variable inspector vi.setTitle(getSketch().getName()); } + // if file location has changed, update autosaver + autosaver.reloadAutosaveDir(); return saved; } public void loadAutoSaver(){ + if(autosaver != null){ + autosaver.stop(); + } autosaver = new AutoSaveUtil(this, dmode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); From 27dc79e288f1e80f546fd1216d0cb6bab4ea076a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 13 Jan 2014 20:43:48 +0530 Subject: [PATCH 275/608] fixes, tidying things up for auto save --- pdex/src/processing/mode/experimental/AutoSaveUtil.java | 7 ++++--- pdex/src/processing/mode/experimental/DebugEditor.java | 6 +++--- .../src/processing/mode/experimental/ExperimentalMode.java | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 8811ed1d2..54e883c0e 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -61,7 +61,7 @@ public class AutoSaveUtil { } public void init(){ - if(saveTime < 1000) return; + if(saveTime < 10000) saveTime = 10 * 1000; //saveTime = 10 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); @@ -76,6 +76,7 @@ public class AutoSaveUtil { } private boolean saveSketch() throws IOException{ + if(!editor.getSketch().isModified()) return false; isSaving = true; Sketch sc = editor.getSketch(); @@ -224,8 +225,8 @@ public class AutoSaveUtil { @Override public void run() { try { - saveSketch(); - ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); + if(saveSketch()) + ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 5bcafd126..9e9c3064a 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -245,7 +245,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); - log("Sketch Path: " + path); + log("Sketch Path: " + path); } private void addXQModeUI(){ @@ -737,7 +737,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { if(autosaver != null) autosaver.stop(); loadAutoSaver(); - //System.out.println("LOADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"); return didOpen; } @@ -878,10 +877,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { } public void loadAutoSaver(){ + log("Load Auto Saver()"); if(autosaver != null){ autosaver.stop(); } - autosaver = new AutoSaveUtil(this, dmode.autoSaveInterval); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 464598459..87b190d21 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -119,9 +119,9 @@ public class ExperimentalMode extends JavaMode { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; - public int autoSaveInterval = 5; //in minutes + public static int autoSaveInterval = 5; //in minutes - public final String prefErrorCheck = "pdex.errorCheckEnabled", + public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval"; From e90ebc461acd1336c9a09dbfcae7b8e72a9be7ec Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Sat, 18 Jan 2014 01:40:23 +0530 Subject: [PATCH 276/608] Added ProgressBarGUI class, and modified saveAs(). ProgressBar now shows properly for all files within the main sketch folder, but not within sub-folders. To Do: 1. Make ProgressBar take into account files that have already been copied within sub-folders in the sketch, and not onlyafter the entire folder has been copied. 2. Rename "Saving X As Y..." with "Saving As " 3. The progress made for very large files is shown only after the ENTIRE file has been copied. Modify processing.app.Base as well so that for large files, the ProgressBar is updated in (almost) real time 4. Make "Done Saving" appear in Message Area only after the entire Save As operation is complete --- app/src/processing/app/Sketch.java | 165 +++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 9 deletions(-) diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 669452b8c..b3af66a54 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -30,6 +30,9 @@ import java.io.*; import javax.swing.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + /** * Stores information about files in the current sketch. @@ -759,7 +762,7 @@ public class Sketch { if (!sanitaryName.equals(newName) && newFolder.exists()) { Base.showMessage("Cannot Save", "A sketch with the cleaned name\n" + - "“" + sanitaryName + "†already exists."); + "“" + sanitaryName + "â€� already exists."); return false; } newName = sanitaryName; @@ -847,20 +850,26 @@ public class Sketch { return true; } }); - // now copy over the items that make sense - for (File copyable : copyItems) { - if (copyable.isDirectory()) { - Base.copyDir(copyable, new File(newFolder, copyable.getName())); - } else { - Base.copyFile(copyable, new File(newFolder, copyable.getName())); - } - } + + final File newFolder2 = newFolder; + final File[] copyItems2 = copyItems; + + // create a new event dispatch thread + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + ProgressBarGUI p = new ProgressBarGUI(copyItems2,newFolder2); + } + }); + + // save the other tabs to their new location for (int i = 1; i < codeCount; i++) { File newFile = new File(newFolder, code[i].getFileName()); code[i].saveAs(newFile); } + + // While the old path to the main .pde is still set, remove the entry from // the Recent menu so that it's not sticking around after the rename. @@ -886,6 +895,143 @@ public class Sketch { } + + private class ProgressBarGUI extends JFrame implements + PropertyChangeListener { + + private static final long serialVersionUID = 1L; + private JProgressBar progressBar; + private JLabel saveAsLabel; + private Task t; + private File[] copyItems; + private File newFolder; + + // create a new background thread + private class Task extends SwingWorker { + + @Override + protected Void doInBackground() throws Exception { + // a large part of the file copying happens in this background + // thread + + long totalSize = 0; + for (File copyable : copyItems) { + totalSize += getFileLength(copyable); + } + + int i = 0; + + long progress = 0; + setProgress(0); + for (File copyable : ProgressBarGUI.this.copyItems) + // loop to copy over the items that make sense, and to set the + // current progress + { + if (copyable.isDirectory()) { + Base.copyDir(copyable, + new File(ProgressBarGUI.this.newFolder, + copyable.getName())); + } else { + Base.copyFile(copyable, + new File(ProgressBarGUI.this.newFolder, + copyable.getName())); + } + progress += getFileLength(copyable); + setProgress((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + + System.out.println(""+(int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + + } + + return null; + } + + @Override + public void done() { + // to close the progress bar automatically when done + ProgressBarGUI.this.closeProgressBar(); + } + + } + + public ProgressBarGUI(File[] c, File nf) { + // initialize a copyItems and newFolder, which are used for file + // copying in the background thread + copyItems = c; + newFolder = nf; + + // the UI of the progres bar follows + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + setBounds(200, 200, 400, 140); + setResizable(false); + setTitle("Saving As..."); + JPanel panel = new JPanel(null); + add(panel); + setContentPane(panel); + saveAsLabel = new JLabel("Saving X as Y..."); + saveAsLabel.setBounds(40, 20, 150, 20); + + progressBar = new JProgressBar(0, 100); + progressBar.setValue(0); + progressBar.setBounds(40, 50, 300, 30); + progressBar.setStringPainted(true); + + panel.add(progressBar); + panel.add(saveAsLabel); + Toolkit.setIcon(this); + this.setVisible(true); + + // create an instance of Task and run execute() on this instance to + // start background thread + t = new Task(); + t.addPropertyChangeListener(this); + t.execute(); + } + + private long getFileLength(File f)// function to return the length of + // the file, or + // ENTIRE directory, including the + // component files + // and sub-folders if passed + { + long fol_len = 0; + if (f.isDirectory()) { + String files[] = f.list(); + for (int i = 0; i < files.length; i++) { + File temp = new File(f, files[i]); + if (temp.isDirectory()) { + fol_len += getFileLength(temp); + } else { + fol_len += (long) (temp.length()); + } + } + } else { + return (long) (f.length()); + } + return fol_len; + } + + public void propertyChange(PropertyChangeEvent evt) + // detects a change in the property of the background task, i.e., is + // called when the size of files already copied changes + { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + + private void closeProgressBar() + // closes progress bar + { + this.dispose(); + } + + } + + /** * Update internal state for new sketch name or folder location. */ @@ -912,6 +1058,7 @@ public class Sketch { editor.updateTitle(); editor.base.rebuildSketchbookMenus(); // editor.header.rebuild(); + } From 848a38096ef5d99307d03b928f95986c74579c40 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 21 Jan 2014 16:25:18 +0530 Subject: [PATCH 277/608] last few minor touches --- pdex/src/processing/mode/experimental/DebugEditor.java | 7 ++++--- .../src/processing/mode/experimental/ExperimentalMode.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 9e9c3064a..5c7cf945b 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -891,13 +891,14 @@ public class DebugEditor extends JavaEditor implements ActionListener { int response = Base .showYesNoQuestion(this, "Unsaved backup found!", - "An automatic backup of " + "An automatic backup of \"" + pastSave.getParentFile().getName() - + "sketch has been found. This may mean Processing quit unexpectedly last time.", + + "\" sketch has been found. This may mean Processing " + + "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ handleOpenInternal(pastSave.getAbsolutePath()); - Base.showMessage("Save it", "Remember to save the backup to a specific location if you want to."); + Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); return; } diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 87b190d21..a75670057 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -119,7 +119,7 @@ public class ExperimentalMode extends JavaMode { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; - public static int autoSaveInterval = 5; //in minutes + public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", From 539368224c38dac065cc6a319812f6de4eb31cfb Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 21 Jan 2014 16:45:03 +0530 Subject: [PATCH 278/608] release notes --- pdex/pdeX.txt | 4 ++-- pdex/revisions.txt | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pdex/pdeX.txt b/pdex/pdeX.txt index 803ecd069..2cc551f78 100644 --- a/pdex/pdeX.txt +++ b/pdex/pdeX.txt @@ -3,5 +3,5 @@ authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. -version=5 -prettyVersion=1.0.2b +version=6 +prettyVersion=1.0.3b diff --git a/pdex/revisions.txt b/pdex/revisions.txt index 5581f04e5..3d99c4f5f 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -1,4 +1,22 @@ +PDE X v1.0.3b - January 21, 2014 + +New Feature + ++ PDE X now saves a backup of your sketch every 3 minutes(configurable in preferences.txt). +In case of an unexpected crash, this should save the day! +https://github.com/processing/processing-experimental/issues/36 + +Bug fixes + ++ Outline Window width is now fixed +https://github.com/processing/processing-experimental/issues/31 + ++ Export Application works again on OS X +https://github.com/processing/processing-experimental/issues/33 + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + PDE X v1.0.2b - October 21, 2013 Bug fixes From eae5d2ee91abbe92f73b24b75e49ed1f371774de Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 21 Jan 2014 18:45:31 +0530 Subject: [PATCH 279/608] Major Blooper :( --- pdex/src/processing/mode/experimental/AutoSaveUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 54e883c0e..458660387 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -27,7 +27,7 @@ public class AutoSaveUtil { */ public AutoSaveUtil(DebugEditor dedit, int timeOut){ editor = dedit; - if (timeOut < 5) { + if (timeOut < 1) { // less than 1 minute not allowed! saveTime = -1; throw new IllegalArgumentException(""); } From 645068ddf63948fe870e251c080f8705a37961db Mon Sep 17 00:00:00 2001 From: AmnonOwed Date: Wed, 22 Jan 2014 21:14:11 +0100 Subject: [PATCH 280/608] Ensure RGB pixels are fully opaque --- core/src/processing/core/PImage.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java index 430d67228..ed17683d7 100644 --- a/core/src/processing/core/PImage.java +++ b/core/src/processing/core/PImage.java @@ -283,10 +283,14 @@ public class PImage implements PConstants, Cloneable { width = bi.getWidth(); height = bi.getHeight(); pixels = new int[width * height]; - WritableRaster raster = bi.getRaster(); - raster.getDataElements(0, 0, width, height, pixels); - if (bi.getType() == BufferedImage.TYPE_INT_ARGB) { + pixels = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData(); + int type = bi.getType(); + if (type == BufferedImage.TYPE_INT_ARGB) { format = ARGB; + } else if (type == BufferedImage.TYPE_INT_RGB) { + for (int i = 0; i < pixels.length; i++) { + pixels[i] = (255 << 24) | pixels[i]; + } } } else { // go the old school java 1.0 route From 2f53dd55665d85b20a769dc8cf7a5d2de463a703 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 13:35:54 +0530 Subject: [PATCH 281/608] javadoc update for TextArea --- .../mode/experimental/TextArea.java | 61 +++++++++++++------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index 8025f96b3..b74d484c4 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Martin Leopold + * Copyright (C) 2012-14 Martin Leopold and Manindra Moharana * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software @@ -127,6 +127,10 @@ public class TextArea extends JEditTextArea { customPainter.setECSandTheme(ecs, mode); } + /** + * Handles KeyEvents for TextArea + * Code completion begins from here. + */ public void processKeyEvent(KeyEvent evt) { if(evt.getKeyCode() == KeyEvent.VK_ESCAPE){ @@ -215,7 +219,11 @@ public class TextArea extends JEditTextArea { } - + /** + * Retrieves the word on which the mouse pointer is present + * @param evt - the MouseEvent which triggered this method + * @return + */ private String fetchPhrase(MouseEvent evt) { log("--handle Mouse Right Click--"); int off = xyToOffset(evt.getX(), evt.getY()); @@ -276,6 +284,14 @@ public class TextArea extends JEditTextArea { return word.trim(); } } + + /** + * Retrieves the current word typed just before the caret. + * Then triggers code completion for that word. + * + * @param evt - the KeyEvent which triggered this method + * @return + */ private String fetchPhrase(KeyEvent evt) { int off = getCaretPosition(); @@ -361,29 +377,29 @@ public class TextArea extends JEditTextArea { break; } -// if (x2 >= 0 && x2 < s.length()) { -// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' -// || s.charAt(x2) == '$') -// word = word + s.charAt(x2++); -// else -// x2 = -1; -// } else -// x2 = -1; - -// if (x1 < 0 )//&& x2 < 0 -// break; + // if (x2 >= 0 && x2 < s.length()) { + // if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + // || s.charAt(x2) == '$') + // word = word + s.charAt(x2++); + // else + // x2 = -1; + // } else + // x2 = -1; + + // if (x1 < 0 )//&& x2 < 0 + // break; if (i > 200) { // time out! break; } } -// if (keyChar != KeyEvent.CHAR_UNDEFINED) + // if (keyChar != KeyEvent.CHAR_UNDEFINED) if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); -// if (word.endsWith(".")) -// word = word.substring(0, word.length() - 1); + // if (word.endsWith(".")) + // word = word.substring(0, word.length() - 1); int lineStartNonWSOffset = 0; if(word.length() > 1) errorCheckerService.getASTGenerator().preparePredictions(word, line @@ -664,7 +680,7 @@ public class TextArea extends JEditTextArea { //JEditTextArea textarea; - // worthless + /* No longer used private void addCompletionPopupListner() { this.addKeyListener(new KeyListener() { @@ -695,7 +711,7 @@ public class TextArea extends JEditTextArea { public void keyPressed(KeyEvent e) { } }); - } + }*/ public void showSuggestionLater(final DefaultListModel defListModel, final String word) { SwingUtilities.invokeLater(new Runnable() { @@ -707,6 +723,12 @@ public class TextArea extends JEditTextArea { }); } + /** + * Calculates location of caret and displays the suggestion popup at the location. + * + * @param defListModel + * @param subWord + */ protected void showSuggestion(DefaultListModel defListModel,String subWord) { hideSuggestion(); if (defListModel.size() == 0) { @@ -745,6 +767,9 @@ public class TextArea extends JEditTextArea { // }); } + /** + * Hides suggestion popup + */ protected void hideSuggestion() { if (suggestion != null) { suggestion.hide(); From 7e2bc0e2dbc1fba5ecd620cfb8ee037980bd20a2 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 13:50:19 +0530 Subject: [PATCH 282/608] javadoc update for ASTNodeWrapper --- .../mode/experimental/ASTNodeWrapper.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 9e99ad5fd..b980f1518 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.log2; @@ -19,6 +37,11 @@ import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.jdt.core.dom.TypeDeclaration; +/** + * Wrapper class for ASTNode objects + * @author Manindra Moharana + * + */ public class ASTNodeWrapper { private ASTNode Node; @@ -142,7 +165,7 @@ public class ASTNodeWrapper { /** - * + * Finds the difference in pde and java code offsets * @param source * @param inpOffset * @param nodeLen @@ -354,6 +377,13 @@ public class ASTNodeWrapper { return new int[][]{javaCodeMap,pdeCodeMap}; } + /** + * Gets offset mapping between java and pde code + * int[0][x] stores the java code offset and + * int[1][x] is the corresponding offset in pde code + * @param ecs + * @return int[0] - java code offset, int[1] - pde code offset + */ public int[][] getOffsetMapping(ErrorCheckerService ecs){ int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); From 83a542bf366fdf1c15734a8a193d2ab921a82538 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 13:55:44 +0530 Subject: [PATCH 283/608] javadoc update for AutoSaveUtil --- .../mode/experimental/AutoSaveUtil.java | 60 ++++++++++++++++--- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 458660387..71b224528 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import java.io.File; @@ -9,6 +27,13 @@ import java.util.TimerTask; import processing.app.Base; import processing.app.Sketch; +/** + * Autosave utility for saving sketch backups in the background after + * certain intervals + * + * @author Manindra Moharana + * + */ public class AutoSaveUtil { private DebugEditor editor; @@ -20,10 +45,11 @@ public class AutoSaveUtil { private File autosaveDir, pastSave; private boolean isSaving; + /** * * @param dedit - * @param timeOut - in minutes + * @param timeOut - in minutes, how frequently should saves occur */ public AutoSaveUtil(DebugEditor dedit, int timeOut){ editor = dedit; @@ -38,6 +64,10 @@ public class AutoSaveUtil { autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } + /** + * Check if any previous autosave exists + * @return + */ public boolean checkForPastSave(){ if(autosaveDir.exists()){ String prevSaves[] = Base.listFiles(autosaveDir, false); @@ -51,6 +81,9 @@ public class AutoSaveUtil { return false; } + /** + * Refresh autosave directory if current sketch location in the editor changes + */ public void reloadAutosaveDir(){ while(isSaving); autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); @@ -60,6 +93,9 @@ public class AutoSaveUtil { return pastSave; } + /** + * Start the auto save service + */ public void init(){ if(saveTime < 10000) saveTime = 10 * 1000; //saveTime = 10 * 1000; //TODO: remove @@ -69,12 +105,21 @@ public class AutoSaveUtil { ExperimentalMode.log("AutoSaver started"); } + /** + * Stop the autosave service + */ public void stop(){ while(isSaving); // save operation mustn't be interrupted if(timer != null) timer.cancel(); Base.removeDir(autosaveDir); } + /** + * Main function that performs the save operation + * Code reused from processing.app.Sketch.saveAs() + * @return + * @throws IOException + */ private boolean saveSketch() throws IOException{ if(!editor.getSketch().isModified()) return false; isSaving = true; @@ -220,6 +265,11 @@ public class AutoSaveUtil { return true; } + /** + * Timertask used to perform the save operation every X minutes + * @author quarkninja + * + */ private class SaveTask extends TimerTask{ @Override @@ -228,19 +278,11 @@ public class AutoSaveUtil { if(saveSketch()) ExperimentalMode.log("Backup Saved " + editor.getSketch().getMainFilePath()); } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } - //editor - - } } - public static void main(String[] args) { - - } - } From 5f54d4fe72ab7fac34d3a41c8be0d9b919311a31 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:06:46 +0530 Subject: [PATCH 284/608] javadoc update for CompletionPanel --- .../mode/experimental/CompletionPanel.java | 77 ++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 7973b7610..ab32e4b7d 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.logE; @@ -23,21 +41,51 @@ import javax.swing.text.BadLocationException; import processing.app.syntax.JEditTextArea; +/** + * Manages the actual suggestion popup that gets displayed + * @author Manindra Moharana + * + */ public class CompletionPanel { + + /** + * The completion list generated by ASTGenerator + */ private JList completionList; + /** + * The popup menu in which the suggestion list is shown + */ private JPopupMenu popupMenu; + /** + * Partial word which triggered the code completion and which needs to be completed + */ private String subWord; + /** + * Postion where the completion has to be inserted + */ private int insertionPosition; private TextArea textarea; + /** + * Scroll pane in which the completion list is displayed + */ private JScrollPane scrollPane; protected DebugEditor editor; + /** + * Triggers the completion popup + * @param textarea + * @param position - insertion position(caret pos) + * @param subWord - Partial word which triggered the code completion and which needs to be completed + * @param items - completion candidates + * @param location - Point location where popup list is to be displayed + * @param dedit + */ public CompletionPanel(final JEditTextArea textarea, int position, String subWord, DefaultListModel items, final Point location, DebugEditor dedit) { this.textarea = (TextArea) textarea; @@ -72,7 +120,7 @@ public class CompletionPanel { popupMenu.setVisible(v); } - protected int setHeight(int itemCount){ + private int setHeight(int itemCount){ if(scrollPane.getHorizontalScrollBar().isVisible()) itemCount++; FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); float h = (fm.getHeight() + fm.getDescent()*0.5f) * (itemCount + 1); @@ -94,6 +142,12 @@ public class CompletionPanel { return Math.min(280,(int)min); // popup menu height }*/ + /** + * Created the popup list to be displayed + * @param position + * @param items + * @return + */ private JList createSuggestionList(final int position, final DefaultListModel items) { @@ -142,6 +196,10 @@ public class CompletionPanel { return true; } + /** + * Inserts the CompletionCandidate chosen from the suggestion list + * @return + */ public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { @@ -174,12 +232,18 @@ public class CompletionPanel { return false; } + /** + * Hide the suggestion list + */ public void hide() { popupMenu.setVisible(false); //log("Suggestion hidden" + System.nanoTime()); //textarea.errorCheckerService.getASTGenerator().jdocWindowVisible(false); } + /** + * When up arrow key is pressed, moves the highlighted selection up in the list + */ public void moveUp() { if (completionList.getSelectedIndex() == 0) { scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); @@ -200,6 +264,9 @@ public class CompletionPanel { } + /** + * When down arrow key is pressed, moves the highlighted selection down in the list + */ public void moveDown() { if (completionList.getSelectedIndex() == completionList.getModel().getSize() - 1) { scrollPane.getVerticalScrollBar().setValue(0); @@ -231,7 +298,13 @@ public class CompletionPanel { // }); } - protected class CustomListRenderer extends + + /** + * Custom cell renderer to display icons along with the completion candidates + * @author Manindra Moharana + * + */ + private class CustomListRenderer extends javax.swing.DefaultListCellRenderer { //protected final ImageIcon classIcon, fieldIcon, methodIcon; From a04d6c6c474c7456fb13dd935302708e0d93fc4c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:11:55 +0530 Subject: [PATCH 285/608] javadoc update for DebugEditor --- .../mode/experimental/DebugEditor.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 5c7cf945b..74f9abcd8 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -346,6 +346,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { super.internalCloseRunner(); } + /** + * Writes all error messages to a csv file. + * For analytics purposes only. + */ private void writeErrorsToFile(){ if (errorCheckerService.tempErrorLog.size() == 0) return; @@ -417,9 +421,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); }*/ + /** + * Whether debug toolbar is enabled + */ AtomicBoolean debugToolbarEnabled; + protected EditorToolbar javaToolbar, debugToolbar; + /** + * Toggles between java mode and debug mode toolbar + */ protected void switchToolbars(){ final EditorToolbar nextToolbar; if(debugToolbarEnabled.get()){ @@ -876,6 +887,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { return saved; } + /** + * Loads and starts the auto save service + * Also handles the case where an auto save backup is found. + * The user is asked to save the sketch to a new location + */ public void loadAutoSaver(){ log("Load Auto Saver()"); if(autosaver != null){ @@ -1376,17 +1392,27 @@ public class DebugEditor extends JavaEditor implements ActionListener { return errorTable.updateTable(tableModel); } + /** + * Handle whether the tiny red error indicator is shown near the error button + * at the bottom of the PDE + */ public void updateErrorToggle(){ btnShowErrors.updateMarker(errorCheckerService.hasErrors(), errorBar.errorColor); } + /** + * Handle refactor operation + */ private void handleRefactor() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); errorCheckerService.getASTGenerator().handleRefactor(); } + /** + * Handle show usage operation + */ private void handleShowUsage() { log("Caret at:"); log(ta.getLineText(ta.getCaretLine())); From ad54beb61933c5737ead380477af2dc3ee5a84ad Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:13:00 +0530 Subject: [PATCH 286/608] javadoc update for DebugEditor2 --- pdex/src/processing/mode/experimental/DebugEditor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 74f9abcd8..02e698be4 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Martin Leopold + * Copyright (C) 2012-14 Martin Leopold and Manindra Moharana * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software From f36a21a00a99734cb60ff8bdb3eb9613923e6a25 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 31 Jan 2014 14:14:02 +0530 Subject: [PATCH 287/608] javadoc update for ECS --- .../experimental/ErrorCheckerService.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 325f09f2c..307cd3b53 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; @@ -42,6 +59,12 @@ import processing.app.syntax.SyntaxDocument; import processing.core.PApplet; import processing.mode.java.preproc.PdePreprocessor; +/** + * The main error checking service + * + * @author Manindra Moharana <me@mkmoharana.com> + * + */ public class ErrorCheckerService implements Runnable{ protected DebugEditor editor; From 6f0195534f97934648c3bdb707956730c6abccc8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 00:36:33 +0530 Subject: [PATCH 288/608] beginning work on race condition bug --- .../mode/experimental/ASTGenerator.java | 16 ++- .../mode/experimental/CompletionPanel.java | 121 +++++++++++++++++- .../mode/experimental/TextArea.java | 5 +- 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 03343de33..4d7602eaa 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import javax.swing.BorderFactory; @@ -150,6 +151,7 @@ public class ASTGenerator { //addCompletionPopupListner(); addListeners(); //loadJavaDoc(); + predictionOngoing = new AtomicBoolean(false); } protected void setupGUI(){ @@ -784,15 +786,24 @@ public class ASTGenerator { //protected AtomicBoolean predictionsEnabled; protected int predictionMinLength = 2; + + private AtomicBoolean predictionOngoing; + public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { + if(predictionOngoing.get()) return; + if(!ExperimentalMode.codeCompletionsEnabled) return; - if(word.length() < predictionMinLength) return; + if(word.length() < predictionMinLength) return; + + predictionOngoing.set(true); // This method is called from TextArea.fetchPhrase, which is called via a SwingWorker instance // in TextArea.processKeyEvent if(caretWithinLineComment()){ log("No predictions."); + predictionOngoing.set(false); return; } + // SwingWorker worker = new SwingWorker() { // // @Override @@ -826,6 +837,7 @@ public class ASTGenerator { } showPredictions(word); lastPredictedWord = word2; + predictionOngoing.set(false); return; } } @@ -1006,7 +1018,7 @@ public class ASTGenerator { } showPredictions(word); - + predictionOngoing.set(false); // } // }; // diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index ab32e4b7d..610be8c3e 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -18,6 +18,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.log2; import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; @@ -25,6 +26,7 @@ import java.awt.Color; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Point; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Iterator; @@ -108,7 +110,7 @@ public class CompletionPanel { textarea.requestFocusInWindow(); popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0) + location.y); - //log("Suggestion constructed" + System.nanoTime()); + log("Suggestion shown: " + System.currentTimeMillis()); } public boolean isVisible() { @@ -205,7 +207,7 @@ public class CompletionPanel { try { String selectedSuggestion = ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString().substring(subWord.length()); - logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion); + logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion + " Current sub: " + fetchPhrase()); textarea.getDocument().remove(insertionPosition-subWord.length(), subWord.length()); textarea.getDocument().insertString(insertionPosition-subWord.length(), ((CompletionCandidate) completionList @@ -223,6 +225,7 @@ public class CompletionPanel { else { textarea.setCaretPosition(insertionPosition + selectedSuggestion.length()); } + log("Suggestion inserted: " + System.currentTimeMillis()); return true; } catch (BadLocationException e1) { e1.printStackTrace(); @@ -231,6 +234,120 @@ public class CompletionPanel { } return false; } + + private String fetchPhrase() { + TextArea ta = editor.ta; + int off = ta.getCaretPosition(); + log2("off " + off); + if (off < 0) + return null; + int line = ta.getCaretLine(); + if (line < 0) + return null; + String s = ta.getLineText(line); + log2("lin " + line); + /* + * if (s == null) return null; else if (s.length() == 0) return null; + */ +// else { + //log2(s + " len " + s.length()); + + int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + if(x >= s.length() || x < 0) + return null; //TODO: Does this check cause problems? Verify. + log2(" x char: " + s.charAt(x)); + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); + + String word = (x < s.length() ? s.charAt(x) : "") + ""; + if (s.trim().length() == 1) { +// word = "" +// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; + word = word.trim(); + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); + + return word; + } +// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) +// ; // accepted these keys +// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) +// return null; + int i = 0; + int closeB = 0; + + while (true) { + i++; + //TODO: currently works on single line only. "a. b()" won't be detected + if (x1 >= 0) { +// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' + || s.charAt(x1) == '.' || s.charAt(x1) == ')' || s.charAt(x1) == ']') { + + if (s.charAt(x1) == ')') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '(') + closeB--; + if (s.charAt(x1) == ')') + closeB++; + x1--; + } + } + else if (s.charAt(x1) == ']') { + word = s.charAt(x1--) + word; + closeB++; + while (x1 >= 0 && closeB > 0) { + word = s.charAt(x1) + word; + if (s.charAt(x1) == '[') + closeB--; + if (s.charAt(x1) == ']') + closeB++; + x1--; + } + } + else { + word = s.charAt(x1--) + word; + } + } else { + break; + } + } else { + break; + } + + // if (x2 >= 0 && x2 < s.length()) { + // if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' + // || s.charAt(x2) == '$') + // word = word + s.charAt(x2++); + // else + // x2 = -1; + // } else + // x2 = -1; + + // if (x1 < 0 )//&& x2 < 0 + // break; + if (i > 200) { + // time out! + break; + } + } + // if (keyChar != KeyEvent.CHAR_UNDEFINED) + + if (Character.isDigit(word.charAt(0))) + return null; + word = word.trim(); + // if (word.endsWith(".")) + // word = word.substring(0, word.length() - 1); + if(word.length() > 1) + + //showSuggestionLater(); + return word; + else return ""; + //} + } /** * Hide the suggestion list diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index b74d484c4..6657353ff 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -205,11 +205,12 @@ public class TextArea extends JEditTextArea { final KeyEvent evt2 = evt; SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { + log("[KeyEvent]" + evt2.getKeyChar() + " |Prediction started: " + System.currentTimeMillis()); errorCheckerService.runManualErrorCheck(); // Provide completions only if it's enabled if(ExperimentalMode.codeCompletionsEnabled) - log(" Typing: " + fetchPhrase(evt2) + " " - + (evt2.getKeyChar() == KeyEvent.VK_ENTER)); + log("Typing: " + fetchPhrase(evt2) + " " + + (evt2.getKeyChar() == KeyEvent.VK_ENTER) + " T: " + System.currentTimeMillis()); return null; } }; From 018ff34c96c03e8e5458e087cf980c11c81c3e71 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 01:23:38 +0530 Subject: [PATCH 289/608] hopefully fixes the tricky #38 --- .../mode/experimental/CompletionPanel.java | 94 ++++++------------- 1 file changed, 30 insertions(+), 64 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 610be8c3e..4eae592e4 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -199,31 +199,37 @@ public class CompletionPanel { } /** - * Inserts the CompletionCandidate chosen from the suggestion list + * Inserts the CompletionCandidate chosen from the suggestion list + * * @return */ public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { + String currentSubword = fetchCurrentSubword(); String selectedSuggestion = ((CompletionCandidate) completionList - .getSelectedValue()).getCompletionString().substring(subWord.length()); - logE(subWord+" <= subword,Inserting suggestion=> " + selectedSuggestion + " Current sub: " + fetchPhrase()); - textarea.getDocument().remove(insertionPosition-subWord.length(), subWord.length()); - textarea.getDocument().insertString(insertionPosition-subWord.length(), - ((CompletionCandidate) completionList - .getSelectedValue()).getCompletionString(), null); - if(selectedSuggestion.endsWith(")")) - { - if(!selectedSuggestion.endsWith("()")){ + .getSelectedValue()).getCompletionString().substring(currentSubword + .length()); + logE(subWord + " <= subword,Inserting suggestion=> " + + selectedSuggestion + " Current sub: " + currentSubword); + textarea.getDocument().remove(insertionPosition + - currentSubword.length(), + currentSubword.length()); + textarea.getDocument() + .insertString(insertionPosition - currentSubword.length(), + ((CompletionCandidate) completionList + .getSelectedValue()).getCompletionString(), null); + if (selectedSuggestion.endsWith(")")) { + if (!selectedSuggestion.endsWith("()")) { int x = selectedSuggestion.indexOf('('); - if(x != -1){ + if (x != -1) { //log("X................... " + x); - textarea.setCaretPosition(insertionPosition + (x+1)); + textarea.setCaretPosition(insertionPosition + (x + 1)); } } - } - else { - textarea.setCaretPosition(insertionPosition + selectedSuggestion.length()); + } else { + textarea.setCaretPosition(insertionPosition + + selectedSuggestion.length()); } log("Suggestion inserted: " + System.currentTimeMillis()); return true; @@ -235,17 +241,17 @@ public class CompletionPanel { return false; } - private String fetchPhrase() { + private String fetchCurrentSubword() { TextArea ta = editor.ta; int off = ta.getCaretPosition(); - log2("off " + off); + //log2("off " + off); if (off < 0) return null; int line = ta.getCaretLine(); if (line < 0) return null; String s = ta.getLineText(line); - log2("lin " + line); + //log2("lin " + line); /* * if (s == null) return null; else if (s.length() == 0) return null; */ @@ -255,7 +261,7 @@ public class CompletionPanel { int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. - log2(" x char: " + s.charAt(x)); + //log2(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; @@ -281,54 +287,16 @@ public class CompletionPanel { //TODO: currently works on single line only. "a. b()" won't be detected if (x1 >= 0) { // if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(') - if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_' - || s.charAt(x1) == '.' || s.charAt(x1) == ')' || s.charAt(x1) == ']') { + if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_') { + + word = s.charAt(x1--) + word; - if (s.charAt(x1) == ')') { - word = s.charAt(x1--) + word; - closeB++; - while (x1 >= 0 && closeB > 0) { - word = s.charAt(x1) + word; - if (s.charAt(x1) == '(') - closeB--; - if (s.charAt(x1) == ')') - closeB++; - x1--; - } - } - else if (s.charAt(x1) == ']') { - word = s.charAt(x1--) + word; - closeB++; - while (x1 >= 0 && closeB > 0) { - word = s.charAt(x1) + word; - if (s.charAt(x1) == '[') - closeB--; - if (s.charAt(x1) == ']') - closeB++; - x1--; - } - } - else { - word = s.charAt(x1--) + word; - } } else { break; } } else { break; } - - // if (x2 >= 0 && x2 < s.length()) { - // if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_' - // || s.charAt(x2) == '$') - // word = word + s.charAt(x2++); - // else - // x2 = -1; - // } else - // x2 = -1; - - // if (x1 < 0 )//&& x2 < 0 - // break; if (i > 200) { // time out! break; @@ -339,13 +307,11 @@ public class CompletionPanel { if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); - // if (word.endsWith(".")) - // word = word.substring(0, word.length() - 1); - if(word.length() > 1) + if (word.endsWith(".")) + word = word.substring(0, word.length() - 1); //showSuggestionLater(); return word; - else return ""; //} } From e6fb7e31b7afb52f81151db51a7dcfd8359374c4 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Sun, 2 Feb 2014 01:34:26 +0530 Subject: [PATCH 290/608] Improved significantly on ProgressBar Improvements 1,2 and 4 as mentioned in the last commit have been implemented, i.e., ProgressBar now takes into account files within sub-folders, the Label now reads properly in the "Save As progress" dialog box, and "Done Saving" message appears in the message area only after the entire process is completed. To do: 1. Ensure progress bar reflects large files accurately 2. Add comments, minor clean-up --- app/src/processing/app/Base.java | 15 ++++++----- app/src/processing/app/Editor.java | 5 +++- app/src/processing/app/Sketch.java | 43 +++++++++++++++++------------- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 50230531b..a9332c94e 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1592,7 +1592,7 @@ public class Base { } - // Because the Oracle JDK is 64-bit only, we lose this ability, feature, + // Because the Oracle JDK is 64-bit only, we lose this ability, feature, // edge case, headache. // /** // * Return whether sketches will run as 32- or 64-bits. On Linux and Windows, @@ -1605,10 +1605,10 @@ public class Base { // } // return nativeBits; // } - - /** + + /** * Return whether sketches will run as 32- or 64-bits based - * on the JVM that's in use. + * on the JVM that's in use. */ static public int getNativeBits() { return nativeBits; @@ -2649,7 +2649,7 @@ public class Base { * files and potentially troublesome .svn folders. */ static public void copyDir(File sourceDir, - File targetDir) throws IOException { + File targetDir,Sketch.ProgressBarGUI.Task progBar,double progress,double totalSize) throws IOException { if (sourceDir.equals(targetDir)) { final String urDum = "source and target directories are identical"; throw new IllegalArgumentException(urDum); @@ -2664,10 +2664,13 @@ public class Base { File target = new File(targetDir, files[i]); if (source.isDirectory()) { //target.mkdirs(); - copyDir(source, target); + copyDir(source, target, progBar, progress, totalSize); target.setLastModified(source.lastModified()); } else { copyFile(source, target); + progress += source.length(); + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); } } } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 3463555e0..240edaf51 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2361,7 +2361,10 @@ public abstract class Editor extends JFrame implements RunnerListener { statusNotice("Saving..."); try { if (sketch.saveAs()) { - statusNotice("Done Saving."); + // statusNotice("Done Saving."); + // status is now printed from Sketch so that "Done Saving." + // is only printed after Save As when progress bar is shown. + // Disabling this for 0125, instead rebuild the menu inside // the Save As method of the Sketch object, since that's the // only one who knows whether something was renamed. diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index b3af66a54..9cbadfd41 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -716,6 +716,8 @@ public class Sketch { protected boolean saveAs() throws IOException { String newParentDir = null; String newName = null; + + final String oldName2 = folder.getName(); // TODO rewrite this to use shared version from PApplet final String PROMPT = "Save sketch folder as..."; if (Preferences.getBoolean("chooser.files.native")) { @@ -762,7 +764,7 @@ public class Sketch { if (!sanitaryName.equals(newName) && newFolder.exists()) { Base.showMessage("Cannot Save", "A sketch with the cleaned name\n" + - "“" + sanitaryName + "â€� already exists."); + "“" + sanitaryName + "†already exists."); return false; } newName = sanitaryName; @@ -854,11 +856,12 @@ public class Sketch { final File newFolder2 = newFolder; final File[] copyItems2 = copyItems; + final String newName2 = newName; // create a new event dispatch thread javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { - ProgressBarGUI p = new ProgressBarGUI(copyItems2,newFolder2); + ProgressBarGUI p = new ProgressBarGUI(copyItems2,newFolder2,oldName2,newName2); } }); @@ -868,8 +871,6 @@ public class Sketch { File newFile = new File(newFolder, code[i].getFileName()); code[i].saveAs(newFile); } - - // While the old path to the main .pde is still set, remove the entry from // the Recent menu so that it's not sticking around after the rename. @@ -896,7 +897,7 @@ public class Sketch { - private class ProgressBarGUI extends JFrame implements + public class ProgressBarGUI extends JFrame implements PropertyChangeListener { private static final long serialVersionUID = 1L; @@ -907,7 +908,7 @@ public class Sketch { private File newFolder; // create a new background thread - private class Task extends SwingWorker { + public class Task extends SwingWorker { @Override protected Void doInBackground() throws Exception { @@ -930,33 +931,38 @@ public class Sketch { if (copyable.isDirectory()) { Base.copyDir(copyable, new File(ProgressBarGUI.this.newFolder, - copyable.getName())); + copyable.getName()),this,progress,totalSize); + progress += getFileLength(copyable); } else { Base.copyFile(copyable, new File(ProgressBarGUI.this.newFolder, copyable.getName())); + progress += getFileLength(copyable); + setProgress((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); } - progress += getFileLength(copyable); - setProgress((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); - - System.out.println(""+(int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); - } return null; } + + public void setProgressBarStatus(int status) + { + setProgress(status); + } @Override public void done() { - // to close the progress bar automatically when done + // to close the progress bar automatically when done, and to + // print that Saving is done in Message Area + + editor.statusNotice("Done Saving."); ProgressBarGUI.this.closeProgressBar(); } } - public ProgressBarGUI(File[] c, File nf) { + public ProgressBarGUI(File[] c, File nf, String oldName, String newName) { // initialize a copyItems and newFolder, which are used for file // copying in the background thread copyItems = c; @@ -970,8 +976,8 @@ public class Sketch { JPanel panel = new JPanel(null); add(panel); setContentPane(panel); - saveAsLabel = new JLabel("Saving X as Y..."); - saveAsLabel.setBounds(40, 20, 150, 20); + saveAsLabel = new JLabel("Saving "+oldName+" as "+newName+"..."); + saveAsLabel.setBounds(40, 20, 300, 20); progressBar = new JProgressBar(0, 100); progressBar.setValue(0); @@ -1058,7 +1064,6 @@ public class Sketch { editor.updateTitle(); editor.base.rebuildSketchbookMenus(); // editor.header.rebuild(); - } From 8f2c2006baf65976346a5e13939942fc82f3b30a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 19:35:58 +0530 Subject: [PATCH 291/608] revisions updated --- pdex/revisions.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pdex/revisions.txt b/pdex/revisions.txt index 3d99c4f5f..5a2a1fd3b 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -1,4 +1,13 @@ +PDE X v1.0.4b - February , 2014 + +Bug fixes + ++ Autocompletion bug, column is sometimes off by 1 +https://github.com/processing/processing-experimental/issues/38 + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + PDE X v1.0.3b - January 21, 2014 New Feature From d1bc54484b28e910ba08e5c01373f9e0152f1726 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Feb 2014 19:58:51 +0530 Subject: [PATCH 292/608] completion popup height bug fix --- .../mode/experimental/CompletionPanel.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index 4eae592e4..cadc007e3 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -123,11 +123,15 @@ public class CompletionPanel { } private int setHeight(int itemCount){ - if(scrollPane.getHorizontalScrollBar().isVisible()) itemCount++; - FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); - float h = (fm.getHeight() + fm.getDescent()*0.5f) * (itemCount + 1); - log("popup height " + Math.min(250,h)); - return Math.min(250,(int)h); // popup menu height + FontMetrics fm = textarea.getFontMetrics(textarea.getFont()); + float h = (fm.getHeight() + (fm.getDescent()) * 0.5f) * (itemCount); + if (scrollPane.getHorizontalScrollBar().isVisible()) + h += scrollPane.getHorizontalScrollBar().getHeight() + fm.getHeight() + + (fm.getDescent() + fm.getAscent()) * 0.8f; + // 0.5f and 0.8f scaling give respectable results. + //log("popup height " + Math.min(250,h) + //+ scrollPane.getHorizontalScrollBar().isVisible()); + return Math.min(250, (int) h); // popup menu height } /*TODO: Make width dynamic From 6f2b4ce9a9569e08916e140d8cd4e59fa08ce57f Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sun, 2 Feb 2014 22:27:02 -0500 Subject: [PATCH 293/608] fixes #2341 - inconsistent bounds checks The core datastructure IntLost, FloatList, and StringList all have unsafe .get methods that do not perform bounds checking. This is in contrast to their .remove methods, which do perform bounds checking. Prior to this patch, the following would print 0: IntList il = new IntList(); println(il.get(5)); But if we tried to *remove* that element, we would get an ArrayIndexOutOfBoundException: il.remove(5); This patch causes calls to .get to throw exceptions instead of returning 0 (or null in the case of StringList) for uninitialized values. --- core/src/processing/data/FloatList.java | 3 +++ core/src/processing/data/IntList.java | 3 +++ core/src/processing/data/StringList.java | 3 +++ 3 files changed, 9 insertions(+) diff --git a/core/src/processing/data/FloatList.java b/core/src/processing/data/FloatList.java index 9921cb326..b379bf0b2 100644 --- a/core/src/processing/data/FloatList.java +++ b/core/src/processing/data/FloatList.java @@ -110,6 +110,9 @@ public class FloatList implements Iterable { * @brief Get an entry at a particular index */ public float get(int index) { + if (index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } return data[index]; } diff --git a/core/src/processing/data/IntList.java b/core/src/processing/data/IntList.java index 78775be3f..ea2d74af7 100644 --- a/core/src/processing/data/IntList.java +++ b/core/src/processing/data/IntList.java @@ -130,6 +130,9 @@ public class IntList implements Iterable { * @brief Get an entry at a particular index */ public int get(int index) { + if (index >= this.count) { + throw new ArrayIndexOutOfBoundsException(index); + } return data[index]; } diff --git a/core/src/processing/data/StringList.java b/core/src/processing/data/StringList.java index a407265a9..7811ee014 100644 --- a/core/src/processing/data/StringList.java +++ b/core/src/processing/data/StringList.java @@ -113,6 +113,9 @@ public class StringList implements Iterable { * @brief Get an entry at a particular index */ public String get(int index) { + if (index >= count) { + throw new ArrayIndexOutOfBoundsException(index); + } return data[index]; } From c1afe7fbc9ff237bd7be8376e54be063c25409ce Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 19 Feb 2014 17:47:44 +0530 Subject: [PATCH 294/608] Save As Progress Bar complete, resolving issue #70 Now works for large files within folders as well. Code is now commented as well. --- app/src/processing/app/Base.java | 90 +++++++++++++++++++++++++++--- app/src/processing/app/Sketch.java | 24 +++++--- 2 files changed, 96 insertions(+), 18 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index a9332c94e..3149ef34b 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1592,7 +1592,7 @@ public class Base { } - // Because the Oracle JDK is 64-bit only, we lose this ability, feature, + // Because the Oracle JDK is 64-bit only, we lose this ability, feature, // edge case, headache. // /** // * Return whether sketches will run as 32- or 64-bits. On Linux and Windows, @@ -1605,10 +1605,10 @@ public class Base { // } // return nativeBits; // } - - /** + + /** * Return whether sketches will run as 32- or 64-bits based - * on the JVM that's in use. + * on the JVM that's in use. */ static public int getNativeBits() { return nativeBits; @@ -2604,6 +2604,47 @@ public class Base { } + static public void copyFile(File sourceFile, + File targetFile,Sketch.ProgressBarGUI.Task progBar, + double progress,double totalSize) throws IOException { + // Overloaded copyFile that is called whenever a Save As is being done, so that the + // ProgressBar is updated for very large files as well + BufferedInputStream from = + new BufferedInputStream(new FileInputStream(sourceFile)); + BufferedOutputStream to = + new BufferedOutputStream(new FileOutputStream(targetFile)); + byte[] buffer = new byte[16 * 1024]; + int bytesRead; + int totalRead=0; + while ((bytesRead = from.read(buffer)) != -1) { + to.write(buffer, 0, bytesRead); + totalRead += bytesRead; + if (totalRead >= 524288) //to update progress bar every 50MB + { + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + totalRead = 0; + } + } + if (sourceFile.length()>524288) { + // Update the progress bar one final time if file size is more than 50MB, + // otherwise, the update is handled either by the copyDir function, + // or directly by Sketch.ProgressBarGUI.Task.doInBackground() + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + } + from.close(); + from = null; + to.flush(); + to.close(); + to = null; + + targetFile.setLastModified(sourceFile.lastModified()); + targetFile.setExecutable(sourceFile.canExecute()); + } + /** * Grab the contents of a file as a string. */ @@ -2649,7 +2690,7 @@ public class Base { * files and potentially troublesome .svn folders. */ static public void copyDir(File sourceDir, - File targetDir,Sketch.ProgressBarGUI.Task progBar,double progress,double totalSize) throws IOException { + File targetDir) throws IOException { if (sourceDir.equals(targetDir)) { final String urDum = "source and target directories are identical"; throw new IllegalArgumentException(urDum); @@ -2664,17 +2705,48 @@ public class Base { File target = new File(targetDir, files[i]); if (source.isDirectory()) { //target.mkdirs(); - copyDir(source, target, progBar, progress, totalSize); + copyDir(source, target); target.setLastModified(source.lastModified()); } else { copyFile(source, target); - progress += source.length(); - progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); } } } + + static public double copyDir(File sourceDir, + File targetDir,Sketch.ProgressBarGUI.Task progBar, + double progress,double totalSize) throws IOException { + // Overloaded copyDir so that the Save As progress bar gets updated when the + // files are in folders as well (like in the data folder) + if (sourceDir.equals(targetDir)) { + final String urDum = "source and target directories are identical"; + throw new IllegalArgumentException(urDum); + } + targetDir.mkdirs(); + String files[] = sourceDir.list(); + for (int i = 0; i < files.length; i++) { + // Ignore dot files (.DS_Store), dot folders (.svn) while copying + if (files[i].charAt(0) == '.') continue; + //if (files[i].equals(".") || files[i].equals("..")) continue; + File source = new File(sourceDir, files[i]); + File target = new File(targetDir, files[i]); + if (source.isDirectory()) { + //target.mkdirs(); + progress = copyDir(source, target, progBar, progress, totalSize); + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + target.setLastModified(source.lastModified()); + } else { + copyFile(source, target, progBar, progress, totalSize); + // Update SaveAs progress bar + progress += source.length(); + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + } + } + return progress; + } static public void copyDirNative(File sourceDir, File targetDir) throws IOException { diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 9cbadfd41..3678c9659 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -896,7 +896,8 @@ public class Sketch { } - + // Class used to handle progress bar, and run Save As in background so that + // progress bar can update without freezing public class ProgressBarGUI extends JFrame implements PropertyChangeListener { @@ -924,10 +925,10 @@ public class Sketch { long progress = 0; setProgress(0); - for (File copyable : ProgressBarGUI.this.copyItems) + for (File copyable : ProgressBarGUI.this.copyItems) { // loop to copy over the items that make sense, and to set the // current progress - { + if (copyable.isDirectory()) { Base.copyDir(copyable, new File(ProgressBarGUI.this.newFolder, @@ -936,18 +937,23 @@ public class Sketch { } else { Base.copyFile(copyable, new File(ProgressBarGUI.this.newFolder, - copyable.getName())); - progress += getFileLength(copyable); - setProgress((int) Math.min( + copyable.getName()), this,progress,totalSize); + if (getFileLength(copyable)<524288) { + // If the file length > 50MB, the Base.copyFile() function has + // been redesigned to change progress every 50MB so that + // the progress bar doesn't stagnate during that time + progress += getFileLength(copyable); + setProgress((int) Math.min( Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + } } } return null; } - public void setProgressBarStatus(int status) - { + public void setProgressBarStatus(int status) { + setProgress(status); } @@ -996,7 +1002,7 @@ public class Sketch { t.execute(); } - private long getFileLength(File f)// function to return the length of + public long getFileLength(File f)// function to return the length of // the file, or // ENTIRE directory, including the // component files From 0632309fc0bba2e035c96a0812f01b999f595a0e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 23 Feb 2014 03:12:10 +0530 Subject: [PATCH 295/608] lookin into jdoc scroll bug, irritating one this --- .../mode/experimental/ASTGenerator.java | 5 +- .../mode/experimental/ASTNodeWrapper.java | 83 ++++++++++++++++++- .../experimental/ErrorCheckerService.java | 4 + 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 4d7602eaa..1d2a05297 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -235,7 +235,10 @@ public class ASTGenerator { } - public static final boolean SHOWAST = !true; + /** + * Toggle AST View window + */ + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index b980f1518..340f956c3 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -29,6 +29,7 @@ import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ExpressionStatement; import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.Javadoc; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.QualifiedName; @@ -99,6 +100,7 @@ public class ASTNodeWrapper { public int[] getJavaCodeOffsets(ErrorCheckerService ecs) { int nodeOffset = Node.getStartPosition(), nodeLength = Node .getLength(); + log("0.nodeOffset " + nodeOffset); ASTNode thisNode = Node; while (thisNode.getParent() != null) { if (getLineNumber(thisNode.getParent()) == lineNumber) { @@ -119,8 +121,34 @@ public class ASTNodeWrapper { */ int altStartPos = thisNode.getStartPosition(); + log("1.Altspos " + altStartPos); thisNode = thisNode.getParent(); + int jdocOffset; Javadoc jd = null; + if(thisNode instanceof TypeDeclaration){ + jd = ((TypeDeclaration)thisNode).getJavadoc(); + log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); + } else if(thisNode instanceof MethodDeclaration){ + jd = ((MethodDeclaration)thisNode).getJavadoc(); + log("Has m jdoc " + jd); + } else if(thisNode instanceof FieldDeclaration){ + jd = ((FieldDeclaration)thisNode).getJavadoc(); + log("Has f jdoc " + ((FieldDeclaration)thisNode).getJavadoc()); + } + + if(jd != null){ + jdocOffset = jd.getLength(); + log("jdoc offset: " + jdocOffset); + while (thisNode.getParent() != null) { + if (getLineNumber2(thisNode.getParent()) == getLineNumber2(getNode())) { + thisNode = thisNode.getParent(); + } else { + break; + } + } + //thisNode = thisNode.getParent(); + } + log("Visiting children of node " + getNodeAsString(thisNode)); Iterator it = thisNode .structuralPropertiesForType().iterator(); boolean flag = true; @@ -130,15 +158,17 @@ public class ASTNodeWrapper { if (prop.isChildListProperty()) { List nodelist = (List) thisNode .getStructuralProperty(prop); + log("prop " + prop); for (ASTNode cnode : nodelist) { - if (getLineNumber(cnode) == lineNumber) { + log("Visiting node " + getNodeAsString(cnode)); + if (getLineNumber2(cnode) == lineNumber) { if (flag) { altStartPos = cnode.getStartPosition(); // log("multi..."); flag = false; } else { - if(cnode == Node){ + if (cnode == Node) { // loop only till the current node. break; } @@ -159,10 +189,36 @@ public class ASTNodeWrapper { if (vals != null) return new int[] { lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; - else + else {// no offset mapping needed + log("joff[1] = " + (nodeOffset - altStartPos)); return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; + } } + private boolean hasJavaDoc(ASTNode node){ + if(node != null){ + Iterator it = node + .structuralPropertiesForType().iterator(); + log("Checkin for javadoc in child node of " + getNodeAsString(node)); + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) node + .getStructuralProperty(prop); + log("prop " + prop); + for (ASTNode cnode : nodelist) { + log("Visiting node " + getNodeAsString(cnode)); + if(cnode instanceof Javadoc){ + log("Visiting jdoc " + cnode); + return true; + } + } + } + } + } + return false; + } /** * Finds the difference in pde and java code offsets @@ -492,6 +548,27 @@ public class ASTNodeWrapper { return ((CompilationUnit) node.getRoot()).getLineNumber(node .getStartPosition()); } + + private static int getLineNumber2(ASTNode thisNode) { + int jdocOffset = 0; Javadoc jd = null; + if(thisNode instanceof TypeDeclaration){ + jd = ((TypeDeclaration)thisNode).getJavadoc(); + log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); + } else if(thisNode instanceof MethodDeclaration){ + jd = ((MethodDeclaration)thisNode).getJavadoc(); + log("Has m jdoc " + jd); + } else if(thisNode instanceof FieldDeclaration){ + jd = ((FieldDeclaration)thisNode).getJavadoc(); + log("Has f jdoc " + ((FieldDeclaration)thisNode).getJavadoc()); + } + if(jd != null){ + jdocOffset = 1+jd.getLength(); + } + log("ln 2 = " + ((CompilationUnit) thisNode.getRoot()).getLineNumber(thisNode + .getStartPosition() + jdocOffset)); + return ((CompilationUnit) thisNode.getRoot()).getLineNumber(thisNode + .getStartPosition() + jdocOffset); + } static private String getNodeAsString(ASTNode node) { if (node == null) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 307cd3b53..cc3d3655a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1278,9 +1278,13 @@ public class ErrorCheckerService implements Runnable{ * @return true - if highlighting happened correctly. */ public boolean highlightNode(ASTNodeWrapper awrap){ + log("Highlighting: " + awrap); try { int pdeoffsets[] = awrap.getPDECodeOffsets(this); int javaoffsets[] = awrap.getJavaCodeOffsets(this); + log("offsets: " +pdeoffsets[0] + "," + + pdeoffsets[1]+ "," +javaoffsets[1]+ "," + + javaoffsets[2]); scrollToErrorLine(editor, pdeoffsets[0], pdeoffsets[1],javaoffsets[1], javaoffsets[2]); From 22fc73ecb0f4418a57f75124b6787b76c16c3233 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 24 Feb 2014 00:48:57 +0530 Subject: [PATCH 296/608] Fixes #15 DIE BUG DIE --- .../mode/experimental/ASTNodeWrapper.java | 191 +++++++++++++----- 1 file changed, 141 insertions(+), 50 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 340f956c3..0f2ad877f 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -36,7 +36,9 @@ import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; /** * Wrapper class for ASTNode objects @@ -127,31 +129,155 @@ public class ASTNodeWrapper { if(thisNode instanceof TypeDeclaration){ jd = ((TypeDeclaration)thisNode).getJavadoc(); + altStartPos = getLen((TypeDeclaration)thisNode); log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); } else if(thisNode instanceof MethodDeclaration){ + altStartPos = getLen((MethodDeclaration)thisNode); jd = ((MethodDeclaration)thisNode).getJavadoc(); log("Has m jdoc " + jd); } else if(thisNode instanceof FieldDeclaration){ - jd = ((FieldDeclaration)thisNode).getJavadoc(); - log("Has f jdoc " + ((FieldDeclaration)thisNode).getJavadoc()); + FieldDeclaration fd = ((FieldDeclaration)thisNode); + jd = fd.getJavadoc(); + log("Has f jdoc " + fd.getJavadoc()); + altStartPos = getLen(fd); + //nodeOffset = ((VariableDeclarationFragment)(fd.fragments().get(0))).getName().getStartPosition(); } if(jd != null){ - jdocOffset = jd.getLength(); - log("jdoc offset: " + jdocOffset); - while (thisNode.getParent() != null) { - if (getLineNumber2(thisNode.getParent()) == getLineNumber2(getNode())) { - thisNode = thisNode.getParent(); - } else { - break; - } - } +// jdocOffset = jd.getLength(); +// log("jdoc offset: " + jdocOffset); + //testForMultilineDecl(thisNode); //thisNode = thisNode.getParent(); } + else{ + log("Visiting children of node " + getNodeAsString(thisNode)); + Iterator it = thisNode + .structuralPropertiesForType().iterator(); + boolean flag = true; + while (it.hasNext()) { + StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it + .next(); + if (prop.isChildListProperty()) { + List nodelist = (List) thisNode + .getStructuralProperty(prop); + log("prop " + prop); + for (ASTNode cnode : nodelist) { + log("Visiting node " + getNodeAsString(cnode)); + if (getLineNumber(cnode) == lineNumber) { + if (flag) { + altStartPos = cnode.getStartPosition(); + // log("multi..."); + + flag = false; + } else { + if (cnode == Node) { + // loop only till the current node. + break; + } + // We've located the first node in the line. + // Now normalize offsets till Node + //altStartPos += normalizeOffsets(cnode); + + } + + } + } + } + } + log("Altspos " + altStartPos); + } + + int pdeoffsets[] = getPDECodeOffsets(ecs); + String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); + int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); + if (vals != null) + return new int[] { + lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; + else {// no offset mapping needed + log("joff[1] = " + (nodeOffset - altStartPos)); + return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; + } + } + + private int getLen(FieldDeclaration fd){ + List list= fd.modifiers(); + SimpleName sn = (SimpleName) getNode(); + + Type tp = fd.getType(); + int lineNum = getLineNumber(sn); + log("SN "+sn + ", " + lineNum); + for (ASTNode astNode : list) { + if(getLineNumber(astNode) == lineNum) + { + log("first node in that line " + astNode); + log("diff " + (sn.getStartPosition() - astNode.getStartPosition())); + return (astNode.getStartPosition()); + } + } + if(getLineNumber(fd.getType()) == lineNum) + { + log("first node in that line " + tp); + log("diff " + (sn.getStartPosition() - tp.getStartPosition())); + return (tp.getStartPosition()); + } + + + return 0; + } + + private int getLen(MethodDeclaration md) { + List list = md.modifiers(); + SimpleName sn = (SimpleName) getNode(); + int lineNum = getLineNumber(sn); + log("SN " + sn + ", " + lineNum); + + for (ASTNode astNode : list) { + if (getLineNumber(astNode) == lineNum) { + log("first node in that line " + astNode); + log("diff " + (sn.getStartPosition() - astNode.getStartPosition())); + return (astNode.getStartPosition()); + } + } + + if (!md.isConstructor()) { + Type tp = md.getReturnType2(); + if (getLineNumber(tp) == lineNum) { + log("first node in that line " + tp); + log("diff " + (sn.getStartPosition() - tp.getStartPosition())); + return (tp.getStartPosition()); + } + } + + return 0; + } + + private int getLen(TypeDeclaration td){ + List list= td.modifiers(); + list = td.modifiers(); + SimpleName sn = (SimpleName) getNode(); + + int lineNum = getLineNumber(sn); + log("SN "+sn + ", " + lineNum); + for (ASTNode astNode : list) { + if(getLineNumber(astNode) == lineNum) + { + log("first node in that line " + astNode); + log("diff " + (sn.getStartPosition() - astNode.getStartPosition())); + return (astNode.getStartPosition()); + } + } + + return 0; + } + + private void testForMultilineDecl(ASTNode thisNode){ + int minLineNum = lineNumber, maxLineNum = ((CompilationUnit) thisNode + .getRoot()).getLineNumber(thisNode.getStartPosition()); log("Visiting children of node " + getNodeAsString(thisNode)); Iterator it = thisNode .structuralPropertiesForType().iterator(); boolean flag = true; + int altStartPos = 0; while (it.hasNext()) { StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it .next(); @@ -161,7 +287,7 @@ public class ASTNodeWrapper { log("prop " + prop); for (ASTNode cnode : nodelist) { log("Visiting node " + getNodeAsString(cnode)); - if (getLineNumber2(cnode) == lineNumber) { + if (getLineNumber(cnode) >= minLineNum && getLineNumber(cnode) <= maxLineNum) { if (flag) { altStartPos = cnode.getStartPosition(); // log("multi..."); @@ -177,49 +303,14 @@ public class ASTNodeWrapper { //altStartPos += normalizeOffsets(cnode); } - + testForMultilineDecl(cnode); FieldDeclaration f; } } } } log("Altspos " + altStartPos); - int pdeoffsets[] = getPDECodeOffsets(ecs); - String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); - if (vals != null) - return new int[] { - lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; - else {// no offset mapping needed - log("joff[1] = " + (nodeOffset - altStartPos)); - return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength }; - } } - private boolean hasJavaDoc(ASTNode node){ - if(node != null){ - Iterator it = node - .structuralPropertiesForType().iterator(); - log("Checkin for javadoc in child node of " + getNodeAsString(node)); - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) node - .getStructuralProperty(prop); - log("prop " + prop); - for (ASTNode cnode : nodelist) { - log("Visiting node " + getNodeAsString(cnode)); - if(cnode instanceof Javadoc){ - log("Visiting jdoc " + cnode); - return true; - } - } - } - } - } - return false; - } - /** * Finds the difference in pde and java code offsets * @param source @@ -549,7 +640,7 @@ public class ASTNodeWrapper { .getStartPosition()); } - private static int getLineNumber2(ASTNode thisNode) { + /*private static int getLineNumber2(ASTNode thisNode) { int jdocOffset = 0; Javadoc jd = null; if(thisNode instanceof TypeDeclaration){ jd = ((TypeDeclaration)thisNode).getJavadoc(); @@ -568,7 +659,7 @@ public class ASTNodeWrapper { .getStartPosition() + jdocOffset)); return ((CompilationUnit) thisNode.getRoot()).getLineNumber(thisNode .getStartPosition() + jdocOffset); - } + }*/ static private String getNodeAsString(ASTNode node) { if (node == null) From 7d54e57ac48a869095d8976318799cbba6e50bba Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 1 Mar 2014 16:25:02 +0530 Subject: [PATCH 297/608] comments and cleanup --- .../mode/experimental/ASTNodeWrapper.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 0f2ad877f..9e4a4739e 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -125,31 +125,33 @@ public class ASTNodeWrapper { int altStartPos = thisNode.getStartPosition(); log("1.Altspos " + altStartPos); thisNode = thisNode.getParent(); - int jdocOffset; Javadoc jd = null; + Javadoc jd = null; - if(thisNode instanceof TypeDeclaration){ - jd = ((TypeDeclaration)thisNode).getJavadoc(); - altStartPos = getLen((TypeDeclaration)thisNode); - log("Has t jdoc " + ((TypeDeclaration)thisNode).getJavadoc()); - } else if(thisNode instanceof MethodDeclaration){ - altStartPos = getLen((MethodDeclaration)thisNode); - jd = ((MethodDeclaration)thisNode).getJavadoc(); + /* + * There's another case that needs to be handled. If a TD, MD or FD + * contains javadoc comments(multi or single line) the starting position + * of the javadoc is treated as the beginning of the declaration by the AST parser. + * But that's clearly not what we need. The true decl begins after the javadoc ends. + * So this offset needs to be found carefully and stored in altStartPos + * + */ + if (thisNode instanceof TypeDeclaration) { + jd = ((TypeDeclaration) thisNode).getJavadoc(); + altStartPos = getLen((TypeDeclaration) thisNode); + log("Has t jdoc " + ((TypeDeclaration) thisNode).getJavadoc()); + } else if (thisNode instanceof MethodDeclaration) { + altStartPos = getLen((MethodDeclaration) thisNode); + jd = ((MethodDeclaration) thisNode).getJavadoc(); log("Has m jdoc " + jd); - } else if(thisNode instanceof FieldDeclaration){ - FieldDeclaration fd = ((FieldDeclaration)thisNode); + } else if (thisNode instanceof FieldDeclaration) { + FieldDeclaration fd = ((FieldDeclaration) thisNode); jd = fd.getJavadoc(); log("Has f jdoc " + fd.getJavadoc()); - altStartPos = getLen(fd); + altStartPos = getJavadocOffset(fd); //nodeOffset = ((VariableDeclarationFragment)(fd.fragments().get(0))).getName().getStartPosition(); } - if(jd != null){ -// jdocOffset = jd.getLength(); -// log("jdoc offset: " + jdocOffset); - //testForMultilineDecl(thisNode); - //thisNode = thisNode.getParent(); - } - else{ + if(jd == null){ log("Visiting children of node " + getNodeAsString(thisNode)); Iterator it = thisNode .structuralPropertiesForType().iterator(); @@ -199,7 +201,12 @@ public class ASTNodeWrapper { } } - private int getLen(FieldDeclaration fd){ + /** + * + * @param fd + * @return + */ + private int getJavadocOffset(FieldDeclaration fd){ List list= fd.modifiers(); SimpleName sn = (SimpleName) getNode(); From 8744a5ffe4018fc7e860d13db467297e4c198aa2 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 1 Mar 2014 16:26:06 +0530 Subject: [PATCH 298/608] reafactored --- pdex/src/processing/mode/experimental/ASTNodeWrapper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 9e4a4739e..45518b4b6 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -137,10 +137,10 @@ public class ASTNodeWrapper { */ if (thisNode instanceof TypeDeclaration) { jd = ((TypeDeclaration) thisNode).getJavadoc(); - altStartPos = getLen((TypeDeclaration) thisNode); + altStartPos = getJavadocOffset((TypeDeclaration) thisNode); log("Has t jdoc " + ((TypeDeclaration) thisNode).getJavadoc()); } else if (thisNode instanceof MethodDeclaration) { - altStartPos = getLen((MethodDeclaration) thisNode); + altStartPos = getJavadocOffset((MethodDeclaration) thisNode); jd = ((MethodDeclaration) thisNode).getJavadoc(); log("Has m jdoc " + jd); } else if (thisNode instanceof FieldDeclaration) { @@ -232,7 +232,7 @@ public class ASTNodeWrapper { return 0; } - private int getLen(MethodDeclaration md) { + private int getJavadocOffset(MethodDeclaration md) { List list = md.modifiers(); SimpleName sn = (SimpleName) getNode(); int lineNum = getLineNumber(sn); @@ -258,7 +258,7 @@ public class ASTNodeWrapper { return 0; } - private int getLen(TypeDeclaration td){ + private int getJavadocOffset(TypeDeclaration td){ List list= td.modifiers(); list = td.modifiers(); SimpleName sn = (SimpleName) getNode(); From 1377f759b3100fb2e6fc4f764d9932ea2cae5023 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 1 Mar 2014 16:54:09 +0530 Subject: [PATCH 299/608] clean up --- .../mode/experimental/ASTNodeWrapper.java | 42 +------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 45518b4b6..6c6cbc6a5 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -259,6 +259,7 @@ public class ASTNodeWrapper { } private int getJavadocOffset(TypeDeclaration td){ + // TODO: This is still broken. Hence no refactoring or highlighting on scroll works :\ List list= td.modifiers(); list = td.modifiers(); SimpleName sn = (SimpleName) getNode(); @@ -277,47 +278,6 @@ public class ASTNodeWrapper { return 0; } - private void testForMultilineDecl(ASTNode thisNode){ - int minLineNum = lineNumber, maxLineNum = ((CompilationUnit) thisNode - .getRoot()).getLineNumber(thisNode.getStartPosition()); - log("Visiting children of node " + getNodeAsString(thisNode)); - Iterator it = thisNode - .structuralPropertiesForType().iterator(); - boolean flag = true; - int altStartPos = 0; - while (it.hasNext()) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) thisNode - .getStructuralProperty(prop); - log("prop " + prop); - for (ASTNode cnode : nodelist) { - log("Visiting node " + getNodeAsString(cnode)); - if (getLineNumber(cnode) >= minLineNum && getLineNumber(cnode) <= maxLineNum) { - if (flag) { - altStartPos = cnode.getStartPosition(); - // log("multi..."); - - flag = false; - } else { - if (cnode == Node) { - // loop only till the current node. - break; - } - // We've located the first node in the line. - // Now normalize offsets till Node - //altStartPos += normalizeOffsets(cnode); - - } - testForMultilineDecl(cnode); FieldDeclaration f; - } - } - } - } - log("Altspos " + altStartPos); - } - /** * Finds the difference in pde and java code offsets * @param source From f159f809863bbcd098f27eda772ee9e8b02ecf50 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Mar 2014 20:40:42 +0530 Subject: [PATCH 300/608] working on autosave --- .../mode/experimental/ASTGenerator.java | 6 +- .../mode/experimental/AutoSaveUtil.java | 30 +++++++++- .../mode/experimental/DebugEditor.java | 59 +++++++++++++++---- .../experimental/ErrorCheckerService.java | 6 +- 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1d2a05297..9d74fd4ee 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -238,7 +238,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -254,14 +254,14 @@ public class ASTGenerator { compilationUnit = (CompilationUnit) parser.createAST(null); } else { compilationUnit = cu; - log("Other cu"); + //log("Other cu"); } // OutlineVisitor visitor = new OutlineVisitor(); // compilationUnit.accept(visitor); getCodeComments(); codeTree = new DefaultMutableTreeNode(new ASTNodeWrapper((ASTNode) compilationUnit .types().get(0))); - log("Total CU " + compilationUnit.types().size()); + //log("Total CU " + compilationUnit.types().size()); if(compilationUnit.types() == null || compilationUnit.types().isEmpty()){ logE("No CU found!"); } diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 71b224528..d02f510fd 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -46,6 +46,10 @@ public class AutoSaveUtil { private boolean isSaving; + private boolean isAutoSaveBackup; + + private File sketchFolder, sketchBackupFolder; + /** * * @param dedit @@ -62,8 +66,18 @@ public class AutoSaveUtil { ExperimentalMode.log("AutoSaver Interval(mins): " + timeOut); } autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); + sketchFolder = editor.getSketch().getFolder(); + checkIfBackup(); } + private void checkIfBackup(){ + + } + + public boolean isAutoSaveBackup() { + return isAutoSaveBackup; + } + /** * Check if any previous autosave exists * @return @@ -73,6 +87,7 @@ public class AutoSaveUtil { String prevSaves[] = Base.listFiles(autosaveDir, false); if(prevSaves.length > 0){ File t = new File(Base.listFiles(new File(prevSaves[0]), false)[0]); + sketchBackupFolder = t; pastSave = new File(t.getAbsolutePath() + File.separator + t.getName() + ".pde"); if(pastSave.exists()) return true; @@ -89,6 +104,18 @@ public class AutoSaveUtil { autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); } + /** + * The folder of the original sketch + * @return + */ + public File getSketchFolder(){ + return sketchFolder; + } + + public File getSketchBackupFolder(){ + return sketchBackupFolder; + } + public File getPastSave(){ return pastSave; } @@ -98,7 +125,7 @@ public class AutoSaveUtil { */ public void init(){ if(saveTime < 10000) saveTime = 10 * 1000; - //saveTime = 10 * 1000; //TODO: remove + saveTime = 5 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; @@ -112,6 +139,7 @@ public class AutoSaveUtil { while(isSaving); // save operation mustn't be interrupted if(timer != null) timer.cancel(); Base.removeDir(autosaveDir); + ExperimentalMode.log("Stopping autosaver and deleting backup dir"); } /** diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 02e698be4..42e6d2340 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -245,7 +245,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { ta.setECSandThemeforTextArea(errorCheckerService, dmode); addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); - log("Sketch Path: " + path); + //log("Sketch Path: " + path); + + viewingAutosaveBackup = false; + log("DebugEdit constructed. Viewing auto save false " + viewingAutosaveBackup); } private void addXQModeUI(){ @@ -342,7 +345,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); - if(autosaver != null) autosaver.stop(); + if(autosaver != null && !viewingAutosaveBackup) { + log("stopping autosaver in internalCloseRunner"); + autosaver.stop(); + } super.internalCloseRunner(); } @@ -738,6 +744,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ @Override protected boolean handleOpenInternal(String path) { + log("handleOpenInternal, path: " + path); boolean didOpen = super.handleOpenInternal(path); if (didOpen && dbg != null) { // should already been stopped (open calls handleStop) @@ -745,9 +752,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { clearBreakpointedLines(); // force clear breakpoint highlights variableInspector().reset(); // clear contents of variable inspector } - if(autosaver != null) - autosaver.stop(); - loadAutoSaver(); + + if(!viewingAutosaveBackup){ + log("Sketch isn't a backup"); + if(autosaver != null){ + log("stopping autosaver in handleOpenInternal"); + autosaver.stop(); + } + loadAutoSaver(); + } + log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); return didOpen; } @@ -825,7 +839,25 @@ public class DebugEditor extends JavaEditor implements ActionListener { @Override public boolean handleSave(boolean immediately) { //System.out.println("handleSave " + immediately); - + + log("handleSave, viewing autosave? " + viewingAutosaveBackup); + /* If user wants to save a backup, the backup sketch should get + * copied to the main sketch directory, simply reload the main sketch. + */ + if(viewingAutosaveBackup){ + File files[] = autosaver.getSketchBackupFolder().listFiles(); + File src = autosaver.getSketchBackupFolder(), dst = autosaver + .getSketchFolder(); + for (File f : files) { + log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath()); +// if(f.isFile()) + //Base.copyFile(f, new File(dst + File.separator + f.getName())); +// else +// Base.copyDir(f, new File(dst + File.separator + f.getName())); + } + //viewingAutosaveBackup = false; + } + // note modified tabs final List modified = new ArrayList(); for (int i = 0; i < getSketch().getCodeCount(); i++) { @@ -887,6 +919,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { return saved; } + private boolean viewingAutosaveBackup; + /** * Loads and starts the auto save service * Also handles the case where an auto save backup is found. @@ -894,15 +928,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ public void loadAutoSaver(){ log("Load Auto Saver()"); - if(autosaver != null){ - autosaver.stop(); - } - autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; } - + if(viewingAutosaveBackup) return; File pastSave = autosaver.getPastSave(); int response = Base .showYesNoQuestion(this, @@ -913,9 +944,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ - handleOpenInternal(pastSave.getAbsolutePath()); - Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); + viewingAutosaveBackup = true; + handleOpenInternal(pastSave.getAbsolutePath()); + // Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); + log("loadAutoSaver, viewing autosave? " + viewingAutosaveBackup); return; } else{ diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index cc3d3655a..cb9ec65e8 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1387,9 +1387,9 @@ public class ErrorCheckerService implements Runnable{ * compiler classpath needs to be updated. */ protected void checkForChangedImports() { - log("Imports: " + programImports.size() + - " Prev Imp: " - + previousImports.size()); +// log("Imports: " + programImports.size() + +// " Prev Imp: " +// + previousImports.size()); if (programImports.size() != previousImports.size()) { // log(1); loadCompClass = true; From aad62bd65d80057fefdbeaf9c950df5fcb95618c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 2 Mar 2014 21:44:29 +0530 Subject: [PATCH 301/608] now going around in circles with autosave --- .../mode/experimental/AutoSaveUtil.java | 47 ++++++++++++++++--- .../mode/experimental/DebugEditor.java | 44 +++++++++-------- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index d02f510fd..3141ed65a 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -27,6 +27,8 @@ import java.util.TimerTask; import processing.app.Base; import processing.app.Sketch; +import static processing.mode.experimental.ExperimentalMode.log; + /** * Autosave utility for saving sketch backups in the background after * certain intervals @@ -50,6 +52,8 @@ public class AutoSaveUtil { private File sketchFolder, sketchBackupFolder; + private static final String AUTOSAVEFOLDER = "__autosave__"; + /** * * @param dedit @@ -63,15 +67,36 @@ public class AutoSaveUtil { } else{ saveTime = timeOut * 60 * 1000; - ExperimentalMode.log("AutoSaver Interval(mins): " + timeOut); + log("AutoSaver Interval(mins): " + timeOut); } - autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); - sketchFolder = editor.getSketch().getFolder(); checkIfBackup(); + if(isAutoSaveBackup){ + sketchBackupFolder = sketchFolder; + } + else{ + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + AUTOSAVEFOLDER); + sketchFolder = editor.getSketch().getFolder(); + sketchBackupFolder = autosaveDir; + } } + /** + * If the sketch path looks like ../__autosave__/../FooSketch + * then assume this is a backup sketch + */ private void checkIfBackup(){ - + File parent = sketchFolder.getParentFile().getParentFile(); + if(parent.isDirectory() && parent.getName().equals(AUTOSAVEFOLDER)){ + isAutoSaveBackup = true; + log("IS AUTOSAVE " + sketchFolder.getAbsolutePath()); + } + } + + public File getActualSketchFolder(){ + if(isAutoSaveBackup) + return sketchFolder.getParentFile().getParentFile().getParentFile(); + else + return sketchFolder; } public boolean isAutoSaveBackup() { @@ -101,7 +126,11 @@ public class AutoSaveUtil { */ public void reloadAutosaveDir(){ while(isSaving); - autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + "_autosave"); + autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + AUTOSAVEFOLDER); + } + + public File getAutoSaveDir(){ + return autosaveDir; } /** @@ -124,12 +153,16 @@ public class AutoSaveUtil { * Start the auto save service */ public void init(){ + if(isAutoSaveBackup) { + log("AutoSaver not started"); + return; + } if(saveTime < 10000) saveTime = 10 * 1000; saveTime = 5 * 1000; //TODO: remove timer = new Timer(); timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; - ExperimentalMode.log("AutoSaver started"); + log("AutoSaver started"); } /** @@ -156,7 +189,7 @@ public class AutoSaveUtil { boolean deleteOldSave = false; String oldSave = null; if(!autosaveDir.exists()){ - autosaveDir = new File(sc.getFolder().getAbsolutePath(), "_autosave"); + autosaveDir = new File(sc.getFolder().getAbsolutePath(), AUTOSAVEFOLDER); autosaveDir.mkdir(); } else diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 42e6d2340..ee4735086 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -246,9 +246,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); //log("Sketch Path: " + path); - - viewingAutosaveBackup = false; - log("DebugEdit constructed. Viewing auto save false " + viewingAutosaveBackup); } private void addXQModeUI(){ @@ -744,7 +741,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ @Override protected boolean handleOpenInternal(String path) { - log("handleOpenInternal, path: " + path); + log("handleOpenInternal, path: " + path); boolean didOpen = super.handleOpenInternal(path); if (didOpen && dbg != null) { // should already been stopped (open calls handleStop) @@ -752,16 +749,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { clearBreakpointedLines(); // force clear breakpoint highlights variableInspector().reset(); // clear contents of variable inspector } - - if(!viewingAutosaveBackup){ - log("Sketch isn't a backup"); - if(autosaver != null){ - log("stopping autosaver in handleOpenInternal"); - autosaver.stop(); - } + //if(didOpen){ + loadAutoSaver(); - } - log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); + viewingAutosaveBackup = autosaver.isAutoSaveBackup(); + log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); + //} return didOpen; } @@ -845,17 +838,30 @@ public class DebugEditor extends JavaEditor implements ActionListener { * copied to the main sketch directory, simply reload the main sketch. */ if(viewingAutosaveBackup){ + /* File files[] = autosaver.getSketchBackupFolder().listFiles(); File src = autosaver.getSketchBackupFolder(), dst = autosaver - .getSketchFolder(); + .getActualSketchFolder(); for (File f : files) { log("Copying " + f.getAbsolutePath() + " to " + dst.getAbsolutePath()); -// if(f.isFile()) - //Base.copyFile(f, new File(dst + File.separator + f.getName())); -// else -// Base.copyDir(f, new File(dst + File.separator + f.getName())); + try { + if (f.isFile()) { + f.delete(); + Base.copyFile(f, new File(dst + File.separator + f.getName())); + } else { + Base.removeDir(f); + Base.copyDir(f, new File(dst + File.separator + f.getName())); + } + } catch (IOException e) { + e.printStackTrace(); + } } + File sk = autosaver.getActualSketchFolder(); + Base.removeDir(autosaver.getAutoSaveDir()); + //handleOpenInternal(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); + getBase().handleOpen(sk.getAbsolutePath() + File.separator + sk.getName() + ".pde"); //viewingAutosaveBackup = false; + */ } // note modified tabs @@ -933,7 +939,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { autosaver.init(); return; } - if(viewingAutosaveBackup) return; File pastSave = autosaver.getPastSave(); int response = Base .showYesNoQuestion(this, @@ -944,7 +949,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ - viewingAutosaveBackup = true; handleOpenInternal(pastSave.getAbsolutePath()); // Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); From 0ee09ee2aaaf281d53fd0182b549188d2fb36525 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Sat, 15 Mar 2014 23:59:02 +0530 Subject: [PATCH 302/608] Progress Bar now displays when Adding Files --- app/src/processing/app/Base.java | 55 ++++++++++-- app/src/processing/app/Sketch.java | 137 ++++++++++++++++++++++++----- 2 files changed, 163 insertions(+), 29 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 3149ef34b..762325af6 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2605,7 +2605,7 @@ public class Base { static public void copyFile(File sourceFile, - File targetFile,Sketch.ProgressBarGUI.Task progBar, + File targetFile,Sketch.ProgressBarGUI.TaskSaveAs progBar, double progress,double totalSize) throws IOException { // Overloaded copyFile that is called whenever a Save As is being done, so that the // ProgressBar is updated for very large files as well @@ -2619,7 +2619,7 @@ public class Base { while ((bytesRead = from.read(buffer)) != -1) { to.write(buffer, 0, bytesRead); totalRead += bytesRead; - if (totalRead >= 524288) //to update progress bar every 50MB + if (totalRead >= 524288) //to update progress bar every 0.5MB { progress += totalRead; progBar.setProgressBarStatus((int) Math.min( @@ -2628,9 +2628,9 @@ public class Base { } } if (sourceFile.length()>524288) { - // Update the progress bar one final time if file size is more than 50MB, + // Update the progress bar one final time if file size is more than 0.5MB, // otherwise, the update is handled either by the copyDir function, - // or directly by Sketch.ProgressBarGUI.Task.doInBackground() + // or directly by Sketch.ProgressBarGUI.TaskSaveAs.doInBackground() progress += totalRead; progBar.setProgressBarStatus((int) Math.min( Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); @@ -2644,6 +2644,51 @@ public class Base { targetFile.setLastModified(sourceFile.lastModified()); targetFile.setExecutable(sourceFile.canExecute()); } + + static public void copyFile(File sourceFile, File targetFile, + Sketch.ProgressBarGUI.TaskAddFile progBar) throws IOException { + // Overloaded copyFile that is called whenever a addFile is being done, + // so that the + // ProgressBar is updated + double totalSize = sourceFile.length(); + int progress = 0; + BufferedInputStream from = new BufferedInputStream(new FileInputStream( + sourceFile)); + BufferedOutputStream to = new BufferedOutputStream( + new FileOutputStream(targetFile)); + byte[] buffer = new byte[16 * 1024]; + int bytesRead; + int totalRead = 0; + while ((bytesRead = from.read(buffer)) != -1) { + to.write(buffer, 0, bytesRead); + totalRead += bytesRead; + if (totalRead >= 1024) // to update progress bar every 1kB + { + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double) progress * 100.0 + / (double) totalSize), 100)); + totalRead = 0; + } + } + if (sourceFile.length() > 1024) { + // Update the progress bar one final time if file size is more than + // 1kB, + // otherwise, the update is handled directly by + // Sketch.ProgressBarGUI.TaskAddFile.doInBackground() + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min( + Math.ceil((double) progress * 100.0 / (double) totalSize), + 100)); + } + from.close(); + from = null; + to.flush(); + to.close(); + to = null; + targetFile.setLastModified(sourceFile.lastModified()); + targetFile.setExecutable(sourceFile.canExecute()); +} /** * Grab the contents of a file as a string. @@ -2715,7 +2760,7 @@ public class Base { static public double copyDir(File sourceDir, - File targetDir,Sketch.ProgressBarGUI.Task progBar, + File targetDir,Sketch.ProgressBarGUI.TaskSaveAs progBar, double progress,double totalSize) throws IOException { // Overloaded copyDir so that the Save As progress bar gets updated when the // files are in folders as well (like in the data folder) diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 3678c9659..8e03224ab 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -858,7 +858,8 @@ public class Sketch { final File[] copyItems2 = copyItems; final String newName2 = newName; - // create a new event dispatch thread + // Create a new event dispatch thread- to display ProgressBar + // while Saving As javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { ProgressBarGUI p = new ProgressBarGUI(copyItems2,newFolder2,oldName2,newName2); @@ -896,20 +897,23 @@ public class Sketch { } - // Class used to handle progress bar, and run Save As in background so that - // progress bar can update without freezing +// Class used to handle progress bar, and run Save As or Add File in +// background so that +// progress bar can update without freezing public class ProgressBarGUI extends JFrame implements PropertyChangeListener { private static final long serialVersionUID = 1L; private JProgressBar progressBar; private JLabel saveAsLabel; - private Task t; + private TaskSaveAs t; + private TaskAddFile t2; private File[] copyItems; private File newFolder; - - // create a new background thread - public class Task extends SwingWorker { + private File addFile, sourceFile; + + // create a new background thread to save as + public class TaskSaveAs extends SwingWorker { @Override protected Void doInBackground() throws Exception { @@ -939,8 +943,8 @@ public class Sketch { new File(ProgressBarGUI.this.newFolder, copyable.getName()), this,progress,totalSize); if (getFileLength(copyable)<524288) { - // If the file length > 50MB, the Base.copyFile() function has - // been redesigned to change progress every 50MB so that + // If the file length > 0.5MB, the Base.copyFile() function has + // been redesigned to change progress every 0.5MB so that // the progress bar doesn't stagnate during that time progress += getFileLength(copyable); setProgress((int) Math.min( @@ -968,14 +972,59 @@ public class Sketch { } + // create a new background thread to add a file + public class TaskAddFile extends SwingWorker { + + @Override + protected Void doInBackground() throws Exception { + // a large part of the file copying happens in this background + // thread + + int i = 0; + long progress = 0; + setProgress(0); + + Base.copyFile(sourceFile, addFile, this); + + if (addFile.length()<1024) { + // If the file length > 1kB, the Base.copyFile() function has + // been redesigned to change progress every 1kB so that + // the progress bar doesn't stagnate during that time + + // If file <1 kB, just fill up Progress Bar to 100% + // directly, since time to copy is now negligable (when + // perceived by a human, anyway) + setProgress(100); + } + + return null; + } + + public void setProgressBarStatus(int status) { + setProgress(status); + } + + @Override + public void done() { + // to close the progress bar automatically when done, and to + // print that adding file is done in Message Area + + editor.statusNotice("One file added to the sketch."); + ProgressBarGUI.this.closeProgressBar(); + } + + } + + + //Use for Save As public ProgressBarGUI(File[] c, File nf, String oldName, String newName) { // initialize a copyItems and newFolder, which are used for file // copying in the background thread copyItems = c; newFolder = nf; - // the UI of the progres bar follows - setDefaultCloseOperation(DISPOSE_ON_CLOSE); + // the UI of the progress bar follows + setDefaultCloseOperation(HIDE_ON_CLOSE); setBounds(200, 200, 400, 140); setResizable(false); setTitle("Saving As..."); @@ -995,13 +1044,50 @@ public class Sketch { Toolkit.setIcon(this); this.setVisible(true); - // create an instance of Task and run execute() on this instance to + // create an instance of TaskSaveAs and run execute() on this + // instance to // start background thread - t = new Task(); + t = new TaskSaveAs(); t.addPropertyChangeListener(this); t.execute(); } + //Use for Add File + public ProgressBarGUI(File sf, File add) { + + addFile = add; + sourceFile = sf; + + // the UI of the progress bar follows + setDefaultCloseOperation(HIDE_ON_CLOSE); + setBounds(200, 200, 400, 140); + setResizable(false); + setTitle("Adding File..."); + JPanel panel = new JPanel(null); + add(panel); + setContentPane(panel); + saveAsLabel = new JLabel("Adding "+addFile.getName()); + saveAsLabel.setBounds(40, 20, 300, 20); + + progressBar = new JProgressBar(0, 100); + progressBar.setValue(0); + progressBar.setBounds(40, 50, 300, 30); + progressBar.setStringPainted(true); + + panel.add(progressBar); + panel.add(saveAsLabel); + Toolkit.setIcon(this); + this.setVisible(true); + + // create an instance of TaskAddFile and run execute() on this + // instance to + // start background thread + t2 = new TaskAddFile(); + t2.addPropertyChangeListener(this); + t2.execute(); + } + + public long getFileLength(File f)// function to return the length of // the file, or // ENTIRE directory, including the @@ -1110,7 +1196,8 @@ public class Sketch { boolean result = addFile(sourceFile); if (result) { - editor.statusNotice("One file added to the sketch."); +// editor.statusNotice("One file added to the sketch."); + //Done from within TaskAddFile inner class when copying is completed } } @@ -1203,16 +1290,18 @@ public class Sketch { // in case the user is "adding" the code in an attempt // to update the sketch's tabs - if (!sourceFile.equals(destFile)) { - try { - Base.copyFile(sourceFile, destFile); - - } catch (IOException e) { - Base.showWarning("Error adding file", - "Could not add '" + filename + "' to the sketch.", e); - return false; - } - } + if (!sourceFile.equals(destFile)) { + final File sourceFile2 = sourceFile; + final File destFile2 = destFile; + // Create a new event dispatch thread- to display ProgressBar + // while Saving As + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + ProgressBarGUI p = new ProgressBarGUI(sourceFile2, + destFile2); + } + }); + } if (codeExtension != null) { SketchCode newCode = new SketchCode(destFile, codeExtension); From 7ba3944f29e14544049ee885d749d933282ec7c8 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 19 Mar 2014 13:50:50 +0530 Subject: [PATCH 303/608] diabling auto save, switching focus on other stuff for now --- .../processing/mode/experimental/AutoSaveUtil.java | 5 ++++- .../processing/mode/experimental/DebugEditor.java | 14 +++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pdex/src/processing/mode/experimental/AutoSaveUtil.java b/pdex/src/processing/mode/experimental/AutoSaveUtil.java index 3141ed65a..7efa14ec0 100644 --- a/pdex/src/processing/mode/experimental/AutoSaveUtil.java +++ b/pdex/src/processing/mode/experimental/AutoSaveUtil.java @@ -60,6 +60,7 @@ public class AutoSaveUtil { * @param timeOut - in minutes, how frequently should saves occur */ public AutoSaveUtil(DebugEditor dedit, int timeOut){ + /* editor = dedit; if (timeOut < 1) { // less than 1 minute not allowed! saveTime = -1; @@ -77,7 +78,7 @@ public class AutoSaveUtil { autosaveDir = new File(editor.getSketch().getFolder().getAbsolutePath() + File.separator + AUTOSAVEFOLDER); sketchFolder = editor.getSketch().getFolder(); sketchBackupFolder = autosaveDir; - } + }*/ } /** @@ -153,6 +154,7 @@ public class AutoSaveUtil { * Start the auto save service */ public void init(){ + /* if(isAutoSaveBackup) { log("AutoSaver not started"); return; @@ -163,6 +165,7 @@ public class AutoSaveUtil { timer.schedule(new SaveTask(), saveTime, saveTime); isSaving = false; log("AutoSaver started"); + */ } /** diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index ee4735086..20206c186 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -342,10 +342,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { // Added temporarily to dump error log. TODO: Remove this later public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); - if(autosaver != null && !viewingAutosaveBackup) { - log("stopping autosaver in internalCloseRunner"); - autosaver.stop(); - } +// if(autosaver != null && !viewingAutosaveBackup) { +// log("stopping autosaver in internalCloseRunner"); +// autosaver.stop(); +// } super.internalCloseRunner(); } @@ -750,8 +750,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { variableInspector().reset(); // clear contents of variable inspector } //if(didOpen){ - - loadAutoSaver(); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); // this is used instead of loadAutosaver(), temp measure + //loadAutoSaver(); viewingAutosaveBackup = autosaver.isAutoSaveBackup(); log("handleOpenInternal, viewing autosave? " + viewingAutosaveBackup); //} @@ -932,7 +932,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { * Also handles the case where an auto save backup is found. * The user is asked to save the sketch to a new location */ - public void loadAutoSaver(){ + private void loadAutoSaver(){ log("Load Auto Saver()"); autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { From c638aac7b3adc8b0eedbd4aed356edac733b3011 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 19 Mar 2014 23:48:05 +0530 Subject: [PATCH 304/608] fixes #45, application export --- pdex/application/Info.plist.tmpl | 3 +-- .../template.app/Contents/MacOS/JavaApplicationStub | Bin pdex/application/template.app/Contents/PkgInfo | 0 pdex/application/template.exe | Bin pdex/application/template.plist | 0 5 files changed, 1 insertion(+), 2 deletions(-) mode change 100644 => 100755 pdex/application/template.app/Contents/MacOS/JavaApplicationStub mode change 100644 => 100755 pdex/application/template.app/Contents/PkgInfo mode change 100644 => 100755 pdex/application/template.exe mode change 100644 => 100755 pdex/application/template.plist diff --git a/pdex/application/Info.plist.tmpl b/pdex/application/Info.plist.tmpl index 787f56ed2..28a2e0277 100644 --- a/pdex/application/Info.plist.tmpl +++ b/pdex/application/Info.plist.tmpl @@ -32,8 +32,7 @@ Created with Processing - JVMRuntime - @@jdk_folder@@ + @@jvm_runtime@@ JVMMainClassName @@sketch@@ diff --git a/pdex/application/template.app/Contents/MacOS/JavaApplicationStub b/pdex/application/template.app/Contents/MacOS/JavaApplicationStub old mode 100644 new mode 100755 diff --git a/pdex/application/template.app/Contents/PkgInfo b/pdex/application/template.app/Contents/PkgInfo old mode 100644 new mode 100755 diff --git a/pdex/application/template.exe b/pdex/application/template.exe old mode 100644 new mode 100755 diff --git a/pdex/application/template.plist b/pdex/application/template.plist old mode 100644 new mode 100755 From bc26658ca955f9d92c1877d41ec8e1efdf6b9b03 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 26 Mar 2014 19:31:48 +0530 Subject: [PATCH 305/608] trying to look into the breakpoint issue --- pdex/src/processing/mode/experimental/DebugEditor.java | 2 +- pdex/src/processing/mode/experimental/LineBreakpoint.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 20206c186..3e4041e70 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -891,7 +891,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } } // if file location has changed, update autosaver - autosaver.reloadAutosaveDir(); + // autosaver.reloadAutosaveDir(); return saved; } diff --git a/pdex/src/processing/mode/experimental/LineBreakpoint.java b/pdex/src/processing/mode/experimental/LineBreakpoint.java index 8d006fd9d..931ea9b49 100755 --- a/pdex/src/processing/mode/experimental/LineBreakpoint.java +++ b/pdex/src/processing/mode/experimental/LineBreakpoint.java @@ -53,6 +53,7 @@ public class LineBreakpoint implements ClassLoadListener { this.dbg = dbg; theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded set(); // activate the breakpoint (show highlight, attach if debugger is running) + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + theClass, new Object[]{}); } /** @@ -108,6 +109,7 @@ public class LineBreakpoint implements ClassLoadListener { return; } try { + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0}", new Object[]{theClass}); List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); if (locations.isEmpty()) { Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); From 98aced8a0cbcdea3a50e8e58f4ca6773ff30535b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Mar 2014 02:35:07 +0530 Subject: [PATCH 306/608] wasn't too tough after all.. Fixes #51 --- pdex/src/processing/mode/experimental/ASTGenerator.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9d74fd4ee..9392fcb30 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1618,7 +1618,13 @@ public class ASTGenerator { log("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); - log("+++> " + simpName); + + if(simpName == null){ //Added while fixing #51 + log("1+++> " + simpName); + simpName = pinpointOnLine(lineNode.getParent(), altOff, + lineNode.getStartPosition(), name); + } + log("2+++> " + simpName); if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); From cf6debb607b3dbead4f2c89a6d841c54b9bda3e5 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 30 Mar 2014 03:08:46 +0530 Subject: [PATCH 307/608] right click on classes with javadoc, related to #51 --- .../mode/experimental/ASTGenerator.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 9392fcb30..325a98b81 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -238,7 +238,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -1625,6 +1625,21 @@ public class ASTGenerator { lineNode.getStartPosition(), name); } log("2+++> " + simpName); + if(simpName == null && lineNode instanceof SimpleName){ + switch (lineNode.getParent().getNodeType()) { + case ASTNode.TYPE_DECLARATION: + + case ASTNode.METHOD_DECLARATION: + + case ASTNode.FIELD_DECLARATION: + + case ASTNode.VARIABLE_DECLARATION_FRAGMENT: + decl = lineNode.getParent(); + return new ASTNodeWrapper(decl,""); + default: + break; + } + } if (simpName instanceof SimpleName) { nameOfNode = simpName.toString(); @@ -2339,7 +2354,7 @@ public class ASTGenerator { if (node instanceof SimpleName) { SimpleName sn = (SimpleName) node; - log(offset+ "off,pol " + getNodeAsString(sn)); + //log(offset+ "off,pol " + getNodeAsString(sn)); if ((lineStartOffset + offset) >= sn.getStartPosition() && (lineStartOffset + offset) <= sn.getStartPosition() + sn.getLength()) { From 18c1cb298a3609baa0e6ec61ef97a673a24c94e3 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 1 Apr 2014 18:30:30 +0530 Subject: [PATCH 308/608] Fixes #45 for ever and ever --- .../processing/mode/experimental/ExperimentalMode.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index a75670057..5b04896d3 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -117,6 +117,15 @@ public class ExperimentalMode extends JavaMode { }; } + public File getContentFile(String path) { + // workaround for #45 + if (path.startsWith("application" + File.separator)) { + return new File(Base.getContentFile("modes" + File.separator + "java") + .getAbsolutePath() + File.separator + path); + } + return new File(folder, path); + } + volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; public static int autoSaveInterval = 3; //in minutes From aefa2f339b2f675f6784b87cfefa07b76c0ca6cf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 1 Apr 2014 19:35:14 +0530 Subject: [PATCH 309/608] Javadocs suck. Screwing the balance everywhere >.< --- .../mode/experimental/ASTNodeWrapper.java | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 6c6cbc6a5..eb35e2215 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -202,6 +202,9 @@ public class ASTNodeWrapper { } /** + * When FD has javadoc attached, the beginning of FD is marked as the + * start of the javadoc. This kind of screws things when trying to locate + * the exact name of the FD. So, offset compensations... * * @param fd * @return @@ -232,6 +235,14 @@ public class ASTNodeWrapper { return 0; } + /** + * When MD has javadoc attached, the beginning of FD is marked as the + * start of the javadoc. This kind of screws things when trying to locate + * the exact name of the MD. So, offset compensations... + * + * @param md + * @return + */ private int getJavadocOffset(MethodDeclaration md) { List list = md.modifiers(); SimpleName sn = (SimpleName) getNode(); @@ -258,8 +269,16 @@ public class ASTNodeWrapper { return 0; } + /** + * When TD has javadoc attached, the beginning of FD is marked as the + * start of the javadoc. This kind of screws things when trying to locate + * the exact name of the TD. So, offset compensations... + * + * @param td + * @return + */ private int getJavadocOffset(TypeDeclaration td){ - // TODO: This is still broken. Hence no refactoring or highlighting on scroll works :\ + // TODO: This isn't perfect yet. Class \n \n \n className still breaks it.. :'( List list= td.modifiers(); list = td.modifiers(); SimpleName sn = (SimpleName) getNode(); @@ -275,7 +294,13 @@ public class ASTNodeWrapper { } } - return 0; + if(td.getJavadoc() != null){ + log("diff " + + (td.getJavadoc().getStartPosition() + td.getJavadoc().getLength() + 1)); + return (td.getJavadoc().getStartPosition() + td.getJavadoc().getLength() + 1); + } + log("getJavadocOffset(TypeDeclaration td) "+sn + ", found nothing. Meh."); + return 0; } /** From 912ef278d90397d2b86e082293427bb8fe7320cf Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 1 Apr 2014 19:59:52 +0530 Subject: [PATCH 310/608] This minor change was long due. --- .../mode/experimental/ErrorCheckerService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index cb9ec65e8..86588100a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -511,7 +511,7 @@ public class ErrorCheckerService implements Runnable{ // Populate the probList problemsList = new ArrayList(); for (int i = 0; i < problems.length; i++) { - int a[] = calculateTabIndexAndLineNumber(problems[i]); + int a[] = calculateTabIndexAndLineNumber(problems[i].getSourceLineNumber()); Problem p = new Problem(problems[i], a[0], a[1] + 1); //TODO: ^Why do cheeky stuff? problemsList.add(p); @@ -642,7 +642,7 @@ public class ErrorCheckerService implements Runnable{ // for (String j : problem.getArguments()) { // log("arg " + j); // } - int a[] = calculateTabIndexAndLineNumber(problem); + int a[] = calculateTabIndexAndLineNumber(problem.getSourceLineNumber()); Problem p = new Problem(problem, a[0], a[1]); if ((Boolean) errorList[i][8]) { p.setType(Problem.ERROR); @@ -1055,16 +1055,16 @@ public class ErrorCheckerService implements Runnable{ * - IProblem * @return int[0] - tab number, int[1] - line number */ - public int[] calculateTabIndexAndLineNumber(IProblem problem) { + public int[] calculateTabIndexAndLineNumber(int javalineNumber) { // String[] lines = {};// = PApplet.split(sourceString, '\n'); int codeIndex = 0; - int x = problem.getSourceLineNumber() - mainClassOffset; + int x = javalineNumber - mainClassOffset; if (x < 0) { // log("Negative line number " // + problem.getSourceLineNumber() + " , offset " // + mainClassOffset); - x = problem.getSourceLineNumber() - 2; // Another -1 for 0 index + x = javalineNumber - 2; // Another -1 for 0 index if (x < programImports.size() && x >= 0) { ImportStatement is = programImports.get(x); // log(is.importName + ", " + is.tab + ", " From 79853f32d923a96d94569cbe95cf91601a847f4e Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 2 Apr 2014 00:37:46 +0530 Subject: [PATCH 311/608] Shifted ProgresSBarGUI inner class to new class Sketch.ProgressBarGUI is now ProgressFrame Also performed some minor formatting --- app/src/processing/app/Base.java | 24 +-- app/src/processing/app/ProgressFrame.java | 248 ++++++++++++++++++++++ app/src/processing/app/Sketch.java | 245 +-------------------- 3 files changed, 265 insertions(+), 252 deletions(-) create mode 100644 app/src/processing/app/ProgressFrame.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 762325af6..d041fd7a3 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2605,7 +2605,7 @@ public class Base { static public void copyFile(File sourceFile, - File targetFile,Sketch.ProgressBarGUI.TaskSaveAs progBar, + File targetFile,ProgressFrame.TaskSaveAs progBar, double progress,double totalSize) throws IOException { // Overloaded copyFile that is called whenever a Save As is being done, so that the // ProgressBar is updated for very large files as well @@ -2623,17 +2623,17 @@ public class Base { { progress += totalRead; progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + Math.ceil(progress * 100.0 / totalSize), 100)); totalRead = 0; } } if (sourceFile.length()>524288) { // Update the progress bar one final time if file size is more than 0.5MB, // otherwise, the update is handled either by the copyDir function, - // or directly by Sketch.ProgressBarGUI.TaskSaveAs.doInBackground() + // or directly by ProgressFrame.TaskSaveAs.doInBackground() progress += totalRead; progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + Math.ceil(progress * 100.0 / totalSize), 100)); } from.close(); from = null; @@ -2646,7 +2646,7 @@ public class Base { } static public void copyFile(File sourceFile, File targetFile, - Sketch.ProgressBarGUI.TaskAddFile progBar) throws IOException { + ProgressFrame.TaskAddFile progBar) throws IOException { // Overloaded copyFile that is called whenever a addFile is being done, // so that the // ProgressBar is updated @@ -2666,8 +2666,8 @@ public class Base { { progress += totalRead; progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double) progress * 100.0 - / (double) totalSize), 100)); + Math.ceil(progress * 100.0 + / totalSize), 100)); totalRead = 0; } } @@ -2675,10 +2675,10 @@ public class Base { // Update the progress bar one final time if file size is more than // 1kB, // otherwise, the update is handled directly by - // Sketch.ProgressBarGUI.TaskAddFile.doInBackground() + // ProgressFrame.TaskAddFile.doInBackground() progress += totalRead; progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double) progress * 100.0 / (double) totalSize), + Math.ceil(progress * 100.0 / totalSize), 100)); } from.close(); @@ -2760,7 +2760,7 @@ public class Base { static public double copyDir(File sourceDir, - File targetDir,Sketch.ProgressBarGUI.TaskSaveAs progBar, + File targetDir,ProgressFrame.TaskSaveAs progBar, double progress,double totalSize) throws IOException { // Overloaded copyDir so that the Save As progress bar gets updated when the // files are in folders as well (like in the data folder) @@ -2780,14 +2780,14 @@ public class Base { //target.mkdirs(); progress = copyDir(source, target, progBar, progress, totalSize); progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + Math.ceil(progress * 100.0 / totalSize), 100)); target.setLastModified(source.lastModified()); } else { copyFile(source, target, progBar, progress, totalSize); // Update SaveAs progress bar progress += source.length(); progBar.setProgressBarStatus((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); + Math.ceil(progress * 100.0 / totalSize), 100)); } } return progress; diff --git a/app/src/processing/app/ProgressFrame.java b/app/src/processing/app/ProgressFrame.java new file mode 100644 index 000000000..9aa5551a2 --- /dev/null +++ b/app/src/processing/app/ProgressFrame.java @@ -0,0 +1,248 @@ +package processing.app; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.SwingWorker; + +//Class used to handle progress bar, and run Save As or Add File in +//background so that +//progress bar can update without freezing +public class ProgressFrame extends JFrame implements PropertyChangeListener { + + private static final long serialVersionUID = 1L; + + private JProgressBar progressBar; + + private JLabel saveAsLabel; + + private TaskSaveAs t; + + private TaskAddFile t2; + + private File[] copyItems; + + private File newFolder; + + private File addFile, sourceFile; + + private Editor editor; + + // create a new background thread to save as + public class TaskSaveAs extends SwingWorker { + + @Override + protected Void doInBackground() throws Exception { + // a large part of the file copying happens in this background + // thread + + long totalSize = 0; + for (File copyable : copyItems) { + totalSize += getFileLength(copyable); + } + + long progress = 0; + setProgress(0); + for (File copyable : ProgressFrame.this.copyItems) { + // loop to copy over the items that make sense, and to set the + // current progress + + if (copyable.isDirectory()) { + Base.copyDir(copyable, new File(ProgressFrame.this.newFolder, + copyable.getName()), this, progress, + totalSize); + progress += getFileLength(copyable); + } else { + Base.copyFile(copyable, new File(ProgressFrame.this.newFolder, + copyable.getName()), this, progress, + totalSize); + if (getFileLength(copyable) < 524288) { + // If the file length > 0.5MB, the Base.copyFile() function has + // been redesigned to change progress every 0.5MB so that + // the progress bar doesn't stagnate during that time + progress += getFileLength(copyable); + setProgress((int) Math.min(Math.ceil(progress * 100.0 / totalSize), + 100)); + } + } + } + + return null; + } + + public void setProgressBarStatus(int status) { + + setProgress(status); + } + + @Override + public void done() { + // to close the progress bar automatically when done, and to + // print that Saving is done in Message Area + + editor.statusNotice("Done Saving."); + ProgressFrame.this.closeProgressBar(); + } + + } + + // create a new background thread to add a file + public class TaskAddFile extends SwingWorker { + + @Override + protected Void doInBackground() throws Exception { + // a large part of the file copying happens in this background + // thread + + setProgress(0); + + Base.copyFile(sourceFile, addFile, this); + + if (addFile.length() < 1024) { + // If the file length > 1kB, the Base.copyFile() function has + // been redesigned to change progress every 1kB so that + // the progress bar doesn't stagnate during that time + + // If file <1 kB, just fill up Progress Bar to 100% + // directly, since time to copy is now negligable (when + // perceived by a human, anyway) + setProgress(100); + } + + return null; + } + + public void setProgressBarStatus(int status) { + setProgress(status); + } + + @Override + public void done() { + // to close the progress bar automatically when done, and to + // print that adding file is done in Message Area + + editor.statusNotice("One file added to the sketch."); + ProgressFrame.this.closeProgressBar(); + } + + } + + //Use for Save As + public ProgressFrame(File[] c, File nf, String oldName, String newName, + Editor editor) { + // initialize a copyItems and newFolder, which are used for file + // copying in the background thread + copyItems = c; + newFolder = nf; + this.editor = editor; + + // the UI of the progress bar follows + setDefaultCloseOperation(HIDE_ON_CLOSE); + setBounds(200, 200, 400, 140); + setResizable(false); + setTitle("Saving As..."); + JPanel panel = new JPanel(null); + add(panel); + setContentPane(panel); + saveAsLabel = new JLabel("Saving " + oldName + " as " + newName + "..."); + saveAsLabel.setBounds(40, 20, 300, 20); + + progressBar = new JProgressBar(0, 100); + progressBar.setValue(0); + progressBar.setBounds(40, 50, 300, 30); + progressBar.setStringPainted(true); + + panel.add(progressBar); + panel.add(saveAsLabel); + Toolkit.setIcon(this); + this.setVisible(true); + + // create an instance of TaskSaveAs and run execute() on this + // instance to + // start background thread + t = new TaskSaveAs(); + t.addPropertyChangeListener(this); + t.execute(); + } + + //Use for Add File + public ProgressFrame(File sf, File add, Editor editor) { + + addFile = add; + sourceFile = sf; + this.editor = editor; + + // the UI of the progress bar follows + setDefaultCloseOperation(HIDE_ON_CLOSE); + setBounds(200, 200, 400, 140); + setResizable(false); + setTitle("Adding File..."); + JPanel panel = new JPanel(null); + add(panel); + setContentPane(panel); + saveAsLabel = new JLabel("Adding " + addFile.getName()); + saveAsLabel.setBounds(40, 20, 300, 20); + + progressBar = new JProgressBar(0, 100); + progressBar.setValue(0); + progressBar.setBounds(40, 50, 300, 30); + progressBar.setStringPainted(true); + + panel.add(progressBar); + panel.add(saveAsLabel); + Toolkit.setIcon(this); + this.setVisible(true); + + // create an instance of TaskAddFile and run execute() on this + // instance to + // start background thread + t2 = new TaskAddFile(); + t2.addPropertyChangeListener(this); + t2.execute(); + } + + public long getFileLength(File f)// function to return the length of + // the file, or + // ENTIRE directory, including the + // component files + // and sub-folders if passed + { + long fol_len = 0; + if (f.isDirectory()) { + String files[] = f.list(); + for (int i = 0; i < files.length; i++) { + File temp = new File(f, files[i]); + if (temp.isDirectory()) { + fol_len += getFileLength(temp); + } else { + fol_len += (temp.length()); + } + } + } else { + return (f.length()); + } + return fol_len; + } + + public void propertyChange(PropertyChangeEvent evt) + // detects a change in the property of the background task, i.e., is + // called when the size of files already copied changes + { + if ("progress" == evt.getPropertyName()) { + int progress = (Integer) evt.getNewValue(); + progressBar.setValue(progress); + } + } + + private void closeProgressBar() + // closes progress bar + { + this.dispose(); + } + +} diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 8e03224ab..58538a455 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -30,9 +30,6 @@ import java.io.*; import javax.swing.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - /** * Stores information about files in the current sketch. @@ -861,9 +858,9 @@ public class Sketch { // Create a new event dispatch thread- to display ProgressBar // while Saving As javax.swing.SwingUtilities.invokeLater(new Runnable() { - public void run() { - ProgressBarGUI p = new ProgressBarGUI(copyItems2,newFolder2,oldName2,newName2); - } + public void run() { + new ProgressFrame(copyItems2, newFolder2, oldName2, newName2, editor); + } }); @@ -897,238 +894,6 @@ public class Sketch { } -// Class used to handle progress bar, and run Save As or Add File in -// background so that -// progress bar can update without freezing - public class ProgressBarGUI extends JFrame implements - PropertyChangeListener { - - private static final long serialVersionUID = 1L; - private JProgressBar progressBar; - private JLabel saveAsLabel; - private TaskSaveAs t; - private TaskAddFile t2; - private File[] copyItems; - private File newFolder; - private File addFile, sourceFile; - - // create a new background thread to save as - public class TaskSaveAs extends SwingWorker { - - @Override - protected Void doInBackground() throws Exception { - // a large part of the file copying happens in this background - // thread - - long totalSize = 0; - for (File copyable : copyItems) { - totalSize += getFileLength(copyable); - } - - int i = 0; - - long progress = 0; - setProgress(0); - for (File copyable : ProgressBarGUI.this.copyItems) { - // loop to copy over the items that make sense, and to set the - // current progress - - if (copyable.isDirectory()) { - Base.copyDir(copyable, - new File(ProgressBarGUI.this.newFolder, - copyable.getName()),this,progress,totalSize); - progress += getFileLength(copyable); - } else { - Base.copyFile(copyable, - new File(ProgressBarGUI.this.newFolder, - copyable.getName()), this,progress,totalSize); - if (getFileLength(copyable)<524288) { - // If the file length > 0.5MB, the Base.copyFile() function has - // been redesigned to change progress every 0.5MB so that - // the progress bar doesn't stagnate during that time - progress += getFileLength(copyable); - setProgress((int) Math.min( - Math.ceil((double)progress * 100.0 / (double)totalSize), 100)); - } - } - } - - return null; - } - - public void setProgressBarStatus(int status) { - - setProgress(status); - } - - @Override - public void done() { - // to close the progress bar automatically when done, and to - // print that Saving is done in Message Area - - editor.statusNotice("Done Saving."); - ProgressBarGUI.this.closeProgressBar(); - } - - } - - // create a new background thread to add a file - public class TaskAddFile extends SwingWorker { - - @Override - protected Void doInBackground() throws Exception { - // a large part of the file copying happens in this background - // thread - - int i = 0; - long progress = 0; - setProgress(0); - - Base.copyFile(sourceFile, addFile, this); - - if (addFile.length()<1024) { - // If the file length > 1kB, the Base.copyFile() function has - // been redesigned to change progress every 1kB so that - // the progress bar doesn't stagnate during that time - - // If file <1 kB, just fill up Progress Bar to 100% - // directly, since time to copy is now negligable (when - // perceived by a human, anyway) - setProgress(100); - } - - return null; - } - - public void setProgressBarStatus(int status) { - setProgress(status); - } - - @Override - public void done() { - // to close the progress bar automatically when done, and to - // print that adding file is done in Message Area - - editor.statusNotice("One file added to the sketch."); - ProgressBarGUI.this.closeProgressBar(); - } - - } - - - //Use for Save As - public ProgressBarGUI(File[] c, File nf, String oldName, String newName) { - // initialize a copyItems and newFolder, which are used for file - // copying in the background thread - copyItems = c; - newFolder = nf; - - // the UI of the progress bar follows - setDefaultCloseOperation(HIDE_ON_CLOSE); - setBounds(200, 200, 400, 140); - setResizable(false); - setTitle("Saving As..."); - JPanel panel = new JPanel(null); - add(panel); - setContentPane(panel); - saveAsLabel = new JLabel("Saving "+oldName+" as "+newName+"..."); - saveAsLabel.setBounds(40, 20, 300, 20); - - progressBar = new JProgressBar(0, 100); - progressBar.setValue(0); - progressBar.setBounds(40, 50, 300, 30); - progressBar.setStringPainted(true); - - panel.add(progressBar); - panel.add(saveAsLabel); - Toolkit.setIcon(this); - this.setVisible(true); - - // create an instance of TaskSaveAs and run execute() on this - // instance to - // start background thread - t = new TaskSaveAs(); - t.addPropertyChangeListener(this); - t.execute(); - } - - //Use for Add File - public ProgressBarGUI(File sf, File add) { - - addFile = add; - sourceFile = sf; - - // the UI of the progress bar follows - setDefaultCloseOperation(HIDE_ON_CLOSE); - setBounds(200, 200, 400, 140); - setResizable(false); - setTitle("Adding File..."); - JPanel panel = new JPanel(null); - add(panel); - setContentPane(panel); - saveAsLabel = new JLabel("Adding "+addFile.getName()); - saveAsLabel.setBounds(40, 20, 300, 20); - - progressBar = new JProgressBar(0, 100); - progressBar.setValue(0); - progressBar.setBounds(40, 50, 300, 30); - progressBar.setStringPainted(true); - - panel.add(progressBar); - panel.add(saveAsLabel); - Toolkit.setIcon(this); - this.setVisible(true); - - // create an instance of TaskAddFile and run execute() on this - // instance to - // start background thread - t2 = new TaskAddFile(); - t2.addPropertyChangeListener(this); - t2.execute(); - } - - - public long getFileLength(File f)// function to return the length of - // the file, or - // ENTIRE directory, including the - // component files - // and sub-folders if passed - { - long fol_len = 0; - if (f.isDirectory()) { - String files[] = f.list(); - for (int i = 0; i < files.length; i++) { - File temp = new File(f, files[i]); - if (temp.isDirectory()) { - fol_len += getFileLength(temp); - } else { - fol_len += (long) (temp.length()); - } - } - } else { - return (long) (f.length()); - } - return fol_len; - } - - public void propertyChange(PropertyChangeEvent evt) - // detects a change in the property of the background task, i.e., is - // called when the size of files already copied changes - { - if ("progress" == evt.getPropertyName()) { - int progress = (Integer) evt.getNewValue(); - progressBar.setValue(progress); - } - } - - private void closeProgressBar() - // closes progress bar - { - this.dispose(); - } - - } - /** * Update internal state for new sketch name or folder location. @@ -1297,8 +1062,8 @@ public class Sketch { // while Saving As javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { - ProgressBarGUI p = new ProgressBarGUI(sourceFile2, - destFile2); + new ProgressFrame(sourceFile2, + destFile2, editor); } }); } From e7a93b9fe0ba07eaba353dd631762df3b8fb8da8 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 2 Apr 2014 12:59:40 +0530 Subject: [PATCH 312/608] All ProgressBar code shifted to ProgressFrame clss Base is now exactly like the original. Only change in Sketch is that a new event dispatch thread has been created during Save As or Add File. Base back to original --- app/src/processing/app/Base.java | 120 ----------------- app/src/processing/app/ProgressFrame.java | 149 ++++++++++++++++++++-- app/src/processing/app/Sketch.java | 11 +- 3 files changed, 145 insertions(+), 135 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index d041fd7a3..50230531b 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2604,92 +2604,6 @@ public class Base { } - static public void copyFile(File sourceFile, - File targetFile,ProgressFrame.TaskSaveAs progBar, - double progress,double totalSize) throws IOException { - // Overloaded copyFile that is called whenever a Save As is being done, so that the - // ProgressBar is updated for very large files as well - BufferedInputStream from = - new BufferedInputStream(new FileInputStream(sourceFile)); - BufferedOutputStream to = - new BufferedOutputStream(new FileOutputStream(targetFile)); - byte[] buffer = new byte[16 * 1024]; - int bytesRead; - int totalRead=0; - while ((bytesRead = from.read(buffer)) != -1) { - to.write(buffer, 0, bytesRead); - totalRead += bytesRead; - if (totalRead >= 524288) //to update progress bar every 0.5MB - { - progress += totalRead; - progBar.setProgressBarStatus((int) Math.min( - Math.ceil(progress * 100.0 / totalSize), 100)); - totalRead = 0; - } - } - if (sourceFile.length()>524288) { - // Update the progress bar one final time if file size is more than 0.5MB, - // otherwise, the update is handled either by the copyDir function, - // or directly by ProgressFrame.TaskSaveAs.doInBackground() - progress += totalRead; - progBar.setProgressBarStatus((int) Math.min( - Math.ceil(progress * 100.0 / totalSize), 100)); - } - from.close(); - from = null; - to.flush(); - to.close(); - to = null; - - targetFile.setLastModified(sourceFile.lastModified()); - targetFile.setExecutable(sourceFile.canExecute()); - } - - static public void copyFile(File sourceFile, File targetFile, - ProgressFrame.TaskAddFile progBar) throws IOException { - // Overloaded copyFile that is called whenever a addFile is being done, - // so that the - // ProgressBar is updated - double totalSize = sourceFile.length(); - int progress = 0; - BufferedInputStream from = new BufferedInputStream(new FileInputStream( - sourceFile)); - BufferedOutputStream to = new BufferedOutputStream( - new FileOutputStream(targetFile)); - byte[] buffer = new byte[16 * 1024]; - int bytesRead; - int totalRead = 0; - while ((bytesRead = from.read(buffer)) != -1) { - to.write(buffer, 0, bytesRead); - totalRead += bytesRead; - if (totalRead >= 1024) // to update progress bar every 1kB - { - progress += totalRead; - progBar.setProgressBarStatus((int) Math.min( - Math.ceil(progress * 100.0 - / totalSize), 100)); - totalRead = 0; - } - } - if (sourceFile.length() > 1024) { - // Update the progress bar one final time if file size is more than - // 1kB, - // otherwise, the update is handled directly by - // ProgressFrame.TaskAddFile.doInBackground() - progress += totalRead; - progBar.setProgressBarStatus((int) Math.min( - Math.ceil(progress * 100.0 / totalSize), - 100)); - } - from.close(); - from = null; - to.flush(); - to.close(); - to = null; - targetFile.setLastModified(sourceFile.lastModified()); - targetFile.setExecutable(sourceFile.canExecute()); -} - /** * Grab the contents of a file as a string. */ @@ -2758,40 +2672,6 @@ public class Base { } } - - static public double copyDir(File sourceDir, - File targetDir,ProgressFrame.TaskSaveAs progBar, - double progress,double totalSize) throws IOException { - // Overloaded copyDir so that the Save As progress bar gets updated when the - // files are in folders as well (like in the data folder) - if (sourceDir.equals(targetDir)) { - final String urDum = "source and target directories are identical"; - throw new IllegalArgumentException(urDum); - } - targetDir.mkdirs(); - String files[] = sourceDir.list(); - for (int i = 0; i < files.length; i++) { - // Ignore dot files (.DS_Store), dot folders (.svn) while copying - if (files[i].charAt(0) == '.') continue; - //if (files[i].equals(".") || files[i].equals("..")) continue; - File source = new File(sourceDir, files[i]); - File target = new File(targetDir, files[i]); - if (source.isDirectory()) { - //target.mkdirs(); - progress = copyDir(source, target, progBar, progress, totalSize); - progBar.setProgressBarStatus((int) Math.min( - Math.ceil(progress * 100.0 / totalSize), 100)); - target.setLastModified(source.lastModified()); - } else { - copyFile(source, target, progBar, progress, totalSize); - // Update SaveAs progress bar - progress += source.length(); - progBar.setProgressBarStatus((int) Math.min( - Math.ceil(progress * 100.0 / totalSize), 100)); - } - } - return progress; - } static public void copyDirNative(File sourceDir, File targetDir) throws IOException { diff --git a/app/src/processing/app/ProgressFrame.java b/app/src/processing/app/ProgressFrame.java index 9aa5551a2..3e91ee54c 100644 --- a/app/src/processing/app/ProgressFrame.java +++ b/app/src/processing/app/ProgressFrame.java @@ -2,7 +2,12 @@ package processing.app; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import javax.swing.JFrame; import javax.swing.JLabel; @@ -53,16 +58,16 @@ public class ProgressFrame extends JFrame implements PropertyChangeListener { // current progress if (copyable.isDirectory()) { - Base.copyDir(copyable, new File(ProgressFrame.this.newFolder, - copyable.getName()), this, progress, - totalSize); + copyDir(copyable, + new File(ProgressFrame.this.newFolder, copyable.getName()), + this, progress, totalSize); progress += getFileLength(copyable); } else { - Base.copyFile(copyable, new File(ProgressFrame.this.newFolder, - copyable.getName()), this, progress, - totalSize); + copyFile(copyable, + new File(ProgressFrame.this.newFolder, copyable.getName()), + this, progress, totalSize); if (getFileLength(copyable) < 524288) { - // If the file length > 0.5MB, the Base.copyFile() function has + // If the file length > 0.5MB, the copyFile() function has // been redesigned to change progress every 0.5MB so that // the progress bar doesn't stagnate during that time progress += getFileLength(copyable); @@ -101,10 +106,10 @@ public class ProgressFrame extends JFrame implements PropertyChangeListener { setProgress(0); - Base.copyFile(sourceFile, addFile, this); + copyFile(sourceFile, addFile, this); if (addFile.length() < 1024) { - // If the file length > 1kB, the Base.copyFile() function has + // If the file length > 1kB, the copyFile() function has // been redesigned to change progress every 1kB so that // the progress bar doesn't stagnate during that time @@ -245,4 +250,130 @@ public class ProgressFrame extends JFrame implements PropertyChangeListener { this.dispose(); } + static public void copyFile(File sourceFile, File targetFile, + ProgressFrame.TaskSaveAs progBar, + double progress, double totalSize) + throws IOException { + // Overloaded copyFile that is called whenever a Save As is being done, so that the + // ProgressBar is updated for very large files as well + BufferedInputStream from = new BufferedInputStream( + new FileInputStream( + sourceFile)); + BufferedOutputStream to = new BufferedOutputStream( + new FileOutputStream( + targetFile)); + byte[] buffer = new byte[16 * 1024]; + int bytesRead; + int totalRead = 0; + while ((bytesRead = from.read(buffer)) != -1) { + to.write(buffer, 0, bytesRead); + totalRead += bytesRead; + if (totalRead >= 524288) //to update progress bar every 0.5MB + { + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 + / totalSize), 100)); + totalRead = 0; + } + } + if (sourceFile.length() > 524288) { + // Update the progress bar one final time if file size is more than 0.5MB, + // otherwise, the update is handled either by the copyDir function, + // or directly by ProgressFrame.TaskSaveAs.doInBackground() + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 + / totalSize), 100)); + } + from.close(); + from = null; + to.flush(); + to.close(); + to = null; + + targetFile.setLastModified(sourceFile.lastModified()); + targetFile.setExecutable(sourceFile.canExecute()); + } + + static public void copyFile(File sourceFile, File targetFile, + ProgressFrame.TaskAddFile progBar) + throws IOException { + // Overloaded copyFile that is called whenever a addFile is being done, + // so that the + // ProgressBar is updated + double totalSize = sourceFile.length(); + int progress = 0; + BufferedInputStream from = new BufferedInputStream( + new FileInputStream( + sourceFile)); + BufferedOutputStream to = new BufferedOutputStream( + new FileOutputStream( + targetFile)); + byte[] buffer = new byte[16 * 1024]; + int bytesRead; + int totalRead = 0; + while ((bytesRead = from.read(buffer)) != -1) { + to.write(buffer, 0, bytesRead); + totalRead += bytesRead; + if (totalRead >= 1024) // to update progress bar every 1kB + { + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 + / totalSize), 100)); + totalRead = 0; + } + } + if (sourceFile.length() > 1024) { + // Update the progress bar one final time if file size is more than + // 1kB, + // otherwise, the update is handled directly by + // ProgressFrame.TaskAddFile.doInBackground() + progress += totalRead; + progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 + / totalSize), 100)); + } + from.close(); + from = null; + to.flush(); + to.close(); + to = null; + targetFile.setLastModified(sourceFile.lastModified()); + targetFile.setExecutable(sourceFile.canExecute()); + } + + static public double copyDir(File sourceDir, File targetDir, + ProgressFrame.TaskSaveAs progBar, + double progress, double totalSize) + throws IOException { + // Overloaded copyDir so that the Save As progress bar gets updated when the + // files are in folders as well (like in the data folder) + if (sourceDir.equals(targetDir)) { + final String urDum = "source and target directories are identical"; + throw new IllegalArgumentException(urDum); + } + targetDir.mkdirs(); + String files[] = sourceDir.list(); + for (int i = 0; i < files.length; i++) { + // Ignore dot files (.DS_Store), dot folders (.svn) while copying + if (files[i].charAt(0) == '.') + continue; + //if (files[i].equals(".") || files[i].equals("..")) continue; + File source = new File(sourceDir, files[i]); + File target = new File(targetDir, files[i]); + if (source.isDirectory()) { + //target.mkdirs(); + progress = copyDir(source, target, progBar, progress, totalSize); + progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 + / totalSize), 100)); + target.setLastModified(source.lastModified()); + } else { + copyFile(source, target, progBar, progress, totalSize); + // Update SaveAs progress bar + progress += source.length(); + progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0 + / totalSize), 100)); + } + } + return progress; + } + } diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 58538a455..ba274a638 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -1060,12 +1060,11 @@ public class Sketch { final File destFile2 = destFile; // Create a new event dispatch thread- to display ProgressBar // while Saving As - javax.swing.SwingUtilities.invokeLater(new Runnable() { - public void run() { - new ProgressFrame(sourceFile2, - destFile2, editor); - } - }); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + new ProgressFrame(sourceFile2, destFile2, editor); + } + }); } if (codeExtension != null) { From 9308c84cdf5b52509ac6281d47bf015802e57668 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 5 Apr 2014 01:23:08 +0530 Subject: [PATCH 313/608] Further work on highlighting issue --- .../mode/experimental/ASTGenerator.java | 7 +- .../mode/experimental/ASTNodeWrapper.java | 76 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 325a98b81..8a58ae2a2 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1678,7 +1678,12 @@ public class ASTGenerator { ASTNode simpName2 = getNodeName(decl,nameOfNode); logE("FINAL String decl: " + getNodeAsString(decl)); logE("FINAL String label: " + getNodeAsString(simpName2)); - errorCheckerService.highlightNode(simpName2); + //errorCheckerService.highlightNode(simpName2); + ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2,nodeLabel); + errorCheckerService.highlightNode(declWrap); +// if (!declWrap.highlightNode(this)) { +// logE("Highlighting failed."); +// } } return new ASTNodeWrapper(decl,nodeLabel); diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index eb35e2215..3ad8bb16c 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -18,6 +18,7 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; import static processing.mode.experimental.ExperimentalMode.log2; import java.util.Iterator; import java.util.List; @@ -25,6 +26,10 @@ import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.PlainDocument; + import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ExpressionStatement; @@ -516,6 +521,77 @@ public class ASTNodeWrapper { return new int[][]{javaCodeMap,pdeCodeMap}; } + public boolean highlightNode(ASTGenerator astGenerator){ + if(!(Node instanceof SimpleName)){ + return false; + } + SimpleName nodeName = (SimpleName) Node; + try { + int javaLineNumber = getLineNumber(nodeName); + int pdeOffs[] = astGenerator.errorCheckerService + .calculateTabIndexAndLineNumber(javaLineNumber); + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, astGenerator.errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(javaLineNumber-1); + if(lineElement == null) { + log(lineNumber + " line element null while highlighting " + nodeName); + return false; + } + + String javaLine = javaSource.getText(lineElement.getStartOffset(), + lineElement.getEndOffset() + - lineElement.getStartOffset()); + astGenerator.editor.getSketch().setCurrentCode(pdeOffs[0]); + String pdeLine = astGenerator.editor.getLineText(pdeOffs[1]); + String lookingFor = nodeName.toString(); + log(lookingFor + ", " + nodeName.getStartPosition()); + log("JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + + lineElement.getEndOffset()); + log("PL " + pdeLine); + if (!javaLine.contains(lookingFor) || !pdeLine.contains(lookingFor)) { + logE("Logical error in highLightNode(). Please file a bug report."); + return false; + } + Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); + Matcher matcher = toFind.matcher(javaLine); + int lsto = lineElement.getStartOffset(); + while(matcher.find()){ + System.out.println(matcher.start() + lsto); + } + // find the count of the name in the java code + int count = 0, index = 0; + do { + index = javaLine.indexOf(lookingFor, index); + if (index != -1) { + count++; + index += lookingFor.length(); + } else + break; + } while (true); + log("count=" + count); + // find the offset of the name of that index in the pde code + index = 0; + while (count > 0) { + index = pdeLine.indexOf(lookingFor, index); + if (index != -1) { + count--; + index += lookingFor.length(); + } + } + log("pde lso " + (index - lookingFor.length())); + + int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); + astGenerator.editor.setSelection(lso + index - lookingFor.length(), lso + + index); + return true; + } catch (BadLocationException e) { + logE("BLE in highLightNode() for " + nodeName); + e.printStackTrace(); + } + return false; + } + /** * Gets offset mapping between java and pde code * int[0][x] stores the java code offset and From 27cf6507a298be6296e55297d63e30d9f82fb47a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 5 Apr 2014 02:14:41 +0530 Subject: [PATCH 314/608] does it work? Or does it not? idk --- .../mode/experimental/ASTGenerator.java | 38 +++++++++++++++++-- .../mode/experimental/ASTNodeWrapper.java | 26 +++++++------ .../experimental/ErrorCheckerService.java | 23 ++++++++++- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 8a58ae2a2..1188b7677 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -53,6 +53,8 @@ import javax.swing.UIManager; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.PlainDocument; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; @@ -1680,10 +1682,10 @@ public class ASTGenerator { logE("FINAL String label: " + getNodeAsString(simpName2)); //errorCheckerService.highlightNode(simpName2); ASTNodeWrapper declWrap = new ASTNodeWrapper(simpName2,nodeLabel); - errorCheckerService.highlightNode(declWrap); -// if (!declWrap.highlightNode(this)) { -// logE("Highlighting failed."); -// } + //errorCheckerService.highlightNode(declWrap); + if (!declWrap.highlightNode(this)) { + logE("Highlighting failed."); + } } return new ASTNodeWrapper(decl,nodeLabel); @@ -1812,6 +1814,34 @@ public class ASTGenerator { if (tnode.getUserObject() instanceof ASTNodeWrapper) { ASTNodeWrapper awrap = (ASTNodeWrapper) tnode.getUserObject(); errorCheckerService.highlightNode(awrap); + + //-- + try { + int javaLineNumber = getLineNumber(awrap.getNode()); + int pdeOffs[] = errorCheckerService + .calculateTabIndexAndLineNumber(javaLineNumber); + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(javaLineNumber-1); + if(lineElement == null) { + return; + } + + String javaLine = javaSource.getText(lineElement.getStartOffset(), + lineElement.getEndOffset() + - lineElement.getStartOffset()); + editor.getSketch().setCurrentCode(pdeOffs[0]); + String pdeLine = editor.getLineText(pdeOffs[1]); + //String lookingFor = nodeName.toString(); + //log(lookingFor + ", " + nodeName.getStartPosition()); + log("JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + + lineElement.getEndOffset()); + log("PL " + pdeLine); + } catch (BadLocationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } }; diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 3ad8bb16c..c0cb491d0 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -546,29 +546,33 @@ public class ASTNodeWrapper { String pdeLine = astGenerator.editor.getLineText(pdeOffs[1]); String lookingFor = nodeName.toString(); log(lookingFor + ", " + nodeName.getStartPosition()); - log("JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + log(javaLineNumber +" JL " + javaLine + " LSO " + lineElement.getStartOffset() + "," + lineElement.getEndOffset()); - log("PL " + pdeLine); + log(pdeOffs[1] + " PL " + pdeLine); if (!javaLine.contains(lookingFor) || !pdeLine.contains(lookingFor)) { logE("Logical error in highLightNode(). Please file a bug report."); return false; } Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); + int count = 0, index = 0; int lsto = lineElement.getStartOffset(); while(matcher.find()){ + count++; System.out.println(matcher.start() + lsto); + if(lsto + matcher.start() == nodeName.getStartPosition()) + break; } // find the count of the name in the java code - int count = 0, index = 0; - do { - index = javaLine.indexOf(lookingFor, index); - if (index != -1) { - count++; - index += lookingFor.length(); - } else - break; - } while (true); + +// do { +// index = javaLine.indexOf(lookingFor, index); +// if (index != -1) { +// count++; +// index += lookingFor.length(); +// } else +// break; +// } while (true); log("count=" + count); // find the offset of the name of that index in the pde code index = 0; diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 86588100a..ec77f9173 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -434,7 +434,7 @@ public class ErrorCheckerService implements Runnable{ // log(sourceCode); // log("--------------------------"); compileCheck(); - astGenerator.buildAST(cu); + //astGenerator.buildAST(cu); log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } @@ -535,6 +535,27 @@ public class ErrorCheckerService implements Runnable{ protected URLClassLoader classLoader; protected void compileCheck() { + + // CU needs to be updated coz before compileCheck xqpreprocessor is run on the source code which makes some further changes + //TODO Check if this breaks things + + parser.setSource(sourceCode.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + + Map options = JavaCore.getOptions(); + + JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options); + options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6); + options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); + parser.setCompilerOptions(options); + + if (cu == null) + cu = (CompilationUnit) parser.createAST(null); + else { + synchronized (cu) { + cu = (CompilationUnit) parser.createAST(null); + } + } // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the From b7f1c04d852c80d6b22f91729f08a366106c9291 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 5 Apr 2014 02:27:29 +0530 Subject: [PATCH 315/608] I guess this is the best that can be done.. --- .../src/processing/mode/experimental/ErrorCheckerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index ec77f9173..41ce2d9ec 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -433,11 +433,11 @@ public class ErrorCheckerService implements Runnable{ // } // log(sourceCode); // log("--------------------------"); - compileCheck(); - //astGenerator.buildAST(cu); + compileCheck(); log(editor.getSketch().getName() + "2 MCO " + mainClassOffset); } + astGenerator.buildAST(cu); if(ExperimentalMode.errorCheckEnabled){ updateErrorTable(); editor.updateErrorBar(problemsList); From 1ce554bc8eeb366030736c7853e78e4d2cd7a0b0 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 15 Apr 2014 02:28:39 +0530 Subject: [PATCH 316/608] Fixes #53 --- .../processing/mode/experimental/ErrorCheckerService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 41ce2d9ec..d908cc51a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -53,6 +53,7 @@ import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import processing.app.Base; import processing.app.Editor; +import processing.app.EditorStatus; import processing.app.Library; import processing.app.SketchCode; import processing.app.syntax.SyntaxDocument; @@ -947,12 +948,16 @@ public class ErrorCheckerService implements Runnable{ } } + protected int lastCaretLine = -1; + /** * Updates editor status bar, depending on whether the caret is on an error * line or not */ public void updateEditorStatus() { + + if(editor.getStatusMode() == EditorStatus.EDIT) return; // editor.statusNotice("Position: " + // editor.getTextArea().getCaretLine()); if(ExperimentalMode.errorCheckEnabled) From a41e77df6f2d960862c4c885a04370305a54b36f Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 15 Apr 2014 02:39:12 +0530 Subject: [PATCH 317/608] Fixes #29 --- .../mode/experimental/ErrorCheckerService.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index d908cc51a..b7fd4be69 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -978,10 +978,17 @@ public class ErrorCheckerService implements Runnable{ } } } - if (editor.ta.getCaretLine() != lastCaretLine) { + + // This line isn't an error line anymore, so probably just clear it + if (editor.getStatusMode() == EditorStatus.ERR + || editor.getStatusMode() == EditorStatus.NOTICE) { editor.statusEmpty(); - lastCaretLine = editor.ta.getCaretLine(); + return; } +// if (editor.ta.getCaretLine() != lastCaretLine) { +// editor.statusEmpty(); +// lastCaretLine = editor.ta.getCaretLine(); +// } } /** From 12a3191cb308bcb57615c472930d24c17a60cf93 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Tue, 15 Apr 2014 12:28:47 +0530 Subject: [PATCH 318/608] a bit of code cleanup --- .../mode/experimental/ASTGenerator.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 1188b7677..ff3709c08 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -3239,17 +3239,16 @@ public class ASTGenerator { } - public void disposeAllWindows(){ - disposeWindow(frmASTView); - disposeWindow(frameAutoComp); - disposeWindow(frmImportSuggest); - disposeWindow(frmOccurenceList); - disposeWindow(frmRename); + public void disposeAllWindows() { + disposeWindow(frmASTView, frameAutoComp, frmImportSuggest, + frmOccurenceList, frmRename); } - public static void disposeWindow(JFrame f) { - if(f != null) - f.dispose(); + public static void disposeWindow(JFrame... f) { + for (JFrame jFrame : f) { + if(jFrame != null) + jFrame.dispose(); + } } public static final String ignoredImports[] = { From fa2f3a7a3fdfb655ad2ffe575b8295b320c021ff Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 19 Apr 2014 23:22:14 +0530 Subject: [PATCH 319/608] Found another bug in refactoring --- .../mode/experimental/ASTNodeWrapper.java | 2 ++ .../mode/experimental/LineBreakpoint.java | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index c0cb491d0..2536e78f8 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -553,6 +553,7 @@ public class ASTNodeWrapper { logE("Logical error in highLightNode(). Please file a bug report."); return false; } + //TODO: Asteriods example. Spaceship ship; wrong highlight Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); int count = 0, index = 0; @@ -583,6 +584,7 @@ public class ASTNodeWrapper { index += lookingFor.length(); } } + log("pde lso " + (index - lookingFor.length())); int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); diff --git a/pdex/src/processing/mode/experimental/LineBreakpoint.java b/pdex/src/processing/mode/experimental/LineBreakpoint.java index 931ea9b49..e35cea22e 100755 --- a/pdex/src/processing/mode/experimental/LineBreakpoint.java +++ b/pdex/src/processing/mode/experimental/LineBreakpoint.java @@ -25,6 +25,10 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import static processing.mode.experimental.ExperimentalMode.log; +import static processing.mode.experimental.ExperimentalMode.logE; +import static processing.mode.experimental.ExperimentalMode.log2; + /** * Model/Controller of a line breakpoint. Can be set before or while debugging. * Adds a highlight using the debuggers view ({@link DebugEditor}). @@ -53,7 +57,7 @@ public class LineBreakpoint implements ClassLoadListener { this.dbg = dbg; theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded set(); // activate the breakpoint (show highlight, attach if debugger is running) - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + theClass, new Object[]{}); + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + className(), new Object[]{}); } /** @@ -109,7 +113,7 @@ public class LineBreakpoint implements ClassLoadListener { return; } try { - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0}", new Object[]{theClass}); + Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "BPs of class: {0} , line " + (javaLine.lineIdx() + 1), new Object[]{theClass}); List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); if (locations.isEmpty()) { Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine}); @@ -189,6 +193,7 @@ public class LineBreakpoint implements ClassLoadListener { if (line.fileName().endsWith(".pde")) { // standard tab ReferenceType mainClass = dbg.getMainClass(); + //System.out.println(dbg.getMainClass().name()); if (mainClass == null) { return null; } @@ -212,9 +217,13 @@ public class LineBreakpoint implements ClassLoadListener { @Override public void classLoaded(ReferenceType theClass) { // check if our class is being loaded + log("Class Loaded: " + theClass.name()); if (theClass.name().equals(className())) { this.theClass = theClass; attach(); } + for (ReferenceType ct : theClass.nestedTypes()) { + log("Nested " + ct.name()); + } } } From b3d6c11cd39b2cf651fe9fb3542371807f9f618a Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sat, 19 Apr 2014 23:27:43 +0530 Subject: [PATCH 320/608] Refactoring bug fix --- .../mode/experimental/ASTNodeWrapper.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 2536e78f8..3b03aa922 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -521,6 +521,12 @@ public class ASTNodeWrapper { return new int[][]{javaCodeMap,pdeCodeMap}; } + /** + * Highlight the ASTNode in the editor, if it's of type + * SimpleName + * @param astGenerator + * @return - true if highlighting was successful + */ public boolean highlightNode(ASTGenerator astGenerator){ if(!(Node instanceof SimpleName)){ return false; @@ -553,7 +559,8 @@ public class ASTNodeWrapper { logE("Logical error in highLightNode(). Please file a bug report."); return false; } - //TODO: Asteriods example. Spaceship ship; wrong highlight + + // First find the name in the java line, and marks its index Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); int count = 0, index = 0; @@ -564,27 +571,18 @@ public class ASTNodeWrapper { if(lsto + matcher.start() == nodeName.getStartPosition()) break; } - // find the count of the name in the java code - -// do { -// index = javaLine.indexOf(lookingFor, index); -// if (index != -1) { -// count++; -// index += lookingFor.length(); -// } else -// break; -// } while (true); log("count=" + count); - // find the offset of the name of that index in the pde code index = 0; - while (count > 0) { - index = pdeLine.indexOf(lookingFor, index); - if (index != -1) { - count--; - index += lookingFor.length(); + // find the same name in the pde line by its index and get its offsets + matcher = toFind.matcher(pdeLine); + while(matcher.find()){ + count--; + if(count == 0){ + log("Found on pde line lso: " + matcher.start()); + index = matcher.end(); + break; } } - log("pde lso " + (index - lookingFor.length())); int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); From bd500259ab92b35fbffa651af252684cf5a1d455 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 1 May 2014 04:18:05 +0530 Subject: [PATCH 321/608] trying to get to the bottom of parameterized type bug --- .../mode/experimental/ASTGenerator.java | 18 +++++++++--------- .../mode/experimental/ErrorCheckerService.java | 8 +++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ff3709c08..0650e8626 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -1545,7 +1545,7 @@ public class ASTGenerator { public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - log("----getASTNodeAt----"); + log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab()); @@ -1558,10 +1558,10 @@ public class ASTGenerator { } } - log("FLON: " + lineNumber); + log("FLON: Node line number " + lineNumber); ASTNode lineNode = findLineOfNode(compilationUnit, lineNumber, offset, name); - log("+> " + lineNode); + log("Node text +> " + lineNode); ASTNode decl = null; String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to @@ -1581,7 +1581,7 @@ public class ASTGenerator { } } } - log("FLON2: " + lineNumber + " LN spos " + log("FLON2: " + lineNumber + " LN start pos " + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); /* * Now I need to see if multiple statements exist with this same line number @@ -1617,16 +1617,16 @@ public class ASTGenerator { } } } - log("FLON3 "+lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); + log("FLON3 new alt off: " + altOff); ASTNode simpName = pinpointOnLine(lineNode, altOff, lineNode.getStartPosition(), name); if(simpName == null){ //Added while fixing #51 - log("1+++> " + simpName); + log("pinpointOnLine 1+++> " + simpName); simpName = pinpointOnLine(lineNode.getParent(), altOff, lineNode.getStartPosition(), name); } - log("2+++> " + simpName); + log("pinpointOnLine 2+++> " + simpName); if(simpName == null && lineNode instanceof SimpleName){ switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: @@ -2386,7 +2386,7 @@ public class ASTGenerator { @SuppressWarnings("unchecked") public static ASTNode pinpointOnLine(ASTNode node, int offset, int lineStartOffset, String name) { - + //log("pinpointOnLine node class: " + node.getClass().getSimpleName()); if (node instanceof SimpleName) { SimpleName sn = (SimpleName) node; //log(offset+ "off,pol " + getNodeAsString(sn)); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index b7fd4be69..5962f8cb5 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -409,13 +409,15 @@ public class ErrorCheckerService implements Runnable{ } + public int compilationUnitState = 0; + protected boolean checkCode() { //log("checkCode() " + textModified.get() ); log("checkCode() " + textModified.get()); lastTimeStamp = System.currentTimeMillis(); try { sourceCode = preprocessCode(editor.getSketch().getMainProgram()); - + compilationUnitState = 0; syntaxCheck(); log(editor.getSketch().getName() + "1 MCO " + mainClassOffset); @@ -503,7 +505,7 @@ public class ErrorCheckerService implements Runnable{ cu = (CompilationUnit) parser.createAST(null); } } - + compilationUnitState = 1; synchronized (problemsList) { // Store errors returned by the ast parser @@ -557,7 +559,7 @@ public class ErrorCheckerService implements Runnable{ cu = (CompilationUnit) parser.createAST(null); } } - + compilationUnitState = 2; // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the // Eclispe JDT compiler, and call its getErrorsAsObj method to obtain From 9a7e1bb9424496e04bb24c5a8884ccbb6ab29a68 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 4 May 2014 16:01:45 +0530 Subject: [PATCH 322/608] before attempting fix --- .../mode/experimental/ASTGenerator.java | 20 +++++++++++++++++++ .../mode/experimental/ASTNodeWrapper.java | 5 ++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 0650e8626..67bca78ce 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1179,6 +1179,26 @@ public class ASTGenerator { return candidates; } + public String getJavaSourceCodeline(int jLineNumber){ + try { + PlainDocument javaSource = new PlainDocument(); + javaSource.insertString(0, errorCheckerService.sourceCode, null); + Element lineElement = javaSource.getDefaultRootElement() + .getElement(jLineNumber-1); + if(lineElement == null) { + log("Couldn't fetch jlinenum " + jLineNumber); + return null; + } + String javaLine = javaSource.getText(lineElement.getStartOffset(), + lineElement.getEndOffset() + - lineElement.getStartOffset()); + return javaLine; + } catch (BadLocationException e) { + logE(e + " in getJavaSourceCodeline() for jinenum: " + jLineNumber); + } + return null; + } + /** * Searches for the particular class in the default list of imports as well as * the Sketch classpath diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 3b03aa922..542d0d80d 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -377,7 +377,7 @@ public class ASTNodeWrapper { * index correction needed. (2) Now all java conversions are applied after * marking the offsets. This ensures that the index order isn't disturbed by * one at a time conversions as done in preprocessCode() in ECS. Took me - * sometime to figure out this was a bug. (3) Next I create a tables(two + * sometime to figure out this was a bug. (3) Next I create a table(two * separate arrays) which allows me to look it up for matching any index * between pde or java version of the snippet. This also lets me find out * any difference in length between both versions. @@ -389,6 +389,8 @@ public class ASTNodeWrapper { */ log("Src:" + source); + // Instead of converting pde into java, how can I simply extract the same source + // from the java code? Think. TODO String sourceAlt = new String(source); TreeMap offsetmap = new TreeMap(); @@ -533,6 +535,7 @@ public class ASTNodeWrapper { } SimpleName nodeName = (SimpleName) Node; try { + //TODO: Redundant code. See ASTGenerator.getJavaSourceCodeline() int javaLineNumber = getLineNumber(nodeName); int pdeOffs[] = astGenerator.errorCheckerService .calculateTabIndexAndLineNumber(javaLineNumber); From b9b74658dbbba58db661cd3c384bb14fd1873cce Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 5 May 2014 02:01:52 +0530 Subject: [PATCH 323/608] work on offset bug fix --- .../mode/experimental/ASTGenerator.java | 2 +- .../mode/experimental/ASTNodeWrapper.java | 36 ++++++++++++------- .../experimental/ErrorCheckerService.java | 10 ++++++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 67bca78ce..ebda1f9ea 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 542d0d80d..3acb311ba 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -196,7 +196,7 @@ public class ASTNodeWrapper { int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength); + int vals[] = createOffsetMapping(ecs, pdeCode,nodeOffset - altStartPos,nodeLength); if (vals != null) return new int[] { lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] }; @@ -315,9 +315,9 @@ public class ASTNodeWrapper { * @param nodeLen * @return int[0] - difference in start offset, int[1] - node length */ - private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) { + private int[] createOffsetMapping(ErrorCheckerService ecs, String source, int inpOffset, int nodeLen) { - int ret[][] = getOffsetMapping(source); + int ret[][] = getOffsetMapping(ecs, source); if(ret == null){ // no offset mapping needed return null; @@ -358,7 +358,7 @@ public class ASTNodeWrapper { * @param source * @return int[0] - java code offsets, int[1] = pde code offsets */ - public int[][] getOffsetMapping(String source){ + public int[][] getOffsetMapping(ErrorCheckerService ecs, String source){ /* * This is some tricky shiz. So detailed explanation follows: @@ -392,8 +392,13 @@ public class ASTNodeWrapper { // Instead of converting pde into java, how can I simply extract the same source // from the java code? Think. TODO String sourceAlt = new String(source); + String sourceJava = ecs.astGenerator.getJavaSourceCodeline(lineNumber); TreeMap offsetmap = new TreeMap(); + if(sourceJava.trim().startsWith("public") && !source.startsWith("public")){ + offsetmap.put(0,6); + //TODO: This is a temp fix. You GOTTA rewrite offset matching + } // Find all #[web color] // Should be 6 digits only. final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W"; @@ -435,7 +440,7 @@ public class ASTNodeWrapper { + Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1) + "("); - } + } if(offsetmap.isEmpty()){ log("No offset matching needed."); return null; @@ -452,8 +457,11 @@ public class ASTNodeWrapper { colorMatcher = colorPattern.matcher(sourceAlt); sourceAlt = colorMatcher.replaceAll("int"); - + + log("From direct source: "); + sourceAlt = sourceJava; log(sourceAlt); + // Create code map. Beware! Dark magic ahead. int javaCodeMap[] = new int[source.length() * 2]; @@ -476,16 +484,20 @@ public class ASTNodeWrapper { pi--; pj--; for (int i = 0; i < kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1]; - pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + if (pi > 1 && pj > 1) { + javaCodeMap[pi] = javaCodeMap[pi - 1]; + pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1; + } } } else { // repeat pde offsets pi--; pj--; for (int i = 0; i < -kval; i++, pi++, pj++) { - javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; - pdeCodeMap[pj] = pdeCodeMap[pj - 1]; + if (pi > 1 && pj > 1) { + javaCodeMap[pi] = javaCodeMap[pi - 1] + 1; + pdeCodeMap[pj] = pdeCodeMap[pj - 1]; + } } } @@ -506,7 +518,7 @@ public class ASTNodeWrapper { pj++; } - // deubg o/p + // debug o/p for (int i = 0; i < pdeCodeMap.length; i++) { if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) { if (i < source.length()) @@ -609,7 +621,7 @@ public class ASTNodeWrapper { public int[][] getOffsetMapping(ErrorCheckerService ecs){ int pdeoffsets[] = getPDECodeOffsets(ecs); String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim(); - return getOffsetMapping(pdeCode); + return getOffsetMapping(ecs, pdeCode); } /** diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 5962f8cb5..b81838cc7 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1163,6 +1163,16 @@ public class ErrorCheckerService implements Runnable{ return new int[] { codeIndex, x }; } + + public int getJavaLineNumFromPDElineNum(int tab, int pdeLineNum){ + int jLineNum = programImports.size() + 1; + for (int i = 0; i < tab; i++) { + SketchCode sc = editor.getSketch().getCode(i); + int len = Base.countLines(sc.getProgram()) + 1; + jLineNum += len; + } + return jLineNum; + } /** * Fetches code from the editor tabs and pre-processes it into parsable pure From f8479ada2b07d339c2be2783bc10aea84c1b4d82 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 5 May 2014 02:02:48 +0530 Subject: [PATCH 324/608] added Utils class, trying edit distance stuff for offset matching --- .../processing/mode/experimental/Utils.java | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 pdex/src/processing/mode/experimental/Utils.java diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java new file mode 100644 index 000000000..d471194ab --- /dev/null +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package processing.mode.experimental; + +/** + * A class containing multiple utility methods + * + * @author Manindra Moharana + * + */ + +public class Utils { + + public static int minDistance(String word1, String word2) { + int len1 = word1.length(); + int len2 = word2.length(); + + // len1+1, len2+1, because finally return dp[len1][len2] + int[][] dp = new int[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) { + dp[i][0] = i; + } + + for (int j = 0; j <= len2; j++) { + dp[0][j] = j; + } + + //iterate though, and check last char + for (int i = 0; i < len1; i++) { + char c1 = word1.charAt(i); + for (int j = 0; j < len2; j++) { + char c2 = word2.charAt(j); + //System.out.print(c1 + "<->" + c2); + //if last two chars equal + if (c1 == c2) { + //update dp value for +1 length + dp[i + 1][j + 1] = dp[i][j]; + System.out.println(); + } else { + int replace = dp[i][j] + 1; + int insert = dp[i][j + 1] + 1; + int delete = dp[i + 1][j] + 1; +// if (replace < delete) { +// System.out.println(" --- D"); +// } else +// System.out.println(" --- R"); + int min = replace > insert ? insert : replace; + min = delete > min ? min : delete; + dp[i + 1][j + 1] = min; + } + } + } +// for (int i = 0; i < dp.length; i++) { +// for (int j = 0; j < dp[0].length; j++) { +// System.out.print(dp[i][j] + " "); +// } +// System.out.println(); +// } + + System.out.println("Edit distance1: " + dp[len1][len2]); + minDistInGrid(dp, 0, 0, len1, len2, word1.toCharArray(), + word2.toCharArray()); + return dp[len1][len2]; + } + + public static int distance(String a, String b) { +// a = a.toLowerCase(); +// b = b.toLowerCase(); + + // i == 0 + int[] costs = new int[b.length() + 1]; + for (int j = 0; j < costs.length; j++) + costs[j] = j; + for (int i = 1; i <= a.length(); i++) { + // j == 0; nw = lev(i - 1, j) + costs[0] = i; + int nw = i - 1; + for (int j = 1; j <= b.length(); j++) { + int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), + a.charAt(i - 1) == b.charAt(j - 1) ? nw : nw + 1); + nw = costs[j]; + costs[j] = cj; + } + } + System.out.println("Edit distance2: " + costs[b.length()]); + return costs[b.length()]; + } + + public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, + char s1[], char s2[]) { +// if(i < s1.length)System.out.print(s1[i] + " <->"); +// if(j < s2.length)System.out.print(s2[j]); + if (i < s1.length && j < s2.length) { + System.out.print(s1[i] + " <-> " + s2[j]); + if (s1[i] != s2[j]) + System.out.println("--"); + } + System.out.println(); + if (i == fi && j == fj) { + System.out.println("Reached end."); + } else { + int a = Integer.MAX_VALUE, b = a, c = a; + if (i < fi) + a = g[i + 1][j]; + if (i < fi && j < fj) + b = g[i][j + 1]; + if (i < fi && j < fj) + c = g[i + 1][j + 1]; + int mini = Math.min(a, Math.min(b, c)); + if (mini == a) { + //System.out.println(s1[i + 1] + " " + s2[j]); + minDistInGrid(g, i + 1, j, fi, fj, s1, s2); + } else if (mini == b) { + //System.out.println(s1[i] + " " + s2[j + 1]); + minDistInGrid(g, i, j + 1, fi, fj, s1, s2); + } else if (mini == c) { + //System.out.println(s1[i + 1] + " " + s2[j + 1]); + minDistInGrid(g, i + 1, j + 1, fi, fj, s1, s2); + } + } + } + + public static void main(String[] args) { + minDistance("c = #qwerty;", "c = 0xffqwerty;"); + //minDistance("c = #bb00aa;", "c = 0xffbb00aa;"); +// distance("c = #bb00aa;", "c = 0xffbb00aa;"); + } +} From 45de56188ef077d7af4db4d02e4b90672dc51ed4 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 7 May 2014 11:42:47 +0530 Subject: [PATCH 325/608] now that's some real progress ;) --- .../processing/mode/experimental/Utils.java | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java index d471194ab..68db30011 100644 --- a/pdex/src/processing/mode/experimental/Utils.java +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -27,10 +27,23 @@ package processing.mode.experimental; public class Utils { + public static String reverse(String s){ + char w[] = s.toCharArray(); + for (int i = 0; i < w.length/2; i++) { + char t = w[i]; + w[i] = w[w.length - 1 - i]; + w[w.length - 1 - i] = t; + } + return new String(w); + } + public static int minDistance(String word1, String word2) { +// word1 = reverse(word1); +// word2 = reverse(word2); int len1 = word1.length(); int len2 = word2.length(); - + System.out.println(word1 + " len: " + len1); + System.out.println(word2 + " len: " + len2); // len1+1, len2+1, because finally return dp[len1][len2] int[][] dp = new int[len1 + 1][len2 + 1]; @@ -52,7 +65,7 @@ public class Utils { if (c1 == c2) { //update dp value for +1 length dp[i + 1][j + 1] = dp[i][j]; - System.out.println(); +// System.out.println(); } else { int replace = dp[i][j] + 1; int insert = dp[i][j + 1] + 1; @@ -67,6 +80,7 @@ public class Utils { } } } + // for (int i = 0; i < dp.length; i++) { // for (int j = 0; j < dp[0].length; j++) { // System.out.print(dp[i][j] + " "); @@ -75,7 +89,7 @@ public class Utils { // } System.out.println("Edit distance1: " + dp[len1][len2]); - minDistInGrid(dp, 0, 0, len1, len2, word1.toCharArray(), + minDistInGrid(dp,len1, len2, 0, 0 , word1.toCharArray(), word2.toCharArray()); return dp[len1][len2]; } @@ -108,38 +122,40 @@ public class Utils { // if(i < s1.length)System.out.print(s1[i] + " <->"); // if(j < s2.length)System.out.print(s2[j]); if (i < s1.length && j < s2.length) { - System.out.print(s1[i] + " <-> " + s2[j]); - if (s1[i] != s2[j]) - System.out.println("--"); + System.out.print(s1[i] + " "+ i +" <-> " + j + " " + s2[j]); +// if (s1[i] != s2[j]) +// System.out.println("--"); } System.out.println(); if (i == fi && j == fj) { System.out.println("Reached end."); } else { int a = Integer.MAX_VALUE, b = a, c = a; - if (i < fi) - a = g[i + 1][j]; - if (i < fi && j < fj) - b = g[i][j + 1]; - if (i < fi && j < fj) - c = g[i + 1][j + 1]; + if (i > 0) + a = g[i - 1][j]; + if (j > 0) + b = g[i][j - 1]; + if (i > 0 && j > 0) + c = g[i - 1][j - 1]; int mini = Math.min(a, Math.min(b, c)); if (mini == a) { //System.out.println(s1[i + 1] + " " + s2[j]); - minDistInGrid(g, i + 1, j, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2); } else if (mini == b) { //System.out.println(s1[i] + " " + s2[j + 1]); - minDistInGrid(g, i, j + 1, fi, fj, s1, s2); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2); } else if (mini == c) { //System.out.println(s1[i + 1] + " " + s2[j + 1]); - minDistInGrid(g, i + 1, j + 1, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2); } } } public static void main(String[] args) { - minDistance("c = #qwerty;", "c = 0xffqwerty;"); - //minDistance("c = #bb00aa;", "c = 0xffbb00aa;"); +// minDistance("c = #qwerty;", "c = 0xffqwerty;"); +// minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); + minDistance("static void main(){;", "public static void main(){;"); +// minDistance("#bb00aa", "0xffbb00aa"); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From d76d5bf6b29cc235405c26dcb447e252d843767e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 7 May 2014 13:10:08 +0530 Subject: [PATCH 326/608] fixed size arrays don't cut it. --- .../processing/mode/experimental/Utils.java | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java index 68db30011..bed7839cd 100644 --- a/pdex/src/processing/mode/experimental/Utils.java +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -18,25 +18,27 @@ package processing.mode.experimental; +import java.util.HashMap; + /** * A class containing multiple utility methods * * @author Manindra Moharana - * + * */ public class Utils { - - public static String reverse(String s){ + + public static String reverse(String s) { char w[] = s.toCharArray(); - for (int i = 0; i < w.length/2; i++) { + for (int i = 0; i < w.length / 2; i++) { char t = w[i]; w[i] = w[w.length - 1 - i]; w[w.length - 1 - i] = t; } return new String(w); } - + public static int minDistance(String word1, String word2) { // word1 = reverse(word1); // word2 = reverse(word2); @@ -80,17 +82,24 @@ public class Utils { } } } - + // for (int i = 0; i < dp.length; i++) { // for (int j = 0; j < dp[0].length; j++) { // System.out.print(dp[i][j] + " "); // } // System.out.println(); // } - + int maxLen = Math.max(len1, len2); + int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; System.out.println("Edit distance1: " + dp[len1][len2]); - minDistInGrid(dp,len1, len2, 0, 0 , word1.toCharArray(), - word2.toCharArray()); + minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), + word2.toCharArray(), pdeCodeMap, javaCodeMap, maxLen); + System.out.println("PDE-to-Java"); + for (int i = 0; i < maxLen; i++) { + System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); + System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " + + word2.charAt(javaCodeMap[i])); + } return dp[len1][len2]; } @@ -118,11 +127,14 @@ public class Utils { } public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, - char s1[], char s2[]) { + char s1[], char s2[], int pdeCodeMap[], + int javaCodeMap[], int k) { // if(i < s1.length)System.out.print(s1[i] + " <->"); // if(j < s2.length)System.out.print(s2[j]); if (i < s1.length && j < s2.length) { - System.out.print(s1[i] + " "+ i +" <-> " + j + " " + s2[j]); + pdeCodeMap[k] = i; + javaCodeMap[k] = j; + System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j] + " k = " + k); // if (s1[i] != s2[j]) // System.out.println("--"); } @@ -140,21 +152,25 @@ public class Utils { int mini = Math.min(a, Math.min(b, c)); if (mini == a) { //System.out.println(s1[i + 1] + " " + s2[j]); - minDistInGrid(g, i - 1, j, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, + k - 1); } else if (mini == b) { //System.out.println(s1[i] + " " + s2[j + 1]); - minDistInGrid(g, i, j - 1, fi, fj, s1, s2); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, + k - 1); } else if (mini == c) { //System.out.println(s1[i + 1] + " " + s2[j + 1]); - minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, + k - 1); } } } public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); + minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); // minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); - minDistance("static void main(){;", "public static void main(){;"); +// minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } From 1fe2f06be7e1667a008cbba4eda39272831f9b19 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 7 May 2014 14:24:40 +0530 Subject: [PATCH 327/608] too much trouble this --- .../processing/mode/experimental/Utils.java | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java index bed7839cd..09007ab8d 100644 --- a/pdex/src/processing/mode/experimental/Utils.java +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -18,6 +18,7 @@ package processing.mode.experimental; +import java.util.ArrayList; import java.util.HashMap; /** @@ -39,7 +40,7 @@ public class Utils { return new String(w); } - public static int minDistance(String word1, String word2) { + public int minDistance(String word1, String word2) { // word1 = reverse(word1); // word2 = reverse(word2); int len1 = word1.length(); @@ -89,17 +90,24 @@ public class Utils { // } // System.out.println(); // } - int maxLen = Math.max(len1, len2); - int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; - System.out.println("Edit distance1: " + dp[len1][len2]); +// int maxLen = Math.max(len1, len2)+2; +// int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; +// System.out.println("Edit distance1: " + dp[len1][len2]); + ArrayList alist = new ArrayList(); minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), - word2.toCharArray(), pdeCodeMap, javaCodeMap, maxLen); + word2.toCharArray(), alist); System.out.println("PDE-to-Java"); - for (int i = 0; i < maxLen; i++) { - System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); - System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " - + word2.charAt(javaCodeMap[i])); +// for (int i = 0; i < maxLen; i++) { +// System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); +// System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " +// + word2.charAt(javaCodeMap[i])); +// } + for (int i = 0; i < alist.size(); i++) { + System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); + System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " + + word2.charAt(alist.get(i).javaOffset)); } + System.out.println("Length " + alist.size()); return dp[len1][len2]; } @@ -126,15 +134,15 @@ public class Utils { return costs[b.length()]; } - public static void minDistInGrid(int g[][], int i, int j, int fi, int fj, - char s1[], char s2[], int pdeCodeMap[], - int javaCodeMap[], int k) { + public void minDistInGrid(int g[][], int i, int j, int fi, int fj, + char s1[], char s2[], ArrayList set) { // if(i < s1.length)System.out.print(s1[i] + " <->"); // if(j < s2.length)System.out.print(s2[j]); if (i < s1.length && j < s2.length) { - pdeCodeMap[k] = i; - javaCodeMap[k] = j; - System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j] + " k = " + k); +// pdeCodeMap[k] = i; +// javaCodeMap[k] = j; + System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); + set.add(new OfsSet(i, j)); // if (s1[i] != s2[j]) // System.out.println("--"); } @@ -152,23 +160,28 @@ public class Utils { int mini = Math.min(a, Math.min(b, c)); if (mini == a) { //System.out.println(s1[i + 1] + " " + s2[j]); - minDistInGrid(g, i - 1, j, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, - k - 1); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2,set); } else if (mini == b) { //System.out.println(s1[i] + " " + s2[j + 1]); - minDistInGrid(g, i, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, - k - 1); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2, set); } else if (mini == c) { //System.out.println(s1[i + 1] + " " + s2[j + 1]); - minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, pdeCodeMap, javaCodeMap, - k - 1); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, set); } } } + + public class OfsSet { + public final int pdeOffset, javaOffset; + public OfsSet(int pde, int java){ + pdeOffset = pde; + javaOffset = java; + } + } public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); - minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + new Utils().minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); // minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); From 34fdfe6a50b829589906e4aebf3c1e78e3e9a76b Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 9 May 2014 22:06:54 +0530 Subject: [PATCH 328/608] release notes for 1.0.4 --- pdex/pdeX.txt | 4 ++-- pdex/revisions.txt | 24 ++++++++++++++++++- .../mode/experimental/ASTNodeWrapper.java | 4 ++-- .../experimental/ErrorCheckerService.java | 9 +++++++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/pdex/pdeX.txt b/pdex/pdeX.txt index 2cc551f78..7c2a3aa85 100644 --- a/pdex/pdeX.txt +++ b/pdex/pdeX.txt @@ -3,5 +3,5 @@ authorList=[The Processing Foundation](http://processing.org) url=https://github.com/processing/processing-experimental sentence=The next generation of PDE paragraph=Intelligent Code Completion, Live Error Checker, Debugger, Auto Refactor, etc. -version=6 -prettyVersion=1.0.3b +version=7 +prettyVersion=1.0.4b diff --git a/pdex/revisions.txt b/pdex/revisions.txt index 5a2a1fd3b..647859ae0 100644 --- a/pdex/revisions.txt +++ b/pdex/revisions.txt @@ -1,11 +1,33 @@ -PDE X v1.0.4b - February , 2014 +PDE X v1.0.4b - May 9, 2014 + +Requires Processing 2.1.2 or above. Bug fixes ++ Disabled auto-save. My sincere apologies to those who lost data due +to this bug. It was wrong of me to release an untested feature without +adding an option to enable/disable it. I've learnt a lesson and I shall +ensure this sort of thing doesn't happen again in the future. + + Autocompletion bug, column is sometimes off by 1 https://github.com/processing/processing-experimental/issues/38 ++ Persistent completion dialog on OS X +https://github.com/processing/processing-experimental/issues/32 + ++ Status bar update bug +https://github.com/processing/processing-experimental/issues/29 + ++ Export application broken +https://github.com/processing/processing-experimental/issues/45 + ++ Status Bar - New Tab prompt bug +https://github.com/processing/processing-experimental/issues/53 + ++ Show usage fails for methods which have javadoc comment +https://github.com/processing/processing-experimental/issues/51 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PDE X v1.0.3b - January 21, 2014 diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 3acb311ba..2823cc9e7 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -459,7 +459,7 @@ public class ASTNodeWrapper { sourceAlt = colorMatcher.replaceAll("int"); log("From direct source: "); - sourceAlt = sourceJava; +// sourceAlt = sourceJava; log(sourceAlt); @@ -582,7 +582,7 @@ public class ASTNodeWrapper { int lsto = lineElement.getStartOffset(); while(matcher.find()){ count++; - System.out.println(matcher.start() + lsto); + //log(matcher.start() + lsto); if(lsto + matcher.start() == nodeName.getStartPosition()) break; } diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index b81838cc7..92948c09a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -213,6 +213,7 @@ public class ErrorCheckerService implements Runnable{ protected ErrorMessageSimplifier errorMsgSimplifier; public ErrorCheckerService(DebugEditor debugEditor) { + ensureMinP5Version(); this.editor = debugEditor; stopThread = new AtomicBoolean(false); pauseThread = new AtomicBoolean(false); @@ -283,6 +284,14 @@ public class ErrorCheckerService implements Runnable{ } }); } + + public void ensureMinP5Version(){ + // Processing 2.1.2 - Revision 0225 + if(Base.getRevision() < 225){ +// System.err.println("ERROR: PDE X requires Processing 2.1.2 or higher."); + Base.showWarning("Error", "ERROR: PDE X requires Processing 2.1.2 or higher.", null); + } + } public void run() { stopThread.set(false); From 33fcb1c4e4e9204b84fbd6a8c8272013d1c68350 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Tue, 20 May 2014 23:16:06 +0530 Subject: [PATCH 329/608] Open sketches display in Sketch menu Consists of 3 commits all squashed up. Used Menu Listener in the end over polling. --- app/src/processing/app/Editor.java | 41 +++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index cfe93d750..99146a533 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -895,10 +895,49 @@ public abstract class Editor extends JFrame implements RunnerListener { }); sketchMenu.add(item); + sketchMenu.add(item); + + sketchMenu.addSeparator(); + + sketchMenu.addMenuListener(new MenuListener() { + + java.util.List menuList = new java.util.ArrayList(); + + @Override + public void menuSelected(MenuEvent arg0) { + java.util.List ed = base.getEditors(); + JMenuItem item; + for (Editor editor2 : ed) + { + item = new JMenuItem(editor2.getSketch().getName()); + item.setText(editor2.getSketch().getName() + " (" + + editor2.getMode().getTitle() + ")"); + sketchMenu.add(item); + menuList.add(item); + } + } + + @Override + public void menuDeselected(MenuEvent arg0) { + for (JMenuItem it : menuList) + sketchMenu.remove(it); + menuList.clear(); + } + + @Override + public void menuCanceled(MenuEvent arg0) { + menuDeselected(arg0); + } + }); + return sketchMenu; } - + //DONE: Handle closing of sketches + //DONE: Destroy uneccesary background threads when a sketch has been closed + //TODO: Handle changing mode of sketches + //TODO: Make current sketch at the top of the list / tick mark it + //TODO: Bring sketch to foreground when it is clicked (duh :p) abstract public void handleImportLibrary(String jarPath); From 879911fcda0c79a4d7f0ea4f53dedcfecf3852e9 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 21 May 2014 12:26:26 +0530 Subject: [PATCH 330/608] Added a submenu; sketch now comes to front. Consists of 2 commits all squashed up. --- app/src/processing/app/Editor.java | 75 +++++++++++++++++------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 99146a533..f993e7717 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -895,49 +895,58 @@ public abstract class Editor extends JFrame implements RunnerListener { }); sketchMenu.add(item); - sketchMenu.add(item); - sketchMenu.addSeparator(); - + sketchMenu.addMenuListener(new MenuListener() { - java.util.List menuList = new java.util.ArrayList(); - - @Override - public void menuSelected(MenuEvent arg0) { - java.util.List ed = base.getEditors(); - JMenuItem item; - for (Editor editor2 : ed) - { - item = new JMenuItem(editor2.getSketch().getName()); - item.setText(editor2.getSketch().getName() + " (" - + editor2.getMode().getTitle() + ")"); - sketchMenu.add(item); - menuList.add(item); - } - } + java.util.List menuList = new java.util.ArrayList(); - @Override - public void menuDeselected(MenuEvent arg0) { - for (JMenuItem it : menuList) - sketchMenu.remove(it); - menuList.clear(); - } + JMenu openSketchesSubmenu = new JMenu("Open Sketches"); - @Override - public void menuCanceled(MenuEvent arg0) { - menuDeselected(arg0); - } - }); + @Override + public void menuSelected(MenuEvent arg0) { + java.util.List ed = base.getEditors(); + JMenuItem item; + for (final Editor editor2 : ed) { + item = new JMenuItem(editor2.getSketch().getName()); + item.setText(editor2.getSketch().getName() + " (" + + editor2.getMode().getTitle() + ")"); + item.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + editor2.setState(Frame.NORMAL); + editor2.setVisible(true); + editor2.toFront(); + } + }); + + openSketchesSubmenu.add(item); + menuList.add(item); + } + sketchMenu.add(openSketchesSubmenu); + } + + @Override + public void menuDeselected(MenuEvent arg0) { + for (JMenuItem it : menuList) + openSketchesSubmenu.remove(it); + menuList.clear(); + sketchMenu.remove(openSketchesSubmenu); + } + + @Override + public void menuCanceled(MenuEvent arg0) { + menuDeselected(arg0); + } + }); + return sketchMenu; } - //DONE: Handle closing of sketches - //DONE: Destroy uneccesary background threads when a sketch has been closed - //TODO: Handle changing mode of sketches + //TODO: Make current sketch at the top of the list / tick mark it - //TODO: Bring sketch to foreground when it is clicked (duh :p) abstract public void handleImportLibrary(String jarPath); From c82d72653f8b866040259e01f45d341a062d89a8 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Thu, 29 May 2014 00:25:14 +0530 Subject: [PATCH 331/608] Open Sketches Sub-Menu implementation complete Current sketch is now indicated with a check box --- app/src/processing/app/Editor.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index f993e7717..6ea9f309d 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -897,7 +897,11 @@ public abstract class Editor extends JFrame implements RunnerListener { sketchMenu.addSeparator(); - sketchMenu.addMenuListener(new MenuListener() { + final Editor editorName = this; + + sketchMenu.addMenuListener(new MenuListener() { // Menu Listener so that + // the Open Sketches sub-menu is populated + // only when the Sketch menu is opened java.util.List menuList = new java.util.ArrayList(); @@ -908,11 +912,19 @@ public abstract class Editor extends JFrame implements RunnerListener { java.util.List ed = base.getEditors(); JMenuItem item; for (final Editor editor2 : ed) { - item = new JMenuItem(editor2.getSketch().getName()); + if (editorName.getSketch().getName().trim().contains(editor2.getSketch().getName().trim())) + { + item = new JCheckBoxMenuItem(editor2.getSketch().getName()); + item.setSelected(true); + } + else + { + item = new JMenuItem(editor2.getSketch().getName()); + } item.setText(editor2.getSketch().getName() + " (" + editor2.getMode().getTitle() + ")"); - - item.addActionListener(new ActionListener() { + + item.addActionListener(new ActionListener() { // Action listener to bring the appropriate sketch in front @Override public void actionPerformed(ActionEvent e) { @@ -921,7 +933,6 @@ public abstract class Editor extends JFrame implements RunnerListener { editor2.toFront(); } }); - openSketchesSubmenu.add(item); menuList.add(item); } @@ -946,7 +957,6 @@ public abstract class Editor extends JFrame implements RunnerListener { } - //TODO: Make current sketch at the top of the list / tick mark it abstract public void handleImportLibrary(String jarPath); From 96f50e975fe318a147c036325dba72fd56086b56 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Sun, 1 Jun 2014 17:02:05 +0530 Subject: [PATCH 332/608] Fixes #66 --- .../mode/experimental/CompletionPanel.java | 63 +++++++++++-------- .../mode/experimental/DebugEditor.java | 2 +- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/pdex/src/processing/mode/experimental/CompletionPanel.java b/pdex/src/processing/mode/experimental/CompletionPanel.java index cadc007e3..00ee4e105 100644 --- a/pdex/src/processing/mode/experimental/CompletionPanel.java +++ b/pdex/src/processing/mode/experimental/CompletionPanel.java @@ -22,16 +22,12 @@ import static processing.mode.experimental.ExperimentalMode.log2; import static processing.mode.experimental.ExperimentalMode.logE; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Point; -import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.Iterator; -import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JLabel; import javax.swing.JList; @@ -210,17 +206,29 @@ public class CompletionPanel { public boolean insertSelection() { if (completionList.getSelectedValue() != null) { try { + // If user types 'abc.', subword becomes '.' and null is returned String currentSubword = fetchCurrentSubword(); + int currentSubwordLen = currentSubword == null ? 0 : currentSubword + .length(); + //logE(currentSubword + " <= subword,len => " + currentSubword.length()); String selectedSuggestion = ((CompletionCandidate) completionList - .getSelectedValue()).getCompletionString().substring(currentSubword - .length()); - logE(subWord + " <= subword,Inserting suggestion=> " + .getSelectedValue()).getCompletionString(); + + if (currentSubword != null) { + selectedSuggestion = selectedSuggestion.substring(currentSubwordLen); + } else { + currentSubword = ""; + } + + logE(subWord + " <= subword, Inserting suggestion=> " + selectedSuggestion + " Current sub: " + currentSubword); - textarea.getDocument().remove(insertionPosition - - currentSubword.length(), - currentSubword.length()); + if (currentSubword.length() > 0) { + textarea.getDocument().remove(insertionPosition - currentSubwordLen, + currentSubwordLen); + } + textarea.getDocument() - .insertString(insertionPosition - currentSubword.length(), + .insertString(insertionPosition - currentSubwordLen, ((CompletionCandidate) completionList .getSelectedValue()).getCompletionString(), null); if (selectedSuggestion.endsWith(")")) { @@ -240,12 +248,16 @@ public class CompletionPanel { } catch (BadLocationException e1) { e1.printStackTrace(); } + catch (Exception e) { + e.printStackTrace(); + } hide(); } return false; } private String fetchCurrentSubword() { + //log("Entering fetchCurrentSubword"); TextArea ta = editor.ta; int off = ta.getCaretPosition(); //log2("off " + off); @@ -256,35 +268,32 @@ public class CompletionPanel { return null; String s = ta.getLineText(line); //log2("lin " + line); - /* - * if (s == null) return null; else if (s.length() == 0) return null; - */ -// else { //log2(s + " len " + s.length()); - int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1; + int x = ta.getCaretPosition() - ta.getLineStartOffset(line) - 1, x1 = x - 1; if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. - //log2(" x char: " + s.charAt(x)); + log2(" x char: " + s.charAt(x)); //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; if (s.trim().length() == 1) { -// word = "" -// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); - //word = (x < s.length()?s.charAt(x):"") + ""; + // word = "" + // + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar); + //word = (x < s.length()?s.charAt(x):"") + ""; word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); return word; } -// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) -// ; // accepted these keys -// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) -// return null; + //log("fetchCurrentSubword 1 " + word); + if(word.equals(".")) return null; // If user types 'abc.', subword becomes '.' + // if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE) + // ; // accepted these keys + // else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$')) + // return null; int i = 0; - int closeB = 0; while (true) { i++; @@ -307,13 +316,13 @@ public class CompletionPanel { } } // if (keyChar != KeyEvent.CHAR_UNDEFINED) - + //log("fetchCurrentSubword 2 " + word); if (Character.isDigit(word.charAt(0))) return null; word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); - + //log("fetchCurrentSubword 3 " + word); //showSuggestionLater(); return word; //} diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 3e4041e70..8813d5a3b 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -921,7 +921,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { vi.setTitle(getSketch().getName()); } // if file location has changed, update autosaver - autosaver.reloadAutosaveDir(); +// autosaver.reloadAutosaveDir(); return saved; } From f2c6b90a8ac53ed03e23ad3b034ceb19d6093816 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 01:12:42 +0530 Subject: [PATCH 333/608] more progress with offset matching --- .../processing/mode/experimental/Utils.java | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java index 09007ab8d..f160dcc9f 100644 --- a/pdex/src/processing/mode/experimental/Utils.java +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -30,6 +30,8 @@ import java.util.HashMap; public class Utils { + public ArrayList offsetMatch; + String word1, word2; public static String reverse(String s) { char w[] = s.toCharArray(); for (int i = 0; i < w.length / 2; i++) { @@ -39,8 +41,19 @@ public class Utils { } return new String(w); } + + public void getJavaOffForPdeOff(int start, int length){ + for (int i = 0; i < offsetMatch.size(); i++) { + System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); + System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " + + word2.charAt(offsetMatch.get(i).javaOffset)); + } + System.out.println("Length " + offsetMatch.size()); + } public int minDistance(String word1, String word2) { + this.word1 = word1; + this.word2 = word2; // word1 = reverse(word1); // word2 = reverse(word2); int len1 = word1.length(); @@ -94,20 +107,21 @@ public class Utils { // int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; // System.out.println("Edit distance1: " + dp[len1][len2]); ArrayList alist = new ArrayList(); + offsetMatch = alist; minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), word2.toCharArray(), alist); - System.out.println("PDE-to-Java"); +// System.out.println("PDE-to-Java"); // for (int i = 0; i < maxLen; i++) { // System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); // System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " // + word2.charAt(javaCodeMap[i])); // } - for (int i = 0; i < alist.size(); i++) { - System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); - System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " - + word2.charAt(alist.get(i).javaOffset)); - } - System.out.println("Length " + alist.size()); +// for (int i = 0; i < alist.size(); i++) { +// System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); +// System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " +// + word2.charAt(alist.get(i).javaOffset)); +// } +// System.out.println("Length " + alist.size()); return dp[len1][len2]; } @@ -141,14 +155,14 @@ public class Utils { if (i < s1.length && j < s2.length) { // pdeCodeMap[k] = i; // javaCodeMap[k] = j; - System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); + //System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); set.add(new OfsSet(i, j)); // if (s1[i] != s2[j]) // System.out.println("--"); } - System.out.println(); + //System.out.println(); if (i == fi && j == fj) { - System.out.println("Reached end."); + //System.out.println("Reached end."); } else { int a = Integer.MAX_VALUE, b = a, c = a; if (i > 0) @@ -178,13 +192,27 @@ public class Utils { javaOffset = java; } } + +// public class OffsetMatch{ +// public final ArrayList pdeOffset, javaOffset; +// +// public OffsetMatch(){ +// pdeOffset = new ArrayList(); +// javaOffset = new ArrayList(); +// } +// } public static void main(String[] args) { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); - new Utils().minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); -// minDistance("int a = int(4.5);", "int a = PApplet.parseInt(4.5f);"); + Utils a = new Utils(); + + a.minDistance("int a = int(can); int ball;", "int a = PApplet.parseInt(can); int ball;"); + a.getJavaOffForPdeOff(10, 20); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); + //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + a.minDistance("color abc = #qwerty;", "int abc = 0xffqwerty;"); + a.getJavaOffForPdeOff(10, 20); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From 6c3ecf6a53e690b5e20a704bc3ace93fd840dd1d Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 02:31:17 +0530 Subject: [PATCH 334/608] things looking promising with offset matching --- .../processing/mode/experimental/Utils.java | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java index f160dcc9f..4081baee7 100644 --- a/pdex/src/processing/mode/experimental/Utils.java +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -42,13 +42,64 @@ public class Utils { return new String(w); } - public void getJavaOffForPdeOff(int start, int length){ + public void getPdeOffForJavaOff(int start, int length){ + System.out.println("PDE <-> Java" ); for (int i = 0; i < offsetMatch.size(); i++) { System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); } System.out.println("Length " + offsetMatch.size()); + System.out.println(start + " java start off, pde start off " + + getPdeOffForJavaOff(start)); + System.out.println((start + length - 1) + " java end off, pde end off " + + getPdeOffForJavaOff(start + length - 1)); + } + + public int getPdeOffForJavaOff(int javaOff){ + for (int i = offsetMatch.size() - 1; i >= 0;i--) { + if(offsetMatch.get(i).javaOffset < javaOff){ + continue; + } + else + if(offsetMatch.get(i).javaOffset == javaOff){ +// int j = i; + while(offsetMatch.get(--i).javaOffset == javaOff){ + System.out.println("MP " + offsetMatch.get(i).javaOffset + " " + + offsetMatch.get(i).pdeOffset); + } + int pdeOff = offsetMatch.get(++i).pdeOffset; + while(offsetMatch.get(--i).pdeOffset == pdeOff); + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).pdeOffset; + } + + } + return -1; + } + + public int getJavaOffForPdeOff(int pdeOff){ + for (int i = offsetMatch.size() - 1; i >= 0;i--) { + if(offsetMatch.get(i).pdeOffset < pdeOff){ + continue; + } + else + if(offsetMatch.get(i).pdeOffset == pdeOff){ +// int j = i; + while(offsetMatch.get(--i).pdeOffset == pdeOff){ +// System.out.println("MP " + offsetMatch.get(i).javaOffset + " " +// + offsetMatch.get(i).pdeOffset); + } + int javaOff = offsetMatch.get(++i).javaOffset; + while(offsetMatch.get(--i).javaOffset == javaOff); + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).javaOffset; + } + + } + return -1; } public int minDistance(String word1, String word2) { @@ -207,12 +258,13 @@ public class Utils { Utils a = new Utils(); a.minDistance("int a = int(can); int ball;", "int a = PApplet.parseInt(can); int ball;"); - a.getJavaOffForPdeOff(10, 20); + a.getPdeOffForJavaOff(25, 3); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + System.out.println("--"); a.minDistance("color abc = #qwerty;", "int abc = 0xffqwerty;"); - a.getJavaOffForPdeOff(10, 20); + a.getPdeOffForJavaOff(4, 3); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From 66dbb1dfdf9a3d4bdf600997844d88aa619b6fbe Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 02:50:41 +0530 Subject: [PATCH 335/608] Added OffsetMatcher. Time for a trial run --- .../mode/experimental/OffsetMatcher.java | 253 ++++++++++++++++++ .../processing/mode/experimental/Utils.java | 27 +- 2 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 pdex/src/processing/mode/experimental/OffsetMatcher.java diff --git a/pdex/src/processing/mode/experimental/OffsetMatcher.java b/pdex/src/processing/mode/experimental/OffsetMatcher.java new file mode 100644 index 000000000..1fe0b62d6 --- /dev/null +++ b/pdex/src/processing/mode/experimental/OffsetMatcher.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2012-14 Manindra Moharana + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package processing.mode.experimental; + +import java.util.ArrayList; +import static processing.mode.experimental.ExperimentalMode.log; + +/** + * Performs offset matching between PDE and Java code (one line of code only) + * + * @author Manindra Moharana + * + */ + +public class OffsetMatcher { + + public ArrayList offsetMatch; + + String word1, word2; + + public OffsetMatcher(String pdeCode, String javaCode) { + this.word1 = pdeCode; + this.word2 = javaCode; + minDistance(); + log("PDE <-> Java"); + for (int i = 0; i < offsetMatch.size(); i++) { + log(offsetMatch.get(i).pdeOffset + " <-> " + + offsetMatch.get(i).javaOffset + + ", " + word1.charAt(offsetMatch.get(i).pdeOffset) + + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); + } + log("Length " + offsetMatch.size()); + } + + public void getPdeOffForJavaOff(int start, int length) { + + log(start + " java start off, pde start off " + + getPdeOffForJavaOff(start)); + log((start + length - 1) + " java end off, pde end off " + + getPdeOffForJavaOff(start + length - 1)); + } + + public void getJavaOffForPdeOff(int start, int length) { +// System.out.println("PDE <-> Java" ); +// for (int i = 0; i < offsetMatch.size(); i++) { +// System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); +// System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " +// + word2.charAt(offsetMatch.get(i).javaOffset)); +// } +// System.out.println("Length " + offsetMatch.size()); + log(start + " pde start off, java start off " + + getJavaOffForPdeOff(start)); + log((start + length - 1) + " pde end off, java end off " + + getJavaOffForPdeOff(start + length - 1)); + } + + public int getPdeOffForJavaOff(int javaOff) { + for (int i = offsetMatch.size() - 1; i >= 0; i--) { + if (offsetMatch.get(i).javaOffset < javaOff) { + continue; + } else if (offsetMatch.get(i).javaOffset == javaOff) { +// int j = i; + while (offsetMatch.get(--i).javaOffset == javaOff) { + log("MP " + offsetMatch.get(i).javaOffset + " " + + offsetMatch.get(i).pdeOffset); + } + int pdeOff = offsetMatch.get(++i).pdeOffset; + while (offsetMatch.get(--i).pdeOffset == pdeOff) + ; + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).pdeOffset; + } + + } + return -1; + } + + public int getJavaOffForPdeOff(int pdeOff) { + for (int i = offsetMatch.size() - 1; i >= 0; i--) { + if (offsetMatch.get(i).pdeOffset < pdeOff) { + continue; + } else if (offsetMatch.get(i).pdeOffset == pdeOff) { +// int j = i; + while (offsetMatch.get(--i).pdeOffset == pdeOff) { +// log("MP " + offsetMatch.get(i).javaOffset + " " +// + offsetMatch.get(i).pdeOffset); + } + int javaOff = offsetMatch.get(++i).javaOffset; + while (offsetMatch.get(--i).javaOffset == javaOff) + ; + int j = i + 1; + if (j > -1 && j < offsetMatch.size()) + return offsetMatch.get(j).javaOffset; + } + + } + return -1; + } + + private int minDistance() { + +// word1 = reverse(word1); +// word2 = reverse(word2); + int len1 = word1.length(); + int len2 = word2.length(); + log(word1 + " len: " + len1); + log(word2 + " len: " + len2); + // len1+1, len2+1, because finally return dp[len1][len2] + int[][] dp = new int[len1 + 1][len2 + 1]; + + for (int i = 0; i <= len1; i++) { + dp[i][0] = i; + } + + for (int j = 0; j <= len2; j++) { + dp[0][j] = j; + } + + //iterate though, and check last char + for (int i = 0; i < len1; i++) { + char c1 = word1.charAt(i); + for (int j = 0; j < len2; j++) { + char c2 = word2.charAt(j); + //System.out.print(c1 + "<->" + c2); + //if last two chars equal + if (c1 == c2) { + //update dp value for +1 length + dp[i + 1][j + 1] = dp[i][j]; +// log(); + } else { + int replace = dp[i][j] + 1; + int insert = dp[i][j + 1] + 1; + int delete = dp[i + 1][j] + 1; +// if (replace < delete) { +// log(" --- D"); +// } else +// log(" --- R"); + int min = replace > insert ? insert : replace; + min = delete > min ? min : delete; + dp[i + 1][j + 1] = min; + } + } + } + +// for (int i = 0; i < dp.length; i++) { +// for (int j = 0; j < dp[0].length; j++) { +// System.out.print(dp[i][j] + " "); +// } +// System.out.println(); +// } +// int maxLen = Math.max(len1, len2)+2; +// int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; +// System.out.println("Edit distance1: " + dp[len1][len2]); + ArrayList alist = new ArrayList(); + offsetMatch = alist; + minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), + word2.toCharArray(), alist); +// System.out.println("PDE-to-Java"); +// for (int i = 0; i < maxLen; i++) { +// System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); +// System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " +// + word2.charAt(javaCodeMap[i])); +// } +// for (int i = 0; i < alist.size(); i++) { +// System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); +// System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " +// + word2.charAt(alist.get(i).javaOffset)); +// } +// System.out.println("Length " + alist.size()); + return dp[len1][len2]; + } + + private void minDistInGrid(int g[][], int i, int j, int fi, int fj, + char s1[], char s2[], ArrayList set) { +// if(i < s1.length)System.out.print(s1[i] + " <->"); +// if(j < s2.length)System.out.print(s2[j]); + if (i < s1.length && j < s2.length) { +// pdeCodeMap[k] = i; +// javaCodeMap[k] = j; + //System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); + set.add(new OffsetPair(i, j)); +// if (s1[i] != s2[j]) +// System.out.println("--"); + } + //System.out.println(); + if (i == fi && j == fj) { + //System.out.println("Reached end."); + } else { + int a = Integer.MAX_VALUE, b = a, c = a; + if (i > 0) + a = g[i - 1][j]; + if (j > 0) + b = g[i][j - 1]; + if (i > 0 && j > 0) + c = g[i - 1][j - 1]; + int mini = Math.min(a, Math.min(b, c)); + if (mini == a) { + //System.out.println(s1[i + 1] + " " + s2[j]); + minDistInGrid(g, i - 1, j, fi, fj, s1, s2, set); + } else if (mini == b) { + //System.out.println(s1[i] + " " + s2[j + 1]); + minDistInGrid(g, i, j - 1, fi, fj, s1, s2, set); + } else if (mini == c) { + //System.out.println(s1[i + 1] + " " + s2[j + 1]); + minDistInGrid(g, i - 1, j - 1, fi, fj, s1, s2, set); + } + } + } + + private class OffsetPair { + public final int pdeOffset, javaOffset; + + public OffsetPair(int pde, int java) { + pdeOffset = pde; + javaOffset = java; + } + } + + public static void main(String[] args) { +// minDistance("c = #qwerty;", "c = 0xffqwerty;"); + OffsetMatcher a; + + a = new OffsetMatcher("int a = int(can); int ball;", + "int a = PApplet.parseInt(can); int ball;"); + a.getPdeOffForJavaOff(25, 3); + a.getJavaOffForPdeOff(12, 3); +// minDistance("static void main(){;", "public static void main(){;"); +// minDistance("#bb00aa", "0xffbb00aa"); + //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + log("--"); + a = new OffsetMatcher("color abc = #qwerty;", "int abc = 0xffqwerty;"); + a.getPdeOffForJavaOff(4, 3); + a.getJavaOffForPdeOff(6, 3); +// distance("c = #bb00aa;", "c = 0xffbb00aa;"); + } +} diff --git a/pdex/src/processing/mode/experimental/Utils.java b/pdex/src/processing/mode/experimental/Utils.java index 4081baee7..7992676dc 100644 --- a/pdex/src/processing/mode/experimental/Utils.java +++ b/pdex/src/processing/mode/experimental/Utils.java @@ -19,7 +19,6 @@ package processing.mode.experimental; import java.util.ArrayList; -import java.util.HashMap; /** * A class containing multiple utility methods @@ -30,7 +29,7 @@ import java.util.HashMap; public class Utils { - public ArrayList offsetMatch; + public ArrayList offsetMatch; String word1, word2; public static String reverse(String s) { char w[] = s.toCharArray(); @@ -56,6 +55,20 @@ public class Utils { + getPdeOffForJavaOff(start + length - 1)); } + public void getJavaOffForPdeOff(int start, int length){ +// System.out.println("PDE <-> Java" ); +// for (int i = 0; i < offsetMatch.size(); i++) { +// System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); +// System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " +// + word2.charAt(offsetMatch.get(i).javaOffset)); +// } +// System.out.println("Length " + offsetMatch.size()); + System.out.println(start + " pde start off, java start off " + + getJavaOffForPdeOff(start)); + System.out.println((start + length - 1) + " pde end off, java end off " + + getJavaOffForPdeOff(start + length - 1)); + } + public int getPdeOffForJavaOff(int javaOff){ for (int i = offsetMatch.size() - 1; i >= 0;i--) { if(offsetMatch.get(i).javaOffset < javaOff){ @@ -157,7 +170,7 @@ public class Utils { // int maxLen = Math.max(len1, len2)+2; // int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; // System.out.println("Edit distance1: " + dp[len1][len2]); - ArrayList alist = new ArrayList(); + ArrayList alist = new ArrayList(); offsetMatch = alist; minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), word2.toCharArray(), alist); @@ -207,7 +220,7 @@ public class Utils { // pdeCodeMap[k] = i; // javaCodeMap[k] = j; //System.out.print(s1[i] + " " + i + " <-> " + j + " " + s2[j]); - set.add(new OfsSet(i, j)); + set.add(new OfsSetTemp(i, j)); // if (s1[i] != s2[j]) // System.out.println("--"); } @@ -236,9 +249,9 @@ public class Utils { } } - public class OfsSet { + public class OfsSetTemp { public final int pdeOffset, javaOffset; - public OfsSet(int pde, int java){ + public OfsSetTemp(int pde, int java){ pdeOffset = pde; javaOffset = java; } @@ -259,12 +272,14 @@ public class Utils { a.minDistance("int a = int(can); int ball;", "int a = PApplet.parseInt(can); int ball;"); a.getPdeOffForJavaOff(25, 3); + a.getJavaOffForPdeOff(12,3); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); System.out.println("--"); a.minDistance("color abc = #qwerty;", "int abc = 0xffqwerty;"); a.getPdeOffForJavaOff(4, 3); + a.getJavaOffForPdeOff(6,3); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } From 78c44cf34a230a529a89cedde93b472f7240d1bd Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 16:27:55 +0530 Subject: [PATCH 336/608] First phase of tests, no major casualties --- .../mode/experimental/ASTNodeWrapper.java | 15 ++++ .../mode/experimental/OffsetMatcher.java | 88 +++++++++---------- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java index 2823cc9e7..734da04d9 100644 --- a/pdex/src/processing/mode/experimental/ASTNodeWrapper.java +++ b/pdex/src/processing/mode/experimental/ASTNodeWrapper.java @@ -575,6 +575,20 @@ public class ASTNodeWrapper { return false; } + OffsetMatcher ofm = new OffsetMatcher(pdeLine, javaLine); + int highlightStart = ofm.getPdeOffForJavaOff(nodeName.getStartPosition() + - lineElement.getStartOffset(), + nodeName.getLength()); + if (highlightStart == -1) { + logE("Logical error in highLightNode() during offset matching. " + + "Please file a bug report."); + return false; + } + int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); + highlightStart += lso; + astGenerator.editor.setSelection(highlightStart, highlightStart + + nodeName.getLength()); + /* // First find the name in the java line, and marks its index Pattern toFind = Pattern.compile("\\b" + nodeName.toString() + "\\b"); Matcher matcher = toFind.matcher(javaLine); @@ -603,6 +617,7 @@ public class ASTNodeWrapper { int lso = astGenerator.editor.ta.getLineStartOffset(pdeOffs[1]); astGenerator.editor.setSelection(lso + index - lookingFor.length(), lso + index); + */ return true; } catch (BadLocationException e) { logE("BLE in highLightNode() for " + nodeName); diff --git a/pdex/src/processing/mode/experimental/OffsetMatcher.java b/pdex/src/processing/mode/experimental/OffsetMatcher.java index 1fe0b62d6..d5aff521b 100644 --- a/pdex/src/processing/mode/experimental/OffsetMatcher.java +++ b/pdex/src/processing/mode/experimental/OffsetMatcher.java @@ -33,44 +33,57 @@ public class OffsetMatcher { public ArrayList offsetMatch; String word1, word2; + + boolean matchingNeeded = false; public OffsetMatcher(String pdeCode, String javaCode) { this.word1 = pdeCode; this.word2 = javaCode; - minDistance(); - log("PDE <-> Java"); - for (int i = 0; i < offsetMatch.size(); i++) { - log(offsetMatch.get(i).pdeOffset + " <-> " - + offsetMatch.get(i).javaOffset + - ", " + word1.charAt(offsetMatch.get(i).pdeOffset) - + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); + if(word1.trim().equals(word2.trim())){ //TODO: trim() needed here? + matchingNeeded = false; + offsetMatch = new ArrayList(); + log("Offset Matching not needed"); + } + else + { + matchingNeeded = true; + minDistance(); } - log("Length " + offsetMatch.size()); - } - - public void getPdeOffForJavaOff(int start, int length) { - log(start + " java start off, pde start off " - + getPdeOffForJavaOff(start)); - log((start + length - 1) + " java end off, pde end off " - + getPdeOffForJavaOff(start + length - 1)); +// log("PDE <-> Java"); + for (int i = 0; i < offsetMatch.size(); i++) { +// log(offsetMatch.get(i).pdeOffset + " <-> " +// + offsetMatch.get(i).javaOffset + +// ", " + word1.charAt(offsetMatch.get(i).pdeOffset) +// + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); + } +// log("Length " + offsetMatch.size()); } - public void getJavaOffForPdeOff(int start, int length) { -// System.out.println("PDE <-> Java" ); -// for (int i = 0; i < offsetMatch.size(); i++) { -// System.out.print(offsetMatch.get(i).pdeOffset + " <-> " + offsetMatch.get(i).javaOffset); -// System.out.println(", " + word1.charAt(offsetMatch.get(i).pdeOffset) + " <-> " -// + word2.charAt(offsetMatch.get(i).javaOffset)); -// } -// System.out.println("Length " + offsetMatch.size()); + public int getPdeOffForJavaOff(int start, int length) { + if(!matchingNeeded) return start; + int ans = getPdeOffForJavaOff(start), end = getPdeOffForJavaOff(start + length - 1); + log(start + " java start off, pde start off " + + ans); + log((start + length - 1) + " java end off, pde end off " + + end); + log("J: " + word2.substring(start, start + length) + "\nP: " + + word1.substring(ans, end + 1)); + return ans; + } + + public int getJavaOffForPdeOff(int start, int length) { + if(!matchingNeeded) return start; + int ans = getJavaOffForPdeOff(start); log(start + " pde start off, java start off " + getJavaOffForPdeOff(start)); log((start + length - 1) + " pde end off, java end off " + getJavaOffForPdeOff(start + length - 1)); + return ans; } public int getPdeOffForJavaOff(int javaOff) { + if(!matchingNeeded) return javaOff; for (int i = offsetMatch.size() - 1; i >= 0; i--) { if (offsetMatch.get(i).javaOffset < javaOff) { continue; @@ -93,6 +106,7 @@ public class OffsetMatcher { } public int getJavaOffForPdeOff(int pdeOff) { + if(!matchingNeeded) return pdeOff; for (int i = offsetMatch.size() - 1; i >= 0; i--) { if (offsetMatch.get(i).pdeOffset < pdeOff) { continue; @@ -114,6 +128,13 @@ public class OffsetMatcher { return -1; } + /** + * Finds 'distance' between two Strings. + * See Edit Distance Problem + * https://secweb.cs.odu.edu/~zeil/cs361/web/website/Lectures/styles/pages/editdistance.html + * http://www.stanford.edu/class/cs124/lec/med.pdf + * + */ private int minDistance() { // word1 = reverse(word1); @@ -159,31 +180,10 @@ public class OffsetMatcher { } } -// for (int i = 0; i < dp.length; i++) { -// for (int j = 0; j < dp[0].length; j++) { -// System.out.print(dp[i][j] + " "); -// } -// System.out.println(); -// } -// int maxLen = Math.max(len1, len2)+2; -// int pdeCodeMap[] = new int[maxLen], javaCodeMap[] = new int[maxLen]; -// System.out.println("Edit distance1: " + dp[len1][len2]); ArrayList alist = new ArrayList(); offsetMatch = alist; minDistInGrid(dp, len1, len2, 0, 0, word1.toCharArray(), word2.toCharArray(), alist); -// System.out.println("PDE-to-Java"); -// for (int i = 0; i < maxLen; i++) { -// System.out.print(pdeCodeMap[i] + " <-> " + javaCodeMap[i]); -// System.out.println(", " + word1.charAt(pdeCodeMap[i]) + " <-> " -// + word2.charAt(javaCodeMap[i])); -// } -// for (int i = 0; i < alist.size(); i++) { -// System.out.print(alist.get(i).pdeOffset + " <-> " + alist.get(i).javaOffset); -// System.out.println(", " + word1.charAt(alist.get(i).pdeOffset) + " <-> " -// + word2.charAt(alist.get(i).javaOffset)); -// } -// System.out.println("Length " + alist.size()); return dp[len1][len2]; } From 316144e62af53f766e12563aa5689315152a1027 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 17:05:30 +0530 Subject: [PATCH 337/608] Testing the new markdown --- pdex/Todo, GSoC 2013.txt | 172 +++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/pdex/Todo, GSoC 2013.txt b/pdex/Todo, GSoC 2013.txt index d2e577745..c7020fcc0 100644 --- a/pdex/Todo, GSoC 2013.txt +++ b/pdex/Todo, GSoC 2013.txt @@ -4,7 +4,7 @@ This would also be a break down of my thought process and ideas as I tackle vari Manindra Moharana (me@mkmoharana.com) -* : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo +[ ]: Todo, [x] : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo Code Completion =============== @@ -16,122 +16,122 @@ The big stuff: - Many of the cases seem to have been covered, and I'm achieving more and more code unification as I'm working through the problem step by step - Looks almost complete now, nearly all cases covered(July 13th) x After popup appears, the popup location is fixed for the current line. So if editor window is moved while staying in the same line, popup appears at the prev location. Need to ensure editor is still at last know location. Fixed. -* Keyboard Shortcut for completion popup - Ctrl + Space -* Scope handling? Static/non static scope? -* Disable completions on comment line -* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. +[ ]Keyboard Shortcut for completion popup - Ctrl + Space +[ ]Scope handling? Static/non static scope? +[ ]Disable completions on comment line +[ ]Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this. -x Ensure that a compilation unit is created at startup! +[x]Ensure that a compilation unit is created at startup! x! Code competition for local code is working with recursive look up. -x Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed -x Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. +[x]Completion doesn't seem to show up for fields of a type defined locally. But works for methods with return type defined locally. Take ideas. Some case missing most probably. Fixed +[x]Discovered another major issue due to offset differences -> While looking for predictions, if the parsed string contains pde enhancements, predictions FAIL! Zomg. Ex - "s.substring(int(13.4))." fails. Thinking to just do the substitutions before sending it to updatePredictions(), coz offsets aren't really a concern here, right? Yup, fixed it! x! Code completion with library code, non-nested seems to be broken, fix it. Fixed. -x Completion for external classes - ArrayList, HashMap, etc. +[x]Completion for external classes - ArrayList, HashMap, etc. x! Recursive lookup for compiled(library) code! x! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance. x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done. -x Differentiating between multiple statements on the same line. How to? Done with offset handling. -x - Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. -x Parameterized type support is broken. -x Array types, all all other types support broken. :\ -x Completion for array access, strings[0]. +[x]Differentiating between multiple statements on the same line. How to? Done with offset handling. +[x]- Cache predictions if current 'word' is increasing in length. If already showing predictions beginning with 's', for 'sa', remove extra completions, rather than recalculating predictions. Performance increase. +[x]Parameterized type support is broken. +[x]Array types, all all other types support broken. :\ +[x]Completion for array access, strings[0]. Finer details -* findDeclarations should support 3rd party classes too. It's about time. ;) -* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? +[ ]findDeclarations should support 3rd party classes too. It's about time. ;) +[ ]printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of(done). Argument list as tooltip if possible? *! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them. Offset handling improvements should help here. -* Diamond operator isn't supported for now. Bummer. +[ ]Diamond operator isn't supported for now. Bummer. -x Completion popup height is now dynamic, decreases to fit. -* Completion width can be dynamic, if really needed.. -x Icons for completions? Or overkill right now? -x 'Show Usage' menu item added -x Show declaring class for completions +[x]Completion popup height is now dynamic, decreases to fit. +[ ]Completion width can be dynamic, if really needed.. +[x]Icons for completions? Or overkill right now? +[x]'Show Usage' menu item added +[x]Show declaring class for completions x! Ignore String case while finding completion candidates -x Multiple 3rd party classes found in various packages. Not a chance no more. -x Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! -x Cursor positioning should be after the first ( if arguments present, else after () -x Display the type of Completion(method return type, variable type) in the popup. +[x]Multiple 3rd party classes found in various packages. Not a chance no more. +[x]Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that. Began working again by itself. Yay! +[x]Cursor positioning should be after the first ( if arguments present, else after () +[x]Display the type of Completion(method return type, variable type) in the popup. - facing some issues for local types. Fixed. -x Sorted list of completion candidates - fields, then methods. It's unsorted presently. -x Reflection API - getMethods vs getDeclaredMethods. declared. -x Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement -x Completion List should get hidden on hitting esc key +[x]Sorted list of completion candidates - fields, then methods. It's unsorted presently. +[x]Reflection API - getMethods vs getDeclaredMethods. declared. +[x]Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later? All set to implement +[x]Completion List should get hidden on hitting esc key Offset Mapping ============== First major hurdle is offset mapping *! pde<->java code offset : precise conversion needed -* W.r.t PDE specific enhancements, things are almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. -x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. -x This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. -x Edge case - multiple statements in a single line -x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. +[ ]W.r.t PDE specific enhancements, things are almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs. +[x]for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature. +[x]This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration. +[x]Edge case - multiple statements in a single line +[x]PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh. Refactoring =========== -* Undo misbehaves here, handle carefully. -* Fails to rename the first defined global variable, if a javadoc comment precedes it. But owrds for single/multiline comments. Wth! -x New Name is validated. -x Ordered list in 'Show Usage' window -x Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully +[ ]Undo misbehaves here, handle carefully. +[ ]Fails to rename the first defined global variable, if a javadoc comment precedes it. But owrds for single/multiline comments. Wth! +[x]New Name is validated. +[x]Ordered list in 'Show Usage' window +[x]Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code. 1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences. 2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found. -x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. -x Renaming any constructor is equivalent to renaming the TD +[x]Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against. +[x]Renaming any constructor is equivalent to renaming the TD 3. Find corresponding PDE offsets of the SimpleNames, rename in each line. -x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. +[x]Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration. 4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts. -x Refactoring ui -x For now, user needs to highlight the name of the var, and then right-click -> Rename.. -x Handle saving. If sketch closed after renaming w/o saving find bugs. Done, marking the sketch as modified after renaming. +[x]Refactoring ui +[x]For now, user needs to highlight the name of the var, and then right-click -> Rename.. +[x]Handle saving. If sketch closed after renaming w/o saving find bugs. Done, marking the sketch as modified after renaming. Quick Navigation ================ *+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top. -x On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? -x Ctrl + Click on an element to scroll to its definition in code -x Local Vars -x Local Methods -x Local Classes -x Recursive lookup, a.b().c() -x Now highlihgting the declaration name, rather than the whole declaration. +[x]On OS X, Ctrl + Click is right mouse click, so implement Cmd + Click instead. isMetaDown()? +[x]Ctrl + Click on an element to scroll to its definition in code +[x]Local Vars +[x]Local Methods +[x]Local Classes +[x]Recursive lookup, a.b().c() +[x]Now highlihgting the declaration name, rather than the whole declaration. Sketch Outline ============== -x Show Sketch Outline Tree -x Filter stuff in text field -x Add icons - custom cell renderer +[x]Show Sketch Outline Tree +[x]Filter stuff in text field +[x]Add icons - custom cell renderer Suggestion for missing imports ============================== -* Find a more subtle way to suggest for imports. The current method is too troublesome. Randomly pops up offering suggestions. May intimidate beginners. +[ ]Find a more subtle way to suggest for imports. The current method is too troublesome. Randomly pops up offering suggestions. May intimidate beginners. 1. In compileCheck() in ECS, check if error message is of the type "__" cannot be resolved to a type. 2. Find the class name via astGen, and suggest import as a popup. -x Barebones functionality done. -x Add imports only to beginning of first tab. -x Search within contributed libraries folder -x Hide suggestion list before showing import suggestions -x Search within code folder of sketch +[x]Barebones functionality done. +[x]Add imports only to beginning of first tab. +[x]Search within contributed libraries folder +[x]Hide suggestion list before showing import suggestions +[x]Search within code folder of sketch Labels for Java elements ======================== -x Working for local code -* Need to modify getASTNodeAt to also fetch the type for predefined classes. -* Labels for predefined class objects -* Chaining support for labels +[x]Working for local code +[ ]Need to modify getASTNodeAt to also fetch the type for predefined classes. +[ ]Labels for predefined class objects +[ ]Chaining support for labels Synchronization =============== @@ -140,31 +140,31 @@ Gotta do it carefully between main thread, ECS Thread, and SwingWorker threads Fields that are concurrently accessed: ECS members: -x ArrayList problems - updated in ECS, accessed by ErrorBar.update() -x ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() -x hasErrors, syntaxErrors - Atomic Boolean -x boolean warningsEnabled - made it volatile -* CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( +[x]ArrayList problems - updated in ECS, accessed by ErrorBar.update() +[x]ArrayList classpathJars - updated in ECS, accessed by ASTGenerator.loadJars() +[x]hasErrors, syntaxErrors - Atomic Boolean +[x]boolean warningsEnabled - made it volatile +[ ]CompilationUnit cu - updated in ECS, accessed a zillion times in ASTGenerator :'( General Stuff ============= -* [Critical] PermGen out of memory bug. Manually triggering GC after making the classloader null ensures permgen memory is reclaimed on editor exit. Max open window still limited by max permgen size. Also, added a classloadcounter in ECS to trigger GC periodically. +[ ][Critical] PermGen out of memory bug. Manually triggering GC after making the classloader null ensures permgen memory is reclaimed on editor exit. Max open window still limited by max permgen size. Also, added a classloadcounter in ECS to trigger GC periodically. https://github.com/processing/processing-experimental/issues/1 See: http://stackoverflow.com/questions/2095974/how-to-unload-a-already-loaded-class-in-java I'm making the classLoader null, but what about the classes loaded by ASTGen? Investigate. -x Disabling Error Checking disables predictions as well! Fixed. -x Added doc listener for text area updates -x Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file -x Save preferences to main preference.txt -x Hide breakpoint markers when Debugger isn't active -x Ensure gutter mouse handler is taken care of when hiding Debugger breakpoint bar. -x Ensure all editor windows are closed when editor is closed. -x Add a red marker near Errors label in console toggle, to indicate errors present in sketch. -x Add option for toggling debug output -x On Run/Debug Console is visible(ProblemsList hidden) -* Update wiki for Ctrl + H instead of Ctrl + J shortcuts -x update build.xml to produce dists -x Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc -x Add GitHub link to PDE X Menu +[x]Disabling Error Checking disables predictions as well! Fixed. +[x]Added doc listener for text area updates +[x]Consult Ben on where to save preferences - main preferences.txt or custom one. - Main prefs file +[x]Save preferences to main preference.txt +[x]Hide breakpoint markers when Debugger isn't active +[x]Ensure gutter mouse handler is taken care of when hiding Debugger breakpoint bar. +[x]Ensure all editor windows are closed when editor is closed. +[x]Add a red marker near Errors label in console toggle, to indicate errors present in sketch. +[x]Add option for toggling debug output +[x]On Run/Debug Console is visible(ProblemsList hidden) +[ ]Update wiki for Ctrl + H instead of Ctrl + J shortcuts +[x]update build.xml to produce dists +[x]Make this a contributed mode - mode.txt, github releases feature, version numbering, git tags, etc +[x]Add GitHub link to PDE X Menu From ab624e53188c0850464d7aaa4889e37d4d045864 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Mon, 2 Jun 2014 21:41:59 +0530 Subject: [PATCH 338/608] Added a new todo.txt --- pdex/todo.txt | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 pdex/todo.txt diff --git a/pdex/todo.txt b/pdex/todo.txt new file mode 100644 index 000000000..acc6cc50f --- /dev/null +++ b/pdex/todo.txt @@ -0,0 +1,38 @@ +TODO List for PDE X +=================== + +This would also be a break down of my thought process and ideas as I tackle +various tasks. Previously, a different todo file was used for GSoC 2013. + +Manindra Moharana (me@mkmoharana.com) + +[ ]: Todo, [x] : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo + + +Critical Bugs +------------- + +[ ] Better memory management. #1 + +[ ] Breakpoints in classes. #47 + + +Normal Bugs +----------- +[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. +Classname in Template, doesn't scroll to decl. This is happening due certain +post processing offsets not being accounted for. "public void" + +Enhancements/New Features +------------------------- + +[ ] When viewing Outline View, instead of showing the beginning of the list, +it should select the current node element within which the cursor is presently positioned. + +[ ] Begin work on code snippets. + +[ ] JUnit Testing? + +[ ] Preferences panel + +[ ] Line Numbers From c02d3585f6df2d2c0fc846370a9c30ad161ee167 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Mon, 2 Jun 2014 23:49:55 +0530 Subject: [PATCH 339/608] Basic fnctionality of autosave before running TODO: Add preferences Improve UI --- .../mode/experimental/DebugEditor.java | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 3e4041e70..7ab11b682 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -48,6 +48,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -921,7 +922,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { vi.setTitle(getSketch().getName()); } // if file location has changed, update autosaver - autosaver.reloadAutosaveDir(); +// autosaver.reloadAutosaveDir(); return saved; } @@ -1071,6 +1072,83 @@ public class DebugEditor extends JavaEditor implements ActionListener { return ta; } + /** + * Grab current contents of the sketch window, advance the console, stop any + * other running sketches, auto-save the user's code... not in that order. + */ + @Override + public void prepareRun() { + super.prepareRun(); + try { + if (sketch.isUntitled()) { + if (handleSave(true)) + statusTimedNotice("Saved. Running...", 5); + else + statusTimedNotice("Save Canceled. Running anyway...", 5); + } + else if (sketch.isModified())// TODO: Fix ugly UI + // TODO: Add to preferences + { + Object[] options = { "Save", "Continue Without Saving" }; + int op = JOptionPane + .showOptionDialog( + new Frame(), + "There are unsaved changes in your sketch. Save before proceeding?", + this.getSketch().getName(), JOptionPane.YES_NO_OPTION, + JOptionPane.PLAIN_MESSAGE, null, options, options[0]); + if (op == JOptionPane.YES_OPTION) { + if (handleSave(true)) + statusTimedNotice("Saved. Running...", 5); + } + else + if (op == JOptionPane.NO_OPTION) + statusTimedNotice("Not saved. Running...", 5); + } + } catch (Exception e) { + // show the error as a message in the window + statusError(e); + } + } + + /** + * Shows a notice message in the editor status bar for a certain duration of + * time. + * + * @param msg + * @param secs + */ + public void statusTimedNotice(final String msg, final int secs) { +// EventQueue.invokeLater(new Runnable() { +// +// @Override +// public void run() { +// statusNotice(msg); +// try { +// Thread.sleep(secs * 1000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// statusEmpty(); +// +// } +// }); + SwingWorker s = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + statusNotice(msg); + try { + Thread.sleep(secs * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + statusEmpty(); + return null; + } + }; + s.execute(); + } + /** * Access variable inspector window. * From 95755e940456d0bf48ef4df4e4d07bb8aa93d06c Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 4 Jun 2014 20:19:42 +0530 Subject: [PATCH 340/608] Added untitledAutoSave, autoSave to preferences --- .../mode/experimental/DebugEditor.java | 19 ++++--------------- .../mode/experimental/ExperimentalMode.java | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 7ab11b682..51e7341d1 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1079,8 +1079,11 @@ public class DebugEditor extends JavaEditor implements ActionListener { @Override public void prepareRun() { super.prepareRun(); + if (!ExperimentalMode.autoSaveEnabled) + return; + try { - if (sketch.isUntitled()) { + if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { if (handleSave(true)) statusTimedNotice("Saved. Running...", 5); else @@ -1118,20 +1121,6 @@ public class DebugEditor extends JavaEditor implements ActionListener { * @param secs */ public void statusTimedNotice(final String msg, final int secs) { -// EventQueue.invokeLater(new Runnable() { -// -// @Override -// public void run() { -// statusNotice(msg); -// try { -// Thread.sleep(secs * 1000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// statusEmpty(); -// -// } -// }); SwingWorker s = new SwingWorker() { @Override diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index 5b04896d3..b90b5a519 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -127,13 +127,15 @@ public class ExperimentalMode extends JavaMode { } volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, - codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false; + codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false, + untitledAutoSaveEnabled = false, autoSaveEnabled = true; public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", - prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval"; + prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval", + prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled", prefAutoSave = "pdex.autoSaveEnabled"; public void loadPreferences(){ log("Load PDEX prefs"); @@ -144,6 +146,8 @@ public class ExperimentalMode extends JavaMode { DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); + untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); + autoSaveEnabled = Preferences.getBoolean(prefAutoSave); } public void savePreferences(){ @@ -154,6 +158,8 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); + Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); + Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } public void ensurePrefsExist(){ @@ -169,6 +175,10 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); if(Preferences.get(prefAutoSaveInterval) == null) Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); + if(Preferences.get(prefUntitledAutoSave) == null) + Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); + if(Preferences.get(prefAutoSave) == null) + Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } From 1e77b43ba4e3c019050b7e5e4621e634edaae3db Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Wed, 4 Jun 2014 21:25:12 +0530 Subject: [PATCH 341/608] minor todo update --- pdex/todo.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pdex/todo.txt b/pdex/todo.txt index acc6cc50f..a56bb9bcb 100644 --- a/pdex/todo.txt +++ b/pdex/todo.txt @@ -19,9 +19,10 @@ Critical Bugs Normal Bugs ----------- -[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. -Classname in Template, doesn't scroll to decl. This is happening due certain -post processing offsets not being accounted for. "public void" +[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 + +[x] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is +happening due certain post processing offsets not being accounted for - "public void" Enhancements/New Features ------------------------- From 63e6f1b912cd0cd35785100fbafe975800d00478 Mon Sep 17 00:00:00 2001 From: joelmoniz Date: Wed, 4 Jun 2014 22:10:40 +0530 Subject: [PATCH 342/608] Commenting out untitledAutoSave --- .../processing/mode/experimental/DebugEditor.java | 15 ++++++++------- .../mode/experimental/ExperimentalMode.java | 12 ++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 51e7341d1..5ac4a9811 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1083,13 +1083,14 @@ public class DebugEditor extends JavaEditor implements ActionListener { return; try { - if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { - if (handleSave(true)) - statusTimedNotice("Saved. Running...", 5); - else - statusTimedNotice("Save Canceled. Running anyway...", 5); - } - else if (sketch.isModified())// TODO: Fix ugly UI +// if (sketch.isUntitled() && ExperimentalMode.untitledAutoSaveEnabled) { +// if (handleSave(true)) +// statusTimedNotice("Saved. Running...", 5); +// else +// statusTimedNotice("Save Canceled. Running anyway...", 5); +// } +// else + if (sketch.isModified() && !sketch.isUntitled())// TODO: Fix ugly UI // TODO: Add to preferences { Object[] options = { "Save", "Continue Without Saving" }; diff --git a/pdex/src/processing/mode/experimental/ExperimentalMode.java b/pdex/src/processing/mode/experimental/ExperimentalMode.java index b90b5a519..29941ad87 100755 --- a/pdex/src/processing/mode/experimental/ExperimentalMode.java +++ b/pdex/src/processing/mode/experimental/ExperimentalMode.java @@ -128,14 +128,14 @@ public class ExperimentalMode extends JavaMode { volatile public static boolean errorCheckEnabled = true, warningsEnabled = true, codeCompletionsEnabled = true, debugOutputEnabled = false, errorLogsEnabled = false, - untitledAutoSaveEnabled = false, autoSaveEnabled = true; + autoSaveEnabled = true; //,untitledAutoSaveEnabled; public static int autoSaveInterval = 3; //in minutes public static final String prefErrorCheck = "pdex.errorCheckEnabled", prefWarnings = "pdex.warningsEnabled", prefCodeCompletionEnabled = "pdex.ccEnabled", prefDebugOP = "pdex.dbgOutput", prefErrorLogs = "pdex.writeErrorLogs", prefAutoSaveInterval = "pdex.autoSaveInterval", - prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled", prefAutoSave = "pdex.autoSaveEnabled"; + prefAutoSave = "pdex.autoSaveEnabled"; //prefUntitledAutoSave = "pdex.autoSave.untitledAutoSaveEnabled" public void loadPreferences(){ log("Load PDEX prefs"); @@ -146,7 +146,7 @@ public class ExperimentalMode extends JavaMode { DEBUG = Preferences.getBoolean(prefDebugOP); errorLogsEnabled = Preferences.getBoolean(prefErrorLogs); autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval); - untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); +// untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave); autoSaveEnabled = Preferences.getBoolean(prefAutoSave); } @@ -158,7 +158,7 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefDebugOP, DEBUG); Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); - Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); +// Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } @@ -175,8 +175,8 @@ public class ExperimentalMode extends JavaMode { Preferences.setBoolean(prefErrorLogs,errorLogsEnabled); if(Preferences.get(prefAutoSaveInterval) == null) Preferences.setInteger(prefAutoSaveInterval,autoSaveInterval); - if(Preferences.get(prefUntitledAutoSave) == null) - Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); +// if(Preferences.get(prefUntitledAutoSave) == null) +// Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled); if(Preferences.get(prefAutoSave) == null) Preferences.setBoolean(prefAutoSave,autoSaveEnabled); } From 3a063efe48f7a0ed4647f68ffd8932acf01d0f0c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 5 Jun 2014 02:27:33 +0530 Subject: [PATCH 343/608] some tidying up, tinkering around --- .../mode/experimental/ASTGenerator.java | 16 +++++++++++++--- .../mode/experimental/ErrorCheckerService.java | 11 +++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index ebda1f9ea..141c3888c 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = !true; + public static final boolean SHOWAST = true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { @@ -794,6 +794,13 @@ public class ASTGenerator { private AtomicBoolean predictionOngoing; + /** + * The main function that calculates possible code completion candidates + * + * @param word + * @param line + * @param lineStartNonWSOffset + */ public void preparePredictions(final String word, final int line, final int lineStartNonWSOffset) { if(predictionOngoing.get()) return; @@ -890,11 +897,14 @@ public class ASTGenerator { MethodInvocation mi = (MethodInvocation)testnode; System.out.println(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size()); } + + // find nearest ASTNode nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() .get(0)); - if (nearestNode == null) - //Make sure nearestNode is not NULL if couldn't find a closeset node + if (nearestNode == null) { + // Make sure nearestNode is not NULL if couldn't find a closeset node nearestNode = (ASTNode) compilationUnit.types().get(0); + } logE(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(nearestNode)); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 92948c09a..e4885a37f 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -36,11 +36,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.JCheckBoxMenuItem; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.DefaultTableModel; -import javax.swing.text.AbstractDocument; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -137,7 +135,7 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu; + protected CompilationUnit cu, lastCorrectCu; /** * If true, compilation checker will be reloaded with updated classpath @@ -537,7 +535,10 @@ public class ErrorCheckerService implements Runnable{ if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); + lastCorrectCu = cu; } else { + CompilationUnit cuTemp = null; + lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -548,7 +549,8 @@ public class ErrorCheckerService implements Runnable{ protected void compileCheck() { - // CU needs to be updated coz before compileCheck xqpreprocessor is run on the source code which makes some further changes + // CU needs to be updated coz before compileCheck xqpreprocessor is run on + // the source code which makes some further changes //TODO Check if this breaks things parser.setSource(sourceCode.toCharArray()); @@ -565,6 +567,7 @@ public class ErrorCheckerService implements Runnable{ cu = (CompilationUnit) parser.createAST(null); else { synchronized (cu) { + if (!hasSyntaxErrors()) cu = (CompilationUnit) parser.createAST(null); } } From f983628f599c2cbc36aaf8fc526c13038de5b160 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 5 Jun 2014 21:38:46 +0530 Subject: [PATCH 344/608] reverting changes before branching --- .../processing/mode/experimental/ErrorCheckerService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index e4885a37f..20ba28a7e 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -135,7 +135,7 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu, lastCorrectCu; + protected CompilationUnit cu; /** * If true, compilation checker will be reloaded with updated classpath @@ -535,10 +535,10 @@ public class ErrorCheckerService implements Runnable{ if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); - lastCorrectCu = cu; + //lastCorrectCu = cu; } else { CompilationUnit cuTemp = null; - lastCorrectCu = cuTemp; + //lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -567,7 +567,7 @@ public class ErrorCheckerService implements Runnable{ cu = (CompilationUnit) parser.createAST(null); else { synchronized (cu) { - if (!hasSyntaxErrors()) + //if (!hasSyntaxErrors()) cu = (CompilationUnit) parser.createAST(null); } } From 62630487be923bac948e191b9e45693a9817dc38 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Thu, 5 Jun 2014 21:39:47 +0530 Subject: [PATCH 345/608] Added a 2nd CU --- .../mode/experimental/ErrorCheckerService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 20ba28a7e..757be96ca 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -135,7 +135,7 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu; + protected CompilationUnit cu, lastCorrectCu; /** * If true, compilation checker will be reloaded with updated classpath @@ -535,10 +535,10 @@ public class ErrorCheckerService implements Runnable{ if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); - //lastCorrectCu = cu; + lastCorrectCu = cu; } else { CompilationUnit cuTemp = null; - //lastCorrectCu = cuTemp; + lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -567,8 +567,8 @@ public class ErrorCheckerService implements Runnable{ cu = (CompilationUnit) parser.createAST(null); else { synchronized (cu) { - //if (!hasSyntaxErrors()) - cu = (CompilationUnit) parser.createAST(null); + if (!hasSyntaxErrors()) + cu = (CompilationUnit) parser.createAST(null); } } compilationUnitState = 2; From 6666d4fe5bf36d92a15cb5514d679b3e6a33d1bd Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Jun 2014 12:18:25 -0400 Subject: [PATCH 346/608] switch to 7u60 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 4d0f0b233..97a9458b3 100755 --- a/build/build.xml +++ b/build/build.xml @@ -151,7 +151,7 @@ - + From f94805087eb3838fca1433756c5c990608dff006 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Jun 2014 12:39:12 -0400 Subject: [PATCH 347/608] fail on error with delete, need to fix some errors --- build/build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build.xml b/build/build.xml index 97a9458b3..212a9b2e4 100755 --- a/build/build.xml +++ b/build/build.xml @@ -679,7 +679,7 @@ - + @@ -832,7 +832,7 @@ - + From d50c97d0a376a40e106e5457ffb6ce55b89663dc Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Jun 2014 12:39:17 -0400 Subject: [PATCH 348/608] general notes --- core/todo.txt | 4 ++++ todo.txt | 23 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/core/todo.txt b/core/todo.txt index ea362845a..fd55c7030 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -2,6 +2,10 @@ high +_ Closing opengl sketch from the PDE doesn't stop java process on windows +_ https://github.com/processing/processing/issues/2335 +_ StingList.insert() error (should be an easy fix) +_ https://github.com/processing/processing/issues/2548 _ pull for image resize and alpha issues _ https://github.com/processing/processing/pull/2324 _ dataPath() not working when app is not run from app dir on Linux diff --git a/todo.txt b/todo.txt index 340c441f5..00ea7707d 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,22 @@ 0228 pde +_ shouldn't write sketch.properties unless it's a non-default mode +_ https://github.com/processing/processing/issues/2531 +_ huge i18n patch +_ https://github.com/processing/processing/pull/2084 +_ make ant fail when trying to delete JRE files that don't exist +_ some aren't being removed properly +earlier +X for() loop with nothing inside parens crashes Auto Format +X https://github.com/processing/processing/issues/2141 + +gsoc +_ `return` keyword not treated as such when followed by a bracket +_ https://github.com/processing/processing/issues/2099 +_ IllegalArgumentException when clicking between editor windows +_ https://github.com/processing/processing/issues/2530 +_ "String index out of range" error +_ https://github.com/processing/processing/issues/1940 medium _ possible to open a sketch multiple times @@ -42,8 +59,6 @@ _ the Find window (also the save windows) also have the same problem _ move old Google Code SVN back to processing.org _ then cull out the old branches/tags from the Github repo _ and/or start bundling separate source downloads -_ "String index out of range" error -_ https://github.com/processing/processing/issues/1940 _ look through all isPopupTrigger() code _ make sure both press/release are implemented _ emacs style errors in commander aren't quite right @@ -692,8 +707,6 @@ _ update will update classes from shared in the current folder TOOLS / Auto Format -_ for() loop with nothing inside parens crashes Auto Format -_ https://github.com/processing/processing/issues/2141 _ extra indent found _ https://github.com/processing/processing/issues/1041 _ Switch block cases not indented @@ -861,6 +874,8 @@ find YOUR_APP/Contents/ -type f \ DIST / Linux +_ Processing is named processing-app-Base in Gnome 3 +_ https://github.com/processing/processing/issues/2534 _ how to run "headless" from user Batuff _ sudo apt-get install xvfb _ Xvfb :2 -screen 0 1024x768x24 & From fcbfdbd8c289fba31c7188eb9ad1b9c16bb36c76 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Jun 2014 13:29:47 -0400 Subject: [PATCH 349/608] add chaining operations and copy() to PVector (#257) --- core/src/processing/core/PVector.java | 128 ++++++++++++++++++-------- core/todo.txt | 13 ++- 2 files changed, 99 insertions(+), 42 deletions(-) diff --git a/core/src/processing/core/PVector.java b/core/src/processing/core/PVector.java index 49e54a0d0..a99f427f7 100644 --- a/core/src/processing/core/PVector.java +++ b/core/src/processing/core/PVector.java @@ -119,6 +119,7 @@ public class PVector implements Serializable { /** Array so that this can be temporarily used in an array context */ transient protected float[] array; + /** * Constructor for an empty vector: x, y, and z are set to 0. */ @@ -149,6 +150,7 @@ public class PVector implements Serializable { this.z = 0; } + /** * ( begin auto-generated from PVector_set.xml ) * @@ -163,28 +165,33 @@ public class PVector implements Serializable { * @param z the z component of the vector * @brief Set the components of the vector */ - public void set(float x, float y, float z) { + public PVector set(float x, float y, float z) { this.x = x; this.y = y; this.z = z; + return this; } + /** * @param x the x component of the vector * @param y the y component of the vector */ - public void set(float x, float y) { + public PVector set(float x, float y) { this.x = x; this.y = y; + return this; } + /** * @param v any variable of type PVector */ - public void set(PVector v) { + public PVector set(PVector v) { x = v.x; y = v.y; z = v.z; + return this; } @@ -192,7 +199,7 @@ public class PVector implements Serializable { * Set the x, y (and maybe z) coordinates using a float[] array as the source. * @param source array to copy from */ - public void set(float[] source) { + public PVector set(float[] source) { if (source.length >= 2) { x = source[0]; y = source[1]; @@ -200,6 +207,7 @@ public class PVector implements Serializable { if (source.length >= 3) { z = source[2]; } + return this; } @@ -217,9 +225,10 @@ public class PVector implements Serializable { * @see PVector#random3D() */ static public PVector random2D() { - return random2D(null,null); + return random2D(null, null); } + /** * Make a new 2D unit vector with a random direction * using Processing's current random number generator @@ -227,7 +236,7 @@ public class PVector implements Serializable { * @return the random PVector */ static public PVector random2D(PApplet parent) { - return random2D(null,parent); + return random2D(null, parent); } /** @@ -236,18 +245,23 @@ public class PVector implements Serializable { * @return the random PVector */ static public PVector random2D(PVector target) { - return random2D(target,null); + return random2D(target, null); } + /** - * Make a new 2D unit vector with a random direction + * Make a new 2D unit vector with a random direction. Pass in the parent + * PApplet if you want randomSeed() to work (and be predictable). Or leave + * it null and be... random. * @return the random PVector */ static public PVector random2D(PVector target, PApplet parent) { - if (parent == null) return fromAngle((float)(Math.random()*Math.PI*2),target); - else return fromAngle(parent.random(PConstants.TWO_PI),target); + return (parent == null) ? + fromAngle((float) (Math.random() * Math.PI*2), target) : + fromAngle(parent.random(PConstants.TAU), target); } + /** * ( begin auto-generated from PVector_random3D.xml ) * @@ -262,9 +276,10 @@ public class PVector implements Serializable { * @see PVector#random2D() */ static public PVector random3D() { - return random3D(null,null); + return random3D(null, null); } + /** * Make a new 3D unit vector with a random direction * using Processing's current random number generator @@ -272,18 +287,20 @@ public class PVector implements Serializable { * @return the random PVector */ static public PVector random3D(PApplet parent) { - return random3D(null,parent); + return random3D(null, parent); } + /** * Set a 3D vector to a random unit vector with a random direction * @param target the target vector (if null, a new vector will be created) * @return the random PVector */ static public PVector random3D(PVector target) { - return random3D(target,null); + return random3D(target, null); } + /** * Make a new 3D unit vector with a random direction * @return the random PVector @@ -309,6 +326,7 @@ public class PVector implements Serializable { return target; } + /** * ( begin auto-generated from PVector_sub.xml ) * @@ -342,6 +360,12 @@ public class PVector implements Serializable { return target; } + + public PVector copy() { + return new PVector(x, y, z); + } + + /** * ( begin auto-generated from PVector_get.xml ) * @@ -353,10 +377,12 @@ public class PVector implements Serializable { * @usage web_application * @brief Get a copy of the vector */ + @Deprecated public PVector get() { - return new PVector(x, y, z); + return copy(); } + /** * @param target */ @@ -393,6 +419,7 @@ public class PVector implements Serializable { return (float) Math.sqrt(x*x + y*y + z*z); } + /** * ( begin auto-generated from PVector_mag.xml ) * @@ -413,6 +440,7 @@ public class PVector implements Serializable { return (x*x + y*y + z*z); } + /** * ( begin auto-generated from PVector_add.xml ) * @@ -429,21 +457,24 @@ public class PVector implements Serializable { * @param v the vector to be added * @brief Adds x, y, and z components to a vector, one vector to another, or two independent vectors */ - public void add(PVector v) { + public PVector add(PVector v) { x += v.x; y += v.y; z += v.z; + return this; } + /** * @param x x component of the vector * @param y y component of the vector * @param z z component of the vector */ - public void add(float x, float y, float z) { + public PVector add(float x, float y, float z) { this.x += x; this.y += y; this.z += z; + return this; } @@ -487,21 +518,24 @@ public class PVector implements Serializable { * @param v any variable of type PVector * @brief Subtract x, y, and z components from a vector, one vector from another, or two independent vectors */ - public void sub(PVector v) { + public PVector sub(PVector v) { x -= v.x; y -= v.y; z -= v.z; + return this; } + /** * @param x the x component of the vector * @param y the y component of the vector * @param z the z component of the vector */ - public void sub(float x, float y, float z) { + public PVector sub(float x, float y, float z) { this.x -= x; this.y -= y; this.z -= z; + return this; } @@ -542,10 +576,11 @@ public class PVector implements Serializable { * @brief Multiply a vector by a scalar * @param n the number to multiply with the vector */ - public void mult(float n) { + public PVector mult(float n) { x *= n; y *= n; z *= n; + return this; } @@ -571,7 +606,6 @@ public class PVector implements Serializable { } - /** * ( begin auto-generated from PVector_div.xml ) * @@ -584,10 +618,11 @@ public class PVector implements Serializable { * @brief Divide a vector by a scalar * @param n the number by which to divide the vector */ - public void div(float n) { + public PVector div(float n) { x /= n; y /= n; z /= n; + return this; } @@ -600,6 +635,7 @@ public class PVector implements Serializable { return div(v, n, null); } + /** * Divide a vector by a scalar and store the result in another vector. * @param target PVector in which to store the result @@ -665,6 +701,7 @@ public class PVector implements Serializable { return x*v.x + y*v.y + z*v.z; } + /** * @param x x component of the vector * @param y y component of the vector @@ -674,6 +711,7 @@ public class PVector implements Serializable { return this.x*x + this.y*y + this.z*z; } + /** * @param v1 any variable of type PVector * @param v2 any variable of type PVector @@ -717,6 +755,7 @@ public class PVector implements Serializable { return target; } + /** * @param v1 any variable of type PVector * @param v2 any variable of type PVector @@ -747,11 +786,12 @@ public class PVector implements Serializable { * @usage web_application * @brief Normalize the vector to a length of 1 */ - public void normalize() { + public PVector normalize() { float m = mag(); if (m != 0 && m != 1) { div(m); } + return this; } @@ -785,13 +825,15 @@ public class PVector implements Serializable { * @param max the maximum magnitude for the vector * @brief Limit the magnitude of the vector */ - public void limit(float max) { + public PVector limit(float max) { if (magSq() > max*max) { normalize(); mult(max); } + return this; } + /** * ( begin auto-generated from PVector_setMag.xml ) * @@ -804,11 +846,13 @@ public class PVector implements Serializable { * @param len the new length for this vector * @brief Set the magnitude of the vector */ - public void setMag(float len) { + public PVector setMag(float len) { normalize(); mult(len); + return this; } + /** * Sets the magnitude of this vector, storing the result in another vector. * @param target Set to null to create a new vector @@ -821,6 +865,7 @@ public class PVector implements Serializable { return target; } + /** * ( begin auto-generated from PVector_setMag.xml ) * @@ -857,11 +902,12 @@ public class PVector implements Serializable { * @brief Rotate the vector by an angle (2D only) * @param theta the angle of rotation */ - public void rotate(float theta) { - float xTemp = x; + public PVector rotate(float theta) { + float temp = x; // Might need to check for rounding errors like with angleBetween function? x = x*PApplet.cos(theta) - y*PApplet.sin(theta); - y = xTemp*PApplet.sin(theta) + y*PApplet.cos(theta); + y = temp*PApplet.sin(theta) + y*PApplet.cos(theta); + return this; } @@ -879,35 +925,40 @@ public class PVector implements Serializable { * @param amt The amount of interpolation; some value between 0.0 (old vector) and 1.0 (new vector). 0.1 is very near the new vector. 0.5 is halfway in between. * @see PApplet#lerp(float, float, float) */ - public void lerp(PVector v, float amt) { - x = PApplet.lerp(x,v.x,amt); - y = PApplet.lerp(y,v.y,amt); - z = PApplet.lerp(z,v.z,amt); + public PVector lerp(PVector v, float amt) { + x = PApplet.lerp(x, v.x, amt); + y = PApplet.lerp(y, v.y, amt); + z = PApplet.lerp(z, v.z, amt); + return this; } + /** * Linear interpolate between two vectors (returns a new PVector object) * @param v1 the vector to start from * @param v2 the vector to lerp to */ public static PVector lerp(PVector v1, PVector v2, float amt) { - PVector v = v1.get(); + PVector v = v1.copy(); v.lerp(v2, amt); return v; } + /** * Linear interpolate the vector to x,y,z values * @param x the x component to lerp to * @param y the y component to lerp to * @param z the z component to lerp to */ - public void lerp(float x, float y, float z, float amt) { - this.x = PApplet.lerp(this.x,x,amt); - this.y = PApplet.lerp(this.y,y,amt); - this.z = PApplet.lerp(this.z,z,amt); + public PVector lerp(float x, float y, float z, float amt) { + this.x = PApplet.lerp(this.x, x, amt); + this.y = PApplet.lerp(this.y, y, amt); + this.z = PApplet.lerp(this.z, z, amt); + return this; } + /** * ( begin auto-generated from PVector_angleBetween.xml ) * @@ -976,14 +1027,17 @@ public class PVector implements Serializable { return array; } + @Override public boolean equals(Object obj) { - if (!(obj instanceof PVector)) + if (!(obj instanceof PVector)) { return false; + } final PVector p = (PVector) obj; return x == p.x && y == p.y && z == p.z; } + @Override public int hashCode() { int result = 1; diff --git a/core/todo.txt b/core/todo.txt index fd55c7030..c2774207f 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,4 +1,12 @@ 0228 core +X add copy() method to PVector +X modify PVector to include better methods for chaining operations +X http://code.google.com/p/processing/issues/detail?id=218 +X https://github.com/processing/processing/issues/257 +X PVector discussion with Dan +o Jer and Dan will look at their code, plus toxiclibs + +_ bring back chaining in JSON (and add to XML) high @@ -434,13 +442,8 @@ _ https://github.com/processing/processing/issues/1596 CORE / PVector -_ PVector discussion with Dan -_ Jer and Dan will look at their code, plus toxiclibs -_ modify PVector to include better methods for chaining operations -_ http://code.google.com/p/processing/issues/detail?id=218 _ add screen(PVector), model(PVector) and world(PVector)? _ maybe screenVec()? or screenXYZ()? -_ PVector chaining -> Dan looking into this CORE / OpenGL (Andres) From a21ae3bc2c0309eb138bc586ee22a22a7b1b27ac Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 01:30:29 +0530 Subject: [PATCH 350/608] A possible solution to #68 --- .../mode/experimental/ASTGenerator.java | 4 +- .../experimental/ErrorCheckerService.java | 43 +++++++++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 141c3888c..641578757 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -899,11 +899,11 @@ public class ASTGenerator { } // find nearest ASTNode - nearestNode = findClosestNode(lineNumber, (ASTNode) compilationUnit.types() + nearestNode = findClosestNode(lineNumber, (ASTNode) errorCheckerService.getLastCorrectCU().types() .get(0)); if (nearestNode == null) { // Make sure nearestNode is not NULL if couldn't find a closeset node - nearestNode = (ASTNode) compilationUnit.types().get(0); + nearestNode = (ASTNode) errorCheckerService.getLastCorrectCU().types().get(0); } logE(lineNumber + " Nearest ASTNode to PRED " + getNodeAsString(nearestNode)); diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 757be96ca..181d02dab 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -135,7 +135,17 @@ public class ErrorCheckerService implements Runnable{ /** * Compilation Unit for current sketch */ - protected CompilationUnit cu, lastCorrectCu; + protected CompilationUnit cu; + + /** + * The Compilation Unit generated during compile check + */ + protected CompilationUnit compileCheckCU; + + /** + * This Compilation Unit points to the last error free CU + */ + protected CompilationUnit lastCorrectCU; /** * If true, compilation checker will be reloaded with updated classpath @@ -431,6 +441,9 @@ public class ErrorCheckerService implements Runnable{ // No syntax errors, proceed for compilation check, Stage 2. //if(hasSyntaxErrors()) astGenerator.buildAST(null); + if (!hasSyntaxErrors()) { + + } if (problems.length == 0 && editor.compilationCheckEnabled) { //mainClassOffset++; // just a hack. @@ -535,10 +548,11 @@ public class ErrorCheckerService implements Runnable{ if (problems.length == 0) { syntaxErrors.set(false); containsErrors.set(false); - lastCorrectCu = cu; + parser.setSource(sourceCode.toCharArray()); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setCompilerOptions(options); + lastCorrectCU = (CompilationUnit) parser.createAST(null); } else { - CompilationUnit cuTemp = null; - lastCorrectCu = cuTemp; syntaxErrors.set(true); containsErrors.set(true); } @@ -563,14 +577,17 @@ public class ErrorCheckerService implements Runnable{ options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); parser.setCompilerOptions(options); - if (cu == null) - cu = (CompilationUnit) parser.createAST(null); + if (compileCheckCU == null) + compileCheckCU = (CompilationUnit) parser.createAST(null); else { - synchronized (cu) { - if (!hasSyntaxErrors()) - cu = (CompilationUnit) parser.createAST(null); + synchronized (compileCheckCU) { + compileCheckCU = (CompilationUnit) parser.createAST(null); } } + if(!hasSyntaxErrors()) + lastCorrectCU = compileCheckCU; + cu = compileCheckCU; + compilationUnitState = 2; // Currently (Sept, 2012) I'm using Java's reflection api to load the // CompilationChecker class(from CompilationChecker.jar) that houses the @@ -722,6 +739,14 @@ public class ErrorCheckerService implements Runnable{ // log("Compilecheck, Done."); } + public CompilationUnit getLastCorrectCU(){ + return lastCorrectCU; + } + + public CompilationUnit getLatestCU(){ + return compileCheckCU; + } + private int loadClassCounter = 0; public URLClassLoader getSketchClassLoader() { loadClassCounter++; From 4956ef2d81cb1b543cf9b792ef78c3059fc04695 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 5 Jun 2014 17:03:07 -0400 Subject: [PATCH 351/608] delete video library now in processing-video --- java/libraries/video/.classpath | 9 - java/libraries/video/.gitignore | 1 - java/libraries/video/.project | 17 - .../.settings/org.eclipse.jdt.core.prefs | 12 - java/libraries/video/build.xml | 31 - .../Capture/AsciiVideo/AsciiVideo.pde | 140 -- .../AsciiVideo/data/UniversLTStd-Light-48.vlw | Bin 168251 -> 0 bytes .../BackgroundSubtraction.pde | 74 - .../BrightnessThresholding.pde | 63 - .../BrightnessTracking/BrightnessTracking.pde | 53 - .../Capture/ColorSorting/ColorSorting.pde | 146 -- .../examples/Capture/ColorSorting/Tuple.pde | 29 - .../FrameDifferencing/FrameDifferencing.pde | 70 - .../Capture/Framingham/Framingham.pde | 62 - .../GettingStartedCapture.pde | 49 - .../examples/Capture/HsvSpace/HsvSpace.pde | 213 --- .../video/examples/Capture/HsvSpace/Tuple.pde | 33 - .../examples/Capture/LivePocky/LivePocky.pde | 57 - .../video/examples/Capture/Mirror/Mirror.pde | 73 - .../examples/Capture/Mirror2/Mirror2.pde | 63 - .../Capture/RadialPocky/RadialPocky.pde | 81 -- .../examples/Capture/SlitScan/SlitScan.pde | 56 - .../Capture/Spatiotemporal/Spatiotemporal.pde | 131 -- .../TimeDisplacement/TimeDisplacement.pde | 84 -- .../video/examples/Movie/Frames/Frames.pde | 79 -- .../video/examples/Movie/Loop/Loop.pde | 29 - .../examples/Movie/Pixelate/Pixelate.pde | 51 - .../video/examples/Movie/Reverse/Reverse.pde | 48 - .../video/examples/Movie/Scratch/Scratch.pde | 39 - .../video/examples/Movie/Speed/Speed.pde | 33 - java/libraries/video/library/.gitignore | 1 - java/libraries/video/library/export.txt | 1 - .../video/src/processing/video/Capture.java | 1227 ----------------- .../src/processing/video/LibraryLoader.java | 236 ---- .../src/processing/video/LibraryPath.java | 62 - .../video/src/processing/video/Movie.java | 1026 -------------- .../video/src/processing/video/Video.java | 229 --- 37 files changed, 4608 deletions(-) delete mode 100644 java/libraries/video/.classpath delete mode 100644 java/libraries/video/.gitignore delete mode 100644 java/libraries/video/.project delete mode 100755 java/libraries/video/.settings/org.eclipse.jdt.core.prefs delete mode 100755 java/libraries/video/build.xml delete mode 100644 java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde delete mode 100644 java/libraries/video/examples/Capture/AsciiVideo/data/UniversLTStd-Light-48.vlw delete mode 100644 java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde delete mode 100644 java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde delete mode 100644 java/libraries/video/examples/Capture/BrightnessTracking/BrightnessTracking.pde delete mode 100644 java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde delete mode 100644 java/libraries/video/examples/Capture/ColorSorting/Tuple.pde delete mode 100644 java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde delete mode 100644 java/libraries/video/examples/Capture/Framingham/Framingham.pde delete mode 100644 java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde delete mode 100644 java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde delete mode 100644 java/libraries/video/examples/Capture/HsvSpace/Tuple.pde delete mode 100644 java/libraries/video/examples/Capture/LivePocky/LivePocky.pde delete mode 100644 java/libraries/video/examples/Capture/Mirror/Mirror.pde delete mode 100644 java/libraries/video/examples/Capture/Mirror2/Mirror2.pde delete mode 100644 java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde delete mode 100644 java/libraries/video/examples/Capture/SlitScan/SlitScan.pde delete mode 100644 java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde delete mode 100644 java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde delete mode 100644 java/libraries/video/examples/Movie/Frames/Frames.pde delete mode 100644 java/libraries/video/examples/Movie/Loop/Loop.pde delete mode 100644 java/libraries/video/examples/Movie/Pixelate/Pixelate.pde delete mode 100644 java/libraries/video/examples/Movie/Reverse/Reverse.pde delete mode 100644 java/libraries/video/examples/Movie/Scratch/Scratch.pde delete mode 100644 java/libraries/video/examples/Movie/Speed/Speed.pde delete mode 100644 java/libraries/video/library/.gitignore delete mode 100644 java/libraries/video/library/export.txt delete mode 100644 java/libraries/video/src/processing/video/Capture.java delete mode 100644 java/libraries/video/src/processing/video/LibraryLoader.java delete mode 100644 java/libraries/video/src/processing/video/LibraryPath.java delete mode 100644 java/libraries/video/src/processing/video/Movie.java delete mode 100644 java/libraries/video/src/processing/video/Video.java diff --git a/java/libraries/video/.classpath b/java/libraries/video/.classpath deleted file mode 100644 index 80820b4c9..000000000 --- a/java/libraries/video/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/java/libraries/video/.gitignore b/java/libraries/video/.gitignore deleted file mode 100644 index ba077a403..000000000 --- a/java/libraries/video/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bin diff --git a/java/libraries/video/.project b/java/libraries/video/.project deleted file mode 100644 index aa59004d2..000000000 --- a/java/libraries/video/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - processing-video - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/java/libraries/video/.settings/org.eclipse.jdt.core.prefs b/java/libraries/video/.settings/org.eclipse.jdt.core.prefs deleted file mode 100755 index 1b3d9a205..000000000 --- a/java/libraries/video/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,12 +0,0 @@ -#Sat Nov 12 10:54:16 CST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/java/libraries/video/build.xml b/java/libraries/video/build.xml deleted file mode 100755 index 202242085..000000000 --- a/java/libraries/video/build.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde b/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde deleted file mode 100644 index 59364288b..000000000 --- a/java/libraries/video/examples/Capture/AsciiVideo/AsciiVideo.pde +++ /dev/null @@ -1,140 +0,0 @@ -/** - * ASCII Video - * by Ben Fry. - * - * - * Text characters have been used to represent images since the earliest computers. - * This sketch is a simple homage that re-interprets live video as ASCII text. - * See the keyPressed function for more options, like changing the font size. - */ - -import processing.video.*; - -Capture video; -boolean cheatScreen; - -// All ASCII characters, sorted according to their visual density -String letterOrder = - " .`-_':,;^=+/\"|)\\<>)iv%xclrs{*}I?!][1taeo7zjLu" + - "nT#JCwfy325Fp6mqSghVd4EgXPGZbYkOA&8U$@KHDBWNMR0Q"; -char[] letters; - -float[] bright; -char[] chars; - -PFont font; -float fontSize = 1.5; - - -void setup() { - size(640, 480); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, 160, 120); - - // Start capturing the images from the camera - video.start(); - - int count = video.width * video.height; - //println(count); - - font = loadFont("UniversLTStd-Light-48.vlw"); - - // for the 256 levels of brightness, distribute the letters across - // the an array of 256 elements to use for the lookup - letters = new char[256]; - for (int i = 0; i < 256; i++) { - int index = int(map(i, 0, 256, 0, letterOrder.length())); - letters[i] = letterOrder.charAt(index); - } - - // current characters for each position in the video - chars = new char[count]; - - // current brightness for each point - bright = new float[count]; - for (int i = 0; i < count; i++) { - // set each brightness at the midpoint to start - bright[i] = 128; - } -} - - -void captureEvent(Capture c) { - c.read(); -} - - -void draw() { - background(0); - - pushMatrix(); - - float hgap = width / float(video.width); - float vgap = height / float(video.height); - - scale(max(hgap, vgap) * fontSize); - textFont(font, fontSize); - - int index = 0; - video.loadPixels(); - for (int y = 1; y < video.height; y++) { - - // Move down for next line - translate(0, 1.0 / fontSize); - - pushMatrix(); - for (int x = 0; x < video.width; x++) { - int pixelColor = video.pixels[index]; - // Faster method of calculating r, g, b than red(), green(), blue() - int r = (pixelColor >> 16) & 0xff; - int g = (pixelColor >> 8) & 0xff; - int b = pixelColor & 0xff; - - // Another option would be to properly calculate brightness as luminance: - // luminance = 0.3*red + 0.59*green + 0.11*blue - // Or you could instead red + green + blue, and make the the values[] array - // 256*3 elements long instead of just 256. - int pixelBright = max(r, g, b); - - // The 0.1 value is used to damp the changes so that letters flicker less - float diff = pixelBright - bright[index]; - bright[index] += diff * 0.1; - - fill(pixelColor); - int num = int(bright[index]); - text(letters[num], 0, 0); - - // Move to the next pixel - index++; - - // Move over for next character - translate(1.0 / fontSize, 0); - } - popMatrix(); - } - popMatrix(); - - if (cheatScreen) { - //image(video, 0, height - video.height); - // set() is faster than image() when drawing untransformed images - set(0, height - video.height, video); - } -} - - -/** - * Handle key presses: - * 'c' toggles the cheat screen that shows the original image in the corner - * 'g' grabs an image and saves the frame to a tiff image - * 'f' and 'F' increase and decrease the font size - */ -void keyPressed() { - switch (key) { - case 'g': saveFrame(); break; - case 'c': cheatScreen = !cheatScreen; break; - case 'f': fontSize *= 1.1; break; - case 'F': fontSize *= 0.9; break; - } -} diff --git a/java/libraries/video/examples/Capture/AsciiVideo/data/UniversLTStd-Light-48.vlw b/java/libraries/video/examples/Capture/AsciiVideo/data/UniversLTStd-Light-48.vlw deleted file mode 100644 index 0d624969b37a0269535392d129a5e6226a6fc966..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168251 zcmeFa2b>i}vp3vlBfI2ffh8|F=dk1~N|q=pIVplj5=DtB8AWmiL1h6Ys(=X)kt8S? z$&zyp%f^2H)nTS*&N=J*Jn#L!>vOODJ9DPGs=B9RRdtvi#@KbnSXx}=aMi_C5LY;^ z{0a`nJ&S@vaVJ**S2|o_xYFaIFafy85lr+PxN<4jgFCrGxQgS-j*Do8ap`abQ`jQ7 zC@mBRJ)0cih_2H_@#t_x0aIE6ap|<^aK(V5%SwndVmY!idGlF+SLa@e*HXx zb({?VQ=GYRMdPA4b$K=fOuR&+yBY2o<)^lk$3<(T{8@2#_lIYJ)6b*$=y`#-$UTRP za5>f8d|qRPqjZaQje9UIa!qhiJdwDl%qX08O#zUf@H(A3Tr)+}ZOMFIb48=HmR2x5 zn_LTA#H;gWhHD8tg^5;oGk?zm=T3``vz6k{?;~7m70y@vwNd;;qx{kHbp5pjtkbE} z3Y2i|@K3zH%DO%96prH4Wd=~V7w}Isk|kQ62m<~(;PMyl#Z+i7DH_$0PNxSjxtDQ~ zJk$M;;@4%?5it3wZ)sVV447OeTof)1F5O;qxpW4O+AZZh8dm{afw;(Z!9_5oB?_`r z#|JO#ii^^r^#g^|>FfrW;?r%A>O<4I1E#Vz+nIh|58x>r^%Z(1h12Qm3D_M@(|UnM z;V2(eW@fnF@KZRFKbaJ))A9=Z1##)LnBiVkG|Gdn2c6D7ibj2h^gqR+X|DmMK0;-! zX#j=mi+|$P#zJeoy4bUZvggJE(1WL=bL%g z;RgDk>9QUK8a;#B5tXO;yut9h>s^N%0$MaKT@R#3bUnNYSl7F*Kb@ALpwTl#8&oiE z!o7umqEXwXi(u{E2H-E;FwiLPzT$jGg`<8%?U3To>3kP3J%{Q?_ajXk4jjn2$6JO!3o2@tS4527Z5OSqmD)L1E}J^RN#7jOwCi5iI~0x%IeoSw|~ar{!z- z-Lh5Z;TzBj;?i|Xap-Ux0h4^7K23E_e44fia0o74-jpsK=Vrj+xOBVL4i}ZR zzNoCV`yK$5wXRz#Yl@%TR$NqO6i&A_otACDmBtmVE`qiD34lM^_Ecy;gH{Sxw7Lk^ zZU+E=asC2Y8C=ooB3Qef0H_QpY&iwvCfqLk6W*7txLeVvJn|@5m-U`hXnRwk{hA7G zpQ349OzHCABDWtG`AwQm%WsO70r&I@#!a~2@lW9h@1`9Dj>?z%GnEg)I?h9Yb$L?# zQyjY952r#qk_zppiYFR(ij$tF<2(k~-}8=x=C6AguKVT*z!WFxBwhbH ze-{`nf3yp! z&@QGzyOav;GH8@eofb-`PRkX*RF*_1JxFz;X;%SLx=Ef<9*Cyv;TmAd1N9?nYs9B% z*8%&Z-AILYGZoq`(C8V|S4b8XfWGCple>+}L4#kX<&L6dz+H#a^9*+tjrx$L={WBz z8kL#OUm##|4{-U*-@{aBk5ZvMPKEX)6)CWL* z3PYDkYYjiOcX}r24(bo8y?ELHrud5DDv67pr)gaQlk6d!mIa#D4LEv+?qdZ2Yuej@ z{m2l{2u0I%M0~3MdC2~xc*s7XdLmfUrURz*lRcr^r=kUrZcKxV+B~&w3a4BE=|+FF zKR^q{MPc0GPAHnDQ=C*MZ~-UrM>dMqV@7!foKm!OxKo^l3m~~mc8{-go&i1-7uiBO zf5ZzHxDtQ#{Cv2m%n1&_1sAvte^fsdhAx7Yi>7j-P> zL$|?VfOVWyf0=Mme1&mQnsi!90w#G!bc&zyqFjOJ08o0gzNNhCa9tH%(>*g?FOhhB(t5_m##Ww*+HCd_{u)idU)}fc zSA97CDh6OOjliM64g0>z$$TmipVU}RvfP{>Vc9tUjb-9|Hw)){I}76c2gdg7orcsoTtswqbl6nH{H*J*P;6{j z#umkPjscCayL{?@IS^jHJX(M0^3+U(3yO(RRbDzKMkDE7iu0Aye--&PTpP~c7v6N7 z?=u)SF$v2!mr=Ll{9Ti0Qh@io|l+IsZj^eN zlC-PM`4S0V;}^PvK0%lT>oGO(7Y6CbXre?rU#a%dIe zzTq0GoS;hbK{+|!B%!^WlW^6p4(A_9_%6S!k#t8Jqz(cx#`!h@sJ}^^*AyU{;Cz#? zmUB`un4IPOO_Okh-;mx9IDcM31HU7ez#oeHcb7TeLr@r7;3L;SrSnh7UIcC&=L6|p zq#jZ$0M#SWC9MVs}V`+Zk`w{AP9uv5+(od@Dmb1oG+RL z30JRWbuW|n(3xdT@`29NWBx(T@9kJPh{U>b0Rtaf)%0Y7>^G2my9k*A?j!>4R21Cl z{s3-%{fvk^q};rxoL?3x`jqo)b-^GXS@0_7`%!cq5w0->Qz@x{=e)w$@0>3stVXld zB--+WxxE8D5Rx&lAa&d;fX*tCVHdUH=HNd_TpxB z!G5!uI}*l7!t)KaJ&s30Tf7f`&d(;ftD){sgojk0S3giZUH{emT9hg0*T<2mV!P}E z5@nG4qhxc|q=$U&M-T#>A9Dntlmzv<2>ed7smcU~t^l6Q4DD39gCJLUVU4s4wg}K~ zd864C&gZ=`XiynRvNHb_=j(21k!{r_I|CVg!V>YCI|t(aU_R%UNbTE?oD6gwXh6Qk zM0W<_jE7CYZ6%pAB9e%y37kK!0L8rt_{7+O^&j(T-RIqfC#5Zg&a_%o1N_q6?)){Lr+1&l*S>NT*vxp>KZBbsLZ+WVnD1>;Aa9@8ePi3YPPc zyZg*`kRHvCTzof^ZLm{gn9UxBs44wV z@o$N%59gifZo7b|w(O=zl`MM zdaRYR!Rk50ZFA_U;)3ctOdp<@njkkS*~azUoJgA zsfI?rew@p?QG9Fp(`X4^)TSN0?Kp3$80dy(J6U=6^Zgc~C+C$d5A*Edw`l-GZaKdu z0sN2VTz4|~(1ZqR5-0^V{2jlpL5x$+@H19kDq3=v!0!>>n6-zPlY z7EzgRL*Lr2bP7L34JZK8*yz7gIIm?h!Tx#76L*YVaT7w>uEyx6x?5}3iqtmY##oi0 zDUN&Ci?h})9ag}BV?hO;X%|BSG2brR`1>O2-#ba`$<6i56G5iGLk=~m7|T%bg9|3c z-o|~mXz0!;wnM`-CRExv;OOTh!WRmIr;o%2?Bx6lFNW#}rmJr_*QTezMhrUBsOn<| zNrD-{Ak-PW-*f({7Xv$D8UJO`lT~s|wl0XG8X-ataDKvSGd4@mN$6KJ%dpMhY+&PU zs4PnID^I$upc@u}O=paB^aPZFA>lFlOlz>r1`z@T2A^^v@II$KxMzZV;Ww(=m@xRu z+TIxGJkI0l*_d?jXV>1q_hCdO-QfJ8-Qn`UGSFf?{YG$~j429^+a-0N8l0b2aBj#r zz8Wbmk7jX2SIUc=Zz~> zpQq@Iy#(vz*YxB?g31f@AxL?xVSwlh{%vVsdBfTknJ5gzGlEn7;o1D_VD=_govs-Q zAk<`FAAut_02X!+f$j#clfknDC?xR)9t77EzM=xM{sPwk$N4CUCoUal9JIHU#4*ZT*qy?y7Tes41Icm^LE+HC3T#tk1%m6Y-MfevV6<_boMeUe0-UVm~SsPNpRO z2YFjV@zQ-R=b}-c;fKguP|4{*JcS}-`(!zweZ5THQT)EB>tPG}kXO3rr6_JKs|vRD z&-`nmq`jG}q*@qM5y{>mx)d?F7e`EC*Z6L$JNG4~0sL_h87=*9;9sY?!e6ryEb=m6 zqRnQ{wpFu6_ig_^WO=ZhQa=!QnOpJi2&r>*|GHKty~vd)1ahSH6&u1#IWL z`E(;GtA6U3ILO&fpnb-5xGWF&8Ojh$rEM}0 zE3j5J-9-bWBvoiE07XT)WrL*6Gsk8YJAnV0gvjBRLx*2#dHNJ{RHf}X?w63Mr{yrE zGS%|5HA?Y+W+A4M!BQ75Ui^r$UMN5a^Z8I?!HmJ;n~OEIB+k*|YjS=8s$d}JlMqiV z=jCuaBP3nshY#O|C#s(9%67G@f^T+sYA&(e;54xFveW_Z9M_+bR>t0sjjd`TG9~b& zY$oDm&VMrf>`TtyFcD#oq~x=3P)YkN4*^Ro%^=Z1x0KY=T=m=*_H@q2X(HV{kkXY* zL?tE8EgbagG|NK(UyuxCvOxc{dZ0_6bjvR))gD82!;?V9Q(soZve=C6~$3kY;5~H_J5` z@LYCGBQhGgA29>a4BmSV#0l93EnEoxAhLR= z%_m!h^Avk2aA$9e@shA*bsRMH!h`GLua<=(;6p5Xu*^uM zG-fqzJ4Pi!0yw&BAOsbp3KY;qvt?F6tc@9~jawTX0q&n-)}NZ=Nk}tWZWKaWnoL|h z!9Ilma^VM2@%aeyYy*C*v^4V3@Jme?6}k%eIEh)^1Xkv~)10xok_JO*&oTxgw{=qaVs zj>7+w&X^?TrO`e4S?C=JKN>~FPjJ6QvKtYs8y>+rMgPFEBz%`cRF_F#pE(;3$ z889uCAjd`;g}Kv>2;ax{O9*1bm;q8$>ft{dr6no%Exju^ z$wPkiyvx-gte2zp4sZ9Yj4`0)m{o@_{jz*qD=pjz-|Vmz;B0>_(=(EkghREFyDb%6 zz&C&&jH#W|lex-kX8>Q#PccvvU!_Yos2B2ZB2vzB>SJ4Omkv{59Y#_HoJFkH=7IykYB$yL)I!f zgP>8Yrz(2GfsO>`efAqVk!~e|yd3BvtP}o!GJ5eF@UH_R-UTfg)nUbD8 zCMKqYW;O0X`w`tv1EE2Zd%g%o;yBXo9m2DnC&H}vCcso23oFu#koN&U9_ov*ktbIt zyVD&4C5syMCS<$K&!MAx6HuwoAUj@!=T*aV6Ea=lS40bQ6BfcM73Jb0G_++{RFc} zhN#&^uTSn;Y$PQ@6+Yn z7kL#2SuD^4E=Sn)&^j^=>B_bKsy;k+e?E(guhz=eYMBh;pV!ZWk{Dv@MNzzvWIjXDbW#?Y!+Jo%b@ z3ouDmI(i46rRTF+phe!K%4`bkY#EOJd%@cu_dl>?A7G=|ZcbY`XmI_Ufo0=_aRkA8 z#>BF+Q>RW1X6LxIy~LnqK^$ETzXBoceRZ6HXzPNbMBBmR26d35SFt7NCz$_T_aGEp z%Fc3vX$IEMncm<j)VId6j(TI zhPkhcQ;=6-$^b7wJaSHpR!1CzL7#%VZSZDAX`CQCEbSrSKT%Sw;T3qAipUC**txK{ zca?VIz9n00p1@)`OVt=q7#(y}SiBQ51T9XwUkX}S0;&y|vSRhjfrS+^uTw=xUjbC3 zw_D^J+i9iSU32WfQ4h-WP;YZr2yuf(-)s5>9QdbR4mL>;mp9DrE@^0FV@)mrLpCRx zGD$Lg?%YQzkvY-V>v%-~Id#Yj8FtIvAczG${7$$RFGR+NUdTp}a?Z*i7L2(`**aY@ zRPwV<6nwMMN~i-mTxK*@5;0B(i}<1Hh&CbUf}Y5=abn|^TxKPFIB`jaefZ1^3{7rBw_RXod*%$n*s?lox(Qe&{bpjoUtWc6k0 zQ!baT$A@bVUD@^ddyS2vj2uH9OuEAz^@y=0iWc4az>g<|p>R?v+^U#8xIZPDq7A6E zE*X-Y3c3ii;jWB?6t41plpmfB!F9~caJ{G0@3TXLY12XSV@+oVuQ0&63n!RlZsFYrK`Cft#nR^d^8zAJn7HgP{9`JKMx=Bo$|( zxRg6LQdvO(?;*ZxV>?za((sif=$H4Or&vN!k9XeCwnW~!2sH}mQ79|3<4yv;CM$$o zIwr7aO6y?Y`-sd`zt~d)_9|=L%SkLFQqb+BYkdt*JBEpEAMic*InS83rPG@w$FO-$xzq zq?Yss7#hfM^iK-;b?mG|9>21&!V)+WAQZnePZTZk5o!B=(2pjw*po7sW-=T`s}!OP zYGa|3n~a0V@2zcdnndc1u!^GAQ7|=&;cx3>aHP(mqi0s>m@hMwlaKySOo zUK*ulL_{JyMO(f5`HD&X8de>$+EC7;!KZtsv9U`p2R<$PTTJkMSXdgtwV{PYdo4KmSZ|PHFU;LsYxcU zH5=#>^<>>uWJgQ<1gLd%Lv7PX>LgyiyYDestnz!lXv3{ zXe)He`TkDJLN7E^8$mMB$WB?3V1sSxHoWvxAh zVo|e()XOkahsZpzb=C9Kqd=`zAox)C?}<+vTIu_2v9;?#lavZ@1Wy(7%nR zz)|1stA9P`0qK0Z@NCYGV&}aW|Fwx53FD>ifPSfKsG2b5RGzPPe5!pW3$0-5IEQYa-HPaT3s69=8AZ)^C6&z8A z^!bC(cPF~#foO22U-zzA5PojuU79$fVTBJc8-(M|9k^z(k z<-RI`FaiARnmOajQvbtX*g9&pFrsnFu50eO zS7@S_9Fag?J2F%Pabz|*R=QR}pF!Q3L!TnBB$pcj3Sp%3TbPX~ftGPnjj;$@4P#w3 zmK97jAahUXd;>#o7@7W%gRr{{I=w`8H@^s~{$SpXF#QYzm1o@u+t4BkIBK{#oQN40 zFIIAJ{Og_|?DEWR28%}7Zv1~ln8Cvf)qdgmY6Tr_z@)QcZ||X=2KVTjH}X12%2Q>V zq^tjgC9sv8F83QlAB3}}9R6-)Nfd++e$ zvoU8BQL<#dU+AV+*0dJ9^` zX3j~zAZ6pkld_O>`SsZ#7C4w>KFz$cZh{zehd+rVp5R}ApD6{(OyZdcWJD5e_QYhs zSHvRboMs6Ky@Yr~1H6Q-g|v5qh9E2r#(4X5eHQ@>J&LitoJY`G5Jku{0O)53AlDKe zdXz|XadwWUP}QZygvvpIrN3eNQM6Eyi#?S`ieN}5J^ z%uvW_`KaQw1K1;9`v`zF`;+ykj@F|(i#KX6Vj)bvpfShd*{L5zyPsN%%%#WqISAQb z^OT22KB_hZCng_IcaTX{fwo%Ech;kj%0UR(R%{Q90D6jwr#s+31>7)&pCkQ(ZCIrA zAU3at2}0dC@Q6yueU&Fk5rIh^lmQZ1Kd;my{f(xCsW*t#~d$FX0_QDTN`~dSS z%(JBulYk>4>jX0)J2(NB{gz9EqFrvuMae zKr0HeychW~sktyzK0!h|M~gnyP#Rd&D&2QXM+nU<$N1xtgn(NB{aiqT=6^P{?`|3q zf~kd@R^!pw4zPU<)e|rU3D|%{*{<{&jHRtu1il;eLejT=q~!PH9Y`7Yqm&&)Kv|~7 zQ*Le_{%*@@0bO}dc9)D||Gpui=uu?sy; zoat*u&+y8>&4C*8-g0Y`b0zU(w|Rm?=-X7rMqq!;bRV1K6i>jP{Am`n?NfeI_^epX zL0L33BemhxVj>G2ca@DZpr{0X7BNRWuWg{01;f@5ma~(EhI6y_h{+X?IPo?vjPgF@OYQ55bqF<*I~A}7v4aC5miXjA!bf! zSlw%xQ*mJsN_CwK%k+$uK+m!CiQ>u}$M1@sCH<8#oVN@;LcQ+jA&kM4C7ENnLyp&S z#S0}QXtaam`c=c?o)xyEVP!3X5US;H5c!{5Au_;*@^*0%n&DM%B4Gw^mXIS#_TYSPti``X7epDWE85N_&d zare|Y0SakD7XcaoDm(!*HeLi)6hYqgMWDlJHv1%ef!(V<36n*0^?nBXNvx%L6L3Tb zS!LdYSD?Qk@x2Ibk~r_^oxx($pd~(_qCkj;>Ls>U$1Ec2>QPt16T#t5_frcPZbJO# zSEca@!ejAj-H7qCmaY8_?V3LorUnRRu}8k}325sPor{2{wtFfT=Di85=0l!b#YYH6 z)6zfqB-BMa@JWb9(sKKF1|1W_8~P$N1fjey!kaMT!+a6e)BX=11V}hO-kad*2$T0> zS|=eWYuWdq1jH*?h$>m_V7>@JAlw7$&mg$nW-(-N5+47#dvXJ+Sf>k#uF<|(X&8oX zm$CbgND;X^p9=%pVh9?JR%p8&&sr2#Vjtlj?p`%z=7z%rCbiSVVz=P^t*7Xqczbmo z;z(#JiFqy{Z=(!VSQ~OUPV{mQT4Yjl9f!ErLepJJ(94K$sDs29?5B9>m+;H3(KfNQ z0e?k&83eZ&S1=YjWXO=BIQiYzdb#Ayfu7Xe9ZdP#W2z~;AKCTmVgcw{ef-ceAm^?8&_Y1#;)ljyY`^1=cGcHz1jP(}xYl2|g}$|wVDAel zfLmfiydwH)tmFwnK4 z5k-RMqSMC8d|Z#z=$s8&#j{-G?+}S9s)2~%$y?g^32aLWr+(35R%Tb7WU2J++CdQ^mP^GW?yuiv!okk1Z_^gMi7#thnU;~Duz3;DJ{ zj73~DjP^&te3L^aFB%R@A;nG-&EmK%9!;)m7>v}}H8lgKXhO$$QR&+tQg9#PiyO$#}I>1aRoJ`TYe`KEP6Z(QxO zoq2{M)B)0IUg>OxXQ_9dOj=l;7Bk4|lYsr8t&@rh>sj-PIsVdh@_ab z2j_qP@uN1DxeSKPx=Wk)*5dpQXMFGtPYqp@da>zp3vSU_bwcDlC!+e_fqtoj)4}?o z%)8xzRMC?sIvvJm|9eXCzoebGUgm?hjIV0IfiHg0jm^%X;HUxaYJ|U#Kjb#EXAqnQ zoNJu@0>1x|$P>=?JF$hBE_apQG{4Bb&OX$k!vD-t`fqFuMl%e^8Pm3L5leH}6iP(JemLu!V}farCI(>i#V-z1Ms|t$6nS4o z#2}ro%cwbV20ms>QhEq~Z;(FJ_Nc%V!=U0ZnZ^;fF+vKkLlM*o>@@X16PnYuM z=+GTF0V~mK3n1uoE?)e@Bbuap`dkJU$3Y{sPnQQzrHK?@t~Ig}=8FK_c(3h+Hsd$$ z*-D#4lXc#$N6}$Fd~C2fz-!JiaR=kgukz<;=D~JjktOXKV`Q@2CNT$Xi*vhnZvD0a zY|O?hy>@KMSdN1BHpVSJggqS;))=$gzFut+vb9xMg@Tl_+t` z{NlT_)_gf{+~BUwOUwKgkByyfa!43oVwh7$9p&bvVnA~BAIkp+WpI0dmzyffT34p? zPPO3M5ygLO=bZIPzJKcU?@|Wq_wB261{=@+4wt)~REv#$&yDNg{a(EH3+@Q?58vOv z47y^cpSylBHMP0K-cgi zkwA+{8Q=}u@jdANR|OmJmUgE1f0LzUOYvBEOlKu`R*?cjmWl=~X@D*6V63pc~H)jA}G4NB& zy4N!zk@3VV$IDB#oM?(42IKu|E;Qj$@%KbpO&ajSU@2WIXd(gAbK56lrOceZQh54W zg1u!;1_VEv!w3+zhnZ0UkNmRfAZ#!#PKEa%4}6I+!~kBTF?bUQlkJ#*m*pS63j}*{ z$-=V;ntZpcLEv>g=E8zaQcD$;foDa~)Zz z*5W!}K{0RVPcmCfEpgU|D-!Znq75n*Q{Z{G+z~-Oqpi0V6MX;=i*7ELD}gq6+DzHv z`J>D(9-58lYBJHj^C2!Kyx4ymEB|&(tcLd+?U0jG5YAwtlOPO*3Zmy2PbuVLLb$Dt z=RK!Z?#-Ce!pyOyJJ?acEhv=9#Gu$07*UnPB2l0hQ!!|0y)+Ese6^#{853T=GtLQ& ze8S`99t6kZ=ot13;sNv!*m|*accqEZdRkjaU?Eqm4QbApNbmlvm^#^KE4Y|)Bv^0! zWBI?2;&(C8>1T2?S#4Ms>HRQ)_EfB`qw&vHJgy=D_OM)0E(qOd=}`CMDAXmaZGUXO z!Rp179tybw%P9W+K905KxHFQeOJ{OyY&nz%U#}7N9d=S< zBDs1OF<7Kay5_B57Rh@jq#~_)%#$ly{1Q;4iEqLzHO)UzkIH0Bq**+d$j~H)v(O&p zb3|#8sJ6fML&}IUw@q~8SpeH%Kb|Sf?Fbot>d$J;&QL5GnX76)&J0DLS~+BA&OxHg zVKk$hgG8BolHWIpGPl_ei89y0XM`ei`dmckv%vq2b*zmS37Jc&A)@pmQRa?_{^U)f z%)Lv&yh)U~IFi*qNR&C!T)s$@IZWpJB2mrVi11CK%q{XmqRiFy86l(09Y3SmA!WpH zlsP!+DH9E}0FgO=B+8thP>eFC=aFTU5hWYE*sM}6OA9z2RC(MniVN=c(pHW^6|t54 zQPR}^<(C~{J>wxO@apxpPbbdXD5Lq=cxfQ;6A)9r)F*}%pM=S8e%kJ7(Bk~cGe(R# zz60ibZiVRv&!I?z4Bd>;vTm|D?_%mSuY(MRFTfy&XG;Lpb&>HskaNf=WiukqeQ>?x zeF?$30UU_CV~nMu@}S1{0ETkgr%=w@5CkmD(k6My8^x9vBjhgPEbdCqfZB(px7pNY zxHIpXOh@wXr`_0(EsPUbM8h-;k6?G##m zX@b0mKM`|07yK=-k-n`ib`{6jvsy+JSmeA4QB@jjV+^zgOQF|}B@asQk=z)qN#ec{ z(?FsNP%&=u>XY4pT_^)A065DLma+P+=QKMRI4ZLO8x z^0YpiWOU)&$ARECXTI9Be7(*iVF|?aL-_)KQ$LID6_$Z;D4iExtRqAAy7@7ChSIv7#v3obTkyOOJROoU*ax1Sz(?H|EMC%8638Iyt<=M7I<#TZE`oy{I+GyoR$J9`5om?bwJKLo&Vrv3H*EIV1`Xq z&$HAO{a8ZTU2doJum7LJlTtGPo?s@4Y;3<4fEW{|W&+d`h34M|5D_ru*9b_`^Z5R( zfJx#3`14~1%=c&p=F<)^mqVBjL*U80l|TG;^u(DiG8!*S08K%74De(Bx@yoD9 zgtHjHC~SdGhS#L>wOyDt25|p$+NjstW>vHdDhlhCvZJXWc@e;|g+dXbk=&SBy;hwU z$8UTH#CZ%#h+wQ6;xOs?zyov=hpM>{l zfZ>%~w@_00uikCt- z+<{)w%=98WSk_ofG!tR0`mWxH4?bFZ5&p$QaX&nu!(+KO&rM+LMOYxdDvEh9A{yl# z6=I($UbXR#igm$xj6OqDMZ&Uqr3z7H1EGR10uErn`Mo}#!H~%wJ_&nhO43&dOk~dT zNtjKe5nmzRqHomrBGiV}7wU_U1_oY3Uj(+(G3HBOseP03QSN1eN^5BP0PfmH<|=Nv z^%5)p_eGv}l7r z*D<^vM``#Bc*jCY9>m-RRR}BeH414vj8o<_Rvk}6Ycbu(^XE5!4*=Nvc$fyO2 zfyUVoAc%>22Ns?*5Mev)IX8nm5kc0O;~7oMO0PM7@9Qy@9)R*>x_ia~0jr(`g(t3V zAFgB3_w=)`(WBoDL)uXg_O^KC?dJ? zqrIt+^7;>z3Mr5OP#~q~=eq8xkaGJE1yZsrBJE9ulnYZ(n$2}jg_P5OD3B6e5ovEK zq#XW3fs~+QaNXS`U;8CtS)%WD@Ud%>F{-(LDF2iJwSyPDz86Z3jYLchD0NrEgSS53 zt;r0k_nh(|9EnB8^jZ_YR^X-d#kei5k0A;wCdqq~`7AbJTKoX2r_d4X6`{38m}s0J zhag8Fx);I_DBvIsM5-DBlMUMYh-o$UhONIwuo6qcC@uK&d<*Z>{DML&0XRNv)$kUT zJ5TwRMr)5PTWp{nLJ|woTFHKF_8GS&69310>4+sgu-aQ6FW<0uV()0pkLBwL8g|?< z4Lz?hM4Vo8auA1O3=?z>$G|(V$^&zuKKn==bLV0x12Z8&9JOYcx|#=X1Wg2d*s(c4 z5j}s(O$=|kKORH$>NFI9%Z0k}+IcxcFWP_SIzb5mu+1+?wwjJutaFwXd&W8`BP|M_ zCPoam#6G(YO=+1y!5QZF_@i_RgK3P14%?=caja4ROr;mhpsUR1z>+q152Sy>uiBa( zmU(=H9Tdr*YWrwDuD9*o=rlG5=u;SoBQlXrB)465oW5sST^NYJW0L@VV^sN1JO!%> zhC{a%wEz@`C_fn#fMNHojZj0(Ps2zq^qdbQw4cXWD;_F_I{LW2qCQSWqjn*xe3W(g zmkLHV%$Cih`yb-F>jW7N(NUFGaBe!#47){DO!m>Bz|ogZp2By@Pib!R9+|)&hS!3* zZXzvs9jbh`agvxtAOHig%{Tcj2hQ?@-a(JHUK_N~3YY_0g0VBoL9Yhl1{3pKZ0rov zFW}J6V`G=vO-$2Yij93f1`%Y}2z_q~r1yA)Z38k8)!jk!>H8w$pR0ZPp5`gXq~Zo^ zcZ9~Xz?=M9lIy$eAVS*zAik;KF8q4TkrR}y}&ILtwC&|msQ^~Egu zbl&F{n$ZWJLL>CCq6U{D*mb2J&LabjwH(I#6fH1q)H7jQoYIgK7^r zc4uL{noIK2c9K2{Wb__lFXP*l&u zn9#!+2&^44dhsz7OW1$R`STi&XIZ-#`)j2FA{y8t&2x|^WzsMe^&85AK4Dc}IXgjF zQq1o|O|UkzWlb_pPo)nbG?wwSalEGr1$CF2p7?JIixYH_AY{v&u}4r;<&%(*d!i?rF$H0+s~OpY#Z4@v z3h;HF^Km%kBC;XQ@Jmj1#=d|WneQ?ZhzH&99%h4I&=8X>{19p~;AB~Y=Mcb>PJU~}r zl@c)*3SsAT9+>anq64GVd2bOL1i46-UEnT^k7JwxOFz}KnuU;x<7SIzbQt&?#SRf| zo#ZP}=vc?XbX?F_$^i^<5UiWxIj>q!ueJL=Cc8#hJ-dwIAl=cUlYy9GXpX zElF*wa-n(gRjM=CC?;k@bD%9*;{nA`JxLyv>Dg@O!VdcZ%=x;)c(HR~QG+3Q&!#Pg zz0&0@oDCFz0=@LBA@pn#px04Q?p#<59vae!y0B0NfFk9;8T!H?u^Pz~?PwEa!Rbz8 zE)p{p4*8&|^RSsY{1}EsUem_n3zm-xu*zsrM(a}nvp|mY0St-mI^P{gbj9z8FZciy zpJ93vt|Pjmw3^F6#;zokiHxHq6lqb%lPaga?` zJE8h`!J>(?Yb{+9gqmDs&{)8B3`~nl%owa+M4Cia5Pe{uP>@wnC@mc{CSEoB0J!iI zmg2WLJl~^pRTYa(7j3nt>3LuSo=V#YqvmHd%D8t!QOs?C?%mZuT40~p*mpuvgHH-t zC=0-W)k&3EH8hUzEu01dcFHb04Y4b`LzBeL{?pVa)1E_vbQS{3g~ZkutT52ra&?WZ zK$d{o(2i0lm&+LyA~V{Lc!Kh0!1&HGAH*q(6YQWfowf8O8gp4qMdtKJs|6|wroTR- zAsEfxDaX4aP5ouicWA=H=`ielDB5P>IQM35Osb&r#lQfvR7GKghLuAvKcK31I`pkz zp`yN$5g+`H_c4@b#UW$oe(p6@q9Pv-NrX);mRV*z6CDg9m}=O!tCZyH+mo6Xt@IfU zd)@ybqDcM@g^(59-iMnQjf(f-4*0`|+N(Ai>Hx7|S>r|vKrguLEuzE+jOD%wgBP>W z5Ac~<2S$3n{nuiFOc8dkD<;Hp$wyjxBI`|DtniW;^%sj4JVq#rrLo~xAjP5v1r8z% zg^NC7>48|RL69AQV)0eF|5_}$p%E9_ky_9u$LsPIx;xV1LxWH(F0)<)NhOv>R-6{# zFP4qi8zaWE7N-D6Yxxi`6w7=kr|?lMUbeUxwDSk{>z5kZr2Dys#AZ4`{(C2{VHBm>P8fz`7vIPVdPs9j06d_Cbe3=Yh%mv>Y+nPy zl&C#%P#BCj6&XU!=oTk^tfYVH;|+rGI%^_+`3Kxf5(=z7X!2+4H-5Ku2PCV&Aq?Lq91gB4^<_=%pPsjVN?H#WAIhV46QpqA~^(0?d4@VSrI?)heJM44iQEIVY8tp z@x=2NM6rEC?7%jJgkMz$y*#)%AaOb;u&9K0Rk4J^?xxi%V0lV+T~;h~6Q{LR!fv*Z zjAe}{)lXQ*C}R~30f9Ycurk^d@R+cAj#v@{5Jfg%hdFrZOt4D8zU;(eHm)_W4V_p# z?hRn=zA4B^@hiX%bn;?(zcH|ro!E68T}mmXN>=dLh}xgc`!ULbdwTSY?l zh|RT)uwB5gEg@UK7q-SIibc8nXdS_jIZsWE%$hW98s6MKAw)BaH>sD|J_R8SW4w@< zzUbzK#HibrPntT*+bU*ku#Y7tS{B=*Ls|EdD3=1359=r6Cr(UHXYNW-B`J`g=NW4O zo`tZIcYFH+U0)>9Jt<#$n#(}CUDB0bAmdp26B+Kud)3TcmG zq(AyG84 zOHzV$E;27yN`>#MZedHGr_y?K@)rJ+$0^=ye_~>Fa$$tc)B|Sra2dl2AR#P;i`>Oi zj#BC1tdnG+wFNrt8;Y$hEsU&HoOH{ZNLU&pHZ`ye5%RX^E|(p)TUEmLc5X7j(k-HB zi+(xDjDWFoz%H|w&lPbSuvTX$LnKqXl!jen!BPX zs(h4QjGU7kCiy7B(*7!Qbs>NXyDh^+mAyj4STi7j4TIG)(n?!ZVHQ9mAkQf+6uRC+ z{t$`|nkwig2#@I{AvkL-h~r63-;+zuk;pkxB09yb7VK@cFDq~)RWDq8Y)&z3o+u+s z(_!4_Uwqixk#JC=-(I?9*V@?~Gg_$uQ1DyP-zbvB_NrDV@uwn7b3&p z0re-lrow;ad>XNoOoFvvRx#&A5LzXFJh@tW7G7lpwBfBHiscoghDf9*`PFI) z%UH3^0t4jb{`5G@YG^1yNy}V5pRSIy6UfHDBdwT_;}o@C`W^^q-<-jt z>We@Jk!q!N;lIZd?Ey$e$JWs(VYBH(z_(k&jQR6rkBW*agLP%xqM}0Xi$tiudQRW_ zINlWv^$Kp2CyRFJFHU;uKQz1SBVJj!Y0sLE>JlbADoV_9r=JH=Alwm%jQ(=Yq6Cx< zgv;rh_)i=}--3pfjL|SuNewici2heG#{$Lj8lyp-WoP6+#S>sNc4r0996z$2n_ZZC zFVTUfM=T`1c!iL>ZDz;|hefoRu&uGIu1r)Jq8?!fI+tHTLEyF@du=5-2<%!f?Xm_~ zD1nwn5&+Huc8ep)f>cq6m?w|Sh0Rcz1z z3e0wuusAF}S-8^1v2d7{Z!k6r&8VV<4*ndy7vsXHC!9YWsMcB<9YgY7C!X4O0L6d% z@jD|{3SsoI3|RaW(Ar(G>)yOZcXfEsrQjV2-lIvjxe(c!fST_H7O8dokyr zQlS4sa6zr+ZQ8wNS~DTUWt!VvQ>Amh334KEQwVb&#SDY8kHo>6TiiU71r+T60Gp31 z6W`gmByEW0MF-hLIMY}voyZe16YjVz{pnEc?u6^23lsPD(71%lY~aubz6b8Efnw>f z>m0cKCN2$Z5a7%~KKloUWh<0R4J<);UP8eJh`)CC@88$T+blu@4v311Ae(E)f5#uv zAySOHNUw4Kzeu`~3mX*qfmdYdKlq+geS9W|8o9tPT0DmE>nOL)iM7Hg3uaW$aRmsm3*0@v{=PkBc~ zrQ-{P0TgG>{ekaGjJ&GaTp}&pz19f6p%@uLjoXf%fq|0#h_E0Kj$t$z*U-tw*d&Yr zWWIbj_?Tx2*3^p2I5mz1kWwxrkQR;wAwTDZ0bt`;@CNLd zBh_!Q%U983E%mH{$E#Kw-H&ir?{lqnq2e*Wg2pN}ao3kLty zN3Ytwenwl-4*H07xz1z|liO5MaFzd7dim83@I%66sT3u(DhV8d}r|l4EE7Hmz0UK8ecXD zg>nPlGW^?@52QZLOFPWkPGWZ2Y1X!&Nu4QZfQDIH2d`(j&Dt0rW^Gvtrn?o?D4Dgz zfif4L|1oQ&$@%|>DX#i?zBdOE;jJdf!~`!Qle$h}Mq zyFZ*SlXy8wAjOM&m&DA& z91|UMK^QU(VSD5-@SS1u(9{Ri`f+aoyL8>$5e>Dum^Dfq1Laz- zK28%EUdz=xF}W+2s}s!S>Ww%u_ZQ5c)IyX&O}FEb%aM#VnBU+jS~rHQ0~$(y1#T&% z{G|)Vw9PJY{*z-(myTza%hh!?C*40)%hkV|NZQ;WmaAtuuu!04xq7G*i>5@&)piO5 z876}Ns+d-hw;Apw}L+8^j%jN2g4r~-^n3k)P?Aiw%^(&XF-!+*x zQFj9`KWkann0k+=!V$0w(*L*k}P4HzaSduiD*Wi|y)`x2z!r1!;SFIv0$Mi}tuCMRgJ7t4+*z2!6U zA4FCrmirLkTMLQTQK?&tWk=K6q)%9gWk=)l69|+aDWPS@6-ERA(fVlFaf%a*K1|Dw z1Dsf-wCz@}WyhJoq6uOu%yf{VwCreZ3IO?MU@;tzHv-%W9bLjUJw(3HZw#pVdb;n-l4=I z6AN0}?CA#X6?s7WSS5$}BJwQlXZ!|J32nkDIx=;`w1;y5P5jTJADjEJL>yS}7B6`S zkNOL~i~X2y%$NZMWxKuT^vkVJ8worPtl$*~I&IYMXl?;nVDJ8hX&32ezhgJNXpY;p z$(1rPPtN9>Axeb?rhNc#aS&Ay4-;g7@}E2dj zLPlKKt>J%fg*6){`OwGIYOfGIa%1p5UeH0@wHL3<=pY}q1qSpvDz@f9gdcoAn?^yV-fLCE(& z{t2@UT6~2XmS*0{cVW*5So(u_xo4Tsu-b2(|IL}!+RD;pD*(F$T>x=<0Rn7|64!ShZd(XE~XuEbp&4xDhn}i1$M>tdz zZwWqcyx}&%+HM(@#2@H_pDM}@M~~f8wyEb&o}fE8Ms4k7)PdLJUgG&y-$W-`r<3ra zXmsR5VfLeY9qUU8(+vrRL*mq-cAxTuNaDj$Lr;a!3cSj1+Qa-sY9N&Mkv`UJqS!tu zPU@LX0j0xZej?~)t2d!ge;~{PhXI95rI1Y6WMvbl5GG@A6LN0qeqL*kIKIyz*&6s)wM(Ir868g4i3aQu~@7ZO(Bx1+?vAG%L%ehu5Y zi>mJ@$>6V`wYIk^Ku4J+p8ttN7T11=zXX1AEx+sTziVNqIaYKS`kSrqt?;b~`-bHO zfQMqv(ZmoO0*RBD&BTUbnEr=}knk+86RAH@+gT+&Gt4==*%K~fR1}(H3p{nKWRd^* z?(j?0NG8LShNZ7v@GhPtN;1Aytnyv z)W34$V8fRq7;&aRu4)(f6DBH2E2H_1*GRhOye?jpZ<4})(Mm#+pMmN8Lhf7qj#NQ* zm@%-(VXe2cF%k;+k&1ho8;wW6GQXobrAZx4{Emq-L2ZbW(xB7pnyi3xT;rD_mOwH& zg=^qeo?MruMF^{KL_o~MybqvEobx5)M#+4q$R~tjawF>zIdAZL(b5NrbR(A{P^rD3 z;EYh}+f@;vlou&9V^xs73BvbW3jf2fe4x8hAZ}Uin>@a}#ST#cX>>a;3xd!^hcsLy z1_8T+Geku>S|>4JpJ)&?sG*oeu+m6t2)*L%s8aC-mdRqh{JJfP5Fq?6Pl0}+eTt^a zW?hwShja;%BjU#2PBq2a3{Nhkk>Z5Hn<3;4IOkC2Gpt!Eh#JX3Tw!-Dt0pT3UL6QW zt_$be1c1L!4Kn&R}{BF(C;;F`bZ7!1UDg>=2 zO;ewf#ZzC_IJy_ZlVKXrQ=Ls0tsJ%(l!2iLDFDojJ7M%xL!uF$zRTMgPyLxZrW=K` z=ke5zCXQg(pK$acWS2wBbl8EKT#xYHW{fx=aEE3x??=o9L7RZWzN59NjTQSh4NYZH zGQxf-W%+EN5AtREYzS4>#r9cHC5Q23q1in1%_bY24zgNLQQ24=4;d3v(e$HrLOeTN zSR|E{!}aumN=sX;Ew>c>+N_oj2>8~r3G@@+!9XUH_K16}B%ToCz(k@U2-DcYdN$$B z16!XG{w>TF*_wbbH8A#Y%#^S!7saLuA}Z(k8pgTS4H5^F@S0OnR>O-j4Rr`{k2r6g zW~(FGfbQVbX@k%MtTB^di@^wihO6gP6)%8&w zK2S22;0}vo=Lj$d6sQ;_ictXH{Uu?WVu+#y$yj@02{!iIGC138Pf`QyZDaqh!SC!~ zNP(6ghpe$w=o2i3%6KszIv}C+N0lvFHzBIFT|789ON0@-4@w}MUxKY?(xkXnj9f+VM4Cdp$>>NIVd ztqAR~5$=$E;93*?Dql|iG+a`}0DgslyBQ|@3_UPeX&4@})o3B`wqZw&Q0JUgHBZV$ zRd1v?N1NxdHAL$t17VjnFoGxaff#2;BquAeG<4#`0(8(gMoBN|cek@7^Mv&DE;mk0 zS*+h2e^CqqJlj#k;g{)~&2ZT+i@6I{6qWI-Iw(2!&rtAUSo8`+4Bu10ld=1jDu2GEr=<5Xhj@|W?l+7riJpEVya{9{d=R1Ue$pTCB#sZS78_bTFZN=Ah# zu$Esu=I^A?%UP%Am~Lt#kT9o$*Zq`^1^0q6BHS}%l_N6pp8L*TZxkH$XTDg&hr zbucTd@I>J0@5Ui9Z6f@KgM-#!tI?~MEGiPz6_Z~`PVk1G)3dOlw-sqS(o^9U)HT{w zTKW$t+JldG6ihUSQM1}Q->?p9b(s;YIZQe^oD|LN4l6S* z;J-Hh^d%Z~s8c{|jey4MApzj-ZV)0hY>VBl1|S_Fo8dn(p>yNbgO{Bn#9OGIema39 zr4GAh{5>#yt7-fR>7PR?!ah!lwz`EoffY+*gw*1Vu<2EU}$eLf7?6U8HMgprV)0o*D^lhov@vn-s#)S2<~_^x9=LrWkMo0b z-&l=7A)$gO6f=W96af#?+_yZje+t>}OKoLSKi?&)I1wypuFSj+0&++ z;7z)M@mCXf|CKjcsmzp~+{;>$3m`QOYy5S)R)G?Mk?U(F5Fu!kJt5 zkgB!8N83;SIJzk7H%=-n!(wA)t1lcID?janJTpeza1~!IuDOmYBSc$$D#0l3uSzJe zwx0w^;fwrp5xHMaP|*465hUkPzFU-wB~!}<33@;;5dl}ji(^We$m0cvssle3fq_Un zP(;91L>Dfb#!m@m9(i0bn%0=92ohSv_@;=h){H6~2h3eZp!$BT+v{L!Q~hcnU&}9v z26;n<-gK>jwvWBev&zZBKjmj~QLJc^x(S2!_)&oyt!_daGRf!9eNr=rVrrW&)^^fp z7OC`8?n~J!^j$o{o}h>_UYkg-hI&Ijt?NJfpN@!{Gv_7OJBQ>QSA}@VI|H%ty$C-n zm^xStK_2qXi)PDAnM#ZqgW{)Dye;p5XujAr|D)wepr1fU4D+N>w&fiVm7#11kt6*) zyAmR9d52cKXd>Zg+?~i>@{W^epmMcy$~$81j9tE_ zb5eS7$UA~)&9Y_7mVUD~9&*0+(s0N-g2=AUpWD#8AwZ0={MHRe-!>6R~RP{5vsn1jsuE5&3&Rf}#TDohSC~E1{l**_=D zj;;^qHJH3p9WzlKUao03U;cV^Z0DuJBr2@Nb4!k{nbb^{8!<+SGPCj$;A^;OKi2Bu zx!HU-hSGjKNlt4T9)&Ajz9co!GuF)Sui1va5J_NLU>a(^S@9f#z!nux31*-2FxQ`!DSuO$?t;JRZs+#{&iyFPO>)l#M>1E>tpM<_a9a*oJttd@fQP>q zTnu7}UOflkGFG(bxH(@KtLFsJek2+DF9han(4eyWF;zNm?R!SbgXzR!S3+;;R#Vam zg%Qt^T=5+-X+8K5#H-Ua2mBigHbL8Y%k}4jN2Cza!fv%x)VH1#`RMPJxmNVZx|bi8;$7^) zgHXWVuQ1o|gjC$%cN)4@N~>1uj~ER^7UUnS6-J_s8yT7 zI?lr4M7xfEK^9aDQ@4`~K0bl9Cf5_qdY%rw8GPZ=_)mDJyR3b!+KTlsTd`xU3afC6 zPh_U;G17zkqpNDA6lgF9t=-six5Zi>I7k%JN^0O+(iHfDZ9$9US9~~g>VgoXG18wS zMODcZ{wdAHS=7foJqFh&{d|45lGk^I;#}HDIzot}kaQ1`A(VOSyqE9g2~E_6-5Dx{mx*d^NG2@JYH3lU^yLTZpH6%yCkw zPTQ$P00Ve-O(MjH-%2?n4k`5~o~{+aZU6tI(wcPwBZQ+p%b5JfC*kHC;?Jgw zqT{GZj9F~ZczB*XqG@OX$cQs_oUXr@Min^dp-6V5!OzDUqS5}oQdqSPt?u~|F;*!>(2cc-0VJ&U(rs(NEZGMeFqSn1D z1p==Xgih&wM{oe|65G>95dGR44>gv(Rwj_7WETH5foBMFLm*bDOb5T_Y%L~P*kPVl zxHh~Uf;=I5?0iN$aH-q50z=j#I;u*9~pA|~u=|atGphR?}TEqLXZ6q{F zus=kW7!zP^+3)d$&GicBFc{#_?A-yyc9gK^0=7m2yhys-ssPdQP{i20LX`uiKVC&) zRI_dS8n%aXiwpFmS(P)O8?Uw?xh@8rE&0B^>I-CVX}^A*r63N%G1M0I;cH^c3?Lfh zTH^?{uoz%;{++HfjfXg`F%4-?WHS_n)=bRsB@n!J`mK(z+1S&I<&$2O)Hsb`pBg;C zfEv*u`i?(?VVR5fDE^~;3}IbZn;k<5<-5Ueoel|KfY)?U_7!aK1Ch#|gq0;WT*tb> zuTroA*z7iIpmB{lr-pYtNq+-wMW@i>7pNP-TRn9$khXYZv4nb#mB$eQznm);HG|44 z^oD(z*2;Jr)Z}{TK>-AKXnbEMdJfR}|5q}97EG5-Yp3xLeH>uWvSY~FNXr3mu1^0?Q zf}J>|BDZP*XdFM_m>5XX$|D|8QkieS2svpDDC1uRg!praKcfwW_;ZLqqZwRt`8lRV zYa#l^og3=GsiNM4ipjtE#r_}qvG6!ByeB@2`14}nm3i{OdiT7rJei+)G%zz3gHDnY z|A_0ou>T#f5dRJFU$n#!{|)h9G=po*e}~1z-9>Ef_P97N{>h+^nM?R-FuBpy9sX7P zrz=(rr!ohwSh3Vy_Wwva#Gga_8BI0BpF{i^&EOjIXOvjz^;1_O`b^j?qt15nDO3=_HeEZ7yP+DEnV{pzJ$&2n((bo52F8IPw+46 z)LdZhRO2khH!&LxXNEBUJ25&{x&Ode9se7yA^siW-)L4L{vG1qXa?7we=C+XTDYkO z{$$_(n_p>9$Gny|Z7 z91lO(x{WwH4Th|S5|jtFzpIC<4wCia=ODrT@bFLv0{!~ z@MNgsCe?cy2y{ufGd!$G;ZT)^&oj{x;I*y8Je=NaIz8=hZDXYA=z24J77QOXv9;r5 zlfZ~mU;4;MGxl`A0jU-meTnzSz8iLUDae*{aJoca@(A880q9F!;U??OMuhs(r*F9e zJYD)2G*)ymmf#0C@xV16sYNr<1WVshh~20YxGa8ZhK5sKt*oIl`#Q(wBn1(V4|=;3`s!_X4A@nnu+!-k>$&?vvvb=-7+0_Uk`h>ZApcW_Pm>3rNhuf2L{3A!|~Ifs+nO4Y@K-fpE_5p=m3E|8VP zhe!$ZMQq)_KT4~R;TRNT9vpnZpF?yy+EfFp7#ZoS8qsx^a5`5}2eRNEeOSaD=s*W+ z8OS2r;LE3q8j2E9Mry~t@O$>6KUfY={i%ngee}fL^=`ZWg?Pm6euVugMb83IhTRT^ z;=7%WF_d9v7o$(f$H?3G(WBeuJk_~+0EX~6lY`8*f$QjheOy~9GsvQh|5tuNHEa)N z%L?nEx4JR1Ska4)<>U%HxCL?4@>$vo!J>w1!ZCjNtC6ps;ai;5E=YVgJ^jh*we#+E zHJ*O(#DKQI9csf_(98JODuZ8%aT6omJ4knZ%HhvxXMB^N)!)|!!dZWjTHmI>Ud?6G;3nKja}GH0S3l1=6x+y{mgb{~##D3IZ$Yn)S30D{xlsHLKXbj&wEl zc+FTr3HZ<7<$NWie9JMmr3LiCN3c0*I^XKD7*xE1tsEg4kfdmb@E`duEEE{eGwa(x z(oCEwi?nYc-(!eUbuv;L3aZ>&jWg}pT_d!PuGENO2Dw?_RpTL65Li9eti^^{fwOY2 zS;hVbSV1|kfeQ3GL*wF%333at0ipfF9QOnJZT}p&_KFoN1P}OR#fp)3A^+xBh!q4@ z_%&;>Ay(k5+-p{`|7KS3a9rF-q28~XtnD0aGkLPyq7G{JujOk#YaQ?UHdhOb!@ts7 zghlu2PQ19kD@ywBsjS^@M_Y5WlFYvCmel z7)IBBJviE$qp5`w20x*S{%@`jdcM5PZWqJDEvMafxPceYz7EfLXzF>f%_|YB(8aQ^ z@E=@8h5h{1TUw8pf1F==*JV*HGD-POT<^-FOZ~gA55htqTuGcanlyiYE!emCVkekV zyD<47l!wXCLLGO#rjaXfn+BC@!4;nEP>R_1nm8N|7A~Q0w|tC=5pcF}bzqHR4YT=W z(yQ3PLXq`O$!!X2qw=5B8$t!3XcKAcEG)v>xfuIKZ~QK^nWz}NoYdtAoQYz?aZrx^ zat;)|oIN>opy=gN%E>!99|N%I&_M@5(aUvLIA?)khwRhJLB@@umzycG1)%V9ez|=` z0E%92mk@jdQS@@pP?3Qsdbv~*)I3o1aw~(N=;eBP=b|rnwvcCm;>*nrf})qZ&FeAn z2*a^22Ur<(hlxmy%3`H*&Bp0KXlX?evBWqe>-q(oRvlRnqM(s(A2{q#O z+{OT!(PynGj|ny6)=bENnNfR!WI~O2@OhI#6f9b(T8n$z*DLAGTI;_AuQd@8=61^E zE~46Z3Mnrq?sE|M#=|`hM_8=+VB*XrvY2&-Yh5@k1NDE_PTjcb%aBF*L7NkOh~!Dr z+3@-mfE+2M?m?bhJBv7Ph>d1+mo5SSgHv+yY18;V1;K+NJqNL-Hb%vA#bXB@dd))c zA^0)?%~%g)>jU@@T&sEDeQ42}0RNc|+VTp+kg+1m4SyIHKUTzLFhJf<$NzYo&n!p| z68}V>a%@p&+zE4upV{m1eKcTZbT<6^*a!BWK_-skV`$OX*TFsL?#He3tXGE@yE7x* z68KX1QlER^2-F4mLZ1Yy9YH(Cqkv*twaYafdi#_?q#$P%?_+Q7G&c*3aAdQ_9DSigO@#gK9<0l zOLPIMMt#baT@Ge~{2iH`h3Iq}BVx@nI6t0W0`tKKiofp=G5TIc>1}nMa)&_h+dY=o zL~T4e&oa7jDfr^xJG?RAj@r$7kJ(O%w7Yd~y5@{SWtrit8%#9fWv9?hWJvl1w*SCT zV>X=jesiF4Op%1meI_A)jYM^~}>P&68 zjybfb8faggdQ}^)V}DZ9sAOieU6&$z& z`>;dj4){sH;rf@w(=0=Ppg&nz7Je@<)|yz*pRm?gbQ*d1xy54hWufV{WEYIfQK&R)hOBl8}kbQOg? z@I)%l?Bd2u!ww$hTBY#Jt`3av4H!f)$!U?ov$`1=-&@$FK-e9dU*TD{-N^Sg=X;e! zv*~4?b+5`3_AZvKTPxPE9zUyxz=X|($+DQA7-*b zHa*2~0#kM`++dS(L9nq6FJ|1se8W7fQa5$5sVGJxVuzc`8coowRNLfxc5WAC9cq?t zIas)CzK8Dhp~M;&Gh54h7)IYW7ws04zqN%~nd5qM3zyZm%D79Q*Pz zew(GIHjc)tY#;&;<8O_N*_|1iiJWNf9@gK|$HjSW4M5NzM>gV8k4myafn93Dk9}g1 z{%{b;iLs){v6j!L55XAr!q_a%QgIl7!xr$>s)EqS6Ip--_*K43x2RFD68hXG;Gz7u zAO4T0{An@^)qsQ?_7M7X)wL>%Z*$q&P=F z8-p44dbpCF+0K=p4w0AEVAcpMG4OC5!yL@Wn_{+X0#-4mJ-DFgjC0{XYzNaIj6=zm z9zYpK?he-k4vTQu=X_(XB0qqFpM9%On_2-T;WzjJG|8M}lZnI*mQA=?##zZ`uA54x zX&D?w;dTx5omsWV#=jfPDqM7o;X7^R5Ro|4V>u^Cr{3XSdnFJy;v0)MXkvZMy_uhL z^fQfMtk^;RzMXQ!Dx3|vN!E?Mn>$GVbfVGx`OgJrDgp;ZEU6aU$B8Y2dJbVibwKT) z8;%`xwhl_g0Mi(qIuO$wVpu_71N~HcVhn- znRfq&jf{(X*bNlv!PxPst{0|EGS9r-3qd1uA5R3nud4;#H!<{kwS;jueoqgxuY|Jn_jN!rWj8&Nyj%vFU(sk&J{V zYxq*09&15Vq((Y_3CHH{=G)*YX@;mB{8JKP%bj!YBr}0;meTnx=~*|KS#k^;QCy{4 zk8pS=npD3Z5AmuHuL|+1{~5WeV_e*D>eS`IuT15YQ12uVrWN>A8;V$A4t)D5@n7p^3=gfNJADR(0?w3cvXm3g?QEf46m{nh4;RB5*=jsJc)#YN~^!E!gK`69gm&# zBsR!?dJ^fqtDeLK*;`K{|D_%FWD)wm1@u-A=!AJ4IDh`rIex_^uTJJJNUCS>top1G z^aU%;EFvDZf%D0TO#}Du?Z#pcvV$Z==8ng*7MEJDr$jI0xMf{`l3R*z$eJyh8>H5MT4AEPesY z%9QXO`3tQOGs6QY_;Cq%I#A2G0vZOPy04h(Ug!(u5A+>hQdX#JR1rqWaJ}aDFb0#$ zhCs=ms`_O9VhKF`Mk9-kR!xJU0=67)g~Vv6_hAcjiT^5Z-^Qn2yb77D=HkjT%s>2pk53Q~3&G{j^Qi$9vcesFr)lEY1UlD|i70lqN zR*PnAzlR+JJ-MlsOGU+d(u*(&$TDu&BN}YLF#b#>7;SB0n=(33Tf84zQt>O=4AVM|AL6_p%LO)? z`fBx@EbmQkU>B?5oDX8G8g*gr7ccllzQ^RoRz;@cJ{0ymz*s*rAW^uX=Zl}te)={M zcm4HGOiZwtpTw0wYZ&Yz`&`O`CiE_@{Uj_XgtS%4HNt|u$#>?r5;9Wz+}@Hd&>u{O z+HR=r%BE7{NMhp27-zFtN)3NCX}zs50DA>{7>^EV%kvhBpm@HX3}+?w@Q#Y6Q7W}&esPbV?@$9w&eQzTIt+FQ$F$eny?i+uV9|CH=Z`3; zOV3wA3-228uUs0y@dWid$wdIJ0Iqz-j7y1x8}PIqr~xQP1BlYKpE#|1;UsK|#-AN;lJpZqwJU{_r_HpCl4{vcK;^O0(Y3t%>l6b3ah zjPPuGmVJ{{2)Z-~Bm{k^pBC38{Bi*!DWhNDfhrl$CSHeWLgDzULBsNJ{*##&aS(mw z0G=~^Jo8s++P-6_d%7)$5v7M2ppwcda^3vOUaGlZp#q4?EeeKJ@Mbt~?=0fK%^lRc zOZ)a6JFmcIsrJ#UGFF@wg9hZ3t!{kZ*4G-(52wxDrR?-Vuk$^_z!$YBN~9~jj!CS5 z<^aB^11Ue!^6M0?g+5<6hv5sJG+<5Wg-oN%VA^~Q>XB5f*8?#$wT_31+QWGbv8n5w zR#A*iv)YL16u z@Fg6_iM?B&yCFO>_F-6>l(Jc>SkNF5(!?|0la8p=8fK1Ak7DUuE=;Q|L9q+a11Kz1 z00NT|X6BIFWs?we6&{-L$@A_rwragFf8EO0AFU@#692adWgL~a*qXDxNOwp+ARaAC z3`F86XTFFs7VZkoQnq;K+d(!%v4gNTp~|P7CpKy=I~5!>hC7~<9X@C=HB7_?~2eT<}xE;F@b8jH3&UdOHL zNT(4&!n?}tBP}8kiABAXH$dUzCr->uuPNkOg=hdJGoy_UlMGGlSRv9lJBJ$))=KHZnKVt!`Q@)^k*N@nJ$X z$44~mhb>b1v3G`loWZA>W#;ZM`K#}jzpia7;y#79Cnhen?`XxUfLOsKAu2(526>Pf`;o5M%h&4rr zk8p(RXlK!f)ayAer`beDS|$8ZP_^xv6A%ibka^Za*byv>*kq@ySd4Nmvj8#@p6cF+ zwBEvnu!+CrE*x$90gR}bJWF*sk-tPLPoxnB*tPbTivEf7X@swaE_$e@pv1~yu%6!} zk9!dBc4bndye#^rXTfZ(a}poM(-4Z-Fh6Ct{3^=?1i%xI8v`0+B_Esm=|?a1YiaOU zbvGO>aWXM+hLy4+Uvj=Ckh}}(I8fLraEc!{#&liAEPhd`EH#9#P5kN2%(RS0Y)Ftc z)u_^c9ky%~19d-;Qz0 zLwE{FOk!URyi9%!Df~SdjPUNP9E(G@q|M=>n zm;MY4xSxJ|F?&i@3WsvZd~2&T{=Jxdg?-PDm!xw8g`#vgzg!!6UgW7{DoD%jNCo&l z<69!2H612Pi{8THepl46s#xT)T4N}sJLq4niRp=nhbV6|eBKsw%;itP6E)hlZAp2G zVB9Q1k-rigU)1qILkTEE%F5p0#Cn7Qr(gRiHeV6DuMAO+!DPNRtN+kxOt(tQZy%#jp=XJd}k1ZwC0oWI+l2n)O6aVWPl>azw=Zlq=n zP|r~YZ@HAg(xL}Kg2!g^jDl4G+9U2JNuh;$unJ(NzP>B&Nw9*dG`iG)@(8d*14NdT z?STDk!g4~r1=z9>EU*qlo&4jpre%k}yL{8)={+4f+1S-uYkK8PTb(*eXvQxb5H0!m zt*VVYi>CJ5qY$%vl_x{3dReO4+5`G?VMTHq6mtnwj&CbWKz2852uId9fZ?fn(Y_61 z9g!};e6XraRwamw56ahZ>}FUEV@xo6jCOSC8*q$M9z1U034tqU4#MC6bIvud&_%7} zyw^_7sn?p}ZJ18C=|vJYVm6)}{{D~K5D{Aiui+Otf7Jy(3>`gmA*2d6LLo4%0`=e` zY#EINawK*T6o)3gWzez+Sb>L&Bd4yI28iCU3Ppo%9r%Kf_e7p{P<{%zr3sXs2g|5( zIzf|tjEETn|KVq!zcB|Z&}3dF>~S|Lk_W(!w9hi%Wosr&eLh>DNP>zr<^@Q3Obr0_njHY_ zF+l*-YmNZ$HJv7)JXZ*H5>+9gkpvZSZAOxRoM|D{NkX0E?-@z1D_-25ewwTqHirdf z+KOL8M46ZvY0a<-|BpqAjP?!#q5Sa-dx9bgJmekj`H#Jv>&EpPHG(qGBV5Bz>s=J_ zvCZGi>LE38Lu$xpu$3!m!!T_g0979arCotjGQ!%JuGt5KgOjCRDca#ROy-l)Pn9ET zhkm6U^eA$t7MFsh1K`3N)2U%8c^K-QOXvtr6-&Wic%MC-Kf|0lmR#$hco+&j19K=@ zBEBM@wjxln6sJQErqEL%_~!8U$U*K`&TnCcnq?yYDuVFv+`69@|F@$AV^8vR(hF-Q zhsOpqKGF!@%fD0gQ&O~0Il{T5ZDzbya*(ElT#4!R8eTbLd6JQ;1$9bJ;#Cupw2qhw zT??y&`iL!kG_AR~H~mRv3vCHA_t$K@$trD&*guVHwJgZBx`lQzkGH+lEPYGZSGdCg zt^7l335SE z&tMI3)KUxq%eeH6aN^v@Kz`K7O7`w>*xeX{pasWS(F4GEL9}N(|d(hlvKLtDr zg#0j;W5a*-W2Lt(xSGRh{S>f|19{@18aZ;^HgZ2dTOv#Nx6qC+2wBvk;f#qRKZFzQ zBPRuzXMa(gvD13TmxxZ|<}8{%#KT+C+Y$3i4>wFNCrnQlOfLt_CLZpWf7SUi)Vx(o z!X+oQr9afQ|35ZwFJ&N%1_2I~Uhb2g&XZoQlU|OKo^F%B>&YNLYp8jLn)mN>Z%+-y zEHBr`KMwr2I6a1%cc^*)e)G2K$YZl6!g+1jL~u-N90qQJAz-qm4!DwO_3yQL6QMjd za3b(u-^7V>vwX#iI~EZV4BC?j%z*smDPf0L*pj1io)1{~_qtg1gw5~HIGpaI6S*G~ z^75F?Iy@1zfqV()-`a&Uwn44-#FW=x!A9V&=Y%ObES~e1Z8+|#Ds_~mAY?8~(JM=; zqG@{lDAM;sc$8qV^k}t?CX@-Br&90nd$z z`hAoecU?mq^a%=v{}bl0j5au#tM zzC^fdz#`B%9Cd)Z_H>e?&623j6P$M?qE89#c5nckJlN@30|GPw>jQuQ>@vNZYywpF z1#7BdgV`L;Uo(NB0zSEwak*Ky;TCkcuK zBdw!(8#J&~4jM*RuZ>vQ~V9Wncfx-!%J(J9MCD$5RJ} z?pMVWnm>P>dTr|W|DGtddb(Rw*Odcg^ujrQ9Hx+{{*bJfcZy);#-G8Ph{yRpd--E3 z+9SsF;{W$OFV)K5bvG(ogo3ecdbGbeuTBQPmKnZ9e&x)KL(sKv!D$Z8FjVKw^%87i zRyg?pEh2J-MT)l8K|&;~o-^^IO<)?FzabQU6tjY&twH#$z0};J>I$UJ!GXV#Bgjcg zMIiVjgUQ`ZpH)sU^h2tvZ!Hi`)^=|&T1;x>Rt!cNa69%YH)jIejw1{@ijwh7OmduX zsvWEDEL6NFEuJ>Twz_HJPrPVLqS)D*!oE)NqU{V?53xPYix$(_Q+9DyY`7Qg8oA+- zMWiCbyl8*p{1Z1J(w?-a-AUfGd%8Pm3v=4gI9-HV0 zVPck}*`1li^WEU)KF1_daZg&TCiw1;(#}SU{G+tshnXIp8lKNk6BY4PV8PFNed90~ z_YWKWQe~U(Ma#yZ;5!2f-t9?SDl70T6qXY+c#r-@Cyo2Xz-1IZ8aMNz#WGTU$>}{& zj}!x5w5%%-#~T@?R@e)OH!TeRSori*0Y#mEQabVmqh-VWpuY0X!)@wze_;_Z!r4$m zrMX69tvI<2J`8rq81Ewv;|eqYiV!vAXN^kz_y*>|t4;Git1$4zIg4k%&>>pq4{{~X zkB#%j)VI)iAA4urs(E8$EdV06Bgm3E0vEQ zZNZ>ALeZhU@lAI@9~RzrHL3=5Se=p?2eWFC*3(dX{RCZmP<(hS`E?^D|Xtd zGVV&^nI#b?Cz9nk6p%%I4G)ZUJlp=TEwN`euuxN;HiX=KSd!;-qWY1a%PCw;p4Vm3 z^?f{p->iqbX>YNc@w9YrE08*AkCj5CICb{EczzSee9)*lAU!&l^G_WBN5^uKITG*9$6X%b7!_%8xFyTV)PHx6M$?*NM^!zVGlx$@bG*2v&N;h!OJ9Y}nOfdFyp;SG#zai>Tg0)IWvO zQ_cBst;G^5|F^{GTwREt^Ic!QHu;0^FeT-DX-}@d`8}ehk)Uk zpLY!yjPg#WN=3K%q(h{UfuhBpJt0v1>}zhVdE~vTXpF%kwy zQ>wrqd=2jJ5{O~Gp~#hLk7Wi)Q}lTUf46X8-d@r;Hs}PRAN&%WJq7t_5ExqtSc|pj z!hVBrmIF;b~n{&hydZ@MC)tie*@JcL-xuZ z#wg2J{@Wg#weZa`{W_F39~lAaLY>jv4@_OK zVa-RAJ6oNl#G9A&d!HO9p(PFwByryvQ6uxHj~3YnMl#By}{7RV`xje-2Ac{c5% zdKs?=(QdeP$MCbFeIz)J2%2!<0EPp6!*&*(ip;>=EuRb63HLfbGPe_off{Xm<%rrQ z_ZXoBxs$Ux+T?kLY*t@2ZGqx(R8--vuWuC{k2VJ|LV-TZsAzCAN4N`(eZOvJ8iO4o z1Nuy4B93Po{QB!O09s))PC5Jt_GJrzHjTbecL(s;;IfS_Xw+Dmga45t@qB};X*&g>_fr*D!KpE(MxYr#a#u1+n9pM=5<# z%I$&VREk&a{<%_0L8^fa8W7L~kGjP$5J5iC+W?wbs1#^10>V{FX&pe!f|aran>u+s zOCLOo2N$AJye#fiO5VVmmPIK^E{!IVOM|uZU~rWDLgF{7llM#9D5d=9{Yu5uA~REn zJRobBB`gC~68Tu`abDtCx3eM#`A;^Nh}yv~)n3O_Z4r*Kn(3tL8*F8x$kTX%?_6vF zb2aB&!I1;553Z1_2nunAhde;JCz*kiad$ZjMsNDu0imahclNJavv`JcW?BT3vtf>G zJ~W)Ko$oXf9aT-=6lr5@WbTl$S>a>u8K>`S@Jwe_V2*j3rZ9GBl*zMO+DXI;9pU^1 z2gLU!bY@QJACt86r5r>JGPvK#!3rL>ydpIvRA)b8CTN7gm}bQoX^a=?n52JThNd2$ z!vo|fg%x;unr;R0_Lc1()A`yOIJFewt@)|@rKZFIvXf~A91;t%53j=`fWnl-&^91 z|0sO;SR*Z?wK2uB8G}Y+T=+@H?dx>q*=R#3hRPk_gdi1;d8V@`63LDD=(z%DdqQm( z0Hm{`1LlQ{t>*FsFb6&9ikdngl(+%kAh6loBbK?jiC=ObHY5lz+`Z(cWIlY!ZUImz z4*kxiOe9ayX%6lXvCpg6u_(Z)y$k>F{k3?7_nrB1BZQywIHBka{NnQgLr~u8F1@JE z)dM?fF41kQR3a5QNaB1ed1}jTJf)II4x-bbOP%5yi9JnvvCzvHF?(Nfcc%K_24v9M8Uk z7240YiX4$!c~adqJWVN9s;AKiHB>$)V zas1NvZ$CZb`wM($7_DlSA-*&b+&F&zsxM~1V}=z+aBn>!3zm1p>Gudm|U zQB&P_W}SE~H{qEa%n_;c_Jy5&#d{Z=<3HL}AX$-Ze5L-ZbNC5Oj26FG65#(Jzf@Ky z=0LU@Sw5o3E#p67#SY2$qa)i{sp*%II0WV5K(2m)jX?{ShFqoHX7VRVrH{|zHEgnWQT`_@>}uZGk1>% z@V?zk-OnD?_N^7WPw!efy(P6%SI9pZ(yR)n$Eap%(cBLeBG3AD*$1oQiKXvrVqqvU z9-za+|R#>{=lM^?2rTFyrqtSBu z-9^d3O_J*q`IkEVSb)2WZyCQ_Mx(=jz>9;vP}^iIc#a1vZ%9Ga90>m|B?PUBkNKyQ%fLMEE!zx(-l z->h065Y|O>LSys{C)ur-vBmF&PWs$V72;ucKy)69Y)>NznBsHlS?LU?RXUFATNp8P z(uG=JoVDgceQRg~TquZfb%GR#Mrl>4GgnkLPqq556IH=9&pAAMGJ zV#wlPj@$Gz<;&v9f{#i-Rb!upJIrdrTn-FfKQF$%gWF?VDK85MJEgj@zQM;zf@~Hf zc(%=}0Nws5Ivu3=px~?A;+mlJbN$gP>Z`>3`OR>7Qhuy0JRReAB{?~P#7ylH()9h( zVf#i#lZK=)7Is2(%w~A#i8!adX3d(yGF2D~$fqFN0E~eE*|T8v{RWeGlyXjV&~ljk zDdJbqFM=IU&s!L8K_rO_)FbLz19;AIzWsDvL~2o=TNLKTS9TKS)%)kZeFw zUz(VIy^hVK8M!EaK}hza(0^dS??S1lG+JSpC!0gyM5qVF* z=->-KMx_P(j2sMi3s<9xHB~>0tyw}){c`NsCW>5#Pc)C=o63VG+avN2`Gmk30O2|G z-GbC$4p55rFoIlz4>(RF6FBcGK4fJ|-T-TOF4}M%f;7UtVpfI^E2XiiLK8ca`=v5u zJwFTXu`YSJpbbBh{Hln^zXJ2;KW`*uw7AKaH1a)WKJ|3=TDlEr@EXfozpO-AI%r2Wr?xb;3_-I%YrV5zW{sB34#bw05c0a9ECK*+GN;( z^p^C!SZxg7GHkCQ0FY_MZ3SKWPou4`3PjEZbv64h9TQ{CC@Bke&UB|spMteQ6(=r` z%FdbTM7W0jJ85ulU$@uR9bG=5sqq+L8xlV;l18);1S%1x*p<+qXF@Rb2s!p+JA+~E z#zBBxsL=(^dM-T%dNAi7lGIb+C)$KjhF5q3O-Tbo&a?cae1dY>+H<^0hS0tR60=(N zly-@p&n)G;jVX|ssk3c&9?f|Sq3+A zw-wYuDH8dc4te$An=of#<9J%RKztBL*%X%}dk{Ja{)C@0bv{?6C3(Kj)hP^Y*f#zX zSY?5pQ&%mY(2ZV0h8qXH`{TzWb=%iaXeSyoc2m5lA-+S1>%cv!c-9O%KcMJd^94W4 z{A$Rkl@RKMGMv2)v+XQgfH(XETdmmeaA>++R`N4$m+avCEcG43pw2 z0#zqlE5q-!HedLH`$_xtk@&!f6uHcQmAz^mkJq1dqqHf|>YxQwQiV)@n%Hfjty=$t z?j$X2!TItA!@NdU4&%jf8@ zY*{T$i)&QVA@9$A^k%!~7wh!gr;~f!V3FjEjg@^Sj$h12&|=Bb?8T<@D`I|KF;gwa z{gh{jrh%FGJ0kyDo-H03v)GRb5DsCZCPfM*^DB~%jTKsOfbyK?XT)rp=Fi|T2rxRv zONI{q-AjPjM!t($icmV-DM4S-$EQ$f(xk$bW956#;=9B+y1rf9FZ$X-X_>B+&392(gHoV9E~PVMwZA46{KZn_s;HNE zCcSh1i&6pkG*2#uBpW`dD_uOp(}~AKMY@pSZJuU{&-i{VpO`to&hIeODju<$f9(Ng zPw;fr!W~$s-6uEzD)BBq;l(-|`U7`tLXNP_)@A~Z!us-TOF3*Hz~W{aNh>;yUnpWF z>OEHFKI*;G`V0JuL&j6Z-H^tgb(c)(#r%-&*Cx8HWA|DM z13_Yil`tYBcxF{2siP&5z3n^m_-QXO0E)OiI;(LF-^Mq|PGbNO9jF+o6UquFczOmx zt#?WD6f;NdY}CiMouW5x%B4@|ITfZ$3Be!fhgGFOojLt!g3 zp`AacN~;Lgm4M_=Qo z-dH%Je|^co`fFcjc^!k?k5SZ^%iKfhCYTABVGRgBB*0{GKk>Jn(hpQ^L17T|>>@&} z|3mIS!OvQZ0fO2w5Xy|G-A80h5N1Q$ZGAY5vJe%55SH^>Yp`+XN;KM)knGwu6}^t#Tfq`U7OpbBq;qKI-?he3Yi;c9=;F0?$R-8#`d)_W;#ULmR}{^>D#1&gK}K z$P)HNVHF(h^bW^tpH4UFgqkr*fO_jJYB>^vh&{b1d|Ww#4T9t%M-NQbmSUosgR(}$ zk6>LvQAj?#QVN(3g%+5J?tiLr{u;wkU6>c%H~J zl6BQW?Grb41bp`80stn`*MUI-k4f4bVbxwQBKF_)S$fA>jDUudjG!2)ZTpOU9UyJ( zwOxho#&@>aAF^Uh+otakiRRQ+C+PZ)QlJPJ-gtq5%$>|rWz!=d>MFgEjeP(LX*_!Jh!=lMAzGDB`dl<1vZ(Hnhc_N$=Q#@)-u|D9)7~om#M;8`!30R=CX1Je@@Nlay4BAgN!op_{rqgARnRb>y7^*pyK zjyfk;3Z$0@jVwC)3c1(kOytRVG{m^Z!iP3jH*|XG9OwE6H|Q}!bS>|{QCCH_>Uq`R zQ$vAw(VR#89{%LwJ{QBUC>QPvlVh`2XEL zn$Mcm#o(9N%V*ZCM%zXX9R|6n0Yk~1j8`0h4Yg_b??UBfPqWysN=>!rx38ikEFrqndOw> zRoryUcMs3L-2~|PXF*pB=IQ`vu8pQLm6?1XXS$vsz>?j3-bG_}bBm=Zju{(|hS|?9bEIxe^}%p4b6jPk z7VE|oeq`aDk$ZWz)NT>MIjb?zgeA^0stb2^lNVGnoPqne8q?3#ngZw_oyM=BmXa0r z{;_mNE0pr{Uu2??-`$wjYCnTJ0vgi*xg{uRI7}r5l~g2C)xny;#$+sn9ZLl!~Ny-L&7+DuKFT=(NY0M#Y1!Qy>&Wk z_?uXq%%Ya@EA3U5q5ODWTC)0~(3#ZuiJu}BT&~4DYrLq4$1_Fm>z&5Wd@}0g4Vipb zjK~@GGNiEghP|;}Zwyg=D>WIO@VGU!w~>&8=m#Q%*XsA`kmjc1$=7Viw8w6CvB&Vc zUi^4MU6lu%MhwFHb-GeAv|k^s)4J#|NNLaF zup14xMgl+!^`=FP2#S|BUIo0 z%=~!X56yHr*YjgsT4Lh!x%T9ZH2Ail%XG2LByQEbz@Kp*-^=2izOG>7m(BY@b)D@< zujgEUDgj@`xl*`GvK5@?H#2<0d0{iX*u|AT=UnmvMf8bFDGqvrdoZ?=b11Xzuz_dU z3B-=^<7PUK>tN%iuKk?fa5k?}m-*>%mA_dOi`~Wf6DnDpXP!s*Sgzk5Edk*@Wh4es z)qxXxS1|7lm#8NF?yF^j2p{zfhHn_P9@IBtrIMazc~!=ntV=YfbCdy$^|*b`QFFOxKq<@uIh{^I2&c%>tKBqz9se&{L&f!V?a<&tc59g`KaT1nAbd9X zH#_*bj=y1)-Pm?~G@$TAYHcP}ysCej2b8_*Y0oH`e#omjCYfq-tF!`1=gjvWlPNB*20EDme4yZ2{RB=%Ix!Lz?7nePTJReqtUZBYFWdEv%F7(8*b}j3r`xC_bHeg_Vfzu zeR)O#aj3sJddobyho6Pv2IodeAyot96(8;V(}8cB=S48y zgwcVs?)=Z7Mib*4G{Bli|9!W_C?1~Epqzq{uw?A z<2{Cq+tV4toDSaFdBojAZ^zcn6^1?;#AL^nmG4%@f ze;VtAmYb2rvp=rp1Xg_?o1lH<`nq*K^Yg5E&R)$LWAd2wekEu2)@v{|nM32X9ej6f z25|NbHUzQo9>0Jo%%Ty}4EUDmGXv*K4btCqatfKJXi%HCS*DJAH_fizO>>TS)9j%O z!&>nd$7!L)2C~Xoj$I5iWFYv%Av&I)boK1Iq%a+3Y+E78 zzoA7e(QqPn^qEF-!Zlbs_o$-3t9E=l_!ZIWy9zf9i@c*$K!p9u z;~n+<6HhH6maRWvkx~TDHJwEq4A_Zh9ZxS)Jz!@pxPim0yNqW#TV=!ndNSxd-glJ! zkbJVmJlpI8QAhY8da{~+$H`HTX;-*Ux!)EnbDh*rc4M}&9TdK2H+8FddiMYbz~}gO zJvLR$vKEItV{Hv_i5-GGAjrS*bLUd6HhY zp>fmbR@bMv1&`uaKn~)%noeC`hDXD>z{O6u+h(5a;xNea0(!$dR}o0!O){OVL(-J0 z;${;BFIc;*dl=0<0pl^hAZm2X{Q3Pw_NYC8A&7; z&%U{I=`}%nk!R|*Ez;sIzu~B1LoxB(Xs2`xP~#K*Stw5ZE?xsx5nPHF7ji(J;>B}a z5-+9xno*hf;=R40&to8lCFZ0Uk41|oTFT>mvJjN&MAjr-|JQ1Vo|)yVSw37u?7yg| zAS&{tM+s7Y{(SM}85SytFo~d0;JiXt+Af3dnl*fMM@m@GW!NjlV#1v??OwH{lt{@u zD@#Z*)xs9kv6G_#Jt8tYOTeV~k3fr1e}D)~m*QePp>i<=u!9(`gF{D9hk#@!`h}QG uUz;ZrPyYwsB1CJnoxh{b3UzsW;D~-t4sCx==V1@UwjcQLfMLu7=KDW6Yr|&% diff --git a/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde b/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde deleted file mode 100644 index 01f16016f..000000000 --- a/java/libraries/video/examples/Capture/BackgroundSubtraction/BackgroundSubtraction.pde +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Background Subtraction - * by Golan Levin. - * - * Detect the presence of people and objects in the frame using a simple - * background-subtraction technique. To initialize the background, press a key. - */ - - -import processing.video.*; - -int numPixels; -int[] backgroundPixels; -Capture video; - -void setup() { - size(640, 480); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - //video = new Capture(this, 160, 120); - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); - - numPixels = video.width * video.height; - // Create array to store the background image - backgroundPixels = new int[numPixels]; - // Make the pixels[] array available for direct manipulation - loadPixels(); -} - -void draw() { - if (video.available()) { - video.read(); // Read a new video frame - video.loadPixels(); // Make the pixels of video available - // Difference between the current frame and the stored background - int presenceSum = 0; - for (int i = 0; i < numPixels; i++) { // For each pixel in the video frame... - // Fetch the current color in that location, and also the color - // of the background in that spot - color currColor = video.pixels[i]; - color bkgdColor = backgroundPixels[i]; - // Extract the red, green, and blue components of the current pixel's color - int currR = (currColor >> 16) & 0xFF; - int currG = (currColor >> 8) & 0xFF; - int currB = currColor & 0xFF; - // Extract the red, green, and blue components of the background pixel's color - int bkgdR = (bkgdColor >> 16) & 0xFF; - int bkgdG = (bkgdColor >> 8) & 0xFF; - int bkgdB = bkgdColor & 0xFF; - // Compute the difference of the red, green, and blue values - int diffR = abs(currR - bkgdR); - int diffG = abs(currG - bkgdG); - int diffB = abs(currB - bkgdB); - // Add these differences to the running tally - presenceSum += diffR + diffG + diffB; - // Render the difference image to the screen - pixels[i] = color(diffR, diffG, diffB); - // The following line does the same thing much faster, but is more technical - //pixels[i] = 0xFF000000 | (diffR << 16) | (diffG << 8) | diffB; - } - updatePixels(); // Notify that the pixels[] array has changed - println(presenceSum); // Print out the total amount of movement - } -} - -// When a key is pressed, capture the background image into the backgroundPixels -// buffer, by copying each of the current frame's pixels into it. -void keyPressed() { - video.loadPixels(); - arraycopy(video.pixels, backgroundPixels); -} diff --git a/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde b/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde deleted file mode 100644 index 0902784ec..000000000 --- a/java/libraries/video/examples/Capture/BrightnessThresholding/BrightnessThresholding.pde +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Brightness Thresholding - * by Golan Levin. - * - * Determines whether a test location (such as the cursor) is contained within - * the silhouette of a dark object. - */ - - -import processing.video.*; - -color black = color(0); -color white = color(255); -int numPixels; -Capture video; - -void setup() { - size(640, 480); // Change size to 320 x 240 if too slow at 640 x 480 - strokeWeight(5); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); - - numPixels = video.width * video.height; - noCursor(); - smooth(); -} - -void draw() { - if (video.available()) { - video.read(); - video.loadPixels(); - int threshold = 127; // Set the threshold value - float pixelBrightness; // Declare variable to store a pixel's color - // Turn each pixel in the video frame black or white depending on its brightness - loadPixels(); - for (int i = 0; i < numPixels; i++) { - pixelBrightness = brightness(video.pixels[i]); - if (pixelBrightness > threshold) { // If the pixel is brighter than the - pixels[i] = white; // threshold value, make it white - } - else { // Otherwise, - pixels[i] = black; // make it black - } - } - updatePixels(); - // Test a location to see where it is contained. Fetch the pixel at the test - // location (the cursor), and compute its brightness - int testValue = get(mouseX, mouseY); - float testBrightness = brightness(testValue); - if (testBrightness > threshold) { // If the test location is brighter than - fill(black); // the threshold set the fill to black - } - else { // Otherwise, - fill(white); // set the fill to white - } - ellipse(mouseX, mouseY, 20, 20); - } -} diff --git a/java/libraries/video/examples/Capture/BrightnessTracking/BrightnessTracking.pde b/java/libraries/video/examples/Capture/BrightnessTracking/BrightnessTracking.pde deleted file mode 100644 index b1a1b5677..000000000 --- a/java/libraries/video/examples/Capture/BrightnessTracking/BrightnessTracking.pde +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Brightness Tracking - * by Golan Levin. - * - * Tracks the brightest pixel in a live video signal. - */ - - -import processing.video.*; - -Capture video; - -void setup() { - size(640, 480); - // Uses the default video input, see the reference if this causes an error - video = new Capture(this, width, height); - video.start(); - noStroke(); - smooth(); -} - -void draw() { - if (video.available()) { - video.read(); - image(video, 0, 0, width, height); // Draw the webcam video onto the screen - int brightestX = 0; // X-coordinate of the brightest video pixel - int brightestY = 0; // Y-coordinate of the brightest video pixel - float brightestValue = 0; // Brightness of the brightest video pixel - // Search for the brightest pixel: For each row of pixels in the video image and - // for each pixel in the yth row, compute each pixel's index in the video - video.loadPixels(); - int index = 0; - for (int y = 0; y < video.height; y++) { - for (int x = 0; x < video.width; x++) { - // Get the color stored in the pixel - int pixelValue = video.pixels[index]; - // Determine the brightness of the pixel - float pixelBrightness = brightness(pixelValue); - // If that value is brighter than any previous, then store the - // brightness of that pixel, as well as its (x,y) location - if (pixelBrightness > brightestValue) { - brightestValue = pixelBrightness; - brightestY = y; - brightestX = x; - } - index++; - } - } - // Draw a large, yellow circle at the brightest pixel - fill(255, 204, 0, 128); - ellipse(brightestX, brightestY, 200, 200); - } -} diff --git a/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde b/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde deleted file mode 100644 index e040a1923..000000000 --- a/java/libraries/video/examples/Capture/ColorSorting/ColorSorting.pde +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Color Sorting - * by Ben Fry. - * - * Example that sorts all colors from the incoming video - * and arranges them into vertical bars. - */ - - -import processing.video.*; - -Capture video; -boolean cheatScreen; - -Tuple[] captureColors; -Tuple[] drawColors; -int[] bright; - -// How many pixels to skip in either direction -int increment = 5; - -void setup() { - size(800, 600); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, 160, 120); - - // Start capturing the images from the camera - video.start(); - - int count = (video.width * video.height) / (increment * increment); - bright = new int[count]; - captureColors = new Tuple[count]; - drawColors = new Tuple[count]; - for (int i = 0; i < count; i++) { - captureColors[i] = new Tuple(); - drawColors[i] = new Tuple(0.5, 0.5, 0.5); - } -} - - -void draw() { - if (video.available()) { - video.read(); - video.loadPixels(); - - background(0); - noStroke(); - - int index = 0; - for (int j = 0; j < video.height; j += increment) { - for (int i = 0; i < video.width; i += increment) { - int pixelColor = video.pixels[j*video.width + i]; - - int r = (pixelColor >> 16) & 0xff; - int g = (pixelColor >> 8) & 0xff; - int b = pixelColor & 0xff; - - // Technically would be sqrt of the following, but no need to do - // sqrt before comparing the elements since we're only ordering - bright[index] = r*r + g*g + b*b; - captureColors[index].set(r, g, b); - - index++; - } - } - sort(index, bright, captureColors); - - beginShape(QUAD_STRIP); - for (int i = 0; i < index; i++) { - drawColors[i].target(captureColors[i], 0.1); - drawColors[i].phil(); - - float x = map(i, 0, index, 0, width); - vertex(x, 0); - vertex(x, height); - } - endShape(); - - if (cheatScreen) { - //image(video, 0, height - video.height); - // Faster method of displaying pixels array on screen - set(0, height - video.height, video); - } - } -} - - -void keyPressed() { - if (key == 'g') { - saveFrame(); - } else if (key == 'c') { - cheatScreen = !cheatScreen; - } -} - - -// Functions to handle sorting the color data - - -void sort(int length, int[] a, Tuple[] stuff) { - sortSub(a, stuff, 0, length - 1); -} - - -void sortSwap(int[] a, Tuple[] stuff, int i, int j) { - int T = a[i]; - a[i] = a[j]; - a[j] = T; - - Tuple v = stuff[i]; - stuff[i] = stuff[j]; - stuff[j] = v; -} - - -void sortSub(int[] a, Tuple[] stuff, int lo0, int hi0) { - int lo = lo0; - int hi = hi0; - int mid; - - if (hi0 > lo0) { - mid = a[(lo0 + hi0) / 2]; - - while (lo <= hi) { - while ((lo < hi0) && (a[lo] < mid)) { - ++lo; - } - while ((hi > lo0) && (a[hi] > mid)) { - --hi; - } - if (lo <= hi) { - sortSwap(a, stuff, lo, hi); - ++lo; - --hi; - } - } - - if (lo0 < hi) - sortSub(a, stuff, lo0, hi); - - if (lo < hi0) - sortSub(a, stuff, lo, hi0); - } -} diff --git a/java/libraries/video/examples/Capture/ColorSorting/Tuple.pde b/java/libraries/video/examples/Capture/ColorSorting/Tuple.pde deleted file mode 100644 index c3d8b5900..000000000 --- a/java/libraries/video/examples/Capture/ColorSorting/Tuple.pde +++ /dev/null @@ -1,29 +0,0 @@ -// Simple vector class that holds an x,y,z position. - -class Tuple { - float x, y, z; - - Tuple() { } - - Tuple(float x, float y, float z) { - set(x, y, z); - } - - void set(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - - void target(Tuple another, float amount) { - float amount1 = 1.0 - amount; - x = x*amount1 + another.x*amount; - y = y*amount1 + another.y*amount; - z = z*amount1 + another.z*amount; - } - - void phil() { - fill(x, y, z); - } -} - diff --git a/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde b/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde deleted file mode 100644 index 78869cd6d..000000000 --- a/java/libraries/video/examples/Capture/FrameDifferencing/FrameDifferencing.pde +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Frame Differencing - * by Golan Levin. - * - * Quantify the amount of movement in the video frame using frame-differencing. - */ - - -import processing.video.*; - -int numPixels; -int[] previousFrame; -Capture video; - -void setup() { - size(640, 480); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); - - numPixels = video.width * video.height; - // Create an array to store the previously captured frame - previousFrame = new int[numPixels]; - loadPixels(); -} - -void draw() { - if (video.available()) { - // When using video to manipulate the screen, use video.available() and - // video.read() inside the draw() method so that it's safe to draw to the screen - video.read(); // Read the new frame from the camera - video.loadPixels(); // Make its pixels[] array available - - int movementSum = 0; // Amount of movement in the frame - for (int i = 0; i < numPixels; i++) { // For each pixel in the video frame... - color currColor = video.pixels[i]; - color prevColor = previousFrame[i]; - // Extract the red, green, and blue components from current pixel - int currR = (currColor >> 16) & 0xFF; // Like red(), but faster - int currG = (currColor >> 8) & 0xFF; - int currB = currColor & 0xFF; - // Extract red, green, and blue components from previous pixel - int prevR = (prevColor >> 16) & 0xFF; - int prevG = (prevColor >> 8) & 0xFF; - int prevB = prevColor & 0xFF; - // Compute the difference of the red, green, and blue values - int diffR = abs(currR - prevR); - int diffG = abs(currG - prevG); - int diffB = abs(currB - prevB); - // Add these differences to the running tally - movementSum += diffR + diffG + diffB; - // Render the difference image to the screen - pixels[i] = color(diffR, diffG, diffB); - // The following line is much faster, but more confusing to read - //pixels[i] = 0xff000000 | (diffR << 16) | (diffG << 8) | diffB; - // Save the current color into the 'previous' buffer - previousFrame[i] = currColor; - } - // To prevent flicker from frames that are all black (no movement), - // only update the screen if the image has changed. - if (movementSum > 0) { - updatePixels(); - println(movementSum); // Print the total amount of movement to the console - } - } -} diff --git a/java/libraries/video/examples/Capture/Framingham/Framingham.pde b/java/libraries/video/examples/Capture/Framingham/Framingham.pde deleted file mode 100644 index 70d775d72..000000000 --- a/java/libraries/video/examples/Capture/Framingham/Framingham.pde +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Framingham - * by Ben Fry. - * - * Show subsequent frames from video input as a grid. Also fun with movie files. - */ - - -import processing.video.*; - -Capture video; -int column; -int columnCount; -int lastRow; - -// Buffer used to move all the pixels up -int[] scoot; - - -void setup() { - size(640, 480); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, 160, 120); - - // Start capturing the images from the camera - video.start(); - - column = 0; - columnCount = width / video.width; - int rowCount = height / video.height; - lastRow = rowCount - 1; - - scoot = new int[lastRow*video.height * width]; - background(0); -} - - -void draw() { - // By using video.available, only the frame rate need be set inside setup() - if (video.available()) { - video.read(); - video.loadPixels(); - image(video, video.width*column, video.height*lastRow); - column++; - if (column == columnCount) { - loadPixels(); - - // Scoot everybody up one row - arrayCopy(pixels, video.height*width, scoot, 0, scoot.length); - arrayCopy(scoot, 0, pixels, 0, scoot.length); - - // Set the moved row to black - for (int i = scoot.length; i < width*height; i++) { - pixels[i] = #000000; - } - column = 0; - updatePixels(); - } - } -} diff --git a/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde b/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde deleted file mode 100644 index 517ba8786..000000000 --- a/java/libraries/video/examples/Capture/GettingStartedCapture/GettingStartedCapture.pde +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Getting Started with Capture. - * - * Reading and displaying an image from an attached Capture device. - */ - -import processing.video.*; - -Capture cam; - -void setup() { - size(640, 480); - - String[] cameras = Capture.list(); - - if (cameras == null) { - println("Failed to retrieve the list of available cameras, will try the default..."); - cam = new Capture(this, 640, 480); - } if (cameras.length == 0) { - println("There are no cameras available for capture."); - exit(); - } else { - println("Available cameras:"); - for (int i = 0; i < cameras.length; i++) { - println(cameras[i]); - } - - // The camera can be initialized directly using an element - // from the array returned by list(): - cam = new Capture(this, cameras[0]); - // Or, the settings can be defined based on the text in the list - //cam = new Capture(this, 640, 480, "Built-in iSight", 30); - - // Start capturing the images from the camera - cam.start(); - } -} - -void draw() { - if (cam.available() == true) { - cam.read(); - } - image(cam, 0, 0); - // The following does the same as the above image() line, but - // is faster when just drawing the image without any additional - // resizing, transformations, or tint. - //set(0, 0, cam); -} - diff --git a/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde b/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde deleted file mode 100644 index c77208410..000000000 --- a/java/libraries/video/examples/Capture/HsvSpace/HsvSpace.pde +++ /dev/null @@ -1,213 +0,0 @@ -/** - * HSV Space - * by Ben Fry. - * - * Arrange the pixels from live video into the HSV Color Cone. - */ - -import processing.video.*; -import java.awt.Color; - -Capture video; -int count; -boolean cheatScreen = true; - -static final float BOX_SIZE = 0.75; -static final float CONE_HEIGHT = 1.2; -static final float MAX_RADIUS = 10; -static final float ROT_INCREMENT = 3.0; -static final float TRANS_INCREMENT = 1; -static final float STEP_AMOUNT = 0.1; - -Tuple[] farbe; -Tuple[] trans; - -float[] hsb = new float[3]; - -float leftRightAngle; -float upDownAngle; -float fwdBackTrans; -float upDownTrans; -float leftRightTrans; -boolean motion; - -boolean blobby = false; - - -void setup() { - size(640, 480, P3D); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, 160, 120); - - // Start capturing the images from the camera - video.start(); - - count = video.width * video.height; - - sphereDetail(60); - - upDownTrans = 0; - leftRightTrans = 0; - motion = false; - - leftRightAngle = 101.501297; - upDownAngle = -180.098694; - fwdBackTrans = 14.800003; - - farbe = new Tuple[count]; - trans = new Tuple[count]; - for (int i = 0; i < count; i++) { - farbe[i] = new Tuple(); - trans[i] = new Tuple(); - } -} - - -void draw() { - background(0); - - if (!blobby) { - lights(); - } - - pushMatrix(); - translate(width/2, height/2); - scale(min(width, height) / 10.0); - - translate(0, 0, -20 + fwdBackTrans); - rotateY(radians(36 + leftRightAngle)); //, 0, 1, 0); - rotateX(radians(-228 + upDownAngle)); //, 1, 0, 0); - - strokeWeight(0.1); - if (blobby) { - stroke(0.35, 0.35, 0.25, 0.15); - wireCone(MAX_RADIUS, MAX_RADIUS * CONE_HEIGHT, 18, 18); - } - else { - stroke(0.35, 0.35, 0.25, 0.25); - wireCone(MAX_RADIUS, MAX_RADIUS * CONE_HEIGHT, 180, 18); - } - - noStroke(); - video.loadPixels(); - for (int i = 0; i < count; i++) { - int pixelColor = video.pixels[i]; - int r = (pixelColor >> 16) & 0xff; - int g = (pixelColor >> 8) & 0xff; - int b = pixelColor & 0xff; - Color.RGBtoHSB(r, g, b, hsb); - - float radius = hsb[1] * hsb[2]; - float angle = hsb[0] * 360.0 * DEG_TO_RAD; - float nx = MAX_RADIUS * radius * cos(angle); - float ny = MAX_RADIUS * radius * sin(angle); - float nz = hsb[2] * MAX_RADIUS * CONE_HEIGHT; - - trans[i].set(trans[i].x - (trans[i].x - nx)*STEP_AMOUNT, - trans[i].y - (trans[i].y - ny)*STEP_AMOUNT, - trans[i].z - (trans[i].z - nz)*STEP_AMOUNT); - - farbe[i].set(farbe[i].x - (farbe[i].x - r)*STEP_AMOUNT, - farbe[i].y - (farbe[i].y - g)*STEP_AMOUNT, - farbe[i].z - (farbe[i].z - b)*STEP_AMOUNT); - - pushMatrix(); - farbe[i].phil(); - trans[i].tran(); - - rotate(radians(45), 1, 1, 0); - if (blobby) { - sphere(BOX_SIZE * 2); //, 20, 20); - } else { - box(BOX_SIZE); - } - - popMatrix(); - } - popMatrix(); - - if (motion) { - upDownAngle--; - leftRightAngle--; - } - - if (cheatScreen) { - image(video, 0, height - video.height); - } -} - - -void captureEvent(Capture c) { - c.read(); -} - - -void keyPressed() { - switch (key) { - case 'g': - saveFrame(); - break; - case 'c': - cheatScreen = !cheatScreen; - break; - - case 'm': - motion = !motion; - break; - case '=': - fwdBackTrans += TRANS_INCREMENT; - break; - case '-': - fwdBackTrans -= TRANS_INCREMENT; - break; - case 'b': - blobby = !blobby; - break; - } -} - - -void mouseDragged() { - float dX, dY; - - switch (mouseButton) { - case LEFT: // left right up down - dX = pmouseX - mouseX; - dY = pmouseY - mouseY; - leftRightAngle -= dX * 0.2; - upDownAngle += dY * 0.4; - break; - - case CENTER: - dX = pmouseX - mouseX; - dY = pmouseY - mouseY; - leftRightTrans -= TRANS_INCREMENT * dX; - upDownTrans -= TRANS_INCREMENT * dY; - break; - - case RIGHT: // in and out - dY = (float) (pmouseY - mouseY); - fwdBackTrans -= TRANS_INCREMENT * dY; - break; - } -} - - -void wireCone(float radius, float height, int stepX, int stepY) { - int steps = 10; - stroke(40); - for (int i = 0; i < steps; i++) { - float angle = map(i, 0, steps, 0, TWO_PI); - float x = radius * cos(angle); - float y = radius * sin(angle); - line(x, y, height, 0, 0, 0); - } - noFill(); - pushMatrix(); - translate(0, 0, height); - ellipseMode(CENTER); - ellipse(0, 0, radius, radius); - popMatrix(); -} diff --git a/java/libraries/video/examples/Capture/HsvSpace/Tuple.pde b/java/libraries/video/examples/Capture/HsvSpace/Tuple.pde deleted file mode 100644 index 19c1507aa..000000000 --- a/java/libraries/video/examples/Capture/HsvSpace/Tuple.pde +++ /dev/null @@ -1,33 +0,0 @@ -// Simple vector class that holds an x,y,z position. - -class Tuple { - float x, y, z; - - Tuple() { } - - Tuple(float x, float y, float z) { - set(x, y, z); - } - - void set(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - - void target(Tuple another, float amount) { - float amount1 = 1.0 - amount; - x = x*amount1 + another.x*amount; - y = y*amount1 + another.y*amount; - z = z*amount1 + another.z*amount; - } - - void phil() { - fill(x, y, z); - } - - void tran() { - translate(x, y, z); - } -} - diff --git a/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde b/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde deleted file mode 100644 index 64b4b6db5..000000000 --- a/java/libraries/video/examples/Capture/LivePocky/LivePocky.pde +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Live Pocky - * by Ben Fry. - * - * Unwrap each frame of live video into a single line of pixels. - */ - -import processing.video.*; - -Capture video; -int count; -int writeRow; -int maxRows; -int topRow; -int buffer[]; - - -void setup() { - size(600, 400); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, 320, 240); - - // Start capturing the images from the camera - video.start(); - - maxRows = height * 2; - buffer = new int[width * maxRows]; - writeRow = height - 1; - topRow = 0; - - background(0); - loadPixels(); -} - - -void draw() { - video.loadPixels(); - arraycopy(video.pixels, 0, buffer, writeRow * width, width); - writeRow++; - if (writeRow == maxRows) { - writeRow = 0; - } - topRow++; - - for (int y = 0; y < height; y++) { - int row = (topRow + y) % maxRows; - arraycopy(buffer, row * width, g.pixels, y*width, width); - } - updatePixels(); -} - - -void captureEvent(Capture c) { - c.read(); -} diff --git a/java/libraries/video/examples/Capture/Mirror/Mirror.pde b/java/libraries/video/examples/Capture/Mirror/Mirror.pde deleted file mode 100644 index 0c527c802..000000000 --- a/java/libraries/video/examples/Capture/Mirror/Mirror.pde +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Mirror - * by Daniel Shiffman. - * - * Each pixel from the video source is drawn as a rectangle with rotation based on brightness. - */ - -import processing.video.*; - - -// Size of each cell in the grid -int cellSize = 20; -// Number of columns and rows in our system -int cols, rows; -// Variable for capture device -Capture video; - - -void setup() { - size(640, 480); - frameRate(30); - cols = width / cellSize; - rows = height / cellSize; - colorMode(RGB, 255, 255, 255, 100); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); - - background(0); -} - - -void draw() { - if (video.available()) { - video.read(); - video.loadPixels(); - - // Begin loop for columns - for (int i = 0; i < cols; i++) { - // Begin loop for rows - for (int j = 0; j < rows; j++) { - - // Where are we, pixel-wise? - int x = i*cellSize; - int y = j*cellSize; - int loc = (video.width - x - 1) + y*video.width; // Reversing x to mirror the image - - float r = red(video.pixels[loc]); - float g = green(video.pixels[loc]); - float b = blue(video.pixels[loc]); - // Make a new color with an alpha component - color c = color(r, g, b, 75); - - // Code for drawing a single rect - // Using translate in order for rotation to work properly - pushMatrix(); - translate(x+cellSize/2, y+cellSize/2); - // Rotation formula based on brightness - rotate((2 * PI * brightness(c) / 255.0)); - rectMode(CENTER); - fill(c); - noStroke(); - // Rects are larger than the cell for some overlap - rect(0, 0, cellSize+6, cellSize+6); - popMatrix(); - } - } - } -} diff --git a/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde b/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde deleted file mode 100644 index 242e55a10..000000000 --- a/java/libraries/video/examples/Capture/Mirror2/Mirror2.pde +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Mirror 2 - * by Daniel Shiffman. - * - * Each pixel from the video source is drawn as a rectangle with size based on brightness. - */ - -import processing.video.*; - -// Size of each cell in the grid -int cellSize = 15; -// Number of columns and rows in our system -int cols, rows; -// Variable for capture device -Capture video; - - -void setup() { - size(640, 480); - // Set up columns and rows - cols = width / cellSize; - rows = height / cellSize; - colorMode(RGB, 255, 255, 255, 100); - rectMode(CENTER); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); - - background(0); -} - - -void draw() { - if (video.available()) { - video.read(); - video.loadPixels(); - - background(0, 0, 255); - - // Begin loop for columns - for (int i = 0; i < cols;i++) { - // Begin loop for rows - for (int j = 0; j < rows;j++) { - - // Where are we, pixel-wise? - int x = i * cellSize; - int y = j * cellSize; - int loc = (video.width - x - 1) + y*video.width; // Reversing x to mirror the image - - // Each rect is colored white with a size determined by brightness - color c = video.pixels[loc]; - float sz = (brightness(c) / 255.0) * cellSize; - fill(255); - noStroke(); - rect(x + cellSize/2, y + cellSize/2, sz, sz); - } - } - } -} diff --git a/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde b/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde deleted file mode 100644 index ed4ca728c..000000000 --- a/java/libraries/video/examples/Capture/RadialPocky/RadialPocky.pde +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Radial Pocky - * by Ben Fry. - * - * Unwrap each frame of live video into a single line of pixels along a circle - */ - -import processing.video.*; - -Capture video; -int videoCount; -int currentAngle; -int pixelCount; -int angleCount = 200; // how many divisions - -int radii[]; -int angles[]; - - -void setup() { - // size must be set to video.width*video.height*2 in both directions - size(600, 600); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, 160, 120); - - // Start capturing the images from the camera - video.start(); - - videoCount = video.width * video.height; - - pixelCount = width*height; - int centerX = width / 2; - int centerY = height / 2; - radii = new int[pixelCount]; - angles = new int[pixelCount]; - - int offset = 0; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int dx = centerX - x; - int dy = centerY - y; - - float angle = atan2(dy, dx); - if (angle < 0) angle += TWO_PI; - angles[offset] = (int) (angleCount * (angle / TWO_PI)); - - int radius = (int) mag(dx, dy); - if (radius >= videoCount) { - radius = -1; - angles[offset] = -1; - } - radii[offset] = radius; - - offset++; - } - } - background(0); -} - - -void draw() { - if (video.available()) { - video.read(); - video.loadPixels(); - - loadPixels(); - for (int i = 0; i < pixelCount; i++) { - if (angles[i] == currentAngle) { - pixels[i] = video.pixels[radii[i]]; - } - } - updatePixels(); - - currentAngle++; - if (currentAngle == angleCount) { - currentAngle = 0; - } - } -} diff --git a/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde b/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde deleted file mode 100644 index 8f4e06a02..000000000 --- a/java/libraries/video/examples/Capture/SlitScan/SlitScan.pde +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Simple Real-Time Slit-Scan Program. - * By Golan Levin. - * - * This demonstration depends on the canvas height being equal - * to the video capture height. If you would prefer otherwise, - * consider using the image copy() function rather than the - * direct pixel-accessing approach I have used here. - */ - - -import processing.video.*; - -Capture video; - -int videoSliceX; -int drawPositionX; - -void setup() { - size(600, 240); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this,320, 240); - - // Start capturing the images from the camera - video.start(); - - videoSliceX = video.width / 2; - drawPositionX = width - 1; - background(0); -} - - -void draw() { - if (video.available()) { - video.read(); - video.loadPixels(); - - // Copy a column of pixels from the middle of the video - // To a location moving slowly across the canvas. - loadPixels(); - for (int y = 0; y < video.height; y++){ - int setPixelIndex = y*width + drawPositionX; - int getPixelIndex = y*video.width + videoSliceX; - pixels[setPixelIndex] = video.pixels[getPixelIndex]; - } - updatePixels(); - - drawPositionX--; - // Wrap the position back to the beginning if necessary. - if (drawPositionX < 0) { - drawPositionX = width - 1; - } - } -} diff --git a/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde b/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde deleted file mode 100644 index 24a1a83d4..000000000 --- a/java/libraries/video/examples/Capture/Spatiotemporal/Spatiotemporal.pde +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Spatiotemporal - * by David Muth - * - * Records a number of video frames into memory, then plays back the video - * buffer by turning the time axis into the x-axis and vice versa - */ - -import processing.video.*; - -Capture video; -int signal = 0; - -//the buffer for storing video frames -ArrayList frames; - -//different program modes for recording and playback -int mode = 0; -int MODE_NEWBUFFER = 0; -int MODE_RECORDING = 1; -int MODE_PLAYBACK = 2; - -int currentX = 0; - -void setup() { - size(640, 480); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); -} - -void captureEvent(Capture c) { - c.read(); - - //create a new buffer in case one is needed - if (mode == MODE_NEWBUFFER) { - frames = new ArrayList(); - mode = MODE_RECORDING; - } - - //record into the buffer until there are enough frames - if (mode == MODE_RECORDING) { - //copy the current video frame into an image, so it can be stored in the buffer - PImage img = createImage(width, height, RGB); - video.loadPixels(); - arrayCopy(video.pixels, img.pixels); - - frames.add(img); - - //in case enough frames have been recorded, switch to playback mode - if (frames.size() >= width) { - mode = MODE_PLAYBACK; - } - } -} - -void draw() { - loadPixels(); - - //code for the recording mode - if (mode == MODE_RECORDING) { - //set the image counter to 0 - int currentImage = 0; - - //begin a loop for displaying pixel columns - for (int x = 0; x < video.width; x++) { - //go through the frame buffer and pick an image using the image counter - if (currentImage < frames.size()) { - PImage img = (PImage)frames.get(currentImage); - - //display a pixel column of the current image - if (img != null) { - img.loadPixels(); - - for (int y = 0; y < video.height; y++) { - pixels[x + y * width] = img.pixels[x + y * video.width]; - } - } - - //increase the image counter - currentImage++; - - } - else { - break; - } - } - } - - //code for displaying the spatiotemporal transformation - if (mode == MODE_PLAYBACK) { - - //begin a loop for displaying pixel columns - for (int x = 0; x < video.width; x++) { - //get an image from the buffer using loopcounter x as the index - PImage img = (PImage)frames.get(x); - - if (img != null) { - img.loadPixels(); - - //pick the same column from each image for display, - //then distribute the columns over the x-axis on the screen - for(int y = 0; y < video.height; y++) { - pixels[x + y * width] = img.pixels[currentX + y * video.width]; - } - } - } - - //a different column shall be used next time draw() is being called - currentX++; - - //if the end of the buffer is reached - if(currentX >= video.width) { - //create a new buffer when the next video frame arrives - mode = MODE_NEWBUFFER; - //reset the column counter - currentX = 0; - } - } - - updatePixels(); -} - - - - - diff --git a/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde b/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde deleted file mode 100644 index 460f8adcf..000000000 --- a/java/libraries/video/examples/Capture/TimeDisplacement/TimeDisplacement.pde +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Time Displacement - * by David Muth - * - * Keeps a buffer of video frames in memory and displays pixel rows - * taken from consecutive frames distributed over the y-axis - */ - -import processing.video.*; - -Capture video; -int signal = 0; - -//the buffer for storing video frames -ArrayList frames = new ArrayList(); - -void setup() { - size(640, 480); - - // This the default video input, see the GettingStartedCapture - // example if it creates an error - video = new Capture(this, width, height); - - // Start capturing the images from the camera - video.start(); -} - -void captureEvent(Capture camera) { - camera.read(); - - // Copy the current video frame into an image, so it can be stored in the buffer - PImage img = createImage(width, height, RGB); - video.loadPixels(); - arrayCopy(video.pixels, img.pixels); - - frames.add(img); - - // Once there are enough frames, remove the oldest one when adding a new one - if (frames.size() > height/4) { - frames.remove(0); - } -} - -void draw() { - // Set the image counter to 0 - int currentImage = 0; - - loadPixels(); - - // Begin a loop for displaying pixel rows of 4 pixels height - for (int y = 0; y < video.height; y+=4) { - // Go through the frame buffer and pick an image, starting with the oldest one - if (currentImage < frames.size()) { - PImage img = (PImage)frames.get(currentImage); - - if (img != null) { - img.loadPixels(); - - // Put 4 rows of pixels on the screen - for (int x = 0; x < video.width; x++) { - pixels[x + y * width] = img.pixels[x + y * video.width]; - pixels[x + (y + 1) * width] = img.pixels[x + (y + 1) * video.width]; - pixels[x + (y + 2) * width] = img.pixels[x + (y + 2) * video.width]; - pixels[x + (y + 3) * width] = img.pixels[x + (y + 3) * video.width]; - } - } - - // Increase the image counter - currentImage++; - - } else { - break; - } - } - - updatePixels(); - - // For recording an image sequence - //saveFrame("frame-####.jpg"); -} - - - - diff --git a/java/libraries/video/examples/Movie/Frames/Frames.pde b/java/libraries/video/examples/Movie/Frames/Frames.pde deleted file mode 100644 index 04fbf81fb..000000000 --- a/java/libraries/video/examples/Movie/Frames/Frames.pde +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Frames - * by Andres Colubri. - * - * Moves through the video one frame at the time by using the - * arrow keys. It estimates the frame counts using the framerate - * of the movie file, so it might not be exact in some cases. - */ - -import processing.video.*; - -Movie mov; -int newFrame = 0; -int movFrameRate = 30; - -void setup() { - size(640, 360); - background(0); - // Load and set the video to play. Setting the video - // in play mode is needed so at least one frame is read - // and we can get duration, size and other information from - // the video stream. - mov = new Movie(this, "transit.mov"); - - // Pausing the video at the first frame. - mov.play(); - mov.jump(0); - mov.pause(); -} - -void movieEvent(Movie m) { - m.read(); -} - -void draw() { - background(0); - image(mov, 0, 0, width, height); - fill(255); - text(getFrame() + " / " + (getLength() - 1), 10, 30); -} - -void keyPressed() { - if (key == CODED) { - if (keyCode == LEFT) { - if (0 < newFrame) newFrame--; - } else if (keyCode == RIGHT) { - if (newFrame < getLength() - 1) newFrame++; - } - } - setFrame(newFrame); -} - -int getFrame() { - return ceil(mov.time() * 30) - 1; -} - -void setFrame(int n) { - mov.play(); - - // The duration of a single frame: - float frameDuration = 1.0 / movFrameRate; - - // We move to the middle of the frame by adding 0.5: - float where = (n + 0.5) * frameDuration; - - // Taking into account border effects: - float diff = mov.duration() - where; - if (diff < 0) { - where += diff - 0.25 * frameDuration; - } - - mov.jump(where); - mov.pause(); -} - -int getLength() { - return int(mov.duration() * movFrameRate); -} - diff --git a/java/libraries/video/examples/Movie/Loop/Loop.pde b/java/libraries/video/examples/Movie/Loop/Loop.pde deleted file mode 100644 index 05383b620..000000000 --- a/java/libraries/video/examples/Movie/Loop/Loop.pde +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Loop. - * - * Shows how to load and play a QuickTime movie file. - * - */ - -import processing.video.*; - -Movie movie; - -void setup() { - size(640, 360); - background(0); - // Load and play the video in a loop - movie = new Movie(this, "transit.mov"); - movie.loop(); -} - -void movieEvent(Movie m) { - m.read(); -} - -void draw() { - //if (movie.available() == true) { - // movie.read(); - //} - image(movie, 0, 0, width, height); -} diff --git a/java/libraries/video/examples/Movie/Pixelate/Pixelate.pde b/java/libraries/video/examples/Movie/Pixelate/Pixelate.pde deleted file mode 100644 index 1ac791581..000000000 --- a/java/libraries/video/examples/Movie/Pixelate/Pixelate.pde +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Pixelate - * by Hernando Barragan. - * - * Load a QuickTime file and display the video signal - * using rectangles as pixels by reading the values stored - * in the current video frame pixels array. - */ - -import processing.video.*; - -int numPixelsWide, numPixelsHigh; -int blockSize = 10; -Movie mov; -color movColors[]; - -void setup() { - size(640, 360); - noStroke(); - mov = new Movie(this, "transit.mov"); - mov.loop(); - numPixelsWide = width / blockSize; - numPixelsHigh = height / blockSize; - println(numPixelsWide); - movColors = new color[numPixelsWide * numPixelsHigh]; -} - -// Display values from movie -void draw() { - if (mov.available() == true) { - mov.read(); - mov.loadPixels(); - int count = 0; - for (int j = 0; j < numPixelsHigh; j++) { - for (int i = 0; i < numPixelsWide; i++) { - movColors[count] = mov.get(i*blockSize, j*blockSize); - count++; - } - } - } - - background(255); - for (int j = 0; j < numPixelsHigh; j++) { - for (int i = 0; i < numPixelsWide; i++) { - fill(movColors[j*numPixelsWide + i]); - rect(i*blockSize, j*blockSize, blockSize, blockSize); - } - } - -} - diff --git a/java/libraries/video/examples/Movie/Reverse/Reverse.pde b/java/libraries/video/examples/Movie/Reverse/Reverse.pde deleted file mode 100644 index 817368aa8..000000000 --- a/java/libraries/video/examples/Movie/Reverse/Reverse.pde +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Reverse playback example. - * - * The Movie.speed() method allows to change the playback speed. - * Use negative values for backwards playback. Note that not all - * video formats support backwards playback. This depends on the - * underlying gstreamer plugins used by gsvideo. For example, the - * theora codec does support backward playback, but not so the H264 - * codec, at least in its current version. - * - */ - -import processing.video.*; - -Movie mov; -boolean speedSet = false; -boolean once = true; - -void setup() { - size(640, 360); - background(0); - mov = new Movie(this, "transit.mkv"); - mov.play(); -} - -void movieEvent(Movie m) { - m.read(); - if (speedSet == true) { - speedSet = false; - } -} - -void draw() { - if (speedSet == false && once == true) { - // Setting the speed should be done only once, - // this is the reason for the if statement. - speedSet = true; - once = false; - mov.jump(mov.duration()); - // -1 means backward playback at normal speed. - mov.speed(-1.0); - // Setting to play again, since the movie stop - // playback once it reached the end. - mov.play(); - } - image(mov, 0, 0, width, height); -} - diff --git a/java/libraries/video/examples/Movie/Scratch/Scratch.pde b/java/libraries/video/examples/Movie/Scratch/Scratch.pde deleted file mode 100644 index dbd9fdcec..000000000 --- a/java/libraries/video/examples/Movie/Scratch/Scratch.pde +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Scratch - * by Andres Colubri. - * - * Move the cursor horizontally across the screen to set - * the position in the movie file. - */ - -import processing.video.*; - -Movie mov; - -void setup() { - size(640, 360); - background(0); - - mov = new Movie(this, "transit.mov"); - - // Pausing the video at the first frame. - mov.play(); - mov.jump(0); - mov.pause(); -} - -void draw() { - - if (mov.available()) { - mov.read(); - // A new time position is calculated using the current mouse location: - float f = map(mouseX, 0, width, 0, 1); - float t = mov.duration() * f; - mov.play(); - mov.jump(t); - mov.pause(); - } - - image(mov, 0, 0); -} - diff --git a/java/libraries/video/examples/Movie/Speed/Speed.pde b/java/libraries/video/examples/Movie/Speed/Speed.pde deleted file mode 100644 index c08137651..000000000 --- a/java/libraries/video/examples/Movie/Speed/Speed.pde +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Speed. - * - * Use the Movie.speed() method to change - * the playback speed. - * - */ - -import processing.video.*; - -Movie mov; - -void setup() { - size(640, 360); - background(0); - mov = new Movie(this, "transit.mov"); - mov.loop(); -} - -void movieEvent(Movie movie) { - mov.read(); -} - -void draw() { - image(mov, 0, 0); - - float newSpeed = map(mouseX, 0, width, 0.1, 2); - mov.speed(newSpeed); - - fill(255); - text(nfc(newSpeed, 2) + "X", 10, 30); -} - diff --git a/java/libraries/video/library/.gitignore b/java/libraries/video/library/.gitignore deleted file mode 100644 index 374cc6ccf..000000000 --- a/java/libraries/video/library/.gitignore +++ /dev/null @@ -1 +0,0 @@ -video.jar diff --git a/java/libraries/video/library/export.txt b/java/libraries/video/library/export.txt deleted file mode 100644 index 189254a96..000000000 --- a/java/libraries/video/library/export.txt +++ /dev/null @@ -1 +0,0 @@ -name = Video diff --git a/java/libraries/video/src/processing/video/Capture.java b/java/libraries/video/src/processing/video/Capture.java deleted file mode 100644 index 5d4221fb5..000000000 --- a/java/libraries/video/src/processing/video/Capture.java +++ /dev/null @@ -1,1227 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-12 Ben Fry and Casey Reas - The previous version of this code was developed by Hernando Barragan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.video; - -import processing.core.*; - -import java.nio.*; -import java.util.ArrayList; -import java.io.File; -import java.lang.reflect.*; - -import org.gstreamer.*; -import org.gstreamer.Buffer; -import org.gstreamer.elements.*; -import org.gstreamer.interfaces.PropertyProbe; -import org.gstreamer.interfaces.Property; - -/** - * ( begin auto-generated from Capture.xml ) - * - * Datatype for storing and manipulating video frames from an attached - * capture device such as a camera. Use Capture.list() to show the - * names of any attached devices. Using the version of the constructor - * without name will attempt to use the last device used by a - * QuickTime program. - * - * ( end auto-generated ) - * - *

    Advanced

    - * Class for storing and manipulating video frames from an attached capture - * device such as a camera. - * @webref video - * @usage application - */ -public class Capture extends PImage implements PConstants { - protected static String sourceElementName; - protected static String devicePropertyName; - protected static String indexPropertyName; - // Default gstreamer capture plugin for each platform, and property names. - static { - if (PApplet.platform == MACOSX) { - sourceElementName = "qtkitvideosrc"; - devicePropertyName = "device-name"; - indexPropertyName = "device-index"; - } else if (PApplet.platform == WINDOWS) { - sourceElementName = "ksvideosrc"; - devicePropertyName = "device-name"; - indexPropertyName = "device-index"; - } else if (PApplet.platform == LINUX) { - sourceElementName = "v4l2src"; - // The "device" property in v4l2src expects the device location - // (/dev/video0, etc). v4l2src has "device-name", which requires the - // human-readable name... but how to query in linux?. - devicePropertyName = "device"; - indexPropertyName = "device-fd"; - } else {} - } - protected static boolean useResMacHack = true; - - public float frameRate; - public Pipeline pipeline; - - protected boolean capturing = false; - - protected String frameRateString; - protected int bufWidth; - protected int bufHeight; - - protected String sourceName; - protected Element sourceElement; - - protected Method captureEventMethod; - protected Object eventHandler; - - protected boolean available; - protected boolean pipelineReady; - protected boolean newFrame; - - protected RGBDataAppSink rgbSink = null; - protected int[] copyPixels = null; - - protected boolean firstFrame = true; - - protected int reqWidth; - protected int reqHeight; - - protected boolean useBufferSink = false; - protected boolean outdatedPixels = true; - protected Object bufferSink; - protected Method sinkCopyMethod; - protected Method sinkSetMethod; - protected Method sinkDisposeMethod; - protected Method sinkGetMethod; - protected String copyMask; - protected Buffer natBuffer = null; - protected BufferDataAppSink natSink = null; - - - public Capture(PApplet parent) { - String[] configs = Capture.list(); - if (configs.length == 0) { - throw new RuntimeException("There are no cameras available for capture"); - } - String name = getName(configs[0]); - int[] size = getSize(configs[0]); - String fps = getFrameRate(configs[0]); - String idName; - Object idValue; - if (devicePropertyName.equals("")) { - // For plugins without device name property, the name is casted - // as an index - idName = indexPropertyName; - idValue = new Integer(PApplet.parseInt(name)); - } else { - idName = devicePropertyName; - idValue = name; - } - initGStreamer(parent, size[0], size[1], sourceElementName, - idName, idValue, fps); - } - - - public Capture(PApplet parent, String requestConfig) { - String name = getName(requestConfig); - int[] size = getSize(requestConfig); - String fps = getFrameRate(requestConfig); - String idName; - Object idValue; - if (devicePropertyName.equals("")) { - // For plugins without device name property, the name is casted - // as an index - idName = indexPropertyName; - idValue = new Integer(PApplet.parseInt(name)); - } else { - idName = devicePropertyName; - idValue = name; - } - initGStreamer(parent, size[0], size[1], sourceElementName, - idName, idValue, fps); - } - - - /** - * @param parent typically use "this" - * @param requestWidth width of the frame - * @param requestHeight height of the frame - */ - public Capture(PApplet parent, int requestWidth, int requestHeight) { - super(requestWidth, requestHeight, RGB); - initGStreamer(parent, requestWidth, requestHeight, sourceElementName, - null, null, ""); - } - - - /** - *

    Advanced

    - * Constructor that takes resolution and framerate. - * - * @param frameRate number of frames to read per second - */ - public Capture(PApplet parent, int requestWidth, int requestHeight, - int frameRate) { - super(requestWidth, requestHeight, RGB); - initGStreamer(parent, requestWidth, requestHeight, sourceElementName, - null, null, frameRate + "/1"); - } - - - /** - *

    Advanced

    - * This constructor allows to specify resolution and camera name. - * - * @param cameraName name of the camera - */ - public Capture(PApplet parent, int requestWidth, int requestHeight, - String cameraName) { - super(requestWidth, requestHeight, RGB); - String idName; - Object idValue; - if (devicePropertyName.equals("")) { - // For plugins without device name property, the name is casted - // as an index - idName = indexPropertyName; - idValue = new Integer(PApplet.parseInt(cameraName)); - } else { - idName = devicePropertyName; - idValue = cameraName; - } - initGStreamer(parent, requestWidth, requestHeight, sourceElementName, - idName, idValue, ""); - } - - - /** - *

    Advanced

    - * This constructor allows to specify the camera name and the desired - * framerate, in addition to the resolution. - */ - public Capture(PApplet parent, int requestWidth, int requestHeight, - String cameraName, int frameRate) { - super(requestWidth, requestHeight, RGB); - String idName; - Object idValue; - if (devicePropertyName.equals("")) { - // For plugins without device name property, the name is casted - // as an index - idName = indexPropertyName; - idValue = new Integer(PApplet.parseInt(cameraName)); - } else { - idName = devicePropertyName; - idValue = cameraName; - } - initGStreamer(parent, requestWidth, requestHeight, sourceElementName, - idName, idValue, frameRate + "/1"); - } - - - /** - * Disposes all the native resources associated to this capture device. - * - * NOTE: This is not official API and may/will be removed at any time. - */ - public void dispose() { - if (pipeline != null) { - try { - if (pipeline.isPlaying()) { - pipeline.stop(); - pipeline.getState(); - } - } catch (Exception e) { - e.printStackTrace(); - } - - pixels = null; - - copyPixels = null; - if (rgbSink != null) { - rgbSink.removeListener(); - rgbSink.dispose(); - rgbSink = null; - } - - natBuffer = null; - if (natSink != null) { - natSink.removeListener(); - natSink.dispose(); - natSink = null; - } - - pipeline.dispose(); - pipeline = null; - - parent.g.removeCache(this); - parent.unregisterMethod("dispose", this); - parent.unregisterMethod("post", this); - } - } - - - /** - * Finalizer of the class. - */ - protected void finalize() throws Throwable { - try { - dispose(); - } finally { - super.finalize(); - } - } - - - /** - * ( begin auto-generated from Capture_available.xml ) - * - * Returns "true" when a new video frame is available to read. - * - * ( end auto-generated ) - * - * @webref capture - * @brief Returns "true" when a new video frame is available to read - */ - public boolean available() { - return available; - } - - - /** - * ( begin auto-generated from Capture_start.xml ) - * - * Starts capturing frames from the selected device. - * - * ( end auto-generated ) - * - * @webref capture - * @brief Starts capturing frames from the selected device - */ - public void start() { - boolean init = false; - if (!pipelineReady) { - initPipeline(); - init = true; - } - - capturing = true; - pipeline.play(); - - if (init) { - checkResIsValid(); - } - } - - - /** - * ( begin auto-generated from Capture_stop.xml ) - * - * Stops capturing frames from an attached device. - * - * ( end auto-generated ) - * - * @webref capture - * @brief Stops capturing frames from an attached device - */ - public void stop() { - if (!pipelineReady) { - initPipeline(); - } - - capturing = false; - pipeline.stop(); - pipeline.getState(); - } - - - /** - * ( begin auto-generated from Capture_read.xml ) - * - * Reads the current video frame. - * - * ( end auto-generated ) - * - *

    Advanced

    - * This method() and invokeEvent() are now synchronized, so that invokeEvent() - * can't be called whilst we're busy reading. Problematic frame error - * fixed by Charl P. Botha - * - * @webref capture - * @brief Reads the current video frame - */ - public synchronized void read() { - if (frameRate < 0) { - // Framerate not set yet, so we obtain from stream, - // which is already playing since we are in read(). - frameRate = getSourceFrameRate(); - } - - if (useBufferSink) { // The native buffer from gstreamer is copied to the buffer sink. - outdatedPixels = true; - if (natBuffer == null) { - return; - } - - if (firstFrame) { - super.init(bufWidth, bufHeight, ARGB); - firstFrame = false; - } - - if (bufferSink == null) { - Object cache = parent.g.getCache(this); - if (cache == null) { - return; - } - setBufferSink(cache); - getSinkMethods(); - } - - ByteBuffer byteBuffer = natBuffer.getByteBuffer(); - - try { - sinkCopyMethod.invoke(bufferSink, - new Object[] { natBuffer, byteBuffer, bufWidth, bufHeight }); - } catch (Exception e) { - e.printStackTrace(); - } - - natBuffer = null; - } else { // The pixels just read from gstreamer are copied to the pixels array. - if (copyPixels == null) { - return; - } - - if (firstFrame) { - super.init(bufWidth, bufHeight, RGB); - firstFrame = false; - } - - int[] temp = pixels; - pixels = copyPixels; - updatePixels(); - copyPixels = temp; - } - - available = false; - newFrame = true; - } - - - public synchronized void loadPixels() { - super.loadPixels(); - if (useBufferSink) { - if (natBuffer != null) { - // This means that the OpenGL texture hasn't been created so far (the - // video frame not drawn using image()), but the user wants to use the - // pixel array, which we can just get from natBuffer. - IntBuffer buf = natBuffer.getByteBuffer().asIntBuffer(); - buf.rewind(); - buf.get(pixels); - Video.convertToARGB(pixels, width, height); - } else if (sinkGetMethod != null) { - try { - // sinkGetMethod will copy the latest buffer to the pixels array, - // and the pixels will be copied to the texture when the OpenGL - // renderer needs to draw it. - sinkGetMethod.invoke(bufferSink, new Object[] { pixels }); - } catch (Exception e) { - e.printStackTrace(); - } - } - - outdatedPixels = false; - } - } - - - public int get(int x, int y) { - if (outdatedPixels) loadPixels(); - return super.get(x, y); - } - - - protected void getImpl(int sourceX, int sourceY, - int sourceWidth, int sourceHeight, - PImage target, int targetX, int targetY) { - if (outdatedPixels) loadPixels(); - super.getImpl(sourceX, sourceY, sourceWidth, sourceHeight, - target, targetX, targetY); - } - - - //////////////////////////////////////////////////////////// - - // List methods. - - - /** - * ( begin auto-generated from Capture_list.xml ) - * - * Gets a list of all available capture devices such as a camera. Use - * print() to write the information to the text window. - * - * ( end auto-generated ) - * - * @webref capture - * @brief Gets a list of all available capture devices such as a camera - */ - static public String[] list() { - if (devicePropertyName.equals("")) { - return list(sourceElementName, indexPropertyName); - } else { - return list(sourceElementName, devicePropertyName); - } - } - - - static protected String[] list(String sourceName, String propertyName) { - Video.init(); - ArrayList devices = listDevices(sourceName, propertyName); - - ArrayList configList = new ArrayList(); - for (String device: devices) { - ArrayList resolutions = listResolutions(sourceName, propertyName, - device); - if (0 < resolutions.size()) { - for (String res: resolutions) { - configList.add("name=" + device + "," + res); - } - } else { - configList.add("name=" + device); - } - } - - String[] configs = new String[configList.size()]; - for (int i = 0; i < configs.length; i++) { - configs[i] = configList.get(i); - } - - return configs; - } - - - static protected ArrayList listDevices(String sourceName, - String propertyName) { - ArrayList devices = new ArrayList(); - try { - // Using property-probe interface - Element videoSource = ElementFactory.make(sourceName, "Source"); - PropertyProbe probe = PropertyProbe.wrap(videoSource); - if (probe != null) { - Property property = probe.getProperty(propertyName); - if (property != null) { - Object[] values = probe.getValues(property); - if (values != null) { - for (int i = 0; i < values.length; i++) { - if (values[i] instanceof String) { - devices.add((String)values[i]); - } else if (values[i] instanceof Integer) { - devices.add(((Integer)values[i]).toString()); - } - } - } - } - } - } catch (IllegalArgumentException e) { - if (PApplet.platform == LINUX) { - // Linux hack to detect currently connected cameras - // by looking for device files named /dev/video0, /dev/video1, etc. - devices = new ArrayList(); - String dir = "/dev"; - File libPath = new File(dir); - String[] files = libPath.list(); - if (files != null) { - for (int i = 0; i < files.length; i++) { - if (-1 < files[i].indexOf("video")) { - devices.add("/dev/" + files[i]); - } - } - } - } else { - PGraphics.showWarning("The capture plugin does not support " + - "device query!"); - devices = new ArrayList(); - } - } - return devices; - } - - - static protected ArrayList listResolutions(String sourceName, - String propertyName, - Object propertyValue) { - // Creating temporary pipeline so that we can query - // the resolutions supported by the device. - Pipeline testPipeline = new Pipeline("test"); - Element source = ElementFactory.make(sourceName, "source"); - source.set(propertyName, propertyValue); - - BufferDataAppSink sink = new BufferDataAppSink("sink", "", - new BufferDataAppSink.Listener() { - public void bufferFrame(int w, int h, Buffer buffer) { } - }); - testPipeline.addMany(source, sink); - Element.linkMany(source, sink); - - // Play/pause sequence (with getState() calls to to make sure - // all async operations are done) to trigger the capture momentarily - // for the device and obtain its supported resolutions. - testPipeline.play(); - testPipeline.getState(); - testPipeline.pause(); - testPipeline.getState(); - - ArrayList resolutions = new ArrayList(); - addResFromSource(resolutions, source); - - testPipeline.stop(); - testPipeline.getState(); - - if (sink != null) { - sink.removeListener(); - sink.dispose(); - } - - testPipeline.dispose(); - return resolutions; - } - - - static protected void addResFromSource(ArrayList res, Element src) { - if (PApplet.platform == MACOSX && useResMacHack) { - addResFromSourceMacHack(res, src); - } else { - addResFromSourceImpl(res, src); - } - } - - - static protected void addResFromSourceImpl(ArrayList res, - Element src) { - for (Pad pad : src.getPads()) { - Caps caps = pad.getCaps(); - int n = caps.size(); - for (int i = 0; i < n; i++) { - Structure str = caps.getStructure(i); - - if (!str.hasIntField("width") || !str.hasIntField("height")) continue; - - int w = ((Integer)str.getValue("width")).intValue(); - int h = ((Integer)str.getValue("height")).intValue(); - - if (PApplet.platform == WINDOWS) { - // In Windows the getValueList() method doesn't seem to - // return a valid list of fraction values, so working on - // the string representation of the caps structure. - addResFromString(res, str.toString(), w, h); - } else { - addResFromStructure(res, str, w, h); - } - } - } - } - - - // The problem on OSX, at least when using qtkitvideosrc, is that it is only - // possible to obtain a single supported caps, the native maximum, using - // getNegotiatedCaps. getCaps() just gives the maximum possible ranges that - // are useless to build a list of supported resolutions. Using the fact that - // QTKit allows to capture streams at arbitrary resolutions, then the list is - // faked by repeatedly dividing the maximum by 2 until the width becomes too - // small (or not divisible by 2). - static protected void addResFromSourceMacHack(ArrayList res, - Element src) { - for (Pad pad : src.getPads()) { - Caps caps = pad.getNegotiatedCaps(); - int n = caps.size(); - if (0 < n) { - Structure str = caps.getStructure(0); - - if (!str.hasIntField("width") || !str.hasIntField("height")) return; - - int w = ((Integer)str.getValue("width")).intValue(); - int h = ((Integer)str.getValue("height")).intValue(); - while (80 <= w) { - int num = 30; - int den = 1; - try { - Fraction fr = str.getFraction("framerate"); - num = fr.numerator; - den = fr.denominator; - } catch (Exception e) { - } - - res.add(makeResolutionString(w, h, num, den)); - if (num == 30 && den == 1) { - // Adding additional framerates to allow for slower capture. Again, - // QTKit can output frames at arbitrary rates. - res.add(makeResolutionString(w, h, 15, 1)); - res.add(makeResolutionString(w, h, 1, 1)); - } - - if (w % 2 == 0 && h % 2 == 0) { - w /= 2; - h /= 2; - } else { - break; - } - } - } - } - } - - - static protected void addResFromString(ArrayList res, String str, - int w, int h) { - int n0 = str.indexOf("framerate=(fraction)"); - if (-1 < n0) { - String temp = str.substring(n0 + 20, str.length()); - int n1 = temp.indexOf("["); - int n2 = temp.indexOf("]"); - if (-1 < n1 && -1 < n2) { - // A list of fractions enclosed between '[' and ']' - temp = temp.substring(n1 + 1, n2); - String[] fractions = temp.split(","); - for (int k = 0; k < fractions.length; k++) { - String fpsStr = fractions[k].trim(); - res.add(makeResolutionString(w, h, fpsStr)); - } - } else { - // A single fraction - int n3 = temp.indexOf(","); - int n4 = temp.indexOf(";"); - if (-1 < n3 || -1 < n4) { - int n5 = -1; - if (n3 == -1) { - n5 = n4; - } else if (n4 == -1) { - n5 = n3; - } else { - n5 = PApplet.min(n3, n4); - } - - temp = temp.substring(0, n5); - String fpsStr = temp.trim(); - res.add(makeResolutionString(w, h, fpsStr)); - } - } - } - } - - - static protected void addResFromStructure(ArrayList res, - Structure str, int w, int h) { - boolean singleFrac = false; - try { - Fraction fr = str.getFraction("framerate"); - res.add(makeResolutionString(w, h, fr.numerator, fr.denominator)); - singleFrac = true; - } catch (Exception e) { - } - - if (!singleFrac) { - ValueList flist = null; - - try { - flist = str.getValueList("framerate"); - } catch (Exception e) { - } - - if (flist != null) { - // All the framerates are put together, but this is not - // entirely accurate since there might be some of them - // that work only for certain resolutions. - for (int k = 0; k < flist.getSize(); k++) { - Fraction fr = flist.getFraction(k); - res.add(makeResolutionString(w, h, fr.numerator, fr.denominator)); - } - } - } - } - - - static protected String makeResolutionString(int width, int height, int - fpsNumerator, - int fpsDenominator) { - String res = "size=" + width + "x" + height + ",fps=" + fpsNumerator; - if (fpsDenominator != 1) { - res += "/" + fpsDenominator; - } - return res; - } - - - static protected String makeResolutionString(int width, int height, - String fpsStr) { - String res = "size=" + width + "x" + height; - String[] parts = fpsStr.split("/"); - if (parts.length == 2) { - int fpsNumerator = PApplet.parseInt(parts[0]); - int fpsDenominator = PApplet.parseInt(parts[1]); - res += ",fps=" + fpsNumerator; - if (fpsDenominator != 1) { - res += "/" + fpsDenominator; - } - } - return res; - } - - - protected void checkResIsValid() { - ArrayList resolutions = new ArrayList(); - addResFromSource(resolutions, sourceElement); - - boolean valid = resolutions.size() == 0; - for (String res: resolutions) { - if (validRes(res)) { - valid = true; - break; - } - } - - if (!valid) { - String fpsStr = ""; - if (!frameRateString.equals("")) { - fpsStr = ", " + frameRateString + "fps"; - } - throw new RuntimeException("The requested resolution of " + reqWidth + - "x" + reqHeight + fpsStr + - " is not supported by the selected capture " + - "device.\n"); - } - } - - - protected void checkValidDevices(String src) { - ArrayList devices; - if (devicePropertyName.equals("")) { - devices = listDevices(src, indexPropertyName); - } else { - devices = listDevices(src, devicePropertyName); - } - if (devices.size() == 0) { - throw new RuntimeException("There are no capture devices connected to " + - "this computer.\n"); - } - } - - - protected boolean validRes(String res) { - int[] size = getSize(res); - String fps = getFrameRate(res); - return (reqWidth == 0 || reqHeight == 0 || - (size[0] == reqWidth && size[1] == reqHeight)) && - (frameRateString.equals("") || frameRateString.equals(fps)); - } - - - //////////////////////////////////////////////////////////// - - // Initialization methods. - - - // The main initialization here. - protected void initGStreamer(PApplet parent, int rw, int rh, String src, - String idName, Object idValue, - String fps) { - this.parent = parent; - - Video.init(); - checkValidDevices(src); - - // register methods - parent.registerMethod("dispose", this); - parent.registerMethod("post", this); - - setEventHandlerObject(parent); - - pipeline = new Pipeline("Video Capture"); - - frameRateString = fps; - if (frameRateString.equals("")) { - frameRate = -1; - } else { - String[] parts = frameRateString.split("/"); - if (parts.length == 2) { - int fpsDenominator = PApplet.parseInt(parts[0]); - int fpsNumerator = PApplet.parseInt(parts[1]); - frameRate = (float)fpsDenominator / (float)fpsNumerator; - } else if (parts.length == 1) { - frameRateString += "/1"; - frameRate = PApplet.parseFloat(parts[0]); - } else { - frameRateString = ""; - frameRate = -1; - } - } - - reqWidth = rw; - reqHeight = rh; - - sourceName = src; - sourceElement = ElementFactory.make(src, "Source"); - - if (idName != null && !idName.equals("")) { - sourceElement.set(idName, idValue); - } - - bufWidth = bufHeight = 0; - pipelineReady = false; - } - - - protected void initPipeline() { - String whStr = ""; - if (0 < reqWidth && 0 < reqHeight) { - whStr = "width=" + reqWidth + ", height=" + reqHeight; - } else { - PGraphics.showWarning("Resolution information not available, attempting" + - " to open the capture device at 320x240"); - whStr = "width=320, height=240"; - } - - String fpsStr = ""; - if (!frameRateString.equals("")) { - // If the framerate string is empty we left the source element - // to use the default value. - fpsStr = ", framerate=" + frameRateString; - } - - if (bufferSink != null || (Video.useGLBufferSink && parent.g.isGL())) { - useBufferSink = true; - - if (bufferSink != null) { - getSinkMethods(); - } - - if (copyMask == null || copyMask.equals("")) { - initCopyMask(); - } - - String caps = whStr + fpsStr + ", " + copyMask; - - natSink = new BufferDataAppSink("nat", caps, - new BufferDataAppSink.Listener() { - public void bufferFrame(int w, int h, Buffer buffer) { - invokeEvent(w, h, buffer); - } - }); - - natSink.setAutoDisposeBuffer(false); - - // No need for rgbSink.dispose(), because the addMany() doesn't increment the - // refcount of the videoSink object. - - pipeline.addMany(sourceElement, natSink); - Element.linkMany(sourceElement, natSink); - - } else { - Element conv = ElementFactory.make("ffmpegcolorspace", "ColorConverter"); - - Element videofilter = ElementFactory.make("capsfilter", "ColorFilter"); - videofilter.setCaps(new Caps("video/x-raw-rgb, width=" + reqWidth + - ", height=" + reqHeight + - ", bpp=32, depth=24" + fpsStr)); - - rgbSink = new RGBDataAppSink("rgb", - new RGBDataAppSink.Listener() { - public void rgbFrame(int w, int h, IntBuffer buffer) { - invokeEvent(w, h, buffer); - } - }); - - // Setting direct buffer passing in the video sink. - rgbSink.setPassDirectBuffer(Video.passDirectBuffer); - - // No need for rgbSink.dispose(), because the addMany() doesn't increment - // the refcount of the videoSink object. - - pipeline.addMany(sourceElement, conv, videofilter, rgbSink); - Element.linkMany(sourceElement, conv, videofilter, rgbSink); - } - - pipelineReady = true; - newFrame = false; - } - - - /** - * Uses a generic object as handler of the capture. This object should have a - * captureEvent method that receives a Capture argument. This method will - * be called upon a new frame read event. - * - */ - protected void setEventHandlerObject(Object obj) { - eventHandler = obj; - - try { - captureEventMethod = obj.getClass().getMethod("captureEvent", Capture.class); - return; - } catch (Exception e) { - // no such method, or an error.. which is fine, just ignore - } - - // The captureEvent method may be declared as receiving Object, rather - // than Capture. - try { - captureEventMethod = obj.getClass().getMethod("captureEvent", Object.class); - return; - } catch (Exception e) { - // no such method, or an error.. which is fine, just ignore - } - } - - - //////////////////////////////////////////////////////////// - - // Stream event handling. - - - /** - * invokeEvent() and read() are synchronized so that they can not be - * called simultaneously. when they were not synchronized, this caused - * the infamous problematic frame crash. - * found and fixed by Charl P. Botha - */ - protected synchronized void invokeEvent(int w, int h, IntBuffer buffer) { - available = true; - bufWidth = w; - bufHeight = h; - if (copyPixels == null) { - copyPixels = new int[w * h]; - } - buffer.rewind(); - try { - buffer.get(copyPixels); - } catch (BufferUnderflowException e) { - e.printStackTrace(); - copyPixels = null; - return; - } - fireCaptureEvent(); - } - - - protected synchronized void invokeEvent(int w, int h, Buffer buffer) { - available = true; - bufWidth = w; - bufHeight = h; - if (natBuffer != null) { - // To handle the situation where read() is not called in the sketch, - // so that the native buffers are not being sent to the sink, - // and therefore, not disposed by it. - natBuffer.dispose(); - } - natBuffer = buffer; - fireCaptureEvent(); - } - - - private void fireCaptureEvent() { - if (captureEventMethod != null) { - try { - captureEventMethod.invoke(eventHandler, this); - - } catch (Exception e) { - System.err.println("error, disabling captureEvent()"); - e.printStackTrace(); - captureEventMethod = null; - } - } - } - - - //////////////////////////////////////////////////////////// - - // Stream query methods. - - - protected float getSourceFrameRate() { - for (Element sink : pipeline.getSinks()) { - for (Pad pad : sink.getPads()) { - Fraction frameRate = org.gstreamer.Video.getVideoFrameRate(pad); - if (frameRate != null) { - return (float)frameRate.toDouble(); - } - } - } - return 0; - } - - - protected String getName(String config) { - String name = ""; - String[] parts = PApplet.split(config, ','); - for (String part: parts) { - if (-1 < part.indexOf("name")) { - String[] values = PApplet.split(part, '='); - if (0 < values.length) { - name = values[1]; - } - } - } - return name; - } - - - protected int[] getSize(String config) { - int[] wh = {0, 0}; - String[] parts = PApplet.split(config, ','); - for (String part: parts) { - if (-1 < part.indexOf("size")) { - String[] values = PApplet.split(part, '='); - if (0 < values.length) { - String[] whstr = PApplet.split(values[1], 'x'); - if (whstr.length == 2) { - wh[0] = PApplet.parseInt(whstr[0]); - wh[1] = PApplet.parseInt(whstr[1]); - } - } - } - } - return wh; - } - - - protected String getFrameRate(String config) { - String fps = ""; - String[] parts = PApplet.split(config, ','); - for (String part: parts) { - if (-1 < part.indexOf("fps")) { - String[] values = PApplet.split(part, '='); - if (0 < values.length) { - fps = values[1]; - if (fps.indexOf("/") == -1) { - fps += "/1"; - } - } - } - } - return fps; - } - - - //////////////////////////////////////////////////////////// - - // Buffer source interface. - - - /** - * Sets the object to use as destination for the frames read from the stream. - * The color conversion mask is automatically set to the one required to - * copy the frames to OpenGL. - * - * NOTE: This is not official API and may/will be removed at any time. - * - * @param Object dest - */ - public void setBufferSink(Object sink) { - bufferSink = sink; - initCopyMask(); - } - - - /** - * Sets the object to use as destination for the frames read from the stream. - * - * NOTE: This is not official API and may/will be removed at any time. - * - * @param Object dest - * @param String mask - */ - public void setBufferSink(Object sink, String mask) { - bufferSink = sink; - copyMask = mask; - } - - - /** - * NOTE: This is not official API and may/will be removed at any time. - */ - public boolean hasBufferSink() { - return bufferSink != null; - } - - - /** - * NOTE: This is not official API and may/will be removed at any time. - */ - public synchronized void disposeBuffer(Object buf) { - ((Buffer)buf).dispose(); - } - - - protected void getSinkMethods() { - try { - sinkCopyMethod = bufferSink.getClass().getMethod("copyBufferFromSource", - new Class[] { Object.class, ByteBuffer.class, int.class, int.class }); - } catch (Exception e) { - throw new RuntimeException("Capture: provided sink object doesn't have " + - "a copyBufferFromSource method."); - } - - try { - sinkSetMethod = bufferSink.getClass().getMethod("setBufferSource", - new Class[] { Object.class }); - sinkSetMethod.invoke(bufferSink, new Object[] { this }); - } catch (Exception e) { - throw new RuntimeException("Capture: provided sink object doesn't have "+ - "a setBufferSource method."); - } - - try { - sinkDisposeMethod = bufferSink.getClass().getMethod("disposeSourceBuffer", - new Class[] { }); - } catch (Exception e) { - throw new RuntimeException("Capture: provided sink object doesn't have " + - "a disposeSourceBuffer method."); - } - - try { - sinkGetMethod = bufferSink.getClass().getMethod("getBufferPixels", - new Class[] { int[].class }); - } catch (Exception e) { - throw new RuntimeException("Capture: provided sink object doesn't have " + - "a getBufferPixels method."); - } - } - - - protected void initCopyMask() { - if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { - copyMask = "red_mask=(int)0xFF000000, green_mask=(int)0xFF0000, blue_mask=(int)0xFF00"; - } else { - copyMask = "red_mask=(int)0xFF, green_mask=(int)0xFF00, blue_mask=(int)0xFF0000"; - } - } - - - public synchronized void post() { - if (useBufferSink && sinkDisposeMethod != null) { - try { - sinkDisposeMethod.invoke(bufferSink, new Object[] {}); - } catch (Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/java/libraries/video/src/processing/video/LibraryLoader.java b/java/libraries/video/src/processing/video/LibraryLoader.java deleted file mode 100644 index befa4c6d4..000000000 --- a/java/libraries/video/src/processing/video/LibraryLoader.java +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2011-12 Ben Fry and Casey Reas - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.video; - -import java.util.HashMap; -import java.util.Map; - -import com.sun.jna.Library; -import com.sun.jna.Native; -import com.sun.jna.Platform; - -/** - * This class loads the gstreamer native libraries. - * By Andres Colubri - * Based on code by Tal Shalif - * - */ -public class LibraryLoader { - - public interface DummyLibrary extends Library { - } - - private static LibraryLoader instance; - - static final Object[][] WINDOWS_DEPENDENCIES = { - // glib libraries - { "gio-2.0", new String[] {}, true }, - { "glib-2.0", new String[] {}, true }, - { "gmodule-2.0", new String[] {}, true }, - { "gobject-2.0", new String[] {}, true }, - { "gthread-2.0", new String[] {}, true }, - - // Core gstreamer libraries - { "gstapp-0.10", new String[] {}, true }, - { "gstaudio-0.10", new String[] {}, true }, - { "gstbase-0.10", new String[] {}, true }, - { "gstbasevideo-0.10", new String[] {}, true }, - { "gstcdda-0.10", new String[] {}, true }, - { "gstcontroller-0.10", new String[] {}, true }, - { "gstdataprotocol-0.10", new String[] {}, true }, - { "gstfft-0.10", new String[] {}, true }, - { "gstinterfaces-0.10", new String[] {}, true }, - { "gstnet-0.10", new String[] {}, true }, - { "gstnetbuffer-0.10", new String[] {}, true }, - { "gstpbutils-0.10", new String[] {}, true }, - { "gstphotography-0.10", new String[] {}, true }, - { "gstreamer-0.10", new String[] {}, true }, - { "gstriff-0.10", new String[] {}, true }, - { "gstrtp-0.10", new String[] {}, true }, - { "gstrtsp-0.10", new String[] {}, true }, - { "gstsdp-0.10", new String[] {}, true }, - { "gstsignalprocessor-0.10", new String[] {}, true }, - { "gsttag-0.10", new String[] {}, true }, - { "gstvideo-0.10", new String[] {}, true }, - - // External libraries - { "libiconv-2", new String[] {}, false }, - { "libintl-8", new String[] {}, false }, - { "libjpeg-8", new String[] {}, false }, - { "libogg-0", new String[] {}, false }, - { "liborc-0.4-0", new String[] {}, false }, - { "liborc-test-0.4-0", new String[] {}, false }, - { "libpng14-14", new String[] {}, false }, - { "libtheora-0", new String[] {}, false }, - { "libtheoradec-1", new String[] {}, false }, - { "libtheoraenc-1", new String[] {}, false }, - { "libvorbis-0", new String[] {}, false }, - { "libvorbisenc-2", new String[] {}, false }, - { "libvorbisfile-3", new String[] {}, false }, - { "libxml2-2", new String[] {}, false }, - { "zlib1", new String[] {}, false } }; - - static final Object[][] MACOSX_DEPENDENCIES = { - { "gstbase-0.10", new String[] { "gstreamer-0.10" }, true }, - { "gstinterfaces-0.10", new String[] { "gstreamer-0.10" }, true }, - { "gstcontroller-0.10", new String[] { "gstreamer-0.10" }, true }, - { "gstaudio-0.10", new String[] { "gstbase-0.10" }, true }, - { "gstvideo-0.10", new String[] { "gstbase-0.10" }, true } }; - - static final Object[][] DEFAULT_DEPENDENCIES = { - { "gstreamer-0.10", new String[] {}, true }, - { "gstbase-0.10", new String[] { "gstreamer-0.10" }, true }, - { "gstinterfaces-0.10", new String[] { "gstreamer-0.10" }, true }, - { "gstcontroller-0.10", new String[] { "gstreamer-0.10" }, true }, - { "gstaudio-0.10", new String[] { "gstbase-0.10" }, true }, - { "gstvideo-0.10", new String[] { "gstbase-0.10" }, true }, }; - - - static final Object[][] dependencies = - Platform.isWindows() ? WINDOWS_DEPENDENCIES : - Platform.isMac() ? MACOSX_DEPENDENCIES : DEFAULT_DEPENDENCIES; - - - private static final Map loadedMap = - new HashMap(); - - - private static final int RECURSIVE_LOAD_MAX_DEPTH = 5; - - - private LibraryLoader() { - } - - - private void preLoadLibs() { - for (Object[] a : dependencies) { - load(a[0].toString(), DummyLibrary.class, true, 0, (Boolean) a[2]); - } - } - - - private String[] findDeps(String name) { - - for (Object[] a : dependencies) { - if (name.equals(a[0])) { - - return (String[]) a[1]; - } - } - - return new String[] {}; // library dependancy load chain unspecified - - // probably client call - } - - - public Object load(String name, Class clazz, boolean reqLib) { - return load(name, clazz, true, 0, reqLib); - } - - - private Object load(String name, Class clazz, boolean forceReload, - int depth, boolean reqLib) { - - assert depth < RECURSIVE_LOAD_MAX_DEPTH : String.format( - "recursive max load depth %s has been exceeded", depth); - - Object library = loadedMap.get(name); - - if (null == library || forceReload) { - - // Logger.getAnonymousLogger().info(String.format("%" + ((depth + 1) * 2) - // + "sloading %s", "->", name)); - - try { - String[] deps = findDeps(name); - - for (String lib : deps) { - load(lib, DummyLibrary.class, false, depth + 1, reqLib); - } - - library = loadLibrary(name, clazz, reqLib); - - if (library != null) { - loadedMap.put(name, library); - } - } catch (Exception e) { - if (reqLib) - throw new RuntimeException(String.format( - "can not load required library %s", name, e)); - else - System.out.println(String.format("can not load library %s", name, e)); - } - } - - return library; - } - - - private static Object loadLibrary(String name, Class clazz, - boolean reqLib) { - - // Logger.getAnonymousLogger().info(String.format("loading %s", name)); - - String[] nameFormats; - nameFormats = Platform.isWindows() ? new String[] { "lib%s", "lib%s-0", - "%s" } : new String[] { "%s-0", "%s" }; - - UnsatisfiedLinkError linkError = null; - - for (String fmt : nameFormats) { - try { - String s = String.format(fmt, name); - //System.out.println("Trying to load library file " + s); - Object obj = Native.loadLibrary(s, clazz); - //System.out.println("Loaded library " + s + " succesfully!"); - return obj; - } catch (UnsatisfiedLinkError ex) { - linkError = ex; - } - } - - if (reqLib) - throw new UnsatisfiedLinkError( - String.format( - "can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " + - "-Djna.library.path=%s. Last error:%s", - name, System.getProperty("jna.library.path"), linkError)); - else { - System.out.println(String.format( - "can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " + - "-Djna.library.path=%s. Last error:%s", - name, System.getProperty("jna.library.path"), linkError)); - return null; - } - } - - - public static synchronized LibraryLoader getInstance() { - if (null == instance) { - instance = new LibraryLoader(); - instance.preLoadLibs(); - } - return instance; - } -} diff --git a/java/libraries/video/src/processing/video/LibraryPath.java b/java/libraries/video/src/processing/video/LibraryPath.java deleted file mode 100644 index ccabe2467..000000000 --- a/java/libraries/video/src/processing/video/LibraryPath.java +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2011-12 Ben Fry and Casey Reas - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.video; - -import java.net.URL; - -import com.sun.jna.Platform; - -class LibraryPath { - // This method returns the folder inside which the gstreamer library folder - // is located. - String get() { - URL url = this.getClass().getResource("LibraryPath.class"); - if (url != null) { - // Convert URL to string, taking care of spaces represented by the "%20" - // string. - String path = url.toString().replace("%20", " "); - int n0 = path.indexOf('/'); - - int n1 = -1; - - if (Platform.isLinux()) { - return ""; - } else { - n1 = path.indexOf("video.jar"); - if (Platform.isWindows()) { - // In Windows, path string starts with "jar file/C:/..." - // so the substring up to the first / is removed. - n0++; - } - } - - if ((-1 < n0) && (-1 < n1)) { - return path.substring(n0, n1); - } else { - return ""; - } - } - return ""; - } -} \ No newline at end of file diff --git a/java/libraries/video/src/processing/video/Movie.java b/java/libraries/video/src/processing/video/Movie.java deleted file mode 100644 index 958be1109..000000000 --- a/java/libraries/video/src/processing/video/Movie.java +++ /dev/null @@ -1,1026 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-12 Ben Fry and Casey Reas - The previous version of this code was developed by Hernando Barragan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.video; - -import processing.core.*; - -import java.awt.Dimension; -import java.io.*; -import java.net.URI; -import java.nio.*; -import java.util.concurrent.TimeUnit; -import java.lang.reflect.*; - -import org.gstreamer.*; -import org.gstreamer.Buffer; -import org.gstreamer.elements.*; - - -/** - * ( begin auto-generated from Movie.xml ) - * - * Datatype for storing and playing movies in Apple's QuickTime format. - * Movies must be located in the sketch's data directory or an accessible - * place on the network to load without an error. - * - * ( end auto-generated ) - * - * @webref video - * @usage application - */ -public class Movie extends PImage implements PConstants { - public static String[] supportedProtocols = { "http" }; - public float frameRate; - public String filename; - public PlayBin2 playbin; - - protected boolean playing = false; - protected boolean paused = false; - protected boolean repeat = false; - - protected float rate; - protected int bufWidth; - protected int bufHeight; - protected float volume; - - protected Method movieEventMethod; - protected Object eventHandler; - - protected boolean available; - protected boolean sinkReady; - protected boolean newFrame; - - protected RGBDataAppSink rgbSink = null; - protected int[] copyPixels = null; - - protected boolean firstFrame = true; - protected boolean seeking = false; - - protected boolean useBufferSink = false; - protected boolean outdatedPixels = true; - protected Object bufferSink; - protected Method sinkCopyMethod; - protected Method sinkSetMethod; - protected Method sinkDisposeMethod; - protected Method sinkGetMethod; - protected String copyMask; - protected Buffer natBuffer = null; - protected BufferDataAppSink natSink = null; - - - /** - * Creates an instance of GSMovie loading the movie from filename. - * - * @param parent PApplet - * @param filename String - */ - public Movie(PApplet parent, String filename) { - super(0, 0, RGB); - initGStreamer(parent, filename); - } - - - /** - * Disposes all the native resources associated to this movie. - * - * NOTE: This is not official API and may/will be removed at any time. - */ - public void dispose() { - if (playbin != null) { - try { - if (playbin.isPlaying()) { - playbin.stop(); - playbin.getState(); - } - } catch (Exception e) { - e.printStackTrace(); - } - - pixels = null; - - copyPixels = null; - if (rgbSink != null) { - rgbSink.removeListener(); - rgbSink.dispose(); - rgbSink = null; - } - - natBuffer = null; - if (natSink != null) { - natSink.removeListener(); - natSink.dispose(); - natSink = null; - } - - playbin.dispose(); - playbin = null; - - parent.g.removeCache(this); - parent.unregisterMethod("dispose", this); - parent.unregisterMethod("post", this); - } - } - - - /** - * Finalizer of the class. - */ - protected void finalize() throws Throwable { - try { - dispose(); - } finally { - super.finalize(); - } - } - - - /** - * ( begin auto-generated from Movie_frameRate.xml ) - * - * Sets how often frames are read from the movie. Setting the fps - * parameter to 4, for example, will cause 4 frames to be read per second. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @param ifps speed of the movie in frames per second - * @brief Sets the target frame rate - */ - public void frameRate(float ifps) { - if (seeking) return; - - // We calculate the target ratio in the case both the - // current and target framerates are valid (greater than - // zero), otherwise we leave it as 1. - float f = (0 < ifps && 0 < frameRate) ? ifps / frameRate : 1; - - if (playing) { - playbin.pause(); - playbin.getState(); - } - - long t = playbin.queryPosition(TimeUnit.NANOSECONDS); - - boolean res; - long start, stop; - if (rate > 0) { - start = t; - stop = -1; - } else { - start = 0; - stop = t; - } - - res = playbin.seek(rate * f, Format.TIME, SeekFlags.FLUSH, - SeekType.SET, start, SeekType.SET, stop); - playbin.getState(); - - if (!res) { - PGraphics.showWarning("Seek operation failed."); - } - - if (playing) { - playbin.play(); - } - - frameRate = ifps; - - // getState() will wait until any async state change - // (like seek in this case) has completed - seeking = true; - playbin.getState(); - seeking = false; - } - - - /** - * ( begin auto-generated from Movie_speed.xml ) - * - * Sets the relative playback speed of the movie. The rate - * parameters sets the speed where 2.0 will play the movie twice as fast, - * 0.5 will play at half the speed, and -1 will play the movie in normal - * speed in reverse. - * - * ( end auto-generated ) - * - - * @webref movie - - * @usage web_application - * @param irate speed multiplier for movie playback - * @brief Sets the relative playback speed - */ - public void speed(float irate) { - // If the frameRate() method is called continuously with very similar - // rate values, playback might become sluggish. This condition attempts - // to take care of that. - if (PApplet.abs(rate - irate) > 0.1) { - rate = irate; - frameRate(frameRate); // The framerate is the same, but the rate (speed) could be different. - } - } - - - /** - * ( begin auto-generated from Movie_duration.xml ) - * - * Returns the length of the movie in seconds. If the movie is 1 minute and - * 20 seconds long the value returned will be 80.0. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Returns length of movie in seconds - */ - public float duration() { - float sec = playbin.queryDuration().toSeconds(); - float nanosec = playbin.queryDuration().getNanoSeconds(); - return sec + Video.nanoSecToSecFrac(nanosec); - } - - - /** - * ( begin auto-generated from Movie_time.xml ) - * - * Returns the location of the playback head in seconds. For example, if - * the movie has been playing for 4 seconds, the number 4.0 will be returned. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Returns location of playback head in units of seconds - */ - public float time() { - float sec = playbin.queryPosition().toSeconds(); - float nanosec = playbin.queryPosition().getNanoSeconds(); - return sec + Video.nanoSecToSecFrac(nanosec); - } - - - /** - * ( begin auto-generated from Movie_jump.xml ) - * - * Jumps to a specific location within a movie. The parameter where - * is in terms of seconds. For example, if the movie is 12.2 seconds long, - * calling jump(6.1) would go to the middle of the movie. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @param where position to jump to specified in seconds - * @brief Jumps to a specific location - */ - public void jump(float where) { - if (seeking) return; - - if (!sinkReady) { - initSink(); - } - - // Round the time to a multiple of the source framerate, in - // order to eliminate stutter. Suggested by Daniel Shiffman - float fps = getSourceFrameRate(); - int frame = (int)(where * fps); - where = frame / fps; - - boolean res; - long pos = Video.secToNanoLong(where); - - res = playbin.seek(rate, Format.TIME, SeekFlags.FLUSH, - SeekType.SET, pos, SeekType.NONE, -1); - - if (!res) { - PGraphics.showWarning("Seek operation failed."); - } - - // getState() will wait until any async state change - // (like seek in this case) has completed - seeking = true; - playbin.getState(); - seeking = false; - /* - if (seeking) return; // don't seek again until the current seek operation is done. - - if (!sinkReady) { - initSink(); - } - - // Round the time to a multiple of the source framerate, in - // order to eliminate stutter. Suggested by Daniel Shiffman - float fps = getSourceFrameRate(); - int frame = (int)(where * fps); - final float seconds = frame / fps; - - // Put the seek operation inside a thread to avoid blocking the main - // animation thread - Thread seeker = new Thread() { - @Override - public void run() { - long pos = Video.secToNanoLong(seconds); - boolean res = playbin.seek(rate, Format.TIME, SeekFlags.FLUSH, - SeekType.SET, pos, SeekType.NONE, -1); - if (!res) { - PGraphics.showWarning("Seek operation failed."); - } - - // getState() will wait until any async state change - // (like seek in this case) has completed - seeking = true; - playbin.getState(); - seeking = false; - } - }; - seeker.start(); - */ - } - - - /** - * ( begin auto-generated from Movie_available.xml ) - * - * Returns "true" when a new movie frame is available to read. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Returns "true" when a new movie frame is available to read. - */ - public boolean available() { - return available; - } - - - /** - * ( begin auto-generated from Movie_play.xml ) - * - * Plays a movie one time and stops at the last frame. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Plays movie one time and stops at the last frame - */ - public void play() { - if (seeking) return; - - if (!sinkReady) { - initSink(); - } - - playing = true; - paused = false; - playbin.play(); - playbin.getState(); - } - - - /** - * ( begin auto-generated from Movie_loop.xml ) - * - * Plays a movie continuously, restarting it when it's over. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Plays a movie continuously, restarting it when it's over. - */ - public void loop() { - if (seeking) return; - - repeat = true; - play(); - } - - - /** - * ( begin auto-generated from Movie_noLoop.xml ) - * - * If a movie is looping, calling noLoop() will cause it to play until the - * end and then stop on the last frame. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Stops the movie from looping - */ - public void noLoop() { - if (seeking) return; - - if (!sinkReady) { - initSink(); - } - - repeat = false; - } - - - /** - * ( begin auto-generated from Movie_pause.xml ) - * - * Pauses a movie during playback. If a movie is started again with play(), - * it will continue from where it was paused. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Pauses the movie - */ - public void pause() { - if (seeking) return; - - if (!sinkReady) { - initSink(); - } - - playing = false; - paused = true; - playbin.pause(); - playbin.getState(); - } - - - /** - * ( begin auto-generated from Movie_stop.xml ) - * - * Stops a movie from continuing. The playback returns to the beginning so - * when a movie is played, it will begin from the beginning. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Stops the movie - */ - public void stop() { - if (seeking) return; - - if (!sinkReady) { - initSink(); - } - - if (playing) { - jump(0); - playing = false; - } - paused = false; - playbin.stop(); - playbin.getState(); - } - - - /** - * ( begin auto-generated from Movie_read.xml ) - * - * Reads the current frame of the movie. - * - * ( end auto-generated ) - * - * @webref movie - * @usage web_application - * @brief Reads the current frame - */ - public synchronized void read() { - if (frameRate < 0) { - // Framerate not set yet, so we obtain from stream, - // which is already playing since we are in read(). - frameRate = getSourceFrameRate(); - } - if (volume < 0) { - // Idem for volume - volume = (float)playbin.getVolume(); - } - - if (useBufferSink) { // The native buffer from gstreamer is copied to the buffer sink. - outdatedPixels = true; - if (natBuffer == null) { - return; - } - - if (firstFrame) { - super.init(bufWidth, bufHeight, ARGB); - firstFrame = false; - } - - if (bufferSink == null) { - Object cache = parent.g.getCache(this); - if (cache == null) { - return; - } - setBufferSink(cache); - getSinkMethods(); - } - - ByteBuffer byteBuffer = natBuffer.getByteBuffer(); - - try { - sinkCopyMethod.invoke(bufferSink, new Object[] { natBuffer, byteBuffer, bufWidth, bufHeight }); - } catch (Exception e) { - e.printStackTrace(); - } - - natBuffer = null; - } else { // The pixels just read from gstreamer are copied to the pixels array. - if (copyPixels == null) { - return; - } - - if (firstFrame) { - super.init(bufWidth, bufHeight, RGB); - firstFrame = false; - } - - int[] temp = pixels; - pixels = copyPixels; - updatePixels(); - copyPixels = temp; - } - - available = false; - newFrame = true; - } - - - /** - * Change the volume. Values are from 0 to 1. - * - * @param float v - */ - public void volume(float v) { - if (playing && PApplet.abs(volume - v) > 0.001f) { - playbin.setVolume(v); - volume = v; - } - } - - - public synchronized void loadPixels() { - super.loadPixels(); - if (useBufferSink) { - if (natBuffer != null) { - // This means that the OpenGL texture hasn't been created so far (the - // video frame not drawn using image()), but the user wants to use the - // pixel array, which we can just get from natBuffer. - IntBuffer buf = natBuffer.getByteBuffer().asIntBuffer(); - buf.rewind(); - buf.get(pixels); - Video.convertToARGB(pixels, width, height); - } else if (sinkGetMethod != null) { - try { - // sinkGetMethod will copy the latest buffer to the pixels array, - // and the pixels will be copied to the texture when the OpenGL - // renderer needs to draw it. - sinkGetMethod.invoke(bufferSink, new Object[] { pixels }); - } catch (Exception e) { - e.printStackTrace(); - } - } - - outdatedPixels = false; - } - } - - - public int get(int x, int y) { - if (outdatedPixels) loadPixels(); - return super.get(x, y); - } - - - protected void getImpl(int sourceX, int sourceY, - int sourceWidth, int sourceHeight, - PImage target, int targetX, int targetY) { - if (outdatedPixels) loadPixels(); - super.getImpl(sourceX, sourceY, sourceWidth, sourceHeight, - target, targetX, targetY); - } - - - //////////////////////////////////////////////////////////// - - // Initialization methods. - - - protected void initGStreamer(PApplet parent, String filename) { - this.parent = parent; - playbin = null; - - File file; - - Video.init(); - - // first check to see if this can be read locally from a file. - try { - try { - // first try a local file using the dataPath. usually this will - // work ok, but sometimes the dataPath is inside a jar file, - // which is less fun, so this will crap out. - file = new File(parent.dataPath(filename)); - if (file.exists()) { - playbin = new PlayBin2("Movie Player"); - playbin.setInputFile(file); - } - } catch (Exception e) { - } // ignored - - // read from a file just hanging out in the local folder. - // this might happen when the video library is used with some - // other application, or the person enters a full path name - if (playbin == null) { - try { - file = new File(filename); - if (file.exists()) { - playbin = new PlayBin2("Movie Player"); - playbin.setInputFile(file); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (playbin == null) { - // Try network read... - for (int i = 0; i < supportedProtocols.length; i++) { - if (filename.startsWith(supportedProtocols[i] + "://")) { - try { - playbin = new PlayBin2("Movie Player"); - playbin.setURI(URI.create(filename)); - break; - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - } catch (SecurityException se) { - // online, whups. catch the security exception out here rather than - // doing it three times (or whatever) for each of the cases above. - } - - if (playbin == null) { - parent.die("Could not load movie file " + filename, null); - } - - // we've got a valid movie! let's rock. - try { - this.filename = filename; // for error messages - - // register methods - parent.registerMethod("dispose", this); - parent.registerMethod("post", this); - - setEventHandlerObject(parent); - - rate = 1.0f; - frameRate = -1; - volume = -1; - sinkReady = false; - bufWidth = bufHeight = 0; - } catch (Exception e) { - e.printStackTrace(); - } - } - - - /** - * Uses a generic object as handler of the movie. This object should have a - * movieEvent method that receives a GSMovie argument. This method will - * be called upon a new frame read event. - * - */ - protected void setEventHandlerObject(Object obj) { - eventHandler = obj; - - try { - movieEventMethod = eventHandler.getClass().getMethod("movieEvent", Movie.class); - return; - } catch (Exception e) { - // no such method, or an error... which is fine, just ignore - } - - // movieEvent can alternatively be defined as receiving an Object, to allow - // Processing mode implementors to support the video library without linking - // to it at build-time. - try { - movieEventMethod = eventHandler.getClass().getMethod("movieEvent", Object.class); - } catch (Exception e) { - // no such method, or an error... which is fine, just ignore - } - } - - - protected void initSink() { - if (bufferSink != null || (Video.useGLBufferSink && parent.g.isGL())) { - useBufferSink = true; - - if (bufferSink != null) { - getSinkMethods(); - } - - if (copyMask == null || copyMask.equals("")) { - initCopyMask(); - } - - natSink = new BufferDataAppSink("nat", copyMask, - new BufferDataAppSink.Listener() { - public void bufferFrame(int w, int h, Buffer buffer) { - invokeEvent(w, h, buffer); - } - }); - - natSink.setAutoDisposeBuffer(false); - playbin.setVideoSink(natSink); - // The setVideoSink() method sets the videoSink as a property of the - // PlayBin, which increments the refcount of the videoSink element. - // Disposing here once to decrement the refcount. - natSink.dispose(); - } else { - rgbSink = new RGBDataAppSink("rgb", - new RGBDataAppSink.Listener() { - public void rgbFrame(int w, int h, IntBuffer buffer) { - invokeEvent(w, h, buffer); - } - }); - - // Setting direct buffer passing in the video sink. - rgbSink.setPassDirectBuffer(Video.passDirectBuffer); - playbin.setVideoSink(rgbSink); - // The setVideoSink() method sets the videoSink as a property of the - // PlayBin, which increments the refcount of the videoSink element. - // Disposing here once to decrement the refcount. - rgbSink.dispose(); - } - - // Creating bus to handle end-of-stream event. - Bus bus = playbin.getBus(); - bus.connect(new Bus.EOS() { - public void endOfStream(GstObject element) { - eosEvent(); - } - }); - - sinkReady = true; - newFrame = false; - } - - - //////////////////////////////////////////////////////////// - - // Stream event handling. - - - protected synchronized void invokeEvent(int w, int h, IntBuffer buffer) { - available = true; - bufWidth = w; - bufHeight = h; - - if (copyPixels == null) { - copyPixels = new int[w * h]; - } - buffer.rewind(); - try { - buffer.get(copyPixels); - } catch (BufferUnderflowException e) { - e.printStackTrace(); - copyPixels = null; - return; - } - - if (playing) { - fireMovieEvent(); - } - } - - protected synchronized void invokeEvent(int w, int h, Buffer buffer) { - available = true; - bufWidth = w; - bufHeight = h; - if (natBuffer != null) { - // To handle the situation where read() is not called in the sketch, so - // that the native buffers are not being sent to the sinke, and therefore, not disposed - // by it. - natBuffer.dispose(); - } - natBuffer = buffer; - - if (playing) { - fireMovieEvent(); - } - } - - private void fireMovieEvent() { - // Creates a movieEvent. - if (movieEventMethod != null) { - try { - movieEventMethod.invoke(eventHandler, this); - } catch (Exception e) { - System.err.println("error, disabling movieEvent() for " + filename); - e.printStackTrace(); - movieEventMethod = null; - } - } - } - - protected void eosEvent() { - if (repeat) { - if (0 < rate) { - // Playing forward, so we return to the beginning - jump(0); - } else { - // Playing backwards, so we go to the end. - jump(duration()); - } - - // The rate is set automatically to 1 when restarting the - // stream, so we need to call frameRate in order to reset - // to the latest fps rate. - frameRate(frameRate); - } else { - playing = false; - } - } - - - //////////////////////////////////////////////////////////// - - // Stream query methods. - - - /** - * Get the height of the source video. Note: calling this method repeatedly - * can slow down playback performance. - * - * @return int - */ - protected int getSourceHeight() { - Dimension dim = playbin.getVideoSize(); - if (dim != null) { - return dim.height; - } else { - return 0; - } - } - - - /** - * Get the original framerate of the source video. Note: calling this method - * repeatedly can slow down playback performance. - * - * @return float - */ - protected float getSourceFrameRate() { - return (float)playbin.getVideoSinkFrameRate(); - } - - - /** - * Get the width of the source video. Note: calling this method repeatedly - * can slow down playback performance. - * - * @return int - */ - protected int getSourceWidth() { - Dimension dim = playbin.getVideoSize(); - if (dim != null) { - return dim.width; - } else { - return 0; - } - } - - - //////////////////////////////////////////////////////////// - - // Buffer source interface. - - - /** - * Sets the object to use as destination for the frames read from the stream. - * The color conversion mask is automatically set to the one required to - * copy the frames to OpenGL. - * - * NOTE: This is not official API and may/will be removed at any time. - * - * @param Object dest - */ - public void setBufferSink(Object sink) { - bufferSink = sink; - initCopyMask(); - } - - - /** - * Sets the object to use as destination for the frames read from the stream. - * - * NOTE: This is not official API and may/will be removed at any time. - * - * @param Object dest - * @param String mask - */ - public void setBufferSink(Object sink, String mask) { - bufferSink = sink; - copyMask = mask; - } - - - /** - * NOTE: This is not official API and may/will be removed at any time. - */ - public boolean hasBufferSink() { - return bufferSink != null; - } - - - /** - * NOTE: This is not official API and may/will be removed at any time. - */ - public synchronized void disposeBuffer(Object buf) { - ((Buffer)buf).dispose(); - } - - - protected void getSinkMethods() { - try { - sinkCopyMethod = bufferSink.getClass().getMethod("copyBufferFromSource", - new Class[] { Object.class, ByteBuffer.class, int.class, int.class }); - } catch (Exception e) { - throw new RuntimeException("Movie: provided sink object doesn't have a " + - "copyBufferFromSource method."); - } - - try { - sinkSetMethod = bufferSink.getClass().getMethod("setBufferSource", - new Class[] { Object.class }); - sinkSetMethod.invoke(bufferSink, new Object[] { this }); - } catch (Exception e) { - throw new RuntimeException("Movie: provided sink object doesn't have a " + - "setBufferSource method."); - } - - try { - sinkDisposeMethod = bufferSink.getClass().getMethod("disposeSourceBuffer", - new Class[] { }); - } catch (Exception e) { - throw new RuntimeException("Movie: provided sink object doesn't have " + - "a disposeSourceBuffer method."); - } - - try { - sinkGetMethod = bufferSink.getClass().getMethod("getBufferPixels", - new Class[] { int[].class }); - } catch (Exception e) { - throw new RuntimeException("Movie: provided sink object doesn't have " + - "a getBufferPixels method."); - } - } - - - protected void initCopyMask() { - if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { - copyMask = "red_mask=(int)0xFF000000, green_mask=(int)0xFF0000, blue_mask=(int)0xFF00"; - } else { - copyMask = "red_mask=(int)0xFF, green_mask=(int)0xFF00, blue_mask=(int)0xFF0000"; - } - } - - - public synchronized void post() { - if (useBufferSink && sinkDisposeMethod != null) { - try { - sinkDisposeMethod.invoke(bufferSink, new Object[] {}); - } catch (Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/java/libraries/video/src/processing/video/Video.java b/java/libraries/video/src/processing/video/Video.java deleted file mode 100644 index 1eaa0e090..000000000 --- a/java/libraries/video/src/processing/video/Video.java +++ /dev/null @@ -1,229 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2011-12 Ben Fry and Casey Reas - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.video; - -import org.gstreamer.*; -import processing.core.PApplet; -import processing.core.PConstants; - -import java.io.File; -import java.nio.ByteOrder; -import java.util.List; - -/** - * This class contains some basic functions used by the rest of the classes in - * this library. - */ -public class Video implements PConstants { - // Path that the video library will use to load the GStreamer base libraries - // and plugins from. They can be passed from the application using the - // gstreamer.library.path and gstreamer.plugin.path system variables (see - // comments in initImpl() below). - protected static String gstreamerLibPath = ""; - protected static String gstreamerPluginPath = ""; - - // Direct buffer pass enabled by default. With this mode enabled, no new - // buffers are created and disposed by the GC in each frame (thanks to Octavi - // Estape for suggesting this improvement) which should help performance in - // most situations. - protected static boolean passDirectBuffer = true; - - // OpenGL texture used as buffer sink by default, when the renderer is - // GL-based. This can improve performance significantly, since the video - // frames are automatically copied into the texture without passing through - // the pixels arrays, as well as having the color conversion into RGBA handled - // natively by GStreamer. - protected static boolean useGLBufferSink = true; - - protected static boolean defaultGLibContext = false; - - protected static long INSTANCES_COUNT = 0; - - protected static int bitsJVM; - static { - bitsJVM = PApplet.parseInt(System.getProperty("sun.arch.data.model")); - } - - - static protected void init() { - if (INSTANCES_COUNT == 0) { - initImpl(); - } - INSTANCES_COUNT++; - } - - - static protected void restart() { - removePlugins(); - Gst.deinit(); - initImpl(); - } - - - static protected void initImpl() { - // The location of the GStreamer base libraries can be passed from the - // application to the vide library via a system variable. In Eclipse, add to - // "VM Arguments" in "Run Configurations" the following line: - // -Dgstreamer.library.path=path - String libPath = System.getProperty("gstreamer.library.path"); - if (libPath != null) { - gstreamerLibPath = libPath; - - // If the GStreamer installation referred by gstreamer.library.path is not - // a system installation, then the path containing the plugins needs to be - // specified separately, otherwise the plugins will be automatically - // loaded from the default location. The system property for the plugin - // path is "gstreamer.plugin.path" - String pluginPath = System.getProperty("gstreamer.plugin.path"); - if (pluginPath != null) { - gstreamerPluginPath = pluginPath; - } - } else { - // Paths are build automatically from the curren location of the video - // library. - if (PApplet.platform == LINUX) { - buildLinuxPaths(); - } else if (PApplet.platform == WINDOWS) { - buildWindowsPaths(); - } else if (PApplet.platform == MACOSX) { - buildMacOSXPaths(); - } - } - - if (!gstreamerLibPath.equals("")) { - System.setProperty("jna.library.path", gstreamerLibPath); - } - - if (PApplet.platform == WINDOWS) { - LibraryLoader loader = LibraryLoader.getInstance(); - if (loader == null) { - System.err.println("Cannot load local version of GStreamer libraries."); - } - } - - String[] args = { "" }; - Gst.setUseDefaultContext(defaultGLibContext); - Gst.init("Processing core video", args); - - addPlugins(); - } - - - static protected void addPlugins() { - if (!gstreamerPluginPath.equals("")) { - Registry reg = Registry.getDefault(); - boolean res; - res = reg.scanPath(gstreamerPluginPath); - if (!res) { - System.err.println("Cannot load GStreamer plugins from " + - gstreamerPluginPath); - } - } - } - - - static protected void removePlugins() { - Registry reg = Registry.getDefault(); - List list = reg.getPluginList(); - for (Plugin plg : list) { - reg.removePlugin(plg); - } - } - - - static protected void buildLinuxPaths() { - gstreamerLibPath = ""; - gstreamerPluginPath = ""; - } - - - static protected void buildWindowsPaths() { - LibraryPath libPath = new LibraryPath(); - String path = libPath.get(); - gstreamerLibPath = buildGStreamerLibPath(path, "\\windows" + bitsJVM); - gstreamerPluginPath = gstreamerLibPath + "\\plugins"; - } - - - static protected void buildMacOSXPaths() { - LibraryPath libPath = new LibraryPath(); - String path = libPath.get(); - gstreamerLibPath = buildGStreamerLibPath(path, "/macosx" + bitsJVM); - gstreamerPluginPath = gstreamerLibPath + "/plugins"; - } - - - static protected String buildGStreamerLibPath(String base, String os) { - File path = new File(base + os); - if (path.exists()) { - return base + os; - } else { - return base; - } - } - - - static protected float nanoSecToSecFrac(float nanosec) { - for (int i = 0; i < 3; i++) - nanosec /= 1E3; - return nanosec; - } - - - static protected long secToNanoLong(float sec) { - Float f = new Float(sec * 1E9); - return f.longValue(); - } - - - /** - * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be - * of size width * height. - * @param pixels int[] - */ - static protected void convertToARGB(int[] pixels, int width, int height) { - int t = 0; - int p = 0; - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { - // RGBA to ARGB conversion: shifting RGB 8 bits to the right, - // and placing A 24 bits to the left. - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int pixel = pixels[p++]; - pixels[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000); - } - } - } else { - // We have to convert ABGR into ARGB, so R and B must be swapped, - // A and G just brought back in. - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int pixel = pixels[p++]; - pixels[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | - (pixel & 0xFF00FF00); - } - } - } - } -} From feb7f2328d33f3bca6e32327886fa12e4286bd43 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 5 Jun 2014 17:18:49 -0400 Subject: [PATCH 352/608] removed video from the build process --- build/build.xml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/build/build.xml b/build/build.xml index 212a9b2e4..f848cdb44 100755 --- a/build/build.xml +++ b/build/build.xml @@ -226,7 +226,6 @@ - @@ -237,7 +236,6 @@ - @@ -495,9 +493,6 @@ - - - - - - - @@ -790,16 +781,6 @@ - - - - - - - - - - Date: Fri, 6 Jun 2014 14:19:51 +0530 Subject: [PATCH 353/608] Dealing with better status messages --- .../mode/experimental/ASTGenerator.java | 23 +++++-- .../mode/experimental/DebugEditor.java | 60 +++++++++++++++++++ .../experimental/ErrorCheckerService.java | 9 +-- 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 641578757..00758a060 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1681,8 +1681,13 @@ public class ASTGenerator { logE("DECLA: " + decl.getClass().getName()); nodeLabel = getLabelIfType(new ASTNodeWrapper(decl), (SimpleName) simpName); //retLabelString = getNodeAsString(decl); - } else + } else { logE("null"); + if(scrollOnly) { + editor.statusMessage("Can't find definition of " + simpName, + DebugEditor.STATUS_ERR); + } + } log(getNodeAsString(decl)); @@ -2027,19 +2032,22 @@ public class ASTGenerator { public void handleShowUsage(){ log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ - editor.statusError("Highlight the class/function/variable name first"); + editor.statusMessage("Highlight the class/function/variable name first" + , DebugEditor.STATUS_INFO); return; } if(errorCheckerService.hasSyntaxErrors()){ - editor.statusError("Can't perform action until syntax errors are fixed :("); + editor.statusMessage("Can't perform action until syntax errors are " + + "fixed :(", DebugEditor.STATUS_WARNING); return; } DefaultMutableTreeNode defCU = findAllOccurrences(); String selText = lastClickedWord == null ? editor.ta.getSelectedText() : lastClickedWord; if(defCU == null){ - editor.statusError("Can't locate definition of " + selText); + editor.statusMessage("Can't locate definition of " + selText, + DebugEditor.STATUS_ERR); return; } if(defCU.getChildCount() == 0) @@ -2291,12 +2299,15 @@ public class ASTGenerator { public void handleRefactor(){ log("Last clicked word:" + lastClickedWord); if(lastClickedWord == null && editor.ta.getSelectedText() == null){ - editor.statusError("Highlight the class/function/variable name first"); + editor.statusMessage("Highlight the class/function/variable name first", + DebugEditor.STATUS_INFO); return; } if(errorCheckerService.hasSyntaxErrors()){ - editor.statusError("Can't perform action until syntax errors are fixed :("); + editor + .statusMessage("Can't perform action until syntax errors are fixed :(", + DebugEditor.STATUS_WARNING); return; } if (!frmRename.isVisible()){ diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index 8813d5a3b..cd7ce4ce6 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -36,6 +36,8 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,6 +50,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.border.EtchedBorder; import javax.swing.table.TableModel; import javax.swing.text.Document; @@ -1377,6 +1380,63 @@ public class DebugEditor extends JavaEditor implements ActionListener { statusNotice("Debugger halted."); } + public static final int STATUS_EMPTY = 100, STATUS_COMPILER_ERR = 200, + STATUS_WARNING = 300, STATUS_INFO = 400, STATUS_ERR = 500; + public int statusMessageType = STATUS_EMPTY; + public String statusMessage; + public void statusMessage(final String what, int type){ + // Don't re-display the old message again + if(what.equals(statusMessage) && type == statusMessageType) { + return; + } + statusMessage = what; + statusMessageType = type; + switch (type) { + case STATUS_COMPILER_ERR: + case STATUS_ERR: + super.statusError(what); + break; + case STATUS_INFO: + case STATUS_WARNING: + statusNotice(what); + break; + } +// log("SW 0"); +// final Timer t = new Timer(); +// t.schedule(new TimerTask() { +// @Override +// public void run() { +// log("SW 1"); +// statusEmpty(); +// log("SW 2"); +// t.cancel(); +// } +// }, 2000); + SwingWorker s = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + + try { + log("SW 1"); + Thread.sleep(2 * 1000); + log("SW 2"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + statusEmpty(); + return null; + } + }; + s.execute(); + } + + public void statusEmpty(){ + statusMessage = null; + statusMessageType = STATUS_EMPTY; + super.statusEmpty(); + } + ErrorCheckerService errorCheckerService; /** diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 181d02dab..d6fabf90b 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -1005,12 +1005,14 @@ public class ErrorCheckerService implements Runnable{ if (emarker.getProblem().getLineNumber() == editor.getTextArea() .getCaretLine() + 1) { if (emarker.getType() == ErrorMarker.Warning) { - editor.statusNotice(emarker.getProblem().getMessage()); + editor.statusMessage(emarker.getProblem().getMessage(), + DebugEditor.STATUS_INFO); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); //TODO: this is temporary } else { - editor.statusError(emarker.getProblem().getMessage()); + editor.statusMessage(emarker.getProblem().getMessage(), + DebugEditor.STATUS_COMPILER_ERR); //+ " : " + errorMsgSimplifier.getIDName(emarker.problem.getIProblem().getID())); } return; @@ -1019,8 +1021,7 @@ public class ErrorCheckerService implements Runnable{ } // This line isn't an error line anymore, so probably just clear it - if (editor.getStatusMode() == EditorStatus.ERR - || editor.getStatusMode() == EditorStatus.NOTICE) { + if (editor.statusMessageType == DebugEditor.STATUS_COMPILER_ERR) { editor.statusEmpty(); return; } From 8ac153b4f5bc457dc27e7a8d0d8727e4daffe49e Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 14:27:32 +0530 Subject: [PATCH 354/608] A possible solution to #65 --- .../mode/experimental/ASTGenerator.java | 2 +- .../mode/experimental/DebugEditor.java | 27 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 00758a060..d4fdbff31 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -240,7 +240,7 @@ public class ASTGenerator { /** * Toggle AST View window */ - public static final boolean SHOWAST = true; + public static final boolean SHOWAST = !true; protected DefaultMutableTreeNode buildAST(String source, CompilationUnit cu) { if (cu == null) { diff --git a/pdex/src/processing/mode/experimental/DebugEditor.java b/pdex/src/processing/mode/experimental/DebugEditor.java index cd7ce4ce6..19eaa3e79 100755 --- a/pdex/src/processing/mode/experimental/DebugEditor.java +++ b/pdex/src/processing/mode/experimental/DebugEditor.java @@ -1386,10 +1386,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { public String statusMessage; public void statusMessage(final String what, int type){ // Don't re-display the old message again - if(what.equals(statusMessage) && type == statusMessageType) { - return; + if(type != STATUS_EMPTY) { + if(what.equals(statusMessage) && type == statusMessageType) { + return; + } } - statusMessage = what; + statusMessage = new String(what); statusMessageType = type; switch (type) { case STATUS_COMPILER_ERR: @@ -1401,26 +1403,15 @@ public class DebugEditor extends JavaEditor implements ActionListener { statusNotice(what); break; } -// log("SW 0"); -// final Timer t = new Timer(); -// t.schedule(new TimerTask() { -// @Override -// public void run() { -// log("SW 1"); -// statusEmpty(); -// log("SW 2"); -// t.cancel(); -// } -// }, 2000); + // Don't need to clear compiler error messages + if(type == STATUS_COMPILER_ERR) return; + + // Clear the message after a delay SwingWorker s = new SwingWorker() { - @Override protected Void doInBackground() throws Exception { - try { - log("SW 1"); Thread.sleep(2 * 1000); - log("SW 2"); } catch (InterruptedException e) { e.printStackTrace(); } From 68958fe3e37be74e7559e26cd0ff5beb26de1056 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 14:38:43 +0530 Subject: [PATCH 355/608] Fixes #69 --- .../processing/mode/experimental/ASTGenerator.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index d4fdbff31..3e9d60806 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1684,7 +1684,7 @@ public class ASTGenerator { } else { logE("null"); if(scrollOnly) { - editor.statusMessage("Can't find definition of " + simpName, + editor.statusMessage(simpName + " is not defined in this sketch", DebugEditor.STATUS_ERR); } } @@ -2310,6 +2310,15 @@ public class ASTGenerator { DebugEditor.STATUS_WARNING); return; } + + DefaultMutableTreeNode defCU = findAllOccurrences(); + String selText = lastClickedWord == null ? editor.ta.getSelectedText() + : lastClickedWord; + if(defCU == null){ + editor.statusMessage(selText + " isn't defined in this sketch, so it can't" + + " be renamed", DebugEditor.STATUS_ERR); + return; + } if (!frmRename.isVisible()){ frmRename.setLocation(editor.getX() + (editor.getWidth() - frmRename.getWidth()) / 2, From 6fca1dd9f40b02128e939ba037f461c1c551b601 Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 17:06:41 +0530 Subject: [PATCH 356/608] todo formatting --- pdex/todo.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pdex/todo.txt b/pdex/todo.txt index a56bb9bcb..af2cc8da5 100644 --- a/pdex/todo.txt +++ b/pdex/todo.txt @@ -12,28 +12,29 @@ Manindra Moharana (me@mkmoharana.com) Critical Bugs ------------- -[ ] Better memory management. #1 +-[ ] Better memory management. #1 -[ ] Breakpoints in classes. #47 +-[ ] Breakpoints in classes. #47 Normal Bugs ----------- -[ ] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 +-[x] Sketch NOC 6_09: steer PVector, doesn't show completion. #68 -[x] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is +-[ ] Sketch NOC 6_09: Classname in Template, doesn't scroll to decl. This is happening due certain post processing offsets not being accounted for - "public void" Enhancements/New Features ------------------------- -[ ] When viewing Outline View, instead of showing the beginning of the list, -it should select the current node element within which the cursor is presently positioned. +-[ ] When viewing Outline View, instead of showing the beginning of the list, +it should select the current node element within which the cursor is presently +positioned. -[ ] Begin work on code snippets. +-[ ] Begin work on code snippets. -[ ] JUnit Testing? +-[ ] JUnit Testing? -[ ] Preferences panel +-[ ] Preferences panel -[ ] Line Numbers +-[ ] Line Numbers From fa801f3f0456e59b11d8b932f507c5412001366c Mon Sep 17 00:00:00 2001 From: Manindra Moharana Date: Fri, 6 Jun 2014 18:47:59 +0530 Subject: [PATCH 357/608] hey look, sweeping changes --- .../mode/experimental/ASTGenerator.java | 131 ++++++++++-------- .../mode/experimental/OffsetMatcher.java | 26 ++-- .../mode/experimental/TextAreaPainter.java | 5 +- 3 files changed, 89 insertions(+), 73 deletions(-) diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index 3e9d60806..97f956696 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -1574,7 +1574,7 @@ public class ASTGenerator { */ public ASTNodeWrapper getASTNodeAt(int lineNumber, String name, int offset, boolean scrollOnly) { - + int originalLN = lineNumber - errorCheckerService.mainClassOffset; log("----getASTNodeAt---- CU State: " + errorCheckerService.compilationUnitState); if (errorCheckerService != null) { editor = errorCheckerService.getEditor(); @@ -1596,67 +1596,80 @@ public class ASTGenerator { String nodeLabel = null; String nameOfNode = null; // The node name which is to be scrolled to if (lineNode != null) { - - // Some delicate offset handling follows. - ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); - int altOff = offset; - int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); - if(ret != null){ - altOff = 0; - int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; + // Being test - for (; altOff < javaCodeMap.length; altOff++) { - if (javaCodeMap[altOff] == pdeCodeMap[offset]) { - break; - } - } - } - log("FLON2: " + lineNumber + " LN start pos " - + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); - /* - * Now I need to see if multiple statements exist with this same line number - * If that's the case, I need to ensure the offset is right. - */ - ASTNode parLineNode = lineNode.getParent(); + //ASTNodeWrapper lineNodeWrap = new ASTNodeWrapper(lineNode); + String pdeCodeLine = errorCheckerService.getPDECodeAtLine(editor + .getSketch().getCurrentCodeIndex(), originalLN); + String javaCodeLine = getJavaSourceCodeline(lineNumber); - Iterator it = parLineNode - .structuralPropertiesForType().iterator(); - boolean flag = true; - int offAdjust = 0; - while (it.hasNext() && flag) { - StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it - .next(); - if (prop.isChildListProperty()) { - List nodelist = (List) parLineNode - .getStructuralProperty(prop); - for (ASTNode cnode : nodelist) { - if (getLineNumber(cnode) == lineNumber) { - if (cnode.getStartPosition() <= lineNode.getStartPosition() - + altOff - && cnode.getStartPosition() + cnode.getLength() > lineNode - .getStartPosition() + altOff) { - log(cnode); - offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); - lineNode = cnode; - altOff -= offAdjust; - flag = false; - break; - } - - } - } - } - } - log("FLON3 new alt off: " + altOff); - ASTNode simpName = pinpointOnLine(lineNode, altOff, - lineNode.getStartPosition(), name); + log(originalLN + " PDE :" + pdeCodeLine); + log("JAVA:" + javaCodeLine); + log("Clicked on: " + name + " start offset: " + offset); + OffsetMatcher ofm = new OffsetMatcher(pdeCodeLine, javaCodeLine); + int javaOffset = ofm.getJavaOffForPdeOff(offset, name.length()); - if(simpName == null){ //Added while fixing #51 - log("pinpointOnLine 1+++> " + simpName); - simpName = pinpointOnLine(lineNode.getParent(), altOff, - lineNode.getStartPosition(), name); - } - log("pinpointOnLine 2+++> " + simpName); + ASTNode simpName = null; + if(simpName == null) return null; + // End test +// int altOff = offset; +// int ret[][] = lineNodeWrap.getOffsetMapping(errorCheckerService); +// if(ret != null){ +// altOff = 0; +// int javaCodeMap[] = ret[0], pdeCodeMap[] = ret[1]; +// +// for (; altOff < javaCodeMap.length; altOff++) { +// if (javaCodeMap[altOff] == pdeCodeMap[offset]) { +// break; +// } +// } +// } +// log("FLON2: " + lineNumber + " LN start pos " +// + lineNode.getStartPosition() + " off " + offset + " alt off" + altOff); +// /* +// * Now I need to see if multiple statements exist with this same line number +// * If that's the case, I need to ensure the offset is right. +// */ +// ASTNode parLineNode = lineNode.getParent(); +// +// Iterator it = parLineNode +// .structuralPropertiesForType().iterator(); +// boolean flag = true; +// int offAdjust = 0; +// while (it.hasNext() && flag) { +// StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it +// .next(); +// if (prop.isChildListProperty()) { +// List nodelist = (List) parLineNode +// .getStructuralProperty(prop); +// for (ASTNode cnode : nodelist) { +// if (getLineNumber(cnode) == lineNumber) { +// if (cnode.getStartPosition() <= lineNode.getStartPosition() +// + altOff +// && cnode.getStartPosition() + cnode.getLength() > lineNode +// .getStartPosition() + altOff) { +// log(cnode); +// offAdjust = cnode.getStartPosition() - lineNode.getStartPosition(); +// lineNode = cnode; +// altOff -= offAdjust; +// flag = false; +// break; +// } +// +// } +// } +// } +// } +// log("FLON3 new alt off: " + altOff); +// ASTNode simpName = pinpointOnLine(lineNode, altOff, +// lineNode.getStartPosition(), name); +// +// if(simpName == null){ //Added while fixing #51 +// log("pinpointOnLine 1+++> " + simpName); +// simpName = pinpointOnLine(lineNode.getParent(), altOff, +// lineNode.getStartPosition(), name); +// } +// log("pinpointOnLine 2+++> " + simpName); if(simpName == null && lineNode instanceof SimpleName){ switch (lineNode.getParent().getNodeType()) { case ASTNode.TYPE_DECLARATION: diff --git a/pdex/src/processing/mode/experimental/OffsetMatcher.java b/pdex/src/processing/mode/experimental/OffsetMatcher.java index d5aff521b..d0707a962 100644 --- a/pdex/src/processing/mode/experimental/OffsetMatcher.java +++ b/pdex/src/processing/mode/experimental/OffsetMatcher.java @@ -52,10 +52,10 @@ public class OffsetMatcher { // log("PDE <-> Java"); for (int i = 0; i < offsetMatch.size(); i++) { -// log(offsetMatch.get(i).pdeOffset + " <-> " -// + offsetMatch.get(i).javaOffset + -// ", " + word1.charAt(offsetMatch.get(i).pdeOffset) -// + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); + log(offsetMatch.get(i).pdeOffset + " <-> " + + offsetMatch.get(i).javaOffset + + ", " + word1.charAt(offsetMatch.get(i).pdeOffset) + + " <-> " + word2.charAt(offsetMatch.get(i).javaOffset)); } // log("Length " + offsetMatch.size()); } @@ -237,17 +237,19 @@ public class OffsetMatcher { // minDistance("c = #qwerty;", "c = 0xffqwerty;"); OffsetMatcher a; - a = new OffsetMatcher("int a = int(can); int ball;", - "int a = PApplet.parseInt(can); int ball;"); - a.getPdeOffForJavaOff(25, 3); - a.getJavaOffForPdeOff(12, 3); +// a = new OffsetMatcher("int a = int(can); int ball;", +// "int a = PApplet.parseInt(can); int ball;"); +// a.getPdeOffForJavaOff(25, 3); +// a.getJavaOffForPdeOff(12, 3); // minDistance("static void main(){;", "public static void main(){;"); // minDistance("#bb00aa", "0xffbb00aa"); - //a.minDistance("color g = #qwerty;", "int g = 0xffqwerty;"); + a = new OffsetMatcher("void test(ArrayList boids){", + "public void test(ArrayList boids){"); + a.getJavaOffForPdeOff(20,4); log("--"); - a = new OffsetMatcher("color abc = #qwerty;", "int abc = 0xffqwerty;"); - a.getPdeOffForJavaOff(4, 3); - a.getJavaOffForPdeOff(6, 3); +// a = new OffsetMatcher("color abc = #qwerty;", "int abc = 0xffqwerty;"); +// a.getPdeOffForJavaOff(4, 3); +// a.getJavaOffForPdeOff(6, 3); // distance("c = #bb00aa;", "c = 0xffbb00aa;"); } } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 4e8b8882c..30f031bb3 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -101,7 +101,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { else { int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1; log("x="+x); - int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line); + int xLS = off - ta.getLineStartOffset(line); if (x < 0 || x >= s.length()) return; String word = s.charAt(x) + ""; @@ -116,6 +116,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { if (x1 >= 0 && x1 < s.length()) { if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') { word = s.charAt(x1--) + word; + xLS--; } else x1 = -1; } else @@ -140,7 +141,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } if (Character.isDigit(word.charAt(0))) return; - + log(errorCheckerService.mainClassOffset + line + "|" + line + "| offset " + xLS + word + " <= \n"); errorCheckerService.getASTGenerator().scrollToDeclaration(line From 4359a16f0eb5cc9d6faf46e1353677f65cf10196 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 6 Jun 2014 12:39:58 -0400 Subject: [PATCH 358/608] increase heap size to 256m (-Xmx256) per Manindra request --- build/build.xml | 3 ++- build/linux/processing | 4 ++-- build/windows/config-cmd.xml | 2 ++ build/windows/config.xml | 2 ++ todo.txt | 17 +++++++++++++++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/build/build.xml b/build/build.xml index f848cdb44..a0aa231ec 100755 --- a/build/build.xml +++ b/build/build.xml @@ -423,8 +423,9 @@ + +

    Force directed graph, - * heavily based on: fid.gen
    - * The Nature of Code
    - * Spring 2010