package bluej.debugmgr.objectbench;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javafx.geometry.Point2D;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.TilePane;

import bluej.Config;
import bluej.collect.DataCollector;
import bluej.debugger.DebuggerObject;
import bluej.debugger.gentype.GenTypeClass;
import bluej.debugmgr.NamedValue;
import bluej.debugmgr.ValueCollection;
import bluej.pkgmgr.PkgMgrFrame;
import bluej.testmgr.record.InvokerRecord;
import bluej.utility.JavaNames;
import bluej.utility.javafx.JavaFXUtil;
import threadchecker.OnThread;
import threadchecker.Tag;


| The class responsible for the panel that displays objects | at the bottom of the package manager. | | @author Michael Cahill | @author Andrew Patterson | @OnThread(Tag.FXPlatform) public class ObjectBench extends javafx.scene.control.ScrollPane implements ValueCollection, ObjectBenchInterface, PkgMgrFrame.PkgMgrPane{ @OnThread(Tag.Any) private final List<ObjectBenchListener> listenerList = new ArrayList<>(); private ObjectBenchPanel obp;
| This list maintains the correct internal state of the object bench. Whenever you | modify this list, you must manually mirror the change into obp.getChildren() | using correct threading rules. | @OnThread(Tag.Any) private final List<ObjectWrapper> objects = new ArrayList<>();
| This can be read from any thread, but should only be altered on FXPlatform thread. | @OnThread(value = Tag.Any, requireSynchronized = true) private ObjectWrapper selectedObject; private final PkgMgrFrame pkgMgrFrame; @OnThread(Tag.FXPlatform) private List<InvokerRecord> invokerRecords;
| Construct an object bench which is used to hold | a bunch of object reference Components. | @OnThread(Tag.FXPlatform) public ObjectBench(PkgMgrFrame pkgMgrFrame) { super(); createComponent(); this.pkgMgrFrame = pkgMgrFrame; updateAccessibleName(); }
| Updates the accessible name for screen readers, based on the number | of objects currently on the bench | @OnThread(Tag.FXPlatform) private void updateAccessibleName() { String name = Config.getString("pkgmgr.objBench.title"); final int n = getObjectCount(); name += ": " + n + " " + Config.getString(n == 1 ? "pkgmgr.objBench.suffix.singular" : "pkgmgr.objBench.suffix.plural"); }
| Add an object (in the form of an ObjectWrapper) to this bench. | @OnThread(Tag.Any) public void addObject(ObjectWrapper wrapper) { addObject(wrapper, Optional.empty()); } @OnThread(Tag.Any) public void addObject(ObjectWrapper wrapper, Optional<Point2D> animateFromScene) { String newname = wrapper.getName(); int count = 1; if (JavaNames.isJavaKeyword(newname)) { newname = "x" + newname; } while (hasObject(newname)) { count++; newname = wrapper.getName() + count; } wrapper.setName(newname); synchronized (ObjectBench.this) { objects.add(wrapper); } JavaFXUtil.runNowOrLater(() -> { wrapper.setVisible(false); wrapper.setLayoutY(-1); obp.getChildren().add(wrapper); wrapper.animateIn(animateFromScene); updateAccessibleName(); }); } @Override public String addObject(DebuggerObject object, GenTypeClass type, String name) { ObjectWrapper wrapper = ObjectWrapper.getWrapper( pkgMgrFrame, this, object, type, name); addObject(wrapper); return wrapper.getName(); }
| Return all the wrappers stored in this object bench in an array | @OnThread(Tag.Any) public synchronized List getObjects() { return Collections.unmodifiableList(new ArrayList<>(objects)); }
| Return an iterator through all the objects on the bench (to meet | the ValueCollection interface) | @OnThread(Tag.Any) public Iterator getValueIterator() { return getObjects().iterator(); }
| Get the object with name 'name', or null, if it does not | exist. | | @param name The name to check for. | @return The named object wrapper, or null if not found. | @OnThread(Tag.Any) public synchronized ObjectWrapper getObject(String name) { for (Iterator<ObjectWrapper> i = objects.iterator(); i.hasNext(); ) { ObjectWrapper wrapper = i.next(); if (wrapper.getName().equals(name)) return wrapper; } return null; } @OnThread(Tag.Any) public NamedValue getNamedValue(String name) { return getObject(name); }
| Check whether the bench contains an object with name 'name'. | | @param name The name to check for. | @OnThread(Tag.Any) public boolean hasObject(String name) { return getObject(name) != null; }
| Count of object bench copmponents that are object wrappers | @return number of ObjectWrappers on the bench | @OnThread(Tag.Any) public synchronized int getObjectCount() { return objects.size(); }
| Remove all objects from the object bench. | public synchronized void removeAllObjects(String scopeId) { setSelectedObject (null); for (Iterator<ObjectWrapper> i = objects.iterator(); i.hasNext(); ) { ObjectWrapper wrapper = i.next(); wrapper.prepareRemove(); wrapper.getPackage().getDebugger().removeObject(scopeId, wrapper.getName()); } objects.clear(); JavaFXUtil.runNowOrLater(() -> obp.getChildren().clear()); resetRecordingInteractions(); updateAccessibleName(); }
| Remove an object from the object bench. When this is done, the object | is also removed from the scope of the package (so it is not accessible | as a parameter anymore) and the bench is redrawn. | public synchronized void removeObject(ObjectWrapper wrapper, String scopeId) { if (wrapper == selectedObject) { setSelectedObject(null); } DataCollector.removeObject(wrapper.getPackage(), wrapper.getName()); wrapper.prepareRemove(); wrapper.getPackage().getDebugger().removeObject(scopeId, wrapper.getName()); objects.remove(wrapper); wrapper.animateOut(() -> obp.getChildren().remove(wrapper)); updateAccessibleName(); }
| Remove the selected object from the bench. If no object is selected, | do nothing. | public void removeSelectedObject(String scopeId) { ObjectWrapper wrapper = getSelectedObject(); if (wrapper != null) removeObject(wrapper, scopeId); }
| Sets what is the currently selected ObjectWrapper, null can be given to | signal that no wrapper is selected. | @OnThread(Tag.FXPlatform) public synchronized void setSelectedObject(ObjectWrapper aWrapper) { if (selectedObject != null) { selectedObject.setSelected(false); } selectedObject = aWrapper; if (selectedObject != null && !selectedObject.isFocused()) { selectedObject.requestFocus(); } }
| Notify that an object has gained focus. The object becomes the selected object. | @OnThread(Tag.FXPlatform) public synchronized void objectGotFocus(ObjectWrapper aWrapper) { if (selectedObject == aWrapper) { return; } if (selectedObject != null) { selectedObject.setSelected(false); } selectedObject = aWrapper; selectedObject.setSelected(true); }
| Returns the currently selected object wrapper. | If no wrapper is selected null is returned. | @OnThread(Tag.Any) public synchronized ObjectWrapper getSelectedObject() { return selectedObject; }
| Add a listener for object events to this bench. | @param l The listener object. | @OnThread(Tag.Any) public void addObjectBenchListener(ObjectBenchListener l) { synchronized (listenerList) { listenerList.add(l); } }
| Remove a listener for object events to this bench. | @param l The listener object. | @OnThread(Tag.Any) public void removeObjectBenchListener(ObjectBenchListener l) { synchronized (listenerList) { listenerList.remove(l); } }
| Fire an object event for the named object. This will | notify all listeners that have registered interest for | notification on this event type. | @OnThread(Tag.FXPlatform) public void fireObjectSelectedEvent(ObjectWrapper wrapper) { synchronized (listenerList) { for (int i = listenerList.size() - 1; i >= 0; i--) { listenerList.get(i).objectEvent( new ObjectBenchEvent(this, ObjectBenchEvent.OBJECT_SELECTED, wrapper)); } } } | A key was pressed in the object bench. | @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) | public synchronized void keyPressed(KeyEvent e) { int selectedObjectIndex; if (selectedObject == null) { selectedObjectIndex = -1; } else { selectedObjectIndex = objects.indexOf(selectedObject); } switch (e.getCode()){ case LEFT: if (selectedObjectIndex > 0) { selectedObjectIndex--; } else { selectedObjectIndex = 0; } setSelectedObjectByIndex(selectedObjectIndex); break; case RIGHT: if (selectedObjectIndex < objects.size() - 1) { setSelectedObjectByIndex(selectedObjectIndex + 1); } break; case UP: selectedObjectIndex = selectedObjectIndex - obp.getNumberOfColumns(); if (selectedObjectIndex >= 0) { setSelectedObjectByIndex(selectedObjectIndex); } break; case DOWN: selectedObjectIndex = selectedObjectIndex + obp.getNumberOfColumns(); if (selectedObjectIndex < objects.size()) { setSelectedObjectByIndex(selectedObjectIndex); } break; case ENTER: case SPACE: case CONTEXT_MENU: showPopupMenu(); break; } }
| Sets the selected object from an index in the objects list. | The index MUST be valid. | private synchronized void setSelectedObjectByIndex(int i) { ((ObjectWrapper) objects.get(i)).requestFocus(); }
| Post the object menu for the selected object. | private synchronized void showPopupMenu() { if (selectedObject != null) { selectedObject.showMenu(); } } | Reset the recording of invocations. | @OnThread(Tag.FXPlatform) public void resetRecordingInteractions() { invokerRecords = new LinkedList<InvokerRecord>(); } @OnThread(Tag.FXPlatform) public void addInteraction(InvokerRecord ir) { if (invokerRecords == null) resetRecordingInteractions(); invokerRecords.add(ir); }
| Get the recorded interaction fixture declarations as Java code. | @OnThread(Tag.FXPlatform) public String getFixtureDeclaration(String firstIndent) { StringBuffer sb = new StringBuffer(); Iterator<InvokerRecord> it = invokerRecords.iterator(); while (it.hasNext()) { InvokerRecord ir = it.next(); if (ir.toFixtureDeclaration(firstIndent) != null) { sb.append(ir.toFixtureDeclaration(firstIndent)); } } return sb.toString(); }
| Get the recorded interaction fixture setup as Java code. | @OnThread(Tag.FXPlatform) public String getFixtureSetup(String secondIndent) { StringBuffer sb = new StringBuffer(); Iterator<InvokerRecord> it = invokerRecords.iterator(); while (it.hasNext()) { InvokerRecord ir = it.next(); if (ir.toFixtureSetup(secondIndent) != null) { sb.append(ir.toFixtureSetup(secondIndent)); } } return sb.toString(); }
| Get the recorded interactions as Java code. | @OnThread(Tag.FXPlatform) public String getTestMethod(String secondIndent) { StringBuffer sb = new StringBuffer(); Iterator<InvokerRecord> it = invokerRecords.iterator(); while (it.hasNext()) { InvokerRecord ir = it.next(); String testMethod = ir.toTestMethod(pkgMgrFrame, secondIndent); if (testMethod != null) { sb.append(testMethod); } } return sb.toString(); } @OnThread(Tag.FXPlatform) private synchronized void createComponent() { obp = new ObjectBenchPanel(); JavaFXUtil.addStyleClass(this, "object-bench"); setContent(obp); setFitToWidth(true); setMinViewportWidth(ObjectWrapper.WIDTH); setMinViewportHeight(ObjectWrapper.HEIGHT); this.setMinWidth(ObjectWrapper.WIDTH + 35 | space for scroll bar, foldout control | ; this.setMinHeight(ObjectWrapper.HEIGHT); resetRecordingInteractions(); setOnKeyPressed(this::keyPressed); } | This is the panel that lives inside the object bench's scrollpane | and actually holds the object wrapper components. | @OnThread(Tag.FXPlatform) private final class ObjectBenchPanel extends TilePane { public ObjectBenchPanel() { JavaFXUtil.addStyleClass(this, "object-bench-panel"); }
| Return the current number of rows or objects on this bench. | public int getNumberOfRows() { int objects = getChildren().size(); if (objects == 0) { return 1; } else { int objectsPerRow = (int)getWidth() / ObjectWrapper.WIDTH; return (objects + objectsPerRow - 1) / objectsPerRow; } }
| Return the current number of rows or objects on this bench. | public int getNumberOfColumns() { return (int)getWidth() / ObjectWrapper.WIDTH; } } @Override @OnThread(Tag.FX) public void requestFocus() { }
| Does one of the objects contained within have focus? | @OnThread(Tag.FXPlatform) public synchronized boolean objectHasFocus() { return objects.stream().anyMatch(w -> w.isFocused()); }
| Highlights the given object, and clears highlights on all | other objects. | | @param currentObject The object to highlight (may be null, | to just clear all existing highlights) | public void highlightObject(DebuggerObject currentObject) { for (ObjectWrapper wrapper : objects) { wrapper.setHighlight(currentObject != null && Objects.equals(wrapper.obj, currentObject)); } } }
top, use, map, class ObjectBench

.   ObjectBench
.   updateAccessibleName
.   addObject
.   addObject
.   addObject
.   getObjects
.   getValueIterator
.   getObject
.   getNamedValue
.   hasObject
.   getObjectCount
.   removeAllObjects
.   removeObject
.   removeSelectedObject
.   setSelectedObject
.   objectGotFocus
.   getSelectedObject
.   addObjectBenchListener
.   removeObjectBenchListener
.   fireObjectSelectedEvent
.   keyPressed
.   setSelectedObjectByIndex
.   showPopupMenu
.   resetRecordingInteractions
.   addInteraction
.   getFixtureDeclaration
.   getFixtureSetup
.   getTestMethod
.   createComponent

top, use, map, class ObjectBenchPanel

.   ObjectBenchPanel
.   getNumberOfRows
.   getNumberOfColumns
.   requestFocus
.   objectHasFocus
.   highlightObject




640 neLoCode + 61 LoComm