package bluej.stride.framedjava.slots;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.beans.binding.StringExpression;
import javafx.scene.Node;

import bluej.Config;
import bluej.editor.stride.FrameCatalogue;
import bluej.stride.framedjava.ast.TypeSlotFragment;
import bluej.stride.framedjava.ast.links.PossibleTypeLink;
import bluej.stride.framedjava.frames.CodeFrame;
import bluej.stride.framedjava.frames.ReturnFrame;
import bluej.stride.generic.Frame;
import bluej.stride.generic.FrameContentRow;
import bluej.stride.generic.InteractionManager;
import bluej.stride.generic.SuggestedFollowUpDisplay;
import bluej.stride.slots.CopyableHeaderItem;
import bluej.stride.slots.TypeCompletionCalculator;
import bluej.utility.Utility;
import bluej.utility.javafx.FXBiConsumer;
import bluej.utility.javafx.FXRunnable;
import bluej.utility.javafx.FXSupplier;
import bluej.utility.javafx.JavaFXUtil;
import threadchecker.OnThread;
import threadchecker.Tag;


| Created by neil on 22/05/2016. | public class TypeSlot extends StructuredSlot<TypeSlotFragment, InfixType, TypeCompletionCalculator> implements CopyableHeaderItem{ private final InteractionManager editor; private boolean isReturnType = false; private final List<FXSupplier<Boolean>> backspaceListeners = new ArrayList<>(); private final List<FXSupplier<Boolean>> deleteListeners = new ArrayList<>(); public static enum Role {
| Declaring arbitrary variable; can be any type | DECLARATION, | Return type; like DECLARATION but could also be void | RETURN, | Extends; must be a non-final class (not interface or primitive) | EXTENDS, | Must be an interface | INTERFACE, | Throws or Catch; must be a throwable | THROWS_CATCH; } public TypeSlot(InteractionManager editor, Frame parentFrame, CodeFrame<?> parentCodeFrame, FrameContentRow row, Role role, String stylePrefix) { super(editor, parentFrame, parentCodeFrame, row, stylePrefix, calculatorForRole(editor, role), hintsForRole(role)); this.editor = editor; onTextPropertyChangeOld(this::adjustReturnFrames); } private static TypeCompletionCalculator calculatorForRole(InteractionManager editor, Role role) { switch (role) { case THROWS_CATCH: return new TypeCompletionCalculator(editor, Throwable.class); case INTERFACE: return new TypeCompletionCalculator(editor, InteractionManager.Kind.INTERFACE); case EXTENDS: return new TypeCompletionCalculator(editor, InteractionManager.Kind.CLASS_NON_FINAL); } return new TypeCompletionCalculator(editor); } private static List hintsForRole(Role role) { FrameCatalogue.Hint hintInt = new FrameCatalogue.Hint("int", "An integer (whole number)"); FrameCatalogue.Hint hintDouble = new FrameCatalogue.Hint("double", "A number value"); FrameCatalogue.Hint hintVoid = new FrameCatalogue.Hint("void", "No return"); FrameCatalogue.Hint hintString = new FrameCatalogue.Hint("String", "Some text"); FrameCatalogue.Hint hintActor = new FrameCatalogue.Hint("Actor", "A Greenfoot actor"); FrameCatalogue.Hint hintList = new FrameCatalogue.Hint("List<String>", "A list of String"); FrameCatalogue.Hint hintObj = Config.isGreenfoot() ? hintActor : hintList; FrameCatalogue.Hint hintIO = new FrameCatalogue.Hint("IOException", "An IO exception"); switch (role) { case DECLARATION: return Arrays.asList(hintInt, hintDouble, hintString, hintObj); case RETURN: return Arrays.asList(hintInt, hintDouble, hintString, hintVoid); case EXTENDS: if (Config.isGreenfoot()) return Arrays.asList(hintActor); else{ return Collections.emptyList(); } case INTERFACE: return Collections.emptyList(); case THROWS_CATCH: return Arrays.asList(hintIO); } return Collections.emptyList(); } @Override protected TypeSlotFragment makeSlotFragment(String content, String javaCode) { return new TypeSlotFragment(content, javaCode, this); } @Override public ExpressionSlot asExpressionSlot() { return null; } public void setText(TypeSlotFragment rhs) { rhs.registerSlot(this); setText(rhs.getContent()); } @Override protected InfixType newInfix(InteractionManager editor, ModificationToken token) { return new InfixType(editor, this, token); } public void markReturnType() { isReturnType = true; } private void adjustReturnFrames(String oldValue, String newValue) { if (!isReturnType) return; if ((oldValue.equals("void") || oldValue.equals("")) && !(newValue.equals("void") || newValue.equals(""))) { for (Frame f : Utility.iterableStream(getParentFrame().getAllFrames())) { if (f instanceof ReturnFrame) { ReturnFrame rf = (ReturnFrame) f; rf.showValue(); } } } else if (!oldValue.equals("void") && newValue.equals("void")) { List<FXRunnable> removeActions = getParentFrame().getAllFrames() .filter(f -> f instanceof ReturnFrame) .map(f -> (ReturnFrame)f) .map(rf -> rf.getRemoveFilledValueAction()) .filter(a -> a != null) .collect(Collectors.toList()); if (!removeActions.isEmpty()) { JavaFXUtil.runNowOrLater(() -> { SuggestedFollowUpDisplay disp = new SuggestedFollowUpDisplay(editor, "Return type changed to void. Would you like to remove return values from all return frames in this method?", () -> removeActions.forEach(FXRunnable::run)); disp.showBefore(getComponents().get(0)); }); } } } @Override public void saved() { } @Override public boolean canCollapse() { return false; } @Override public List findLinks() { return topLevel.findTypeLinks(); } public StringExpression javaProperty() { return textMirror; }
| An action to call when a comma is inserted at the top-level of | the type slot (i.e. "HashMap<Int,>" would not trigger this because | * it's inside a generic sub-structured item). Passes the text * before the comma and after the comma. */ public void onTopLevelComma(FXBiConsumer<String, String> listener) | |
{ | |
afterModify.add(() -> { | | topLevel.runIfCommaDirect(listener); | | }); | | } | | @Override | | public @OnThread(Tag.FXPlatform) boolean backspaceAtStart() | | { | | // Must make sure that we run all listeners, and not short-circuit because one returned true: | | boolean transferredFocus = Utility.mapList(backspaceListeners, FXSupplier::get).stream().reduce(false, (a, b) -> a || b); | | if (transferredFocus) | | return true; | | else{ return super.backspaceAtStart(); | | } | | } | | @Override | | @OnThread(Tag.FXPlatform) | | public boolean deleteAtEnd() | | { | | // Must make sure that we run all listeners, and not short-circuit because one returned true: | | boolean transferredFocus = Utility.mapList(deleteListeners, FXSupplier::get).stream().reduce(false, (a, b) -> a || b); | | if (transferredFocus) | | return true; | | else{ return super.deleteAtEnd(); | | } | | } | | // Should return true if focus has been transferred out of the slot | | public void addBackspaceAtStartListener(FXSupplier<Boolean> listener) | | { | | backspaceListeners.add(listener); | | } | | // Should return true if focus has been transferred out of the slot | | public void addDeleteAtEndListener(FXSupplier<Boolean> listener) | | { | | deleteListeners.add(listener); | | } | | @Override | | public Stream<? extends Node> makeDisplayClone(InteractionManager editor) | | { | | return topLevel.makeDisplayClone(editor); | | } | | }

.   TypeSlot
.   calculatorForRole
.   hintsForRole
.   makeSlotFragment
.   asExpressionSlot
.   setText
.   newInfix
.   markReturnType
.   adjustReturnFrames
.   saved
.   canCollapse
.   findLinks
.   javaProperty




247 neLoCode + 50 LoComm