Search code examples
javadocx4j

Add content that prevents page breaks inside


Using docx4j I'm adding multiple dynamically filled subTemplates to my main template.
I don't want to have page breaks inside those subTemplates (unless even a whole page is too small for one).
Therefore: If a subTemplate would break inside, I want to move the whole subTemplate to the next page.
How do I do this?

My code so far:

//... 
WordprocessingMLPackage mainTemplate = getWp();//ignore this method
List<WordprocessingMLPackage> projectTemplates = new ArrayList<>();

List<Project> projects = getProjects();//ignore this method
for (Project project : projects) {
  WordprocessingMLPackage template = getWpProject();//ignore this method
  //fill template with content from project
  //...
  projectList.add(template);
}

//Here's the part that will have to be changed I think:
//Since the projectTemplate only consists of tables I just added all its tables to the main template 
for (WordprocessingMLPackage temp : projectTemplates){
  List<Object> tables = doc.getAllElementFromObject(temp.getMainDocumentPart(), Tbl.class);
  for (Object table : tables) {
    mainTemplate.getMainDocumentPart().addObject(table);
  }
}

If you can think of a way to change the .docx template with Word to achieve my goal feel free to suggest it.
And if you have suggestions for code improvement in general just write a comment.


Solution

  • I made this "workaround" that works nicely for me:
    I count all rows together and also check if the text inside the rows breaks (with an approximate threshold).
    Then I add the rows of each project up and as soon as there are too many rows I insert a break before the current project and start over.

    final int maxRowCountPerPage = 44;
    final int maxLettersPerLineInDescr = 55;
    int totalRowCount = 0;
    
    WordprocessingMLPackage mainTemplate = getWp();
    
    //Iterate over projects
    for (Project project : getProjects()) {
      WordprocessingMLPackage template = this.getWpProject();
      String projectDescription = project.getDescr();
    
      //Fill template...
    
      //Count the lines
      int rowsInProjectDescr = (int) Math.floor((double) projectDescription.length() / maxLettersPerLineInDescr);
      int projectRowCount = 0;
      List<Object> tables = doc.getAllElementFromObject(template.getMainDocumentPart(), Tbl.class);
      for (Object table : tables) {
        List<Object> rows = doc.getAllElementFromObject(table, Tr.class);
        int tableRowCount = rows.size();
        projectRowCount += tableRowCount;
      }
      //System.out.println("projectRowCount before desc:" + projectRowCount);
      projectRowCount += rowsInProjectDescr;
      //System.out.println("projectRowCount after desc:" + projectRowCount);
      totalRowCount += projectRowCount;
      //System.out.println("totalRowCount: " + totalRowCount);
    
      //Break page if too many lines for page
      if (totalRowCount > maxRowCountPerPage) {
        addPageBreak(wp);
        totalRowCount = projectRowCount;
      }
      //Add project template to main template
      for (Object table : tables) {
        mainTemplate.getMainDocumentPart().addObject(table);
      }
    }
    

    If you notice a way to make the code nicer, let me know in a comment!