/**
   * Creates document footer including page number
   *
   * @param doc WordprocessingMLPackage for the document.
   * @throws InvalidFormatException
   */
  private void createFooter(WordprocessingMLPackage doc) throws InvalidFormatException {
    MainDocumentPart content = doc.getMainDocumentPart();

    // Create footer
    FooterPart footer = new FooterPart();

    Ftr ftr = objectFactory.createFtr();
    P footerParagraph = objectFactory.createP();

    setStyle(footerParagraph, "footer");

    PPr parProps = objectFactory.createPPr();
    Jc al = objectFactory.createJc();
    al.setVal(JcEnumeration.RIGHT);
    parProps.setJc(al);
    footerParagraph.setPPr(parProps);

    // Add field start
    R run = objectFactory.createR();
    FldChar fldChar = objectFactory.createFldChar();
    fldChar.setFldCharType(STFldCharType.BEGIN);
    run.getContent().add(fldChar);
    footerParagraph.getContent().add(run);

    // Add pageNumber field
    run = objectFactory.createR();
    Text txt = objectFactory.createText();
    txt.setSpace("preserve");
    txt.setValue(" PAGE   \\* MERGEFORMAT ");
    run.getContent().add(objectFactory.createRInstrText(txt));
    footerParagraph.getContent().add(run);

    // Add field end
    run = objectFactory.createR();
    fldChar = objectFactory.createFldChar();
    fldChar.setFldCharType(STFldCharType.END);
    run.getContent().add(fldChar);
    footerParagraph.getContent().add(run);

    ftr.getContent().add(footerParagraph);
    footer.setJaxbElement(ftr);

    Relationship rel = content.addTargetPart(footer);

    // Relate footer to document
    List<SectionWrapper> sections = doc.getDocumentModel().getSections();

    SectPr sectPr = sections.get(sections.size() - 1).getSectPr();

    if (null == sectPr) {
      sectPr = objectFactory.createSectPr();
      content.addObject(sectPr);
      sections.get(sections.size() - 1).setSectPr(sectPr);
    }

    FooterReference footerReference = objectFactory.createFooterReference();
    footerReference.setId(rel.getId());
    footerReference.setType(HdrFtrRef.DEFAULT);
    sectPr.getEGHdrFtrReferences().add(footerReference);
  }
  /**
   * Sets style of paragraph
   *
   * @param paragraph Paragraph to style
   * @param styleName Style name
   */
  private void setStyle(ContentAccessor element, String styleName) {
    if (element instanceof P) {
      PPrBase.PStyle style = objectFactory.createPPrBasePStyle();
      style.setVal(styleName);

      PPr ppr = objectFactory.createPPr();
      ppr.setPStyle(style);
      ((P) element).setPPr(ppr);
    } else if (element instanceof Tbl) {
      TblPr.TblStyle style = objectFactory.createCTTblPrBaseTblStyle();
      style.setVal(styleName);

      TblPr tpr = objectFactory.createTblPr();
      CTTblLook tblLook = objectFactory.createCTTblLook();
      tblLook.setFirstColumn(STOnOff.FALSE);
      tblLook.setFirstRow(STOnOff.TRUE);
      tblLook.setLastColumn(STOnOff.FALSE);
      tblLook.setLastRow(STOnOff.FALSE);
      tblLook.setNoHBand(STOnOff.FALSE);
      tblLook.setNoVBand(STOnOff.TRUE);
      tpr.setTblLook(tblLook);

      tpr.setTblStyle(style);
      ((Tbl) element).setTblPr(tpr);
    }
  }
 // create paraghraph with no space after
 private P createParagraph() {
   P paragraph = factory.createP();
   PPr pPr = factory.createPPr();
   Spacing spacing = new Spacing();
   spacing.setAfter(BigInteger.ZERO);
   pPr.setSpacing(spacing);
   paragraph.setPPr(pPr);
   return paragraph;
 }
  /**
   * Fija la alineación de un párrafo
   *
   * @param paragraph Párrafo a alinear
   * @param alignment Valor de alineamiento
   */
  private void alignParagraph(P paragraph, JcEnumeration alignment) {
    PPr parProps = paragraph.getPPr();
    if (null == parProps) parProps = objectFactory.createPPr();
    Jc al = objectFactory.createJc();
    al.setVal(alignment);
    parProps.setJc(al);

    paragraph.setPPr(parProps);
  }
  /**
   * Follow the resolution rules to return the paragraph properties which actually apply, given this
   * pPr element (on a w:p).
   *
   * <p>Note 1: the properties are not the definition of any style name returned. Note 2: run
   * properties are not resolved or returned by this method.
   *
   * <p>What is returned is a live object. If you want to change it, you should clone it first!
   *
   * @param expressPPr
   * @return
   */
  public PPr getEffectivePPr(PPr expressPPr) {

    PPr effectivePPr = null;
    //	First, the document defaults are applied

    // Done elsewhere
    // PPr effectivePPr = (PPr)XmlUtils.deepCopy(documentDefaultPPr);

    //	Next, the table style properties are applied to each table in the document,
    //	following the conditional formatting inclusions and exclusions specified
    //	per table.

    // TODO - if the paragraph is in a table?

    //	Next, numbered item and paragraph properties are applied to each paragraph
    //	formatted with a *numbering *style**.

    // TODO - who uses numbering styles (as opposed to numbering
    // via a paragraph style or direct formatting)?

    //  Next, paragraph and run properties are
    //	applied to each paragraph as defined by the paragraph style.
    PPr resolvedPPr = null;
    String styleId;
    if (expressPPr == null || expressPPr.getPStyle() == null) {
      //			styleId = "Normal";
      styleId = defaultParagraphStyleId;

    } else {
      styleId = expressPPr.getPStyle().getVal();
    }
    resolvedPPr = getEffectivePPr(styleId);

    //	Next, run properties are applied to each run with a specific character style
    //	applied.

    // Not for pPr

    //	Finally, we apply direct formatting (paragraph or run properties not from
    //	styles).
    if (hasDirectPPrFormatting(expressPPr)) {
      if (resolvedPPr == null) {
        log.warn("resolvedPPr was null. Look into this?");
        effectivePPr = Context.getWmlObjectFactory().createPPr();
      } else {
        effectivePPr = (PPr) XmlUtils.deepCopy(resolvedPPr);
      }
      applyPPr(expressPPr, effectivePPr);
      return effectivePPr;
    } else {
      return resolvedPPr;
    }
  }
 private void setHorizontalAlignment(P paragraph, JcEnumeration hAlign) {
   if (hAlign != null) {
     PPr pprop = paragraph.getPPr();
     if (pprop == null) {
       pprop = new PPr();
       paragraph.setPPr(pprop);
     }
     Jc align = new Jc();
     align.setVal(hAlign);
     pprop.setJc(align);
     paragraph.setPPr(pprop);
   }
 }
  private Lvl createLevel(int level, Map<String, CSSValue> cssMap) {

    if (level > 8) level = 8; // Word can't open a document with Ilvl>8

    // Create object for lvl
    Lvl lvl = wmlObjectFactory.createLvl();
    lvl.setIlvl(BigInteger.valueOf(level));

    //            // Create object for pStyle
    //            Lvl.PStyle lvlpstyle = wmlObjectFactory.createLvlPStyle();
    //            lvl.setPStyle(lvlpstyle);
    //                lvlpstyle.setVal( "Heading1");

    // Create object for pPr
    PPr ppr = wmlObjectFactory.createPPr();
    lvl.setPPr(ppr);

    ppr.setInd(getInd(getAncestorIndentation()));

    // Create object for numFmt
    NumFmt numfmt = wmlObjectFactory.createNumFmt();
    lvl.setNumFmt(numfmt);
    numfmt.setVal(getNumberFormatFromCSSListStyleType(cssMap.get("list-style-type").getCssText()));

    // Create object for lvlText
    Lvl.LvlText lvllvltext = wmlObjectFactory.createLvlLvlText();
    lvl.setLvlText(lvllvltext);
    lvllvltext.setVal(
        getLvlTextFromCSSListStyleType(cssMap.get("list-style-type").getCssText(), level + 1));

    // Bullets have an associated font
    RFonts rfonts = geRFontsForCSSListStyleType(cssMap.get("list-style-type").getCssText());
    if (rfonts != null) {
      RPr rpr = wmlObjectFactory.createRPr();
      rpr.setRFonts(rfonts);
      lvl.setRPr(rpr);
    }

    // Create object for lvlJc
    Jc jc = wmlObjectFactory.createJc();
    lvl.setLvlJc(jc);
    jc.setVal(org.docx4j.wml.JcEnumeration.LEFT);

    // Create object for start
    Lvl.Start lvlstart = wmlObjectFactory.createLvlStart();
    lvl.setStart(lvlstart);
    lvlstart.setVal(BigInteger.valueOf(1));

    return lvl;
  }
  /**
   * Create a paragraph containing the string simpleText, styled using the specified style (up to
   * user to ensure it is a paragraph style) without adding it to the document.
   *
   * @param styleId
   * @param text
   * @return
   */
  public org.docx4j.wml.P createStyledParagraphOfText(String styleId, String text) {

    org.docx4j.wml.P p = createParagraphOfText(text);

    StyleDefinitionsPart styleDefinitionsPart = this.getStyleDefinitionsPart();

    if (getPropertyResolver().activateStyle(styleId)) {
      // Style is available
      org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory();
      org.docx4j.wml.PPr pPr = factory.createPPr();
      p.setPPr(pPr);
      org.docx4j.wml.PPrBase.PStyle pStyle = factory.createPPrBasePStyle();
      pPr.setPStyle(pStyle);
      pStyle.setVal(styleId);
    }

    return p;
  }
  public void setParagraphProperties(ParagraphPropertiesML pPr) {
    if (pPr != null && pPr.getParent() != null) {
      throw new IllegalArgumentException("Not an orphan.");
    }

    this.pPr = pPr;

    if (this.docxObject instanceof org.docx4j.wml.P) {
      org.docx4j.wml.PPr newDocxPPr = null;
      if (pPr != null) {
        pPr.setParent(ParagraphML.this);
        newDocxPPr = (org.docx4j.wml.PPr) pPr.getDocxObject();
      }
      ((org.docx4j.wml.P) this.docxObject).setPPr(newDocxPPr);

      if (newDocxPPr != null) {
        newDocxPPr.setParent(this.docxObject);
      }
    }
  }
  private P createPageNumParagraph() {
    CTSimpleField pgnum = factory.createCTSimpleField();
    pgnum.setInstr(" PAGE \\* MERGEFORMAT ");
    RPr RPr = factory.createRPr();
    RPr.setNoProof(new BooleanDefaultTrue());
    PPr ppr = factory.createPPr();
    Jc jc = factory.createJc();
    jc.setVal(JcEnumeration.CENTER);
    ppr.setJc(jc);
    PPrBase.Spacing pprbase = factory.createPPrBaseSpacing();
    pprbase.setBefore(BigInteger.valueOf(240));
    pprbase.setAfter(BigInteger.valueOf(0));
    ppr.setSpacing(pprbase);

    R run = factory.createR();
    run.getContent().add(RPr);
    pgnum.getContent().add(run);

    JAXBElement<CTSimpleField> fldSimple = factory.createPFldSimple(pgnum);
    P para = createParagraph();
    para.getContent().add(fldSimple);
    para.setPPr(ppr);
    return para;
  }
  protected void setNumbering(PPr pPr, BigInteger numId) {

    // Create and add <w:numPr>
    NumPr numPr = Context.getWmlObjectFactory().createPPrBaseNumPr();
    pPr.setNumPr(numPr);

    // The <w:numId> element
    NumId numIdElement = Context.getWmlObjectFactory().createPPrBaseNumPrNumId();
    numPr.setNumId(numIdElement);
    numIdElement.setVal(numId); // point to the correct list

    // The <w:ilvl> element
    Ilvl ilvlElement = Context.getWmlObjectFactory().createPPrBaseNumPrIlvl();
    numPr.setIlvl(ilvlElement);
    ilvlElement.setVal(BigInteger.valueOf(this.listStack.size() - 1));

    // TMP: don't let this override our numbering
    //	    p.getPPr().setInd(null);

  }
Exemple #12
0
  /**
   * @param expressRPr
   * @param pPr -
   * @return
   */
  public RPr getEffectiveRPr(RPr expressRPr, PPr pPr) {

    // NB Currently used in PDF viaXSLFO only

    log.debug("in getEffectiveRPr");

    //		Idea is that you pass pPr if you are using this for XSL FO,
    //		since we need to take account of rPr in paragraph styles
    //		(but not the rPr in a pPr direct formatting, since
    //       that only applies to the paragraph mark).
    //		 * For HTML/CSS, this would be null (since the pPr level rPr
    //		 * is made into a separate style applied via a second value in
    //		 * the class attribute).  But, in the CSS case, this
    // function is not used - since the rPr is made into a style as well.

    //	First, the document defaults are applied

    RPr effectiveRPr = (RPr) XmlUtils.deepCopy(documentDefaultRPr);

    // Apply DefaultParagraphFont.  We only do it explicitly
    // here as per conditions, because if there is a run style,
    // walking the hierarchy will include this if it is needed
    if (expressRPr == null || expressRPr.getRStyle() == null) {
      applyRPr(resolvedStyleRPrComponent.get(defaultCharacterStyleId), effectiveRPr);
    }

    //	Next, the table style properties are applied to each table in the document,
    //	following the conditional formatting inclusions and exclusions specified
    //	per table.

    // TODO - if the paragraph is in a table?

    //	Next, numbered item and paragraph properties are applied to each paragraph
    //	formatted with a *numbering *style**.

    //			 TODO - who uses numbering styles (as opposed to numbering
    // via a paragraph style or direct formatting)?

    //  Next, paragraph and run properties are
    //	applied to each paragraph as defined by the paragraph style
    // (this includes run properties defined in a paragraph style,
    //  but not run properties directly included in a pPr in the
    //  document (those only apply to a paragraph mark).

    if (pPr == null) {
      log.debug("pPr was null");
    } else {
      // At the pPr level, what rPr do we have?
      // .. ascend the paragraph style tree
      if (pPr.getPStyle() == null) {
        //					log.warn("No pstyle:");
        //					log.debug(XmlUtils.marshaltoString(pPr, true, true));
      } else {
        log.debug("pstyle:" + pPr.getPStyle().getVal());
        RPr pPrLevelRunStyle = getEffectiveRPr(pPr.getPStyle().getVal());
        // .. and apply those
        applyRPr(pPrLevelRunStyle, effectiveRPr);
      }
      // Check Paragraph rPr (our special hack of using ParaRPr
      // to format a fo:block)
      if ((expressRPr == null)
          && (pPr.getRPr() != null)
          && (hasDirectRPrFormatting(pPr.getRPr()))) {
        applyRPr(pPr.getRPr(), effectiveRPr);
      }
    }
    //	Next, run properties are applied to each run with a specific character style
    //	applied.
    RPr resolvedRPr = null;
    String runStyleId;
    if (expressRPr != null && expressRPr.getRStyle() != null) {
      runStyleId = expressRPr.getRStyle().getVal();
      resolvedRPr = getEffectiveRPr(runStyleId);
      applyRPr(resolvedRPr, effectiveRPr);
    }

    //	Finally, we apply direct formatting (run properties not from
    //	styles).
    if (hasDirectRPrFormatting(expressRPr)) {
      // effectiveRPr = (RPr)XmlUtils.deepCopy(effectiveRPr);
      applyRPr(expressRPr, effectiveRPr);
    }
    return effectiveRPr;
  }
Exemple #13
0
 @Override
 public void set(PPr pPr) {
   pPr.setShd((CTShd) this.getObject());
 }
    @Override
    public List<Object> apply(Object o) {

      if (o instanceof org.docx4j.wml.P) {
        pPr = ((P) o).getPPr();
        if (stylesInUse != null) { // do the styles
          boolean customPStyle = false;
          if (pPr != null) {
            if (pPr.getPStyle() != null) {
              // Note this paragraph style
              // log.debug("put style " + pPr.getPStyle().getVal());
              customPStyle = true;
              stylesInUse.add(pPr.getPStyle().getVal());
            }
            if ((pPr.getRPr() != null) && (pPr.getRPr().getRStyle() != null)) {
              // 	Note this run style
              // log.debug("put style " + pPr.getRPr().getRStyle().getVal() );
              stylesInUse.add(pPr.getRPr().getRStyle().getVal());
            }
          }
          defaultParagraphStyleUsed = defaultParagraphStyleUsed || (!customPStyle);
        }

      } else if (o instanceof org.docx4j.wml.R) {
        rPr = ((R) o).getRPr();
        if (stylesInUse != null) {
          if (rPr != null) {
            if (rPr.getRStyle() == null) {
              defaultCharacterStyleUsed = true;
            } else {
              stylesInUse.add(rPr.getRStyle().getVal());
            }
          }
        }

      } else if (o instanceof org.docx4j.wml.Text) {

        if (runFontSelector != null) {
          // discover the fonts which apply to this text
          log.debug(((Text) o).getValue());
          runFontSelector.fontSelector(pPr, rPr, ((Text) o));
        }

      } else if (o instanceof org.docx4j.wml.R.Sym) {

        if (fontsDiscovered != null) {
          org.docx4j.wml.R.Sym sym = (org.docx4j.wml.R.Sym) o;
          fontsDiscovered.add(sym.getFont());
        }

      } else if (o instanceof org.docx4j.wml.Tbl) {
        // The table could have a table style;
        // Tables created in Word 2007 default to table style "TableGrid",
        // which is based on "TableNormal".
        org.docx4j.wml.Tbl tbl = (org.docx4j.wml.Tbl) o;
        if (stylesInUse != null && tbl.getTblPr() != null && tbl.getTblPr().getTblStyle() != null) {
          //					log.debug("Adding table style: " + tbl.getTblPr().getTblStyle().getVal() );
          stylesInUse.add(tbl.getTblPr().getTblStyle().getVal());
        }
        // There is no such thing as a tr or a tc style,
        // so we don't need to look for them,
        // but since a tc can contain w:p or nested table,
        // we still need to recurse

      }
      return null;
    }
Exemple #15
0
  private boolean hasDirectPPrFormatting(PPr pPrToApply) {

    // NB, any rPr is intentionally ignored,
    // since pPr/rPr is not applicable to anything
    // except the paragraph mark

    if (pPrToApply == null) {
      return false;
    }

    // Here is where we do the real work.
    // There are a lot of paragraph properties
    // The below list is taken directly from PPrBase.

    // PPrBase.PStyle pStyle;

    // Ignore

    // BooleanDefaultTrue keepNext;
    if (pPrToApply.getKeepNext() != null) {
      return true;
    }

    // BooleanDefaultTrue keepLines;
    if (pPrToApply.getKeepLines() != null) {
      return true;
    }

    // BooleanDefaultTrue pageBreakBefore;
    if (pPrToApply.getPageBreakBefore() != null) {
      return true;
    }

    // CTFramePr framePr;
    // BooleanDefaultTrue widowControl;
    if (pPrToApply.getWidowControl() != null) {
      return true;
    }

    // PPrBase.NumPr numPr;
    // NumPr numPr;
    if (pPrToApply.getNumPr() != null) {
      return true;
    }

    // BooleanDefaultTrue suppressLineNumbers;
    if (pPrToApply.getSuppressLineNumbers() != null) {
      return true;
    }

    // PBdr pBdr;
    if (pPrToApply.getPBdr() != null) {
      return true;
    }

    // CTShd shd;
    if (pPrToApply.getShd() != null) {
      return true;
    }

    // Tabs tabs;
    if (pPrToApply.getTabs() != null) {
      return true;
    }

    // BooleanDefaultTrue suppressAutoHyphens;
    // BooleanDefaultTrue kinsoku;
    // BooleanDefaultTrue wordWrap;
    // BooleanDefaultTrue overflowPunct;
    // BooleanDefaultTrue topLinePunct;
    // BooleanDefaultTrue autoSpaceDE;
    // BooleanDefaultTrue autoSpaceDN;
    // BooleanDefaultTrue bidi;
    // BooleanDefaultTrue adjustRightInd;
    // BooleanDefaultTrue snapToGrid;
    // PPrBase.Spacing spacing;
    if (pPrToApply.getSpacing() != null) {
      return true;
    }

    // PPrBase.Ind ind;
    if (pPrToApply.getInd() != null) {
      return true;
    }

    // BooleanDefaultTrue contextualSpacing;
    // BooleanDefaultTrue mirrorIndents;
    // BooleanDefaultTrue suppressOverlap;
    // Jc jc;
    if (pPrToApply.getJc() != null) {
      return true;
    }

    // TextDirection textDirection;
    // PPrBase.TextAlignment textAlignment;
    if (pPrToApply.getTextAlignment() != null) {
      return true;
    }

    // CTTextboxTightWrap textboxTightWrap;
    // PPrBase.OutlineLvl outlineLvl;
    if (pPrToApply.getOutlineLvl() != null) {
      return true;
    }
    // PPrBase.DivId divId;
    // CTCnf cnfStyle;
    return false;
  }
  protected static List<ConversionSectionWrapper> processComplete(
      WordprocessingMLPackage wmlPackage,
      Document document,
      RelationshipsPart rels,
      BooleanDefaultTrue evenAndOddHeaders,
      boolean dummyPageNumbering) {
    List<ConversionSectionWrapper> conversionSections = new ArrayList<ConversionSectionWrapper>();
    List<Object> sectionContent = new ArrayList<Object>();
    ConversionSectionWrapper currentSectionWrapper = null;
    HeaderFooterPolicy previousHF = null;
    int conversionSectionIndex = 0;

    // According to the ECMA-376 2ed, if type is not specified, read it as next page
    // However Word 2007 sometimes treats it as continuous, and sometimes doesn't??
    // 20130216 Review above comment: !  In the Word UI, the Word "continuous" is shown where it is
    // effective.
    // In the XML, it is stored in the next following sectPr.

    // First, remove content controls,
    // since the P could be in a content control.
    // (It is easier to remove content controls, than
    //  to make the code below TraversalUtil based)
    // RemovalHandler is an XSLT-based way of doing this,
    // but here we avoid introducing a dependency on
    // XSLT (Xalan) for PDF output.
    SdtBlockFinder sbr = new SdtBlockFinder();
    new TraversalUtil(document.getContent(), sbr);
    for (int i = sbr.sdtBlocks.size() - 1; i >= 0; i--) {
      // Have to process in reverse order
      // so that parentList is correct for nested sdt

      SdtBlock sdtBlock = sbr.sdtBlocks.get(i);
      List<Object> parentList = null;
      if (sdtBlock.getParent() instanceof ArrayList) {
        parentList = (ArrayList) sdtBlock.getParent();
      } else {
        log.error("Handle " + sdtBlock.getParent().getClass().getName());
      }
      int index = parentList.indexOf(sdtBlock);
      parentList.remove(index);
      parentList.addAll(index, sdtBlock.getSdtContent().getContent());
    }

    //		if (log.isDebugEnabled()) {
    //			log.debug(XmlUtils.marshaltoString(document, true, true));
    //		}

    // Make a list, so it is easy to look at the following sectPr,
    // which we need to do to handle continuous sections properly
    List<SectPr> sectPrs = new ArrayList<SectPr>();
    for (Object o : document.getBody().getContent()) {

      if (o instanceof org.docx4j.wml.P) {
        if (((org.docx4j.wml.P) o).getPPr() != null) {
          org.docx4j.wml.PPr ppr = ((org.docx4j.wml.P) o).getPPr();
          if (ppr.getSectPr() != null) {
            sectPrs.add(ppr.getSectPr());
          }
        }
      }
    }

    if (document.getBody().getSectPr() != null) {
      // usual case
      sectPrs.add(document.getBody().getSectPr());

    } else {
      log.debug("No body level sectPr in document");

      // OK if the last object is w:p and it contains a sectPr.
      List<Object> all = document.getBody().getContent();
      Object last = all.get(all.size() - 1);
      if (last instanceof P
          && ((P) last).getPPr() != null
          && ((P) last).getPPr().getSectPr() != null) {
        // ok
        log.debug(
            ".. but last p contains sectPr .. move it"); // so our assumption later about there
                                                         // being a following section is correct

        SectPr thisSectPr = ((P) last).getPPr().getSectPr();
        document.getBody().setSectPr(thisSectPr);
        ((P) last).getPPr().setSectPr(null);
        sectPrs.remove(thisSectPr);

      } else {
        document.getBody().setSectPr(Context.getWmlObjectFactory().createSectPr());
        sectPrs.add(document.getBody().getSectPr());
      }
    }

    int sectPrIndex = 0; // includes continuous ones
    for (Object o : document.getBody().getContent()) {

      if (o instanceof org.docx4j.wml.P) {

        if (((org.docx4j.wml.P) o).getPPr() != null) {

          org.docx4j.wml.PPr ppr = ((org.docx4j.wml.P) o).getPPr();
          if (ppr.getSectPr() != null) {

            // If the *following* section is continuous, don't add *this* section
            boolean ignoreThisSection = false;
            SectPr followingSectPr = sectPrs.get(++sectPrIndex);
            if (followingSectPr.getType() != null
                && followingSectPr.getType().getVal().equals("continuous")) {

              ignoreThisSection = true;

              // If the w:pgSz on the two sections differs,
              // then Word inserts a page break (ie doesn't treat it as continuous).
              // If no w:pgSz element is present, then Word defaults
              // (presumably to Legal? TODO CHECK. There is no default setting in the docx).
              // Word always inserts a w:pgSz element?

              PgSz pgSzThis = ppr.getSectPr().getPgSz();
              PgSz pgSzNext = followingSectPr.getPgSz();

              if (pgSzThis != null && pgSzNext != null) {

                if (pgSzThis.getH().compareTo(pgSzNext.getH()) != 0) {
                  ignoreThisSection = false;
                }
                if (pgSzThis.getW().compareTo(pgSzNext.getW()) != 0) {
                  ignoreThisSection = false;
                }

                // Orientation:default is portrait
                boolean portraitThis = true;
                if (pgSzThis.getOrient() != null) {
                  portraitThis = pgSzThis.getOrient().equals(STPageOrientation.PORTRAIT);
                }
                boolean portraitNext = true;
                if (pgSzNext.getOrient() != null) {
                  portraitNext = pgSzNext.getOrient().equals(STPageOrientation.PORTRAIT);
                }
                if (portraitThis != portraitNext) {
                  ignoreThisSection = false;
                }
              }
              // TODO: handle cases where one or both pgSz elements are missing,
              // or H or W is missing.
              // Treat pgSz element missing as Legal size?
            }

            if (ignoreThisSection) {
              // In case there are some headers/footers that get inherited by the next section
              previousHF =
                  new HeaderFooterPolicy(ppr.getSectPr(), previousHF, rels, evenAndOddHeaders);

            } else {
              currentSectionWrapper =
                  createSectionWrapper(
                      ppr.getSectPr(),
                      previousHF,
                      rels,
                      evenAndOddHeaders,
                      ++conversionSectionIndex,
                      sectionContent,
                      dummyPageNumbering);
              conversionSections.add(currentSectionWrapper);
              previousHF = currentSectionWrapper.getHeaderFooterPolicy();
              sectionContent = new ArrayList<Object>();
            }
          }
        }
      }
      sectionContent.add(o);
      //			System.out.println(XmlUtils.marshaltoString(o, true));
    }

    currentSectionWrapper =
        createSectionWrapper(
            document.getBody().getSectPr(),
            previousHF,
            rels,
            evenAndOddHeaders,
            ++conversionSectionIndex,
            sectionContent,
            dummyPageNumbering);
    conversionSections.add(currentSectionWrapper);
    return conversionSections;
  }
 @Override
 public void set(PPr pPr) {
   pPr.setInd((Ind) this.getObject());
 }
  private WordprocessingMLPackage fetchComponents(
      WordprocessingMLPackage srcPackage, ContentAccessor contentAccessor) throws Docx4JException {

    // convert components to altChunk
    Map<Integer, CTAltChunk> replacements = new HashMap<Integer, CTAltChunk>();
    Integer index = 0;
    justGotAComponent = false;

    LinkedList<Integer> continuousBeforeIndex = new LinkedList<Integer>();
    List<Boolean> continuousBefore = new ArrayList<Boolean>();

    List<Boolean> continuousAfter = new ArrayList<Boolean>();

    for (Object block : contentAccessor.getContent()) {

      // Object ublock = XmlUtils.unwrap(block);
      if (block instanceof org.docx4j.wml.SdtBlock) {

        org.docx4j.wml.SdtBlock sdt = (org.docx4j.wml.SdtBlock) block;

        Tag tag = getSdtPr(sdt).getTag();

        if (tag == null) {
          List<Object> newContent = new ArrayList<Object>();
          newContent.add(sdt);
          continue;
        }

        log.info(tag.getVal());

        HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

        String componentId = map.get(BINDING_ROLE_COMPONENT);
        if (componentId == null) continue;

        // Convert the sdt to a w:altChunk
        // .. get the IRI
        String iri = ComponentsPart.getComponentById(components, componentId).getIri();
        log.debug("Fetching " + iri);

        if (docxFetcher == null) {
          log.error("You need a docxFetcher (and the MergeDocx extension) to fetch components");
          return srcPackage;
        }

        // .. create the part
        AlternativeFormatInputPart afiPart =
            new AlternativeFormatInputPart(
                getNewPartName(
                    "/chunk", ".docx", srcPackage.getMainDocumentPart().getRelationshipsPart()));
        afiPart.setBinaryData(docxFetcher.getDocxFromIRI(iri));

        afiPart.setContentType(
            new ContentType(
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")); // docx

        Relationship altChunkRel = srcPackage.getMainDocumentPart().addTargetPart(afiPart);
        CTAltChunk ac = Context.getWmlObjectFactory().createCTAltChunk();
        ac.setId(altChunkRel.getId());

        replacements.put(index, ac);

        /*
         * 2011 12 11 TODO.  Rethink support for
         * od:continuousBefore and od:continuousAfter.
         */

        // This is handled in this class
        if (map.get(BINDING_ROLE_COMPONENT_BEFORE) != null
            && map.get(BINDING_ROLE_COMPONENT_BEFORE).equals("true")) {
          continuousBefore.add(Boolean.TRUE);
          continuousBeforeIndex.addFirst(index);
          log.info("ctsBefore index: " + index);
        } else {
          continuousBefore.add(Boolean.FALSE);
          continuousBeforeIndex.addFirst(index);
        }

        // The following is handled in ProcessAltChunk
        if (map.get(BINDING_ROLE_COMPONENT_AFTER) != null
            && map.get(BINDING_ROLE_COMPONENT_AFTER).equals("true")) {
          continuousAfter.add(Boolean.TRUE);
        } else {
          continuousAfter.add(Boolean.TRUE);
        }

        justGotAComponent = true;
      }
      index++;
    }

    if (!justGotAComponent) {
      return srcPackage;
    }

    // Now replace in list
    for (Integer key : replacements.keySet()) {
      contentAccessor.getContent().set(key, replacements.get(key));
    }

    // Go through docx in reverse order
    List<Object> bodyChildren = contentAccessor.getContent();
    int i = 0;
    for (Integer indexIntoBody : continuousBeforeIndex) {

      if (continuousBefore.get(i)) {
        // Element before the w:altChunk
        if (indexIntoBody == 0) {
          // // Insert a sectPr right at the beginning of the docx?
          // // TODO check this isn't necessary
          // SectPr newSectPr =
          // Context.getWmlObjectFactory().createSectPr();
          // SectPr.Type type =
          // Context.getWmlObjectFactory().createSectPrType();
          // type.setVal("continuous");
          // newSectPr.setType( type );
          //
          // bodyChildren.add(0, newSectPr);

        } else {
          Object block = bodyChildren.get(indexIntoBody.intValue() - 1);
          if (block instanceof P
              && ((P) block).getPPr() != null
              && ((P) block).getPPr().getSectPr() != null) {
            makeContinuous(((P) block).getPPr().getSectPr());
          } else if (block instanceof P) {
            // More likely
            PPr ppr = ((P) block).getPPr();
            if (ppr == null) {
              ppr = Context.getWmlObjectFactory().createPPr();
              ((P) block).setPPr(ppr);
            }
            SectPr newSectPr = Context.getWmlObjectFactory().createSectPr();
            SectPr.Type type = Context.getWmlObjectFactory().createSectPrType();
            type.setVal("continuous");
            newSectPr.setType(type);

            ppr.setSectPr(newSectPr);
          } else {
            // Equally likely - its a table or something, so add a p
            P newP = Context.getWmlObjectFactory().createP();
            PPr ppr = Context.getWmlObjectFactory().createPPr();
            newP.setPPr(ppr);

            SectPr newSectPr = Context.getWmlObjectFactory().createSectPr();
            SectPr.Type type = Context.getWmlObjectFactory().createSectPrType();
            type.setVal("continuous");
            newSectPr.setType(type);
            ppr.setSectPr(newSectPr);

            bodyChildren.add(indexIntoBody.intValue(), newP); // add
            // before
            // altChunk
          }
        }
      }
      // else nothing specified, so go with normal MergeDocx behaviour

      i++;
    }

    // process altChunk
    try {
      // Use reflection, so docx4j can be built
      // by users who don't have the MergeDocx utility
      Class<?> documentBuilder = Class.forName("com.plutext.merge.ProcessAltChunk");
      // Method method = documentBuilder.getMethod("merge",
      // wmlPkgList.getClass());
      Method[] methods = documentBuilder.getMethods();
      Method processMethod = null;
      for (int j = 0; j < methods.length; j++) {
        log.debug(methods[j].getName());
        if (methods[j].getName().equals("process")) {
          processMethod = methods[j];
        }
      }
      if (processMethod == null) throw new NoSuchMethodException();
      return (WordprocessingMLPackage) processMethod.invoke(null, srcPackage);

    } catch (ClassNotFoundException e) {
      extensionMissing(e);
      justGotAComponent = false;
      return srcPackage;
      // throw new Docx4JException("Problem processing w:altChunk", e);
    } catch (NoSuchMethodException e) {
      // Degrade gracefully
      extensionMissing(e);
      justGotAComponent = false;
      return srcPackage;
      // throw new Docx4JException("Problem processing w:altChunk", e);
    } catch (Exception e) {
      throw new Docx4JException("Problem processing w:altChunk", e);
    }
  }
    @Override
    public List<Object> apply(Object o) {

      // NB: the tests in this method have to be comprehensive,
      // so if support for glow etc is introduced, tests for those
      // will need to be added

      if (o instanceof org.docx4j.wml.P) {
        P p = (P) o;

        // W14?
        if (p.getParaId() != null) {
          needW14 = true;
        }
        // W15?
        if (!needW15) {
          PPr ppr = p.getPPr();
          if (ppr != null) {
            if (ppr.getCollapsed() != null) {
              needW15 = true;
            }

            if (ppr.getSectPr() != null && ppr.getSectPr().getFootnoteColumns() != null) {
              needW15 = true;
            }
          }
        }

      } else if (o instanceof SdtElement) {
        SdtPr sdtPr = ((SdtElement) o).getSdtPr();
        if (sdtPr != null) {
          if (contains(
              sdtPr.getRPrOrAliasOrLock(),
              "http://schemas.microsoft.com/office/word/2010/wordml",
              w14SdtPrNames)) {
            needW14 = true;
          }
          if (contains(
              sdtPr.getRPrOrAliasOrLock(),
              "http://schemas.microsoft.com/office/word/2012/wordml",
              w15SdtPrNames)) {
            needW15 = true;
          }
        }
      } else if (o instanceof Tr) { // TODO does this need to be unwrapped?
        if (((Tr) o).getParaId() != null) {
          needW14 = true;
        }
      } else if (o instanceof CTObject) {
        if (((CTObject) o).getAnchorId() != null) {
          needW14 = true;
        }
      } else if (o instanceof Pict) {
        if (((Pict) o).getAnchorId() != null) {
          needW14 = true;
        }
      }

      return null;
    }