Mierpo
Mierpo

Reputation: 244

Apache Poi for Word - Create Custom style with TextAlignment

    private static void applyTextAlign(XWPFStyle style, TextAlignment value) {
        // Steps here
    }

How can I apply text alignment (of any sort, like TextAlignment.CENTER) to the style object being passed to the input of this function? I've been unable to find proper tutorials and examples on this.

        CTPPr ppr = style.getCTStyle().addNewPPr();
        CTTextAlignment textAlignment = ppr.addNewTextAlignment();
        STTextAlignment.Enum en = STTextAlignment.Enum.forInt(value.ordinal());
        textAlignment.setVal(en);

I tried something like the above, but naturally it's not correct and it even corrupts on docx. Other examples I've found here apply the text alignment directly to a paragraph, but I need the text alignment to be part of the style so it can be provided for any element, be it a paragraph or something else.

Upvotes: 1

Views: 1503

Answers (1)

Axel Richter
Axel Richter

Reputation: 61945

Using the low level CT* classes is not as simple. Those classes are auto created from the XML schema. They do consider nothing. So one can not simply add a new PPr to the style. What if it has one already? It cannot have two because that would lead to a corrupt file. One has to check whether there is already a PPr and only if not, then add a new one. Same for TextAlignment in the PPr then.

But of course there are more problems because of the very experimental state of XWPF in apache poi. For example XWPFStyle is mostly made for reading only up to now. There are not much setters until now. And when using CTStyle one needs to check whether changes on this really were stored. For example the java.util.List<XWPFStyle> of XWPFStyles seems lost the contact to the single CTStyles of the XWPFStyles in it. So I had to use reflection to find a way to change the CTStyle so that the changes were stored.

Oh, and of course one can not be sure, that the ordinal of the ST* enumerations is the same as the one of the apache poi enumerations. That would be too simple, wouldn't it?

Following code works for me using current apache poi 4.1.2:

import java.io.*;

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.lang.reflect.Field;

public class CreateWordTextAlingmentStyles {

 private static XWPFStyle createNamedStyle(XWPFStyles styles, STStyleType.Enum styleType, String styleId) {
  if (styles == null || styleId == null) return null;
  XWPFStyle style = styles.getStyle(styleId);
  if (style == null) {
   CTStyle ctStyle = CTStyle.Factory.newInstance();
   ctStyle.addNewName().setVal(styleId);
   ctStyle.setCustomStyle(STOnOff.TRUE);
   style = new XWPFStyle(ctStyle, styles);
   style.setType(styleType);
   style.setStyleId(styleId);
   styles.addStyle(style);
  }
  return style;
 }

 private static void applyTextAlignment(XWPFStyle style, TextAlignment value) throws Exception {
  if (style == null || value == null) return;

  Field _ctStyles = XWPFStyles.class.getDeclaredField("ctStyles");
  _ctStyles.setAccessible(true);
  CTStyles ctStyles = (CTStyles)_ctStyles.get(style.getStyles());

  for (CTStyle ctStyle : ctStyles.getStyleList()) {
   if (ctStyle.getStyleId().equals(style.getStyleId())) {
    CTPPr ppr = ctStyle.getPPr(); 
    if (ppr == null) ppr = ctStyle.addNewPPr();
    CTTextAlignment ctTextAlignment = ppr.getTextAlignment(); 
    if (ctTextAlignment == null) ctTextAlignment = ppr.addNewTextAlignment();
    if (value == TextAlignment.AUTO) {
     ctTextAlignment.setVal(STTextAlignment.AUTO);
    } else if (value == TextAlignment.BASELINE) {
     ctTextAlignment.setVal(STTextAlignment.BASELINE);
    } else if (value == TextAlignment.BOTTOM) {
     ctTextAlignment.setVal(STTextAlignment.BOTTOM);
    } else if (value == TextAlignment.CENTER) {
     ctTextAlignment.setVal(STTextAlignment.CENTER);
    } else if (value == TextAlignment.TOP) {
     ctTextAlignment.setVal(STTextAlignment.TOP);
    }
    style.setStyle(ctStyle);
   }
  }
 }

 private static void applyJustification(XWPFStyle style, ParagraphAlignment value) throws Exception {
  if (style == null || value == null) return;

  Field _ctStyles = XWPFStyles.class.getDeclaredField("ctStyles");
  _ctStyles.setAccessible(true);
  CTStyles ctStyles = (CTStyles)_ctStyles.get(style.getStyles());

  for (CTStyle ctStyle : ctStyles.getStyleList()) {
   if (ctStyle.getStyleId().equals(style.getStyleId())) {
    CTPPr ppr = ctStyle.getPPr(); if (ppr == null) ppr = ctStyle.addNewPPr();
    CTJc jc = ppr.getJc(); if (jc == null) jc = ppr.addNewJc();
    if (value == ParagraphAlignment.BOTH) {
     jc.setVal(STJc.BOTH);
    } else if (value == ParagraphAlignment.CENTER) {
     jc.setVal(STJc.CENTER);
    } else if (value == ParagraphAlignment.DISTRIBUTE) {
     jc.setVal(STJc.DISTRIBUTE);
    } else if (value == ParagraphAlignment.HIGH_KASHIDA) {
     jc.setVal(STJc.HIGH_KASHIDA);
    } else if (value == ParagraphAlignment.LEFT) {
     jc.setVal(STJc.LEFT);
    } else if (value == ParagraphAlignment.LOW_KASHIDA) {
     jc.setVal(STJc.LOW_KASHIDA);
    } else if (value == ParagraphAlignment.MEDIUM_KASHIDA) {
     jc.setVal(STJc.MEDIUM_KASHIDA);
    } else if (value == ParagraphAlignment.NUM_TAB) {
     jc.setVal(STJc.NUM_TAB);
    } else if (value == ParagraphAlignment.RIGHT) {
     jc.setVal(STJc.RIGHT);
    } else if (value == ParagraphAlignment.THAI_DISTRIBUTE) {
     jc.setVal(STJc.THAI_DISTRIBUTE);
    }
    style.setStyle(ctStyle);
   }
  }
 }

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

  XWPFDocument document = new XWPFDocument();
  XWPFParagraph paragraph = null;
  XWPFRun run = null;

  XWPFStyles styles = document.createStyles();

  XWPFStyle style = createNamedStyle(styles, STStyleType.PARAGRAPH, "TextAlignmentAUTO");
  applyTextAlignment(style, TextAlignment.AUTO);
  paragraph = document.createParagraph();
  paragraph.setStyle(style.getStyleId());
  run = paragraph.createRun();
  run.setText("TextAlignment.AUTO");
  run.setFontSize(8);
  run = paragraph.createRun();
  run.setText("Bigger text");
  run.setFontSize(30);

  style = createNamedStyle(styles, STStyleType.PARAGRAPH, "TextAlignmentBASELINECentered");
  applyJustification(style, ParagraphAlignment.CENTER);
  applyTextAlignment(style, TextAlignment.BASELINE);
  paragraph = document.createParagraph();
  paragraph.setStyle(style.getStyleId());
  run = paragraph.createRun();
  run.setText("TextAlignment.BASELINE");
  run.setFontSize(8);
  run = paragraph.createRun();
  run.setText("Bigger text");
  run.setFontSize(30);

  style = createNamedStyle(styles, STStyleType.PARAGRAPH, "TextAlignmentBOTTOMRight");
  applyJustification(style, ParagraphAlignment.RIGHT);
  applyTextAlignment(style, TextAlignment.BOTTOM);
  paragraph = document.createParagraph();
  paragraph.setStyle(style.getStyleId());
  run = paragraph.createRun();
  run.setText("TextAlignment.BOTTOM");
  run.setFontSize(8);
  run = paragraph.createRun();
  run.setText("Bigger text");
  run.setFontSize(30);

  style = createNamedStyle(styles, STStyleType.PARAGRAPH, "TextAlignmentCENTERBoth");
  applyJustification(style, ParagraphAlignment.BOTH);
  applyTextAlignment(style, TextAlignment.CENTER);
  paragraph = document.createParagraph();
  paragraph.setStyle(style.getStyleId());
  run = paragraph.createRun();
  run.setText("TextAlignment.CENTER");
  run.setFontSize(8);
  run = paragraph.createRun();
  run.setText("Bigger text");
  run.setFontSize(30);

  style = createNamedStyle(styles, STStyleType.PARAGRAPH, "TextAlignmentTOPLeft");
  applyJustification(style, ParagraphAlignment.LEFT);
  applyTextAlignment(style, TextAlignment.TOP);
  paragraph = document.createParagraph();
  paragraph.setStyle(style.getStyleId());
  run = paragraph.createRun();
  run.setText("TextAlignment.TOP");
  run.setFontSize(8);
  run = paragraph.createRun();
  run.setText("Bigger text");
  run.setFontSize(30);

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

 }
}

It produces:

enter image description here

Upvotes: 3

Related Questions