processing.mode.java.debug.VariableNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-mode Show documentation
Show all versions of java-mode Show documentation
Processing is a programming language, development environment, and online community.
This Java Mode package contains the Java mode for Processing IDE.
/* -*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package processing.mode.java.debug;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.StringReference;
import com.sun.jdi.Value;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
/**
* Model for a variable in the variable inspector. Has a type and name and
* optionally a value. Can have sub-variables (as is the case for objects, and
* arrays).
*
* @author Martin Leopold
*/
public class VariableNode implements MutableTreeNode {
public static final int TYPE_UNKNOWN = -1;
public static final int TYPE_OBJECT = 0;
public static final int TYPE_ARRAY = 1;
public static final int TYPE_INTEGER = 2;
public static final int TYPE_FLOAT = 3;
public static final int TYPE_BOOLEAN = 4;
public static final int TYPE_CHAR = 5;
public static final int TYPE_STRING = 6;
public static final int TYPE_LONG = 7;
public static final int TYPE_DOUBLE = 8;
public static final int TYPE_BYTE = 9;
public static final int TYPE_SHORT = 10;
public static final int TYPE_VOID = 11;
protected String type;
protected String name;
protected Value value;
protected List children = new ArrayList();
protected MutableTreeNode parent;
/**
* Construct a {@link VariableNode}.
* @param name the name
* @param type the type
* @param value the value
*/
public VariableNode(String name, String type, Value value) {
this.name = name;
this.type = type;
this.value = value;
}
public void setValue(Value value) {
this.value = value;
}
public Value getValue() {
return value;
}
/**
* Get a String representation of this variable nodes value.
*
* @return a String representing the value.
*/
public String getStringValue() {
String str;
if (value != null) {
if (getType() == TYPE_OBJECT) {
str = "instance of " + type;
} else if (getType() == TYPE_ARRAY) {
//instance of int[5] (id=998) --> instance of int[5]
str = value.toString().substring(0, value.toString().lastIndexOf(" "));
} else if (getType() == TYPE_STRING) {
str = ((StringReference) value).value(); // use original string value (without quotes)
} else {
str = value.toString();
}
} else {
str = "null";
}
return str;
}
public String getTypeName() {
return type;
}
public int getType() {
if (type == null) {
return TYPE_UNKNOWN;
}
if (type.endsWith("[]")) {
return TYPE_ARRAY;
}
if (type.equals("int")) {
return TYPE_INTEGER;
}
if (type.equals("long")) {
return TYPE_LONG;
}
if (type.equals("byte")) {
return TYPE_BYTE;
}
if (type.equals("short")) {
return TYPE_SHORT;
}
if (type.equals("float")) {
return TYPE_FLOAT;
}
if (type.equals("double")) {
return TYPE_DOUBLE;
}
if (type.equals("char")) {
return TYPE_CHAR;
}
if (type.equals("java.lang.String")) {
return TYPE_STRING;
}
if (type.equals("boolean")) {
return TYPE_BOOLEAN;
}
if (type.equals("void")) {
return TYPE_VOID; //TODO: check if this is correct
}
return TYPE_OBJECT;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* Add a {@link VariableNode} as child.
*
* @param c the {@link VariableNode} to add.
*/
public void addChild(VariableNode c) {
children.add(c);
c.setParent(this);
}
/**
* Add multiple {@link VariableNode}s as children.
*
* @param children the list of {@link VariableNode}s to add.
*/
public void addChildren(List children) {
for (VariableNode child : children) {
addChild(child);
}
}
@Override
public TreeNode getChildAt(int i) {
return children.get(i);
}
@Override
public int getChildCount() {
return children.size();
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public int getIndex(TreeNode tn) {
return children.indexOf(tn);
}
@Override
public boolean getAllowsChildren() {
if (value == null) {
return false;
}
// handle strings
if (getType() == TYPE_STRING) {
return false;
}
// handle arrays
if (getType() == TYPE_ARRAY) {
ArrayReference array = (ArrayReference) value;
return array.length() > 0;
}
// handle objects
if (getType() == TYPE_OBJECT) { // this also rules out null
// check if this object has any fields
ObjectReference obj = (ObjectReference) value;
return !obj.referenceType().visibleFields().isEmpty();
}
return false;
}
/**
* This controls the default icon and disclosure triangle.
*
* @return true, will show "folder" icon and disclosure triangle.
*/
@Override
public boolean isLeaf() {
//return children.size() == 0;
return !getAllowsChildren();
}
@Override
public Enumeration children() {
return Collections.enumeration(children);
}
/**
* Get a String representation of this {@link VariableNode}.
*
* @return the name of the variable (for sorting to work).
*/
@Override
public String toString() {
return getName(); // for sorting
}
/**
* Get a String description of this {@link VariableNode}. Contains the type,
* name and value.
*
* @return the description
*/
public String getDescription() {
String str = "";
if (type != null) {
str += type + " ";
}
str += name;
str += " = " + getStringValue();
return str;
}
@Override
public void insert(MutableTreeNode mtn, int i) {
children.add(i, this);
}
@Override
public void remove(int i) {
MutableTreeNode mtn = children.remove(i);
if (mtn != null) {
mtn.setParent(null);
}
}
@Override
public void remove(MutableTreeNode mtn) {
children.remove(mtn);
mtn.setParent(null);
}
/**
* Remove all children from this {@link VariableNode}.
*/
public void removeAllChildren() {
for (MutableTreeNode mtn : children) {
mtn.setParent(null);
}
children.clear();
}
@Override
public void setUserObject(Object o) {
if (o instanceof Value) {
value = (Value) o;
}
}
@Override
public void removeFromParent() {
parent.remove(this);
this.parent = null;
}
@Override
public void setParent(MutableTreeNode mtn) {
parent = mtn;
}
/**
* Test for equality. To be equal, two {@link VariableNode}s need to have
* equal type, name and value.
*
* @param obj the object to test for equality with this {@link VariableNode}
* @return true if the given object is equal to this {@link VariableNode}
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final VariableNode other = (VariableNode) obj;
if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
//System.out.println("type not equal");
return false;
}
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
//System.out.println("name not equal");
return false;
}
if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) {
//System.out.println("value not equal");
return false;
}
// if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) {
// System.out.println("parent not equal: " + this.parent + "/" + other.parent);
// return false;
// }
return true;
}
/**
* Returns a hash code based on type, name and value.
*/
@Override
public int hashCode() {
int hash = 3;
hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0);
hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0);
// hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0);
return hash;
}
}