diff --git a/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinking.java b/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinking.java new file mode 100644 index 000000000..90eda9678 --- /dev/null +++ b/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinking.java @@ -0,0 +1,111 @@ +/* + * Copyright 2019 Miroslav Pokorny (github.com/mP1) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package walkingkooka.spreadsheet.format; + +import walkingkooka.spreadsheet.format.provider.SpreadsheetFormatterSelectorToken; +import walkingkooka.text.printer.IndentingPrinter; +import walkingkooka.text.printer.TreePrintable; +import walkingkooka.tree.text.TextNode; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * A {@link SpreadsheetFormatter} that wraps another {@link SpreadsheetFormatter} attempting to convert any text into + * {@link walkingkooka.net.Url} using {@link walkingkooka.net.TextUrlVisitor}. + */ +final class SpreadsheetFormatterSharedHyperlinking extends SpreadsheetFormatterShared + implements TreePrintable { + + static SpreadsheetFormatterSharedHyperlinking with(final SpreadsheetFormatter formatter) { + return new SpreadsheetFormatterSharedHyperlinking( + Objects.requireNonNull(formatter, "formatter") + ); + } + + private SpreadsheetFormatterSharedHyperlinking(final SpreadsheetFormatter formatter) { + super(); + this.formatter = formatter; + } + + @Override + public Optional format(final Optional value, + final SpreadsheetFormatterContext context) { + final Optional formatted = this.formatter.format( + value, + context + ); + + // try and turn any Text from the formatted result of the wrapped formatter into Hyperlinks + return formatted.map( + t -> t.replaceIf( + TextNode::isText, + (TextNode textNode) -> SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.toTextNode( + textNode.text() + ) + ) + ); + } + + private final SpreadsheetFormatter formatter; + + @Override + public List tokens(final SpreadsheetFormatterContext context) { + Objects.requireNonNull(context, "context"); + + return NO_TOKENS; + } + + // Object........................................................................................................... + + @Override + public int hashCode() { + return this.formatter.hashCode(); + } + + @Override + public boolean equals(final Object other) { + return this == other || other instanceof SpreadsheetFormatterSharedHyperlinking && this.equals0((SpreadsheetFormatterSharedHyperlinking) other); + } + + private boolean equals0(final SpreadsheetFormatterSharedHyperlinking other) { + return this.formatter.equals(other.formatter); + } + + @Override + public String toString() { + return "linking " + this.formatter; + } + + // TreePrintable.................................................................................................... + + @Override + public void printTree(final IndentingPrinter printer) { + printer.println(this.getClass().getSimpleName()); + + printer.indent(); + { + TreePrintable.printTreeOrToString( + this.formatter, + printer + ); + } + printer.outdent(); + } +} diff --git a/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.java b/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.java new file mode 100644 index 000000000..eba2118da --- /dev/null +++ b/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2019 Miroslav Pokorny (github.com/mP1) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package walkingkooka.spreadsheet.format; + +import walkingkooka.collect.list.Lists; +import walkingkooka.net.TextUrlVisitor; +import walkingkooka.net.Url; +import walkingkooka.tree.text.TextNode; +import walkingkooka.visit.Visiting; + +import java.util.List; + +/** + * Accepts some plain text and converts urls into {@link walkingkooka.tree.text.Hyperlink} and text into {@link walkingkooka.tree.text.Text}. + */ +final class SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor extends TextUrlVisitor { + + static TextNode toTextNode(final String text) { + final SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor visitor = new SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor(); + visitor.accept(text); + return TextNode.style( + visitor.nodes + ); + } + + // @VisibleForTesting + SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor() { + super(); + } + + @Override + protected Visiting startVisit(final Url url) { + this.append( + TextNode.hyperlink(url) + ); + return Visiting.SKIP; + } + + @Override + protected void visitText(final String text) { + this.appendText(text); + } + + @Override + protected void visitInvalidUrlText(final String text) { + this.appendText(text); + } + + private void appendText(final String text) { + this.nodes.add( + TextNode.text(text) + ); + } + + private void append(final TextNode textNode) { + this.nodes.add(textNode); + } + + private final List nodes = Lists.array(); + + // Object........................................................................................................... + + @Override + public String toString() { + return String.valueOf(this.nodes); + } +} diff --git a/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatters.java b/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatters.java index a399cf07a..92391cf25 100644 --- a/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatters.java +++ b/src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatters.java @@ -171,6 +171,13 @@ public static SpreadsheetFormatter general() { return SpreadsheetPatternSpreadsheetFormatters.general(); } + /** + * {@see SpreadsheetFormatterSharedHyperlinking} + */ + public static SpreadsheetFormatter hyperlinking(final SpreadsheetFormatter formatter) { + return SpreadsheetFormatterSharedHyperlinking.with(formatter); + } + /** * {@see SpreadsheetPatternSpreadsheetFormatterNumber} */ diff --git a/src/test/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTest.java b/src/test/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTest.java new file mode 100644 index 000000000..34ab6f1db --- /dev/null +++ b/src/test/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTest.java @@ -0,0 +1,136 @@ +/* + * Copyright 2019 Miroslav Pokorny (github.com/mP1) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package walkingkooka.spreadsheet.format; + +import org.junit.jupiter.api.Test; +import walkingkooka.Either; +import walkingkooka.collect.list.Lists; +import walkingkooka.color.Color; +import walkingkooka.color.WebColorName; +import walkingkooka.convert.Converter; +import walkingkooka.convert.Converters; +import walkingkooka.net.Url; +import walkingkooka.spreadsheet.format.pattern.SpreadsheetPatternKind; +import walkingkooka.text.printer.TreePrintableTesting; +import walkingkooka.tree.text.TextNode; +import walkingkooka.tree.text.TextStyle; +import walkingkooka.tree.text.TextStylePropertyName; + +import java.util.Optional; + +public final class SpreadsheetFormatterSharedHyperlinkingTest extends SpreadsheetFormatterSharedTestCase + implements TreePrintableTesting { + + private final static Color RED = WebColorName.RED.color(); + + @Test + public void testFormatValueWithText() { + final String text = "HelloWorld"; + + this.formatAndCheck( + text, + SpreadsheetText.with(text + text) + .setColor( + Optional.of(RED) + ) + ); + } + + @Test + public void testFormatValueTextIncludesAbsoluteUrl() { + final String text = " HelloWorld https://www.example.com"; + + this.formatAndCheck( + text, + TextNode.style( + TextNode.NO_CHILDREN + ).setTextStyle( + TextStyle.EMPTY.set( + TextStylePropertyName.COLOR, + RED + ) + ).appendChild( + TextNode.style( + Lists.of( + TextNode.text(" HelloWorld "), + TextNode.hyperlink( + Url.parseAbsolute("https://www.example.com") + ), + TextNode.text(" HelloWorld "), + TextNode.hyperlink( + Url.parseAbsolute("https://www.example.com") + ) + ) + ) + ) + ); + } + + @Override + public SpreadsheetFormatterSharedHyperlinking createFormatter() { + return SpreadsheetFormatterSharedHyperlinking.with( + SpreadsheetPatternKind.TEXT_FORMAT_PATTERN.parse("[RED]@@") + .formatter() + ); + } + + @Override + public Object value() { + return "HelloWorld"; + } + + @Override + public SpreadsheetFormatterContext createContext() { + return new FakeSpreadsheetFormatterContext() { + @Override + public boolean canConvert(final Object value, + final Class type) { + return this.converter.canConvert( + value, + type, + this + ); + } + + @Override + public Either convert(final Object value, + final Class target) { + return this.converter.convert( + value, + target, + this + ); + } + + private final Converter converter = Converters.simple(); + + @Override + public Optional colorName(final SpreadsheetColorName name) { + checkEquals(SpreadsheetColorName.RED, name); + return Optional.of(RED); + } + }; + } + + // class............................................................................................................ + + @Override + public Class type() { + return SpreadsheetFormatterSharedHyperlinking.class; + } +} diff --git a/src/test/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTextUrlVisitorTest.java b/src/test/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTextUrlVisitorTest.java new file mode 100644 index 000000000..e49208039 --- /dev/null +++ b/src/test/java/walkingkooka/spreadsheet/format/SpreadsheetFormatterSharedHyperlinkingTextUrlVisitorTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019 Miroslav Pokorny (github.com/mP1) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package walkingkooka.spreadsheet.format; + +import org.junit.jupiter.api.Test; +import walkingkooka.collect.list.Lists; +import walkingkooka.net.TextUrlVisitorTesting; +import walkingkooka.net.Url; +import walkingkooka.reflect.JavaVisibility; +import walkingkooka.tree.text.TextNode; + +public final class SpreadsheetFormatterSharedHyperlinkingTextUrlVisitorTest implements TextUrlVisitorTesting { + + @Test + public void testToTextWithPlainText() { + final String text = "PlainText123"; + + this.toTextNodeAndCheck( + text, + TextNode.text(text) + ); + } + + @Test + public void testToTextWithHyperlink() { + final String url = "https://example.com"; + + this.toTextNodeAndCheck( + url, + TextNode.hyperlink( + Url.parse(url) + ) + ); + } + + @Test + public void testToTextWithHyperlinkAndText() { + final String url = "https://example.com"; + final String text = " textAfter123"; + + this.toTextNodeAndCheck( + url + text, + TextNode.style( + Lists.of( + TextNode.hyperlink( + Url.parse(url) + ), + TextNode.text(text) + ) + ) + ); + } + + private void toTextNodeAndCheck(final String text, + final TextNode expected) { + this.checkEquals( + expected, + SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.toTextNode(text), + text + ); + } + + @Override + public SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor createVisitor() { + return new SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor(); + } + + // class............................................................................................................ + + @Override + public Class type() { + return SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.class; + } + + @Override + public JavaVisibility typeVisibility() { + return JavaVisibility.PACKAGE_PRIVATE; + } +}