package bluej.stride.generic;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import bluej.stride.framedjava.ast.JavaFragment;
import bluej.stride.framedjava.ast.links.PossibleLink;
import bluej.stride.framedjava.frames.TopLevelFrame;
import bluej.utility.javafx.ScalableHeightLabel;
import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import bluej.stride.framedjava.errors.CodeError;
import bluej.stride.framedjava.slots.TextOverlayPosition;
import bluej.stride.generic.Frame.View;
import bluej.stride.slots.EditableSlot;
import bluej.stride.slots.Focus;
import bluej.stride.slots.FocusParent;
import bluej.stride.slots.HeaderItem;
import bluej.utility.javafx.FXRunnable;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.ScrollFreeTextArea;
import bluej.utility.javafx.SharedTransition;
import javafx.scene.layout.BorderPane;
import threadchecker.OnThread;
import threadchecker.Tag;


| A custom text area for documentation comment of a class, method, etc. | @author Fraser McKay | public class DocumentationTextArea extends ScrollFreeTextArea implements EditableSlot, FrameContentItem{ private Frame frameParent; private View curView = View.NORMAL; private final ScalableHeightLabel previewCommentStart = new ScalableHeightLabel("/**", true); private final ScalableHeightLabel previewCommentEnd = new ScalableHeightLabel("*/", true); private final BorderPane wrapper; private boolean hacking; public DocumentationTextArea(InteractionManager editor, Frame frameParent, FocusParent<? super DocumentationTextArea> focusParent, final String stylePrefix) { this(editor, frameParent, focusParent, stylePrefix, null); }
| If enterAction is not null, pressing Enter will trigger it, and shift-Enter will add newline instead. | public DocumentationTextArea(InteractionManager editor, Frame frameParent, FocusParent<? super DocumentationTextArea> focusParent, final String stylePrefix, FXRunnable enterAction) { super(editor); wrapper = new BorderPane(super.getNode()); JavaFXUtil.addStyleClass(wrapper, "documentation-text-wrapper", stylePrefix + "documentation-text-wrapper"); this.frameParent = frameParent; addTextStyleClasses("documentation-text", stylePrefix + "documentation-text"); if (frameParent instanceof TopLevelFrame) { ImageView classImage = editor.makeClassImageView(); if (classImage != null) { BorderPane.setMargin(classImage, new Insets(8)); classImage.setOpacity(0.6); wrapper.setRight(classImage); } } setFocusTraversable(true); editor.setupFocusableSlotComponent(this, super.getNode(), false, Collections::emptyList, Collections.emptyList()); textProperty().addListener((e, oldValue, newValue) -> { if (!hacking) editor.modifiedFrame(frameParent, false); }); JavaFXUtil.addStyleClass(previewCommentStart, "preview-slashstar"); JavaFXUtil.addStyleClass(previewCommentEnd, "preview-slashstar"); wrapper.setTop(previewCommentStart); wrapper.setBottom(previewCommentEnd); setPseudoclass("bj-blank", true); textProperty().addListener((a, b, c) -> { setPseudoclass("bj-blank", getText().equals("")); }); addEventFilter(KeyEvent.KEY_PRESSED, event -> { switch(event.getCode()) { case TAB: if (event.isShiftDown()) { focusParent.focusLeft(this); } else { focusParent.focusRight(this); } event.consume(); break; case UP: if (getCaretPosition() != 0) { final int oldPos = getCaretPosition(); JavaFXUtil.runAfterCurrent(() -> { if (getCaretPosition() == oldPos) { focusParent.focusUp(this, true); } }); } case LEFT: if (caretPositionProperty().get() == 0) { focusParent.focusUp(this, true); event.consume(); } break; case DOWN: if (getCaretPosition() != getLength()) { final int oldPos = getCaretPosition(); JavaFXUtil.runAfterCurrent(() -> { if (getCaretPosition() == oldPos) { focusParent.focusDown(this); } }); } case RIGHT: if (caretPositionProperty().get() == getLength()) { focusParent.focusDown(this); event.consume(); } break; case ENTER: if (event.isShiftDown() || event.isControlDown() || event.isShortcutDown()) { insertAtCaret("\n"); event.consume(); } else { if (enterAction != null) { enterAction.run(); event.consume(); } } break; } }); } @Override public void requestFocus(Focus on) { requestFocus(); if (on == Focus.LEFT) { positionCaret(0); } else if (on == Focus.RIGHT) { positionCaret(getLength()); } else if (on == Focus.SELECT_ALL) { selectAll(); } } @Override public ObservableList getComponents() { return FXCollections.observableArrayList(getNode()); } @Override public TextOverlayPosition getOverlayLocation(int caretPos, boolean javaPos) { return null; } @Override public void removeOldErrors() { } @Override public void flagErrorsAsOld() { } @Override public void cleanup() { } @Override public void addError(CodeError err) { } @Override public void focusAndPositionAtError(CodeError err) { } @Override public Stream getCurrentErrors() { return Stream.empty(); } @Override public void addUnderline(Underline u) { } @Override public void removeAllUnderlines() { } @Override public void saved() { } @Override public int getFocusInfo() { return getCaretPosition(); } @Override public Node recallFocus(int info) { positionCaret(info); return getNode(); } @Override public List findLinks() { return Collections.emptyList(); } @Override public Frame getParentFrame() { return frameParent; } @Override public void lostFocus() { } @Override public void setView(View oldView, View newView, SharedTransition animate) { setDisable(newView != View.NORMAL); if (newView == View.BIRDSEYE_NODOC) { shrinkToNothingUsing(animate); } else if (oldView == View.BIRDSEYE_NODOC) { growFromNothingUsing(animate); } if (newView == View.JAVA_PREVIEW && (getParentFrame() == null || getParentFrame().isFrameEnabled())) { previewCommentStart.growToFullHeightWith(animate, true); previewCommentEnd.growToFullHeightWith(animate, true); wrapper.setSnapToPixel(false); } else if (curView == View.JAVA_PREVIEW) { previewCommentStart.shrinkToNothingWith(animate, true); previewCommentEnd.shrinkToNothingWith(animate, true); animate.addOnStopped(() -> wrapper.setSnapToPixel(true)); } curView = newView; } public String getJavadocs(String prefix) { String out = ""; if (! getText().isEmpty()) { String[] lines = getText().split("\n"); for (int i = 0; i < lines.length; i++) { out += prefix + " * " + lines[i] + "\n"; } } return out; } @OnThread(Tag.FXPlatform) public void hackFixSizing() { hacking = true; String s = getText(); setText(""); setText(s); hacking = false; } @Override public JavaFragment getSlotElement() { return null; } @Override public boolean isAlmostBlank() { return getText().trim().isEmpty(); } @Override public Optional getCanvas() { return Optional.empty(); } @Override public Stream getHeaderItemsDeep() { return Stream.of(this); } @Override public Stream getHeaderItemsDirect() { return Stream.of(this); } @Override public boolean focusTopEndFromPrev() { requestFocus(Focus.LEFT); return true; } @Override public boolean focusBottomEndFromNext() { requestFocus(Focus.LEFT); return true; } @Override public boolean focusLeftEndFromPrev() { requestFocus(Focus.LEFT); return true; } @Override public boolean focusRightEndFromNext() { requestFocus(Focus.RIGHT); return true; } @Override public boolean isEditable() { return !isDisable(); } @Override public void setEditable(boolean editable) { setDisable(!editable); } @Override public Node getNode() { return wrapper; } public void setDocComment(boolean docComment) { previewCommentStart.setText(docComment ? "/**" : "/*"); } @Override public ObservableBooleanValue effectivelyFocusedProperty() { return focusedProperty(); } @Override public int calculateEffort() { return getText().length(); } }
top, use, map, class DocumentationTextArea

.   DocumentationTextArea
.   DocumentationTextArea
.   requestFocus
.   getComponents
.   getOverlayLocation
.   removeOldErrors
.   flagErrorsAsOld
.   cleanup
.   addError
.   focusAndPositionAtError
.   getCurrentErrors
.   addUnderline
.   removeAllUnderlines
.   saved
.   getFocusInfo
.   recallFocus
.   findLinks
.   getParentFrame
.   lostFocus
.   setView
.   getJavadocs
.   hackFixSizing
.   getSlotElement
.   isAlmostBlank
.   getCanvas
.   getHeaderItemsDeep
.   getHeaderItemsDirect
.   focusTopEndFromPrev
.   focusBottomEndFromNext
.   focusLeftEndFromPrev
.   focusRightEndFromNext
.   isEditable
.   setEditable
.   getNode
.   setDocComment
.   effectivelyFocusedProperty
.   calculateEffort




535 neLoCode + 3 LoComm