Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: text area removes selection on text append #1237

Open
PavelTurk opened this issue Jun 3, 2024 · 10 comments
Open

Bug: text area removes selection on text append #1237

PavelTurk opened this issue Jun 3, 2024 · 10 comments
Labels

Comments

@PavelTurk
Copy link
Contributor

PavelTurk commented Jun 3, 2024

This is my code:

public class JavaFxTest8 extends Application {

   @Override
    public void start(Stage primaryStage) {
        var codeArea = new CodeArea("Some text is here.");
        var button1 = new Button("Jmi");
        codeArea.selectedTextProperty().addListener((ov, oldV, newV) -> System.err.println(newV.length()));

        button1.setOnAction(e -> {
            codeArea.appendText("Appended text");
        });

        Scene scene = new Scene(new VBox(codeArea, button1), 400, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
        codeArea.selectRange(0, 4);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

If you click the button, then selection will be removed. I consider it is a bug because text appending have nothing with text selection. I tried to save selection and restore it after text appending but then I get two events in selectedTextProperty. So, one problem leads to another.

@Jugen
Copy link
Collaborator

Jugen commented Jun 3, 2024

I think I agree with your assessment, I'll have a look and see ....

@Jugen Jugen added the bug label Jun 3, 2024
@Jugen
Copy link
Collaborator

Jugen commented Jun 3, 2024

You can use the following as a work-around or alternative:

    button1.setOnAction(e -> {
        var mc = codeArea.createMultiChange();
        mc.insertText( codeArea.getLength(), "Appended text" );
        mc.commit();
    });

@PavelTurk
Copy link
Contributor Author

@Jugen I am trying to use your workaround, but I can't understand how I can do mutlichange insert with styles. I mean, now I do:

textArea.appendText(sb.toString());
textArea.setStyleSpans(oldLength, ssb.create());

There is insert(int position, StyledDocument<PS,SEG,S> document) method, but I don't know how create styled document from text and styles.

@Jugen
Copy link
Collaborator

Jugen commented Jun 3, 2024

It would look something like this:

StyleSpansBuilder<Collection<String>> styleBld;
ReadOnlyStyledDocumentBuilder<Collection<String>,String,Collection<String>> docBld;

styleBld = new StyleSpansBuilder<>();
styleBld.add( Collections.EMPTY_LIST, 9 );
styleBld.add( Collections.singletonList("highlighted"), 4 );

docBld = new ReadOnlyStyledDocumentBuilder<>( textArea.getSegOps(), Collections.EMPTY_LIST );
docBld.addParagraph( "Appended text", styleBld.create() );

var mc = textArea.createMultiChange();
mc.insert( textArea.getLength(), docBld.build() );
mc.commit();

@PavelTurk
Copy link
Contributor Author

@Jugen Thank you very much for your help. But this workaround is very, very slow on appending.

@Jugen
Copy link
Collaborator

Jugen commented Jun 4, 2024

Okay, let's try something else then. Since the problem is that the selection highlight is being removed when the text changes would it work if you used your own highlight instead which doesn't get removed ? You can add any number of highlights like so:

var mySelection = new SelectionImpl<>( "myselection", textArea, 6, 13 );
textArea.addSelection( mySelection );

There are other constructors as well, and if you want to style it do this:

var styledSelection = new SelectionImpl<>( "styledSelection", textArea, path -> path.getStyleClass().add("selectionStyle") );

You can also deselect it or change its location/range.

@PavelTurk
Copy link
Contributor Author

@Jugen Thank you very much for your help. I've checked your solution. It works, but it has different logic. When there are find matches then current match is selected, for example, to be replaced:

Peek 2024-06-04 13-01

But I can wait until this issue is resolved, as there is a lot of work to do and the project won't be released in the next couple of months.

@Jugen
Copy link
Collaborator

Jugen commented Jun 4, 2024

Shouldn't that type of selection be done by adding a selection in any case, and not by using the user selection ?

@PavelTurk
Copy link
Contributor Author

@Jugen As I understand, there can be different variants. I decided to use user selection textArea.selectRange(start, end) because it lets user modify selection if he needs it. The same solution is used in NB:

Peek 2024-06-04 14-45

@Jugen
Copy link
Collaborator

Jugen commented Jun 11, 2024

I've given this "bug" some thought and for inserts or replacements before or after the main selection it will be easy to adjust. However for inserts or replacements that overlap the main selection the behavior is not clear as to what should be done.
Also since the current behavior has been the way it is for a very long time I'm reluctant to change it.

Having looked into it though you can easily change this behavior in your custom text area class like so:

@Override
public void replace(int start, int end, StyledDocument<String,String,MyStyle> replacement) {

    var range = codeArea.getCaretSelectionBind().getRange();
    getContent().replace(start, end, replacement);

    if (end < range.getStart()) {
        // insert/replace is before selection, so adjust selection
        int newCaretPos = end - start + replacement.length();
        selectRange(newCaretPos, newCaretPos + range.getLength());
    }
    else if (start < range.getEnd()) {
        // insert/replace overlaps or is inside the selection
        // TODO
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants