/************************************************************************ * * ListStyleConverter.java * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Copyright: 2002-2008 by Henrik Just * * All Rights Reserved. * * Version 1.0 (2008-09-08) * */ package writer2latex.latex; import java.util.Hashtable; import writer2latex.util.*; import writer2latex.office.*; import writer2latex.latex.util.BeforeAfter; import writer2latex.latex.util.Context; /* This class creates LaTeX code from OOo list styles */ public class ListStyleConverter extends StyleConverter { boolean bNeedSaveEnumCounter = false; private Hashtable listStyleLevelNames = new Hashtable(); /**
Constructs a new ListStyleConverter
.
Apply a list style to an ordered or unordered list.
*/ public void applyListStyle(String sStyleName, int nLevel, boolean bOrdered, boolean bContinue, BeforeAfter ba) { // Step 1. We may have a style map, this always takes precedence String sDisplayName = ofr.getListStyles().getDisplayName(sStyleName); if (config.getListStyleMap().contains(sDisplayName)) { ba.add(config.getListStyleMap().getBefore(sDisplayName), config.getListStyleMap().getAfter(sDisplayName)); return; } // Step 2: The list style may not exist, or the user wants to ignore it. // In this case we create default lists ListStyle style = ofr.getListStyle(sStyleName); if (style==null || config.formatting()<=LaTeXConfig.IGNORE_MOST) { if (nLevel<=4) { if (bOrdered) { ba.add("\\begin{enumerate}","\\end{enumerate}"); } else { ba.add("\\begin{itemize}","\\end{itemize}"); } } return; } // Step 3: Export as default lists, but redefine labels if (config.formatting()==LaTeXConfig.CONVERT_BASIC) { if (nLevel==1) { if (!styleNames.containsName(getDisplayName(sStyleName))) { createListStyleLabels(sStyleName); } ba.add("\\liststyle"+styleNames.getExportName(getDisplayName(sStyleName))+"\n",""); } if (nLevel<=4) { String sCounterName = ((String[]) listStyleLevelNames.get(sStyleName))[nLevel]; if (bContinue && style.isNumber(nLevel)) { bNeedSaveEnumCounter = true; ba.add("\\setcounter{saveenum}{\\value{"+sCounterName+"}}\n",""); } if (bOrdered) { ba.add("\\begin{enumerate}","\\end{enumerate}"); } else { ba.add("\\begin{itemize}","\\end{itemize}"); } if (bContinue && style.isNumber(nLevel)) { ba.add("\n\\setcounter{"+sCounterName+"}{\\value{saveenum}}",""); } } return; } // Step 4: Export with formatting, as "Writer style" custom lists if (nLevel<=4) { // TODO: Max level should not be fixed if (!styleNames.containsName(getDisplayName(sStyleName))) { createListStyle(sStyleName); } String sTeXName="list"+styleNames.getExportName(getDisplayName(sStyleName)) +"level"+Misc.int2roman(nLevel); if (!bContinue && style.isNumber(nLevel)) { int nStartValue = Misc.getPosInteger(style.getLevelProperty(nLevel,XMLString.TEXT_START_VALUE),1)-1; ba.add("\\setcounter{"+sTeXName+"}{"+Integer.toString(nStartValue)+"}\n",""); } ba.add("\\begin{"+sTeXName+"}","\\end{"+sTeXName+"}"); } } /**Apply a list style to a list item.
*/ public void applyListItemStyle(String sStyleName, int nLevel, boolean bHeader, boolean bRestart, int nStartValue, BeforeAfter ba) { // Step 1. We may have a style map, this always takes precedence String sDisplayName = ofr.getListStyles().getDisplayName(sStyleName); if (config.getListItemStyleMap().contains(sDisplayName)) { ba.add(config.getListItemStyleMap().getBefore(sDisplayName), config.getListItemStyleMap().getAfter(sDisplayName)); return; } // Step 2: The list style may not exist, or the user wants to ignore it. // In this case we create default lists ListStyle style = ofr.getListStyle(sStyleName); if (style==null || config.formatting()<=LaTeXConfig.IGNORE_MOST) { if (nLevel<=4) { if (bHeader) { ba.add("\\item[] ",""); } else { ba.add("\\item ",""); } } return; } // Step 3: Export as default lists (with redefined labels) if (config.formatting()==LaTeXConfig.CONVERT_BASIC) { if (nLevel<=4) { if (bHeader) { ba.add("\\item[] ",""); } else if (bRestart && style.isNumber(nLevel)) { ba.add("\n\\setcounter{enum"+Misc.int2roman(nLevel) +"}{"+(nStartValue-1)+"}\n\\item ",""); } else { ba.add("\\item ",""); } } return; } // Step 4: Export with formatting, as "Writer style" custom lists if (nLevel<=4 && !bHeader) { // TODO: Max level should not be fixed String sTeXName="list"+styleNames.getExportName(getDisplayName(sStyleName)) +"level"+Misc.int2roman(nLevel); if (bRestart && style.isNumber(nLevel)) { ba.add("\\setcounter{"+sTeXName+"}{"+(nStartValue-1)+"}\n",""); } ba.add("\\item ",""); } } /**Create labels for default lists (enumerate/itemize) based on * a List Style */ private void createListStyleLabels(String sStyleName) { String sTeXName = styleNames.getExportName(getDisplayName(sStyleName)); declarations.append("\\newcommand\\liststyle") .append(sTeXName).append("{%").nl(); ListStyle style = ofr.getListStyle(sStyleName); int nEnum = 0; int nItem = 0; String sName[] = new String[5]; for (int i=1; i<=4; i++) { if (style.isNumber(i)) { sName[i]="enum"+Misc.int2roman(++nEnum); } else { sName[i]="item"+Misc.int2roman(++nItem); } } listStyleLevelNames.put(sStyleName, sName); createLabels(style, sName, 4, false, true, false, declarations); declarations.append("}").nl(); } /**
Create "Writer style" lists based on a List Style.
A list in writer is really a sequence of numbered paragraphs, so this is also how we implement it in LaTeX. The enivronment + redefined \item defines three hooks: \writerlistleftskip, \writerlistparindent, \writerlistlabel which are used by exported paragraph styles to apply numbering. */ private void createListStyle(String sStyleName) { ListStyle style = ofr.getListStyle(sStyleName); // Create labels String sTeXName = styleNames.getExportName(getDisplayName(sStyleName)); String[] sLevelName = new String[5]; for (int i=1; i<=4; i++) { sLevelName[i]="list"+sTeXName+"level"+Misc.int2roman(i); } createLabels(style,sLevelName,4,true,false,true,declarations); // Create environments for (int i=1; i<=4; i++) { String sSpaceBefore = getLength(style,i,XMLString.TEXT_SPACE_BEFORE); String sLabelWidth = getLength(style,i,XMLString.TEXT_MIN_LABEL_WIDTH); String sLabelDistance = getLength(style,i,XMLString.TEXT_MIN_LABEL_DISTANCE); String sTextAlign = style.getLevelStyleProperty(i,XMLString.FO_TEXT_ALIGN); String sAlignmentChar = "l"; // start (or left) is default if (sTextAlign!=null) { if ("end".equals(sTextAlign)) { sAlignmentChar="r"; } else if ("right".equals(sTextAlign)) { sAlignmentChar="r"; } else if ("center".equals(sTextAlign)) { sAlignmentChar="c"; } } declarations .append("\\newenvironment{") .append(sLevelName[i]).append("}{") .append("\\def\\writerlistleftskip{\\addtolength\\leftskip{") .append(Misc.add(sSpaceBefore,sLabelWidth)).append("}}") .append("\\def\\writerlistparindent{}") .append("\\def\\writerlistlabel{}"); // Redefine \item declarations .append("\\def\\item{") .append("\\def\\writerlistparindent{\\setlength\\parindent{") .append("-").append(sLabelWidth).append("}}") .append("\\def\\writerlistlabel{"); if (style.isNumber(i)) { declarations.append("\\stepcounter{") .append(sLevelName[i]).append("}"); } declarations .append("\\makebox[").append(sLabelWidth).append("][") .append(sAlignmentChar).append("]{") .append("\\label").append(sLevelName[i]).append("}") .append("\\hspace{").append(sLabelDistance).append("}") .append("\\writerlistremovelabel}}}{}").nl(); } } /**
Create LaTeX list labels from an OOo list style. Examples:
*Bullets:
*\newcommand\labelliststylei{\textbullet} * \newcommand\labelliststyleii{*} * \newcommand\labelliststyleiii{\textstylebullet{>}}*
Numbering:
*\newcounter{liststylei} * \newcounter{liststyleii}[liststylei] * \newcounter{liststyleiii}[liststyleii] * \renewcommand\theliststylei{\Roman{liststylei}} * \renewcommand\theliststyleii{\Roman{liststylei}.\arabic{liststyleii}} * \renewcommand\theliststyleiii{\alph{liststyleiii}} * \newcommand\labelliststylei{\textstylelabel{\theliststylei .}} * \newcommand\labelliststyleii{\textstylelabel{\theliststyleii .}} * \newcommand\labelliststyleiii{\textstylelabel{\theliststyleiii )}}* * @param
style
the OOo list style to use
* @param sName
an array of label basenames to use
* @param nMaxLevel
the highest level in this numbering
* @param bDeclareCounters
true if counters should be declared (they may
* exist already, eg. "section", "subsection"... or "enumi", "enumii"...
* @param bRenewLabels
true if labels should be defined with \renewcommand
* @param bUseTextStyle
true if labels should be formatted with the associated text style
* (rather than \newcommand).
* @param ldp
the LaTeXDocumentPortion
to add LaTeX code to.
*/
private void createLabels(ListStyle style, String[] sName, int nMaxLevel,
boolean bDeclareCounters, boolean bRenewLabels,
boolean bUseTextStyle, LaTeXDocumentPortion ldp) {
// Declare counters if required (eg. "\newcounter{countername1}[countername2]")
if (bDeclareCounters) {
int j = 0;
for (int i=1; i<=nMaxLevel; i++) {
if (style.isNumber(i)) {
ldp.append("\\newcounter{").append(sName[i]).append("}");
if (j>0) { ldp.append("[").append(sName[j]).append("]"); }
ldp.nl();
j = i;
}
}
}
// Create numbering for each level (eg. "\arabic{countername}")
String[] sNumFormat = new String[nMaxLevel+1];
for (int i=1; i<=nMaxLevel; i++) {
String s = numFormat(style.getLevelProperty(i,XMLString.STYLE_NUM_FORMAT));
if (s==null) { sNumFormat[i]=""; }
else { sNumFormat[i] = s + "{" + sName[i] + "}"; }
}
// Create numberings (ie. define "\thecountername"):
for (int i=1; i<=nMaxLevel; i++) {
if (style.isNumber(i)) {
ldp.append("\\renewcommand\\the").append(sName[i]).append("{");
int nLevels = Misc.getPosInteger(style.getLevelProperty(i,XMLString.TEXT_DISPLAY_LEVELS),1);
for (int j=i-nLevels+1; j