diff --git a/app/src/processing/app/Messages.java b/app/src/processing/app/Messages.java index 72f757d67..8f6eaae3e 100644 --- a/app/src/processing/app/Messages.java +++ b/app/src/processing/app/Messages.java @@ -327,7 +327,9 @@ public class Messages { static public void loge(String message, Throwable e) { if (Base.DEBUG) { - System.err.println(message); + if (message != null) { + System.err.println(message); + } e.printStackTrace(); } } diff --git a/java/src/processing/mode/java/debug/ArrayFieldNode.java b/java/src/processing/mode/java/debug/ArrayFieldNode.java index ec5423729..ac7d6a08d 100644 --- a/java/src/processing/mode/java/debug/ArrayFieldNode.java +++ b/java/src/processing/mode/java/debug/ArrayFieldNode.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; @@ -24,45 +25,38 @@ 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; + +import processing.app.Messages; /** * 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; - 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; + /** + * Construct an {@link ArrayFieldNode}. + */ + 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) { + Messages.loge(null, ex); + } catch (ClassNotLoadedException ex) { + Messages.loge(null, ex); } + this.value = value; + } } diff --git a/java/src/processing/mode/java/debug/ClassLoadListener.java b/java/src/processing/mode/java/debug/ClassLoadListener.java index bee6ffa47..1dd4a288d 100644 --- a/java/src/processing/mode/java/debug/ClassLoadListener.java +++ b/java/src/processing/mode/java/debug/ClassLoadListener.java @@ -1,40 +1,38 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; 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); + /** + * Event handler called when a class is loaded. + */ + public void classLoaded(ReferenceType theClass); } diff --git a/java/src/processing/mode/java/debug/FieldNode.java b/java/src/processing/mode/java/debug/FieldNode.java index 76b4bc2ad..cae4d7178 100644 --- a/java/src/processing/mode/java/debug/FieldNode.java +++ b/java/src/processing/mode/java/debug/FieldNode.java @@ -2,11 +2,12 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2012-15 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. + Copyright (c) 2012-16 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 @@ -14,8 +15,8 @@ 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. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; @@ -25,46 +26,40 @@ 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; + +import processing.app.Messages; /** * 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; + 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; + /** + * Construct a {@link FieldNode}. + * @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 ite) { + Messages.loge(null, ite); + } catch (ClassNotLoadedException cnle) { + Messages.loge(null, cnle); } + this.value = value; + } } diff --git a/java/src/processing/mode/java/debug/LineBreakpoint.java b/java/src/processing/mode/java/debug/LineBreakpoint.java index 5272270e5..584b780a3 100644 --- a/java/src/processing/mode/java/debug/LineBreakpoint.java +++ b/java/src/processing/mode/java/debug/LineBreakpoint.java @@ -1,28 +1,27 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import processing.app.Messages; import processing.mode.java.Debugger; @@ -32,201 +31,210 @@ import com.sun.jdi.Location; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.BreakpointRequest; + /** * 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 - 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.getEditor().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) - Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "LBP Created " +toString() + " class: " + className(), new Object[]{}); + /** + * 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.getEditor().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) + Messages.log("LBP Created " + toString() + " class: " + className()); + } + + + /** + * Create a {@link LineBreakpoint} on a line in the current tab. + * @param lineIdx the line index of the current tab to create the breakpoint + */ + // TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)} + public LineBreakpoint(int lineIdx, Debugger dbg) { + this(dbg.getEditor().getLineIDInCurrentTab(lineIdx), dbg); + } + + + /** + * Get the line id this breakpoint is on. + */ + 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()) { + log("can't attach breakpoint, debugger not paused"); + return; } - /** - * 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.getEditor().getLineIDInCurrentTab(lineIdx), dbg); + if (theClass == null) { + log("can't attach breakpoint, class not loaded: " + className()); + return; } - /** - * Get the line id this breakpoint is on. - * - * @return the line id - */ - public LineID lineID() { - return line; + // find line in java space + LineID javaLine = dbg.sketchToJavaLine(line); + if (javaLine == null) { + log("couldn't find line " + line + " in the java code"); + return; } - - /** - * 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); + try { + log("BPs of class: " + theClass + ", line " + (javaLine.lineIdx() + 1)); + List locations = theClass.locationsOfLine(javaLine.lineIdx() + 1); + if (locations.isEmpty()) { + log("no location found for line " + line + " -> " + javaLine); + return; + } + // use first found location + bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0)); + bpr.enable(); + log("attached breakpoint to " + line + " -> " + javaLine); + } catch (AbsentInformationException ex) { + Messages.loge(null, ex); } + } - /** - * 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 { - 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}); - 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; } + } - /** - * 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.getEditor().addBreakpointedLine(line); + if (theClass != null && dbg.isPaused()) { // class is loaded + // immediately activate the breakpoint + attach(); } - - /** - * 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.getEditor().addBreakpointedLine(line); - if (theClass != null && dbg.isPaused()) { // class is loaded - // immediately activate the breakpoint - attach(); - } - if (dbg.getEditor().isInCurrentTab(line)) { - dbg.getEditor().getSketch().setModified(true); - } + if (dbg.getEditor().isInCurrentTab(line)) { + dbg.getEditor().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.getEditor().removeBreakpointedLine(line.lineIdx()); - if (dbg.isPaused()) { - // immediately remove the breakpoint - detach(); - } - line.stopTracking(); - if (dbg.getEditor().isInCurrentTab(line)) { - dbg.getEditor().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.getEditor().removeBreakpointedLine(line.lineIdx()); + if (dbg.isPaused()) { + // immediately remove the breakpoint + detach(); } - -// public void enable() { -// } -// -// public void disable() { -// } - @Override - public String toString() { - return line.toString(); + line.stopTracking(); + if (dbg.getEditor().isInCurrentTab(line)) { + dbg.getEditor().getSketch().setModified(true); } + } - /** - * 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(); - //System.out.println(dbg.getMainClass().name()); - 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")); - } + @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(); + //System.out.println(dbg.getMainClass().name()); + if (mainClass == null) { return null; + } + return dbg.getMainClass().name(); } - /** - * 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 - Messages.log("Class Loaded: " + theClass.name()); - if (theClass.name().equals(className())) { - this.theClass = theClass; - attach(); - } - for (ReferenceType ct : theClass.nestedTypes()) { - Messages.log("Nested " + ct.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 + Messages.log("Class Loaded: " + theClass.name()); + if (theClass.name().equals(className())) { + this.theClass = theClass; + attach(); + } + for (ReferenceType ct : theClass.nestedTypes()) { + Messages.log("Nested " + ct.name()); + } + } + + + // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + private void log(String msg, Object... args) { + if (args != null && args.length != 0) { + Messages.logf(getClass().getName() + " " + msg, args); + } else { + Messages.log(getClass().getName() + " " + msg); + } + } } diff --git a/java/src/processing/mode/java/debug/LineHighlight.java b/java/src/processing/mode/java/debug/LineHighlight.java index 789d4ba96..66856f829 100644 --- a/java/src/processing/mode/java/debug/LineHighlight.java +++ b/java/src/processing/mode/java/debug/LineHighlight.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; @@ -29,23 +30,17 @@ import processing.mode.java.JavaEditor; /** * 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 { - protected final JavaEditor editor; // the view, used for highlighting lines by setting a background color protected final LineID lineID; // the id of the line protected String marker; // protected int priority = 0; protected static final Set allHighlights = new HashSet<>(); - + /** * Create a {@link LineHighlight}. - * - * @param lineID the line id to highlight - * @param editor the {@link JavaEditor} */ public LineHighlight(LineID lineID, JavaEditor editor) { this.lineID = lineID; @@ -56,10 +51,10 @@ public class LineHighlight { allHighlights.add(this); } - + protected static boolean isHighestPriority(LineHighlight hl) { for (LineHighlight check : allHighlights) { - if (check.getLineID().equals(hl.getLineID()) && + if (check.getLineID().equals(hl.getLineID()) && check.priority() > hl.priority()) { return false; } @@ -67,107 +62,114 @@ public class LineHighlight { return true; } - + 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 editor the {@link JavaEditor} - */ - // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, JavaEditor editor)} - public LineHighlight(int lineIdx, JavaEditor editor) { - this(editor.getLineIDInCurrentTab(lineIdx), editor); + + /** + * Create a {@link LineHighlight} on the current tab. + * + * @param lineIdx the line index on the current tab to highlight + * @param editor the {@link JavaEditor} + */ + // TODO: Remove and replace by {@link #LineHighlight(LineID lineID, JavaEditor editor)} + public LineHighlight(int lineIdx, JavaEditor editor) { + this(editor.getLineIDInCurrentTab(lineIdx), 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(); + } + + + /** + * Retrieve the line id of this {@link LineHighlight}. + * + * @return the line id + */ + public LineID getLineID() { + return lineID; + } + + + /** + * 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) + */ + public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { + // clear old line + if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { + editor.getJavaTextArea().clearGutterText(oldLineIdx); } - /** - * 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(); + // 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(); } + } - /** - * Retrieve the line id of this {@link LineHighlight}. - * - * @return the line id - */ - public LineID getLineID() { - return lineID; + + /** + * 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)) { + if (marker != null) { + editor.getJavaTextArea().setGutterText(lineID.lineIdx(), marker); + } } + } - /** - * 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) - */ - public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) { - // clear old line - if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) { - editor.getJavaTextArea().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)) { - if (marker != null) { - editor.getJavaTextArea().setGutterText(lineID.lineIdx(), marker); - } - } - } - - /** - * Clear this line highlight. - */ - public void clear() { - if (editor.isInCurrentTab(lineID)) { - editor.getJavaTextArea().clearGutterText(lineID.lineIdx()); - } + + /** + * Clear this line highlight. + */ + public void clear() { + if (editor.isInCurrentTab(lineID)) { + editor.getJavaTextArea().clearGutterText(lineID.lineIdx()); } + } } diff --git a/java/src/processing/mode/java/debug/LineID.java b/java/src/processing/mode/java/debug/LineID.java index e7c066110..251a29cee 100644 --- a/java/src/processing/mode/java/debug/LineID.java +++ b/java/src/processing/mode/java/debug/LineID.java @@ -1,29 +1,29 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; 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; @@ -31,251 +31,247 @@ import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.Position; +import processing.app.Messages; + + /** * 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 - 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; + 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; } - - /** - * Get the file name of this line. - * - * @return the file name - */ - public String fileName() { - return fileName; + if (getClass() != obj.getClass()) { + return false; } - - /** - * 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; + final LineID other = (LineID) obj; + if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) { + return false; } - - @Override - public int hashCode() { - return toString().hashCode(); + if (this.lineIdx != other.lineIdx) { + return false; } + return true; + } - /** - * 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; + + /** + * 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); + } + + + /** + * 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, + // or, if the line consists of entirely white spaces, just before the newline + // character + pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText)); + this.doc = doc; + doc.addDocumentListener(this); + } catch (BadLocationException ex) { + Messages.loge(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 (LineHighlight l : listeners) { + if (l != null) { + l.lineChanged(this, oldLineIdx, lineIdx); + } else { + listeners.remove(l); // remove null listener + } } - 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; + } + } + } + + + /** + * Add listener to be notified when the line number changes. + * + * @param l the listener to add + */ + public void addListener(LineHighlight l) { + listeners.add(l); + } + + + /** + * Remove a listener for line number changes. + * + * @param l the listener to remove + */ + public void removeListener(LineHighlight 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; + } } - /** - * 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); - } + // If we've reached here, that implies the line consists of purely white + // space. So return at a position just after the whitespace (i.e., + // just before the newline). + // + // The " - 1" part resolves issue #3552 + return str.length() - 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, - // or, if the line consists of entirely white spaces, just before the newline - // character - 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; - } + /** + * Called when the {@link Document} registered using {@link #startTracking} + * is edited. This happens when text is inserted or removed. + */ + 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); } + } - /** - * 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 (LineHighlight l : listeners) { - if (l != null) { - l.lineChanged(this, oldLineIdx, lineIdx); - } else { - listeners.remove(l); // remove null listener - } - } - } - } - } + /** + * {@link DocumentListener} callback. Called when text is inserted. + */ + @Override + public void insertUpdate(DocumentEvent de) { + editEvent(de); + } - /** - * Add listener to be notified when the line number changes. - * - * @param l the listener to add - */ - public void addListener(LineHighlight l) { - listeners.add(l); - } - /** - * Remove a listener for line number changes. - * - * @param l the listener to remove - */ - public void removeListener(LineHighlight l) { - listeners.remove(l); - } + /** + * {@link DocumentListener} callback. Called when text is removed. + */ + @Override + public void removeUpdate(DocumentEvent de) { + editEvent(de); + } - /** - * 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; - } - } - - /* If we've reached here, that implies the line consists of purely white - * space. So return at a position just after the whitespace (i.e., - * just before the newline). - * - * The " - 1" part resolves issue #3552 - */ - return str.length() - 1; - } - /** - * 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. - } + /** + * {@link DocumentListener} callback. Called when attributes are changed. + * Not used. + */ + @Override + public void changedUpdate(DocumentEvent de) { + // not needed. + } } diff --git a/java/src/processing/mode/java/debug/LocalVariableNode.java b/java/src/processing/mode/java/debug/LocalVariableNode.java index 435a230f6..39c42a2a7 100644 --- a/java/src/processing/mode/java/debug/LocalVariableNode.java +++ b/java/src/processing/mode/java/debug/LocalVariableNode.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; @@ -25,45 +26,36 @@ 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; + +import processing.app.Messages; + /** - * Specialized {@link VariableNode} for representing local variables. Overrides - * {@link #setValue} to properly change the value of the encapsulated local - * variable. - * - * @author Martin Leopold + * Specialized {@link VariableNode} for representing local variables. + * Overrides {@link #setValue} to properly change the value of the + * encapsulated local variable. */ public class LocalVariableNode extends VariableNode { + protected LocalVariable var; + protected StackFrame frame; - 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; + 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) { + Messages.loge(null, ex); + } catch (ClassNotLoadedException ex) { + Messages.loge(null, ex); } + this.value = value; + } } diff --git a/java/src/processing/mode/java/debug/VariableNode.java b/java/src/processing/mode/java/debug/VariableNode.java index e370f7da1..d9ad2e5f4 100644 --- a/java/src/processing/mode/java/debug/VariableNode.java +++ b/java/src/processing/mode/java/debug/VariableNode.java @@ -1,21 +1,22 @@ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* -Part of the Processing project - http://processing.org -Copyright (c) 2012-15 The Processing Foundation + Part of the Processing project - http://processing.org -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. + Copyright (c) 2012-16 The Processing 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. + 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. -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. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + 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.java.debug; @@ -33,329 +34,350 @@ 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 + * optionally a value. Can have sub-variables (as is the case for objects, + * and arrays). */ 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; - 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; + 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; + + /** + * 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; } - public void setValue(Value value) { - this.value = value; + // handle strings + if (getType() == TYPE_STRING) { + return false; } - public Value getValue() { - return value; + // 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(); } - /** - * 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; + 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; + } - public String getTypeName() { - return type; + + @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); } + } - 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; + + @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(); + } - public String getName() { - return name; + + @Override + public void setUserObject(Object o) { + if (o instanceof Value) { + value = (Value) o; } + } - public void setName(String name) { - this.name = name; + + @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; } - - /** - * Add a {@link VariableNode} as child. - * - * @param c the {@link VariableNode} to add. - */ - public void addChild(VariableNode c) { - children.add(c); - c.setParent(this); + if (getClass() != obj.getClass()) { + return false; } - - /** - * 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); - } + 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; } - - @Override - public TreeNode getChildAt(int i) { - return children.get(i); + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + //System.out.println("name not equal"); + return false; } - - @Override - public int getChildCount() { - return children.size(); + if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) { + //System.out.println("value not equal"); + return false; } + return true; + } - @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; - } + /** + * 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); + return hash; + } }