package bluej.stride.framedjava.frames;

import bluej.Config;
import bluej.stride.framedjava.ast.AccessPermission;
import bluej.stride.framedjava.ast.HighlightedBreakpoint;
import bluej.stride.framedjava.ast.ParamFragment;
import bluej.stride.framedjava.canvases.JavaCanvas;
import bluej.stride.framedjava.elements.CodeElement;
import bluej.stride.framedjava.elements.MethodWithBodyElement;
import bluej.stride.framedjava.slots.TypeSlot;
import bluej.stride.generic.DocumentedSingleCanvasFrame;
import bluej.stride.generic.ExtensionDescription;
import bluej.stride.generic.ExtensionDescription.ExtensionSource;
import bluej.stride.generic.Frame;
import bluej.stride.generic.FrameCanvas;
import bluej.stride.generic.FrameContentRow;
import bluej.stride.generic.FrameCursor;
import bluej.stride.generic.InteractionManager;
import bluej.stride.slots.AccessPermissionSlot;
import bluej.stride.slots.ChoiceSlot;
import bluej.stride.slots.EditableSlot;
import bluej.stride.slots.FormalParameters;
import bluej.stride.slots.HeaderItem;
import bluej.stride.slots.Throws;
import bluej.utility.javafx.FXRunnable;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.SharedTransition;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

import threadchecker.OnThread;
import threadchecker.Tag;


| Container-block representing a method. | @author Fraser McKay | public abstract class MethodFrameWithBody<T extends MethodWithBodyElement> extends DocumentedSingleCanvasFrame implements DebuggableFrame, CodeFrame<T>{ protected final ChoiceSlot<AccessPermission> access; protected final Throws throwsPane; private final Rectangle dropShadowDummy; protected FormalParameters paramsPane; private boolean showingBirdseye; private FXRunnable headerCleanup;
| Default constructor. | public MethodFrameWithBody(final InteractionManager editor) { super(editor, "", "method-"); access = new AccessPermissionSlot(editor, this, getHeaderRow(), "method-"); access.setValue(AccessPermission.PUBLIC); throwsPane = new Throws(this, () -> { TypeSlot s = new TypeSlot(editor, this, this, getHeaderRow(), TypeSlot.Role.THROWS_CATCH, "method-"); s.setSimplePromptText("thrown type"); return s; }, () -> getCanvas().getFirstCursor().requestFocus(), editor); dropShadowDummy = new Rectangle(0, 0, 0, 0); final Region headerRow = getHeaderRow().getNode(); headerRow.getStyleClass().add("method-header"); dropShadowDummy.widthProperty().bind(headerRow.widthProperty()); dropShadowDummy.heightProperty().bind(headerRow.heightProperty()); Rectangle small = new Rectangle(); small.widthProperty().bind(canvas.widthProperty().subtract(canvas.leftMargin()).subtract(canvas.rightMargin())); small.yProperty().bind(dropShadowDummy.heightProperty().add(dropShadowDummy.yProperty())); small.heightProperty().set(15.0); dropShadowDummy.clipProperty().set(small); if (editor != null && editor.getWindowOverlayPane() != null) { final DoubleBinding offset = new DoubleBinding() { @Override protected double computeValue() { if (!getHeaderItems().findFirst().isPresent()) return 0; final double headerTopSceneY = getHeaderRow().getNode().localToScene(0, 0).getY(); final double headerHeight = getHeaderRow().getNode().getHeight(); final double overlayY = editor.getWindowOverlayPane().sceneYToWindowOverlayY(headerTopSceneY); final double marginBeneathHeader = 20.0; final double maxOffset = getRegion().localToScene(getRegion().getBoundsInLocal()).getMaxY() - headerTopSceneY - marginBeneathHeader - headerHeight; if (overlayY > 0) { return overlayY; } else { if (overlayY < -maxOffset) { if (overlayY < - (maxOffset + getHeaderRow().getNode().getHeight())) { return 1; } else { return overlayY + maxOffset; } } else { return 0; } } } { super.bind(editor.getObservableScroll()); super.bind(getRegion().layoutBoundsProperty()); super.bind(getRegion().heightProperty()); super.bind(getHeaderRow().getNode().heightProperty()); super.bind(getRegion().localToSceneTransformProperty()); super.bind(editor.getObservableViewportHeight()); super.bind(getHeaderRow().getNode().layoutBoundsProperty()); } }; dropShadowDummy.effectProperty().bind(new ObjectBinding<Effect>() { DropShadow dropShadow = new DropShadow(); @Override protected Effect computeValue() { return offset.get() <= 0 ? dropShadow : null; } { super.bind(offset); } { dropShadow.setRadius(8.0); dropShadow.setOffsetX(4.0); dropShadow.setOffsetY(4.0); dropShadow.setColor(Color.color(0.6, 0.6, 0.6)); } }); offset.addListener(new ChangeListener<Number>() { private Pane imageView; private boolean addingImageView = false; private SimpleDoubleProperty imageViewY = new SimpleDoubleProperty(0.0); @Override public void changed(ObservableValue<? extends Number> arg0, Number oldVal, Number newVal) { if (editor.getWindowOverlayPane() == null) { return; } if (!isFrameEnabled() || getParentCanvas() == null) { return; } if (editor.viewProperty().get() != View.NORMAL) { return; } if (newVal.doubleValue() > 0 && imageView != null) { editor.getWindowOverlayPane().removeOverlay(imageView); editor.getWindowOverlayPane().removeOverlay(dropShadowDummy); imageView = null; } else if (newVal.doubleValue() <= 0) { imageViewY.setValue(newVal); if (imageView == null && !addingImageView) { addingImageView = true; imageView = getHeaderRow().makeDisplayClone(editor); imageView.getStyleClass().addAll("method-header", "method-header-row-pinned-clone"); double sceneX = getHeaderRow().getSceneBounds().getMinX(); double windowOverlayX = editor.getWindowOverlayPane().sceneXToWindowOverlayX(sceneX); editor.getWindowOverlayPane().addOverlay(imageView, new SimpleDoubleProperty(windowOverlayX), imageViewY); imageView.applyCss(); small.xProperty().set(canvas.getNode().localToScene(canvas.getNode().getBoundsInLocal()).getMinX() - sceneX + canvas.leftMargin().get()); editor.getWindowOverlayPane().addOverlay(dropShadowDummy, new SimpleDoubleProperty(windowOverlayX), imageViewY); imageView.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent e) { editor.scrollTo(headerRow, -2); } }); addingImageView = false; } }
| | |// Play a fade if it was zero and now isn't, or vice versa: | |if ((oldVal.doubleValue() == 0 && newVal.doubleValue() != 0) || (oldVal.doubleValue() != 0 && newVal.doubleValue() == 0)) {} FadeTransition ft = new FadeTransition(Duration.millis(200), getHeadVBox()); | |ft.setToValue(newVal.doubleValue() == 0 ? 1.0 : 0.8); | |ft.play(); | |} } { JavaFXUtil.addChangeListener(editor.viewProperty(), v -> { if (v != View.NORMAL && imageView != null) { editor.getWindowOverlayPane().removeOverlay(imageView); editor.getWindowOverlayPane().removeOverlay(dropShadowDummy); imageView = null; } else if (v == View.NORMAL && imageView == null) { changed(offset, offset.get(), offset.get()); } }); headerCleanup = () -> { editor.getWindowOverlayPane().removeOverlay(imageView); editor.getWindowOverlayPane().removeOverlay(dropShadowDummy); imageView = null; }; } }); } AnchorPane.setTopAnchor(canvas.getNode(), 0.0); } protected List generateParams() { return paramsPane.getSlotElement(); } @Override public FrameCanvas createCanvas(InteractionManager editor, String stylePrefix) { return new JavaCanvas(editor, this, stylePrefix, true); } @Override @OnThread(Tag.FXPlatform) public HighlightedBreakpoint showDebugBefore(DebugInfo debug) { return ((JavaCanvas)getCanvas()).showDebugBefore(null, debug); } @SuppressWarnings("unchecked") protected List getContents() { List<CodeElement> contents = new ArrayList<CodeElement>(); getMembersFrames().forEach(f -> { f.regenerateCode(); contents.add(f.getCode()); }); return contents; } public List getMembersFrames() { return canvas.getBlocksSubtype(CodeFrame.class); } @Override public void checkForEmptySlot() { paramsPane.checkForEmptySlot(); } public void setAccess(AccessPermission value) { access.setValue(value); } public FormalParameters getParamsPane() { return paramsPane; } @Override public List getDeclaredVariablesWithin(FrameCanvas c) { if (c != getCanvas()) throw new IllegalArgumentException("Canvas does not exist in this frame"); return paramsPane.getVars().filter(s -> s != null && !s.isEmpty()).collect(Collectors.toList()); } @Override public List getAvailableExtensions(FrameCanvas canvas, FrameCursor cursorInCanvas) { ArrayList<ExtensionDescription> extensions = new ArrayList<>(super.getAvailableExtensions(canvas, cursorInCanvas)); extensions.add(new ExtensionDescription(StrideDictionary.THROWS_EXTENSION_CHAR, Config.getString("frame.class.add.throw"), () -> throwsPane.addTypeSlotAtEnd("", true), true, ExtensionSource.INSIDE_FIRST, ExtensionSource.MODIFIER)); return extensions; } public void addThrows(String type) { throwsPane.addTypeSlotAtEnd(type, true); } @Override @OnThread(Tag.FXPlatform) public void setView(View oldView, View newView, SharedTransition animate) { super.setView(oldView, newView, animate); paramsPane.setView(newView, animate); if (newView.isBirdseye() != oldView.isBirdseye()) { if (newView.isBirdseye()) { canvas.shrinkUsing(animate.getProgress().negate().add(1.0)); } else { canvas.growUsing(animate.getProgress()); } showingBirdseye = newView.isBirdseye(); } animate.getProgress().addListener((a, oldVal, newVal) -> { if (Math.round(oldVal.doubleValue()) != Math.round(newVal.doubleValue())) { JavaFXUtil.setPseudoclass("bj-birdseye", newView.isBirdseye(), getNode(), canvas.getNode()); JavaFXUtil.setPseudoclass("bj-birdseye-nodoc", newView == View.BIRDSEYE_NODOC, getNode(), canvas.getNode()); JavaFXUtil.setPseudoclass("bj-birdseye-doc", newView == View.BIRDSEYE_DOC, getNode(), canvas.getNode()); } }); if (isFrameEnabled() && (oldView == View.JAVA_PREVIEW || newView == View.JAVA_PREVIEW)) canvas.previewCurly(newView == View.JAVA_PREVIEW, header.getLeftFirstItem() + tweakCurlyX(), tweakOpeningCurlyY(), animate); } protected void restoreDetails(MethodWithBodyElement nme) { setDocumentation(nme.getDocumentation()); access.setValue(nme.getAccessPermission()); throwsPane.setTypes(nme.getThrowsTypes()); paramsPane.setParams(nme.getParams(), f -> f.getParamType().getContent(), f -> f.getParamName().getContent()); canvas.restore(nme.getContents(), getEditor()); } @Override protected void cleanupFrame() { headerCleanup.run(); super.cleanupFrame(); } @Override protected double tweakCurlyX() { return 2; } protected abstract class MethodHeaderRow extends FrameContentRow { public MethodHeaderRow(Frame parentFrame, String stylePrefix) { super(parentFrame, stylePrefix); } protected abstract EditableSlot getSlotBeforeParams(); protected abstract EditableSlot getSlotAfterParams(); @Override public void focusRight(HeaderItem src) { if (src == getSlotBeforeParams()) { paramsPane.ensureAtLeastOneParameter(); } super.focusRight(src); } @Override public void focusLeft(HeaderItem src) { if (src == getSlotAfterParams()) { if (paramsPane.ensureAtLeastOneParameter()) { paramsPane.focusBeginning(); return; } } super.focusLeft(src); } @Override public boolean focusRightEndFromNext() { if (getSlotAfterParams() == null) { if (paramsPane.ensureAtLeastOneParameter()) { paramsPane.focusBeginning(); return true; } } return super.focusRightEndFromNext(); } @Override @OnThread(Tag.FXPlatform) public void escape(HeaderItem src) { if (paramsPane.findFormal(src) != null){ paramsPane.escape(src); } else { super.escape(src); } } } }

.   MethodFrameWithBody
.   computeValue
.   computeValue
.   changed
.   handle
.   generateParams
.   createCanvas
.   showDebugBefore
.   getContents
.   getMembersFrames
.   checkForEmptySlot
.   setAccess
.   getParamsPane
.   getDeclaredVariablesWithin
.   getAvailableExtensions
.   addThrows
.   setView
.   restoreDetails
.   cleanupFrame
.   tweakCurlyX

top, use, map, abstract class MethodHeaderRow

.   MethodHeaderRow
.   getSlotBeforeParams
.   getSlotAfterParams
.   focusRight
.   focusLeft
.   focusRightEndFromNext
.   escape




594 neLoCode + 9 LoComm