Skip to content

Commit 73fd3a5

Browse files
committed
SpreadsheetFormatterSharedHyperlinking
- Closes #8100 - SpreadsheetFormatter that turns urls into links
1 parent 9364388 commit 73fd3a5

File tree

5 files changed

+430
-0
lines changed

5 files changed

+430
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright 2019 Miroslav Pokorny (github.com/mP1)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package walkingkooka.spreadsheet.format;
19+
20+
import walkingkooka.spreadsheet.format.provider.SpreadsheetFormatterSelectorToken;
21+
import walkingkooka.text.printer.IndentingPrinter;
22+
import walkingkooka.text.printer.TreePrintable;
23+
import walkingkooka.tree.text.TextNode;
24+
25+
import java.util.List;
26+
import java.util.Objects;
27+
import java.util.Optional;
28+
29+
/**
30+
* A {@link SpreadsheetFormatter} that wraps another {@link SpreadsheetFormatter} attempting to convert any text into
31+
* {@link walkingkooka.net.Url} using {@link walkingkooka.net.TextUrlVisitor}.
32+
*/
33+
final class SpreadsheetFormatterSharedHyperlinking extends SpreadsheetFormatterShared
34+
implements TreePrintable {
35+
36+
static SpreadsheetFormatterSharedHyperlinking with(final SpreadsheetFormatter formatter) {
37+
return new SpreadsheetFormatterSharedHyperlinking(
38+
Objects.requireNonNull(formatter, "formatter")
39+
);
40+
}
41+
42+
private SpreadsheetFormatterSharedHyperlinking(final SpreadsheetFormatter formatter) {
43+
super();
44+
this.formatter = formatter;
45+
}
46+
47+
@Override
48+
public Optional<TextNode> format(final Optional<Object> value,
49+
final SpreadsheetFormatterContext context) {
50+
final Optional<TextNode> formatted = this.formatter.format(
51+
value,
52+
context
53+
);
54+
55+
// try and turn any Text from the formatted result of the wrapped formatter into Hyperlinks
56+
return formatted.map(
57+
t -> t.replaceIf(
58+
TextNode::isText,
59+
(TextNode textNode) -> SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor.toTextNode(
60+
textNode.text()
61+
)
62+
)
63+
);
64+
}
65+
66+
private final SpreadsheetFormatter formatter;
67+
68+
@Override
69+
public List<SpreadsheetFormatterSelectorToken> tokens(final SpreadsheetFormatterContext context) {
70+
Objects.requireNonNull(context, "context");
71+
72+
return NO_TOKENS;
73+
}
74+
75+
// Object...........................................................................................................
76+
77+
@Override
78+
public int hashCode() {
79+
return this.formatter.hashCode();
80+
}
81+
82+
@Override
83+
public boolean equals(final Object other) {
84+
return this == other || other instanceof SpreadsheetFormatterSharedHyperlinking && this.equals0((SpreadsheetFormatterSharedHyperlinking) other);
85+
}
86+
87+
private boolean equals0(final SpreadsheetFormatterSharedHyperlinking other) {
88+
return this.formatter.equals(other.formatter);
89+
}
90+
91+
@Override
92+
public String toString() {
93+
return "linking " + this.formatter;
94+
}
95+
96+
// TreePrintable....................................................................................................
97+
98+
@Override
99+
public void printTree(final IndentingPrinter printer) {
100+
printer.println(this.getClass().getSimpleName());
101+
102+
printer.indent();
103+
{
104+
TreePrintable.printTreeOrToString(
105+
this.formatter,
106+
printer
107+
);
108+
}
109+
printer.outdent();
110+
}
111+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2019 Miroslav Pokorny (github.com/mP1)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package walkingkooka.spreadsheet.format;
19+
20+
import walkingkooka.collect.list.Lists;
21+
import walkingkooka.net.TextUrlVisitor;
22+
import walkingkooka.net.Url;
23+
import walkingkooka.tree.text.TextNode;
24+
import walkingkooka.visit.Visiting;
25+
26+
import java.util.List;
27+
28+
/**
29+
* Accepts some plain text and converts urls into {@link walkingkooka.tree.text.Hyperlink} and text into {@link walkingkooka.tree.text.Text}.
30+
*/
31+
final class SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor extends TextUrlVisitor {
32+
33+
static TextNode toTextNode(final String text) {
34+
final SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor visitor = new SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor();
35+
visitor.accept(text);
36+
return TextNode.style(
37+
visitor.nodes
38+
);
39+
}
40+
41+
// @VisibleForTesting
42+
SpreadsheetFormatterSharedHyperlinkingTextUrlVisitor() {
43+
super();
44+
}
45+
46+
@Override
47+
protected Visiting startVisit(final Url url) {
48+
this.append(
49+
TextNode.hyperlink(url)
50+
);
51+
return Visiting.SKIP;
52+
}
53+
54+
@Override
55+
protected void visitText(final String text) {
56+
this.appendText(text);
57+
}
58+
59+
@Override
60+
protected void visitInvalidUrlText(final String text) {
61+
this.appendText(text);
62+
}
63+
64+
private void appendText(final String text) {
65+
this.nodes.add(
66+
TextNode.text(text)
67+
);
68+
}
69+
70+
private void append(final TextNode textNode) {
71+
this.nodes.add(textNode);
72+
}
73+
74+
private final List<TextNode> nodes = Lists.array();
75+
76+
// Object...........................................................................................................
77+
78+
@Override
79+
public String toString() {
80+
return String.valueOf(this.nodes);
81+
}
82+
}

src/main/java/walkingkooka/spreadsheet/format/SpreadsheetFormatters.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ public static SpreadsheetFormatter general() {
171171
return SpreadsheetPatternSpreadsheetFormatters.general();
172172
}
173173

174+
/**
175+
* {@see SpreadsheetFormatterSharedHyperlinking}
176+
*/
177+
public static SpreadsheetFormatter hyperlinking(final SpreadsheetFormatter formatter) {
178+
return SpreadsheetFormatterSharedHyperlinking.with(formatter);
179+
}
180+
174181
/**
175182
* {@see SpreadsheetPatternSpreadsheetFormatterNumber}
176183
*/
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright 2019 Miroslav Pokorny (github.com/mP1)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package walkingkooka.spreadsheet.format;
19+
20+
import org.junit.jupiter.api.Test;
21+
import walkingkooka.Either;
22+
import walkingkooka.collect.list.Lists;
23+
import walkingkooka.color.Color;
24+
import walkingkooka.color.WebColorName;
25+
import walkingkooka.convert.Converter;
26+
import walkingkooka.convert.Converters;
27+
import walkingkooka.net.Url;
28+
import walkingkooka.spreadsheet.format.pattern.SpreadsheetPatternKind;
29+
import walkingkooka.text.printer.TreePrintableTesting;
30+
import walkingkooka.tree.text.TextNode;
31+
import walkingkooka.tree.text.TextStyle;
32+
import walkingkooka.tree.text.TextStylePropertyName;
33+
34+
import java.util.Optional;
35+
36+
public final class SpreadsheetFormatterSharedHyperlinkingTest extends SpreadsheetFormatterSharedTestCase<SpreadsheetFormatterSharedHyperlinking>
37+
implements TreePrintableTesting {
38+
39+
private final static Color RED = WebColorName.RED.color();
40+
41+
@Test
42+
public void testFormatValueWithText() {
43+
final String text = "HelloWorld";
44+
45+
this.formatAndCheck(
46+
text,
47+
SpreadsheetText.with(text + text)
48+
.setColor(
49+
Optional.of(RED)
50+
)
51+
);
52+
}
53+
54+
@Test
55+
public void testFormatValueTextIncludesAbsoluteUrl() {
56+
final String text = " HelloWorld https://www.example.com";
57+
58+
this.formatAndCheck(
59+
text,
60+
TextNode.style(
61+
TextNode.NO_CHILDREN
62+
).setTextStyle(
63+
TextStyle.EMPTY.set(
64+
TextStylePropertyName.COLOR,
65+
RED
66+
)
67+
).appendChild(
68+
TextNode.style(
69+
Lists.of(
70+
TextNode.text(" HelloWorld "),
71+
TextNode.hyperlink(
72+
Url.parseAbsolute("https://www.example.com")
73+
),
74+
TextNode.text(" HelloWorld "),
75+
TextNode.hyperlink(
76+
Url.parseAbsolute("https://www.example.com")
77+
)
78+
)
79+
)
80+
)
81+
);
82+
}
83+
84+
@Override
85+
public SpreadsheetFormatterSharedHyperlinking createFormatter() {
86+
return SpreadsheetFormatterSharedHyperlinking.with(
87+
SpreadsheetPatternKind.TEXT_FORMAT_PATTERN.parse("[RED]@@")
88+
.formatter()
89+
);
90+
}
91+
92+
@Override
93+
public Object value() {
94+
return "HelloWorld";
95+
}
96+
97+
@Override
98+
public SpreadsheetFormatterContext createContext() {
99+
return new FakeSpreadsheetFormatterContext() {
100+
@Override
101+
public boolean canConvert(final Object value,
102+
final Class<?> type) {
103+
return this.converter.canConvert(
104+
value,
105+
type,
106+
this
107+
);
108+
}
109+
110+
@Override
111+
public <T> Either<T, String> convert(final Object value,
112+
final Class<T> target) {
113+
return this.converter.convert(
114+
value,
115+
target,
116+
this
117+
);
118+
}
119+
120+
private final Converter<SpreadsheetFormatterContext> converter = Converters.simple();
121+
122+
@Override
123+
public Optional<Color> colorName(final SpreadsheetColorName name) {
124+
checkEquals(SpreadsheetColorName.RED, name);
125+
return Optional.of(RED);
126+
}
127+
};
128+
}
129+
130+
// class............................................................................................................
131+
132+
@Override
133+
public Class<SpreadsheetFormatterSharedHyperlinking> type() {
134+
return SpreadsheetFormatterSharedHyperlinking.class;
135+
}
136+
}

0 commit comments

Comments
 (0)