Skip to content

Commit

Permalink
Add linebreaks in .docx on \n (#257)
Browse files Browse the repository at this point in the history
As word does not show linebreaks on the `\n`
character, jocument needs to break the lines
properly using `XWPFRun.addBreak()` if a
string contains this symbol
  • Loading branch information
AntonOellerer authored Sep 10, 2024
1 parent b94ef94 commit 25ecd54
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 10 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
}

group 'com.docutools'
version = '4.2.3'
version = '4.2.4'

java {
toolchain {
Expand Down
24 changes: 15 additions & 9 deletions src/main/java/com/docutools/jocument/impl/word/WordUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,22 @@ public static String toString(XWPFParagraph paragraph) {
* @param newText the new test
*/
public static void replaceText(XWPFParagraph paragraph, String newText) {
String[] lines = newText.split("(\\r\\n|\\r|\\n)");
List<XWPFRun> runs = paragraph.getRuns();
if (runs.isEmpty()) {
XWPFRun run = paragraph.createRun();
run.setText(newText, 0);
} else {
runs.get(0).setText(newText, 0);
// When deleting a run from a paragraph, the collection keeping the runs shrinks to fit to the new size
// If we delete the runs with indices 1,2,3...,x, the second half of the delete operations fails silently
// To avoid this, we simply delete the first run x times.
IntStream.range(1, runs.size()).forEach(value -> paragraph.removeRun(1));
// When deleting a run from a paragraph, the collection keeping the runs shrinks to fit to the new size
// If we delete the runs with indices 1,2,3...,x, the second half of the delete operations fails silently
// To avoid this, we simply delete the first run x times.
IntStream.range(0, runs.size()).forEach(value -> paragraph.removeRun(0));
XWPFRun run = paragraph.createRun();
insertLines(lines, run);
}

private static void insertLines(String[] lines, XWPFRun run) {
for (int i = 0; i < lines.length; i++) {
run.setText(lines[i]);
if (i < lines.length - 1) {
run.addBreak();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
import com.docutools.jocument.sample.model.SampleModelData;
import com.docutools.jocument.sample.placeholders.QuotePlaceholder;
import com.docutools.jocument.sample.placeholders.TextPlaceholder;
import com.docutools.poipath.xwpf.RunWrapper;
import com.docutools.poipath.xwpf.XWPFDocumentWrapper;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import org.apache.poi.xwpf.usermodel.BodyElementType;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
Expand Down Expand Up @@ -583,4 +585,26 @@ void doesNotResolveCustomPlaceholderWithoutBrackets() throws InterruptedExceptio
equalTo("quote"));
}

@Test
void preservesLinebreaksInStrings() throws InterruptedException, IOException {
// Arrange
Template template = Template.fromClassPath("/templates/word/UserProfileTemplate.docx")
.orElseThrow();
PlaceholderResolver resolver = new ReflectionResolver(SampleModelData.LINEBREAK_NAME_PERSON);

// Act
Document document = template.startGeneration(resolver);
document.blockUntilCompletion(60000L); // 1 minute

// Assert
assertThat(document.completed(), is(true));
xwpfDocument = TestUtils.getXWPFDocumentFromDocument(document);
var documentWrapper = new XWPFDocumentWrapper(xwpfDocument);
List<RunWrapper> runs = documentWrapper.bodyElement(0).asParagraph().runs();
assertThat(runs.size(), equalTo(1));
XWPFRun xwpfRun = runs.get(0).xwpfRun();
assertThat(xwpfRun.getText(0), equalTo("User Profile: Tyron "));
assertThat(xwpfRun.getText(1), equalTo(" Socci Mignon "));
assertThat(xwpfRun.getText(2), equalTo(" Ellworths"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class SampleModelData {
public static final Planet PLANET;
public static final Army ARMY;
private static final Random RANDOM = new Random();
public static final Person LINEBREAK_NAME_PERSON = new Person("Tyron \n Socci", "Mignon \n Ellworths", LocalDate.now());

static {
try {
Expand Down

0 comments on commit 25ecd54

Please sign in to comment.