mirror of
https://github.com/processing/processing4.git
synced 2026-01-30 11:51:54 +01:00
fix copyrights, remove authors per guidelines, replace logging
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user