Skip to content
Open
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
1 change: 1 addition & 0 deletions java/bundles/org.eclipse.set.nattable.utils/.classpath
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="lib" path="hyph/"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ Automatic-Module-Name: org.eclipse.set.nattable.utils
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-Vendor: Eclipse Signalling Engineering Toolbox
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: hyph/,
.
Export-Package: org.eclipse.set.nattable.utils
Import-Package: org.eclipse.nebula.widgets.nattable.config;version="1.5.0",
Import-Package: com.google.common.collect,
org.apache.fop.hyphenation,
org.eclipse.nebula.widgets.nattable.config;version="1.5.0",
org.eclipse.nebula.widgets.nattable.export;version="1.5.0",
org.eclipse.nebula.widgets.nattable.export.command;version="1.5.0",
org.eclipse.nebula.widgets.nattable.export.csv;version="1.5.0",
Expand Down
3 changes: 2 additions & 1 deletion java/bundles/org.eclipse.set.nattable.utils/build.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
.,\
hyph/
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Copyright (c) 2026 DB InfraGO AG and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*/
package org.eclipse.set.nattable.utils;

import java.io.ObjectInputStream;

import org.apache.fop.hyphenation.Hyphenation;
import org.apache.fop.hyphenation.HyphenationTree;

/**
*
*/
public class Hyphenator {
HyphenationTree hyphenation;

/**
* @param hyphenationTree
* the {@link HyphenationTree}
*/
public Hyphenator(final HyphenationTree hyphenationTree) {
hyphenation = hyphenationTree;
}

/**
* @param word
* the word to hyphenate
* @return the split index
*/
public int[] points(final String word) {
final Hyphenation hyphenate = hyphenation.hyphenate(word, 2, 2);
return hyphenate == null ? new int[0]
: hyphenate.getHyphenationPoints();
}

/**
* @param word
* the word to hyphenate
* @return the split words
*/
public String[] splitedWord(final String word) {
final int[] points = points(word);
final String[] splitWords = new String[points.length + 1];
int startIndex = 0;
for (int i = 0; i < points.length; i++) {
splitWords[i] = word.substring(startIndex, points[i]);
startIndex = points[i];
}
splitWords[points.length] = word.substring(startIndex, word.length());
return splitWords;
}

/**
* @return the {@link Hyphenator}
*/
public static Hyphenator createInstance() {
try (var inputStream = Hyphenator.class.getClassLoader()
.getResourceAsStream("hyph/de.hyp")) { //$NON-NLS-1$
final ObjectInputStream objectInputStream = new ObjectInputStream(
inputStream);
if (objectInputStream
.readObject() instanceof final HyphenationTree hyphenationTree) {
return new Hyphenator(hyphenationTree);
}
throw new IllegalArgumentException("Can't create Hyphenator"); //$NON-NLS-1$
} catch (final Exception e) {
throw new IllegalArgumentException("Can't create Hyphenator"); //$NON-NLS-1$
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public PlanProRichTextCellPainter(final boolean wrapText,
final boolean calculateByTextLength,
final boolean calculateByTextHeight) {
super(wrapText, calculateByTextLength, calculateByTextHeight);
richTextPainter.setWordSplitRegex(WORD_SPLIT_REGEX);
this.richTextPainter = new PlanProRichTextPainter(wrapText);
this.richTextPainter.setWordSplitRegex(WORD_SPLIT_REGEX);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/**
* Copyright (c) 2026 DB InfraGO AG and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*/
package org.eclipse.set.nattable.utils;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.XMLEvent;

import org.eclipse.nebula.widgets.richtext.RichTextPainter;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;

/**
*
*/
public class PlanProRichTextPainter extends RichTextPainter {
private static String HYPHENATION_SEPARATOR = "-"; //$NON-NLS-1$
private static String RICHTEXT_LINE_BREAK = "<br></br>"; //$NON-NLS-1$
XMLInputFactory factory = XMLInputFactory.newInstance();
{
// as we don't have a well-formed XML document, we need to take care
// of
// entity references ourself
factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES,
Boolean.FALSE);
}
Hyphenator hyphenator;

/**
* @param wrap
*/
public PlanProRichTextPainter(final boolean wrap) {
super(wrap);
hyphenator = Hyphenator.createInstance();
}

@Override
protected void paintHTML(final String html, final GC gc,
final Rectangle bounds, final boolean render) {
try {
final String cleanedHTML = html
.replaceAll(RichTextPainter.CONTROL_CHARACTER_REGEX, ""); //$NON-NLS-1$
final XMLEventReader reader = factory
.createXMLEventReader(new StringReader(cleanedHTML));
String newHtmlText = html;
while (reader.hasNext()) {
final XMLEvent event = reader.nextEvent();
if (event.getEventType() == XMLStreamConstants.CHARACTERS) {
final Characters asCharacters = event.asCharacters();
final String textValue = asCharacters.getData();
final String hyphenationText = hyphenationText(textValue,
gc, bounds.width);
newHtmlText = html.replace(textValue, hyphenationText);
}
}
super.paintHTML(newHtmlText, gc, bounds, render);
} catch (final Exception e) {
super.paintHTML(html, gc, bounds, render);
}
}

/**
* @param text
* the text to hyphenation
* @param gc
* the {@link GC}
* @param availableLength
* the available length
* @return the hyphenated text
*/
public String hyphenationText(final String text, final GC gc,
final int availableLength) {
if (gc.textExtent(text).x <= availableLength) {
return text;
}
final StringBuilder result = new StringBuilder();
final Matcher matcher = Pattern.compile("\\S+|\\s+").matcher(text);
while (matcher.find()) {
final String word = matcher.group();
if (Character.isWhitespace(word.charAt(0))) {
// Keep original whitespace character
result.append(word);
} else {
result.append(hyphenationText(word, gc, availableLength, "_")); //$NON-NLS-1$
}
}
return result.toString();
}

private String hyphenationText(final String text, final GC gc,
final int availableLength, final String seperator) {
final String[] words = text.split(seperator);
if (words.length == 1) {
if (gc.textExtent(text).x > availableLength) {
return splitWord(gc, text, availableLength).stream()
.collect(Collectors.joining(
HYPHENATION_SEPARATOR + RICHTEXT_LINE_BREAK));
}
return text;
}
final StringBuilder result = new StringBuilder();
final int separatorW = gc.textExtent(seperator).x;
int lineWidth = 0;
for (int i = 0; i < words.length; i++) {
final int w = gc.textExtent(words[i]).x;
if (lineWidth + separatorW + w > availableLength) {
// Add line break instead hyphenation, when word length relevant
if (separatorW + w <= availableLength) {
result.append(RICHTEXT_LINE_BREAK).append(words[i]);
lineWidth = w;
} else {
int rest = availableLength - lineWidth - separatorW;
if (rest <= 0) {
result.append(RICHTEXT_LINE_BREAK);
rest = availableLength;
lineWidth = 0;
}
final List<String> hyphenatedWord = splitWord(gc, words[i],
rest);
result.append(hyphenatedWord.stream()
.collect(Collectors.joining(HYPHENATION_SEPARATOR
+ RICHTEXT_LINE_BREAK)));
lineWidth = gc.textExtent(hyphenatedWord.getLast()).x;
}
} else {
result.append(words[i]);
lineWidth += w;
}

if (i < words.length - 1) {
lineWidth += separatorW;
result.append(seperator);
}
}
return result.toString();

}

private List<String> splitWord(final GC gc, final String word,
final int rest) {
final String[] splitdWord = hyphenator.splitedWord(word);
final List<String> hyphenatedWord = new ArrayList<>();
StringBuilder builder = new StringBuilder();
for (final String w : splitdWord) {
final String tmpW = builder.toString() + w;
if (builder.length() > 0
&& gc.textExtent(tmpW + HYPHENATION_SEPARATOR).x > rest) {
hyphenatedWord.add(builder.toString());
builder = new StringBuilder(w);
} else {
builder.append(w);
}
}

if (builder.length() > 0 || hyphenatedWord.isEmpty()) {
hyphenatedWord.add(builder.toString());
}

return hyphenatedWord;

}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 DB Netz AG and others.
* Copyright (c) 2017 DB Netz AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
Expand Down Expand Up @@ -39,18 +39,27 @@ public class PlanProTableCellPainter extends BackgroundPainter {
public PlanProTableCellPainter(final ICellPainter interiorPainter,
final Image yellowWarningImage, final Image redWarningImage,
final Image blackWarningImage) {
super(new PaddingDecorator(new BasePainterDecorator(
new BasePainterDecorator(new BasePainterDecorator(
interiorPainter, BaseEdgeEnum.BEFORE,
new WarningPainter(redWarningImage,
CellContentExtensions.WARNING_MARK_RED)),
BaseEdgeEnum.BEFORE,
new WarningPainter(blackWarningImage,
CellContentExtensions.WARNING_MARK_BLACK)),
BaseEdgeEnum.BEFORE,
new WarningPainter(yellowWarningImage,
CellContentExtensions.WARNING_MARK_YELLOW)),
TOP_PADDING, RIGHT_PADDING, BOTTOM_PADDING, LEFT_PADDING,
super(new PaddingDecorator( //
new BasePainterDecorator( //
new BasePainterDecorator( //
new BasePainterDecorator( //
interiorPainter, //
BaseEdgeEnum.BEFORE,
new WarningPainter(redWarningImage,
CellContentExtensions.WARNING_MARK_RED) //
), //
BaseEdgeEnum.BEFORE, //
new WarningPainter(blackWarningImage,
CellContentExtensions.WARNING_MARK_BLACK) //
), //
BaseEdgeEnum.BEFORE, //
new WarningPainter(yellowWarningImage,
CellContentExtensions.WARNING_MARK_YELLOW) //
), //
TOP_PADDING, //
RIGHT_PADDING, //
BOTTOM_PADDING, //
LEFT_PADDING, //
false));
}
}
12 changes: 12 additions & 0 deletions java/java-test/org.eclipse.set.nattable.utils.test/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="lib" path="hyph/"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src">
<attributes>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>
28 changes: 28 additions & 0 deletions java/java-test/org.eclipse.set.nattable.utils.test/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.set.nattable.utils.test</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=21
Loading
Loading