-
Notifications
You must be signed in to change notification settings - Fork 236
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #550 from JordanMartinez/hyperlinkDemo
Add Hyperlink demo - minimum needed for custom object integration
- Loading branch information
Showing
6 changed files
with
579 additions
and
0 deletions.
There are no files selected for viewing
75 changes: 75 additions & 0 deletions
75
richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/hyperlink/Hyperlink.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package org.fxmisc.richtext.demo.hyperlink; | ||
|
||
public class Hyperlink<S> { | ||
|
||
private final String originalDisplayedText; | ||
private final String displayedText; | ||
private final S style; | ||
private final String link; | ||
|
||
Hyperlink(String originalDisplayedText, String displayedText, S style, String link) { | ||
this.originalDisplayedText = originalDisplayedText; | ||
this.displayedText = displayedText; | ||
this.style = style; | ||
this.link = link; | ||
} | ||
|
||
public boolean isEmpty() { | ||
return length() == 0; | ||
} | ||
|
||
public boolean isReal() { | ||
return length() > 0; | ||
} | ||
|
||
public boolean shareSameAncestor(Hyperlink<S> other) { | ||
return link.equals(other.link) && originalDisplayedText.equals(other.originalDisplayedText); | ||
} | ||
|
||
public int length() { | ||
return displayedText.length(); | ||
} | ||
|
||
public char charAt(int index) { | ||
return isEmpty() ? '\0' : displayedText.charAt(index); | ||
} | ||
|
||
public String getOriginalDisplayedText() { return originalDisplayedText; } | ||
|
||
public String getDisplayedText() { | ||
return displayedText; | ||
} | ||
|
||
public String getLink() { | ||
return link; | ||
} | ||
|
||
public Hyperlink<S> subSequence(int start, int end) { | ||
return new Hyperlink<>(originalDisplayedText, displayedText.substring(start, end), style, link); | ||
} | ||
|
||
public Hyperlink<S> subSequence(int start) { | ||
return new Hyperlink<>(originalDisplayedText, displayedText.substring(start), style, link); | ||
} | ||
|
||
public S getStyle() { | ||
return style; | ||
} | ||
|
||
public Hyperlink<S> setStyle(S style) { | ||
return new Hyperlink<>(originalDisplayedText, displayedText, style, link); | ||
} | ||
|
||
public Hyperlink<S> mapDisplayedText(String text) { | ||
return new Hyperlink<>(originalDisplayedText, text, style, link); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return isEmpty() | ||
? String.format("EmptyHyperlink[original=%s style=%s link=%s]", originalDisplayedText, style, link) | ||
: String.format("RealHyperlink[original=%s displayedText=%s, style=%s, link=%s]", | ||
originalDisplayedText, displayedText, style, link); | ||
} | ||
|
||
} |
38 changes: 38 additions & 0 deletions
38
richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/hyperlink/HyperlinkDemo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.fxmisc.richtext.demo.hyperlink; | ||
|
||
import com.sun.deploy.uitoolkit.impl.fx.HostServicesFactory; | ||
import com.sun.javafx.application.HostServicesDelegate; | ||
import javafx.application.Application; | ||
import javafx.application.HostServices; | ||
import javafx.scene.Scene; | ||
import javafx.stage.Stage; | ||
import org.fxmisc.flowless.VirtualizedScrollPane; | ||
|
||
import java.util.function.Consumer; | ||
|
||
/** | ||
* Demonstrates the minimum needed to support custom objects (in this case, hyperlinks) alongside of text. | ||
* | ||
* Note: demo does not handle cases where the link changes its state when it has already been visited | ||
*/ | ||
public class HyperlinkDemo extends Application { | ||
|
||
public static void main(String[] args) { | ||
launch(args); | ||
} | ||
|
||
@Override | ||
public void start(Stage primaryStage) { | ||
Consumer<String> showLink = HostServicesFactory.getInstance(this)::showDocument; | ||
TextHyperlinkArea area = new TextHyperlinkArea(showLink); | ||
|
||
area.appendText("Some text in the area\n"); | ||
area.appendWithLink("Google.com", "http://www.google.com"); | ||
|
||
VirtualizedScrollPane<TextHyperlinkArea> vsPane = new VirtualizedScrollPane<>(area); | ||
|
||
Scene scene = new Scene(vsPane, 500, 500); | ||
primaryStage.setScene(scene); | ||
primaryStage.show(); | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/hyperlink/HyperlinkOps.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package org.fxmisc.richtext.demo.hyperlink; | ||
|
||
import org.fxmisc.richtext.model.SegmentOps; | ||
|
||
import java.util.Optional; | ||
|
||
public class HyperlinkOps<S> implements SegmentOps<Hyperlink<S>, S> { | ||
|
||
@Override | ||
public int length(Hyperlink<S> hyperlink) { | ||
return hyperlink.length(); | ||
} | ||
|
||
@Override | ||
public char charAt(Hyperlink<S> hyperlink, int index) { | ||
return hyperlink.charAt(index); | ||
} | ||
|
||
@Override | ||
public String getText(Hyperlink<S> hyperlink) { | ||
return hyperlink.getDisplayedText(); | ||
} | ||
|
||
@Override | ||
public Hyperlink<S> subSequence(Hyperlink<S> hyperlink, int start, int end) { | ||
return hyperlink.subSequence(start, end); | ||
} | ||
|
||
@Override | ||
public Hyperlink<S> subSequence(Hyperlink<S> hyperlink, int start) { | ||
return hyperlink.subSequence(start); | ||
} | ||
|
||
@Override | ||
public S getStyle(Hyperlink<S> hyperlink) { | ||
return hyperlink.getStyle(); | ||
} | ||
|
||
@Override | ||
public Hyperlink<S> setStyle(Hyperlink<S> hyperlink, S style) { | ||
return hyperlink.setStyle(style); | ||
} | ||
|
||
@Override | ||
public Optional<Hyperlink<S>> join(Hyperlink<S> currentSeg, Hyperlink<S> nextSeg) { | ||
if (currentSeg.isEmpty()) { | ||
if (nextSeg.isEmpty()) { | ||
return Optional.empty(); | ||
} else { | ||
return Optional.of(nextSeg); | ||
} | ||
} else { | ||
if (nextSeg.isEmpty()) { | ||
return Optional.of(currentSeg); | ||
} else { | ||
return concatHyperlinks(currentSeg, nextSeg); | ||
} | ||
} | ||
} | ||
|
||
private Optional<Hyperlink<S>> concatHyperlinks(Hyperlink<S> leftSeg, Hyperlink<S> rightSeg) { | ||
if (!leftSeg.shareSameAncestor(rightSeg)) { | ||
return Optional.empty(); | ||
} | ||
|
||
String original = leftSeg.getOriginalDisplayedText(); | ||
String leftText = leftSeg.getDisplayedText(); | ||
String rightText = rightSeg.getDisplayedText(); | ||
int leftOffset = 0; | ||
int rightOffset = 0; | ||
for (int i = 0; i <= original.length() - leftText.length(); i++) { | ||
if (original.regionMatches(i, leftText, 0, leftText.length())) { | ||
leftOffset = i; | ||
break; | ||
} | ||
} | ||
for (int i = 0; i <= original.length() - rightText.length(); i++) { | ||
if (original.regionMatches(i, rightText, 0, rightText.length())) { | ||
rightOffset = i; | ||
break; | ||
} | ||
} | ||
|
||
if (rightOffset + rightText.length() == leftOffset) { | ||
return Optional.of(leftSeg.mapDisplayedText(rightText + leftText)); | ||
} else if (leftOffset + leftText.length() == rightOffset) { | ||
return Optional.of(leftSeg.mapDisplayedText(leftText + rightText)); | ||
} else { | ||
return Optional.empty(); | ||
} | ||
} | ||
|
||
@Override | ||
public Hyperlink<S> createEmpty() { | ||
return new Hyperlink<>("", "", null, ""); | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/hyperlink/TextHyperlinkArea.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package org.fxmisc.richtext.demo.hyperlink; | ||
|
||
import javafx.geometry.VPos; | ||
import org.fxmisc.richtext.GenericStyledArea; | ||
import org.fxmisc.richtext.TextExt; | ||
import org.fxmisc.richtext.model.ReadOnlyStyledDocument; | ||
import org.fxmisc.richtext.model.StyledText; | ||
import org.fxmisc.richtext.model.TextOps; | ||
import org.reactfx.util.Either; | ||
|
||
import java.util.function.Consumer; | ||
|
||
public class TextHyperlinkArea extends GenericStyledArea<Void, Either<StyledText<TextStyle>, Hyperlink<TextStyle>>, TextStyle> { | ||
|
||
private static final TextOps<StyledText<TextStyle>, TextStyle> STYLED_TEXT_OPS = StyledText.textOps(); | ||
private static final HyperlinkOps<TextStyle> HYPERLINK_OPS = new HyperlinkOps<>(); | ||
private static final TextOps<Either<StyledText<TextStyle>, Hyperlink<TextStyle>>, TextStyle> EITHER_OPS = STYLED_TEXT_OPS._or(HYPERLINK_OPS); | ||
|
||
public TextHyperlinkArea(Consumer<String> showLink) { | ||
super( | ||
null, | ||
(t, p) -> {}, | ||
TextStyle.EMPTY, | ||
EITHER_OPS, | ||
e -> e.unify( | ||
styledText -> | ||
createStyledTextNode(t -> { | ||
t.setText(styledText.getText()); | ||
t.setStyle(styledText.getStyle().toCss()); | ||
}), | ||
hyperlink -> | ||
createStyledTextNode(t -> { | ||
if (hyperlink.isReal()) { | ||
t.setText(hyperlink.getDisplayedText()); | ||
t.getStyleClass().add("hyperlink"); | ||
t.setOnMouseClicked(ae -> showLink.accept(hyperlink.getLink())); | ||
} | ||
}) | ||
) | ||
); | ||
|
||
getStyleClass().add("text-hyperlink-area"); | ||
getStylesheets().add(TextHyperlinkArea.class.getResource("text-hyperlink-area.css").toExternalForm()); | ||
} | ||
|
||
public void appendWithLink(String displayedText, String link) { | ||
replaceWithLink(getLength(), getLength(), displayedText, link); | ||
} | ||
|
||
public void replaceWithLink(int start, int end, String displayedText, String link) { | ||
replace(start, end, ReadOnlyStyledDocument.fromSegment( | ||
Either.right(new Hyperlink<>(displayedText, displayedText, TextStyle.EMPTY, link)), | ||
null, | ||
TextStyle.EMPTY, | ||
EITHER_OPS | ||
)); | ||
} | ||
|
||
public static TextExt createStyledTextNode(Consumer<TextExt> applySegment) { | ||
TextExt t = new TextExt(); | ||
t.setTextOrigin(VPos.TOP); | ||
applySegment.accept(t); | ||
|
||
// XXX: binding selectionFill to textFill, | ||
// see the note at highlightTextFill | ||
t.impl_selectionFillProperty().bind(t.fillProperty()); | ||
return t; | ||
} | ||
} |
Oops, something went wrong.