package bluej.debugmgr.inspector;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import javax.swing.SwingUtilities;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Rectangle;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import bluej.Config;
import bluej.debugger.DebuggerField;
import bluej.debugger.DebuggerObject;
import bluej.debugger.gentype.GenTypeClass;
import bluej.pkgmgr.Package;
import bluej.pkgmgr.PackageEditor;
import bluej.testmgr.record.ArrayElementGetRecord;
import bluej.testmgr.record.ArrayElementInspectorRecord;
import bluej.testmgr.record.GetInvokerRecord;
import bluej.testmgr.record.InvokerRecord;
import bluej.testmgr.record.ObjectInspectInvokerRecord;
import bluej.utility.DialogManager;
import bluej.utility.JavaNames;
import bluej.utility.javafx.JavaFXUtil;
import threadchecker.OnThread;
import threadchecker.Tag;
| A window that displays the fields in an object or a method return value.
|
| @author Michael Kolling
| @author Poul Henriksen
| @author Bruce Quig
|
@OnThread(Tag.FXPlatform)
public class ObjectInspector
extends Inspector{
protected final static String inspectTitle = Config.getString("debugger.inspector.object.title");
protected final static String noFieldsMsg = Config.getString("debugger.inspector.object.noFields");
protected final static String numFields = Config.getString("debugger.inspector.numFields");
public static final int CORNER_SIZE = 40;
| A reference to the object being inspected
|
protected DebuggerObject obj;
| Name of the object, as it appears on the object bench, or null if the
| object being inspected is not on the object bench
|
protected String objName;
protected boolean queryArrayElementSelected = false;
private int selectedIndex;
| Array of Integers representing the array indexes from a large array that
| have been selected for viewing
|
| List which is built when viewing an array that records the object slot
| corresponding to each array index
|
protected List<Integer> indexToSlotList = null;
private StackPane stackPane;
| Note: 'pkg' may be null if 'ir' is null.
|
| @param obj
| The object displayed by this viewer
| @param name
| The name of this object or "null" if the name is unobtainable
|* @param pkg
* The package all this belongs to
* @param ir
* the InvokerRecord explaining how we created this result/object
* if null, the "get" button is permanently disabled
* @param parent
* The parent frame of this frame
*/
public ObjectInspector(DebuggerObject obj, InspectorManager inspectorManager, String name, Package pkg, InvokerRecord ir, final Window parent)
|
|{
|
|super(inspectorManager, pkg, ir, StageStyle.TRANSPARENT);
|
|this.obj = obj;
|
|this.objName = name;
|
|makeFrame();
|
|update();
|
|setMinWidth(500);
|
|setMinHeight(260);
|
|if (parent instanceof Inspector) {
|
|setX(parent.getX() + 40);
|
|setY(parent.getY() + 40);
|
|}
|
|else {
|
|//DialogManager.centreWindow(thisInspector, parent);
|
|}
|
|installListenersForMoveDrag(20.0);
|
|}
|
|/**
| Build the GUI
|
protected void makeFrame()
{
Pane header = new VBox();
GenTypeClass objType = obj.getGenType();
String className = objType != null ? objType.toString(true) : "";
String fullTitle = null;
if (objName != null) {
fullTitle = objName + " : " + className;
setTitle(inspectTitle + " - " + objName + ", " + className + " " + numFields + " " + getListData().size());
}
else {
fullTitle = " : " + className;
setTitle(inspectTitle);
}
Label headerLabel = new Label(fullTitle);
header.getChildren().add(headerLabel);
BorderPane mainPanel = new BorderPane();
mainPanel.setCenter(fieldList);
Label lab = new Label(" " + noFieldsMsg);
fieldList.setPlaceholder(lab);
mainPanel.setRight(createInspectAndGetButtons());
Pane bottomPanel = new VBox();
BorderPane buttonPanel = new BorderPane();
Button button = createCloseButton();
buttonPanel.setRight(button);
Button classButton = new Button(showClassLabel);
classButton.setOnAction(e -> showClass());
buttonPanel.setLeft(classButton);
bottomPanel.getChildren().add(buttonPanel);
Pane contentPane = new VBox();
contentPane.setBackground(null);
contentPane.getChildren().addAll(header, mainPanel, bottomPanel);
VBox.setVgrow(mainPanel, Priority.ALWAYS);
JavaFXUtil.addStyleClass(contentPane, "inspector", "inspector-object");
JavaFXUtil.addStyleClass(header, "inspector-object-header", "inspector-header");
button.setDefaultButton(true);
stackPane = new StackPane(new ObjectBackground(CORNER_SIZE, new ReadOnlyDoubleWrapper(3.0)), contentPane);
Rectangle clip = new Rectangle();
clip.widthProperty().bind(widthProperty());
clip.heightProperty().bind(heightProperty());
clip.setArcWidth(CORNER_SIZE);
clip.setArcHeight(CORNER_SIZE);
stackPane.setClip(clip);
stackPane.setBackground(null);
BorderPane root = new BorderPane(stackPane);
root.setBackground(null);
Scene scene = new Scene(root);
scene.setFill(null);
setScene(scene);
}
@Override
public Region getContent()
{
return stackPane;
}
@Override
protected boolean shouldAutoUpdate()
{
return Config.isGreenfoot();
}
| True if this inspector is used to display a method call result.
|
@Override
@OnThread(Tag.FXPlatform)
protected List getListData()
{
if (obj.isArray()) {
return compressArrayList(obj);
}
else {
List<DebuggerField> fields = obj.getFields();
List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(fields.size());
for (DebuggerField field : fields) {
if (! Modifier.isStatic(field.getModifiers())) {
String desc = Inspector.fieldToString(field);
String value = field.getValueString();
fieldInfos.add(new FieldInfo(desc, value));
}
}
return fieldInfos;
}
}
| An element in the field list was selected.
|
protected void listElementSelected(int slot)
{
if (slot == -1)
{
setCurrentObj(null, null, null);
setButtonsEnabled(false, false);
return;
}
if (obj.isArray()) {
slot = indexToSlot(slot);
if (slot >= 0) {
selectedIndex = slot;
}
if (slot == ARRAY_LENGTH_SLOT_VALUE) {
setCurrentObj(null, null, null);
setButtonsEnabled(false, false);
return;
}
queryArrayElementSelected = (slot == (ARRAY_QUERY_SLOT_VALUE));
if (queryArrayElementSelected) {
setCurrentObj(null, null, null);
if (! obj.getElementType().isPrimitive()) {
setButtonsEnabled(true, false);
}
else {
setButtonsEnabled(false, false);
}
}
else {
if (!obj.getElementType().isPrimitive()) {
DebuggerObject elementObj = obj.getElementObject(slot);
if (! elementObj.isNullObject()) {
setCurrentObj(elementObj, "[" + slot + "]", obj.getElementType().toString());
setButtonsEnabled(true, true);
return;
}
}
setCurrentObj(null, null, null);
setButtonsEnabled(false, false);
}
return;
}
DebuggerField field = obj.getInstanceField(slot);
if (field != null && field.isReferenceType() && ! field.isNull()) {
setCurrentObj(field.getValueObject(null), field.getName(), field.getType().toString());
if (Modifier.isPublic(field.getModifiers())) {
setButtonsEnabled(true, true);
}
else {
boolean canGet = false;
if (! Modifier.isPrivate(field.getModifiers())) {
String fieldPkg = JavaNames.getPrefix(field.getDeclaringClassName());
String pkgName = (pkg == null) ? "" : pkg.getQualifiedName();
canGet = fieldPkg.equals(pkgName);
}
setButtonsEnabled(true, canGet);
}
}
else {
setCurrentObj(null, null, null);
setButtonsEnabled(false, false);
}
}
| Show the inspector for the class of an object.
|
protected void showClass()
{
inspectorManager.getClassInspectorInstance(obj.getClassRef(), pkg, this, null);
}
@Override
protected void doInspect()
{
if (queryArrayElementSelected) {
selectArrayElement();
}
else if (selectedField != null) {
boolean isPublic = !getButton.isDisable();
if (! obj.isArray()) {
InvokerRecord newIr = new ObjectInspectInvokerRecord(selectedFieldName, ir);
inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg, isPublic ? newIr : null, this, null);
}
else {
InvokerRecord newIr = new ArrayElementInspectorRecord(ir, selectedIndex);
inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg, isPublic ? newIr : null, this, null);
}
}
}
@Override
protected void doGet()
{
if (selectedField != null) {
InvokerRecord getIr;
if (! obj.isArray()) {
getIr = new GetInvokerRecord(selectedFieldType, selectedFieldName, ir);
}
else {
getIr = new ArrayElementGetRecord(selectedFieldType, selectedIndex, ir);
}
DebuggerObject selField = this.selectedField;
PackageEditor pkgEd = pkg.getEditor();
pkgEd.recordInteraction(getIr);
pkgEd.raisePutOnBenchEvent(this, selField, selField.getGenType(), getIr, true, Optional.empty());
}
}
| Remove this inspector.
|
protected void remove()
{
if (inspectorManager != null) {
inspectorManager.removeInspector(obj);
}
}
| Shows a dialog to select array element for inspection
|
private void selectArrayElement()
{
String response = DialogManager.askStringFX(this, "ask-index");
if (response != null) {
try {
int slot = Integer.parseInt(response);
if (slot >= 0 && slot < obj.getElementCount()) {
if (! obj.getElementType().isPrimitive() && ! obj.getElementObject(slot).isNullObject()) {
boolean isPublic = !getButton.isDisable();
InvokerRecord newIr = new ArrayElementInspectorRecord(ir, slot);
setCurrentObj(obj.getElementObject(slot), "[" + slot + "]", obj.getElementType().toString());
inspectorManager.getInspectorInstance(selectedField, selectedFieldName, pkg,
isPublic ? newIr : null, this, null);
}
else {
setButtonsEnabled(false, false);
update();
}
}
else {
DialogManager.showErrorFX(this, "out-of-bounds");
}
}
catch (NumberFormatException e) {
setCurrentObj(null, null, null);
DialogManager.showErrorFX(this, "cannot-access-element");
}
}
else {
setCurrentObj(null, null, null);
}
}
private final static int VISIBLE_ARRAY_START = 40;
private final static int VISIBLE_ARRAY_TAIL = 5;
private final static int ARRAY_QUERY_SLOT_VALUE = -2;
private final static int ARRAY_LENGTH_SLOT_VALUE = -1;
| Compress a potentially large array into a more displayable shortened
| form.
|
| Compresses an array field name list to a maximum of VISIBLE_ARRAY_START
| which are guaranteed to be displayed at the start, then some [..]
| expansion slots, followed by VISIBLE_ARRAY_TAIL elements from the end of
| the array. When a selected element is chosen indexToSlot allows the
| selection to be converted to the original array element position.
|
| @param fullArrayFieldList
| the full field list for an array
| @return the compressed array
|
private List compressArrayList(DebuggerObject arrayObject)
{
indexToSlotList = new LinkedList<Integer>();
indexToSlotList.add(0, Integer.valueOf(ARRAY_LENGTH_SLOT_VALUE));
if (arrayObject.getElementCount() > (VISIBLE_ARRAY_START + VISIBLE_ARRAY_TAIL + 2)) {
List<FieldInfo> newArray = new ArrayList<FieldInfo>(2 + VISIBLE_ARRAY_START + VISIBLE_ARRAY_TAIL);
newArray.add(0, new FieldInfo("int length", "" + arrayObject.getElementCount()));
for (int i = 0; i <= VISIBLE_ARRAY_START; i++) {
newArray.add(new FieldInfo("[" + i + "]", arrayObject.getElementValueString(i)));
indexToSlotList.add(i);
}
newArray.add(new FieldInfo("[...]", ""));
indexToSlotList.add(Integer.valueOf(ARRAY_QUERY_SLOT_VALUE));
for (int i = VISIBLE_ARRAY_TAIL; i > 0; i--) {
int elNum = arrayObject.getElementCount() - i;
newArray.add(new FieldInfo("[" + elNum + "]", arrayObject.getElementValueString(elNum)));
indexToSlotList.add(arrayObject.getElementCount() - i);
}
return newArray;
}
else {
List<FieldInfo> fullArrayFieldList = new ArrayList<FieldInfo>(arrayObject.getElementCount() + 1);
fullArrayFieldList.add(0, new FieldInfo("int length", "" + arrayObject.getElementCount()));
for (int i = 0; i < arrayObject.getElementCount(); i++) {
fullArrayFieldList.add(new FieldInfo("[" + i + "]", arrayObject.getElementValueString(i)));
indexToSlotList.add(i);
}
return fullArrayFieldList;
}
}
| Converts list index position to that of array element position in arrays.
| Uses the List built in compressArrayList to do the mapping.
|
| @param listIndexPosition
| the position selected in the list
| @return the translated index of field array element
|
private int indexToSlot(int listIndexPosition)
{
Integer slot = indexToSlotList.get(listIndexPosition);
return slot.intValue();
}
protected int getPreferredRows()
{
return 8;
}
}
top,
use,
map,
class ObjectInspector
. makeFrame
. getContent
. shouldAutoUpdate
. getListData
. listElementSelected
. showClass
. doInspect
. doGet
. remove
. selectArrayElement
. compressArrayList
. indexToSlot
. getPreferredRows
546 neLoCode
+ 55 LoComm