fix copyrights, remove authors per guidelines, replace logging

This commit is contained in:
Ben Fry
2016-11-09 21:13:06 -05:00
parent 992738e087
commit 9d051cd052
9 changed files with 995 additions and 986 deletions

View File

@@ -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 <m@martinleopold.com>
*/
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;
}
}

View File

@@ -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 <m@martinleopold.com>
*/
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);
}

View File

@@ -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 <m@martinleopold.com>
*/
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;
}
}

View File

@@ -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 <m@martinleopold.com>
*/
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<Location> 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<Location> 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);
}
}
}

View File

@@ -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 <m@martinleopold.com>
*/
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<LineHighlight> 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());
}
}
}

View File

@@ -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 <m@martinleopold.com>
*/
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<LineHighlight> listeners = new HashSet<LineHighlight>(); // 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<LineHighlight> listeners = new HashSet<LineHighlight>(); // 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.
}
}

View File

@@ -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 <m@martinleopold.com>
* 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;
}
}

View File

@@ -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 <m@martinleopold.com>
* 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<MutableTreeNode> children = new ArrayList<MutableTreeNode>();
protected MutableTreeNode parent;
protected String type;
protected String name;
protected Value value;
protected List<MutableTreeNode> children = new ArrayList<MutableTreeNode>();
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<VariableNode> 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<MutableTreeNode> 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<VariableNode> 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<MutableTreeNode> 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;
}
}