package bluej.editor.stride;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import bluej.utility.BackgroundConsumer;
import bluej.utility.Utility;
import bluej.utility.javafx.FXPlatformRunnable;
import bluej.utility.javafx.JavaFXUtil;
import javafx.beans.Observable;
import javafx.beans.binding.DoubleExpression;
import javafx.beans.binding.StringExpression;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableStringValue;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
import javafx.util.Duration;

import bluej.collect.StrideEditReason;
import bluej.parser.AssistContent;
import bluej.stride.framedjava.ast.JavaFragment;
import bluej.stride.framedjava.ast.Loader;
import bluej.stride.framedjava.ast.SlotFragment;
import bluej.stride.framedjava.ast.links.PossibleLink;
import bluej.stride.framedjava.elements.CodeElement;
import bluej.stride.framedjava.frames.GreenfootFrameUtil;
import bluej.stride.framedjava.frames.StrideCategory;
import bluej.stride.framedjava.frames.StrideDictionary;
import bluej.stride.framedjava.slots.ExpressionSlot;
import bluej.stride.generic.AssistContentThreadSafe;
import bluej.stride.generic.CanvasParent;
import bluej.stride.generic.ExtensionDescription;
import bluej.stride.generic.Frame;
import bluej.stride.generic.FrameCanvas;
import bluej.stride.generic.FrameCursor;
import bluej.stride.generic.FrameDictionary;
import bluej.stride.generic.FrameTypeCheck;
import bluej.stride.generic.InteractionManager;
import bluej.stride.generic.RecallableFocus;
import bluej.stride.slots.EditableSlot;
import bluej.stride.slots.LinkedIdentifier;
import bluej.stride.slots.SuggestionList;
import bluej.utility.javafx.FXPlatformConsumer;
import bluej.utility.javafx.FXSupplier;
import nu.xom.Element;
import threadchecker.OnThread;
import threadchecker.Tag;


| This is the GUI representation of the frame shelf, one per Stride editor window. | @OnThread(Tag.FX) public class FrameShelf implements InteractionManager, CanvasParent, FrameTypeCheck{ private final SimpleStringProperty fakeName = new SimpleStringProperty("..."); private final ObjectProperty<Frame.View> viewHolder = new ReadOnlyObjectWrapper<>(Frame.View.NORMAL); private final FXTabbedEditor parent; private final BorderPaneWithHighlightColor shelfPane = new BorderPaneWithHighlightColor(); private final FrameCanvas canvas = new FrameCanvas(this, this, "shelf-"); private final FrameSelection selection = new FrameSelection(this); private final FrameShelfStorage centralStorage; private FrameCursor dragTarget; public FrameShelf(FXTabbedEditor parent, FrameShelfStorage storage) { this.parent = parent; shelfPane.setCenter(canvas.getNode()); shelfPane.setStyle(getFontCSS().get()); this.centralStorage = storage; storage.registerShelf(this); } @Override @OnThread(Tag.FXPlatform) public void withCompletions(JavaFragment.PosInSourceDoc pos, ExpressionSlot<?> completing, CodeElement codeEl, FXPlatformConsumer<List<AssistContentThreadSafe>> handler) { JavaFXUtil.runAfterCurrent(() -> handler.accept(Collections.emptyList())); } @Override @OnThread(Tag.FXPlatform) public void withAccessibleMembers(JavaFragment.PosInSourceDoc pos, Set<AssistContent.CompletionKind> kinds, boolean includeOverridden, FXPlatformConsumer<List<AssistContentThreadSafe>> handler) { JavaFXUtil.runAfterCurrent(() -> handler.accept(Collections.emptyList())); } @Override @OnThread(Tag.FXPlatform) public void withSuperConstructors(FXPlatformConsumer<List<AssistContentThreadSafe>> handler) { JavaFXUtil.runAfterCurrent(() -> handler.accept(Collections.emptyList())); } @Override @OnThread(Tag.FXPlatform) public void withTypes(BackgroundConsumer<Map<String, AssistContentThreadSafe>> handler) { Utility.runBackground(() -> handler.accept(Collections.emptyMap())); } @Override @OnThread(Tag.FXPlatform) public void withTypes(Class<?> superType, boolean includeSelf, Set<Kind> kinds, BackgroundConsumer<Map<String, AssistContentThreadSafe>> handler) { Utility.runBackground(() -> handler.accept(Collections.emptyMap())); } @Override @OnThread(Tag.Any) public Map> getImportSuggestions() { return Collections.emptyMap(); } @Override public void addImport(String importSrc) { } @Override public FrameCursor getFocusedCursor() { return null; } @Override public List getAvailableFilenames() { return Collections.emptyList(); } @Override public ObservableStringValue nameProperty() { return fakeName; } @Override public FrameDictionary getDictionary() { return StrideDictionary.getDictionary(); } @Override @OnThread(Tag.FXPlatform) public void searchLink(PossibleLink link, FXPlatformConsumer<Optional<LinkedIdentifier>> callback) { JavaFXUtil.runAfterCurrent(() -> callback.accept(Optional.empty())); } @Override public Pane getDragTargetCursorPane() { return parent.getDragCursorPane(); } @Override public void ensureImportsVisible() { } @Override public void updateCatalog(FrameCursor f) { } @Override public void updateErrorOverviewBar() { } @Override public Paint getHighlightColor() { return shelfPane.cssHighlightColorProperty().get(); } @Override public List getThisConstructors() { return Collections.emptyList(); } @Override public FrameEditor getFrameEditor() { return null; } @Override public void recordCodeCompletionStarted(SlotFragment position, int index, String stem, int codeCompletionId) { } @Override public void recordCodeCompletionEnded(SlotFragment position, int index, String stem, String completion, int codeCompletionId) { } @Override public void recordErrorIndicatorShown(int identifier) { } @Override public void setupFrame(Frame f) { FXTabbedEditor.setupFrameDrag(f, true, () -> parent, () -> true, () -> selection); } @Override public void setupFrameCursor(FrameCursor c) { } @Override public void setupFocusableSlotComponent(EditableSlot parent, Node focusableComponent, boolean canCodeComplete, FXSupplier<List<ExtensionDescription>> getExtensions, List<FrameCatalogue.Hint> hints) { } @Override public void setupSuggestionWindow(Stage window) { } @Override public void clickNearestCursor(double sceneX, double sceneY, boolean shiftDown) { FrameCursor c = canvas.findClosestCursor(sceneX, sceneY, Collections.emptyList(), false, true); if (c != null) c.requestFocus(); } @Override public FrameCursor findCursor(double sceneX, double sceneY, FrameCursor prevCursor, FrameCursor nextCursor, List<Frame> exclude, boolean isDrag, boolean canDescend) { return canvas.findClosestCursor(sceneX, sceneY, exclude, isDrag, canDescend); } @Override public FrameCursor createCursor(FrameCanvas parent) { return new FrameCursor(this, parent); } @Override public Observable getObservableScroll() { return new ReadOnlyDoubleWrapper(0.0); } @Override public DoubleExpression getObservableViewportHeight() { return new ReadOnlyDoubleWrapper(0.0); } @Override public WindowOverlayPane getWindowOverlayPane() { return null; } @Override public CodeOverlayPane getCodeOverlayPane() { return null; } @Override public void modifiedFrame(Frame f, boolean force) { } @Override public void recordEdits(StrideEditReason reason) { } @Override public void afterRegenerateAndReparse(FXPlatformRunnable action) { } @Override public void beginRecordingState(RecallableFocus f) { } @Override public void endRecordingState(RecallableFocus f) { } @Override public void scrollTo(Node n, double yOffsetFromTop, Duration duration) { } @Override public void ensureNodeVisible(Node node) { } @Override public FrameSelection getSelection() { return selection; } @Override public void registerStackHighlight(Frame frame) { } @Override public boolean isLoading() { return false; } @Override public ReadOnlyObjectProperty viewProperty() { return viewHolder; } @Override public void showUndoDeleteBanner(int totalEffort) { } @Override public boolean isEditable() { return true; } @Override public BooleanProperty cheatSheetShowingProperty() { return null; } @Override public void recordUnknownCommandKey(Frame enclosingFrame, int index, char key) { } @Override public void recordShowHideFrameCatalogue(boolean show, FrameCatalogue.ShowReason reason) { } @Override @OnThread(Tag.FX) public ImageView makeClassImageView() { return null; } @Override public FrameTypeCheck check(FrameCanvas childCanvas) { return this; } @Override public FrameCursor getCursorBefore(FrameCanvas c) { return null; } @Override public FrameCursor getCursorAfter(FrameCanvas c) { return null; } @Override public List getAvailableExtensions(FrameCanvas canvas, FrameCursor cursorInCanvas) { return Collections.emptyList(); } @Override public InteractionManager getEditor() { return this; } @Override public void modifiedCanvasContent() { } @Override public Frame getFrame() { return null; } @Override public CanvasKind getChildKind(FrameCanvas c) { return null; } @Override public boolean canInsert(StrideCategory category) { return true; } @Override public boolean canPlace(Class<? extends Frame> type) { return true; } @Override public StringExpression getFontCSS() { return new ReadOnlyStringWrapper("-fx-font-size:10pt;"); } @Override public double getFontSize() { return 10; } public Node getNode() { return shelfPane; } @OnThread(Tag.FXPlatform) public void draggedTo(List<Frame> dragSourceFrames, double sceneX, double sceneY, boolean copying) { Bounds shelfBounds = shelfPane.localToScene(shelfPane.getBoundsInLocal()); if (sceneX < shelfBounds.getMinX() || sceneX > shelfBounds.getMaxX()) { if (dragTarget != null) { dragTarget.stopShowAsDropTarget(); dragTarget = null; } } else { FrameCursor newDragTarget = canvas.findClosestCursor(sceneX, sceneY, dragSourceFrames, true, true); if (newDragTarget != null && dragTarget != newDragTarget) { if (dragTarget != null) { dragTarget.stopShowAsDropTarget(); dragTarget = null; } boolean src = FXTabbedEditor.isUselessDrag(newDragTarget, dragSourceFrames, copying); boolean acceptsAll = true; for (Frame srcFrame : dragSourceFrames) { acceptsAll &= newDragTarget.getParentCanvas().acceptsType(srcFrame); } newDragTarget.showAsDropTarget(src, acceptsAll, copying); dragTarget = newDragTarget; } } if (dragTarget != null) { dragTarget.updateDragCopyState(copying); } } @OnThread(Tag.FXPlatform) public void dragEnd(ArrayList<Frame> dragSourceFrames, boolean fromShelf, boolean copying) { if (dragSourceFrames != null && !dragSourceFrames.isEmpty()) { if (dragTarget != null) { boolean canMove = dragSourceFrames.stream().allMatch(src -> dragTarget.getParentCanvas().acceptsType(src)); if (canMove && !FXTabbedEditor.isUselessDrag(dragTarget, dragSourceFrames, copying)) { beginRecordingState(dragTarget); performDrag(dragSourceFrames, fromShelf, copying); endRecordingState(dragTarget); } selection.clear(); dragTarget.stopShowAsDropTarget(); dragTarget = null; } } } @OnThread(Tag.FXPlatform) private void performDrag(List<Frame> dragSourceFrames, boolean fromShelf, boolean copying) { Frame parentFrame = dragTarget.getParentCanvas().getParent().getFrame(); boolean shouldDisable = parentFrame != null && !parentFrame.isFrameEnabled(); InteractionManager editor = dragSourceFrames.get(0).getEditor(); if (!fromShelf && !copying) editor.recordEdits(StrideEditReason.FLUSH); Collections.reverse(dragSourceFrames); List<CodeElement> elements = GreenfootFrameUtil.getElementsForMultipleFrames(dragSourceFrames); for (CodeElement codeElement : elements) { final Frame frame = codeElement.createFrame(this); dragTarget.insertBlockAfter(frame); if (shouldDisable) frame.setFrameEnabled(false); } if (!copying) dragSourceFrames.forEach(src -> src.getParentCanvas().removeBlock(src)); if (!fromShelf && !copying) editor.recordEdits(StrideEditReason.FRAMES_DRAG_SHELF); } public void cleanup() { centralStorage.deregisterShelf(this); }
| Gets the observable list of frames on this graphical shelf interface. | | Do not modify the contents directly under any circumstances! Only use it for listening. | public ObservableList getContent() { return canvas.getBlockContents(); } public void setContent(Element framesElement) { canvas.clear(); for (int i = 0; i < framesElement.getChildElements().size(); i++) { canvas.insertBlockAfter(Loader.loadElement(framesElement.getChildElements().get(i)).createFrame(this), null); } } }
top, use, map, class FrameShelf

.   FrameShelf
.   withCompletions
.   withAccessibleMembers
.   withSuperConstructors
.   withTypes
.   withTypes
.   getImportSuggestions
.   addImport
.   getFocusedCursor
.   getAvailableFilenames
.   nameProperty
.   getDictionary
.   searchLink
.   getDragTargetCursorPane
.   ensureImportsVisible
.   updateCatalog
.   updateErrorOverviewBar
.   getHighlightColor
.   getThisConstructors
.   getFrameEditor
.   recordCodeCompletionStarted
.   recordCodeCompletionEnded
.   recordErrorIndicatorShown
.   setupFrame
.   setupFrameCursor
.   setupFocusableSlotComponent
.   setupSuggestionWindow
.   clickNearestCursor
.   findCursor
.   createCursor
.   getObservableScroll
.   getObservableViewportHeight
.   getWindowOverlayPane
.   getCodeOverlayPane
.   modifiedFrame
.   recordEdits
.   afterRegenerateAndReparse
.   beginRecordingState
.   endRecordingState
.   scrollTo
.   ensureNodeVisible
.   getSelection
.   registerStackHighlight
.   isLoading
.   viewProperty
.   showUndoDeleteBanner
.   isEditable
.   cheatSheetShowingProperty
.   recordUnknownCommandKey
.   recordShowHideFrameCatalogue
.   makeClassImageView
.   check
.   getCursorBefore
.   getCursorAfter
.   getAvailableExtensions
.   getEditor
.   modifiedCanvasContent
.   getFrame
.   getChildKind
.   canInsert
.   canPlace
.   getFontCSS
.   getFontSize
.   getNode
.   draggedTo
.   dragEnd
.   performDrag
.   cleanup
.   getContent
.   setContent




740 neLoCode + 3 LoComm