Open garawaa opened 1 year ago
If you are using either CodeArea, InlineCssTextArea, or StyleClassedTextArea then just use the following API:
foldText( int start, int end )
foldSelectedParagraphs() // paragraph in this context is a line/block of text ending with a line break.
foldParagraphs( int startPar, int endPar )
unfoldParagraphs( int startingFromPar )
unfoldText( int startingFromPos )
You can also look at JavaKeywordsDemo that uses a context menu to demo folding.
I want indicate fold unfold icon on the line indicator?
I think you'll have to provide your own custom LineNumberFactory and then add it to the area with codeArea.setParagraphGraphicFactory( .... )
Can you give me some example implementation of custom LineNumberFactory class?
If you are using either CodeArea, InlineCssTextArea, or StyleClassedTextArea then just use the following API:
foldText( int start, int end ) foldSelectedParagraphs() // paragraph in this context is a line/block of text ending with a line break. foldParagraphs( int startPar, int endPar ) unfoldParagraphs( int startingFromPar ) unfoldText( int startingFromPos )
You can also look at JavaKeywordsDemo that uses a context menu to demo folding.
I know this example. This works just for selected text. But I need to similar functionality for a method folding or unfolding
Here is a custom LineNumberFactory implementation for you:
import java.util.function.IntFunction;
import java.util.function.Predicate;
import org.fxmisc.richtext.InlineCssTextArea;
import org.reactfx.collection.LiveList;
import org.reactfx.value.Val;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
/**
* Graphic factory that produces labels containing line numbers and a "+" to indicate folded paragraphs.
* To customize appearance, use {@code .lineno} and {@code .fold-indicator} style classes in CSS stylesheets.
*/
public class InlineCssLineNumberFactory<PS> implements IntFunction<Node> {
private static final Insets DEFAULT_INSETS = new Insets(0.0, 5.0, 0.0, 5.0);
private static final Paint DEFAULT_TEXT_FILL = Color.web("#666");
private static final Font DEFAULT_FONT = Font.font("monospace", FontPosture.ITALIC, 13);
private static final Font DEFAULT_FOLD_FONT = Font.font("monospace", FontWeight.BOLD, 13);
private static final Background DEFAULT_BACKGROUND = new Background(new BackgroundFill(Color.web("#ddd"), null, null));
public static IntFunction<Node> get(InlineCssTextArea area) {
return get(area, digits -> "%1$" + digits + "s");
}
/**
* @param <PS> The paragraph style type being used by the text area
* @param format Given an int convert to a String for the line number.
*/
public static <PS> IntFunction<Node> get( InlineCssTextArea area, IntFunction<String> format )
{
return new InlineCssLineNumberFactory<>( area, format );
}
private final Val<Integer> nParagraphs;
private final IntFunction<String> format;
private final InlineCssTextArea area;
private final Predicate<String> isFoldedCheck = pstyle -> pstyle != null && pstyle.contains( "collapse" );
private InlineCssLineNumberFactory( InlineCssTextArea area, IntFunction<String> format )
{
nParagraphs = LiveList.sizeOf(area.getParagraphs());
this.format = format;
this.area = area;
area.getParagraphs().sizeProperty().addListener( (ob,ov,nv) -> {
if ( nv <= ov ) Platform.runLater( () -> deleteParagraphCheck() );
else Platform.runLater( () -> insertParagraphCheck() );
});
}
@Override
public Node apply(int idx) {
Val<String> formatted = nParagraphs.map(n -> format(idx+1, n));
Label lineNo = new Label();
lineNo.setFont(DEFAULT_FONT);
lineNo.setBackground(DEFAULT_BACKGROUND);
lineNo.setTextFill(DEFAULT_TEXT_FILL);
lineNo.setPadding(DEFAULT_INSETS);
lineNo.setAlignment(Pos.TOP_RIGHT);
lineNo.getStyleClass().add("lineno");
// bind label's text to a Val that stops observing area's paragraphs
// when lineNo is removed from scene
lineNo.textProperty().bind(formatted.conditionOnShowing(lineNo));
Label foldIndicator = new Label( " " );
foldIndicator.setTextFill( Color.BLUE ); // Prevents CSS errors
foldIndicator.setFont( DEFAULT_FOLD_FONT );
lineNo.setContentDisplay( ContentDisplay.RIGHT );
lineNo.setGraphic( foldIndicator );
if ( area.getParagraphs().size() > idx+1 ) {
if ( isFoldedCheck.test( area.getParagraph( idx+1 ).getParagraphStyle() )
&& ! isFoldedCheck.test( area.getParagraph( idx ).getParagraphStyle() ) ) {
foldIndicator.setOnMouseClicked( ME -> area.unfoldParagraphs( idx ) );
foldIndicator.getStyleClass().add( "fold-indicator" );
foldIndicator.setCursor( Cursor.HAND );
foldIndicator.setText( "+" );
}
}
return lineNo;
}
private String format(int x, int max) {
int digits = (int) Math.floor(Math.log10(max)) + 1;
return String.format(format.apply(digits), x);
}
private void deleteParagraphCheck()
{
int p = area.getCurrentParagraph();
// Was the deleted paragraph in the viewport ?
if ( p >= area.firstVisibleParToAllParIndex() && p <= area.lastVisibleParToAllParIndex() )
{
int col = area.getCaretColumn();
// Delete was pressed on an empty paragraph, and so the cursor is now at the start of the next paragraph.
if ( col == 0 ) {
// Check if the now current paragraph is folded.
if ( isFoldedCheck.test( area.getParagraph( p ).getParagraphStyle() ) ) {
p = Math.max( p-1, 0 ); // Adjust to previous paragraph.
area.recreateParagraphGraphic( p ); // Show fold/unfold indicator on previous paragraph.
area.moveTo( p, 0 ); // Move cursor to previous paragraph.
}
}
// Backspace was pressed on an empty paragraph, and so the cursor is now at the end of the previous paragraph.
else if ( col == area.getParagraph( p ).length() ) {
area.recreateParagraphGraphic( p ); // Shows fold/unfold indicator on current paragraph if needed.
}
// In all other cases the paragraph graphic is created/updated automatically.
}
}
private void insertParagraphCheck()
{
int p = area.getCurrentParagraph();
// Is the inserted paragraph in the viewport ?
if ( p > area.firstVisibleParToAllParIndex() && p <= area.lastVisibleParToAllParIndex() ) {
// Check limits, as p-1 and p+1 are accessed ...
if ( p > 0 && p+1 < area.getParagraphs().size() ) {
// Now check if the inserted paragraph is before a folded block ?
if ( isFoldedCheck.test( area.getParagraph( p+1 ).getParagraphStyle() ) ) {
area.recreateParagraphGraphic( p-1 ); // Remove the unfold indicator.
}
}
}
}
}
The "java keywords" foldable demo is all a bit misleading. It has nothing to do with Java or Java code structure, it's just folding/unfolding any randomly selected text.
What the OP was looking for was a way to show in the line number bar (in a CodeArea, not a InlineCssTextArea), collapsible areas, such as methods, etc. Basically like a tree but without the ugly-ness of a standard tree control.
I just want to implement code folding just like other ide-s : intellij, eclipse, netbeans. I reviewed java keyboard sample. The folding is controlled from context menu. I want indicate fold unfold icon on the line indicator? How to do it with codearea? Can you give me some code hints? Thank you.