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

Easier custom object support #553

Merged
merged 2 commits into from
Jul 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,68 +1,21 @@
package org.fxmisc.richtext.demo.richtext;

import java.util.Optional;
import org.fxmisc.richtext.model.NodeSegmentOpsBase;

import org.fxmisc.richtext.model.SegmentOps;
public class LinkedImageOps<S> extends NodeSegmentOpsBase<LinkedImage<S>, S> {

public class LinkedImageOps<S> implements SegmentOps<LinkedImage<S>, S> {

private final EmptyLinkedImage<S> emptySeg = new EmptyLinkedImage<>();

@Override
public int length(LinkedImage<S> seg) {
return seg == emptySeg ? 0 : 1;
}

@Override
public char charAt(LinkedImage<S> seg, int index) {
return seg == emptySeg ? '\0' : '\ufffc';
}

@Override
public String getText(LinkedImage<S> seg) {
return seg == emptySeg ? "" : "\ufffc";
}

@Override
public LinkedImage<S> subSequence(LinkedImage<S> seg, int start, int end) {
if (start < 0) {
throw new IllegalArgumentException("Start cannot be negative. Start = " + start);
}
if (end > length(seg)) {
throw new IllegalArgumentException("End cannot be greater than segment's length");
}
return start == 0 && end == 1
? seg
: emptySeg;
}

@Override
public LinkedImage<S> subSequence(LinkedImage<S> seg, int start) {
if (start < 0) {
throw new IllegalArgumentException("Start cannot be negative. Start = " + start);
}
return start == 0
? seg
: emptySeg;
public LinkedImageOps() {
super(new EmptyLinkedImage<>());
}

@Override
public S getStyle(LinkedImage<S> seg) {
return seg.getStyle();
public S realGetStyle(LinkedImage<S> linkedImage) {
return linkedImage.getStyle();
}

@Override
public LinkedImage<S> setStyle(LinkedImage<S> seg, S style) {
return seg == emptySeg ? emptySeg : seg.setStyle(style);
public LinkedImage<S> realSetStyle(LinkedImage<S> linkedImage, S style) {
return linkedImage.setStyle(style);
}

@Override
public Optional<LinkedImage<S>> join(LinkedImage<S> currentSeg, LinkedImage<S> nextSeg) {
return Optional.empty();
}

@Override
public LinkedImage<S> createEmpty() {
return emptySeg;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.fxmisc.richtext.model;

/**
* Properly implements {@link SegmentOps} when implementing a non-text custom object (e.g. shape, circle, image)
* and reduces boilerplate. Developers only need to override {@link #realGetStyle(Object)} and
* {@link #realSetStyle(Object, Object)}. Developers may also want to override {@link #join(Object, Object)}.
*
* @param <SEG> type of segment
* @param <S> type of style
*/
public abstract class NodeSegmentOpsBase<SEG, S> extends SegmentOpsBase<SEG, S> {

public NodeSegmentOpsBase(SEG empty) {
super(empty);
}

@Override
public int realLength(SEG seg) {
return 1;
}

@Override
public char realCharAt(SEG seg, int index) {
return '\ufffc';
}

@Override
public String realGetText(SEG seg) {
return "\ufffc";
}

@Override
public SEG realSubsequence(SEG seg, int start, int end) {
return seg;
}

@Override
public SEG realSubsequence(SEG seg, int start) {
return seg;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.fxmisc.richtext.model;

import java.util.Optional;

/**
* Properly implements the {@link SegmentOps} interface and reduces boilerplate, so that developer only needs to
* implement methods for real segments, not empty ones. Optionally, {@link #join(Object, Object)} can be overridden
* as well.
*
* @param <SEG> the type of segment
* @param <S> the type of style
*/
public abstract class SegmentOpsBase<SEG, S> implements SegmentOps<SEG, S> {

private final SEG empty;

public SegmentOpsBase(SEG emptySEg) {
this.empty = emptySEg;
}

@Override
public final int length(SEG seg) {
return seg == empty ? 0 : realLength(seg);
}
public abstract int realLength(SEG seg);

@Override
public final char charAt(SEG seg, int index) {
return seg == empty ? '\0' : realCharAt(seg, index);
}
public abstract char realCharAt(SEG seg, int index);

@Override
public final String getText(SEG seg) {
return seg == empty ? "\0" : realGetText(seg);
}
public abstract String realGetText(SEG seg);

@Override
public final SEG subSequence(SEG seg, int start, int end) {
if (start < 0) {
throw new IllegalArgumentException("Start cannot be negative. Start=" + start);
}
if (end > length(seg)) {
throw new IllegalArgumentException(
String.format("End cannot be greater than segment's length. End=%s Length=%s", end, length(seg))
);
}
return seg == empty || start == end
? empty
: realSubsequence(seg, start, end);
}
public abstract SEG realSubsequence(SEG seg, int start, int end);

@Override
public final SEG subSequence(SEG seg, int start) {
return seg == empty || length(seg) == start
? empty
: realSubsequence(seg, start);
}
public SEG realSubsequence(SEG seg, int start) {
return realSubsequence(seg, start, length(seg));
}

@Override
public final S getStyle(SEG seg) {
return seg == empty ? null : realGetStyle(seg);
}
public abstract S realGetStyle(SEG seg);

@Override
public final SEG setStyle(SEG seg, S style) {
return seg == empty ? empty : realSetStyle(seg, style);
}
public abstract SEG realSetStyle(SEG seg, S style);

@Override
public final Optional<SEG> join(SEG currentSeg, SEG nextSeg) {
return Optional.empty();
}

@Override
public final SEG createEmpty() {
return empty;
}
}