1

I'm working creating a docx file which needs to be readonly protected except in some fields. For those fields I have solved it with this:

pInit.getCTP().addNewPermStart();
...
pEnd.getCTP().addNewPermEnd();

But now I want to allow adding new rows to a XWPFTable, but this line:

document.enforceReadonlyProtection(wordLockedPass, HashAlgorithm.sha1);

block this functionality and I don't know what to do.

Thanks in advance!

mz0
  • 21
  • 3

1 Answers1

2

If the table is in an editable region (between PermStart and PermEnd) then it will be editable including adding rows.

The PermStart and PermEnd can be inserted in document body using

// CTPermStart marking the start of unprotected range  
CTPermStart ctPermStart = document.getDocument().getBody().addNewPermStart();
ctPermStart.setEdGrp(STEdGrp.EVERYONE);
ctPermStart.setId("123456"); //note the Id

and

// CTPerm marking the end of unprotected range  
document.getDocument().getBody().addNewPermEnd().setId("123456"); //note the same Id

All body elements between this PermStart and PermEnd are editable in a protected document. That is true also for tables between this PermStart and PermEnd.

If only parts of tables shall be editable, then PermStart and PermEnd also can be inserted within the table. For example if only the last row of a table shall be editable and new rows shall be insertable, then:

XWPFTable table = ...;
...  
// CTPermStart marking the start of unprotected range  
ctPermStart = table.getCTTbl().addNewPermStart();
ctPermStart.setEdGrp(STEdGrp.EVERYONE);
ctPermStart.setId("789012"); //note the Id

XWPFTableRow row = table.createRow();

// CTPerm marking the end of unprotected range  
table.getCTTbl().addNewPermEnd().setId("789012"); //note the same Id
...

Complete example:

import java.io.*;

import org.apache.poi.wp.usermodel.*;

import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPermStart;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STEdGrp;

public class CreateWordPartialProtected {

 public static void main(String[] args) throws Exception {

  XWPFDocument document= new XWPFDocument();

  // create header
  XWPFHeader header = document.createHeader(HeaderFooterType.DEFAULT);

  XWPFParagraph paragraph = header.createParagraph();
  paragraph.setAlignment(ParagraphAlignment.LEFT);

  XWPFRun run = paragraph.createRun();  
  run.setText("The page header:");

  // create footer
  XWPFFooter footer = document.createFooter(HeaderFooterType.DEFAULT);

  paragraph = footer.createParagraph();
  paragraph.setAlignment(ParagraphAlignment.CENTER);

  run = paragraph.createRun();  
  run.setText("Page ");
  paragraph.getCTP().addNewFldSimple().setInstr("PAGE \\* MERGEFORMAT");
  run = paragraph.createRun();  
  run.setText(" of ");
  paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* MERGEFORMAT");

  // the body content
  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("This body part is protected.");
  paragraph = document.createParagraph();

  // CTPermStart marking the start of unprotected range  
  CTPermStart ctPermStart = document.getDocument().getBody().addNewPermStart();
  ctPermStart.setEdGrp(STEdGrp.EVERYONE);
  ctPermStart.setId("123456"); //note the Id

  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("This body part is not protected.");

  // CTPerm marking the end of unprotected range  
  document.getDocument().getBody().addNewPermEnd().setId("123456"); //note the same Id

  paragraph = document.createParagraph();

  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("This body part is protected again.");
  paragraph = document.createParagraph();
  

  XWPFTable table = document.createTable(1, 3);
  table.setWidth("100%");
  table.getRow(0).getCell(0).setText("Column 1");
  table.getRow(0).getCell(1).setText("Column 2");
  table.getRow(0).getCell(2).setText("Column 3");
  
  // CTPermStart marking the start of unprotected range  
  ctPermStart = table.getCTTbl().addNewPermStart();
  ctPermStart.setEdGrp(STEdGrp.EVERYONE);
  ctPermStart.setId("789012"); //note the Id
  
  XWPFTableRow row = table.createRow();

  // CTPerm marking the end of unprotected range  
  table.getCTTbl().addNewPermEnd().setId("789012"); //note the same Id
  
  paragraph = document.createParagraph();

  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("This body part is protected again.");
  paragraph = document.createParagraph();

  document.enforceReadonlyProtection("passwd", org.apache.poi.poifs.crypt.HashAlgorithm.sha1); //enforce readonly protection

  FileOutputStream out = new FileOutputStream("CreateWordPartialProtected.docx");
  document.write(out);
  out.close();
  document.close();

 }
}

This code is tested and works using apache poi 5.2.2. It produces a Word document having two editable regions. The second is in a table after the title row. So that title row is protected. The last row is in that editable region. So this row is editable and new rows can be inserted above and below that row. All this tested in Microsoft Word 2017 and Microsoft Word 365. Other text-processing applications, which are able to handle *.docx files, might not respect editable regions.

Axel Richter
  • 56,077
  • 6
  • 60
  • 87