Package org.docx4j.convert.out.html

Source Code of org.docx4j.convert.out.html.ListsToContentControls

package org.docx4j.convert.out.html;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.JAXBElement;

import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.TraversalUtil.CallbackImpl;
import org.docx4j.finders.SdtFinder;
import org.docx4j.finders.TcFinder;
import org.docx4j.model.PropertyResolver;
import org.docx4j.model.listnumbering.AbstractListNumberingDefinition;
import org.docx4j.model.listnumbering.Emulator;
import org.docx4j.model.listnumbering.Emulator.ResultTriple;
import org.docx4j.model.listnumbering.ListLevel;
import org.docx4j.model.listnumbering.ListNumberingDefinition;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.CTShd;
import org.docx4j.wml.Numbering;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.SdtBlock;
import org.docx4j.wml.SdtContentBlock;
import org.docx4j.wml.SdtElement;
import org.docx4j.wml.SdtPr;
import org.docx4j.wml.Tag;
import org.docx4j.wml.Tbl;
import org.docx4j.wml.Tc;
import org.docx4j.wml.PPrBase.NumPr;
import org.docx4j.wml.PPrBase.PBdr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;

/**
* Create list items in OL or UL (as appropriate).
*
* We can't just use a LinkedList (stack) of list contexts,
* which we push and pop, since we have to write complete
* XML elements (as opposed to opening and closing tags).
*
* So this means either extending org.docx4j.model.structure.jaxb
* beyond sections, or some other approach, like wrapping
* list items in a content control.  Let's try that.
*
* That's like org.docx4j.convert.out.common.preprocess.Containerization
*
* So we have a 2 step process:
*
* 1.  insert the content controls
*
* 2.  use an SdtWriter to turn these into UL or OL.
*
* This class does step 1. 
*
* Step 2 is implemented by ....;  it will only be used if
* property docx4j.Convert.Out.HTML.Lists is set.
*
* @author jharrop
*
*/
public class ListsToContentControls {
 
  public static Logger log = LoggerFactory.getLogger(ListsToContentControls.class);   
 
  public ListsToContentControls(WordprocessingMLPackage wmlPackage) {
    this.wmlPackage = wmlPackage;
    mainDocument = wmlPackage.getMainDocumentPart();
    this.ndp=mainDocument.getNumberingDefinitionsPart();
    stylesPart = wmlPackage.getMainDocumentPart().getStyleDefinitionsPart();
   
    propertyResolver = wmlPackage.getMainDocumentPart().getPropertyResolver();
  }
 
  private WordprocessingMLPackage wmlPackage;
  private MainDocumentPart mainDocument;
  private NumberingDefinitionsPart ndp;
  private StyleDefinitionsPart stylesPart;
 
  private PropertyResolver propertyResolver;
 
    private LinkedList<ListSpec> listStack = null;

  public static class ListSpec {
   
    ListSpec(BigInteger numId, BigInteger ilvl) {
      this.numId = numId;
      this.ilvl = ilvl;
    }
   
    BigInteger ilvl;
    BigInteger numId;
   
    SdtBlock sdtList = null;
   
   
  }
 
  public static void process(WordprocessingMLPackage wmlPackage) {
    //TODO: Convert to visitor behaviour here like TraversalUtil.visit with onlyBody = false
   
    ListsToContentControls lc = new ListsToContentControls(wmlPackage);
    lc.process();
  }
 
  private void process() {
    List<Object> content = null;
    List<Object> groupedContent = null;
   
    ///////////////////////////////////////////////
    // First, contents of existing content controls
    // .. find the content controls
    SdtFinder sdtFinder = new SdtFinder();
    new TraversalUtil(mainDocument.getContent(), sdtFinder);
   
    // .. loop through them
    for (SdtElement sdtEl : sdtFinder.getSdtList()) {
      content = sdtEl.getSdtContent().getContent();
      groupedContent = groupContent(content);
     
      if (groupedContent != null) {
        content.clear();
        content.addAll(groupedContent);
      }
     
    }
   
   
    ///////////////////////////////////////////////
    // Second, contents of table cells
    TcFinder tcFinder = new TcFinder();
    tcFinder.setTraverseTables(true);
    new TraversalUtil(mainDocument.getContent(), tcFinder);
    for (Tc tc : tcFinder.tcList) {
     
      content = tc.getContent();
      groupedContent = groupContent(content);
     
      if (groupedContent != null) {
        content.clear();
        content.addAll(groupedContent);
      }
     
    }
   
   
    ///////////////////////////////////////////////
    // Third, body level content
    content = mainDocument.getContent();
    groupedContent = groupContent(content);
   
    if (groupedContent != null) {
      content.clear();
      content.addAll(groupedContent);
    }
  }
 
  private void closeAllLists() {
    listStack.clear();
  }
 
  private void setTag(SdtBlock sdtList, BigInteger numId, BigInteger ilvl) {
   
    SdtPr sdtPr = new SdtPr();
    Tag tag = new Tag();
    sdtPr.setTag(tag);
   
    sdtList.setSdtPr(sdtPr);
   
    // Bullets = UL.  Work it out.
    ListNumberingDefinition lnd = ndp.getInstanceListDefinitions().get(numId.toString());
    if (lnd==null) {
      // Default to UL
      log.warn("Couldn't find instance list for numId " + numId);
      tag.setVal("HTML_ELEMENT=OL");
      return;
    }
   
    AbstractListNumberingDefinition ald = lnd.getAbstractListDefinition();
    if (ald==null) {
      // Default to UL
      log.warn("Couldn't find abstract list for instance list " + numId);
      tag.setVal("HTML_ELEMENT=OL");
      return;
    }
   
    ListLevel level = ald.getListLevels().get(ilvl.toString());
    if (level==null) {
      // Default to UL
      log.warn("Couldn't find level " + ilvl.toString() + " in instance list ");
      tag.setVal("HTML_ELEMENT=OL");
      return;     
    }
   
    if (level.IsBullet()) {
      tag.setVal("HTML_ELEMENT=UL");     
    } else {
      tag.setVal("HTML_ELEMENT=OL");           
    }
   
  }
 
  private List<Object> groupContent(List<Object> bodyElts) {
   
    // Reset state
    listStack = new LinkedList<ListSpec>();
   
    List<Object> resultElts = new ArrayList<Object>();
    P paragraph = null;
   
    for (Object o : bodyElts) {
     
      if (o instanceof JAXBElement) {
        o = ((JAXBElement)o).getValue();
      }

      /*
       * We can nest lists, but any time a bare table
       * or paragraph etc is encountered (ie anything not a list item),
       * we'll finish the lists.
       */
         
      if (o instanceof P) {
       
        paragraph = (P)o;       
        PPr ppr = propertyResolver.getEffectivePPr(paragraph.getPPr());
       
        NumPr numPr = ppr.getNumPr();
       
        if (numPr==null) {
          closeAllLists();
          resultElts.add(o);
          continue;
        }
       
        /* It is numbered.
         *
         * Cases:
         *
         * - no current list
         *
         * - same list, same level
         *
         * - same list, different level
         *
         * - different list
         *
         *
         * If a list item uses the same list but is a different
         * level, we'll push/pop levels as appropriate.
         *
         * This implies that when we start, we'll push levels
         * to get to the right starting level.
         *
         * If its a different list, we'll pop all levels, and
         * start again.
         *
         * TODO: consider what styling to attach to the OL|UL.
         * We should match the ImportXHTML behaviour.
         *
         */
       
        BigInteger numId = numPr.getNumId().getVal();
       
        BigInteger ilvl = null;
        if (numPr.getIlvl()==null) {
          ilvl = BigInteger.ZERO;
        } else {
          ilvl = numPr.getIlvl().getVal();
        }
       
        ListSpec listSpec = listStack.peek();
        if (listSpec==null
            || (numId!=null
                && !numId.equals(listSpec.numId))) {
          // new or different list
         
          // if its a different list, pop all levels
          if (listSpec!=null) {
            closeAllLists();           
          }
         
          // add appropriate levels
          for (int i=0; i<=ilvl.intValue(); i++) {
            listSpec = new ListSpec(numId, BigInteger.valueOf(i));
            listSpec.sdtList = new SdtBlock();
            setTag(listSpec.sdtList, numId, ilvl);     

            listSpec.sdtList.setSdtContent(new SdtContentBlock());
           
            if (listStack.peek()==null) {
              resultElts.add(listSpec.sdtList);
            } else {
              listStack.peek().sdtList.getSdtContent().getContent().add(listSpec.sdtList);
            }
            listStack.push(listSpec);
          }
         
          listSpec.sdtList.getSdtContent().getContent().add(paragraph);
        } else if (numId==null) {
          log.error("TODO: encountered null numId!");
          closeAllLists();
          resultElts.add(o);
          continue
        } else // (numId.equals(listSpec.numId))
        {
          // same list
         
          if (ilvl.equals(listSpec.ilvl)) {
            // just add to it
          } else if (ilvl.compareTo(listSpec.ilvl)>0) {

            // deeper, so add levels
            for (int i=listSpec.ilvl.intValue(); i<ilvl.intValue(); i++) {
              listSpec = new ListSpec(numId, BigInteger.valueOf(i));
              listSpec.sdtList = new SdtBlock();
              setTag(listSpec.sdtList, numId, ilvl);     
             
              listSpec.sdtList.setSdtContent(new SdtContentBlock());
             
              if (listStack.peek()==null) {
                resultElts.add(listSpec.sdtList);
              } else {
                listStack.peek().sdtList.getSdtContent().getContent().add(listSpec.sdtList);
              }
              listStack.push(listSpec);
            }
           
          } else {
            System.out.println("popping");
            // shallower, so pop levels
            for (int i=listSpec.ilvl.intValue(); i>ilvl.intValue(); i--) {
              listStack.pop();
              listSpec = listStack.peek();
              System.out.println("popped!");
            }
           
          }
          listSpec.sdtList.getSdtContent().getContent().add(paragraph);                   
        }
       
       
      } else if (o instanceof Tbl) {
        closeAllLists();
        resultElts.add(o);
       
      } else {
        log.warn("TODO: handle " + o.getClass().getName());
        closeAllLists();
        resultElts.add(o);
      }
     
    }
    return resultElts;
 
 
   

}
TOP

Related Classes of org.docx4j.convert.out.html.ListsToContentControls

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.