-
Notifications
You must be signed in to change notification settings - Fork 542
8370140: RichTextArea: line endings #1944
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
base: master
Are you sure you want to change the base?
8370140: RichTextArea: line endings #1944
Conversation
|
👋 Welcome back angorya! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
|
/reviewers 2 |
|
@andy-goryachev-oracle |
|
@andy-goryachev-oracle has indicated that a compatibility and specification (CSR) request is needed for this pull request. @andy-goryachev-oracle please create a CSR request for issue JDK-8370140 with the correct fix version. This pull request cannot be integrated until the CSR request is approved. |
Webrevs
|
|
Reviewers: @kevinrushforth @jayathirthrao |
jayathirthrao
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code change looks good to me. I have minor suggestions.
Also played around with demos everything works fine.
| public void setLineSeparator(String s) { | ||
| newline = s; | ||
| public StringBuilderStyledOutput(LineEnding lineEnding) { | ||
| sb = new StringBuilder(1024); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its better to name this constant.
| return System.getProperty("line.separator"); | ||
| } | ||
| return switch(v) { | ||
| case CR -> "\r"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing indentation.
kevinrushforth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked over the proposed API and left some inline comments. I'll repeat my two main points here:
- Rather than a Nullable enum, create an explicit enum value for "use the
line.separatorproperty" - Why is the new lineEnding property on the
CodeAreasubclass and not onRichTextArea?
| * | ||
| * @since 26 | ||
| */ | ||
| public enum LineEnding { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add an explicit enum value that means "use the value of System.getProperty("line.separator")". Relying on null to mean this is not clean for two reasons: 1) it is more difficult to document (case in point, it isn't documented here); and 2) using an enum that might be null in a switch statement without first checking for null will cause an NPE.
Possible names: NATIVE? LINE_SEPARATOR? something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possible name: DEFAULT
I'm not sure which one I like best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PLATFORM_DEFAULT maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe. Or maybe SYSTEM_DEFAULT (since it comes from Java's system properties)?
| /** Classic Mac OS */ | ||
| CR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I question the need for this enum value. CR was only used prior to macOS 10.0, which is so old as to be uninteresting without a good reason (for comparison, the very first version of Java for macOS was for macOS 10.5). Do you have a use case in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the use case is for application developers to have full control of the line endings. This might be useful for programming editors that deal with legacy formats.
| /** Windows */ | ||
| CRLF, | ||
| /** macOS/Unix */ | ||
| LF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this shows up in the javadoc-generated API docs, it might be worth expanding this a bit.
| * | ||
| * @return the line ending property | ||
| * @since 26 | ||
| * @defaultValue null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of a good reason for this to be a Nullable property. Instead, define a new enum value that means "use the value of the line.separator system property". It seems much cleaner (I don't like relying on null for out of band enum values, since it will cause an NPE if you switch on it without checking for null first).
Separately, should "use line.separator" should be the default value or should it use "\n" instead. Probably using "line.separator" is a better choice, which is what this PR does. The reason I bring this up is so that we make a conscious decision.
| * @since 26 | ||
| * @defaultValue null | ||
| */ | ||
| public final ObjectProperty<LineEnding> lineEndingProperty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be a property of RichTextArea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, RichTextArea might have a model that has no concept of line ending, or has its own idea of line ending - that's why it's an attribute of the model rather than the property in the control.
CodeArea, on the other hand, deals with plain text as an underlying data, so line ending is a property of the control, just like font and tabSize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike font and tabSize, the lineEnding property is used when exporting to an external format where you want line endings, which also applies to RichTextArea. This is done implicitly by various operations (copy/paste/export) or explicitly when calling getText. I realize that getText is not currently a public method in RichTextArea, but I understand is likely to be proposed in the future. Once you add that method to the public API it will seem odd that users of CodeArea set the property in the control, but users of RichTextArea itself would need to set it in the model.
Do you still think it belongs in the CodeArea subclass? I suppose it can be moved to the superclass later, if needed (without breaking anything), but I at least want you to think through all the issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I thought of a bigger concern. Having a writable attribute in both the control and the model is not going to give coherent results in the case where you have more than one view on the same model. So you might need to rethink the idea of having a writable property on the view (the control) while also having state (via a writable attribute) on the model.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point!
What do you think we should do then?
I should probably move the setter and getter to the RichTextArea class then, and remove the property altogether.
Any custom UI can always create its own property for line ending and deal with the model directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making the property in the model be the primary and having the RTA setter/getter forward to the model makes it a lot like setUndoRedoEnable, which seems like a good choice. The state is only in one place (the model) with convenience methods in the control.
| * @since 26 | ||
| * @defaultValue null | ||
| */ | ||
| public final ObjectProperty<LineEnding> lineEndingProperty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike font and tabSize, the lineEnding property is used when exporting to an external format where you want line endings, which also applies to RichTextArea. This is done implicitly by various operations (copy/paste/export) or explicitly when calling getText. I realize that getText is not currently a public method in RichTextArea, but I understand is likely to be proposed in the future. Once you add that method to the public API it will seem odd that users of CodeArea set the property in the control, but users of RichTextArea itself would need to set it in the model.
Do you still think it belongs in the CodeArea subclass? I suppose it can be moved to the superclass later, if needed (without breaking anything), but I at least want you to think through all the issues.
| /** macOS/Unix line ending, sequence of CR/LF (0x0d 0x0a)*/ | ||
| LF, | ||
| /** Platform default line ending, using the value of {@code System.getProperty("line.separator")} */ | ||
| SYSTEM_DEFAULT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe just SYSTEM? Now that I look at it, I'm not sure we need the "DEFAULT" suffix (nor the word "default" in the description).
| * @since 26 | ||
| */ | ||
| public enum LineEnding { | ||
| /** Classic Mac OS line ending, ASCII CR (0x0d) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say "Legacy" rather than "Classic", and maybe add a sentence that this was used on Mac systems prior to macOS 10.
| /** Windows line ending, ASCII LF (0x0a) */ | ||
| CRLF, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a . at the end of the sentence (here and for all the enums)?
| */ | ||
| public static StyledOutput forPlainText() { | ||
| return new StringBuilderStyledOutput(); | ||
| return new StringBuilderStyledOutput(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Null is not allowed. Pass LineEnding.SYSTEM_DEFAULT.
| @Override | ||
| protected void invalidated() { | ||
| LineEnding v = get(); | ||
| if(v == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: space after if
| protected void invalidated() { | ||
| LineEnding v = get(); | ||
| if(v == null) { | ||
| set(old); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also need to unbind if bound.
kevinrushforth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good with a couple fairly minor comments inline.
| /** Legacy Mac OS line ending, ASCII CR (0x0d). */ | ||
| CR, | ||
| /** Windows */ | ||
| /** Windows line ending, ASCII LF (0x0a). */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "ASCII LF (0x0a)" bit belongs to the LF enum value, not here.
| CRLF, | ||
| /** macOS/Unix */ | ||
| LF | ||
| /** macOS/Unix line ending, sequence of CR/LF (0x0d 0x0a). */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The The "CR/LF (0x0d 0x0a)" bit belongs to the CRLF enum value, not here. While you are at it, maybe add "ASCII" before "CR/LF" for consistency?
| if (lineEnding == null) { | ||
| lineEnding = LineEnding.SYSTEM; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed, right? lineEnding can never be null as long as you initialize it to LineEnding.SYSTEM , since you check and throw on an attempt to set it to null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tried to do a lazy init, but it's not that essential.
kevinrushforth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I left one minor comment, but will approve as is. Will reapprove if you decide to make changes.
| ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
| try { | ||
| try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: you don't need two levels of try here. Even better, you can use try with resources instead of adding finally clause.
Adds control of line endings (newline separators) in
StyledTextModel,RichTextArea, andCodeArea.The impacted areas are:
This feature is implemented as a regular field in the
StyledTextModel(since it is ultimately an attribute of the model), with convenience setter and getter in theRichTextArea.NOTES
Progress
Issues
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1944/head:pull/1944$ git checkout pull/1944Update a local copy of the PR:
$ git checkout pull/1944$ git pull https://git.openjdk.org/jfx.git pull/1944/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1944View PR using the GUI difftool:
$ git pr show -t 1944Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1944.diff
Using Webrev
Link to Webrev Comment