-
Notifications
You must be signed in to change notification settings - Fork 236
Implementing custom objects
The following three (3) conditions need to be met for undo/redo to work on custom segment objects (as noted by Jugen in #403):
- The
preserveStyle
parameter must be TRUE when invoking theGenericStyledArea
constructor. - A properly implemented
Codec
for yourSEG
must be set viaGenericStyledArea.setStyleCodecs()
-
The Object.equals( Object obj ) method must be overridden and properly implemented by your SEG(Requirement removed by #795)
Your area's nodeFactory
must return a TextExt
object to display that text, not the regular Text
object, in order for RichTextFX-specific CSS styling to work.
To implement a custom object, you will need to have three things:
- A non-empty immutable version of your object
- An empty immutable version of your object
- A
SegOps
(an object that handles operations on your object and its style).
See the Hyperlink Demo for an example.
Ideally, you would use an interface for your custom object, have both object versions implement this interface, and use only one object for the empty version of your object. For example...
public interface CustomObject {
// relevant information
// if you want to provide a Codec for your object, you should include it here
static Codec<CustomObject> codec() {
return new Codec<CustomObject>() {
@Override
public String getName() {
return "CustomObject";
}
@Override
public void encode(DataOutputStream os, CustomObject object) throws IOException {
if (object.isRealObject()) {
os.writeBoolean(true);
// encode object code here...
} else {
os.writeBoolean(false);
}
}
@Override
public CustomObject<S> decode(DataInputStream is) throws IOException {
if (is.readBoolean()) {
// decode real object here
} else {
return new EmptyObject();
}
}
};
}
}
public class RealObject implements CustomObject {
// implementation
// Note: setters should always return a new immutable RealObject
}
public class EmptyObject implements CustomObject {
// Note: setters should always return "this"
}
Then, in your CustomObjectOps
class, you would extend SegmentOpsBase
/ TextOpsBase
for text-related objects or NodeSegmentOpsBase
for non-text-related objects (e.g. shapes, images, etc.).
public class CustomTextObjectOps<Style> extends SegmentOpsBase<CustomObject, Style> {
public CustomTextObjectOps() {
super(new EmptyObject());
}
public int realLength(CustomObject seg) {
return seg.length();
}
public char realCharAt(CustomObject seg, int index) {
return seg.charAt(index);
}
public String realGetText(CustomObject seg) {
return seg.getText();
}
public CustomObject realSubSequence(CustomObject seg, int start, int end) {
return seg.subSequence(start, end);
}
public CustomObject realSubSequence(CustomObject seg, int start) {
return seg.subSequence(start);
}
@Override
public Optional<CustomObject> joinSeg(CustomObject currentSeg, CustomObject nextSeg) {
// returns either an empty optional when the two cannot be merged
// or an optional containing the merged segment
return Optional.empty();
}
@Override
public Optional<Style> joinStyle(S currentStyle, S nextStyle) {
// this only needs to be overridden when one wants to merge
// styles together. By default, it returns Optional.empty()
}
}
public class CustomNodeObjectOps<Style> extends NodeSegmentOpsBase<CustomObject, Style> {
public CustomNodeObjectOps() {
super(new EmptyObject());
}
@Override
public int length(CustomObject object) {
// override this method and the base class will take care of the rest
}
}
- Home
- General guidelines
- Core classes
- Text Styles: Inline, Style Class, and Custom Style Objects
- PS, S, and SEG: Explaining the main generics in RichTextFX
- Implementing custom objects
- How to Override the Default Behavior
- RichTextFX CSS Reference Guide
- Adding Support for Emojis
- Known Issues
- Test Automation