package bluej.stride.framedjava.frames;

import java.util.ArrayList;
import java.util.List;

import bluej.Config;
import bluej.stride.framedjava.ast.ExpressionSlotFragment;
import bluej.stride.framedjava.ast.FilledExpressionSlotFragment;
import bluej.stride.framedjava.ast.HighlightedBreakpoint;
import bluej.stride.framedjava.canvases.JavaCanvas;
import bluej.stride.framedjava.elements.CodeElement;
import bluej.stride.framedjava.elements.SwitchElement;
import bluej.stride.framedjava.frames.BreakFrame.BreakEncloser;
import bluej.stride.framedjava.slots.ExpressionSlot;
import bluej.stride.framedjava.slots.FilledExpressionSlot;
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.FrameFactory;
import bluej.stride.generic.FrameTypeCheck;
import bluej.stride.generic.InteractionManager;
import bluej.stride.generic.MultiCanvasFrame;
import bluej.stride.operations.PullUpContentsOperation;
import bluej.stride.slots.EditableSlot;
import bluej.stride.slots.SlotLabel;
import bluej.utility.Debug;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.SharedTransition;

import threadchecker.OnThread;
import threadchecker.Tag;


| Container-block representing a switch-case statement. | public class SwitchFrame extends MultiCanvasFrame implements CodeFrame<SwitchElement>, DebuggableParentFrame{ private static final String SWITCH_STYLE_PREFIX = "switch-"; private final ExpressionSlot<FilledExpressionSlotFragment> expression; private final JavaCanvas casesCanvas; private JavaCanvas defaultCanvas; private SwitchElement element; private final InteractionManager editor; private SlotLabel defaultLabel = new SlotLabel("default");
| Default constructor. | private SwitchFrame(InteractionManager editor) { super(editor, "switch", SWITCH_STYLE_PREFIX); this.editor = editor; casesCanvas = new JavaCanvas(editor, this, SWITCH_STYLE_PREFIX, false); addCanvas(null, casesCanvas); expression = new FilledExpressionSlot(editor, this, this, getHeaderRow(), SWITCH_STYLE_PREFIX){ @Override @OnThread(Tag.FXPlatform) public boolean backspaceAtStart() { if (isAlmostBlank()) { new PullUpContentsOperation(editor).activate(getParentFrame()); return true; } return super.backspaceAtStart(); } }; expression.setSimplePromptText("expression"); setHeaderRow(new SlotLabel("("), expression, new SlotLabel(")")); expression.onTextPropertyChange(updateSidebarCurried("switch ")); } public SwitchFrame(InteractionManager editor, ExpressionSlotFragment expression, boolean enabled) { this(editor); this.expression.setText(expression); frameEnabledProperty.set(enabled); } public boolean addDefault() { if (defaultCanvas != null) { return false; } defaultCanvas = new JavaCanvas(editor, this, "default-case-", false); JavaFXUtil.addStyleClass(defaultLabel, "divider-default-case"); addCanvas(new FrameContentRow(this, defaultLabel), defaultCanvas); defaultCanvas.getFirstCursor().requestFocus(); return true; } private void removeDefault() { if (defaultCanvas != null) { removeCanvas(defaultCanvas); defaultCanvas = null; } } public static FrameFactory getFactory() { return new FrameFactory<SwitchFrame>() { @Override public SwitchFrame createBlock(InteractionManager editor) { SwitchFrame switchFrame = new SwitchFrame(editor); switchFrame.getFirstInternalCursor().insertBlockAfter(CaseFrame.getFactory().createBlock(editor)); return switchFrame; } @Override public Class getBlockClass() { return SwitchFrame.class; } }; } @Override public void pullUpContents() { List<Frame> casesFrames = new ArrayList<>(casesCanvas.getBlockContents()); casesFrames.forEach(c -> casesCanvas.removeBlock(c)); final List<Frame> contents = new ArrayList<>(); casesFrames.forEach(c -> { contents.add(new BlankFrame(editor)); contents.addAll(((CaseFrame) c).getValidPulledStatements()); } ); getCursorBefore().insertFramesAfter(contents); if (defaultCanvas != null) { getCursorBefore().insertBlockAfter(new BlankFrame(getEditor())); List<Frame> defaultContents = new ArrayList<>(defaultCanvas.getBlockContents()); defaultContents.forEach(c -> defaultCanvas.removeBlock(c)); getCursorBefore().insertFramesAfter(defaultContents); } editor.modifiedFrame(this, false); } public void pullUpInnerCaseContents(CaseFrame frame) { int index = casesCanvas.getBlockContents().indexOf(frame); if (index < 0) { throw new IllegalStateException("CaseFrame should be in the casesCanvas"); } else if (index == 0) { Debug.message("pullUpInnerCaseContents @ SwitchFrame: Unimplemented case, waiting a design decision"); } else { List<Frame> contents = frame.getValidPulledStatements(); CaseFrame previous = (CaseFrame) casesCanvas.getBlockContents().get(index - 1); previous.getLastInternalCursor().insertBlockAfter(new BlankFrame(getEditor())); previous.getLastInternalCursor().insertFramesAfter(contents); casesCanvas.removeBlock(frame); } editor.modifiedFrame(this, false); } private void pullUpDefaultContents() { if (defaultCanvas == null) { throw new IllegalStateException("Default couldn't be null if this method is invoked."); } int casesCount = casesCanvas.blockCount(); if (casesCount == 0) { Debug.message("pullUpDefaultContents @ SwitchFrame: Unimplemented case, waiting a design decision"); } else { List<Frame> defaultContents = new ArrayList<>(defaultCanvas.getBlockContents()); defaultContents.forEach(frame -> frame.setParentCanvas(null)); defaultContents.forEach(c -> defaultCanvas.removeBlock(c)); CaseFrame previous = (CaseFrame) casesCanvas.getBlockContents().get(casesCount - 1); previous.getLastInternalCursor().insertBlockAfter(new BlankFrame(getEditor())); previous.getLastInternalCursor().insertFramesAfter(defaultContents); removeDefault(); } editor.modifiedFrame(this, false); } @Override @OnThread(Tag.FXPlatform) public HighlightedBreakpoint showDebugAtEnd(DebugInfo debug) { return getCasesCanvas().showDebugBefore(null, debug); } @Override public void regenerateCode() { List<CodeElement> casesContents = new ArrayList<>(); casesCanvas.getBlocksSubtype(CodeFrame.class).forEach(f -> { f.regenerateCode(); casesContents.add(f.getCode()); }); List<CodeElement> defaultContents = null; if (defaultCanvas != null) { defaultContents = new ArrayList<>(); for (CodeFrame<?> f : defaultCanvas.getBlocksSubtype(CodeFrame.class)) { f.regenerateCode(); defaultContents.add(f.getCode()); } } element = new SwitchElement(this, expression.getSlotElement(), casesContents, defaultContents, frameEnabledProperty.get()); } @Override public SwitchElement getCode() { return element; } @Override public BreakEncloser asBreakEncloser() { return BreakEncloser.SWITCH; } public JavaCanvas getCasesCanvas() { return casesCanvas; } public JavaCanvas getDefaultCanvas() { return defaultCanvas; } public DebuggableParentFrame getCasesDebug() { return new DebuggableParentFrame() { @Override @OnThread(Tag.FXPlatform) public HighlightedBreakpoint showDebugBefore(DebugInfo debug) { return ((JavaCanvas) getParentCanvas()).showDebugBefore(SwitchFrame.this, debug); } @Override @OnThread(Tag.FXPlatform) public HighlightedBreakpoint showDebugAtEnd(DebugInfo debug) { return getCasesCanvas().showDebugBefore(null, debug); } @Override public FrameCanvas getParentCanvas() { return SwitchFrame.this.getParentCanvas(); } }; } public DebuggableParentFrame getDefaultDebug() { return new DebuggableParentFrame() { @Override @OnThread(Tag.FXPlatform) public HighlightedBreakpoint showDebugBefore(DebugInfo debug) { return ((JavaCanvas)getParentCanvas()).showDebugBefore(SwitchFrame.this, debug); } @Override @OnThread(Tag.FXPlatform) public HighlightedBreakpoint showDebugAtEnd(DebugInfo debug) { return getDefaultCanvas().showDebugBefore(null, debug); } @Override public FrameCanvas getParentCanvas() { return SwitchFrame.this.getParentCanvas(); } }; } @Override public boolean focusWhenJustAdded() { expression.requestFocus(); return true; }
| | |// TODO AA fix it | |@Override | |public Stream<EditableSlot> getHeaderItems() | |{}Stream<EditableSlot> s = Stream.concat(casesCanvas.getHeaderItems(), Stream.of(exceptions)); | |s = Stream.concat(s, catchCanvas.getHeaderItems()); | |return (defaultCanvas == null) ? s : Stream.concat(s, defaultCanvas.getHeaderItems()); | |} @Override public FrameTypeCheck check(FrameCanvas canvas) { if (canvas == casesCanvas) { return new FrameTypeCheck() { @Override public boolean canInsert(StrideCategory category) { return category == StrideCategory.CASE; } @Override public boolean canPlace(Class<? extends Frame> type) { return type.equals(CaseFrame.class); } }; } else if (canvas == defaultCanvas) { return StrideDictionary.checkStatement(); } else { throw new IllegalStateException("Asking about unknown child of SwitchFrame"); } } @Override public List getAvailableExtensions(FrameCanvas canvas, FrameCursor cursorInCanvas) { List<ExtensionDescription> result = new ArrayList<>(super.getAvailableExtensions(canvas, cursorInCanvas)); if (defaultCanvas == null) { result.add(new ExtensionDescription(StrideDictionary.DEFAULT_EXTENSION_CHAR, "Add default", SwitchFrame.this::addDefault, true, ExtensionSource.INSIDE_FIRST, ExtensionSource.INSIDE_LATER, ExtensionSource.AFTER)); } if (canvas == casesCanvas) { result.add(new ExtensionDescription('\b', Config.getString("frame.switch.remove.switch"), () -> new PullUpContentsOperation(editor).activate(getFrame()), false, ExtensionSource.INSIDE_FIRST)); } if (defaultCanvas != null && canvas == defaultCanvas) { result.add(new ExtensionDescription('\b', Config.getString("frame.switch.remove.default"), SwitchFrame.this::pullUpDefaultContents, false, ExtensionSource.INSIDE_FIRST)); } return result; } public boolean isAlmostBlank() { return getEditableSlotsDirect().allMatch(EditableSlot::isAlmostBlank) && defaultCanvas == null && (casesCanvas.blockCount() == 0 || (casesCanvas.blockCount() == 1 && casesCanvas.getBlockContents().get(0).isAlmostBlank())); } @Override @OnThread(Tag.FXPlatform) public void setView(View oldView, View newView, SharedTransition animate) { super.setView(oldView, newView, animate); JavaFXUtil.setPseudoclass("bj-java-preview", newView == View.JAVA_PREVIEW, sidebar.getStyleable()); boolean java = newView == View.JAVA_PREVIEW; if (isFrameEnabled() && (java || oldView == View.JAVA_PREVIEW)) { if (defaultCanvas != null) { casesCanvas.previewCurly(java, true, false, header.getLeftFirstItem(), null, animate); defaultCanvas.previewCurly(java, false, true, header.getLeftFirstItem(), null, animate); } else { casesCanvas.previewCurly(java, header.getLeftFirstItem(), null, animate); } } getCanvases().forEach(c -> { c.getCursors().forEach(cur -> cur.setView(newView, animate)); c.setView(oldView, newView, animate); }); defaultLabel.setText(newView == View.JAVA_PREVIEW ? "default :" : "default"); } }

.   SwitchFrame
.   backspaceAtStart
.   SwitchFrame
.   addDefault
.   removeDefault
.   getFactory
.   createBlock
.   getBlockClass
.   pullUpContents
.   pullUpInnerCaseContents
.   pullUpDefaultContents
.   showDebugAtEnd
.   regenerateCode
.   getCode
.   asBreakEncloser
.   getCasesCanvas
.   getDefaultCanvas
.   getCasesDebug
.   showDebugBefore
.   showDebugAtEnd
.   getParentCanvas
.   getDefaultDebug
.   showDebugBefore
.   showDebugAtEnd
.   getParentCanvas
.   focusWhenJustAdded
.   check
.   canInsert
.   canPlace
.   getAvailableExtensions
.   isAlmostBlank
.   setView




513 neLoCode + 10 LoComm