More math and TexMaths work
git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@160 f0f2a975-2e09-46c8-9428-3b39399b9f3c
This commit is contained in:
parent
79ae252419
commit
3dff4f20b4
15 changed files with 514 additions and 525 deletions
|
@ -16,11 +16,11 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
* Copyright: 2002-2012 by Henrik Just
|
||||
* Copyright: 2002-2014 by Henrik Just
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Version 1.2 (2012-02-26)
|
||||
* Version 1.4 (2014-08-10)
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -80,7 +80,7 @@ public final class ConverterPalette extends ConverterBase {
|
|||
private InlineConverter inlineCv;
|
||||
private FieldConverter fieldCv;
|
||||
private DrawConverter drawCv;
|
||||
private MathmlConverter mathmlCv;
|
||||
private MathConverter mathCv;
|
||||
private Info info;
|
||||
|
||||
// Constructor
|
||||
|
@ -117,7 +117,7 @@ public final class ConverterPalette extends ConverterBase {
|
|||
public InlineConverter getInlineCv() { return inlineCv; }
|
||||
public FieldConverter getFieldCv() { return fieldCv; }
|
||||
public DrawConverter getDrawCv() { return drawCv; }
|
||||
public MathmlConverter getMathmlCv() { return mathmlCv; }
|
||||
public MathConverter getMathCv() { return mathCv; }
|
||||
public Info getInfo() { return info; }
|
||||
|
||||
|
||||
|
@ -172,7 +172,7 @@ public final class ConverterPalette extends ConverterBase {
|
|||
inlineCv = new InlineConverter(ofr,config,this);
|
||||
fieldCv = new FieldConverter(ofr,config,this);
|
||||
drawCv = new DrawConverter(ofr,config,this);
|
||||
mathmlCv = new MathmlConverter(ofr,config,this);
|
||||
mathCv = new MathConverter(ofr,config,this);
|
||||
info = new Info(ofr,config,this);
|
||||
|
||||
// Create master document and add this
|
||||
|
@ -223,7 +223,7 @@ public final class ConverterPalette extends ConverterBase {
|
|||
inlineCv.appendDeclarations(packages,declarations);
|
||||
fieldCv.appendDeclarations(packages,declarations);
|
||||
drawCv.appendDeclarations(packages,declarations);
|
||||
mathmlCv.appendDeclarations(packages,declarations);
|
||||
mathCv.appendDeclarations(packages,declarations);
|
||||
|
||||
// Add custom preamble
|
||||
String sCustomPreamble = config.getCustomPreamble();
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Version 1.4 (2014-08-06)
|
||||
* Version 1.4 (2014-08-11)
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -31,17 +31,13 @@ import java.util.Stack;
|
|||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
//import org.w3c.dom.Node;
|
||||
|
||||
|
||||
import writer2latex.latex.util.BeforeAfter;
|
||||
import writer2latex.latex.util.Context;
|
||||
//import writer2latex.office.ImageLoader;
|
||||
import writer2latex.office.EmbeddedObject;
|
||||
import writer2latex.office.EmbeddedXMLObject;
|
||||
import writer2latex.office.MIMETypes;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.CSVList;
|
||||
import writer2latex.util.Misc;
|
||||
|
@ -53,9 +49,8 @@ import writer2latex.xmerge.BinaryGraphicsDocument;
|
|||
public class DrawConverter extends ConverterHelper {
|
||||
|
||||
private boolean bNeedGraphicx = false;
|
||||
private boolean bNeedOOoLaTeXPreamble = false;
|
||||
|
||||
// Keep track of floating frames (images, textboxes...)
|
||||
// Keep track of floating frames (images, text boxes...)
|
||||
private Stack<LinkedList<Element>> floatingFramesStack = new Stack<LinkedList<Element>>();
|
||||
|
||||
private Element getFrame(Element onode) {
|
||||
|
@ -76,17 +71,6 @@ public class DrawConverter extends ConverterHelper {
|
|||
else if (config.getBackend()==LaTeXConfig.DVIPS) pack.append("[dvips]");
|
||||
pack.append("{graphicx}").nl();
|
||||
}
|
||||
if (bNeedOOoLaTeXPreamble) {
|
||||
// The preamble may be stored in the description
|
||||
String sDescription = palette.getMetaData().getDescription();
|
||||
int nStart = sDescription.indexOf("%%% OOoLatex Preamble %%%%%%%%%%%%%%");
|
||||
int nEnd = sDescription.indexOf("%%% End OOoLatex Preamble %%%%%%%%%%%%");
|
||||
if (nStart>-1 && nEnd>nStart) {
|
||||
decl.append("% OOoLaTeX preamble").nl()
|
||||
.append(sDescription.substring(nStart+37,nEnd));
|
||||
}
|
||||
// TODO: Otherwise try the user settings...
|
||||
}
|
||||
}
|
||||
|
||||
public void handleCaption(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
|
@ -129,25 +113,16 @@ public class DrawConverter extends ConverterHelper {
|
|||
palette.getFieldCv().handleAnchor(node,ldp,oc);
|
||||
}
|
||||
else if (sName.equals(XMLString.DRAW_FRAME)) {
|
||||
Element equation = palette.getTexMathsEquation(node);
|
||||
if (equation!=null) {
|
||||
palette.getMathmlCv().handleTexMathsEquation(equation,ldp,oc);
|
||||
}
|
||||
else {
|
||||
if (!palette.getMathCv().handleTexMathsEquation(node,ldp)) {
|
||||
// OpenDocument: Get the actual draw element in the frame
|
||||
handleDrawElement(Misc.getFirstChildElement(node),ldp,oc);
|
||||
}
|
||||
}
|
||||
else if (sName.equals(XMLString.DRAW_G)) {
|
||||
Element equation = palette.getTexMathsEquation(node);
|
||||
if (equation!=null) {
|
||||
palette.getMathmlCv().handleTexMathsEquation(equation,ldp,oc);
|
||||
}
|
||||
else {
|
||||
if (!palette.getMathCv().handleTexMathsEquation(node,ldp)) {
|
||||
// Shapes are currently not supported
|
||||
ldp.append("[Warning: Draw object ignored]");
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// Other drawing objects are currently not supported
|
||||
|
@ -159,6 +134,7 @@ public class DrawConverter extends ConverterHelper {
|
|||
// handle draw:object elements (OOo objects such as Chart, Math,...)
|
||||
|
||||
private void handleDrawObject(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
|
||||
String sHref = Misc.getAttribute(node,XMLString.XLINK_HREF);
|
||||
|
||||
if (sHref!=null) { // Embedded object in package or linked object
|
||||
|
@ -169,13 +145,13 @@ public class DrawConverter extends ConverterHelper {
|
|||
if (object!=null) {
|
||||
if (MIMETypes.MATH.equals(object.getType()) || MIMETypes.ODF.equals(object.getType())) { // Formula!
|
||||
try {
|
||||
Document settings = ((EmbeddedXMLObject) object).getSettingsDOM();
|
||||
Element settings = ((EmbeddedXMLObject) object).getSettingsDOM().getDocumentElement();
|
||||
Document formuladoc = ((EmbeddedXMLObject) object).getContentDOM();
|
||||
Element formula = Misc.getChildByTagName(formuladoc,XMLString.MATH); // Since OOo3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH);
|
||||
}
|
||||
String sLaTeX = palette.getMathmlCv().convert(settings,formula);
|
||||
String sLaTeX = palette.getMathCv().convert(settings,formula);
|
||||
if (!" ".equals(sLaTeX)) { // ignore empty formulas
|
||||
ldp.append(" $")
|
||||
.append(sLaTeX)
|
||||
|
@ -214,7 +190,7 @@ public class DrawConverter extends ConverterHelper {
|
|||
}
|
||||
if (formula!=null) {
|
||||
ldp.append(" $")
|
||||
.append(palette.getMathmlCv().convert(null,formula))
|
||||
.append(palette.getMathCv().convert(null,formula))
|
||||
.append("$");
|
||||
if (Character.isLetterOrDigit(OfficeReader.getNextChar(node))) { ldp.append(" "); }
|
||||
}
|
||||
|
@ -233,7 +209,6 @@ public class DrawConverter extends ConverterHelper {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
@ -288,47 +263,6 @@ public class DrawConverter extends ConverterHelper {
|
|||
String sName = frame.getAttribute(XMLString.DRAW_NAME);
|
||||
palette.getFieldCv().addTarget(sName,"|graphic",ldp);
|
||||
String sAnchor = frame.getAttribute(XMLString.TEXT_ANCHOR_TYPE);
|
||||
|
||||
// TODO: Recognize Jex equations (needs further testing of Jex)
|
||||
/*Element desc = Misc.getChildByTagName(frame,XMLString.SVG_DESC);
|
||||
if (desc!=null) {
|
||||
String sDesc = Misc.getPCDATA(desc);
|
||||
if (sDesc.startsWith("jex149$tex={") && sDesc.endsWith("}")) {
|
||||
String sTeX = sDesc.substring(12,sDesc.length()-1);
|
||||
if (sTeX.length()>0) {
|
||||
// Succesfully extracted Jex equation!
|
||||
ldp.append("$"+sTeX+"$");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Recognize OOoLaTeX equation
|
||||
// The LaTeX code is embedded in a custom style attribute:
|
||||
StyleWithProperties style = ofr.getFrameStyle(
|
||||
Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME));
|
||||
if (style!=null) {
|
||||
String sOOoLaTeX = style.getProperty("OOoLatexArgs");
|
||||
// The content of the attribute is <point size><paragraph sign><mode><paragraph sign><TeX code>
|
||||
int n=0;
|
||||
if (sOOoLaTeX!=null) {
|
||||
if ((n=sOOoLaTeX.indexOf("\u00A7display\u00A7"))>-1) {
|
||||
ldp.append("\\[").append(sOOoLaTeX.substring(n+9)).append("\\]");
|
||||
bNeedOOoLaTeXPreamble = true;
|
||||
return;
|
||||
}
|
||||
else if ((n=sOOoLaTeX.indexOf("\u00A7inline\u00A7"))>-1) {
|
||||
ldp.append("$").append(sOOoLaTeX.substring(n+8)).append("$");
|
||||
bNeedOOoLaTeXPreamble = true;
|
||||
return;
|
||||
}
|
||||
else if ((n=sOOoLaTeX.indexOf("\u00A7text\u00A7"))>-1) {
|
||||
ldp.append(sOOoLaTeX.substring(n+6));
|
||||
bNeedOOoLaTeXPreamble = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (oc.isInFrame() || "as-char".equals(sAnchor)) {
|
||||
if ("as-char".equals(sAnchor)) {
|
||||
|
|
392
source/java/writer2latex/latex/MathConverter.java
Normal file
392
source/java/writer2latex/latex/MathConverter.java
Normal file
|
@ -0,0 +1,392 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* MathConverter.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-2014 by Henrik Just
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Version 1.4 (2014-08-13)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import writer2latex.base.ConverterBase.TexMathsStyle;
|
||||
import writer2latex.office.EmbeddedObject;
|
||||
import writer2latex.office.EmbeddedXMLObject;
|
||||
import writer2latex.office.MIMETypes;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.StyleWithProperties;
|
||||
import writer2latex.office.TableReader;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/**
|
||||
* This ConverterHelper converts mathematical content to LaTeX.
|
||||
* It works slightly different than the other helpers: A number of elements may or may not
|
||||
* have content that should be converted to math. Thus the methods offered first examines
|
||||
* the content. If it turns out to be a mathematical formula, it is converted. Otherwise
|
||||
* nothing is done, and the method returns false.
|
||||
* Mathematical content may be MathML (with StarMath annotation), TexMaths or (the now obsolete) OOoLaTeX
|
||||
*/
|
||||
public final class MathConverter extends ConverterHelper {
|
||||
|
||||
private StarMathConverter smc;
|
||||
|
||||
private boolean bContainsFormulas = false;
|
||||
private boolean bAddParAfterDisplay = false;
|
||||
|
||||
private boolean bNeedOOoLaTeXPreamble = false;
|
||||
|
||||
private Element theEquation = null;
|
||||
private Element theSequence = null;
|
||||
|
||||
public MathConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
smc = new StarMathConverter(palette.getI18n(),config);
|
||||
bAddParAfterDisplay = config.formatting()>=LaTeXConfig.CONVERT_MOST;
|
||||
}
|
||||
|
||||
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
if (bContainsFormulas) {
|
||||
if (config.useOoomath()) {
|
||||
pack.append("\\usepackage{ooomath}").nl();
|
||||
}
|
||||
else {
|
||||
smc.appendDeclarations(pack,decl);
|
||||
}
|
||||
}
|
||||
if (bNeedOOoLaTeXPreamble) {
|
||||
// The preamble may be stored in the description
|
||||
String sDescription = palette.getMetaData().getDescription();
|
||||
int nStart = sDescription.indexOf("%%% OOoLatex Preamble %%%%%%%%%%%%%%");
|
||||
int nEnd = sDescription.indexOf("%%% End OOoLatex Preamble %%%%%%%%%%%%");
|
||||
if (nStart>-1 && nEnd>nStart) {
|
||||
decl.append("% OOoLaTeX preamble").nl()
|
||||
.append(sDescription.substring(nStart+37,nEnd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: Replace with a method "handleEquation"
|
||||
public String convert(Element settings, Element formula) {
|
||||
// TODO: Use settings to determine display mode/text mode
|
||||
// formula must be a math:math node
|
||||
// First try to find a StarMath annotation
|
||||
Node semantics = Misc.getChildByTagName(formula,XMLString.SEMANTICS); // Since OOo 3.2
|
||||
if (semantics==null) {
|
||||
semantics = Misc.getChildByTagName(formula,XMLString.MATH_SEMANTICS);
|
||||
}
|
||||
if (semantics!=null) {
|
||||
Node annotation = Misc.getChildByTagName(semantics,XMLString.ANNOTATION); // Since OOo 3.2
|
||||
if (annotation==null) {
|
||||
annotation = Misc.getChildByTagName(semantics,XMLString.MATH_ANNOTATION);
|
||||
}
|
||||
if (annotation!=null) {
|
||||
String sStarMath = "";
|
||||
if (annotation.hasChildNodes()) {
|
||||
NodeList anl = annotation.getChildNodes();
|
||||
int nLen = anl.getLength();
|
||||
for (int i=0; i<nLen; i++) {
|
||||
if (anl.item(i).getNodeType() == Node.TEXT_NODE) {
|
||||
sStarMath+=anl.item(i).getNodeValue();
|
||||
}
|
||||
}
|
||||
bContainsFormulas = true;
|
||||
return smc.convert(sStarMath);
|
||||
}
|
||||
}
|
||||
}
|
||||
// No annotation was found. In this case we should convert the mathml,
|
||||
// but currently we ignore the problem.
|
||||
// TODO: Investigate if Vasil I. Yaroshevich's MathML->LaTeX
|
||||
// XSL transformation could be used here. (Potential problem:
|
||||
// OOo uses MathML 1.01, not MathML 2)
|
||||
if (formula.hasChildNodes()) {
|
||||
return "\\text{Warning: No StarMath annotation}";
|
||||
}
|
||||
else { // empty formula
|
||||
return " ";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Try to convert a draw:frame or draw:g element as an (inline) TexMaths or OOoLaTeX equation
|
||||
*
|
||||
* @param the element containing the equation (draw:frame or draw:g)
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
*
|
||||
* @return true if this elements happen to be a TexMaths equation, otherwise false
|
||||
*/
|
||||
public boolean handleTexMathsEquation(Element node, LaTeXDocumentPortion ldp) {
|
||||
String sLaTeX = null;
|
||||
Element equation = palette.getTexMathsEquation(node);
|
||||
if (equation!=null) {
|
||||
sLaTeX = Misc.getPCDATA(equation);
|
||||
}
|
||||
else { // Try OOoLaTeX
|
||||
// The LaTeX code is embedded in a custom style attribute:
|
||||
StyleWithProperties style = ofr.getFrameStyle(Misc.getAttribute(node, XMLString.DRAW_STYLE_NAME));
|
||||
if (style!=null) {
|
||||
sLaTeX = style.getProperty("OOoLatexArgs");
|
||||
}
|
||||
}
|
||||
if (sLaTeX!=null) {
|
||||
// Format is <point size>X<mode>X<TeX code>X<format>X<resolution>X<transparency>
|
||||
// where X is a paragraph sign
|
||||
switch (palette.getTexMathsStyle(sLaTeX)) {
|
||||
case inline:
|
||||
ldp.append("$").append(palette.getTexMathsEquation(sLaTeX)).append("$");
|
||||
break;
|
||||
case display:
|
||||
ldp.append("$\\displaystyle ").append(palette.getTexMathsEquation(sLaTeX)).append("$");
|
||||
break;
|
||||
case latex:
|
||||
ldp.append(palette.getTexMathsEquation(sLaTeX));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Try to convert a table as a display equation:
|
||||
* A 1 row by 2 columns table in which each cell contains exactly one paragraph,
|
||||
* the left cell contains exactly one formula and the right cell contains exactly
|
||||
* one sequence number is treated as a (numbered) display equation.
|
||||
* This happens to coincide with the AutoText provided with OOo Writer :-)
|
||||
* @param table the table reader
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @return true if the conversion was successful, false if the table
|
||||
* did not represent a display equation
|
||||
*/
|
||||
public boolean handleDisplayEquation(TableReader table, LaTeXDocumentPortion ldp) {
|
||||
if (table.getRowCount()==1 && table.getColCount()==2 &&
|
||||
OfficeReader.isSingleParagraph(table.getCell(0, 0)) && OfficeReader.isSingleParagraph(table.getCell(0, 1)) ) {
|
||||
// Table of the desired form
|
||||
if (parseDisplayEquation(Misc.getFirstChildElement(table.getCell(0, 0))) && theEquation!=null && theSequence==null) {
|
||||
// Found equation in first cell
|
||||
Element myEquation = theEquation;
|
||||
if (parseDisplayEquation(Misc.getFirstChildElement(table.getCell(0, 1))) && theEquation==null && theSequence!=null) {
|
||||
// Found sequence in second cell
|
||||
handleDisplayEquation(myEquation, theSequence, ldp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**Try to convert a paragraph as a display equation:
|
||||
* A paragraph which contains exactly one formula + at most one sequence
|
||||
* number is treated as a display equation. Other content must be brackets
|
||||
* or whitespace (possibly with formatting).
|
||||
* @param node the paragraph
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @return true if the conversion was successful, false if the paragraph
|
||||
* did not contain a display equation
|
||||
*/
|
||||
public boolean handleDisplayEquation(Element node, LaTeXDocumentPortion ldp) {
|
||||
if (parseDisplayEquation(node) && theEquation!=null) {
|
||||
handleDisplayEquation(theEquation, theSequence, ldp);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDisplayEquation(Element equation, Element sequence, LaTeXDocumentPortion ldp) {
|
||||
boolean bTexMaths = equation.getTagName().equals(XMLString.SVG_DESC);
|
||||
TexMathsStyle style = TexMathsStyle.inline;
|
||||
String sLaTeX;
|
||||
if (bTexMaths) {
|
||||
// TeXMaths equation
|
||||
sLaTeX = palette.getTexMathsEquation(Misc.getPCDATA(equation));
|
||||
style = palette.getTexMathsStyle(Misc.getPCDATA(equation));
|
||||
}
|
||||
else {
|
||||
// MathML equation
|
||||
sLaTeX = convert(null,equation);
|
||||
}
|
||||
if (!" ".equals(sLaTeX)) { // ignore empty formulas
|
||||
if (!bTexMaths || style!=TexMathsStyle.latex) {
|
||||
if (sequence!=null) {
|
||||
// Numbered equation
|
||||
ldp.append("\\begin{equation}");
|
||||
palette.getFieldCv().handleSequenceLabel(sequence,ldp);
|
||||
if (bTexMaths && style==TexMathsStyle.inline) {
|
||||
ldp.append("\\textstyle ");
|
||||
}
|
||||
ldp.nl()
|
||||
.append(sLaTeX).nl()
|
||||
.append("\\end{equation}").nl();
|
||||
}
|
||||
else {
|
||||
// Unnumbered equation
|
||||
ldp.append("\\begin{equation*}");
|
||||
if (bTexMaths && style==TexMathsStyle.inline) {
|
||||
ldp.append("\\textstyle ");
|
||||
}
|
||||
ldp.nl()
|
||||
.append(sLaTeX).nl()
|
||||
.append("\\end{equation*}").nl();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ldp.append(sLaTeX).nl();
|
||||
}
|
||||
if (bAddParAfterDisplay) { ldp.nl(); }
|
||||
}
|
||||
}
|
||||
|
||||
/** Determine whether or not a paragraph contains a display equation.
|
||||
* A paragraph is a display equation if it contains a single formula and no text content except whitespace
|
||||
* and an optional sequence number which may be in brackets.
|
||||
* As a side effect, this method keeps a reference to the equation and the sequence number
|
||||
*
|
||||
* @param node the paragraph
|
||||
* @return true if this is a display equation
|
||||
*/
|
||||
public boolean parseDisplayEquation(Node node) {
|
||||
theEquation = null;
|
||||
theSequence = null;
|
||||
return doParseDisplayEquation(node);
|
||||
}
|
||||
|
||||
private boolean doParseDisplayEquation(Node node) {
|
||||
Node child = node.getFirstChild();
|
||||
while (child!=null) {
|
||||
if (Misc.isElement(child)) {
|
||||
Element elm = (Element) child;
|
||||
String sName = elm.getTagName();
|
||||
// First check for MathML or TexMaths equation
|
||||
Element equation = getMathmlEquation(elm);
|
||||
if (equation==null) {
|
||||
equation = palette.getTexMathsEquation(elm);
|
||||
}
|
||||
|
||||
if (equation!=null) {
|
||||
if (theEquation==null) {
|
||||
theEquation = equation;
|
||||
}
|
||||
else { // two or more equations -> not a display
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (XMLString.TEXT_SEQUENCE.equals(sName)) {
|
||||
if (theSequence==null) {
|
||||
theSequence = elm;
|
||||
}
|
||||
else { // two sequence numbers -> not a display
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (XMLString.TEXT_SPAN.equals(sName)) {
|
||||
if (!doParseDisplayEquation(child)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (XMLString.TEXT_S.equals(sName)) {
|
||||
// Spaces are allowed
|
||||
}
|
||||
else if (XMLString.TEXT_TAB.equals(sName)) {
|
||||
// Tab stops are allowed
|
||||
}
|
||||
else if (XMLString.TEXT_TAB_STOP.equals(sName)) { // old
|
||||
// Tab stops are allowed
|
||||
}
|
||||
else if (XMLString.TEXT_SOFT_PAGE_BREAK.equals(sName)) { // since ODF 1.1
|
||||
// Soft page breaks are allowed
|
||||
}
|
||||
else {
|
||||
// Other elements -> not a display
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (Misc.isText(child)) {
|
||||
String s = child.getNodeValue();
|
||||
int nLen = s.length();
|
||||
for (int i=0; i<nLen; i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c!='(' && c!=')' && c!='[' && c!=']' && c!='{' && c!='}' && c!=' ' && c!='\u00A0') {
|
||||
// Characters except brackets and whitespace -> not a display
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get a MathML formula from a draw:frame
|
||||
*
|
||||
* @param node the draw:frame
|
||||
* @return the MathML element, or null if this is not a MathML formula
|
||||
*/
|
||||
public Element getMathmlEquation(Element node) {
|
||||
if (node.getTagName().equals(XMLString.DRAW_FRAME)) {
|
||||
node=Misc.getFirstChildElement(node);
|
||||
}
|
||||
|
||||
String sHref = Misc.getAttribute(node,XMLString.XLINK_HREF);
|
||||
|
||||
if (sHref!=null) { // Embedded object in package or linked object
|
||||
if (ofr.isInPackage(sHref)) { // Embedded object in package
|
||||
if (sHref.startsWith("#")) { sHref=sHref.substring(1); }
|
||||
if (sHref.startsWith("./")) { sHref=sHref.substring(2); }
|
||||
EmbeddedObject object = palette.getEmbeddedObject(sHref);
|
||||
if (object!=null) {
|
||||
if (MIMETypes.MATH.equals(object.getType()) || MIMETypes.ODF.equals(object.getType())) { // Formula!
|
||||
try {
|
||||
Document formuladoc = ((EmbeddedXMLObject) object).getContentDOM();
|
||||
Element formula = Misc.getChildByTagName(formuladoc,XMLString.MATH); // Since OOo 3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH);
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
catch (org.xml.sax.SAXException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (java.io.IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // flat XML, object is contained in node
|
||||
Element formula = Misc.getChildByTagName(node,XMLString.MATH); // Since OOo 3.2
|
||||
if (formula==null) {
|
||||
formula = Misc.getChildByTagName(node,XMLString.MATH_MATH);
|
||||
}
|
||||
return formula;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,249 +0,0 @@
|
|||
/************************************************************************
|
||||
*
|
||||
* MathmlConverter.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-2014 by Henrik Just
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Version 1.4 (2014-08-08)
|
||||
*
|
||||
*/
|
||||
|
||||
package writer2latex.latex;
|
||||
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import writer2latex.latex.util.Context;
|
||||
import writer2latex.office.OfficeReader;
|
||||
import writer2latex.office.TableReader;
|
||||
import writer2latex.office.XMLString;
|
||||
import writer2latex.util.Misc;
|
||||
|
||||
/**
|
||||
* This class converts MathML nodes to LaTeX.
|
||||
* The class name is slightly misleading:
|
||||
* It only converts the StarMath annotation, if available
|
||||
* and it also converts TexMaths formulas
|
||||
*/
|
||||
public final class MathmlConverter extends ConverterHelper {
|
||||
|
||||
private enum TexMathsStyle {inline, display, latex};
|
||||
|
||||
private StarMathConverter smc;
|
||||
|
||||
private boolean bContainsFormulas = false;
|
||||
private boolean bAddParAfterDisplay = false;
|
||||
|
||||
public MathmlConverter(OfficeReader ofr,LaTeXConfig config, ConverterPalette palette) {
|
||||
super(ofr,config,palette);
|
||||
smc = new StarMathConverter(palette.getI18n(),config);
|
||||
bAddParAfterDisplay = config.formatting()>=LaTeXConfig.CONVERT_MOST;
|
||||
}
|
||||
|
||||
public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
|
||||
if (bContainsFormulas) {
|
||||
if (config.useOoomath()) {
|
||||
pack.append("\\usepackage{ooomath}").nl();
|
||||
}
|
||||
else {
|
||||
smc.appendDeclarations(pack,decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String convert(Node settings, Node formula) {
|
||||
// TODO: Use settings to determine display mode/text mode
|
||||
// formula must be a math:math node
|
||||
// First try to find a StarMath annotation
|
||||
Node semantics = Misc.getChildByTagName(formula,XMLString.SEMANTICS); // Since OOo 3.2
|
||||
if (semantics==null) {
|
||||
semantics = Misc.getChildByTagName(formula,XMLString.MATH_SEMANTICS);
|
||||
}
|
||||
if (semantics!=null) {
|
||||
Node annotation = Misc.getChildByTagName(semantics,XMLString.ANNOTATION); // Since OOo 3.2
|
||||
if (annotation==null) {
|
||||
annotation = Misc.getChildByTagName(semantics,XMLString.MATH_ANNOTATION);
|
||||
}
|
||||
if (annotation!=null) {
|
||||
String sStarMath = "";
|
||||
if (annotation.hasChildNodes()) {
|
||||
NodeList anl = annotation.getChildNodes();
|
||||
int nLen = anl.getLength();
|
||||
for (int i=0; i<nLen; i++) {
|
||||
if (anl.item(i).getNodeType() == Node.TEXT_NODE) {
|
||||
sStarMath+=anl.item(i).getNodeValue();
|
||||
}
|
||||
}
|
||||
bContainsFormulas = true;
|
||||
return smc.convert(sStarMath);
|
||||
}
|
||||
}
|
||||
}
|
||||
// No annotation was found. In this case we should convert the mathml,
|
||||
// but currently we ignore the problem.
|
||||
// TODO: Investigate if Vasil I. Yaroshevich's MathML->LaTeX
|
||||
// XSL transformation could be used here. (Potential problem:
|
||||
// OOo uses MathML 1.01, not MathML 2)
|
||||
if (formula.hasChildNodes()) {
|
||||
return "\\text{Warning: No StarMath annotation}";
|
||||
}
|
||||
else { // empty formula
|
||||
return " ";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Handle an (inline) TexMaths equation
|
||||
*
|
||||
* @param node the equation (an svg:desc element containing the formula)
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @param oc the current context
|
||||
*/
|
||||
public void handleTexMathsEquation(Element node, LaTeXDocumentPortion ldp, Context oc) {
|
||||
// LaTeX code is contained in svg:desc
|
||||
// Format is <point size>X<mode>X<TeX code>X<format>X<resolution>X<transparency>
|
||||
// where X is a paragraph sign
|
||||
switch (getTexMathsStyle(node)) {
|
||||
case inline:
|
||||
ldp.append("$").append(getTexMathsEquation(node)).append("$");
|
||||
break;
|
||||
case display:
|
||||
ldp.append("$\\displaystyle ").append(getTexMathsEquation(node)).append("$");
|
||||
break;
|
||||
case latex:
|
||||
ldp.append(getTexMathsEquation(node));
|
||||
}
|
||||
}
|
||||
|
||||
private TexMathsStyle getTexMathsStyle(Element node) {
|
||||
String[] sContent = Misc.getPCDATA(node).split("\u00a7");
|
||||
if (sContent.length>=3) { // we only need 3 items of 6
|
||||
if ("display".equals(sContent[1])) {
|
||||
return TexMathsStyle.display;
|
||||
}
|
||||
else if ("latex".equals(sContent[1])) {
|
||||
return TexMathsStyle.latex;
|
||||
}
|
||||
}
|
||||
return TexMathsStyle.inline;
|
||||
}
|
||||
|
||||
private String getTexMathsEquation(Element node) {
|
||||
String[] sContent = Misc.getPCDATA(node).split("\u00a7");
|
||||
if (sContent.length>=3) { // we only need 3 items of 6
|
||||
return sContent[2];
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/** Try to convert a table as a display equation:
|
||||
* A 1 row by 2 columns table in which each cell contains exactly one paragraph,
|
||||
* the left cell contains exactly one formula and the right cell contains exactly
|
||||
* one sequence number is treated as a (numbered) display equation.
|
||||
* This happens to coincide with the AutoText provided with OOo Writer :-)
|
||||
* @param table the table reader
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @return true if the conversion was successful, false if the table
|
||||
* did not represent a display equation
|
||||
*/
|
||||
public boolean handleDisplayEquation(TableReader table, LaTeXDocumentPortion ldp) {
|
||||
if (table.getRowCount()==1 && table.getColCount()==2 &&
|
||||
OfficeReader.isSingleParagraph(table.getCell(0, 0)) && OfficeReader.isSingleParagraph(table.getCell(0, 1)) ) {
|
||||
// Table of the desired form
|
||||
if (palette.parseDisplayEquation(Misc.getFirstChildElement(table.getCell(0, 0))) && palette.getEquation()!=null && palette.getSequence()==null) {
|
||||
// Found equation in first cell
|
||||
Element myEquation = palette.getEquation();
|
||||
if (palette.parseDisplayEquation(Misc.getFirstChildElement(table.getCell(0, 1))) && palette.getEquation()==null && palette.getSequence()!=null) {
|
||||
// Found sequence in second cell
|
||||
handleDisplayEquation(myEquation, palette.getSequence(), ldp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**Try to convert a paragraph as a display equation:
|
||||
* A paragraph which contains exactly one formula + at most one sequence
|
||||
* number is treated as a display equation. Other content must be brackets
|
||||
* or whitespace (possibly with formatting).
|
||||
* @param node the paragraph
|
||||
* @param ldp the LaTeXDocumentPortion to contain the converted equation
|
||||
* @return true if the conversion was successful, false if the paragraph
|
||||
* did not contain a display equation
|
||||
*/
|
||||
public boolean handleDisplayEquation(Element node, LaTeXDocumentPortion ldp) {
|
||||
if (palette.parseDisplayEquation(node) && palette.getEquation()!=null) {
|
||||
handleDisplayEquation(palette.getEquation(), palette.getSequence(), ldp);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDisplayEquation(Element equation, Element sequence, LaTeXDocumentPortion ldp) {
|
||||
boolean bTexMaths = equation.getTagName().equals(XMLString.SVG_DESC);
|
||||
TexMathsStyle style = TexMathsStyle.inline;
|
||||
String sLaTeX;
|
||||
if (bTexMaths) {
|
||||
// TeXMaths equation
|
||||
sLaTeX = getTexMathsEquation(equation);
|
||||
style = getTexMathsStyle(equation);
|
||||
}
|
||||
else {
|
||||
// MathML equation
|
||||
sLaTeX = convert(null,equation);
|
||||
}
|
||||
if (!" ".equals(sLaTeX)) { // ignore empty formulas
|
||||
if (!bTexMaths || style!=TexMathsStyle.latex) {
|
||||
if (sequence!=null) {
|
||||
// Numbered equation
|
||||
ldp.append("\\begin{equation}");
|
||||
palette.getFieldCv().handleSequenceLabel(sequence,ldp);
|
||||
if (bTexMaths && style==TexMathsStyle.inline) {
|
||||
ldp.append("\\textstyle ");
|
||||
}
|
||||
ldp.nl()
|
||||
.append(sLaTeX).nl()
|
||||
.append("\\end{equation}").nl();
|
||||
}
|
||||
else {
|
||||
// Unnumbered equation
|
||||
ldp.append("\\begin{equation*}");
|
||||
if (bTexMaths && style==TexMathsStyle.inline) {
|
||||
ldp.append("\\textstyle ");
|
||||
}
|
||||
ldp.nl()
|
||||
.append(sLaTeX).nl()
|
||||
.append("\\end{equation*}").nl();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ldp.append(sLaTeX).nl();
|
||||
}
|
||||
if (bAddParAfterDisplay) { ldp.nl(); }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -98,7 +98,7 @@ public class ParConverter extends StyleConverter {
|
|||
* \end{enumerate}).
|
||||
*/
|
||||
public void handleParagraph(Element node, LaTeXDocumentPortion ldp, Context oc, boolean bLastInBlock) {
|
||||
if (palette.getMathmlCv().handleDisplayEquation(node,ldp)) { return; }
|
||||
if (palette.getMathCv().handleDisplayEquation(node,ldp)) { return; }
|
||||
|
||||
// Get the style name for this paragraph
|
||||
String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
|
||||
|
|
|
@ -166,7 +166,7 @@ public class TableConverter extends ConverterHelper {
|
|||
// Read the table
|
||||
table = ofr.getTableReader(node);
|
||||
|
||||
if (palette.getMathmlCv().handleDisplayEquation(table,ldp)) { return; }
|
||||
if (palette.getMathCv().handleDisplayEquation(table,ldp)) { return; }
|
||||
|
||||
// Get formatter and update flags according to formatter
|
||||
formatter = new TableFormatter(ofr,config,palette,table,!oc.isInMulticols(),oc.isInTable());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue