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 extends PossibleLink> 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