RunUtil.java
package pro.verron.officestamper.core;
import jakarta.xml.bind.JAXBElement;
import org.docx4j.model.styles.StyleUtil;
import org.docx4j.wml.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import pro.verron.officestamper.api.OfficeStamperException;
import java.util.Objects;
import static java.util.stream.Collectors.joining;
import static pro.verron.officestamper.utils.WmlFactory.newRun;
import static pro.verron.officestamper.utils.WmlFactory.newText;
/**
* Utility class to handle runs.
*
* @author Joseph Verron
* @author Tom Hombergs
* @version ${version}
* @since 1.0.0
*/
public class RunUtil {
private static final String PRESERVE = "preserve";
private static final Logger log = LoggerFactory.getLogger(RunUtil.class);
private RunUtil() {
throw new OfficeStamperException("Utility class shouldn't be instantiated");
}
/**
* Extracts textual content from a given object, handling various object types,
* such as runs, text elements, and other specific constructs.
* The method accounts for different cases, such as run breaks, hyphens,
* and other document-specific constructs, and converts them into
* corresponding string representations.
*
* @param content the object from which text content is to be extracted.
* This could be of various types such as R, JAXBElement, Text,
* or specific document elements.
*
* @return a string representation of the extracted textual content.
* If the object's type is not handled, an empty string is returned.
*/
public static String getText(Object content) {
return switch (content) {
case R run -> run.getContent()
.stream()
.map(RunUtil::getText)
.collect(joining());
case JAXBElement<?> jaxbElement when jaxbElement.getName()
.getLocalPart()
.equals("instrText") -> "<instrText>";
case JAXBElement<?> jaxbElement when !jaxbElement.getName()
.getLocalPart()
.equals("instrText") -> getText(jaxbElement.getValue());
case Text text -> getText(text);
case R.Tab ignored -> "\t";
case R.Cr ignored -> "\n";
case Br br when br.getType() == null -> "\n";
case Br br when br.getType() == STBrType.TEXT_WRAPPING -> "\n";
case Br br when br.getType() == STBrType.PAGE -> "\n";
case Br br when br.getType() == STBrType.COLUMN -> "\n";
case R.NoBreakHyphen ignored -> "‑";
case R.SoftHyphen ignored -> "\u00AD";
case R.LastRenderedPageBreak ignored -> "";
case R.AnnotationRef ignored -> "";
case R.CommentReference ignored -> "";
case Drawing ignored -> "";
case FldChar ignored -> "<fldchar>";
case CTFtnEdnRef ref -> ref.getId()
.toString();
case R.Sym sym -> "<sym(%s, %s)>".formatted(sym.getFont(), sym.getChar());
default -> {
log.debug("Unhandled object type: {}", content.getClass());
yield "";
}
};
}
/**
* Processes and retrieves text content from a given Text object.
* It handles situations where the text may or may not preserve spaces,
* trimming the text if spaces are not to be preserved.
*
* @param text the Text object from which the value is to be processed and returned.
* The object contains the textual value, and an associated space property
* that determines if spaces should be preserved.
*
* @return a processed string value from the Text object.
* If spaces are to be preserved, the original value is returned;
* otherwise, the value is trimmed of leading and trailing spaces.
*/
private static String getText(Text text) {
var value = text.getValue();
var space = text.getSpace();
return Objects.equals(space, PRESERVE) ? value : value.trim();
}
/**
* Creates a new run with the specified text and inherits the style of the parent paragraph.
*
* @param text the initial text of the run.
*
* @return the newly created run.
*/
public static R create(String text, PPr paragraphPr) {
R run = newRun(text);
applyParagraphStyle(run, paragraphPr);
return run;
}
/**
* Applies the style of the given paragraph to the given content object (if the content object is a Run).
*
* @param run the Run to which the style should be applied.
*/
public static void applyParagraphStyle(R run, @Nullable PPr paragraphPr) {
if (paragraphPr == null) return;
var runPr = paragraphPr.getRPr();
if (runPr == null) return;
RPr runProperties = new RPr();
StyleUtil.apply(runPr, runProperties);
run.setRPr(runProperties);
}
/**
* Sets the text of the given run to the given value.
*
* @param run the run whose text to change.
* @param text the text to set.
*/
public static void setText(R run, String text) {
run.getContent()
.clear();
Text textObj = newText(text);
run.getContent()
.add(textObj);
}
static R create(String text, RPr rPr) {
R newStartRun = newRun(text);
newStartRun.setRPr(rPr);
return newStartRun;
}
}