From 6c161688f7ca08942a12b453e32e3cbcb2c06121 Mon Sep 17 00:00:00 2001 From: Oliver Bolte Date: Thu, 13 Jul 2006 08:24:15 +0000 Subject: [PATCH] INTEGRATION: CWS latex (1.1.2); FILE ADDED 2006/04/06 14:09:04 sus 1.1.2.1: #i24813# Adding LaTeX and BibTeX filter --- .../latex/style/ParStyleConverter.java | 566 ++++++++++++++++++ 1 file changed, 566 insertions(+) create mode 100644 xmerge/source/writer2latex/source/writer2latex/latex/style/ParStyleConverter.java diff --git a/xmerge/source/writer2latex/source/writer2latex/latex/style/ParStyleConverter.java b/xmerge/source/writer2latex/source/writer2latex/latex/style/ParStyleConverter.java new file mode 100644 index 000000000000..e2d368f16412 --- /dev/null +++ b/xmerge/source/writer2latex/source/writer2latex/latex/style/ParStyleConverter.java @@ -0,0 +1,566 @@ +/************************************************************************ + * + * ParStyleConverter.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-2004 by Henrik Just + * + * All Rights Reserved. + * + * Version 0.3.3i (2004-12-28) + * + */ + +package writer2latex.latex.style; + +import java.util.Hashtable; + +import writer2latex.util.*; +import writer2latex.office.*; +import writer2latex.latex.LaTeXDocumentPortion; +import writer2latex.latex.HeadingMap; +import writer2latex.latex.ConverterPalette; +import writer2latex.latex.Context; + +/* This class creates LaTeX code from OOo paragraph styles + */ +public class ParStyleConverter extends StyleConverter { + private String[] sHeadingStyles = new String[11]; + + /**

Constructs a new ParStyleConverter.

+ */ + public ParStyleConverter(WriterStyleCollection wsc, Config config, + ConverterPalette palette) { + super(wsc,config,palette); + } + + public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) { + if (config.formatting()>=Config.CONVERT_MOST) { + // We typeset with \raggedbottom since OOo doesn't use rubber lengths + // TODO: Maybe turn vertical spacing from OOo into rubber lengths? + decl.append("\\raggedbottom").nl(); + } + + appendHeadingStyles(decl); + + if (config.formatting()>=Config.CONVERT_MOST) { + decl.append("% Paragraph styles").nl(); + // First default paragraph style + palette.getCharSc().applyDefaultFont(wsc.getDefaultParStyle(),decl); + super.appendDeclarations(pack,decl); + } + } + + /**

Use a paragraph style in LaTeX.

+ * @param sName the name of the text style + * @param ba a BeforeAfter to put code into + * @param context the current context. This method will use and update the formatting context + */ + public void applyParStyle(String sName, BeforeAfter ba, Context context) { + applyParStyle(sName,ba,context,true); + } + + private void applyParStyle(String sName, BeforeAfter ba, Context context, boolean bBreakInside) { + // No style specified? + if (sName==null) { return; } + + // Always end with a line break + ba.add("","\n"); + // Apply the style + if (!styleMap.contains(sName)) { createParStyle(sName); } + String sBefore = styleMap.getBefore(sName); + String sAfter = styleMap.getAfter(sName); + ba.add(sBefore,sAfter); + // Add line breaks inside? + if (bBreakInside && styleMap.getLineBreak(sName)) { + if (sBefore.length()>0) { ba.add("\n",""); } + if (sAfter.length()>0 && !"}".equals(sAfter)) { ba.add("","\n"); } + } + + // Register master page and update context + ParStyle style = wsc.getParStyle(sName); + if (style==null) { return; } + palette.getPageSc().collectMasterPage(style); + context.updateFormattingFromStyle(style); + context.setVerbatim(styleMap.getVerbatim(sName)); + } + + /**

Convert a paragraph style to LaTeX.

+ *

A soft style is declared in styleDeclarations as + * \newenvironment...

+ *

A hard style is used by applying LaTeX code directly

+ * @param sName the OOo name of the style + */ + private void createParStyle(String sName) { + // A paragraph style should always be created relative to main context + Context context = (Context) palette.getMainContext().clone(); + // The style may already be declared in the configuration: + StyleMap sm = config.getParStyleMap(); + if (sm.contains(sName)) { + styleMap.put(sName,sm.getBefore(sName),sm.getAfter(sName), + sm.getLineBreak(sName),sm.getVerbatim(sName)); + return; + } + // Does the style exist? + ParStyle style = wsc.getParStyle(sName); + if (style==null) { + styleMap.put(sName,"",""); + return; + } + // Convert the style! + switch (config.formatting()) { + case Config.CONVERT_MOST: + if (style.isAutomatic()) { + createAutomaticParStyle(style,context); + return; + } + case Config.CONVERT_ALL: + createSoftParStyle(style,context); + return; + case Config.CONVERT_BASIC: + case Config.IGNORE_MOST: + createSimpleParStyle(style,context); + return; + case Config.IGNORE_ALL: + default: + styleMap.put(sName,"",""); + } + } + + private void createAutomaticParStyle(ParStyle style, Context context) { + // Hard paragraph formatting from this style should be ignored + // (because the user wants to ignore hard paragraph formatting + // or there is a style map for the parent.) + BeforeAfter ba = new BeforeAfter(); + BeforeAfter baPar = new BeforeAfter(); + BeforeAfter baText = new BeforeAfter(); + + // Apply paragraph formatting from parent + // If parent is verbatim, this is all + String sParentName = style.getParentName(); + if (styleMap.getVerbatim(sParentName)) { + styleMap.put(style.getName(),styleMap.getBefore(sParentName),styleMap.getAfter(sParentName), + styleMap.getLineBreak(sParentName),styleMap.getVerbatim(sParentName)); + return; + } + applyParStyle(sParentName,baPar,context,false); + + // Apply hard formatting properties: + applyPageBreak(style,false,ba); + palette.getI18n().applyLanguage(style,true,false,baText); + palette.getCharSc().applyFont(style,true,false,baText,context); + + // Assemble the bits. If there is any hard character formatting + // we must group the contents. + if (baPar.isEmpty() && !baText.isEmpty()) { ba.add("{","}"); } + else { ba.add(baPar.getBefore(),baPar.getAfter()); } + ba.add(baText.getBefore(),baText.getAfter()); + boolean bLineBreak = styleMap.getLineBreak(sParentName); + if (!bLineBreak && !baText.isEmpty()) { ba.add(" ",""); } + styleMap.put(style.getName(),ba.getBefore(),ba.getAfter(),bLineBreak,false); + } + + private void createSimpleParStyle(ParStyle style, Context context) { + // Export character formatting + alignment only + if (style.isAutomatic() && config.getParStyleMap().contains(style.getParentName())) { + createAutomaticParStyle(style,context); + } + + BeforeAfter ba = new BeforeAfter(); + BeforeAfter baText = new BeforeAfter(); + + // Apply hard formatting attributes + // Note: Left justified text is exported as full justified text! + applyPageBreak(style,false,ba); + String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,true); + if ("center".equals(sTextAlign)) { baText.add("\\centering","\\par"); } + else if ("end".equals(sTextAlign)) { baText.add("\\raggedleft","\\par"); } + palette.getI18n().applyLanguage(style,true,true,baText); + palette.getCharSc().applyFont(style,true,true,baText,context); + + // Assemble the bits. If there is any hard character formatting + // or alignment we must group the contents. + if (!baText.isEmpty()) { ba.add("{","}"); } + ba.add(baText.getBefore(),baText.getAfter()); + styleMap.put(style.getName(),ba.getBefore(),ba.getAfter()); + } + + private void createSoftParStyle(ParStyle style, Context context) { + // This style should be converted to an enviroment, except if + // it's automatic and there is a config style map for the parent + if (style.isAutomatic() && config.getParStyleMap().contains(style.getParentName())) { + createAutomaticParStyle(style,context); + } + + BeforeAfter ba = new BeforeAfter(); + applyParProperties(style,ba); + ba.add("\\writerlistparindent\\writerlistleftskip",""); + palette.getI18n().applyLanguage(style,true,true,ba); + ba.add("\\leavevmode",""); + palette.getCharSc().applyNormalFont(ba); + palette.getCharSc().applyFont(style,true,true,ba,context); + ba.add("\\writerlistlabel",""); + ba.add("\\ignorespaces",""); + // Declare the paragraph style (\newenvironment) + String sTeXName = "style" + styleNames.getExportName(style.getName()); + styleMap.put(style.getName(),"\\begin{"+sTeXName+"}","\\end{"+sTeXName+"}"); + declarations.append("\\newenvironment{").append(sTeXName) + .append("}{").append(ba.getBefore()).append("}{") + .append(ba.getAfter()).append("}").nl(); + } + + /**

Use a paragraph style on a heading. If hard paragraph formatting + * is applied to a heading, page break and font is converted - other + * hard formatting is ignored. + *

This method also collects name of heading style and master page + * @param nLevel The level of this heading + * @param sStyleName the name of the paragraph style to use + * @param baPage a BeforeAfter to put page break code into + * @param baText a BeforeAfter to put character formatting code into + * @param context the current context. This method will use and update the formatting context + */ + public void applyHardHeadingStyle(int nLevel, String sStyleName, + BeforeAfter baPage, BeforeAfter baText, Context context) { + + // Get the style + ParStyle style = wsc.getParStyle(sStyleName); + if (style==null) { return; } + + // Register master page and heading style + palette.getPageSc().collectMasterPage(style); + if (sHeadingStyles[nLevel]==null) { + sHeadingStyles[nLevel] = style.isAutomatic() ? style.getParentName() : sStyleName; + } + + // Do conversion + if (style.isAutomatic()) { + applyPageBreak(style,false,baPage); + palette.getCharSc().applyHardCharFormatting(style,baText); + } + + // Update context + context.updateFormattingFromStyle(style); + } + + // utility method to get the font name from a char style + public String getFontName(String sStyleName) { + StyleWithProperties style = wsc.getParStyle(sStyleName); + if (style==null) { return null; } + String sName = style.getProperty(XMLString.STYLE_FONT_NAME); + if (sName==null) { return null; } + FontDeclaration fd = wsc.getFontDeclaration(sName); + if (fd==null) { return null; } + return fd.getProperty(XMLString.FO_FONT_FAMILY); + } + + /**

Apply page break properties from a style.

+ * @param style the paragraph style to use + * @param bInherit true if inheritance from parent style should be used + * @param ba a BeforeAfter to put code into + */ + public void applyPageBreak(ParStyle style, boolean bInherit, BeforeAfter ba) { + if (style==null) { return; } + if (style.isAutomatic() && config.ignoreHardPageBreaks()) { return; } + // A page break can be a simple page break before or after... + String s = style.getProperty(XMLString.FO_BREAK_BEFORE,bInherit); + if ("page".equals(s)) { ba.add("\\clearpage",""); } + s = style.getProperty(XMLString.FO_BREAK_AFTER,bInherit); + if ("page".equals(s)) { ba.add("","\\clearpage"); } + // ...or it can be a new master page + String sMasterPage = style.getMasterPageName(); + if (sMasterPage==null || sMasterPage.length()==0) { return; } + ba.add("\\clearpage",""); + palette.getPageSc().applyMasterPage(sMasterPage,ba); + } + + // Remaining methods are private helpers + + /**

Apply line spacing from a style.

+ * @param style the paragraph style to use + * @param ba a BeforeAfter to put code into + */ + private void applyLineSpacing(ParStyle style, BeforeAfter ba) { + if (style==null) { return; } + String sLineHeight = style.getProperty(XMLString.FO_LINE_HEIGHT); + if (sLineHeight==null || !sLineHeight.endsWith("%")) { return; } + float fPercent=Misc.getFloat(sLineHeight.substring(0,sLineHeight.length()-1),1); + ba.add("\\renewcommand\\baselinestretch{"+fPercent/120+"}",""); + } + + /**

Helper: Get a length property that + * defaults to 0cm. + */ + private String getLength(ParStyle style,String sProperty) { + String s = style.getAbsoluteProperty(sProperty); + if (s==null) { return "0cm"; } + else { return s; } + } + + /**

Helper: Create a horizontal border.

+ */ + private String createBorder(String sLeft, String sRight, String sTop, + String sHeight, String sColor) { + BeforeAfter baColor = new BeforeAfter(); + palette.getCharSc().applyThisColor(sColor,false,baColor); + return "{\\setlength\\parindent{0pt}\\setlength\\leftskip{" + sLeft + "}" + + "\\setlength\\baselineskip{0pt}\\setlength\\parskip{" + sHeight + "}" + + baColor.getBefore() + + "\\rule{\\textwidth-" + sLeft + "-" + sRight + "}{" + sHeight + "}" + + baColor.getAfter() + + "\\par}"; + } + + /**

Apply margin+alignment properties from a style.

+ * @param style the paragraph style to use + * @param ba a BeforeAfter to put code into + */ + private void applyMargins(ParStyle style, BeforeAfter ba) { + // Read padding/margin/indentation properties: + String sPaddingTop = getLength(style,XMLString.FO_PADDING_TOP); + String sPaddingBottom = getLength(style,XMLString.FO_PADDING_BOTTOM); + String sPaddingLeft = getLength(style,XMLString.FO_PADDING_LEFT); + String sPaddingRight = getLength(style,XMLString.FO_PADDING_RIGHT); + String sMarginTop = getLength(style,XMLString.FO_MARGIN_TOP); + String sMarginBottom = getLength(style,XMLString.FO_MARGIN_BOTTOM); + String sMarginLeft = getLength(style,XMLString.FO_MARGIN_LEFT); + String sMarginRight = getLength(style,XMLString.FO_MARGIN_RIGHT); + String sTextIndent; + if ("true".equals(style.getProperty(XMLString.STYLE_AUTO_TEXT_INDENT))) { + sTextIndent = "2em"; + } + else { + sTextIndent = getLength(style,XMLString.FO_TEXT_INDENT); + } + // Read alignment properties: + boolean bRaggedLeft = false; // add 1fil to \leftskip + boolean bRaggedRight = false; // add 1fil to \rightskip + boolean bParFill = false; // add 1fil to \parfillskip + String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN); + if ("center".equals(sTextAlign)) { + bRaggedLeft = true; bRaggedRight = true; // centered paragraph + } + else if ("start".equals(sTextAlign)) { + bRaggedRight = true; bParFill = true; // left aligned paragraph + } + else if ("end".equals(sTextAlign)) { + bRaggedLeft = true; // right aligned paragraph + } + else if (!"justify".equals(style.getProperty(XMLString.FO_TEXT_ALIGN_LAST))) { + bParFill = true; // justified paragraph with ragged last line + } + // Create formatting: + ba.add("\\setlength\\leftskip{"+sMarginLeft+(bRaggedLeft?" plus 1fil":"")+"}",""); + ba.add("\\setlength\\rightskip{"+sMarginRight+(bRaggedRight?" plus 1fil":"")+"}",""); + ba.add("\\setlength\\parindent{"+sTextIndent+"}",""); + ba.add("\\setlength\\parfillskip{"+(bParFill?"0pt plus 1fil":"0pt")+"}",""); + ba.add("\\setlength\\parskip{"+sMarginTop+"}","\\unskip\\vspace{"+sMarginBottom+"}"); + } + + private void applyAlignment(ParStyle style, boolean bIsSimple, boolean bInherit, BeforeAfter ba) { + if (bIsSimple || style==null) { return; } + String sTextAlign = style.getProperty(XMLString.FO_TEXT_ALIGN,bInherit); + if ("center".equals(sTextAlign)) { ba.add("\\centering",""); } + else if ("start".equals(sTextAlign)) { ba.add("\\raggedright",""); } + else if ("end".equals(sTextAlign)) { ba.add("\\raggedleft",""); } + } + + + /**

Apply all paragraph properties.

+ * @param style the paragraph style to use + * @param ba a BeforeAfter to put code into + */ + private void applyParProperties(ParStyle style, BeforeAfter ba) { + applyPageBreak(style,true,ba); + ba.add("","\\par"); + applyLineSpacing(style,ba); + applyMargins(style,ba); + } + + /**

Convert heading styles and outline numbering to LaTeX.

+ *

An array of stylenames to use is required: The OOo writer file format + * allows different paragraph styles to be applied to individual headings, + * so this is not included in the styles. + * LaTeX (and OOo Writer!) usually uses the same format for all headings.

+ * @param ldp the LaTeXDocumentPortion to add definitions to. + */ + // TODO: use method from ListStyleConverter to create labels + private void appendHeadingStyles(LaTeXDocumentPortion ldp) { + // The user may not want to convert the formatting of headings + if (config.formatting()<=Config.IGNORE_MOST) { return; } + + HeadingMap hm = config.getHeadingMap(); + + // OK, we are going to convert. First find the max level for headings + int nMaxLevel = 0; + for (int i=1; i<=5; i++) { if (sHeadingStyles[i]!=null) { nMaxLevel=i; } } + if (nMaxLevel==0) { return; } // no headings, nothing to do! + if (nMaxLevel>hm.getMaxLevel()) { nMaxLevel = hm.getMaxLevel(); } + + boolean bOnlyNum = config.formatting()==Config.CONVERT_BASIC; + if (bOnlyNum) { + ldp.append("% Outline numbering").nl(); + } + else { + ldp.append("% Headings and outline numbering").nl() + .append("\\makeatletter").nl(); + } + + // Paragraph style for headings: + if (!bOnlyNum) { + for (int i=1; i<=nMaxLevel; i++) { + if (sHeadingStyles[i]!=null) { + ParStyle style = wsc.getParStyle(sHeadingStyles[i]); + if (style!=null) { + BeforeAfter decl = new BeforeAfter(); + BeforeAfter comm = new BeforeAfter(); + + applyPageBreak(style,true,decl); + + palette.getCharSc().applyNormalFont(decl); + palette.getCharSc().applyFont(style,true,true,decl,new Context()); + applyAlignment(style,false,true,decl); + + palette.getI18n().applyLanguage(style,false,true,comm); + palette.getCharSc().applyFontEffects(style,true,comm); + + String sMarginTop = getLength(style,XMLString.FO_MARGIN_TOP); + String sMarginBottom = getLength(style,XMLString.FO_MARGIN_BOTTOM); + String sMarginLeft = getLength(style,XMLString.FO_MARGIN_LEFT); + + String sSecName = hm.getName(i); + if (!comm.isEmpty()) { // have to create a cs for this heading + ldp.append("\\newcommand\\cs").append(sSecName).append("[1]{") + .append(comm.getBefore()).append("#1").append(comm.getAfter()) + .append("}").nl(); + } + ldp.append("\\renewcommand\\").append(sSecName) + .append("{\\@startsection{").append(sSecName).append("}{"+hm.getLevel(i)) + .append("}{"+sMarginLeft+"}{"); + // Suppress indentation after heading? currently not.. + // ldp.append("-"); + ldp.append(sMarginTop) + .append("}{").append(sMarginBottom).append("}{"); + // Note: decl.getAfter() may include a page break after, which we ignore + ldp.append(decl.getBefore()); + if (!comm.isEmpty()) { + ldp.append("\\cs").append(sSecName); + } + ldp.append("}}").nl(); + } + } + } + } + + // redefine formatting of section counters + // simplified if the user wants to ignore formatting + if (!bOnlyNum) { + ldp.append("\\renewcommand\\@seccntformat[1]{") + .append("\\csname @textstyle#1\\endcsname{\\csname the#1\\endcsname}") + .append("\\csname @distance#1\\endcsname}").nl(); + } + + // Collect numbering styles and set secnumdepth + int nSecnumdepth = nMaxLevel; + ListStyle outline = wsc.getOutlineStyle(); + String[] sNumFormat = new String[6]; + for (int i=nMaxLevel; i>=1; i--) { + sNumFormat[i] = ListStyleConverter.numFormat(outline.getLevelProperty(i, + XMLString.STYLE_NUM_FORMAT)); + if (sNumFormat[i]==null || "".equals(sNumFormat[i])) { + nSecnumdepth = i-1; + } + } + ldp.append("\\setcounter{secnumdepth}{"+nSecnumdepth+"}").nl(); + + for (int i=1; i<=nMaxLevel; i++) { + if (sNumFormat[i]==null || "".equals(sNumFormat[i])) { + // no numbering at this level + if (!bOnlyNum) { + ldp.append("\\newcommand\\@distance") + .append(hm.getName(i)).append("{}").nl() + .append("\\newcommand\\@textstyle") + .append(hm.getName(i)).append("[1]{#1}").nl(); + } + } + else { + if (!bOnlyNum) { + // Distance between label and text: + String sDistance = outline.getLevelProperty(i,XMLString.TEXT_MIN_LABEL_DISTANCE); + ldp.append("\\newcommand\\@distance") + .append(hm.getName(i)).append("{"); + if (sDistance!=null) { + ldp.append("\\hspace{").append(sDistance).append("{"); + } + ldp.append("}").nl(); + // Textstyle to use for label: + String sStyleName = outline.getLevelProperty(i,XMLString.TEXT_STYLE_NAME); + BeforeAfter baText = new BeforeAfter(); + if (!bOnlyNum) {palette.getCharSc().applyTextStyle(sStyleName,baText,new Context()); } + ldp.append("\\newcommand\\@textstyle") + .append(hm.getName(i)).append("[1]{") + .append(baText.getBefore()) + .append("#1") + .append(baText.getAfter()) + .append("}").nl(); + } + + // The label: + String sPrefix = outline.getLevelProperty(i,XMLString.STYLE_NUM_PREFIX); + String sSuffix = outline.getLevelProperty(i,XMLString.STYLE_NUM_SUFFIX); + int nLevels = Misc.getPosInteger(outline.getLevelProperty(i, + XMLString.TEXT_DISPLAY_LEVELS),1); + ldp.append("\\renewcommand\\the") + .append(hm.getName(i)) + .append("{"); + StringBuffer labelbuf = new StringBuffer(); + if (sPrefix!=null) { labelbuf.append(sPrefix); } + for (int j=i-nLevels+1; j