Started modifying project structure

This commit is contained in:
Georgy Litvinov 2020-12-13 14:03:25 +01:00
parent 4e16ed01c2
commit 1e4ee37f89
566 changed files with 3340 additions and 176 deletions

View file

@ -0,0 +1,151 @@
/************************************************************************
*
* AlphabeticalIndexConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-19)
*
*/
package writer2latex.xhtml;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.IndexMark;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
import writer2latex.util.StringComparator;
// Helper class (a struct) to contain information about an alphabetical index entry.
final class AlphabeticalEntry {
String sWord; // the word for the index
int nIndex; // the original index of this entry
}
/** This class processes alphabetical index marks and the associated index table
*/
class AlphabeticalIndexConverter extends IndexConverterHelper {
private List<AlphabeticalEntry> index = new ArrayList<AlphabeticalEntry>(); // All words for the index
private int nIndexIndex = -1; // Current index used for id's (of form idxN)
private int nAlphabeticalIndex = -1; // File containing alphabetical index
AlphabeticalIndexConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter,XMLString.TEXT_ALPHABETICAL_INDEX_SOURCE,"index");
}
/** Return the id of the file containing the alphabetical index
*
* @return the file id
*/
int getFileIndex() {
return nAlphabeticalIndex;
}
/** Handle an alphabetical index mark
*
* @param onode a text:alphabetical-index-mark node
* @param hnode the link target will be added to this inline HTML node
*/
void handleIndexMark(Node onode, Node hnode) {
handleIndexMark(Misc.getAttribute(onode,XMLString.TEXT_STRING_VALUE),hnode);
}
/** Handle an alphabetical index mark start
*
* @param onode a text:alphabetical-index-mark-start node
* @param hnode the link target will be added to this inline HTML node
*/
void handleIndexMarkStart(Node onode, Node hnode) {
handleIndexMark(IndexMark.getIndexValue(onode),hnode);
}
// Create an entry for an index mark
void handleIndexMark(String sWord, Node hnode) {
if (sWord!=null) {
AlphabeticalEntry entry = new AlphabeticalEntry();
entry.sWord = sWord;
entry.nIndex = ++nIndexIndex;
index.add(entry);
hnode.appendChild(converter.createTarget("idx"+nIndexIndex));
}
}
/** Handle an alphabetical index
*
* @param onode a text:alphabetical-index node
* @param hnode the index will be added to this block HTML node
*/
@Override void handleIndex(Element onode, Element hnode) {
// Register the file index (we assume that there is only one alphabetical index)
nAlphabeticalIndex = converter.getOutFileIndex();
converter.setIndexFile(null);
super.handleIndex(onode, hnode);
}
@Override void populateIndex(Element source, Element container) {
sortEntries(source);
String sEntryStyleName = getEntryStyleName(source);
for (int i=0; i<=nIndexIndex; i++) {
AlphabeticalEntry entry = index.get(i);
Element li = converter.createElement("li");
container.appendChild(li);
Element p = getTextCv().createParagraph(li,sEntryStyleName);
Element a = converter.createLink("idx"+entry.nIndex);
p.appendChild(a);
a.appendChild(converter.createTextNode(entry.sWord));
}
}
// Sort the list of words based on the language defined by the index source
private void sortEntries(Element source) {
Comparator<AlphabeticalEntry> comparator = new StringComparator<AlphabeticalEntry>(
Misc.getAttribute(source,XMLString.FO_LANGUAGE),
Misc.getAttribute(source, XMLString.FO_COUNTRY)) {
public int compare(AlphabeticalEntry a, AlphabeticalEntry b) {
return getCollator().compare(a.sWord, b.sWord);
}
};
Collections.sort(index,comparator);
}
// Get the style name to use for the individual words
private String getEntryStyleName(Element source) {
// TODO: Should read the entire template
Node child = source.getFirstChild();
while (child!=null) {
if (child.getNodeType() == Node.ELEMENT_NODE
&& child.getNodeName().equals(XMLString.TEXT_ALPHABETICAL_INDEX_ENTRY_TEMPLATE)) {
// Note: There are actually three outline-levels: separator, 1, 2 and 3
int nLevel = Misc.getPosInteger(Misc.getAttribute(child,XMLString.TEXT_OUTLINE_LEVEL),0);
if (nLevel==1) {
return Misc.getAttribute(child,XMLString.TEXT_STYLE_NAME);
}
}
child = child.getNextSibling();
}
return null;
}
}

View file

@ -0,0 +1,234 @@
/************************************************************************
*
* BatchConverterImpl.java
*
* Copyright: 2002-2010 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.2 (2010-04-23)
*
*/
package writer2latex.xhtml;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Locale;
import java.text.Collator;
import org.w3c.dom.Element;
import writer2latex.api.IndexPageEntry;
import writer2latex.api.OutputFile;
import writer2latex.base.BatchConverterBase;
import writer2latex.xhtml.l10n.L10n;
/**
* Implementation of <code>writer2latex.api.BatchConverter</code> for
* xhtml 1.0 strict
*/
public class BatchConverterImpl extends BatchConverterBase {
private XhtmlConfig config;
private XhtmlDocument template;
private String sDefaultLang;
private String sDefaultCountry;
private L10n l10n;
public BatchConverterImpl() {
super();
config = new XhtmlConfig();
template = null;
l10n = new L10n();
sDefaultLang = System.getProperty("user.language");
sDefaultCountry = System.getProperty("user.country");
l10n.setLocale(sDefaultLang, sDefaultCountry);
}
// Implementation of the remaining (xhtml specific) parts of the interface
public writer2latex.api.Config getConfig() {
return config;
}
public void readTemplate(InputStream is) throws IOException {
template = new XhtmlDocument("Template",XhtmlDocument.XHTML10);
try {
template.read(is);
}
catch (IOException e) {
template = null;
throw e;
}
}
public void readTemplate(File file) throws IOException {
readTemplate(new FileInputStream(file));
}
protected String getIndexFileName() {
return "index.html";
}
public OutputFile createIndexFile(String sHeading, IndexPageEntry[] entries) {
// Create the index page (with header/footer or from template)
XhtmlDocument htmlDoc = new XhtmlDocument("index",XhtmlDocument.XHTML10);
htmlDoc.setConfig(config);
if (template!=null) { htmlDoc.readFromTemplate(template); }
else { htmlDoc.createHeaderFooter(); }
org.w3c.dom.Document htmlDOM = htmlDoc.getContentDOM();
Element head = htmlDoc.getHeadNode();
if (head!=null) {
// Declare charset (we need this for xhtml because we have no <?xml ... ?>)
Element meta = htmlDOM.createElement("meta");
meta.setAttribute("http-equiv","Content-Type");
meta.setAttribute("content","text/html; charset="+htmlDoc.getEncoding().toLowerCase());
head.appendChild(meta);
// Add link to stylesheet
if (config.xhtmlCustomStylesheet().length()>0) {
Element htmlStyle = htmlDOM.createElement("link");
htmlStyle.setAttribute("rel","stylesheet");
htmlStyle.setAttribute("type","text/css");
htmlStyle.setAttribute("media","all");
htmlStyle.setAttribute("href",config.xhtmlCustomStylesheet());
head.appendChild(htmlStyle);
}
}
// Add uplink to header and footer
Element header = htmlDoc.getHeaderNode();
if (header!=null) {
if (config.getXhtmlUplink().length()>0) {
Element a = htmlDOM.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(htmlDOM.createTextNode(l10n.get(L10n.UP)));
header.appendChild(a);
}
else {
header.appendChild(htmlDOM.createTextNode(l10n.get(L10n.UP)));
}
}
Element footer = htmlDoc.getFooterNode();
if (footer!=null) {
if (config.getXhtmlUplink().length()>0) {
Element a = htmlDOM.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(htmlDOM.createTextNode(l10n.get(L10n.UP)));
footer.appendChild(a);
}
else {
footer.appendChild(htmlDOM.createTextNode(l10n.get(L10n.UP)));
}
}
// Add title and heading
Element title = htmlDoc.getTitleNode();
if (title!=null) {
title.appendChild(htmlDOM.createTextNode(sHeading));
}
Element h1 = htmlDOM.createElement("h1");
htmlDoc.getContentNode().appendChild(h1);
h1.appendChild(htmlDOM.createTextNode(sHeading));
// Sort the entries
int nLen = entries.length;
Collator collator = Collator.getInstance(new Locale(sDefaultLang,sDefaultCountry));
for (int i = 0; i<nLen; i++) {
if (entries[i]!=null) {
for (int j = i+1; j<nLen ; j++) {
if (entries[j]!=null) {
IndexPageEntry entryi = entries[i];
IndexPageEntry entryj = entries[j];
if (collator.compare(entryi.getDisplayName(), entryj.getDisplayName()) > 0) {
entries[i] = entryj;
entries[j] = entryi;
}
}
}
}
}
// Insert directory entries
boolean bUseIcon = config.getXhtmlDirectoryIcon().length()>0;
for (int i=0; i<nLen; i++) {
if (entries[i]!=null && entries[i].isDirectory()) {
Element p = htmlDOM.createElement("p");
htmlDoc.getContentNode().appendChild(p);
if (bUseIcon) {
Element img = htmlDOM.createElement("img");
p.appendChild(img);
img.setAttribute("src",config.getXhtmlDirectoryIcon());
img.setAttribute("alt",l10n.get(L10n.DIRECTORY));
p.appendChild(htmlDOM.createTextNode(" "));
}
Element a = htmlDOM.createElement("a");
p.appendChild(a);
a.setAttribute("href",entries[i].getFile());
a.appendChild(htmlDOM.createTextNode(entries[i].getDisplayName()));
}
}
// Insert document entries
bUseIcon = config.getXhtmlDocumentIcon().length()>0;
for (int i=0; i<nLen; i++) {
if (entries[i]!=null && !entries[i].isDirectory()) {
Element p = htmlDOM.createElement("p");
htmlDoc.getContentNode().appendChild(p);
if (bUseIcon) {
Element img = htmlDOM.createElement("img");
p.appendChild(img);
img.setAttribute("src",config.getXhtmlDocumentIcon());
img.setAttribute("alt",l10n.get(L10n.DOCUMENT));
p.appendChild(htmlDOM.createTextNode(" "));
}
// Add link to html file
if (entries[i].getFile()!=null) {
Element a = htmlDOM.createElement("a");
p.appendChild(a);
a.setAttribute("href",entries[i].getFile());
a.appendChild(htmlDOM.createTextNode(entries[i].getDisplayName()));
}
else {
p.appendChild(htmlDOM.createTextNode(entries[i].getDisplayName()));
}
// Add link to pdf file
if (entries[i].getPdfFile()!=null) {
p.appendChild(htmlDOM.createTextNode(" "));
Element pdfa = htmlDOM.createElement("a");
p.appendChild(pdfa);
pdfa.setAttribute("href",entries[i].getPdfFile());
pdfa.appendChild(htmlDOM.createTextNode("pdf"));
}
// TODO: Add link to original file if defined
// Add description if available
if (entries[i].getDescription()!=null) {
p.appendChild(htmlDOM.createTextNode(": "+entries[i].getDescription()));
}
}
}
return htmlDoc;
}
}

View file

@ -0,0 +1,59 @@
/************************************************************************
*
* BibliographyConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-16)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
/** This class handles the export of the bibliography. Most of the work is delegated to the
* {@link XhtmlBibliographyGenerator}
*/
class BibliographyConverter extends IndexConverterHelper {
private XhtmlBibliographyGenerator bibGenerator;
BibliographyConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter,XMLString.TEXT_BIBLIOGRAPHY_SOURCE,"bibliography");
bibGenerator = new XhtmlBibliographyGenerator(ofr,converter);
}
void handleBibliographyMark(Node onode, Node hnode) {
String sKey = Misc.getAttribute(onode, XMLString.TEXT_IDENTIFIER);
if (sKey!=null) {
Element anchor = converter.createLink("bib"+sKey);
hnode.appendChild(anchor);
anchor.appendChild(converter.createTextNode(bibGenerator.generateCitation(sKey)));
}
}
@Override void populateIndex(Element source, Element container) {
bibGenerator.populateBibliography(source, container);
}
}

View file

@ -0,0 +1,103 @@
/************************************************************************
*
* CellStyleConverter.java
*
* Copyright: 2002-2008 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
/**
* This class converts OpenDocument cell styles to CSS2 styles.
* Cells are formatted using box properties and alignment.
*/
public class CellStyleConverter extends StyleWithPropertiesConverterHelper {
/** Create a new <code>CellStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public CellStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
// Style maps for Cells are currently not supported.
// (In OOo, cell styles are only supported by Calc)
this.styleMap = new XhtmlStyleMap();
this.bConvertStyles = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_STYLES;
}
/** Get the family of cell styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getCellStyles();
}
/** Create default tag name to represent a Cell object
* @param style to use
* @return the tag name.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "td";
}
/** Convert formatting properties for a specific Cell style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
// Apply "inner" box properties (no margins)
getFrameSc().cssBorder(style,props,bInherit);
getFrameSc().cssPadding(style,props,bInherit);
getFrameSc().cssBackground(style,props,bInherit);
// only relevant for spreadsheets
getParSc().cssPar(style,props,bInherit);
getTextSc().cssTextCommon(style,props,bInherit);
// Cell-specific properties (vertical alignment)
cssCell(style,props,bInherit);
}
private void cssCell(StyleWithProperties style, CSVList props, boolean bInherit){
// Vertical align: Some values fit with css
String s = ofr.isOpenDocument() ?
style.getProperty(XMLString.STYLE_VERTICAL_ALIGN,bInherit) :
style.getProperty(XMLString.FO_VERTICAL_ALIGN,bInherit);
if ("middle".equals(s)) { props.addValue("vertical-align","middle"); }
else if ("bottom".equals(s)) { props.addValue("vertical-align","bottom"); }
else if ("top".equals(s)) { props.addValue("vertical-align","top"); }
else {
// No value or "automatic" means, according to the spec,
//"The application decide how to align the text."
// We treat this case like OOo does:
props.addValue("vertical-align", ofr.isSpreadsheet() ? "bottom" : "top");
}
}
}

View file

@ -0,0 +1,893 @@
/************************************************************************
*
* Converter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-11)
*
*/
package writer2latex.xhtml;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Iterator;
import java.io.InputStream;
import java.io.IOException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import writer2latex.api.Config;
import writer2latex.api.ContentEntry;
import writer2latex.api.ConverterFactory;
import writer2latex.api.OutputFile;
import writer2latex.base.ContentEntryImpl;
import writer2latex.base.ConverterBase;
import writer2latex.office.MIMETypes;
import writer2latex.office.OfficeReader;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.ExportNameCollection;
import writer2latex.util.Misc;
import writer2latex.xhtml.l10n.L10n;
/**
* <p>This class converts an OpenDocument file to an XHTML(+MathML) or EPUB document.</p>
*
*/
public class Converter extends ConverterBase {
private static final String EPUB_STYLES_FOLDER = "styles/";
private static final String EPUB_STYLESHEET = "styles/styles1.css";
private static final String EPUB_CUSTOM_STYLESHEET = "styles/styles.css";
// Config
private XhtmlConfig config;
public Config getConfig() { return config; }
protected XhtmlConfig getXhtmlConfig() { return config; }
// The locale
private L10n l10n;
// The helpers
private StyleConverter styleCv;
private TextConverter textCv;
private TableConverter tableCv;
private DrawConverter drawCv;
private MathConverter mathCv;
// The template
private XhtmlDocument template = null;
// The included style sheet and associated resources
private CssDocument styleSheet = null;
private Set<ResourceDocument> resources = new HashSet<ResourceDocument>();
// The xhtml output file(s)
protected int nType = XhtmlDocument.XHTML10; // the doctype
private boolean bOPS = false; // Do we need to be OPS conforming?
Vector<XhtmlDocument> outFiles;
private int nOutFileIndex;
private XhtmlDocument htmlDoc; // current outfile
private Document htmlDOM; // current DOM, usually within htmlDoc
private boolean bNeedHeaderFooter = false;
//private int nTocFileIndex = -1;
//private int nAlphabeticalIndex = -1;
// Hyperlinks
Hashtable<String, Integer> targets = new Hashtable<String, Integer>();
LinkedList<LinkDescriptor> links = new LinkedList<LinkDescriptor>();
// Strip illegal characters from internal hyperlink targets
private ExportNameCollection targetNames = new ExportNameCollection(true);
// The current context (currently we only track the content width, but this might be expanded with formatting
// attributes - at least background color and font size later)
private Stack<String> contentWidth = new Stack<String>();
// Constructor setting the DOCTYPE
public Converter(int nType) {
super();
config = new XhtmlConfig();
this.nType = nType;
}
// override methods to read templates, style sheets and resources
@Override public void readTemplate(InputStream is) throws IOException {
template = new XhtmlDocument("Template",nType);
template.read(is);
}
@Override public void readTemplate(File file) throws IOException {
readTemplate(new FileInputStream(file));
}
@Override public void readStyleSheet(InputStream is) throws IOException {
if (styleSheet==null) {
styleSheet = new CssDocument(EPUB_CUSTOM_STYLESHEET);
}
styleSheet.read(is);
}
@Override public void readStyleSheet(File file) throws IOException {
readStyleSheet(new FileInputStream(file));
}
@Override public void readResource(InputStream is, String sFileName, String sMediaType) throws IOException {
if (sMediaType==null) {
// Guess the media type from the file extension
sMediaType="";
String sfilename = sFileName.toLowerCase();
// PNG, JPEG and GIF are the basic raster image formats that must be supported by EPUB readers
if (sfilename.endsWith(MIMETypes.PNG_EXT)) { sMediaType = MIMETypes.PNG; }
else if (sfilename.endsWith(MIMETypes.JPEG_EXT)) { sMediaType = MIMETypes.JPEG; }
else if (sfilename.endsWith(".jpeg")) { sMediaType = MIMETypes.JPEG; }
else if (sfilename.endsWith(MIMETypes.GIF_EXT)) { sMediaType = MIMETypes.GIF; }
// The OPS 2.0.1 specification recommends (and only mentions) OpenType with this media type
else if (sfilename.endsWith(".otf")) { sMediaType = "application/vnd.ms-opentype"; }
// For convenience we also include a media type for true type fonts (the most common, it seems)
else if (sfilename.endsWith(".ttf")) { sMediaType = "application/x-font-ttf"; }
}
ResourceDocument doc = new ResourceDocument(EPUB_STYLES_FOLDER+sFileName, sMediaType);
doc.read(is);
resources.add(doc);
}
@Override public void readResource(File file, String sFileName, String sMediaType) throws IOException {
readResource(new FileInputStream(file), sFileName, sMediaType);
}
protected String getContentWidth() {
return contentWidth.peek();
}
protected String pushContentWidth(String sWidth) {
return contentWidth.push(sWidth);
}
protected void popContentWidth() {
contentWidth.pop();
}
protected boolean isTopLevel() {
return contentWidth.size()==1;
}
protected StyleConverter getStyleCv() { return styleCv; }
protected TextConverter getTextCv() { return textCv; }
protected TableConverter getTableCv() { return tableCv; }
protected DrawConverter getDrawCv() { return drawCv; }
protected MathConverter getMathCv() { return mathCv; }
protected int getType() { return nType; }
public boolean isHTML5() { return nType==XhtmlDocument.HTML5; }
protected int getOutFileIndex() { return nOutFileIndex; }
protected void addContentEntry(String sTitle, int nLevel, String sTarget) {
converterResult.addContentEntry(new ContentEntryImpl(sTitle,nLevel,htmlDoc,sTarget));
}
protected void setTocFile(String sTarget) {
converterResult.setTocFile(new ContentEntryImpl(l10n.get(L10n.CONTENTS),1,htmlDoc,sTarget));
//nTocFileIndex = nOutFileIndex;
}
protected void setLofFile(String sTarget) {
converterResult.setLofFile(new ContentEntryImpl("Figures",1,htmlDoc,sTarget));
}
protected void setLotFile(String sTarget) {
converterResult.setLotFile(new ContentEntryImpl("Tables",1,htmlDoc,sTarget));
}
protected void setIndexFile(String sTarget) {
converterResult.setIndexFile(new ContentEntryImpl(l10n.get(L10n.INDEX),1,htmlDoc,sTarget));
//nAlphabeticalIndex = nOutFileIndex;
}
protected void setCoverFile(String sTarget) {
converterResult.setCoverFile(new ContentEntryImpl("Cover",0,htmlDoc,sTarget));
}
protected void setCoverImageFile(OutputFile file, String sTarget) {
converterResult.setCoverImageFile(new ContentEntryImpl("Cover image",0,file,sTarget));
}
protected Element createElement(String s) { return htmlDOM.createElement(s); }
protected Text createTextNode(String s) { return htmlDOM.createTextNode(s); }
protected Node importNode(Node node, boolean bDeep) { return htmlDOM.importNode(node,bDeep); }
protected L10n getL10n() { return l10n; }
public void setOPS(boolean b) { bOPS = true; }
public boolean isOPS() { return bOPS; }
@Override public void convertInner() throws IOException {
sTargetFileName = Misc.trimDocumentName(sTargetFileName,XhtmlDocument.getExtension(nType));
outFiles = new Vector<XhtmlDocument>();
nOutFileIndex = -1;
bNeedHeaderFooter = !bOPS && (ofr.isSpreadsheet() || ofr.isPresentation() || config.getXhtmlSplitLevel()>0 || config.pageBreakSplit()>XhtmlConfig.NONE || config.getXhtmlUplink().length()>0);
l10n = new L10n();
if (isOPS()) {
imageConverter.setBaseFileName("image");
imageConverter.setUseSubdir("images");
}
else {
imageConverter.setBaseFileName(sTargetFileName+"-img");
if (config.saveImagesInSubdir()) {
imageConverter.setUseSubdir(sTargetFileName+"-img");
}
}
imageConverter.setDefaultFormat(MIMETypes.PNG);
imageConverter.addAcceptedFormat(MIMETypes.JPEG);
imageConverter.addAcceptedFormat(MIMETypes.GIF);
if (nType==XhtmlDocument.HTML5) { // HTML supports SVG as well
imageConverter.setDefaultVectorFormat(MIMETypes.SVG);
}
styleCv = new StyleConverter(ofr,config,this,nType);
textCv = new TextConverter(ofr,config,this);
tableCv = new TableConverter(ofr,config,this);
drawCv = new DrawConverter(ofr,config,this);
mathCv = new MathConverter(ofr,config,this,nType!=XhtmlDocument.XHTML10 && nType!=XhtmlDocument.XHTML11);
// Set locale to document language
StyleWithProperties style = ofr.isSpreadsheet() ? ofr.getDefaultCellStyle() : ofr.getDefaultParStyle();
if (style!=null) {
// The only CTL language recognized currently is farsi
if ("fa".equals(style.getProperty(XMLString.STYLE_LANGUAGE_COMPLEX))) {
l10n.setLocale("fa", "IR");
}
else {
l10n.setLocale(style.getProperty(XMLString.FO_LANGUAGE), style.getProperty(XMLString.FO_COUNTRY));
}
}
// Set the main content width
pushContentWidth(getStyleCv().getPageSc().getTextWidth());
// Traverse the body
Element body = ofr.getContent();
if (ofr.isSpreadsheet()) { tableCv.convertTableContent(body); }
else if (ofr.isPresentation()) { drawCv.convertDrawContent(body); }
else { textCv.convertTextContent(body); }
// Set the title page and text page entries
if (converterResult.getContent().isEmpty()) {
// No headings in the document: There is no title page and the text page is the first page
converterResult.setTextFile(new ContentEntryImpl("Text", 1, outFiles.get(0), null));
// We also have to add a toc entry (the ncx file cannot be empty)
converterResult.addContentEntry(new ContentEntryImpl("Text", 1, outFiles.get(0), null));
}
else {
ContentEntry firstHeading = converterResult.getContent().get(0);
// The title page is the first page after the cover, unless the first page starts with a heading
int nFirstPage = converterResult.getCoverFile()!=null ? 1 : 0;
if (outFiles.get(nFirstPage)!=firstHeading.getFile() || firstHeading.getTarget()!=null) {
converterResult.setTitlePageFile(new ContentEntryImpl("Title page", 1, outFiles.get(nFirstPage), null));
}
// The text page is the one containing the first heading
converterResult.setTextFile(new ContentEntryImpl("Text", 1, firstHeading.getFile(), firstHeading.getTarget()));
}
// Resolve links
ListIterator<LinkDescriptor> iter = links.listIterator();
while (iter.hasNext()) {
LinkDescriptor ld = iter.next();
Integer targetIndex = targets.get(ld.sId);
if (targetIndex!=null) {
int nTargetIndex = targetIndex.intValue();
if (nTargetIndex == ld.nIndex) { // same file
ld.element.setAttribute("href","#"+targetNames.getExportName(ld.sId));
}
else {
ld.element.setAttribute("href",getOutFileName(nTargetIndex,true)
+"#"+targetNames.getExportName(ld.sId));
}
}
}
// Add included style sheet, if any - and we are creating OPS content
if (bOPS && styleSheet!=null) {
converterResult.addDocument(styleSheet);
for (ResourceDocument doc : resources) {
converterResult.addDocument(doc);
}
}
// Export styles (XHTML)
if (!isOPS() && !config.separateStylesheet()) {
for (int i=0; i<=nOutFileIndex; i++) {
Element head = outFiles.get(i).getHeadNode();
if (head!=null) {
Node styles = styleCv.exportStyles(outFiles.get(i).getContentDOM());
if (styles!=null) {
head.appendChild(styles);
}
}
}
}
// Load MathJax
// TODO: Should we support different configurations of MathJax?
if ((nType==XhtmlDocument.HTML5 || nType==XhtmlDocument.XHTML_MATHML) && config.useMathJax()) {
for (int i=0; i<=nOutFileIndex; i++) {
if (outFiles.get(i).hasMath()) {
XhtmlDocument doc = outFiles.get(i);
Element head = doc.getHeadNode();
if (head!=null) {
Element script = doc.getContentDOM().createElement("script");
head.appendChild(script);
script.setAttribute("type", "text/javascript");
script.setAttribute("src", "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML");
}
}
}
}
// Create headers & footers (if nodes are available)
if (ofr.isSpreadsheet()) {
for (int i=0; i<=nOutFileIndex; i++) {
XhtmlDocument doc = outFiles.get(i);
Document dom = doc.getContentDOM();
Element header = doc.getHeaderNode();
Element footer = doc.getFooterNode();
Element headerPar = dom.createElement("p");
Element footerPar = dom.createElement("p");
footerPar.setAttribute("style","clear:both"); // no floats may pass!
// Add uplink
if (config.getXhtmlUplink().length()>0) {
Element a = dom.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(dom.createTextNode(l10n.get(L10n.UP)));
headerPar.appendChild(a);
headerPar.appendChild(dom.createTextNode(" "));
a = dom.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(dom.createTextNode(l10n.get(L10n.UP)));
footerPar.appendChild(a);
footerPar.appendChild(dom.createTextNode(" "));
}
// Add links to all sheets:
int nSheets = tableCv.sheetNames.size();
for (int j=0; j<nSheets; j++) {
if (config.xhtmlCalcSplit()) {
addNavigationLink(dom,headerPar,tableCv.sheetNames.get(j),j);
addNavigationLink(dom,footerPar,tableCv.sheetNames.get(j),j);
}
else {
addInternalNavigationLink(dom,headerPar,tableCv.sheetNames.get(j),"tableheading"+j);
addInternalNavigationLink(dom,footerPar,tableCv.sheetNames.get(j),"tableheading"+j);
}
}
if (header!=null) { header.appendChild(headerPar); }
if (footer!=null) { footer.appendChild(footerPar); }
}
}
else if (nOutFileIndex>0) {
for (int i=0; i<=nOutFileIndex; i++) {
XhtmlDocument doc = outFiles.get(i);
Document dom = doc.getContentDOM();
//Element content = doc.getContentNode();
// Header links
Element header = doc.getHeaderNode();
if (header!=null) {
if (ofr.isPresentation()) {
// Absolute placement in presentations (quick and dirty solution)
header.setAttribute("style","position:absolute;top:0;left:0");
}
if (config.getXhtmlUplink().length()>0) {
Element a = dom.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(dom.createTextNode(l10n.get(L10n.UP)));
header.appendChild(a);
header.appendChild(dom.createTextNode(" "));
}
addNavigationLink(dom,header,l10n.get(L10n.FIRST),0);
addNavigationLink(dom,header,l10n.get(L10n.PREVIOUS),i-1);
addNavigationLink(dom,header,l10n.get(L10n.NEXT),i+1);
addNavigationLink(dom,header,l10n.get(L10n.LAST),nOutFileIndex);
if (textCv.getTocIndex()>=0) {
addNavigationLink(dom,header,l10n.get(L10n.CONTENTS),textCv.getTocIndex());
}
if (textCv.getAlphabeticalIndex()>=0) {
addNavigationLink(dom,header,l10n.get(L10n.INDEX),textCv.getAlphabeticalIndex());
}
}
// Footer links
Element footer = doc.getFooterNode();
if (footer!=null && !ofr.isPresentation()) {
// No footer in presentations
if (config.getXhtmlUplink().length()>0) {
Element a = dom.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(dom.createTextNode(l10n.get(L10n.UP)));
footer.appendChild(a);
footer.appendChild(dom.createTextNode(" "));
}
addNavigationLink(dom,footer,l10n.get(L10n.FIRST),0);
addNavigationLink(dom,footer,l10n.get(L10n.PREVIOUS),i-1);
addNavigationLink(dom,footer,l10n.get(L10n.NEXT),i+1);
addNavigationLink(dom,footer,l10n.get(L10n.LAST),nOutFileIndex);
if (textCv.getTocIndex()>=0) {
addNavigationLink(dom,footer,l10n.get(L10n.CONTENTS),textCv.getTocIndex());
}
if (textCv.getAlphabeticalIndex()>=0) {
addNavigationLink(dom,footer,l10n.get(L10n.INDEX),textCv.getAlphabeticalIndex());
}
}
}
}
else if (config.getXhtmlUplink().length()>0) {
for (int i=0; i<=nOutFileIndex; i++) {
XhtmlDocument doc = outFiles.get(i);
Document dom = doc.getContentDOM();
//Element content = doc.getContentNode();
Element header = doc.getHeaderNode();
if (header!=null) {
Element a = dom.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(dom.createTextNode(l10n.get(L10n.UP)));
header.appendChild(a);
header.appendChild(dom.createTextNode(" "));
}
Element footer = doc.getFooterNode();
if (footer!=null) {
Element a = dom.createElement("a");
a.setAttribute("href",config.getXhtmlUplink());
a.appendChild(dom.createTextNode(l10n.get(L10n.UP)));
footer.appendChild(a);
footer.appendChild(dom.createTextNode(" "));
}
}
}
// Export styles
if (config.xhtmlFormatting()>XhtmlConfig.IGNORE_STYLES) {
if (isOPS()) { // EPUB
CssDocument cssDoc = new CssDocument(EPUB_STYLESHEET);
cssDoc.read(styleCv.exportStyles(false));
converterResult.addDocument(cssDoc);
}
else if (config.separateStylesheet()) { // XHTML
CssDocument cssDoc = new CssDocument(sTargetFileName+"-styles.css");
cssDoc.read(styleCv.exportStyles(false));
converterResult.addDocument(cssDoc);
}
}
}
private void addNavigationLink(Document dom, Node node, String s, int nIndex) {
if (nIndex>=0 && nIndex<=nOutFileIndex) {
Element a = dom.createElement("a");
a.setAttribute("href",Misc.makeHref(getOutFileName(nIndex,true)));
a.appendChild(dom.createTextNode(s));
//node.appendChild(dom.createTextNode("["));
node.appendChild(a);
node.appendChild(dom.createTextNode(" "));
//node.appendChild(dom.createTextNode("] "));
}
else {
Element span = dom.createElement("span");
span.setAttribute("class","nolink");
node.appendChild(span);
span.appendChild(dom.createTextNode(s));
node.appendChild(dom.createTextNode(" "));
//node.appendChild(dom.createTextNode("["+s+"] "));
}
}
private void addInternalNavigationLink(Document dom, Node node, String s, String sLink) {
Element a = dom.createElement("a");
a.setAttribute("href","#"+sLink);
a.appendChild(dom.createTextNode(s));
//node.appendChild(dom.createTextNode("["));
node.appendChild(a);
node.appendChild(dom.createTextNode(" "));
//node.appendChild(dom.createTextNode("] "));
}
/* get inline text, ignoring any draw objects, footnotes, formatting and hyperlinks */
protected String getPlainInlineText(Node node) {
StringBuilder buf = new StringBuilder();
Node child = node.getFirstChild();
while (child!=null) {
short nodeType = child.getNodeType();
switch (nodeType) {
case Node.TEXT_NODE:
buf.append(child.getNodeValue());
break;
case Node.ELEMENT_NODE:
String sName = child.getNodeName();
if (sName.equals(XMLString.TEXT_S)) {
buf.append(" ");
}
else if (sName.equals(XMLString.TEXT_LINE_BREAK) || sName.equals(XMLString.TEXT_TAB_STOP) || sName.equals(XMLString.TEXT_TAB)) { // text:tab in oasis
buf.append(" ");
}
else if (OfficeReader.isNoteElement(child)) {
// ignore
}
else if (OfficeReader.isTextElement(child)) {
buf.append(getPlainInlineText(child));
}
break;
default:
// Do nothing
}
child = child.getNextSibling();
}
return buf.toString();
}
public void handleOfficeAnnotation(Node onode, Node hnode) {
if (config.xhtmlNotes()) {
// Extract the text from the paragraphs, separate paragraphs with newline
StringBuilder buf = new StringBuilder();
Element creator = null;
Element date = null;
Node child = onode.getFirstChild();
while (child!=null) {
if (Misc.isElement(child, XMLString.TEXT_P)) {
if (buf.length()>0) { buf.append('\n'); }
buf.append(getPlainInlineText(child));
}
else if (Misc.isElement(child, XMLString.DC_CREATOR)) {
creator = (Element) child;
}
else if (Misc.isElement(child, XMLString.DC_DATE)) {
date = (Element) child;
}
child = child.getNextSibling();
}
if (creator!=null) {
if (buf.length()>0) { buf.append('\n'); }
buf.append(getPlainInlineText(creator));
}
if (date!=null) {
if (buf.length()>0) { buf.append('\n'); }
buf.append(Misc.formatDate(OfficeReader.getTextContent(date), l10n.getLocale().getLanguage(), l10n.getLocale().getCountry()));
}
Node commentNode = htmlDOM.createComment(buf.toString());
hnode.appendChild(commentNode);
}
}
/////////////////////////////////////////////////////////////////////////
// UTILITY METHODS
// Create output file name (docname.html, docname1.html, docname2.html etc.)
public String getOutFileName(int nIndex, boolean bWithExt) {
return sTargetFileName + (nIndex>0 ? Integer.toString(nIndex) : "")
+ (bWithExt ? htmlDoc.getFileExtension() : "");
}
// Return true if the current outfile has a non-empty body
public boolean outFileHasContent() {
return htmlDoc.getContentNode().hasChildNodes();
}
// Use another document. TODO: This is very ugly; clean it up!!!
public void changeOutFile(int nIndex) {
nOutFileIndex = nIndex;
htmlDoc = outFiles.get(nIndex);
htmlDOM = htmlDoc.getContentDOM();
}
public Element getPanelNode() {
return htmlDoc.getPanelNode();
}
public String getTitle(){
String title = metaData.getTitle();
if (title==null) {
// use filename as fallback
title = htmlDoc.getFileName();
}
return title;
}
// Prepare next output file
public Element nextOutFile() {
htmlDoc = new XhtmlDocument(getOutFileName(++nOutFileIndex,false),nType);
htmlDoc.setConfig(config);
if (template!=null) { htmlDoc.readFromTemplate(template); }
else if (bNeedHeaderFooter) { htmlDoc.createHeaderFooter(); }
outFiles.add(nOutFileIndex,htmlDoc);
converterResult.addDocument(htmlDoc);
// Create head + body
htmlDOM = htmlDoc.getContentDOM();
Element rootElement = htmlDOM.getDocumentElement();
styleCv.applyDefaultLanguage(rootElement);
addEpubNs(rootElement);
rootElement.insertBefore(htmlDOM.createComment(
"This file was converted to xhtml by "
+ (ofr.isText() ? "Writer" : (ofr.isSpreadsheet() ? "Calc" : "Impress"))
+ "2xhtml ver. " + ConverterFactory.getVersion() +
". See http://writer2latex.sourceforge.net for more info."),
rootElement.getFirstChild());
// Apply default writing direction
if (!ofr.isPresentation()) {
StyleInfo pageInfo = new StyleInfo();
styleCv.getPageSc().applyDefaultWritingDirection(pageInfo);
styleCv.getPageSc().applyStyle(pageInfo,htmlDoc.getContentNode());
}
// Add title (required by xhtml)
Element title = htmlDoc.getTitleNode();
if (title!=null) {
String sTitle = metaData.getTitle();
if (sTitle==null) { // use filename as fallback
sTitle = htmlDoc.getFileName();
}
title.appendChild( htmlDOM.createTextNode(sTitle) );
}
Element head = htmlDoc.getHeadNode();
if (head!=null) {
// Declare charset (we need this for XHTML 1.0 strict and HTML5 because we have no <?xml ... ?>)
if (nType==XhtmlDocument.XHTML10) {
Element meta = htmlDOM.createElement("meta");
meta.setAttribute("http-equiv","Content-Type");
meta.setAttribute("content","text/html; charset="+htmlDoc.getEncoding().toLowerCase());
head.appendChild(meta);
}
else if (nType==XhtmlDocument.HTML5) {
// The encoding should be UTF-8, but we still respect the user's setting
Element meta = htmlDOM.createElement("meta");
meta.setAttribute("charset",htmlDoc.getEncoding().toUpperCase());
head.appendChild(meta);
}
// Add meta data (for EPUB the meta data belongs to the .opf file)
if (!bOPS) {
// "Traditional" meta data
//createMeta("generator","Writer2LaTeX "+Misc.VERSION);
createMeta(head,"description",metaData.getDescription());
createMeta(head,"keywords",metaData.getKeywords());
// Dublin core meta data (optional)
// Format as recommended on dublincore.org (http://dublincore.org/documents/dc-html/)
// Declare meta data profile
if (config.xhtmlUseDublinCore()) {
head.setAttribute("profile","http://dublincore.org/documents/2008/08/04/dc-html/");
// Add link to declare namespace
Element dclink = htmlDOM.createElement("link");
dclink.setAttribute("rel","schema.DC");
dclink.setAttribute("href","http://purl.org/dc/elements/1.1/");
head.appendChild(dclink);
// Insert the actual meta data
createMeta(head,"DC.title",metaData.getTitle());
// DC.subject actually contains subject+keywords, so we merge them
String sDCSubject = "";
if (metaData.getSubject()!=null && metaData.getSubject().length()>0) {
sDCSubject = metaData.getSubject();
}
if (metaData.getKeywords()!=null && metaData.getKeywords().length()>0) {
if (sDCSubject.length()>0) { sDCSubject+=", "; }
sDCSubject += metaData.getKeywords();
}
createMeta(head,"DC.subject",sDCSubject);
createMeta(head,"DC.description",metaData.getDescription());
createMeta(head,"DC.creator",metaData.getCreator());
createMeta(head,"DC.date",metaData.getDate());
createMeta(head,"DC.language",metaData.getLanguage());
}
}
// Add link to custom stylesheet, if producing normal XHTML
if (!bOPS && config.xhtmlCustomStylesheet().length()>0) {
Element htmlStyle = htmlDOM.createElement("link");
htmlStyle.setAttribute("rel","stylesheet");
htmlStyle.setAttribute("type","text/css");
htmlStyle.setAttribute("media","all");
htmlStyle.setAttribute("href",config.xhtmlCustomStylesheet());
head.appendChild(htmlStyle);
}
// Add link to generated stylesheet if producing normal XHTML and the user wants separate css
if (!bOPS && config.separateStylesheet() && config.xhtmlFormatting()>XhtmlConfig.IGNORE_STYLES) {
Element htmlStyle = htmlDOM.createElement("link");
htmlStyle.setAttribute("rel","stylesheet");
htmlStyle.setAttribute("type","text/css");
htmlStyle.setAttribute("media","all");
htmlStyle.setAttribute("href",sTargetFileName+"-styles.css");
head.appendChild(htmlStyle);
}
// Add link to included style sheet if producing OPS content
if (bOPS && styleSheet!=null) {
Element sty = htmlDOM.createElement("link");
sty.setAttribute("rel", "stylesheet");
sty.setAttribute("type", "text/css");
sty.setAttribute("href", EPUB_CUSTOM_STYLESHEET);
head.appendChild(sty);
}
// Add link to generated stylesheet if producing OPS content
if (isOPS() && config.xhtmlFormatting()>XhtmlConfig.IGNORE_STYLES) {
Element htmlStyle = htmlDOM.createElement("link");
htmlStyle.setAttribute("rel","stylesheet");
htmlStyle.setAttribute("type","text/css");
htmlStyle.setAttribute("href",EPUB_STYLESHEET);
head.appendChild(htmlStyle);
}
}
// Recreate nested sections, if any
if (!textCv.sections.isEmpty()) {
Iterator<Node> iter = textCv.sections.iterator();
while (iter.hasNext()) {
Element section = (Element) iter.next();
String sStyleName = Misc.getAttribute(section,XMLString.TEXT_STYLE_NAME);
Element div = htmlDOM.createElement("div");
htmlDoc.getContentNode().appendChild(div);
htmlDoc.setContentNode(div);
StyleInfo sectionInfo = new StyleInfo();
styleCv.getSectionSc().applyStyle(sStyleName,sectionInfo);
styleCv.getSectionSc().applyStyle(sectionInfo,div);
}
}
return htmlDoc.getContentNode();
}
// Add epub namespace for the purpose of semantic inflection in EPUB 3
public void addEpubNs(Element elm) {
if (bOPS && nType==XhtmlDocument.HTML5) {
elm.setAttribute("xmlns:epub", "http://www.idpf.org/2007/ops");
}
}
// Add a type from the structural semantics vocabulary of EPUB 3
public void addEpubType(Element elm, String sType) {
if (bOPS && nType==XhtmlDocument.HTML5 && sType!=null) {
elm.setAttribute("epub:type", sType);
}
}
// create a target
public Element createTarget(String sId) {
Element a = htmlDOM.createElement("a");
a.setAttribute("id",targetNames.getExportName(sId));
targets.put(sId, new Integer(nOutFileIndex));
return a;
}
// put a target id on an existing element
public void addTarget(Element node,String sId) {
node.setAttribute("id",targetNames.getExportName(sId));
targets.put(sId, new Integer(nOutFileIndex));
}
// create an internal link
public Element createLink(String sId) {
Element a = htmlDOM.createElement("a");
LinkDescriptor ld = new LinkDescriptor();
ld.element = a; ld.sId = sId; ld.nIndex = nOutFileIndex;
links.add(ld);
return a;
}
// create a link
public Element createLink(Element onode) {
// First create the anchor
String sHref = onode.getAttribute(XMLString.XLINK_HREF);
Element anchor;
if (sHref.startsWith("#")) { // internal link
anchor = createLink(sHref.substring(1));
}
else { // external link
anchor = htmlDOM.createElement("a");
sHref = ofr.fixRelativeLink(sHref);
// Workaround for an OOo problem:
if (sHref.indexOf("?")==-1) { // No question mark
int n3F=sHref.indexOf("%3F");
if (n3F>0) { // encoded question mark
sHref = sHref.substring(0,n3F)+"?"+sHref.substring(n3F+3);
}
}
anchor.setAttribute("href",sHref);
String sName = Misc.getAttribute(onode,XMLString.OFFICE_NAME);
if (sName!=null) {
// The name attribute is rarely use (usually the user will insert a bookmark)
// Hence we (mis)use it to set additional attributes that are not supported by OOo
if (sName.indexOf(";")==-1 && sName.indexOf("=")==-1) {
// Simple case, use the value to set name and title
anchor.setAttribute("name",sName);
anchor.setAttribute("title",sName);
}
else {
// Complex case - using the syntax: name=value;name=value;...
String[] sElements = sName.split(";");
for (String sElement : sElements) {
String[] sNameVal = sElement.split("=");
if (sNameVal.length>=2) {
anchor.setAttribute(sNameVal[0].trim(),sNameVal[1].trim());
}
}
}
}
// TODO: target has been deprecated in xhtml 1.0 strict
String sTarget = Misc.getAttribute(onode,XMLString.OFFICE_TARGET_FRAME_NAME);
if (sTarget!=null) { anchor.setAttribute("target",sTarget); }
}
// Then style it
String sStyleName = onode.getAttribute(XMLString.TEXT_STYLE_NAME);
String sVisitedStyleName = onode.getAttribute(XMLString.TEXT_VISITED_STYLE_NAME);
StyleInfo anchorInfo = new StyleInfo();
styleCv.getTextSc().applyAnchorStyle(sStyleName,sVisitedStyleName,anchorInfo);
styleCv.getTextSc().applyStyle(anchorInfo,anchor);
return anchor;
}
private void createMeta(Element head, String sName, String sValue) {
if (sValue==null) { return; }
Element meta = htmlDOM.createElement("meta");
meta.setAttribute("name",sName);
meta.setAttribute("content",sValue);
head.appendChild(meta);
}
}

View file

@ -0,0 +1,110 @@
/************************************************************************
*
* ConverterHelper.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-15)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import writer2latex.office.OfficeReader;
/** A <code>ConverterHelper</code> is responsible for conversion of some specific content into XHTML.
*/
class ConverterHelper {
// Member variables providing our content (set in constructor)
OfficeReader ofr;
XhtmlConfig config;
Converter converter;
/** Construct a new converter helper based on a
*
* @param ofr the office reader used to access the source document
* @param config the configuration to use
* @param converter the main converter to which the helper belongs
*/
ConverterHelper(OfficeReader ofr, XhtmlConfig config, Converter converter) {
this.ofr = ofr;
this.config = config;
this.converter = converter;
}
// Convenience accessor methods to other converter helpers (only needed to save some typing)
StyleConverter getStyleCv() { return converter.getStyleCv(); }
TextStyleConverter getTextSc() { return converter.getStyleCv().getTextSc(); }
ParStyleConverter getParSc() { return converter.getStyleCv().getParSc(); }
HeadingStyleConverter getHeadingSc() { return converter.getStyleCv().getHeadingSc(); }
ListStyleConverter getListSc() { return converter.getStyleCv().getListSc(); }
SectionStyleConverter getSectionSc() { return converter.getStyleCv().getSectionSc(); }
TableStyleConverter getTableSc() { return converter.getStyleCv().getTableSc(); }
RowStyleConverter getRowSc() { return converter.getStyleCv().getRowSc(); }
CellStyleConverter getCellSc() { return converter.getStyleCv().getCellSc(); }
FrameStyleConverter getFrameSc() { return converter.getStyleCv().getFrameSc(); }
PresentationStyleConverter getPresentationSc() { return converter.getStyleCv().getPresentationSc(); }
PageStyleConverter getPageSc() { return converter.getStyleCv().getPageSc(); }
TextConverter getTextCv() { return converter.getTextCv(); }
TableConverter getTableCv() { return converter.getTableCv(); }
DrawConverter getDrawCv() { return converter.getDrawCv(); }
MathConverter getMathCv() { return converter.getMathCv(); }
/** Apply style information to an XHTML node
*
* @param info the style to apply
* @param hnode the XHTML node
*/
void applyStyle(StyleInfo info, Element hnode) {
if (info.sClass!=null) {
hnode.setAttribute("class",info.sClass);
}
if (!info.props.isEmpty()) {
hnode.setAttribute("style",info.props.toString());
}
if (info.sLang!=null) {
hnode.setAttribute("xml:lang",info.sLang);
if (converter.getType()==XhtmlDocument.XHTML10 || converter.getType()==XhtmlDocument.HTML5) {
hnode.setAttribute("lang",info.sLang); // HTML4 compatibility/polyglot HTML5S
}
}
if (info.sDir!=null) {
hnode.setAttribute("dir",info.sDir);
}
}
}

View file

@ -0,0 +1,102 @@
/************************************************************************
*
* CssDocument.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-05-05)
*
*/
package writer2latex.xhtml;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import writer2latex.api.OutputFile;
/**
* An implementation of <code>OutputFile</code> for CSS documents.
* (Actually this is a trivial implementation which never parses the files)
*/
public class CssDocument implements OutputFile {
// Content
private String sName;
private String sContent;
/**
* Constructor (creates an empty document)
* @param sName <code>Document</code> name.
*/
public CssDocument(String sName) {
this.sName = sName;
sContent = "";
}
public String getFileName() {
return sName;
}
public String getMIMEType() {
return "text/css";
}
public boolean isMasterDocument() {
return false;
}
public boolean containsMath() {
return false;
}
public void write(OutputStream os) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
osw.write(sContent);
osw.flush();
osw.close();
}
public void read(InputStream is) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8"));
StringBuilder buf = new StringBuilder();
String sLine;
while ((sLine=reader.readLine())!=null) {
buf.append(sLine).append('\n');
}
sContent = buf.toString();
}
public void read(String s) {
sContent = s;
}
}

View file

@ -0,0 +1,23 @@
package writer2latex.xhtml;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
public class Debug {
public static void printNode(Node node){
Document document = node.getOwnerDocument();
DOMImplementationLS domImplLS = (DOMImplementationLS) document
.getImplementation();
LSSerializer serializer = domImplLS.createLSSerializer();
String str = serializer.writeToString(node);
System.out.println(str);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
/************************************************************************
*
* EndnoteConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-12)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
class EndnoteConverter extends NoteConverter {
EndnoteConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter,ofr.getEndnotesConfiguration());
}
/** Insert all the endnotes
*
* @param hnode a block HTML element to contain the endnotes
*/
void insertEndnotes(Node hnode) {
if (hasNotes()) {
if (config.getXhtmlSplitLevel()>0) { hnode = converter.nextOutFile(); }
Element section = createNoteSection(hnode, "rearnotes");
insertNoteHeading(section, config.getEndnotesHeading(), "endnotes");
flushNotes(section,"rearnote");
}
}
}

View file

@ -0,0 +1,77 @@
/************************************************************************
*
* FootnoteConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-14)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
import writer2latex.office.PropertySet;
import writer2latex.office.XMLString;
class FootnoteConverter extends NoteConverter {
// Footnote position (can be page or document)
private boolean bFootnotesAtPage = true;
FootnoteConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter,ofr.getFootnotesConfiguration());
PropertySet configuration=ofr.getFootnotesConfiguration();
if (configuration!=null) {
bFootnotesAtPage = !"document".equals(configuration.getProperty(XMLString.TEXT_FOOTNOTES_POSITION));
}
}
/** Insert the footnotes gathered so far. Export will only happen if the source document configures footnotes
* per page, or if this is the final call of the method.
*
* @param hnode a block HTML element to contain the footnotes
* @param bFinal true if this is the final call
*/
void insertFootnotes(Node hnode, boolean bFinal) {
if (hasNotes()) {
if (bFootnotesAtPage) {
Element section = createNoteSection(hnode, "footnotes");
// Add footnote rule
Element rule = converter.createElement("hr");
StyleInfo info = new StyleInfo();
getPageSc().applyFootnoteRuleStyle(info);
getPageSc().applyStyle(info, rule);
section.appendChild(rule);
flushNotes(section,"footnote");
}
else if (bFinal) {
// New page if required for footnotes as endnotes
if (config.getXhtmlSplitLevel()>0) { hnode = converter.nextOutFile(); }
Element section = createNoteSection(hnode, "footnotes");
insertNoteHeading(section, config.getFootnotesHeading(), "footnotes");
flushNotes(section,"footnote");
}
}
}
}

View file

@ -0,0 +1,301 @@
/************************************************************************
*
* FrameStyleConverter.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.4 (2014-09-16)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.Calc;
//import writer2latex.util.Misc;
import writer2latex.util.SimpleInputBuffer;
/**
* This class converts OpenDocument graphic (frame) styles to CSS2 styles.
* This includes conversion of frame properties in other styles (paragraph,
* cell, section, page and presentation styles).
*/
public class FrameStyleConverter extends StyleWithPropertiesConverterHelper {
/** Create a new <code>FrameStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public FrameStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
this.styleMap = config.getXFrameStyleMap();
this.bConvertStyles = config.xhtmlFrameFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFrameFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlFrameFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFrameFormatting()==XhtmlConfig.IGNORE_STYLES;
}
/** Convert style information for used styles
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
if (bConvertStyles) {
StringBuilder buf = new StringBuilder();
buf.append(super.getStyleDeclarations(sIndent));
Enumeration<String> names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = names.nextElement();
StyleWithProperties style = (StyleWithProperties)
getStyles().getStyleByDisplayName(sDisplayName);
if (!style.isAutomatic()) {
// Apply style to paragraphs contained in this frame
CSVList props = new CSVList(";");
getFrameSc().cssMargins(style,props,true);
getParSc().cssPar(style,props,true);
getTextSc().cssTextCommon(style,props,true);
if (!props.isEmpty()) {
buf.append(sIndent)
.append(getDefaultTagName(null))
.append(".").append(getClassNamePrefix())
.append(styleNames.getExportName(sDisplayName))
.append(" p {").append(props.toString()).append("}").append(config.prettyPrint() ? "\n" : " ");
}
}
}
return buf.toString();
}
else {
return "";
}
}
/** Return a prefix to be used in generated css class names
* @return the prefix
*/
public String getClassNamePrefix() { return "frame"; }
/** Get the family of frame styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getFrameStyles();
}
/** Create default tag name to represent a frame
* @param style to use
* @return the tag name.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "";
}
/** Convert formatting properties for a specific frame style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
cssBox(style,props,bInherit);
getTextSc().cssTextCommon(style,props,bInherit); // only in presentations
}
////////////////////////////////////////////////////////////////////////////
// OpenDocument frame properties
public void cssBox(StyleWithProperties style, CSVList props, boolean bInherit){
// translates "box" style properties.
// these can be applied to paragraph styles, frame styles and page styles.
// The following properties are not supported by CSS2:
// style:border-line-width and style:border-line-width-*
// TODO: What about shadow?
cssMargins(style,props,bInherit);
cssBorder(style,props,bInherit);
cssPadding(style,props,bInherit);
cssBackground(style,props,bInherit);
}
public void cssMargins(StyleWithProperties style, CSVList props, boolean bInherit){
// *Absolute* values fit with css
String s;
if (bInherit || style.getProperty(XMLString.FO_MARGIN_LEFT,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_LEFT);
if (s!=null) { props.addValue("margin-left",scale(s)); }
else { props.addValue("margin-left","0"); }
}
if (bInherit || style.getProperty(XMLString.FO_MARGIN_RIGHT,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_RIGHT);
if (s!=null) { props.addValue("margin-right",scale(s)); }
else { props.addValue("margin-right","0"); }
}
if (bInherit || style.getProperty(XMLString.FO_MARGIN_TOP,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_TOP);
if (s!=null) { props.addValue("margin-top",scale(s)); }
else { props.addValue("margin-top","0"); }
}
if (bInherit || style.getProperty(XMLString.FO_MARGIN_BOTTOM,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_BOTTOM);
if (s!=null) { props.addValue("margin-bottom",scale(s)); }
else { props.addValue("margin-bottom","0"); }
}
}
public void cssBorder(StyleWithProperties style, CSVList props, boolean bInherit){
// Same as in css
boolean bHasBorder = false;
String s=null;
if (bInherit || style.getProperty(XMLString.FO_BORDER,false)!=null) {
s = style.getProperty(XMLString.FO_BORDER);
}
if (s!=null) {
props.addValue("border",borderScale(s)); bHasBorder = true;
}
else { // apply individual borders
if (bInherit || style.getProperty(XMLString.FO_BORDER_TOP,false)!=null) {
s = style.getProperty(XMLString.FO_BORDER_TOP);
if (s!=null) { props.addValue("border-top",borderScale(s)); bHasBorder=true; }
}
if (bInherit || style.getProperty(XMLString.FO_BORDER_BOTTOM,false)!=null) {
s = style.getProperty(XMLString.FO_BORDER_BOTTOM);
if (s!=null) { props.addValue("border-bottom",borderScale(s)); bHasBorder=true; }
}
if (bInherit || style.getProperty(XMLString.FO_BORDER_LEFT,false)!=null) {
s = style.getProperty(XMLString.FO_BORDER_LEFT);
if (s!=null) { props.addValue("border-left",borderScale(s)); bHasBorder=true; }
}
if (bInherit || style.getProperty(XMLString.FO_BORDER_RIGHT,false)!=null) {
s = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (s!=null) { props.addValue("border-right",borderScale(s)); bHasBorder=true; }
}
}
// Default to no border:
if (bInherit && !bHasBorder) { props.addValue("border","none"); }
}
public void cssPadding(StyleWithProperties style, CSVList props, boolean bInherit){
// *Absolute* values fit with css
String s=null;
if (bInherit || style.getProperty(XMLString.FO_PADDING,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_PADDING);
}
if (s!=null) {
props.addValue("padding",scale(s));
}
else { // apply individual paddings
boolean bTop = false;
boolean bBottom = false;
boolean bLeft = false;
boolean bRight = false;
if (bInherit || style.getProperty(XMLString.FO_PADDING_TOP,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_PADDING_TOP);
if (s!=null) { props.addValue("padding-top",scale(s)); bTop=true; }
}
if (bInherit || style.getProperty(XMLString.FO_PADDING_BOTTOM,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_PADDING_BOTTOM);
if (s!=null) { props.addValue("padding-bottom",scale(s)); bBottom=true; }
}
if (bInherit || style.getProperty(XMLString.FO_PADDING_LEFT,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_PADDING_LEFT);
if (s!=null) { props.addValue("padding-left",scale(s)); bLeft=true; }
}
if (bInherit || style.getProperty(XMLString.FO_PADDING_RIGHT,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_PADDING_RIGHT);
if (s!=null) { props.addValue("padding-right",scale(s)); bRight=true; }
}
if (bInherit) { // must specify padding
if (!bTop && !bBottom && !bLeft && !bRight) {
props.addValue("padding","0");
}
else {
if (!bTop) { props.addValue("padding-top","0"); }
if (!bBottom) { props.addValue("padding-bottom","0"); }
if (!bLeft) { props.addValue("padding-left","0"); }
if (!bRight) { props.addValue("padding-right","0"); }
}
}
}
}
// parapgrah styles need this for special treatment of background color
public void cssBackgroundCommon(StyleWithProperties style, CSVList props, boolean bInherit){
// Background image:
String sUrl = style.getBackgroundImageProperty(XMLString.XLINK_HREF);
if (sUrl!=null) { // currently only support for linked image
props.addValue("background-image","url("+escapeUrl(sUrl)+")");
String sRepeat = style.getBackgroundImageProperty(XMLString.STYLE_REPEAT);
if ("no-repeat".equals(sRepeat) || "stretch".equals(sRepeat)) {
props.addValue("background-repeat","no-repeat");
}
else {
props.addValue("background-repeat","repeat");
}
String sPosition = style.getBackgroundImageProperty(XMLString.STYLE_POSITION);
if (sPosition!=null) { props.addValue("background-position",sPosition); }
}
}
public void cssBackground(StyleWithProperties style, CSVList props, boolean bInherit){
// Background color: Same as in css
String s = style.getProperty(XMLString.FO_BACKGROUND_COLOR,bInherit);
if (s!=null) { props.addValue("background-color",s); }
cssBackgroundCommon(style,props,bInherit);
}
// Scale the border with while preserving the rest of the attribute
public String borderScale(String sBorder) {
SimpleInputBuffer in = new SimpleInputBuffer(sBorder);
StringBuilder out = new StringBuilder();
while (in.peekChar()!='\0') {
// Skip spaces
while(in.peekChar()==' ') { out.append(" "); in.getChar(); }
// If it's a number it must be a unit -> convert it
if ('0'<=in.peekChar() && in.peekChar()<='9') {
String sDim = scale(in.getNumber()+in.getIdentifier());
// Do not output a border less than 1px wide - some browsers will render it invisible
out.append(Calc.isLessThan(sDim, "1px") ? "1px" : sDim);
}
// skip other characters
while (in.peekChar()!=' ' && in.peekChar()!='\0') {
out.append(in.getChar());
}
}
return out.toString();
}
// Must escape certain characters in the url property
private String escapeUrl(String sUrl) {
StringBuilder buf = new StringBuilder();
int nLen = sUrl.length();
for (int i=0; i<nLen; i++) {
char c = sUrl.charAt(i);
if (c=='\'' || c=='"' || c=='(' || c==')' || c==',' || c==' ') {
buf.append("\\");
}
buf.append(c);
}
return buf.toString();
}
}

View file

@ -0,0 +1,236 @@
package writer2latex.xhtml;
import java.util.LinkedList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
//LinkedList<String> stringList = new LinkedList<String>();
public class GreenstoneTags {
private static final String NONE = "none";
private static final String SECTIONS = "sections";
private static final String DIV = "div";
private static LinkedList<Integer> headerStack = new LinkedList<Integer>();
private static boolean pageOpened = false;
//headings none
private static String headingTags = "headings";
//sections div none
private static String pageTags = "sections";
protected static Node processHeading(Node currentNode, Node hnode, int pageNum) {
//Get outline level
String sLevel = Misc.getAttribute(currentNode, XMLString.TEXT_OUTLINE_LEVEL);
if (sLevel == null || sLevel.isEmpty()) {
return hnode;
}
int nLevel = Integer.parseInt(sLevel);
if (pageOpened) {
hnode = closePage(hnode);
}
if (headingTags.equals(SECTIONS)){
closeHeadingSections(hnode, nLevel);
String title = getTitle(currentNode);
openHeadingSection(hnode, title);
headerStack.offerFirst(Integer.parseInt(sLevel));
}
if (!pageTags.equals(NONE)){
hnode = openPage(hnode, pageNum);
}
return hnode;
}
protected static Node processPageBreak(Node currentNode, Node hnode, Integer pageNum){
if (pageTags.equals(NONE)){
return hnode;
}
if (pageOpened) {
hnode = closePage(hnode);
}
hnode = openPage(hnode, pageNum);
return hnode;
}
/**
* Opens main document section heading tag
*/
protected static Node StartDocument(Node hnode, String title, String heading, String pages, int pageNum){
headingTags = heading;
pageTags = pages;
if (headingTags.equals(NONE) && pageTags.equals(NONE)){
return hnode;
}
if(headingTags.equals(SECTIONS)){
//Create global section
openHeadingSection(hnode, title);
}
hnode = openPage(hnode, pageNum);
return hnode;
}
//Method to close open tags at the end of the document
protected static Node endDocument(Node hnode){
if (headingTags.equals(NONE) && pageTags.equals(NONE)){
return hnode;
}
if (pageOpened){
hnode = closePage(hnode);
}
if (headingTags.equals(SECTIONS)){
closeHeadingSections(hnode, 0);
//Close global section
closeSection(hnode);
}
return hnode;
}
private static Node openPageDiv(Node hnode,int pageNum){
if (hnode == null){
return hnode;
}
Document doc = hnode.getOwnerDocument();
Element openBlock = (Element) doc.createElement("div");
openBlock.setAttribute("class", "pageNum");
openBlock.setAttribute("page", Integer.toString(pageNum));
// insert open section comment before header node
hnode.appendChild((Node)openBlock);
hnode = openBlock;
return openBlock;
}
private static Node exitPageDiv(Node hnode){
while ( hnode.getParentNode() != null
&&
!(
hnode.getNodeType() == Node.ELEMENT_NODE
&&
((Element) hnode).getTagName().equals("div")
)
){
hnode = hnode.getParentNode();
}
Node result = hnode.getParentNode();
if (hnode.getChildNodes().getLength() == 0){
result.removeChild(hnode);
}
return result;
}
private static String getTitle(Node currentNode) {
Node content = currentNode.cloneNode(true);
NodeList contentNodes = content.getChildNodes();
String title = null;
int i = 0;
while (i < contentNodes.getLength()) {
Node child = contentNodes.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE){
if (child.getNodeName().equals(XMLString.TEXT_TAB) ||
child.getNodeName().equals(XMLString.TEXT_LINE_BREAK) ){
Document doc = child.getOwnerDocument();
Node testSpace = doc.createTextNode(" ");
content.insertBefore(testSpace, child);
content.removeChild(child);
}
}
i++;
}
NodeList notes = ((Element) content).getElementsByTagName(XMLString.TEXT_NOTE);
int j = 0;
while (j < notes.getLength()){
Node note = notes.item(j);
note.getParentNode().removeChild(note);
}
title = content.getTextContent();
return title;
}
private static void openPageSection(Node hnode, Integer pageNum){
Document doc = hnode.getOwnerDocument();
String commentText = "<Section>\n<Description>\n<Metadata name=\"Title\">" + pageNum
+ "</Metadata>\n<Metadata name=\"Page\">" + pageNum + "</Metadata>\n</Description>";
Node openSection = doc.createComment(commentText);
// insert open section comment before header node
hnode.appendChild(openSection);
}
private static void openHeadingSection(Node hnode, String title){
Document doc = hnode.getOwnerDocument();
String commentText = "<Section>\n<Description>\n<Metadata name=\"Title\">" + title
+ "</Metadata>\n</Description>";
Node openSection = doc.createComment(commentText);
// insert open section comment before header node
hnode.appendChild(openSection);
}
private static void closeSection(Node hnode){
Document doc = hnode.getOwnerDocument();
String commentText = "</Section>";
Node closeSection = doc.createComment(commentText);
//insert open section comment before header node
hnode.appendChild(closeSection);
}
private static void closeHeadingSections(Node hnode, int nLevel){
if (headerStack.isEmpty()) {
return;
}
//Close all sections with level less than current
while (nLevel <= headerStack.peek()) {
closeSection(hnode);
headerStack.poll();
if (headerStack.isEmpty()) {
break;
}
}
}
protected static Node closePage(Node hnode){
if (pageTags.equals(SECTIONS)){
//If section is empty. In case we are closing section
// the last comment is opened page section
if (hnode.getLastChild().getNodeType() == Node.COMMENT_NODE){
hnode.removeChild(hnode.getLastChild());
} else {
closeSection(hnode);
}
} else if (pageTags.equals(DIV)){
hnode = exitPageDiv(hnode);
}
pageOpened = false;
return hnode;
}
protected static Node openPage(Node hnode, Integer pageNum){
if (pageTags.equals(SECTIONS)){
openPageSection(hnode, pageNum);
pageOpened = true;
}
else if (pageTags.equals(DIV)){
hnode = openPageDiv(hnode, pageNum);
pageOpened = true;
}
return hnode;
}
}

View file

@ -0,0 +1,154 @@
/************************************************************************
*
* HeadingStyleConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-10)
*
*/
package writer2latex.xhtml;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.util.CSVList;
public class HeadingStyleConverter extends StyleConverterHelper {
// Sets of additional styles (other than the main heading style for the level)
private List<Set<String>> otherLevelStyles;
public HeadingStyleConverter(OfficeReader ofr, XhtmlConfig config,
Converter converter, int nType) {
super(ofr, config, converter, nType);
this.styleMap = config.getXHeadingStyleMap();
this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
this.otherLevelStyles = new ArrayList<Set<String>>();
for (int i=0; i<=6; i++) {
otherLevelStyles.add(new HashSet<String>());
}
}
@Override
public String getStyleDeclarations(String sIndent) {
if (bConvertStyles) {
StringBuilder buf = new StringBuilder();
for (int i=1; i<=6; i++) {
// Convert main style for this level
if (ofr.getHeadingStyle(i)!=null) {
CSVList props = new CSVList(";");
getParSc().applyProperties(ofr.getHeadingStyle(i),props,true);
props.addValue("clear","left");
buf.append(sIndent).append("h").append(i)
.append(" {").append(props.toString()).append("}").append(config.prettyPrint() ? "\n" : " ");
}
// Convert other styles for this level
for (String sDisplayName : otherLevelStyles.get(i)) {
StyleWithProperties style = (StyleWithProperties)
getStyles().getStyleByDisplayName(sDisplayName);
CSVList props = new CSVList(";");
getParSc().applyProperties(style,props,true);
props.addValue("clear","left");
buf.append(sIndent).append("h").append(i).append(".").append(styleNames.getExportName(sDisplayName))
.append(" {").append(props.toString()).append("}").append(config.prettyPrint() ? "\n" : " ");
}
}
return buf.toString();
}
return "";
}
@Override
public OfficeStyleFamily getStyles() {
return ofr.getParStyles();
}
/** Apply a style on a heading
*
* @param nLevel the heading level
* @param sStyleName the style name
* @param info add style information to this StyleInfo
*/
public void applyStyle(int nLevel, String sStyleName, StyleInfo info) {
StyleWithProperties style = (StyleWithProperties) getStyles().getStyle(sStyleName);
if (style!=null) {
if (config.multilingual()) { applyLang(style,info); }
applyDirection(style,info);
if (style.isAutomatic()) {
// Apply parent style + hard formatting
applyStyle(nLevel, style.getParentName(),info);
if (bConvertHard) { getParSc().applyProperties(style,info.props,false); }
}
else {
String sDisplayName = style.getDisplayName();
if (styleMap.contains(sDisplayName)) {
// Apply attributes as specified in style map from user
XhtmlStyleMapItem map = styleMap.get(sDisplayName);
info.sTagName = map.sBlockElement;
if (!"(none)".equals(map.sBlockCss)) {
info.sClass = map.sBlockCss;
}
}
else if (style!=ofr.getHeadingStyle(nLevel)) {
// This is not the main style for this level, add class and remember
info.sClass = styleNames.getExportName(sDisplayName);
if (1<=nLevel && nLevel<=6) {
otherLevelStyles.get(nLevel).add(sDisplayName);
}
}
}
}
}
/** Apply an inner style on a heading. The inner style surrounds the text content, excluding the numbering label.
* Inner styles are not an OpenDocument feature, but is provided as an additional style hook for own style sheets.
* An inner style is only applied if there is an explicit style map for the style.
*
* @param nLevel the heading level
* @param sStyleName the style name
* @param info add style information to this StyleInfo
*/
public void applyInnerStyle(int nLevel, String sStyleName, StyleInfo info) {
StyleWithProperties style = (StyleWithProperties) getStyles().getStyle(sStyleName);
if (style!=null) {
if (style.isAutomatic()) {
// Apply parent style
applyInnerStyle(nLevel, style.getParentName(), info);
}
else {
String sDisplayName = style.getDisplayName();
if (styleMap.contains(sDisplayName)) {
// Apply attributes as specified in style map from user
XhtmlStyleMapItem map = styleMap.get(sDisplayName);
info.sTagName = map.sElement;
if (!"(none)".equals(map.sCss)) {
info.sClass = map.sCss;
}
}
}
}
}
}

View file

@ -0,0 +1,34 @@
/************************************************************************
*
* Html5Converter.java
*
* Copyright: 2002-2012 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.4 (2012-03-28)
*
*/
package writer2latex.xhtml;
public class Html5Converter extends Converter {
public Html5Converter() {
super(XhtmlDocument.HTML5);
}
}

View file

@ -0,0 +1,124 @@
/************************************************************************
*
* IndexConverterBase.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-16)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
/** This is a base class for conversion of indexes (table of contents, bibliography, alphabetical index,
* list of tables, list of figures)
*/
abstract class IndexConverterHelper extends ConverterHelper {
private String sEpubType;
private String sSourceName;
/** Construct a new index converter
*
* @param ofr the office reader used to read the source document
* @param config the configuration
* @param converter the converter
* @param sSourceName the name of the source data element in the index
* @param sEpubType the EPUB 3 semantic type of the index
*/
IndexConverterHelper(OfficeReader ofr, XhtmlConfig config, Converter converter,
String sSourceName, String sEpubType) {
super(ofr,config,converter);
this.sSourceName = sSourceName;
this.sEpubType = sEpubType;
}
/** Generate the actual contents of the index
*
* @param source the index source
* @param container an ul element to populate with list items
*/
abstract void populateIndex(Element source, Element container);
/** Handle an index
*
* @param onode an index node
* @param hnode the index will be added to this block HTML node
*/
void handleIndex(Element onode, Element hnode) {
Element source = Misc.getChildByTagName(onode,sSourceName);
if (source!=null) {
Element container = createContainer(onode, hnode);
generateTitle(source, container);
generateIndex(source, container);
}
}
// Create a container node for the index
private Element createContainer(Element source, Element hnode) {
Element container = converter.createElement(converter.isHTML5() ? "section" : "div");
hnode.appendChild(container);
converter.addEpubType(container, sEpubType);
String sName = source.getAttribute(XMLString.TEXT_NAME);
if (sName!=null) {
converter.addTarget(container,sName);
}
String sStyleName = source.getAttribute(XMLString.TEXT_STYLE_NAME);
if (sStyleName!=null) {
StyleInfo sectionInfo = new StyleInfo();
getSectionSc().applyStyle(sStyleName,sectionInfo);
applyStyle(sectionInfo,container);
}
return container;
}
// Generate the index title and add it to the container
private void generateTitle(Element source, Element container) {
Node title = Misc.getChildByTagName(source,XMLString.TEXT_INDEX_TITLE_TEMPLATE);
if (title!=null) {
Element h1 = converter.createElement("h1");
container.appendChild(h1);
String sStyleName = Misc.getAttribute(title,XMLString.TEXT_STYLE_NAME);
StyleInfo info = new StyleInfo();
info.sTagName = "h1";
getHeadingSc().applyStyle(1, sStyleName, info);
applyStyle(info,h1);
getTextCv().traversePCDATA(title,h1);
}
}
// Generate the index and add it to the container
private void generateIndex(Element source, Element container) {
Element ul = converter.createElement("ul");
// TODO: Support column formatting from the index source
ul.setAttribute("style", "list-style-type:none;margin:0;padding:0");
container.appendChild(ul);
populateIndex(source,ul);
}
}

View file

@ -0,0 +1,41 @@
/************************************************************************
*
* LOFConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-10)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
public class LOFConverter extends ConverterHelper {
public LOFConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter);
}
public void handleLOF(Node onode, Node hnode) {
// TODO
}
}

View file

@ -0,0 +1,41 @@
/************************************************************************
*
* LOTConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-10)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
public class LOTConverter extends ConverterHelper {
public LOTConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter);
}
public void handleLOT(Node onode, Node hnode) {
// TODO
}
}

View file

@ -0,0 +1,39 @@
/************************************************************************
*
* LinkDescriptor.java
*
* Copyright: 2002-2007 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 0.5 (2007-07-27)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
/**
* Helper class (a struct) to contain information about a Link (used to manage
* links to be resolved later)
*/
final class LinkDescriptor {
Element element; // the a-element
String sId; // the id to link to
int nIndex; // the index of *this* file
}

View file

@ -0,0 +1,212 @@
/************************************************************************
*
* ListStyleConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-03)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
//import java.util.Hashtable;
import writer2latex.office.ListStyle;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
/**
* This class converts OpenDocument list styles to
* CSS2 styles (currently, actually CSS1).
*/
public class ListStyleConverter extends StyleConverterHelper {
/** Create a new <code>ListStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public ListStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
this.styleMap = config.getXListStyleMap();
this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
}
public void applyStyle(int nLevel, String sStyleName, StyleInfo info) {
ListStyle style = ofr.getListStyle(sStyleName);
if (style!=null) {
if (style.isAutomatic()) {
applyStyle(nLevel,style.getParentName(),info);
if (bConvertHard) { cssList(style,nLevel,info.props); }
}
else {
String sDisplayName = style.getDisplayName();
if (styleMap.contains(sDisplayName)) {
XhtmlStyleMapItem map = styleMap.get(sDisplayName);
if (map.sElement.length()>0) {
info.sTagName = map.sElement;
}
if (!"(none)".equals(map.sCss)) {
info.sClass = map.sCss;
}
}
else {
info.sClass = "listlevel"+Integer.toString(nLevel)
+styleNames.getExportName(sDisplayName);
}
}
}
}
/** <p>Convert style information for used styles</p>
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
if (bConvertStyles) {
StringBuilder buf = new StringBuilder();
Enumeration<String> names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = names.nextElement();
ListStyle style = (ListStyle)
getStyles().getStyleByDisplayName(sDisplayName);
if (!style.isAutomatic()) {
for (int nLevel=1; nLevel<10; nLevel++) {
CSVList props = new CSVList(";");
cssList(style,nLevel,props);
buf.append(sIndent);
buf.append(".listlevel");
buf.append(nLevel);
buf.append(styleNames.getExportName(sDisplayName));
buf.append(" {");
buf.append(props.toString());
buf.append("}");
buf.append(config.prettyPrint() ? "\n" : " ");
if (config.listFormatting()==XhtmlConfig.HARD_LABELS) {
// Apply left margin and text indent to the paragraphs contained in the list
CSVList parProps = new CSVList(";");
cssListParMargins(style,nLevel,parProps);
if (!parProps.isEmpty()) {
buf.append(sIndent)
.append(".listlevel")
.append(nLevel)
.append(styleNames.getExportName(sDisplayName))
.append(" p {").append(parProps.toString()).append("}").append(config.prettyPrint() ? "\n" : " ");
}
}
}
}
}
return buf.toString();
}
else {
return "";
}
}
/** Get the family of list styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getListStyles();
}
private void cssList(ListStyle style, int nLevel, CSVList props){
// translates "list" style properties for a particular level
// Mozilla does not seem to support the "marker" mechanism of CSS2
// so we will stick with the simpler CSS1-like list style properties
props.addValue("margin-top","0");
props.addValue("margin-bottom","0");
if (config.listFormatting()!=XhtmlConfig.HARD_LABELS) {
// Export the numbering to CSS1
String sLevelType = style.getLevelType(nLevel);
if (XMLString.TEXT_LIST_LEVEL_STYLE_NUMBER.equals(sLevelType)) {
// Numbering style, get number format
String sNumFormat = style.getLevelProperty(nLevel,XMLString.STYLE_NUM_FORMAT);
if ("1".equals(sNumFormat)) { props.addValue("list-style-type","decimal"); }
else if ("i".equals(sNumFormat)) { props.addValue("list-style-type","lower-roman"); }
else if ("I".equals(sNumFormat)) { props.addValue("list-style-type","upper-roman"); }
else if ("a".equals(sNumFormat)) { props.addValue("list-style-type","lower-alpha"); }
else if ("A".equals(sNumFormat)) { props.addValue("list-style-type","upper-alpha"); }
}
else if (XMLString.TEXT_LIST_LEVEL_STYLE_BULLET.equals(sLevelType)) {
// Bullet. We can only choose from disc, bullet and square
switch (nLevel % 3) {
case 1: props.addValue("list-style-type","disc"); break;
case 2: props.addValue("list-style-type","circle"); break;
case 0: props.addValue("list-style-type","square"); break;
}
}
else if (XMLString.TEXT_LIST_LEVEL_STYLE_IMAGE.equals(sLevelType)) {
// Image. TODO: Handle embedded images
String sHref = style.getLevelProperty(nLevel,XMLString.XLINK_HREF);
if (sHref!=null) { props.addValue("list-style-image","url('"+sHref+"')"); }
}
}
else {
// No numbering generated by the list; we add hard numbering to the paragraph
props.addValue("list-style-type:none");
// In this case we also set the left margin for the list
// For real styles the margins are applied to the paragraphs
// This is more tricky for hard styles, so we use a default left margin on the list
if (style.isAutomatic() && nLevel>1) {
props.addValue("margin-left", "2em");
}
else {
props.addValue("margin-left","0");
}
// Also reset the padding (some browsers use a non-zero default value)
props.addValue("padding-left", "0");
}
// We don't want floats to pass a list to the left (Mozilla and IE both
//handles this terribly!)
props.addValue("clear:left");
}
private void cssListParMargins(ListStyle style, int nLevel, CSVList props){
// Instead margin is applied to the paragraphs in the list, more precisely the list style defines a
// left margin and a text indent to *replace* the values from the paragraph style
String sMarginLeft = style.getLevelStyleProperty(nLevel, XMLString.FO_MARGIN_LEFT);
if (sMarginLeft!=null) {
props.addValue("margin-left", sMarginLeft);
}
else {
props.addValue("margin-left", "0");
}
String sTextIndent = style.getLevelStyleProperty(nLevel, XMLString.FO_TEXT_INDENT);
if (sTextIndent!=null) {
props.addValue("text-indent", sTextIndent);
}
else {
props.addValue("text-indent", "0");
}
}
}

View file

@ -0,0 +1,373 @@
/************************************************************************
*
* MathConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-05-05)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import writer2latex.office.*;
import writer2latex.util.Misc;
import writer2latex.base.BinaryGraphicsDocument;
import writer2latex.latex.StarMathConverter;
/** This class converts formulas: Either as MathML, as an image or as plain text (StarMath or LaTeX format)
*/
public class MathConverter extends ConverterHelper {
private StarMathConverter smc = null;
private boolean bSupportMathML;
private boolean bUseImage;
private boolean bUseLaTeX;
/** Create a new <code>MathConverter</code>
*
* @param ofr the OfficeReader to query about the document
* @param config the configuration determining the type of export
* @param converter the converter instance
* @param bSupportMathML true if the formula should be exported as MathML
*/
public MathConverter(OfficeReader ofr, XhtmlConfig config, Converter converter,
boolean bSupportMathML) {
super(ofr,config,converter);
this.bSupportMathML = bSupportMathML;
this.bUseImage = config.formulas()==XhtmlConfig.IMAGE_LATEX || config.formulas()==XhtmlConfig.IMAGE_STARMATH;
this.bUseLaTeX = config.formulas()==XhtmlConfig.IMAGE_LATEX || config.formulas()==XhtmlConfig.LATEX;
if (bUseLaTeX) { smc = new StarMathConverter(); }
}
/** Convert a formula
*
* @param image image version of the formula (or null if no image is available)
* @param onode the math node
* @param hnode the xhtml node to which content should be added
*/
public void convert(Element image, Element onode, Node hnode, boolean bAllowDisplayStyle) {
if (bSupportMathML) {
convertAsMathML(onode,hnode,bAllowDisplayStyle);
}
else {
convertAsImageOrText(image,onode,hnode);
}
}
public boolean convertTexMathsEquation(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
// If possible, add the object inline. In pure block context, add a div.
Element hnode;
if (hnodeInline!=null) {
hnode = hnodeInline;
}
else {
Element div = converter.createElement("div");
hnodeBlock.appendChild(div);
hnode = div;
}
String sLaTeX = null;
Element equation = converter.getTexMathsEquation(onode);
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(onode, 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
String sMathJax;
if (config.useMathJax() && bSupportMathML) {
switch (converter.getTexMathsStyle(sLaTeX)) {
case inline:
sMathJax = "\\("+converter.getTexMathsEquation(sLaTeX)+"\\)";
break;
case display:
sMathJax = "\\["+converter.getTexMathsEquation(sLaTeX)+"\\]";
break;
case latex:
default: // Arbitrary LaTeX; this is the tricky bit
sMathJax = "\\("+converter.getTexMathsEquation(sLaTeX)+"\\)";
}
}
else {
sMathJax = " "+converter.getTexMathsEquation(sLaTeX)+" ";
}
hnode.appendChild(converter.createTextNode(sMathJax));
return true;
}
return false;
}
// For plain xhtml: Convert the formula as an image or as plain text
private void convertAsImageOrText(Element image, Node onode, Node hnode) {
NodeList annotationList = ((Element) onode).getElementsByTagName(XMLString.ANNOTATION); // Since OOo 3.2
if (annotationList.getLength()==0) {
annotationList = ((Element) onode).getElementsByTagName(XMLString.MATH_ANNOTATION);
}
if (annotationList.getLength()>0 && annotationList.item(0).hasChildNodes()) {
// First create the annotation (either StarMath or LaTeX)
String sAnnotation = "";
Node child = annotationList.item(0).getFirstChild();
while (child!=null) {
sAnnotation+=child.getNodeValue();
child = child.getNextSibling();
}
if (bUseLaTeX) { sAnnotation = smc.convert(sAnnotation); }
// Next insert the image if required and available
if (bUseImage) {
// Get the image from the ImageLoader
String sHref = Misc.getAttribute(onode,XMLString.XLINK_HREF);
if (sHref==null || sHref.length()==0 || ofr.isInPackage(sHref)) {
BinaryGraphicsDocument bgd = converter.getImageCv().getImage(image);
if (bgd!=null) {
String sMIME = bgd.getMIMEType();
if (MIMETypes.PNG.equals(sMIME) || MIMETypes.JPEG.equals(sMIME) || MIMETypes.GIF.equals(sMIME)) {
converter.addDocument(bgd);
// Create the image and add the StarMath/LaTeX formula as alternative text
Element img = converter.createElement("img");
img.setAttribute("src",bgd.getFileName());
img.setAttribute("class", "formula");
img.setAttribute("alt",sAnnotation);
hnode.appendChild(img);
return;
}
}
}
}
// Otherwise insert the StarMath/LaTeX annotation as a kbd element
Element kbd = converter.createElement("kbd");
kbd.setAttribute("class", "formula");
hnode.appendChild(kbd);
kbd.appendChild(converter.createTextNode(sAnnotation));
}
else {
hnode.appendChild(converter.createTextNode("[Warning: formula ignored]"));
}
}
// For xhtml+mathml: Insert the mathml, removing the namespace (if any) and the annotation
private void convertAsMathML(Element onode, Node hnode, boolean bAllowDisplay) {
Element math = converter.createElement("math");
if (onode.hasAttribute("xmlns:math")) {
math.setAttribute("xmlns", onode.getAttribute("xmlns:math"));
}
else if (onode.hasAttribute("xmlns") && (converter.nType!=XhtmlDocument.HTML5 || converter.isOPS())) {
// Don't include xmlns attribute in HTML5, unless we are creating EPUB 3
math.setAttribute("xmlns", onode.getAttribute("xmlns"));
}
if (bAllowDisplay && onode.hasAttribute("display")) {
// Starting with version 4.2, LO exports display="block" for display equations
// This is a good thing, but in XHTML we can unfortunately only allow this for
// paragraphs with no other text content
math.setAttribute("display", onode.getAttribute("display"));
}
hnode.appendChild(math);
convertMathMLNodeList(onode.getChildNodes(), math);
}
private void convertElementAsMathML(Node onode, Node hnode) {
if (onode.getNodeType()==Node.ELEMENT_NODE) {
if (onode.getNodeName().equals(XMLString.SEMANTICS)) { // Since OOo 3.2
// ignore this construction
convertMathMLNodeList(onode.getChildNodes(),hnode);
}
else if (onode.getNodeName().equals(XMLString.MATH_SEMANTICS)) {
// ignore this construction
convertMathMLNodeList(onode.getChildNodes(),hnode);
}
else if (onode.getNodeName().equals(XMLString.ANNOTATION)) { // Since OOo 3.2
// ignore the annotation (StarMath) completely
// (mozilla renders it for some reason)
}
else if (onode.getNodeName().equals(XMLString.MATH_ANNOTATION)) {
// ignore the annotation (StarMath) completely
// (mozilla renders it for some reason)
}
else {
String sElementName = stripNamespace(onode.getNodeName());
Element newNode = converter.createElement(sElementName);
hnode.appendChild(newNode);
if (onode.hasAttributes()) {
NamedNodeMap attr = onode.getAttributes();
int nLen = attr.getLength();
for (int i=0; i<nLen; i++) {
String sName = stripNamespace(attr.item(i).getNodeName());
String sValue = attr.item(i).getNodeValue();
newNode.setAttribute(sName,replacePrivateChars(sValue));
}
}
convertMathMLNodeList(onode.getChildNodes(),newNode);
}
}
else if (onode.getNodeType()==Node.TEXT_NODE) {
String s = replacePrivateChars(onode.getNodeValue());
hnode.appendChild(hnode.getOwnerDocument().createTextNode(s));
}
}
private void convertMathMLNodeList(NodeList list, Node hnode) {
if (list==null) { return; }
int nLen = list.getLength();
for (int i=0; i<nLen; i++) {
convertElementAsMathML(list.item(i),hnode);
}
}
private String stripNamespace(String s) {
int nPos = s.indexOf(':');
if (nPos>-1) { return s.substring(nPos+1); }
else { return s; }
}
// OOo exports some characters (from the OpenSymbol/StarSymbol font)
// in the private use area of unicode. These should be replaced
// with real unicode positions.
private String replacePrivateChars(String s) {
int nLen = s.length();
StringBuilder buf = new StringBuilder(nLen);
for (int i=0; i<nLen; i++) {
buf.append(replacePrivateChar(s.charAt(i)));
}
return buf.toString();
}
// This method maps {Open|Star}Symbol private use area to real unicode
// positions. This is the same table as in w2l/latex/style/symbols.xml.
// The list is contributed by Bruno Mascret
private char replacePrivateChar(char c) {
switch (c) {
case '\uE002': return '\u2666';
case '\uE003': return '\u25C6';
case '\uE005': return '\u274D';
case '\uE006': return '\u2794';
case '\uE007': return '\u2713';
case '\uE008': return '\u25CF';
case '\uE009': return '\u274D';
case '\uE00A': return '\u25FC';
case '\uE00B': return '\u2752';
case '\uE00D': return '\u2756';
case '\uE013': return '\u2742';
case '\uE01B': return '\u270D';
case '\uE01E': return '\u2022';
case '\uE021': return '\u00A9';
case '\uE024': return '\u00AE';
case '\uE025': return '\u21E8';
case '\uE026': return '\u21E9';
case '\uE027': return '\u21E6';
case '\uE028': return '\u21E7';
case '\uE02B': return '\u279E';
case '\uE032': return '\u2741';
case '\uE036': return '\u0028';
case '\uE037': return '\u0029';
case '\uE03A': return '\u20AC';
case '\uE080': return '\u2030';
case '\uE081': return '\uFE38'; // underbrace
case '\uE082': return '\uFE37'; // overbrace
case '\uE083': return '\u002B';
case '\uE084': return '\u003C';
case '\uE085': return '\u003E';
case '\uE086': return '\u2264';
case '\uE087': return '\u2265';
case '\uE089': return '\u2208';
case '\uE08B': return '\u2026';
case '\uE08C': return '\u2192';
case '\uE090': return '\u2225';
case '\uE091': return '\u005E';
case '\uE092': return '\u02C7';
case '\uE093': return '\u02D8';
case '\uE094': return '\u00B4';
case '\uE095': return '\u0060';
case '\uE096': return '\u02DC'; // or 007E
case '\uE097': return '\u00AF';
case '\uE098': return '\u2192'; // or 21E1
case '\uE09B': return '\u20DB'; // triple dot, neither MathPlayer nor Mozilla understands this glyph
case '\uE09E': return '\u0028';
case '\uE09F': return '\u0029';
case '\uE0A0': return '\u2221';
case '\uE0AA': return '\u2751';
case '\uE0AC': return '\u0393';
case '\uE0AD': return '\u0394';
case '\uE0AE': return '\u0398';
case '\uE0AF': return '\u039B';
case '\uE0B0': return '\u039E';
case '\uE0B1': return '\u03A0';
case '\uE0B2': return '\u03A3';
case '\uE0B3': return '\u03A5';
case '\uE0B4': return '\u03A6';
case '\uE0B5': return '\u03A8';
case '\uE0B6': return '\u03A9';
case '\uE0B7': return '\u03B1';
case '\uE0B8': return '\u03B2';
case '\uE0B9': return '\u03B3';
case '\uE0BA': return '\u03B4';
case '\uE0BB': return '\u03F5';
case '\uE0BC': return '\u03B6';
case '\uE0BD': return '\u03B7';
case '\uE0BE': return '\u03B8';
case '\uE0BF': return '\u03B9';
case '\uE0C0': return '\u03BA';
case '\uE0C1': return '\u03BB';
case '\uE0C2': return '\u03BC';
case '\uE0C3': return '\u03BD';
case '\uE0C4': return '\u03BE';
case '\uE0C5': return '\u03BF';
case '\uE0C6': return '\u03C0';
case '\uE0C7': return '\u03C1';
case '\uE0C8': return '\u03C3';
case '\uE0C9': return '\u03C4';
case '\uE0CA': return '\u03C5';
case '\uE0CB': return '\u03D5';
case '\uE0CC': return '\u03C7';
case '\uE0CD': return '\u03C8';
case '\uE0CE': return '\u03C9';
case '\uE0CF': return '\u03B5';
case '\uE0D0': return '\u03D1';
case '\uE0D1': return '\u03D6';
case '\uE0D3': return '\u03C2';
case '\uE0D4': return '\u03C6';
case '\uE0D5': return '\u2202';
case '\uE0D9': return '\u22A4';
case '\uE0DB': return '\u2190';
case '\uE0DC': return '\u2191';
case '\uE0DD': return '\u2193';
default:
return c;
}
}
}

View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?>

View file

@ -0,0 +1,188 @@
/************************************************************************
*
* NoteConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-14)
*
*/
package writer2latex.xhtml;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.OfficeReader;
import writer2latex.office.PropertySet;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
/** This is a base class handles the conversion of footnotes and endnotes
*/
class NoteConverter extends ConverterHelper {
// The notes configuration
private PropertySet noteConfig;
// The collection of notes
private List<Node> notes = new ArrayList<Node>();
/** Construct a new note converter
*
* @param ofr the office reader used to read the source document
* @param config the configuration
* @param converter the converter
* @param noteConfig the configuration of the notes
*/
NoteConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, PropertySet noteConfig) {
super(ofr,config,converter);
this.noteConfig = noteConfig;
}
/** Handle a footnote or endnote. This method inserts the citation and stores the actual note for later processing
*
* @param onode a text:note element
* @param hnode the inline HTML element to contain the citation
*/
void handleNote(Node onode, Node hnode) {
// Create a style span for the citation
String sCitBodyStyle = noteConfig.getProperty(XMLString.TEXT_CITATION_BODY_STYLE_NAME);
Element span = getTextCv().createInline((Element) hnode,sCitBodyStyle);
// Add target and back-link to the span
String sId = Misc.getAttribute(onode,XMLString.TEXT_ID);
Element link = converter.createLink(sId);
converter.addTarget(link,"body"+sId);
converter.addEpubType(link, "noteref");
span.appendChild(link);
// Get the citation
Element citation = Misc.getChildByTagName(onode,XMLString.TEXT_NOTE_CITATION);
if (citation==null) { // try old format
citation = Misc.getChildByTagName(onode,XMLString.TEXT_FOOTNOTE_CITATION);
if (citation==null) {
citation = Misc.getChildByTagName(onode,XMLString.TEXT_ENDNOTE_CITATION);
}
}
// Insert the citation
if (citation!=null) {
getTextCv().traversePCDATA(citation,link);
}
// Remember the actual note
notes.add(onode);
}
boolean hasNotes() {
return notes.size()>0;
}
Element createNoteSection(Node hnode, String sEpubType) {
Element section = converter.createElement(converter.isHTML5() ? "section" : "div");
hnode.appendChild(section);
converter.addEpubType(section, sEpubType);
return section;
}
void insertNoteHeading(Node hnode, String sHeading, String sTarget) {
if (sHeading.length()>0) {
// Create heading
Element heading = converter.createElement("h1");
hnode.appendChild(heading);
heading.appendChild(converter.createTextNode(sHeading));
// Add to external content.
if (config.getXhtmlSplitLevel()>0) {
converter.addContentEntry(sHeading, 1, null);
}
else {
//For single output file we need a target
converter.addTarget(heading,sTarget);
converter.addContentEntry(sHeading, 1, sTarget);
}
}
}
void flushNotes(Node hnode, String sEpubType) {
int nSize = notes.size();
for (int i=0; i<nSize; i++) {
Node note = notes.get(i);
// Create container
Element aside = converter.createElement(converter.isHTML5() ? "aside" : "div");
hnode.appendChild(aside);
converter.addEpubType(aside, sEpubType);
// Get the citation
Node citation = Misc.getChildByTagName(note,XMLString.TEXT_NOTE_CITATION);
if (citation==null) { // try old format
citation = Misc.getChildByTagName(note,XMLString.TEXT_FOOTNOTE_CITATION);
if (citation==null) {
citation = Misc.getChildByTagName(note,XMLString.TEXT_ENDNOTE_CITATION);
}
}
// Get the body
Node body = Misc.getChildByTagName(note,XMLString.TEXT_NOTE_BODY);
if (body==null) { // try old format
body = Misc.getChildByTagName(note,XMLString.TEXT_FOOTNOTE_BODY);
if (body==null) {
body = Misc.getChildByTagName(note,XMLString.TEXT_ENDNOTE_BODY);
}
}
// Export the note
String sId = Misc.getAttribute(note,XMLString.TEXT_ID);
converter.addTarget(aside,sId);
createAnchor(sId,citation);
getTextCv().traverseBlockText(body,aside);
}
notes.clear();
}
private void createAnchor(String sId, Node citation) {
// Create target and link
Element link = converter.createLink("body"+sId);
// Style it
String sCitStyle = noteConfig.getProperty(XMLString.TEXT_CITATION_STYLE_NAME);
StyleInfo linkInfo = new StyleInfo();
getTextSc().applyStyle(sCitStyle,linkInfo);
applyStyle(linkInfo,link);
// Add prefix
String sPrefix = noteConfig.getProperty(XMLString.STYLE_NUM_PREFIX);
if (sPrefix!=null) {
link.appendChild(converter.createTextNode(sPrefix));
}
// Add citation
getTextCv().traversePCDATA(citation,link);
// Add suffix
String sSuffix = noteConfig.getProperty(XMLString.STYLE_NUM_SUFFIX);
if (sSuffix!=null) {
link.appendChild(converter.createTextNode(sSuffix));
}
// Add space
Element span = converter.createElement("span");
span.appendChild(link);
span.appendChild(converter.createTextNode(" "));
// Save it for later insertion
getTextCv().setAsapNode(span);
}
}

View file

@ -0,0 +1,15 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>The package writer2latex.xhtml</title>
</head>
<body>
<p>This package contains xhtml specific code.</p>
<p>It contains a <code>writerlatex.api.Converter</code> implementation for
conversion into xhtml and xhtml+MathML.</p>
<p>Since version 1.0 you can build Writer2LaTeX without this package if you
don't need xhtml support.</p>
</body>
</html>

View file

@ -0,0 +1,638 @@
package writer2latex.xhtml;
import javax.print.Doc;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import writer2latex.office.OfficeReader;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
public class PageSplitter {
static Node truncatedListItemNodeContent = null;
protected static Node splitSoftPageBreak(Node onode,OfficeReader ofr){
//Find par node with soft page break inside and split it
Document document = onode.getOwnerDocument();
Element softPageBreak = document.createElement(XMLString.TEXT_SOFT_PAGE_BREAK);
NodeList nodes = onode.getChildNodes();
int i = 0;
//Loop through the content nodes and split paragraph nodes with soft page break
while (i < nodes.getLength()){
Node child = nodes.item(i);
//Necessary check if node is an Element
if ((child.getNodeType() == Node.ELEMENT_NODE) && containsSPB(child)){
String nodeName = child.getNodeName();
//DEBUG
//System.out.println("----------CURRENT NODE IS-------" + nodeName);
//Create Duplicate Node!
Element childFirstPart = (Element) child.cloneNode(false);
StyleWithProperties style = null;
if ((nodeName.equals(XMLString.TEXT_P) || nodeName.equals(XMLString.TEXT_H))) {
//If SPB not the first node
if (handleParagraph(childFirstPart, child)){
onode.insertBefore(childFirstPart, child);
style = ofr.getTableStyle(Misc.getAttribute(child, XMLString.TEXT_STYLE_NAME));
}
} else if (nodeName.equals(XMLString.TABLE_TABLE)) {
if (handleTableTable(childFirstPart, child)){
onode.insertBefore(childFirstPart, child);
style = ofr.getTableStyle(Misc.getAttribute(child, XMLString.TABLE_STYLE_NAME));
}
} else if (nodeName.equals(XMLString.TEXT_LIST)) {
if (handleList(childFirstPart, child)){
onode.insertBefore(childFirstPart, child);
style = ofr.getTableStyle(Misc.getAttribute(child, XMLString.TEXT_LIST_STYLE));
}
} else if (nodeName.equals(XMLString.TEXT_SECTION)) {
if (handleSection(childFirstPart, child)){
onode.insertBefore(childFirstPart, child);
style = ofr.getTableStyle(Misc.getAttribute(child, XMLString.TEXT_SECTION));
}
} else if (nodeName.equals(XMLString.TEXT_TABLE_OF_CONTENT)){
//HACK
containsSPB(childFirstPart);
i++;
continue;
} else if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)){
//HACK
i++;
continue;
}
//TODO: IF fo:break before in original table - don't create SPB
if (style == null || !"page".equals(style.getProperty(XMLString.FO_BREAK_BEFORE))){
onode.insertBefore(softPageBreak.cloneNode(false), child);
}
//HACK!
if (truncatedListItemNodeContent != null){
NodeList itemNodeList= truncatedListItemNodeContent.getChildNodes();
while (itemNodeList.getLength() > 0){
onode.insertBefore(itemNodeList.item(0), child);
}
truncatedListItemNodeContent.getParentNode().removeChild(truncatedListItemNodeContent);
truncatedListItemNodeContent = null;
}
if (!child.hasChildNodes()){
onode.removeChild(child);
}
continue;
}
i++;
}
return onode;
}
private static boolean handleList(Node listFirstPart, Node list){
NodeList listNodes = list.getChildNodes();
int i = 0;
boolean dataMoved = false;
while (listNodes.getLength() > i) {
Node listChild = listNodes.item(i);
if(listChild.getNodeType() == Node.ELEMENT_NODE){
String nodeName = listChild.getNodeName();
if (nodeName.equals(XMLString.TEXT_LIST_HEADER)) {
if(containsSPB(listChild)){
//Remove inner SPB
removeSPB(listChild);
//HACK :(
break;
}
listFirstPart.appendChild(listChild.cloneNode(true));
//Get next element
i++;
} else if (nodeName.equals(XMLString.TEXT_LIST_ITEM)) {
if (containsSPB(listChild)){
Node listItemFirstPart = listChild.cloneNode(false);
//remove SPB, move previous nodes to firstPart.
if (handleListItem(listItemFirstPart,listChild)){
dataMoved = true;
//Add first part of list item to previous list item
listFirstPart.appendChild(listItemFirstPart);
//Get list parent node and move cutted node
//After First Part and SPB but before this list;
//TODO!!!!!!!!!!
truncatedListItemNodeContent = listChild;
listFirstPart.getParentNode();
//If List item is empty - remove it
if (!listChild.hasChildNodes()){
list.removeChild(listChild);
}
}
//Add text:continue-numbering="true"
if (dataMoved){
((Element) list).setAttribute(XMLString.TEXT_CONTINUE_NUMBERING, "true");
}
break;
} else {
// Not with SPB yet, move node, set dataMoved=true
listFirstPart.appendChild(listChild);
dataMoved = true;
}
}
}
}
return dataMoved;
}
//If SPB before first item - return false, remove SPB
//Otherwise add childNodes before SPB to firstPart, return true
private static boolean handleListItem(Node listItemFirstPart, Node listItem){
int i = 0;
boolean dataMoved = false;
NodeList listItemNodes = listItem.getChildNodes();
while(listItemNodes.getLength() > i){
Node listItemChild = listItemNodes.item(i);
if(listItemChild.getNodeType() == Node.ELEMENT_NODE){
//Node name
String nodeName = listItemChild.getNodeName();
if (containsSPB(listItemChild)){
Node listItemChildFirstPart = listItemChild.cloneNode(false);
//Break if SPB
if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)) {
//Remove SPB.Return result
listItem.removeChild(listItemChild);
} else if (nodeName.equals(XMLString.TEXT_LIST)) {
if (handleList(listItemChildFirstPart, listItemChild)){
listItemFirstPart.appendChild(listItemChildFirstPart);
dataMoved=true;
}
} else if (nodeName.equals(XMLString.TEXT_H) || nodeName.equals(XMLString.TEXT_P)) {
if (handleParagraph(listItemChildFirstPart, listItemChild)){
listItemFirstPart.appendChild(listItemChildFirstPart);
dataMoved=true;
}
}
break;
//Move to first part
} else {
listItemFirstPart.appendChild(listItemChild);
dataMoved = true;
}
} else {
listItemFirstPart.appendChild(listItemChild);
dataMoved = true;
}
//check internal nodes
}
return dataMoved;
}
//Needs finish
private static boolean handleTableTable(Node tableFirstPart, Node table) {
/*
* // TODO: 0.Test if soft-page-break not at start of table // - in that
* case just remove it and insert before table // 1.Create new table //
* 2.Copy to it table:table-column's and // table:table-header-rows //
* 3.Move nodes before soft-page-break to new table //4. IF in one
* table:row exist more one Algorithm IF SPB at start - just move it
* higher IF SPB between rows - just copy table move row and put SPB
* between tables IF SPB inside row, inside cell - copy table, copy
* empty row, copy each empty cell and in each cell move every node up
* to the first SPB
*
*
*/
NodeList tableChildNodes = table.getChildNodes();
// Node counter
int i = 0;
boolean dataMoved = false;
// Loop through the TABLE:TABLE child nodes
while (tableChildNodes.getLength() > i) {
Node tableChildNode = tableChildNodes.item(i);
if (tableChildNode.getNodeType() == Node.ELEMENT_NODE) {
//Node name
String tableChildNodeName = tableChildNode.getNodeName();
//System.out.println("Table child node " + tableChildNodeName);
if (containsSPB(tableChildNode)){
Node tableChildFirstPart = tableChildNode.cloneNode(false);
if (tableChildNodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)) {
// remove inner soft page break node
table.removeChild(tableChildNode);
} else if (tableChildNodeName.equals(XMLString.TABLE_TABLE_ROW_GROUP)) {
if (handleTableRowGroup(tableChildFirstPart, tableChildNode)){
dataMoved = true;
tableFirstPart.appendChild(tableChildFirstPart);
}
} else if ( tableChildNodeName.equals(XMLString.TABLE_TABLE_ROWS)) {
if (handleTableRows(tableChildFirstPart, tableChildNode)){
dataMoved = true;
tableFirstPart.appendChild(tableChildFirstPart);
}
} else if ( tableChildNodeName.equals(XMLString.TABLE_TABLE_ROW)) {
if (handleTableRow(tableChildFirstPart, tableChildNode)){
dataMoved = true;
tableFirstPart.appendChild(tableChildFirstPart);
}
} else if (tableChildNodeName.equals(XMLString.TABLE_TABLE_COLUMN)
|| tableChildNodeName.equals(XMLString.TABLE_TABLE_COLUMN_GROUP)
|| tableChildNodeName.equals(XMLString.TABLE_TABLE_HEADER_ROWS)
|| tableChildNodeName.equals(XMLString.TABLE_TABLE_HEADER_COLUMNS)) {
//Remove Soft Page Break
removeSPB(tableChildNode);
}
break;
} else {
//Before SPB
//Description nodes
if (tableChildNodeName.equals(XMLString.TABLE_TABLE_COLUMN)
|| tableChildNodeName.equals(XMLString.TABLE_TABLE_COLUMN_GROUP)
|| tableChildNodeName.equals(XMLString.TABLE_TABLE_HEADER_ROWS)
|| tableChildNodeName.equals(XMLString.TABLE_TABLE_HEADER_COLUMNS)) {
//Append to clone table
tableFirstPart.appendChild(tableChildNode.cloneNode(true));
//increment counter
i++;
} else {
//Append to clone table
tableFirstPart.appendChild(tableChildNode);
dataMoved = true;
}
}
}
}
return dataMoved;
}
private static boolean handleTableRowGroup(Node tableRowGroupFistPart, Node tableRowGroup) {
boolean dataMoved = false;
// Node counter
int i = 0;
NodeList tableRowGroupChildNodes = tableRowGroup.getChildNodes();
while (tableRowGroupChildNodes.getLength() > i) {
Node tableRowGroupChildNode = tableRowGroupChildNodes.item(0);
if ((tableRowGroupChildNode.getNodeType() == Node.ELEMENT_NODE)) {
String nodeName = tableRowGroupChildNode.getNodeName();
if (containsSPB(tableRowGroupChildNode)){
Node tableRowGroupChildFirstPart = tableRowGroupChildNode.cloneNode(false);
if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)){
// remove inner soft page break node
tableRowGroup.removeChild(tableRowGroupChildNode);
} else if (nodeName.equals(XMLString.TABLE_TABLE_HEADER_ROWS)){
//Nothing IF table-header-rows found - it is description node,
//Not needed to set dataMoved = true, not needed to append First part
} else if (nodeName.equals(XMLString.TABLE_TABLE_ROW)){
if (handleTableRow(tableRowGroupChildFirstPart, tableRowGroupChildNode)){
dataMoved = true;
tableRowGroupFistPart.appendChild(tableRowGroupChildFirstPart);
}
} else if (nodeName.equals(XMLString.TABLE_TABLE_ROW_GROUP)){
if (handleTableRowGroup(tableRowGroupChildFirstPart, tableRowGroupChildNode)){
dataMoved = true;
tableRowGroupFistPart.appendChild(tableRowGroupChildFirstPart);
}
} else if (nodeName.equals(XMLString.TABLE_TABLE_ROWS)){
if (handleTableRows(tableRowGroupChildFirstPart, tableRowGroupChildNode)){
dataMoved = true;
tableRowGroupFistPart.appendChild(tableRowGroupChildFirstPart);
}
}
break;
} else {
if (nodeName.equals(XMLString.TABLE_TABLE_HEADER_ROWS)){
tableRowGroupFistPart.appendChild(tableRowGroupChildNode.cloneNode(true));
//increment counter
i++;
} else {
tableRowGroupFistPart.appendChild(tableRowGroupChildNode);
dataMoved = true;
}
}
} else {
//Append text nodes
tableRowGroupFistPart.appendChild(tableRowGroupChildNode);
dataMoved = true;
}
}
return dataMoved;
}
private static boolean handleTableRows(Node tableRowsFistPart, Node tableRows) {
boolean dataMoved = false;
// Node counter
int i = 0;
NodeList tableRowsChildNodes = tableRows.getChildNodes();
while (tableRowsChildNodes.getLength() > i) {
Node tableRowsChildNode = tableRowsChildNodes.item(0);
if ((tableRowsChildNode.getNodeType() == Node.ELEMENT_NODE)) {
String nodeName = tableRowsChildNode.getNodeName();
if (containsSPB(tableRowsChildNode)){
Node tableRowGroupChildFirstPart = tableRowsChildNode.cloneNode(false);
if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)){
// remove inner soft page break node
tableRows.removeChild(tableRowsChildNode);
} else if (nodeName.equals(XMLString.TABLE_TABLE_ROW)){
if (handleTableRow(tableRowGroupChildFirstPart, tableRowsChildNode)){
dataMoved = true;
tableRowsFistPart.appendChild(tableRowGroupChildFirstPart);
}
}
break;
} else {
tableRowsFistPart.appendChild(tableRowsChildNode);
dataMoved = true;
}
} else {
System.out.println("ERROR: TEXT NODE FOUND INSIDE tabl:table-rows");
//Append text nodes
//tableRowsFistPart.appendChild(tableRowsChildNode);
//dataMoved = true;
}
}
return dataMoved;
}
private static boolean handleTableRow(Node tableRowFistPart, Node tableRow) {
boolean dataMoved = false;
// Node counter
int i = 0;
NodeList tableRowChildNodes = tableRow.getChildNodes();
while (tableRowChildNodes.getLength() > i) {
Node tableRowChildNode = tableRowChildNodes.item(i);
if ((tableRowChildNode.getNodeType() == Node.ELEMENT_NODE)) {
String nodeName = tableRowChildNode.getNodeName();
if (containsSPB(tableRowChildNode)){
Node tableRowGroupChildFirstPart = tableRowChildNode.cloneNode(false);
if (nodeName.equals(XMLString.TABLE_TABLE_CELL)){
if (handleCell(tableRowGroupChildFirstPart, tableRowChildNode)){
dataMoved = true;
tableRowFistPart.appendChild(tableRowGroupChildFirstPart);
}
} else if (nodeName.equals(XMLString.TABLE_COVERED_TABLE_CELL)){
//Implement handleCoveredCell in future
if (handleCell(tableRowGroupChildFirstPart, tableRowChildNode)){
dataMoved = true;
tableRowFistPart.appendChild(tableRowGroupChildFirstPart);
}
}
} else {
//System.out.println("HERE " + nodeName);
//Move node without SPB above
tableRowFistPart.appendChild(tableRowChildNode.cloneNode(true));
Node emptyCell = tableRowChildNode.cloneNode(false);
Document document = tableRow.getOwnerDocument();
Element textP = document.createElement(XMLString.TEXT_P);
emptyCell.appendChild(textP);
tableRow.insertBefore(emptyCell, tableRowChildNode);
tableRow.removeChild(tableRowChildNode);
dataMoved = true;
}
i++;
} else {
System.out.println("ERROR: TEXT NODE FOUND INSIDE tabl:table-row");
//Append text nodes
//tableRowsFistPart.appendChild(tableRowsChildNode);
//dataMoved = true;
}
}
return dataMoved;
}
private static boolean handleCell(Node cellFirstPart, Node cellNode) {
boolean dataMoved = false;
// Node counter
int i = 0;
NodeList cellChildNodes = cellNode.getChildNodes();
while (cellChildNodes.getLength() > i) {
Node cellChildNode = cellChildNodes.item(0);
if ((cellChildNode.getNodeType() == Node.ELEMENT_NODE)) {
String nodeName = cellChildNode.getNodeName();
if (containsSPB(cellChildNode)){
Node cellChildFirstPart = cellChildNode.cloneNode(false);
if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)){
// remove inner soft page break node
cellNode.removeChild(cellChildNode);
} else if (nodeName.equals(XMLString.TEXT_H) || nodeName.equals(XMLString.TEXT_P)) {
if (handleParagraph(cellChildFirstPart, cellChildNode)){
cellFirstPart.appendChild(cellChildFirstPart);
dataMoved=true;
}
}
break;
} else {
cellFirstPart.appendChild(cellChildNode);
dataMoved = true;
}
} else {
//Append text nodes
cellFirstPart.appendChild(cellChildNode);
dataMoved = true;
}
}
return dataMoved;
}
private static boolean handleSection(Node sectionFirstPart, Node sectionNode) {
boolean dataMoved = false;
// Node counter
int i = 0;
NodeList sectionChildNodes = sectionNode.getChildNodes();
while (sectionChildNodes.getLength() > i) {
Node sectionChildNode = sectionChildNodes.item(0);
if ((sectionChildNode.getNodeType() == Node.ELEMENT_NODE)) {
String nodeName = sectionChildNode.getNodeName();
if (containsSPB(sectionChildNode)){
Node sectionChildFirstPart = sectionChildNode.cloneNode(false);
if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)){
// remove inner soft page break node
sectionNode.removeChild(sectionChildNode);
} else if (nodeName.equals(XMLString.TEXT_H) || nodeName.equals(XMLString.TEXT_P)) {
if (handleParagraph(sectionChildFirstPart, sectionChildNode)){
sectionFirstPart.appendChild(sectionChildFirstPart);
dataMoved=true;
}
} else if (nodeName.equals(XMLString.TEXT_TABLE_OF_CONTENT)) {
//HACK
removeSPB(sectionNode);
i++;
continue;
} else if (nodeName.equals(XMLString.TEXT_SECTION)) {
if (handleSection(sectionChildFirstPart, sectionChildNode)){
sectionFirstPart.appendChild(sectionChildFirstPart);
dataMoved=true;
}
}
//split node with spb and exit
break;
} else {
sectionFirstPart.appendChild(sectionChildNode);
dataMoved = true;
}
} else {
//Append text nodes
sectionFirstPart.appendChild(sectionChildNode);
dataMoved = true;
}
}
return dataMoved;
}
private static boolean handleParagraph(Node paraFirstPart, Node paraNode) {
boolean dataMoved = false;
int i = 0;
NodeList paraChildNodes = paraNode.getChildNodes();
while (paraChildNodes.getLength() > i) {
Node paraChildNode = paraChildNodes.item(i);
//NOT TEXT NODES
if ((paraChildNode.getNodeType() == Node.ELEMENT_NODE)) {
String nodeName = paraChildNode.getNodeName();
//System.out.println(nodeName);
//SPB FOUND
if (containsSPB(paraChildNode)){
if (nodeName.equals(XMLString.TEXT_SOFT_PAGE_BREAK)){
//Next node in paragraph. If it is text node go further
Node paraNextNode = paraChildNodes.item(i+1);
Node paraPrevNode = paraFirstPart.getLastChild();
String nextText = null;
String prevText = null;
if (paraNextNode != null && paraPrevNode != null ){
if (paraNextNode.getNodeType() == Node.TEXT_NODE) {
nextText = paraNextNode.getTextContent();
} else if (paraNextNode.getNodeType() == Node.ELEMENT_NODE) {
Node nextNodeFirstChild = paraNextNode.getFirstChild();
if (nextNodeFirstChild != null && nextNodeFirstChild.getNodeType() == Node.TEXT_NODE) {
nextText = nextNodeFirstChild.getTextContent();
}
}
if (paraPrevNode.getNodeType() == Node.TEXT_NODE){
prevText = paraPrevNode.getTextContent();
} else if (paraPrevNode.getNodeType() == Node.ELEMENT_NODE) {
Node prevNodeLastChild = paraPrevNode.getLastChild();
if (prevNodeLastChild != null && prevNodeLastChild.getNodeType() == Node.TEXT_NODE) {
prevText = prevNodeLastChild.getTextContent();
}
}
//If previous and next texts exists
if (nextText != null && prevText != null) {
//If first character in next text is a letter
//And if last character in previous text is a letter or soft hyphen
if (Character.isLetter(nextText.charAt(0))
&& (Character.isLetter(prevText.charAt(prevText.length() - 1))
|| prevText.charAt(prevText.length() - 1) == 173)) {
paraPrevNode.setTextContent(prevText + "\u2010");
}
}
}
// In case paragraph is empty add space to prevent it's removing
if (paraNextNode == null && paraPrevNode == null){
Document doc = paraNode.getOwnerDocument();
Node space = doc.createTextNode(" ");
paraNode.insertBefore(space, paraChildNode);
}
// remove inner soft page break node
paraNode.removeChild(paraChildNode);
/* Check if next node in para is text and first char is a letter
* Check if last node in paraFirstPart is text and last char is a letter
* If both true - add
*/
} else {
System.out.println("ERROR: SPB INSIDE Paragraph Element in inner element " + nodeName);
//checkSoftPageBreak(internalNode, true);
//paraFirstPart.appendChild(internalNode);
//dataMoved = true;
}
break;
//ELEMENT WITHOUT SPB
} else if (nodeName.equals(XMLString.TEXT_BOOKMARK_START)){
paraFirstPart.appendChild(paraChildNode.cloneNode(true));
i++;
} else {
paraFirstPart.appendChild(paraChildNode);
dataMoved = true;
}
//TEXT NODES
} else {
paraFirstPart.appendChild(paraChildNode);
dataMoved = true;
}
}
return dataMoved;
}
// Returns true if soft-page-break found. Removes it if removeFound = true
private static void removeSPB(Node node) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getNodeName().equals(XMLString.TEXT_SOFT_PAGE_BREAK)) {
Node parent = node.getParentNode();
parent.removeChild(node);
return;
}
if (node.hasChildNodes()) {
int currentNo = 0;
NodeList childNodes = node.getChildNodes();
while (currentNo < childNodes.getLength()) {
Node childNode = childNodes.item(currentNo);
removeSPB(childNode);
currentNo++;
}
}
}
}
private static boolean containsSPB(Node node) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getNodeName().equals(XMLString.TEXT_SOFT_PAGE_BREAK)) {
return true;
}
if (node.hasChildNodes()) {
int currentNo = 0;
NodeList childNodes = node.getChildNodes();
while (currentNo < childNodes.getLength()) {
Node childNode = childNodes.item(currentNo);
if (containsSPB(childNode)) {
return true;
}
currentNo++;
}
}
}
return false;
}
}

View file

@ -0,0 +1,249 @@
/************************************************************************
*
* PageStyleConverter.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.4 (2014-09-16)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
import writer2latex.office.MasterPage;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.PageLayout;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.Calc;
/**
* This class converts OpenDocument page styles to CSS2 styles.
* A page style in a presentation is represented through the master page,
* which links to a page layout defining the geometry and optionally a drawing
* page defining the drawing background.
*
* In a presentation document we export the full page style.
* In a text document we export the writing direction, background color and footnote rule for the first master page only
*/
public class PageStyleConverter extends StyleConverterHelper {
private boolean bHasFootnoteRules = false;
/** Create a new <code>PageStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public PageStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
}
/** Get the text width of the first master page (page width minus left and right margin)
*
* @return the text width
*/
public String getTextWidth() {
MasterPage masterPage = ofr.getFirstMasterPage();
if (masterPage!=null) {
PageLayout pageLayout = ofr.getPageLayout(masterPage.getPageLayoutName());
if (pageLayout!=null) {
String sWidth = pageLayout.getProperty(XMLString.FO_PAGE_WIDTH);
if (sWidth!=null) {
String sMarginLeft = pageLayout.getProperty(XMLString.FO_MARGIN_LEFT);
if (sMarginLeft!=null) {
sWidth = Calc.sub(sWidth, sMarginLeft);
}
String sMarginRight = pageLayout.getProperty(XMLString.FO_MARGIN_RIGHT);
if (sMarginRight!=null) {
sWidth = Calc.sub(sWidth, sMarginRight);
}
return sWidth;
}
}
}
return "17cm"; // Default in Writer, hence usable as a fallback value
}
/** Apply footnote rule formatting (based on first master page)
*
* @param info then StyleInfo to which style information should be attached
*/
public void applyFootnoteRuleStyle(StyleInfo info) {
bHasFootnoteRules = true;
info.sClass="footnoterule";
}
/** Apply default writing direction (based on first master page)
*
* @param info then StyleInfo to which style information should be attached
*/
public void applyDefaultWritingDirection(StyleInfo info) {
MasterPage masterPage = ofr.getFirstMasterPage();
if (masterPage!=null) {
PageLayout pageLayout = ofr.getPageLayout(masterPage.getPageLayoutName());
if (pageLayout!=null) {
applyDirection(pageLayout,info);
}
}
}
/** Apply a master page style - currently only for presentations
*
* @param sStyleName The name of the master page
* @param info the StyleInfo to which style information should be attached
*/
public void applyStyle(String sStyleName, StyleInfo info) {
MasterPage masterPage = ofr.getMasterPage(sStyleName);
if (masterPage!=null) {
String sDisplayName = masterPage.getDisplayName();
if (ofr.isPresentation()) {
// Always generates class name
info.sClass="masterpage"+styleNames.getExportName(sDisplayName);
}
}
}
/** Convert style information for used styles
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
StringBuilder buf = new StringBuilder();
// This will be master pages for presentations only
Enumeration<String> names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = names.nextElement();
MasterPage style = (MasterPage)
getStyles().getStyleByDisplayName(sDisplayName);
StyleInfo info = new StyleInfo();
// First apply page layout (size)
PageLayout pageLayout = ofr.getPageLayout(style.getPageLayoutName());
if (pageLayout!=null) {
applyDirection(pageLayout,info);
cssPageSize(pageLayout,info.props);
getFrameSc().cssBackground(pageLayout,info.props,true);
}
// Next apply drawing-page style (draw background)
StyleWithProperties drawingPage = ofr.getDrawingPageStyle(style.getProperty(XMLString.DRAW_STYLE_NAME));
if (drawingPage!=null) {
cssDrawBackground(drawingPage,info.props,true);
}
// Then export the results
buf.append(sIndent)
.append(".masterpage").append(styleNames.getExportName(sDisplayName))
.append(" {").append(info.props.toString()).append("}")
.append(config.prettyPrint() ? "\n" : " ");
}
if (ofr.isText()) {
// Export page formatting for first master page in text documents
MasterPage masterPage = ofr.getFirstMasterPage();
if (masterPage!=null) {
PageLayout pageLayout = ofr.getPageLayout(masterPage.getPageLayoutName());
if (pageLayout!=null) {
if (bConvertStyles) {
// Background color
StyleInfo pageInfo = new StyleInfo();
getFrameSc().cssBackground(pageLayout,pageInfo.props,true);
/*if (converter.isOPS()) { // Use zero margin for EPUB and default margins for XHTML
pageInfo.props.addValue("margin", "0");
}*/
if (pageInfo.hasAttributes()) {
buf.append(sIndent).append("body {").append(pageInfo.props.toString()).append("}")
.append(config.prettyPrint() ? "\n" : " ");
}
// Footnote rule
if (bHasFootnoteRules) {
StyleInfo ruleInfo = new StyleInfo();
cssFootnoteRule(pageLayout,ruleInfo.props);
buf.append(sIndent).append("hr.footnoterule {").append(ruleInfo.props.toString()).append("}")
.append(config.prettyPrint() ? "\n" : " ");
}
}
}
}
}
return buf.toString();
}
/** Get the family of page styles (master pages)
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getMasterPages();
}
// Background properties in draw: Color, gradient, hatching or bitmap
private void cssDrawBackground(StyleWithProperties style, CSVList props, boolean bInherit){
// Fill color: Same as in css
String s = style.getProperty(XMLString.DRAW_FILL_COLOR,bInherit);
if (s!=null) { props.addValue("background-color",s); }
}
private void cssPageSize(PageLayout style, CSVList props) {
String sWidth = style.getProperty(XMLString.FO_PAGE_WIDTH);
if (sWidth!=null) { props.addValue("width",scale(sWidth)); }
String sHeight = style.getProperty(XMLString.FO_PAGE_HEIGHT);
if (sHeight!=null) { props.addValue("height",scale(sHeight)); }
}
// Footnote rule
private void cssFootnoteRule(PageLayout style, CSVList props) {
String sBefore = style.getFootnoteProperty(XMLString.STYLE_DISTANCE_BEFORE_SEP);
if (sBefore!=null) { props.addValue("margin-top",scale(sBefore)); }
String sAfter = style.getFootnoteProperty(XMLString.STYLE_DISTANCE_AFTER_SEP);
if (sAfter!=null) { props.addValue("margin-bottom", scale(sAfter)); }
String sHeight = style.getFootnoteProperty(XMLString.STYLE_WIDTH);
if (sHeight!=null) { props.addValue("height", scale(sHeight)); }
String sWidth = style.getFootnoteProperty(XMLString.STYLE_REL_WIDTH);
if (sWidth!=null) { props.addValue("width", sWidth); }
String sColor = style.getFootnoteProperty(XMLString.STYLE_COLOR);
if (sColor!=null) { // To get the expected result in all browsers we must set both
props.addValue("color", sColor);
props.addValue("background-color", sColor);
}
String sAdjustment = style.getFootnoteProperty(XMLString.STYLE_ADJUSTMENT);
if ("right".equals(sAdjustment)) {
props.addValue("margin-left", "auto");
props.addValue("margin-right", "0");
}
else if ("center".equals(sAdjustment)) {
props.addValue("margin-left", "auto");
props.addValue("margin-right", "auto");
}
else { // default left
props.addValue("margin-left", "0");
props.addValue("margin-right", "auto");
}
}
}

View file

@ -0,0 +1,169 @@
/************************************************************************
*
* ParStyleConverter.java
*
* Copyright: 2002-2010 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.2 (2010-05-13)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
/*
TODO: drop caps (contained in a child of the style:properties element)
The CSS attributes should be applied to the :first-letter
pseudo-element or to an additional inline element.
*/
/**
* This class converts OpenDocument paragraph styles to CSS2 styles for
* use in ordinary paragraphs.
* This also includes conversion of paragraph properties in other styles
* (heading styles, cell styles).
*/
public class ParStyleConverter extends StyleWithPropertiesConverterHelper {
/** Create a new <code>ParStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of XHTML to use
*/
public ParStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
this.styleMap = config.getXParStyleMap();
this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
}
/** Get the family of paragraph styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getParStyles();
}
/** Create default tag name to represent a paragraph
* @param style to use
* @return the tag name.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "p";
}
/** Convert formatting properties for a specific Par style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
cssPageBreak(style,props,bInherit);
getFrameSc().cssMargins(style,props,bInherit);
getFrameSc().cssBorder(style,props,bInherit);
getFrameSc().cssPadding(style,props,bInherit);
getFrameSc().cssBackgroundCommon(style,props,bInherit);
cssPar(style,props,bInherit);
getTextSc().cssTextCommon(style,props,bInherit);
}
public String getTextBackground(String sStyleName) {
CSVList props = new CSVList(";");
StyleWithProperties style = ofr.getParStyle(sStyleName);
if (style!=null) {
getTextSc().cssTextBackground(style,props,true);
}
return props.toString();
}
// TODO: get rid of this
public String getRealParStyleName(String sStyleName) {
if (sStyleName==null) { return sStyleName; }
StyleWithProperties style = ofr.getParStyle(sStyleName);
if (style==null || !style.isAutomatic()) { return sStyleName; }
return style.getParentName();
}
public void cssPageBreak(StyleWithProperties style, CSVList props, boolean bInherit) {
if ("page".equals(style.getProperty(XMLString.FO_BREAK_BEFORE, bInherit))) {
props.addValue("page-break-before", "always");
}
else if ("page".equals(style.getProperty(XMLString.FO_BREAK_AFTER, bInherit))) {
props.addValue("page-break-after", "always");
}
}
public void cssPar(StyleWithProperties style, CSVList props, boolean bInherit){
String s;
// translates paragraph style properties.
// The following properties are not supported by CSS2:
// style:justify-single-word and style:text-align-last
/* problem: 120% times normal makes no sense...
s = style.getProperty(XMLString.FO_LINE_HEIGHT);
if (s!=null && s.equals("normal")) {
props.addValue("line-height:normal;";
}
else { // length or percentage
s = style.getAbsoluteProperty(XMLString.FO_LINE_HEIGHT);
if (s!=null) { props.addValue("line-height",s); }
}
*/
// TODO: style:line-height-at-least and stype:line-spacing
// Background color fits with css (note: Paragraph property!)
s = style.getParProperty(XMLString.FO_BACKGROUND_COLOR,bInherit);
if (s!=null) { props.addValue("background-color",s); }
// Indentation: Absolute values of this property fit with css...
if (bInherit || style.getProperty(XMLString.FO_TEXT_INDENT,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_TEXT_INDENT);
if (s!=null) {
props.addValue("text-indent",scale(s));
}
else { // ... but css doesn't have this one
s = style.getProperty(XMLString.STYLE_AUTO_TEXT_INDENT);
if ("true".equals(s)) { props.addValue("text-indent","2em"); }
}
}
// Alignment: This property fit with css, but two values have different names
s = style.getProperty(XMLString.FO_TEXT_ALIGN,bInherit);
if (s!=null) { // rename two property values:
if (s.equals("start")) { s="left"; }
else if (s.equals("end")) { s="right"; }
props.addValue("text-align",s);
}
// Wrap (only in table cells, only in spreadsheets):
if (ofr.isSpreadsheet()) {
s = style.getProperty(XMLString.FO_WRAP_OPTION,bInherit);
if ("no-wrap".equals(s)) props.addValue("white-space","nowrap");
else if ("wrap".equals(s)) props.addValue("white-space","normal");
}
}
}

View file

@ -0,0 +1,157 @@
/************************************************************************
*
* PresentationStyleConverter.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.4 (2014-09-16)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
import java.util.Hashtable;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
//import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.ExportNameCollection;
/**
* This class converts OpenDocument presentation styles to CSS2 styles.
* Presentation styles are special frame styles, used to style the standard
* elements in a presentation (title, subtitle and textbox)
*/
public class PresentationStyleConverter extends FrameStyleConverter {
// Data about outline styles
String sCurrentOutlineStyle = null;
Hashtable<String, String[]> outlineStyles = new Hashtable<String, String[]>();
ExportNameCollection outlineStyleNames = new ExportNameCollection(true);
/** Create a new <code>PresentationStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public PresentationStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
// style maps for presentations are currently not supported:
this.styleMap = new XhtmlStyleMap();
}
/** Return a prefix to be used in generated css class names
* @return the prefix
*/
public String getClassNamePrefix() { return "prsnt"; }
/** Get the family of presentation styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getPresentationStyles();
}
/** Create default tag name to represent a presentation object
* @param style to use
* @return the tag name.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "div";
}
/** <p>Convert style information for used styles</p>
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
if (bConvertStyles) {
StringBuilder buf = new StringBuilder();
buf.append(super.getStyleDeclarations(sIndent));
Enumeration<String> names = outlineStyleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = names.nextElement();
StyleWithProperties style = (StyleWithProperties)
getStyles().getStyleByDisplayName(sDisplayName);
if (!style.isAutomatic()) {
// Apply style to paragraphs within a list item with this class
CSVList props = new CSVList(";");
getFrameSc().cssMargins(style,props,true);
getParSc().cssPar(style,props,true);
getTextSc().cssTextCommon(style,props,true);
if (!props.isEmpty()) {
buf.append(sIndent)
.append("li.outline")
.append(styleNames.getExportName(sDisplayName))
.append(" p {").append(props.toString()).append("}")
.append(config.prettyPrint() ? "\n" : " ");
}
}
}
return buf.toString();
}
else {
return "";
}
}
public void enterOutline(String sStyleName) {
sCurrentOutlineStyle = sStyleName;
if (!outlineStyles.containsKey(sCurrentOutlineStyle)) {
String[] sNames = new String[10];
outlineStyles.put(sCurrentOutlineStyle,sNames);
StyleWithProperties style1 = ofr.getPresentationStyle(sCurrentOutlineStyle);
if (style1!=null) {
String sCurrentOutlineStyle1 = sCurrentOutlineStyle;
if (style1.isAutomatic()) { sCurrentOutlineStyle1 = style1.getParentName(); }
sNames[1] = sCurrentOutlineStyle1;
String sBaseName = sCurrentOutlineStyle1.substring(0,sCurrentOutlineStyle1.length()-1);
for (int i=2; i<10; i++) {
String sName = sBaseName + Integer.toString(i);
StyleWithProperties style = ofr.getPresentationStyle(sName);
if (style!=null && style.getParentName().equals(sNames[i-1])) {
sNames[i] = sName;
}
else {
break;
}
}
sNames[1] = null;
}
}
}
public void exitOutline() {
sCurrentOutlineStyle = null;
}
public void applyOutlineStyle(int nLevel, StyleInfo info) {
if (2<=nLevel && nLevel<=9 && sCurrentOutlineStyle!=null) {
if (outlineStyles.containsKey(sCurrentOutlineStyle)) {
info.sClass = "outline"+outlineStyleNames.getExportName(outlineStyles.get(sCurrentOutlineStyle)[nLevel]);
}
}
}
}

View file

@ -0,0 +1,88 @@
/************************************************************************
*
* ResourceDocument.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.5 (2015-05-05)
*
*/
package writer2latex.xhtml;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import writer2latex.api.OutputFile;
import writer2latex.util.Misc;
/** An implementation of <code>OutputFile</code> for resource documents.
* (A resource document is an arbitrary binary file to include in the converter result)
*/
public class ResourceDocument implements OutputFile {
// Content
private String sFileName;
private String sMediaType;
private byte[] content;
/**
* Constructor (creates an empty document)
* @param sFileName <code>Document</code> name.
* @param sMediaType the media type
*/
public ResourceDocument(String sFileName, String sMediaType) {
this.sFileName = sFileName;
this.sMediaType = sMediaType;
content = new byte[0];
}
// Implement OutputFile
public String getFileName() {
return sFileName;
}
public String getMIMEType() {
return sMediaType;
}
public boolean isMasterDocument() {
return false;
}
public boolean containsMath() {
return false;
}
public void write(OutputStream os) throws IOException {
os.write(content);
}
/** Load the resource document bytes from an arbitrary input stream
*
* @param is the input stream
* @throws IOException if any error occurs reading the input stream
*/
public void read(InputStream is) throws IOException {
content = Misc.inputStreamToByteArray(is);
}
}

View file

@ -0,0 +1,79 @@
/************************************************************************
*
* RowStyleConverter.java
*
* Copyright: 2002-2008 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.0 (2008-11-22)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
//import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
/**
* This class converts OpenDocument row styles to CSS2 styles.
* Rows formatting includes <em>background</em>, and also <em>height</em>,
* which is considered elsewhere.
*/
public class RowStyleConverter extends StyleWithPropertiesConverterHelper {
/** Create a new <code>RowStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public RowStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
// Style maps for rows are currently not supported.
this.styleMap = new XhtmlStyleMap();
this.bConvertStyles = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_STYLES;
}
/** Get the family of row styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getRowStyles();
}
/** Create default tag name to represent a row object
* @param style to use
* @return the tag name.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "tr";
}
/** Convert formatting properties for a specific Row style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
getFrameSc().cssBackground(style,props,bInherit);
}
}

View file

@ -0,0 +1,83 @@
/************************************************************************
*
* SectionStyleConverter.java
*
* Copyright: 2002-2008 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.0 (2008-11-22)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
//import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
/**
* This class converts OpenDocument section styles to CSS2 styles.
* Sections are formatted using (a subset of) box properties and with columns.
* The latter would require css3 to be converted (column-count property)
*/
public class SectionStyleConverter extends StyleWithPropertiesConverterHelper {
/** Create a new <code>SectionStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public SectionStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
// Style maps for sections are currently not supported.
// (Section styles are not supported by OOo yet)
this.styleMap = new XhtmlStyleMap();
this.bConvertStyles = config.xhtmlSectionFormatting()==XhtmlConfig.CONVERT_ALL
|| config.xhtmlSectionFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlSectionFormatting()==XhtmlConfig.CONVERT_ALL
|| config.xhtmlSectionFormatting()==XhtmlConfig.IGNORE_STYLES;
}
/** Get the family of section styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getSectionStyles();
}
/** <p>Create default tag name to represent a section object</p>
* @param style to use
* @return the tag name. If the style is null, a default result should be
* returned.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "div";
}
/** <p>Convert formatting properties for a specific section style.</p>
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
getFrameSc().cssBox(style,props,bInherit);
}
}

View file

@ -0,0 +1,218 @@
/************************************************************************
*
* StyleConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-15)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.*;
import writer2latex.util.*;
/** This class converts OpenDocument styles to CSS2 styles.
* Note that some elements in OpenDocument has attributes that also maps to CSS2 properties.
* Example: the width of a text box.
* Also note, that some OpenDocument style properties cannot be mapped to CSS2 without creating an additional inline element.
* The class uses one helper class per OpenDocument style family (paragraph, frame etc.)
*/
class StyleConverter extends ConverterHelper {
// Helpers for text styles
private TextStyleConverter textSc;
private ParStyleConverter parSc;
private HeadingStyleConverter headingSc;
private ListStyleConverter listSc;
private SectionStyleConverter sectionSc;
// Helpers for table styles
private TableStyleConverter tableSc;
private RowStyleConverter rowSc;
private CellStyleConverter cellSc;
// Helpers for drawing styles
private FrameStyleConverter frameSc;
private PresentationStyleConverter presentationSc;
// Helper for page styles
private PageStyleConverter pageSc;
/** Create a new <code>StyleConverter</code>
*
* @param ofr the office reader used to access the source document
* @param config the configuration to use
* @param converter the main converter
* @param nType the XHTML type
*/
StyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter);
// Create the helpers
textSc = new TextStyleConverter(ofr,config,converter,nType);
parSc = new ParStyleConverter(ofr,config,converter,nType);
headingSc = new HeadingStyleConverter(ofr,config,converter,nType);
listSc = new ListStyleConverter(ofr,config,converter,nType);
sectionSc = new SectionStyleConverter(ofr,config,converter,nType);
tableSc = new TableStyleConverter(ofr,config,converter,nType);
rowSc = new RowStyleConverter(ofr,config,converter,nType);
cellSc = new CellStyleConverter(ofr,config,converter,nType);
frameSc = new FrameStyleConverter(ofr,config,converter,nType);
presentationSc = new PresentationStyleConverter(ofr,config,converter,nType);
pageSc = new PageStyleConverter(ofr,config,converter,nType);
}
// Accessor methods for helpers: We need to override the style helper accessors
TextStyleConverter getTextSc() { return textSc; }
ParStyleConverter getParSc() { return parSc; }
HeadingStyleConverter getHeadingSc() { return headingSc; }
ListStyleConverter getListSc() { return listSc; }
SectionStyleConverter getSectionSc() { return sectionSc; }
TableStyleConverter getTableSc() { return tableSc; }
RowStyleConverter getRowSc() { return rowSc; }
CellStyleConverter getCellSc() { return cellSc; }
FrameStyleConverter getFrameSc() { return frameSc; }
PresentationStyleConverter getPresentationSc() { return presentationSc; }
PageStyleConverter getPageSc() { return pageSc; }
/** Apply the default language of the source document on an XHTML element
*
* @param node the XHTML element
*/
void applyDefaultLanguage(Element node) {
StyleWithProperties style = getDefaultStyle();
if (style!=null) {
StyleInfo info = new StyleInfo();
StyleConverterHelper.applyLang(style,info);
applyStyle(info,node);
}
}
/** Export style information as a string of plain CSS code
*
* @param bIndent true if the CSS code should be indented
* @return the CSS code
*/
String exportStyles(boolean bIndent) {
String sIndent = bIndent ? " " : "";
StringBuilder buf = new StringBuilder();
exportDefaultStyle(buf,sIndent);
// Export declarations from helpers
// For OpenDocument documents created with OOo only some will generate content:
// Text documents: text, par, list, frame
// Spreadsheet documents: cell
// Presentation documents: frame, presentation, page
buf.append(getTextSc().getStyleDeclarations(sIndent));
buf.append(getParSc().getStyleDeclarations(sIndent));
buf.append(getHeadingSc().getStyleDeclarations(sIndent));
buf.append(getListSc().getStyleDeclarations(sIndent));
buf.append(getSectionSc().getStyleDeclarations(sIndent));
buf.append(getCellSc().getStyleDeclarations(sIndent));
buf.append(getTableSc().getStyleDeclarations(sIndent));
buf.append(getRowSc().getStyleDeclarations(sIndent));
buf.append(getFrameSc().getStyleDeclarations(sIndent));
buf.append(getPresentationSc().getStyleDeclarations(sIndent));
buf.append(getPageSc().getStyleDeclarations(sIndent));
return buf.toString();
}
/** Export style information as an XHTML style element
*
* @param htmlDOM the XHTML DOM to which the generated element belongs
* @return the style element
*/
Node exportStyles(Document htmlDOM) {
String sStyles = exportStyles(config.prettyPrint());
// Create node
if (sStyles.length()>0) {
Element htmlStyle = htmlDOM.createElement("style");
htmlStyle.setAttribute("media","all");
htmlStyle.setAttribute("type","text/css");
htmlStyle.appendChild(htmlDOM.createTextNode(config.prettyPrint() ? "\n" : " "));
htmlStyle.appendChild(htmlDOM.createTextNode(sStyles));
if (config.prettyPrint()) { htmlStyle.appendChild(htmlDOM.createTextNode(" ")); }
return htmlStyle;
}
else {
return null;
}
}
// Private helper methods
private void exportDefaultStyle(StringBuilder buf, String sIndent) {
// Export default style
if (config.xhtmlCustomStylesheet().length()==0 &&
(config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL ||
config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD)) {
CSVList props = new CSVList(";");
// Default paragraph/cell/frame style is applied to the body element
StyleWithProperties defaultStyle = getDefaultStyle();
if (defaultStyle!=null) {
// text properties only!
getTextSc().cssTextCommon(defaultStyle,props,true);
if (config.useDefaultFont() && config.defaultFontName().length()>0) {
props.addValue("font-family", "'"+config.defaultFontName()+"'");
}
}
// For text documents (XHTML only), also set maximum width
if (ofr.isText() && !converter.isOPS()) {
String sMaxWidth = config.getMaxWidth().trim();
if (sMaxWidth.length()>0) {
props.addValue("max-width", sMaxWidth);
props.addValue("margin-left","auto");
props.addValue("margin-right","auto");
}
}
// Apply properties to body
if (!props.isEmpty()) {
buf.append(sIndent)
.append("body {").append(props.toString()).append("}").append(config.prettyPrint() ? "\n" : " ");
}
}
}
private StyleWithProperties getDefaultStyle() {
if (ofr.isSpreadsheet()) return ofr.getDefaultCellStyle();
else if (ofr.isPresentation()) return ofr.getDefaultFrameStyle();
else return ofr.getDefaultParStyle();
}
}

View file

@ -0,0 +1,120 @@
/************************************************************************
*
* StyleConverterHelper.java
*
* Copyright: 2002-2011 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.2 (2011-03-10)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.Calc;
import writer2latex.util.ExportNameCollection;
/**
* <p>This is an abstract base class to convert an OpenDocument style family to
* CSS2 styles.</p>
*/
public abstract class StyleConverterHelper extends ConverterHelper {
// Translation of OpenDocument style names to CSS class names
protected ExportNameCollection styleNames = new ExportNameCollection(true);
// Style map to use
protected XhtmlStyleMap styleMap;
// Should we convert styles resp. hard formatting?
protected boolean bConvertStyles = true;
protected boolean bConvertHard = true;
// The type of xhtml document
protected int nType;
// Scaling and unit transformation to use
private String sScale;
private String sColScale;
private boolean bConvertToPx;
/** Create a new <code>StyleConverterHelper</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public StyleConverterHelper(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter);
this.nType = nType;
sScale = config.getXhtmlScaling();
sColScale = config.getXhtmlColumnScaling();
bConvertToPx = config.xhtmlConvertToPx();
}
protected String scale(String s) {
if (bConvertToPx) {
return Calc.length2px(Calc.multiply(sScale,s));
}
else {
return Calc.multiply(sScale,s);
}
}
protected String colScale(String s) {
return scale(Calc.multiply(sColScale,s));
}
/** Apply the writing direction (ltr or rtl) attribute from a style
* @param style the OpenDocument style to use
* @param info the <code>StyleInfo</code> object to add information to
*/
protected static void applyDirection(StyleWithProperties style, StyleInfo info) {
String sDir = style.getProperty(XMLString.STYLE_WRITING_MODE);
if ("lr-tb".equals(sDir)) { info.sDir="ltr"; }
else if ("rl-tb".equals(sDir)) { info.sDir="rtl"; }
}
/** Apply language+country from a style
* @param style the OpenDocument style to use
* @param info the <code>StyleInfo</code> object to add information to
*/
protected static void applyLang(StyleWithProperties style, StyleInfo info) {
String sLang = style.getProperty(XMLString.FO_LANGUAGE);
String sCountry = style.getProperty(XMLString.FO_COUNTRY);
if (sLang!=null) {
if (sCountry==null || sCountry.equals("none")) { info.sLang = sLang; }
else { info.sLang = sLang+"-"+sCountry; }
}
}
/** Get the OpenDocument style family associated with this
* StyleConverterHelper
* @return the style family
*/
public abstract OfficeStyleFamily getStyles();
/** <p>Convert style information for used styles</p>
* @param sIndent a String of spaces to add before each line
*/
public abstract String getStyleDeclarations(String sIndent);
}

View file

@ -0,0 +1,40 @@
/************************************************************************
*
* StyleInfo.java
*
* Copyright: 2002-2007 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 0.5 (2007-02-27)
*
*/
package writer2latex.xhtml;
import writer2latex.util.CSVList;
public class StyleInfo {
public String sTagName = null;
public String sClass = null;
public CSVList props = new CSVList(";");
public String sLang = null;
public String sDir = null;
public boolean hasAttributes() {
return !props.isEmpty() || sClass!=null || sLang!=null || sDir!=null;
}
}

View file

@ -0,0 +1,147 @@
/************************************************************************
*
* StyleWithPropertiesConverterHelper.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2014-10-24)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
//import java.util.Hashtable;
//import writer2latex.latex.util.Info;
import writer2latex.office.OfficeReader;
import writer2latex.office.StyleWithProperties;
import writer2latex.util.CSVList;
//import writer2latex.util.ExportNameCollection;
/**
* <p>This is an abstract class to convert an OpenDocument style family
* represented by <code>StyleWithProperties</code> to CSS2 styles.</p>
*/
public abstract class StyleWithPropertiesConverterHelper
extends StyleConverterHelper {
/** Create a new <code>StyleWithPropertiesConverterHelper</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public StyleWithPropertiesConverterHelper(OfficeReader ofr, XhtmlConfig config,
Converter converter, int nType) {
super(ofr,config,converter,nType);
}
/** Apply a style, either by converting the style or by applying the
* style map from the configuarion
* @param sStyleName name of the OpenDocument style
* @param info the <code>StyleInfo</code> object to add information to
*/
public void applyStyle(String sStyleName, StyleInfo info) {
StyleWithProperties style = (StyleWithProperties) getStyles().getStyle(sStyleName);
info.sTagName = getDefaultTagName(style);
if (style!=null) {
if (config.multilingual()) { applyLang(style,info); }
applyDirection(style,info);
if (style.isAutomatic()) {
// Apply parent style + hard formatting
applyStyle(style.getParentName(),info);
if (bConvertHard) { applyProperties(style,info.props,false); }
}
else {
String sDisplayName = style.getDisplayName();
if (styleMap.contains(sDisplayName)) {
// Apply attributes as specified in style map from user
XhtmlStyleMapItem map = styleMap.get(sDisplayName);
if (map.sElement.length()>0) {
info.sTagName = map.sElement;
}
if (!"(none)".equals(map.sCss)) {
info.sClass = map.sCss;
}
}
else {
// Generate class name from display name
info.sClass = getClassNamePrefix()
+ styleNames.getExportName(sDisplayName);
}
}
}
}
/** Convert style information for used styles
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
if (bConvertStyles) {
StringBuilder buf = new StringBuilder();
Enumeration<String> names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = names.nextElement();
StyleWithProperties style = (StyleWithProperties)
getStyles().getStyleByDisplayName(sDisplayName);
if (!style.isAutomatic()) {
CSVList props = new CSVList(";");
applyProperties(style,props,true);
buf.append(sIndent);
buf.append(getDefaultTagName(null));
buf.append(".");
buf.append(getClassNamePrefix());
buf.append(styleNames.getExportName(sDisplayName));
buf.append(" {");
buf.append(props.toString());
buf.append("}");
buf.append(config.prettyPrint() ? "\n" : " ");
// TODO: Create a method "getStyleDeclarationsInner"
// to be used by eg. FrameStyleConverter
}
}
return buf.toString();
}
else {
return "";
}
}
/** Return a prefix to be used in generated css class names
* @return the prefix
*/
public String getClassNamePrefix() { return ""; }
/** Create default tag name to represent a specific style, e.g.
* <code>span</code> (text style) or <code>ul</code> (unordered list)
* @param style to use
* @return the tag name. If the style is null, a default result should be
* returned.
*/
public abstract String getDefaultTagName(StyleWithProperties style);
/** Convert formatting properties for a specific style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public abstract void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit);
}

View file

@ -0,0 +1,428 @@
/************************************************************************
*
* TOCConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-07-23)
*
*/
package writer2latex.xhtml;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.IndexMark;
import writer2latex.office.ListCounter;
import writer2latex.office.OfficeReader;
import writer2latex.office.TocReader;
import writer2latex.office.XMLString;
import writer2latex.util.Misc;
import writer2latex.xhtml.l10n.L10n;
//Helper class (a struct) to contain information about a toc entry (ie. a heading, other paragraph or toc-mark)
final class TocEntry {
Element onode; // the original node
String sLabel = null; // generated label for the entry
int nFileIndex; // the file index for the generated content
int nOutlineLevel; // the outline level for this heading
int[] nOutlineNumber; // the natural outline number for this heading
}
//Helper class (a struct) to point back to indexes that should be processed
final class IndexData {
int nOutFileIndex; // the index of the out file containing the index
Element onode; // the original node
Element chapter; // the chapter containing this toc
Element hnode; // a block node where the index should be added
}
// TODO: This class needs some refactoring
/** This class processes table of content index marks and the associated table of content
*/
class TOCConverter extends IndexConverterHelper {
private static final String TOC_LINK_PREFIX = "toc";
private List<IndexData> indexes = new ArrayList<IndexData>(); // All tables of content
private List<TocEntry> tocEntries = new ArrayList<TocEntry>(); // All potential(!) toc items
private int nTocFileIndex = -1; // file index for main toc
private Element currentChapter = null; // Node for the current chapter (level 1) heading
private int nTocIndex = -1; // Current index for id's (of form tocN)
private ListCounter naturalOutline = new ListCounter(); // Current "natural" outline number
private int nExternalTocDepth = 1; // The number of levels to include in the "external" table of contents
TOCConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter,XMLString.TEXT_TABLE_OF_CONTENT_SOURCE,"toc");
nExternalTocDepth = config.externalTocDepth();
if (nExternalTocDepth==0) { // A value of zero means auto (i.e. determine from split level)
nExternalTocDepth = Math.max(config.getXhtmlSplitLevel(),1);
}
}
/** Return the id of the file containing the alphabetical index
*
* @return the file id
*/
int getFileIndex() {
return nTocFileIndex;
}
/** Handle a heading as a table of content entry
*
* @param onode the text:h element
* @param heading the link target will be added to this inline HTML node
* @param sLabel the numbering label of this heading
*/
void handleHeading(Element onode, Element heading, String sLabel) {
int nLevel = getTextCv().getOutlineLevel(onode);
String sTarget = TOC_LINK_PREFIX+(++nTocIndex);
converter.addTarget(heading,sTarget);
this.currentChapter = onode;
// Add in external content. For single file output we include all level 1 headings + their target
// Targets are added only when the toc level is deeper than the split level
if (nLevel<=nExternalTocDepth) {
converter.addContentEntry(sLabel+converter.getPlainInlineText(onode), nLevel,
nLevel>config.getXhtmlSplitLevel() ? sTarget : null);
}
// Add to real toc
TocEntry entry = new TocEntry();
entry.onode = onode;
entry.sLabel = sLabel;
entry.nFileIndex = converter.getOutFileIndex();
entry.nOutlineLevel = nLevel;
entry.nOutlineNumber = naturalOutline.step(nLevel).getValues();
tocEntries.add(entry);
}
// Add in external content. For single file output we include all level 1 headings + their target
// Targets are added only when the toc level is deeper than the split level
void handleHeadingExternal(Element onode, Element hnode, String sLabel) {
int nLevel = getTextCv().getOutlineLevel(onode);
if (nLevel<=nExternalTocDepth) {
// Add an empty div to use as target, if required
String sTarget = null;
if (nLevel>config.getXhtmlSplitLevel()) {
Element div = converter.createElement("div");
hnode.appendChild(div);
sTarget = TOC_LINK_PREFIX+(++nTocIndex);
converter.addTarget(div,sTarget);
}
converter.addContentEntry(sLabel+converter.getPlainInlineText(onode), nLevel, sTarget);
}
}
void handleParagraph(Element onode, Element par, String sCurrentListLabel) {
String sStyleName = Misc.getAttribute(onode,XMLString.TEXT_STYLE_NAME);
if (ofr.isIndexSourceStyle(getParSc().getRealParStyleName(sStyleName))) {
converter.addTarget(par,TOC_LINK_PREFIX+(++nTocIndex));
TocEntry entry = new TocEntry();
entry.onode = (Element) onode;
entry.sLabel = sCurrentListLabel;
entry.nFileIndex = converter.getOutFileIndex();
tocEntries.add(entry);
}
}
/** Handle a table of contents mark
*
* @param onode a text:toc-mark or text:toc-mark-start node
* @param hnode the link target will be added to this inline HTML node
*/
void handleTocMark(Node onode, Node hnode) {
hnode.appendChild(converter.createTarget(TOC_LINK_PREFIX+(++nTocIndex)));
TocEntry entry = new TocEntry();
entry.onode = (Element) onode;
entry.nFileIndex = converter.getOutFileIndex();
tocEntries.add(entry);
}
/** Handle a table of contents
*
* @param onode a text:alphabetical-index node
* @param hnode the index will be added to this block HTML node
*/
@Override void handleIndex(Element onode, Element hnode) {
if (config.includeToc()) {
if (!ofr.getTocReader((Element)onode).isByChapter()) {
nTocFileIndex = converter.getOutFileIndex();
}
converter.setTocFile(null);
super.handleIndex(onode,hnode);
}
}
@Override void populateIndex(Element source, Element container) {
// Actually we are not populating the index, but collects information to generate it later
IndexData data = new IndexData();
data.nOutFileIndex = converter.getOutFileIndex();
data.onode = source;
data.chapter = currentChapter;
data.hnode = container;
indexes.add(data);
}
/** Generate the content of all tables of content
*
*/
void generate() {
int nIndexCount = indexes.size();
for (int i=0; i<nIndexCount; i++) {
generateToc(indexes.get(i));
}
}
private void generateToc(IndexData data) {
Element onode = data.onode;
Element chapter = data.chapter;
Element ul = data.hnode;
int nSaveOutFileIndex = converter.getOutFileIndex();
converter.changeOutFile(data.nOutFileIndex);
TocReader tocReader = ofr.getTocReader((Element)onode.getParentNode());
// TODO: Read the entire content of the entry templates!
String[] sEntryStyleName = new String[11];
for (int i=1; i<=10; i++) {
Element entryTemplate = tocReader.getTocEntryTemplate(i);
if (entryTemplate!=null) {
sEntryStyleName[i] = Misc.getAttribute(entryTemplate,XMLString.TEXT_STYLE_NAME);
}
}
int nStart = 0;
int nLen = tocEntries.size();
// Find the chapter
if (tocReader.isByChapter() && chapter!=null) {
for (int i=0; i<nLen; i++) {
TocEntry entry = tocEntries.get(i);
if (entry.onode==chapter) { nStart=i; break; }
}
}
// Generate entries
for (int i=nStart; i<nLen; i++) {
Element li = converter.createElement("li");
ul.appendChild(li);
TocEntry entry = tocEntries.get(i);
String sNodeName = entry.onode.getTagName();
if (XMLString.TEXT_H.equals(sNodeName)) {
int nLevel = getTextCv().getOutlineLevel(entry.onode);
if (nLevel==1 && tocReader.isByChapter() && entry.onode!=chapter) { break; }
if (tocReader.useOutlineLevel() && nLevel<=tocReader.getOutlineLevel()) {
Element p = getTextCv().createParagraph(li,sEntryStyleName[nLevel]);
if (entry.sLabel!=null) {
Element span = converter.createElement("span");
p.appendChild(span);
span.setAttribute("class","SectionNumber");
span.appendChild(converter.createTextNode(entry.sLabel));
}
Element a = converter.createLink(TOC_LINK_PREFIX+i);
p.appendChild(a);
getTextCv().traverseInlineText(entry.onode,a);
}
else {
String sStyleName = getParSc().getRealParStyleName(entry.onode.getAttribute(XMLString.TEXT_STYLE_NAME));
nLevel = tocReader.getIndexSourceStyleLevel(sStyleName);
if (tocReader.useIndexSourceStyles() && 1<=nLevel && nLevel<=tocReader.getOutlineLevel()) {
Element p = getTextCv().createParagraph(li,sEntryStyleName[nLevel]);
if (entry.sLabel!=null) {
p.appendChild(converter.createTextNode(entry.sLabel));
}
Element a = converter.createLink(TOC_LINK_PREFIX+i);
p.appendChild(a);
getTextCv().traverseInlineText(entry.onode,a);
}
}
}
else if (XMLString.TEXT_P.equals(sNodeName)) {
String sStyleName = getParSc().getRealParStyleName(entry.onode.getAttribute(XMLString.TEXT_STYLE_NAME));
int nLevel = tocReader.getIndexSourceStyleLevel(sStyleName);
if (tocReader.useIndexSourceStyles() && 1<=nLevel && nLevel<=tocReader.getOutlineLevel()) {
Element p = getTextCv().createParagraph(li,sEntryStyleName[nLevel]);
if (entry.sLabel!=null) {
p.appendChild(converter.createTextNode(entry.sLabel));
}
Element a = converter.createLink(TOC_LINK_PREFIX+i);
p.appendChild(a);
getTextCv().traverseInlineText(entry.onode,a);
}
}
else if (XMLString.TEXT_TOC_MARK.equals(sNodeName)) {
int nLevel = Misc.getPosInteger(entry.onode.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
if (tocReader.useIndexMarks() && nLevel<=tocReader.getOutlineLevel()) {
Element p = getTextCv().createParagraph(li,sEntryStyleName[nLevel]);
Element a = converter.createLink(TOC_LINK_PREFIX+i);
p.appendChild(a);
a.appendChild(converter.createTextNode(IndexMark.getIndexValue(entry.onode)));
}
}
else if (XMLString.TEXT_TOC_MARK_START.equals(sNodeName)) {
int nLevel = Misc.getPosInteger(entry.onode.getAttribute(XMLString.TEXT_OUTLINE_LEVEL),1);
if (tocReader.useIndexMarks() && nLevel<=tocReader.getOutlineLevel()) {
Element p = getTextCv().createParagraph(li,sEntryStyleName[nLevel]);
Element a = converter.createLink(TOC_LINK_PREFIX+i);
p.appendChild(a);
a.appendChild(converter.createTextNode(IndexMark.getIndexValue(entry.onode)));
}
}
}
converter.changeOutFile(nSaveOutFileIndex);
}
// The panel is populated with a minitoc
void generatePanels(int nSplit) {
// TODO: Include link to toc and index in appropriate places..
int nLastIndex = converter.getOutFileIndex();
boolean bHasFrontMatter = false;
TocEntry fakeEntry = new TocEntry();
fakeEntry.nOutlineLevel = 0;
fakeEntry.nOutlineNumber = new int[11];
int nLen = tocEntries.size();
for (int nIndex=0; nIndex<=nLastIndex; nIndex++) {
converter.changeOutFile(nIndex);
Element panel = converter.getPanelNode();
if (panel!=null) {
// Get the last heading of level <= split level for this file
TocEntry entryCurrent = null;
for (int i=nLen-1; i>=0; i--) {
TocEntry entry = tocEntries.get(i);
if (XMLString.TEXT_H.equals(entry.onode.getTagName()) && entry.nFileIndex==nIndex && entry.nOutlineLevel<=nSplit) {
entryCurrent = entry; break;
}
}
if (entryCurrent==null) {
entryCurrent = fakeEntry;
if (nIndex==0) { bHasFrontMatter=true; }
}
// Determine the maximum outline level to include
int nMaxLevel = entryCurrent.nOutlineLevel;
if (nMaxLevel<nSplit) { nMaxLevel++; }
// Create minitoc with relevant entries
if (bHasFrontMatter) {
Element inline = createPanelLink(panel, nIndex, 0, 1);
inline.appendChild(converter.createTextNode(converter.getL10n().get(L10n.HOME)));
}
int nPrevFileIndex = 0;
for (int i=0; i<nLen; i++) {
TocEntry entry = tocEntries.get(i);
if (entry.nFileIndex>nPrevFileIndex+1) {
// Skipping a file index means we have passed an index
for (int k=nPrevFileIndex+1; k<entry.nFileIndex; k++) {
createIndexLink(panel,nIndex,k);
}
}
nPrevFileIndex = entry.nFileIndex;
String sNodeName = entry.onode.getTagName();
if (XMLString.TEXT_H.equals(sNodeName)) {
// Determine whether or not to include this heading
// Note that this condition misses the case where
// a heading of level n is followed by a heading of
// level n+2. This is considered a bug in the document!
boolean bInclude = entry.nOutlineLevel<=nMaxLevel;
if (bInclude) {
// Check that this heading matches the current
int nCompareLevels = entry.nOutlineLevel;
for (int j=1; j<nCompareLevels; j++) {
if (entry.nOutlineNumber[j]!=entryCurrent.nOutlineNumber[j]) {
bInclude = false;
}
}
}
if (bInclude) {
Element inline = createPanelLink(panel, nIndex, entry.nFileIndex, entry.nOutlineLevel);
// Add content of heading
if (entry.sLabel!=null && entry.sLabel.length()>0) {
inline.appendChild(converter.createTextNode(entry.sLabel));
if (!entry.sLabel.endsWith(" ")) {
inline.appendChild(converter.createTextNode(" "));
}
}
getTextCv().traverseInlineText(entry.onode,inline);
}
}
}
if (nPrevFileIndex<nLastIndex) {
// Trailing index
for (int k=nPrevFileIndex+1; k<=nLastIndex; k++) {
createIndexLink(panel,nIndex,k);
}
}
}
}
converter.changeOutFile(nLastIndex);
}
private void createIndexLink(Element panel, int nIndex, int nFileIndex) {
if (nFileIndex==nTocFileIndex) {
Element inline = createPanelLink(panel, nIndex, nTocFileIndex, 1);
inline.appendChild(converter.createTextNode(converter.getL10n().get(L10n.CONTENTS)));
}
else if (nFileIndex==getTextCv().getAlphabeticalIndex()) {
Element inline = createPanelLink(panel, nIndex, getTextCv().getAlphabeticalIndex(), 1);
inline.appendChild(converter.createTextNode(converter.getL10n().get(L10n.INDEX)));
}
}
private Element createPanelLink(Element panel, int nCurrentFile, int nLinkFile, int nOutlineLevel) {
// Create a link
Element p = converter.createElement("p");
p.setAttribute("class","level"+nOutlineLevel);
panel.appendChild(p);
Element inline;
if (nCurrentFile!=nLinkFile) {
inline = converter.createElement("a");
inline.setAttribute("href",converter.getOutFileName(nLinkFile,true));
}
else {
inline = converter.createElement("span");
inline.setAttribute("class","nolink");
}
p.appendChild(inline);
return inline;
}
}

View file

@ -0,0 +1,489 @@
/************************************************************************
*
* TableConverter.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-07-27)
*
*/
package writer2latex.xhtml;
import java.util.Vector;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import writer2latex.util.Calc;
import writer2latex.util.Misc;
import writer2latex.util.SimpleInputBuffer;
import writer2latex.office.XMLString;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.OfficeReader;
//import writer2latex.office.TableLine;
import writer2latex.office.TableRange;
import writer2latex.office.TableReader;
import writer2latex.office.TableView;
public class TableConverter extends ConverterHelper {
// The collection of all table names
// TODO: Navigation should be handled here rather than in Converter.java
protected Vector<String> sheetNames = new Vector<String>();
public TableConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter);
}
/** Converts an office node as a complete table (spreadsheet) document
*
* @param onode the Office node containing the content to convert
*/
public void convertTableContent(Element onode) {
Element hnode = null;
if (!onode.hasChildNodes()) { return; }
if (!config.xhtmlCalcSplit()) { hnode = nextOutFile(); }
NodeList nList = onode.getChildNodes();
int nLen = nList.getLength();
for (int i=0; i<nLen; i++) {
Node child = nList.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
String sNodeName = child.getNodeName();
if (sNodeName.equals(XMLString.TABLE_TABLE)) {
StyleWithProperties style = ofr.getTableStyle(
Misc.getAttribute(child,XMLString.TABLE_STYLE_NAME));
if ((config.xhtmlDisplayHiddenSheets() || style==null
|| !"false".equals(style.getProperty(XMLString.TABLE_DISPLAY)))
&& (!config.applyPrintRanges() || ofr.getTableReader((Element)child).getPrintRangeCount()>0)) {
if (config.xhtmlCalcSplit()) { hnode = nextOutFile(); }
// Collect name
String sName = Misc.getAttribute(child,XMLString.TABLE_NAME);
sheetNames.add(sName);
// Add sheet name as heading, if required
if (config.xhtmlUseSheetNamesAsHeadings()) {
Element heading = converter.createElement("h2");
hnode.appendChild(heading);
heading.setAttribute("id","tableheading"+(sheetNames.size()-1));
heading.appendChild(converter.createTextNode(sName));
}
// Handle the table
handleTable(child,hnode);
// Add frames belonging to this table
Element div = converter.createElement("div");
Element shapes = Misc.getChildByTagName(child,XMLString.TABLE_SHAPES);
if (shapes!=null) {
Node shape = shapes.getFirstChild();
while (shape!=null) {
if (OfficeReader.isDrawElement(shape)) {
// Actually only the first parameter is used
getDrawCv().handleDrawElement((Element)shape,div,null,DrawConverter.CENTERED);
}
shape = shape.getNextSibling();
}
}
getDrawCv().flushFrames(div);
if (div.hasChildNodes()) { hnode.appendChild(div); }
}
}
}
}
if (converter.getOutFileIndex()<0) {
// No files, add an empty one (This may happen if apply_print_ranges=true
// and the document does not contain any print ranges)
nextOutFile();
}
}
private Element nextOutFile() {
Element hnode = converter.nextOutFile();
// Add title, if required by config
if (config.xhtmlUseTitleAsHeading()) {
String sTitle = converter.getMetaData().getTitle();
if (sTitle!=null) {
Element title = converter.createElement("h1");
hnode.appendChild(title);
title.appendChild(converter.createTextNode(sTitle));
}
}
return hnode;
}
/** Process a table:table tag
*
* @param onode the Office node containing the table element
* @param hnode the XHTML node to which the table should be attached
*/
public void handleTable(Node onode, Node hnode) {
TableReader tblr = ofr.getTableReader((Element)onode);
if (config.applyPrintRanges()) {
if (tblr.getPrintRangeCount()>0) {
Element div = converter.createElement("div");
if (!tblr.isSubTable()) {
converter.addTarget(div,tblr.getTableName()+"|table");
}
hnode.appendChild(div);
int nCount = tblr.getPrintRangeCount();
for (int nRange=0; nRange<nCount; nRange++) {
Element table = createTable(tblr);
div.appendChild(table);
TableRange range = tblr.getPrintRange(nRange);
range.setIncludeHidden(config.displayHiddenRowsCols());
range.setIncludeFiltered(config.displayFilteredRowsCols());
traverseTable(range.createTableView(),table);
}
}
}
else {
// Create table
Element table = createTable(tblr);
if (!tblr.isSubTable()) {
converter.addTarget(table,tblr.getTableName()+"|table");
}
hnode.appendChild(table);
// Create view (full table)
TableRange range = new TableRange(tblr);
if (ofr.isSpreadsheet()) {
// skip trailing empty rows and columns
range.setLastRow(tblr.getMaxRowCount()-1);
range.setLastCol(tblr.getMaxColCount()-1);
}
range.setIncludeHidden(config.displayHiddenRowsCols());
range.setIncludeFiltered(config.displayFilteredRowsCols());
traverseTable(range.createTableView(),table);
}
}
private Element createTable(TableReader tblr) {
Element table = converter.createElement("table");
// Apply table style
// Older versions of IE needs the cellspacing attribute, as it doesn't understand the css border-spacing attribute
// We cannot do this with HTML5
if (!converter.isHTML5()) {
table.setAttribute("cellspacing","0");
}
applyTableStyle(tblr.getTableStyleName(), table, tblr.isSubTable());
return table;
}
private void traverseTable(TableView view, Element hnode) {
int nRowCount = view.getRowCount();
int nColCount = view.getColCount();
// Check to see, if the first row contains any colspan
boolean bFirstRowColSpan = false;
for (int nCol=0; nCol<nColCount; nCol++) {
Node cell = view.getCell(0,nCol);
if (cell!=null && XMLString.TABLE_TABLE_CELL.equals(cell.getNodeName())) {
String sColSpan = Misc.getAttribute(cell,XMLString.TABLE_NUMBER_COLUMNS_SPANNED);
if (Misc.getPosInteger(sColSpan,1)>1) {
bFirstRowColSpan = true;
}
}
}
// Create columns; only for tables with relative width
// Otherwise we set the cell width. Reason: IE and Mozilla does not
// interpret column width the same way. IE excludes padding and border,
// Mozilla (like OOo) includes them.
// If the first row contains colspan we have to add <col> anyway
if (config.tableSize()!=XhtmlConfig.NONE) {
if (view.getRelTableWidth()!=null || config.tableSize()==XhtmlConfig.RELATIVE || bFirstRowColSpan) {
Element colgroup = hnode;
if (converter.nType==XhtmlDocument.HTML5) {
// Polyglot HTML5 documents must use an explicit colgroup
colgroup = converter.createElement("colgroup");
hnode.appendChild(colgroup);
}
if (view.getRelTableWidth()!=null || config.tableSize()==XhtmlConfig.RELATIVE) {
for (int nCol=0; nCol<nColCount; nCol++) {
Element col = converter.createElement("col");
colgroup.appendChild(col);
col.setAttribute("style","width:"+view.getRelColumnWidth(nCol));
}
}
else if (bFirstRowColSpan) {
for (int nCol=0; nCol<nColCount; nCol++) {
Element col = converter.createElement("col");
colgroup.appendChild(col);
col.setAttribute("style","width:"+getTableSc().colScale(view.getColumnWidth(nCol)));
}
}
}
}
// Indentify head
int nBodyStart = 0;
while (nBodyStart<nRowCount && view.getRow(nBodyStart).isHeader()) {
nBodyStart++;
}
if (nBodyStart==0 || nBodyStart==nRowCount) {
// all body or all head
Element tbody = hnode;
if (converter.nType==XhtmlDocument.HTML5) {
// Polyglot HTML5 documents must use an explicit tbody
tbody = converter.createElement("tbody");
hnode.appendChild(tbody);
}
traverseRows(view,0,nRowCount,tbody);
}
else {
// Create thead
Element thead = converter.createElement("thead");
hnode.appendChild(thead);
traverseRows(view,0,nBodyStart,thead);
// Create tbody
Element tbody = converter.createElement("tbody");
hnode.appendChild(tbody);
traverseRows(view,nBodyStart,nRowCount,tbody);
}
}
private void traverseRows(TableView view, int nFirstRow, int nLastRow, Element hnode) {
for (int nRow=nFirstRow; nRow<nLastRow; nRow++) {
// Create row and apply row style
Element tr = converter.createElement("tr");
hnode.appendChild(tr);
applyRowStyle(view.getRow(nRow).getStyleName(),tr);
for (int nCol=0; nCol<view.getColCount(); nCol++) {
Node cell = view.getCell(nRow,nCol);
if (cell!=null) {
if (XMLString.TABLE_TABLE_CELL.equals(cell.getNodeName())) {
// Create cell
Element td = converter.createElement("td");
tr.appendChild(td);
int nRowSpan = view.getRowSpan(nRow,nCol);
if (nRowSpan>1) {
td.setAttribute("rowspan",Integer.toString(nRowSpan));
}
int nColSpan = view.getColSpan(nRow,nCol);
if (nColSpan>1) {
td.setAttribute("colspan",Integer.toString(nColSpan));
}
// Handle content
if (!isEmptyCell(cell)) {
String sWidth = view.getCellWidth(nRow, nCol);
if (sWidth!=null) {
converter.pushContentWidth(sWidth);
}
getTextCv().traverseBlockText(cell,td);
if (sWidth!=null) {
converter.popContentWidth();
}
}
else {
// Hack to display empty cells even in msie...
Element par = converter.createElement("p");
td.appendChild(par);
par.setAttribute("style","margin:0;font-size:1px");
par.appendChild(converter.createTextNode("\u00A0"));
}
// Is this a subtable?
Node subTable = Misc.getChildByTagName(cell,XMLString.TABLE_SUB_TABLE);
String sTotalWidth=null;
if (nColSpan==1) {
sTotalWidth = view.getCellWidth(nRow,nCol);
}
String sValueType = ofr.isOpenDocument() ?
Misc.getAttribute(cell,XMLString.OFFICE_VALUE_TYPE) :
Misc.getAttribute(cell,XMLString.TABLE_VALUE_TYPE);
applyCellStyle(view.getCellStyleName(nRow,nCol), view.getRelTableWidth()!=null, sTotalWidth, sValueType, td, subTable!=null);
}
else if (XMLString.TABLE_COVERED_TABLE_CELL.equals(cell.getNodeName())) {
// covered table cells are not part of xhtml table model
}
}
else {
// non-existing cell, not needed in the xhtml table model (it will probably be a trailing cell)
}
}
}
}
private boolean isEmptyCell(Node cell) {
if (!cell.hasChildNodes()) {
return true;
}
else if (OfficeReader.isSingleParagraph(cell)) {
Element par = Misc.getChildByTagName(cell,XMLString.TEXT_P);
return par==null || !par.hasChildNodes();
}
return false;
}
private void applyTableStyle(String sStyleName, Element table, boolean bIsSubTable) {
StyleInfo info = new StyleInfo();
getTableSc().applyStyle(sStyleName,info);
if (config.tableSize()!=XhtmlConfig.NONE) {
StyleWithProperties style = ofr.getTableStyle(sStyleName);
if (style!=null) {
// Set table width
String sWidth = style.getProperty(XMLString.STYLE_REL_WIDTH);
if (sWidth!=null) {
info.props.addValue("width",sWidth);
}
else {
sWidth = style.getProperty(XMLString.STYLE_WIDTH);
if (sWidth!=null) {
if (config.tableSize()==XhtmlConfig.RELATIVE){
// Force relative width
sWidth=Calc.divide(sWidth, converter.getContentWidth(), true);
info.props.addValue("width",sWidth);
}
else {
info.props.addValue("width",getTableSc().colScale(sWidth));
}
}
}
}
}
// Writer uses a separating border model, Calc a collapsing:
// props.addValue("border-collapse", bCalc ? "collapse" : "separate");
// For now always use separating model:
info.props.addValue("border-collapse", "separate");
info.props.addValue("border-spacing", "0");
info.props.addValue("table-layout","fixed");
//info.props.addValue("empty-cells","show"); use &nbsp; instead...
if (ofr.isSpreadsheet()) { info.props.addValue("white-space","nowrap"); }
if (bIsSubTable) {
// Should try to fill the cell; hence:
info.props.addValue("width","100%");
info.props.addValue("margin","0");
}
applyStyle(info,table);
}
private void applyRowStyle(String sStyleName, Element row) {
StyleInfo info = new StyleInfo();
getRowSc().applyStyle(sStyleName,info);
if (config.tableSize()!=XhtmlConfig.NONE) {
StyleWithProperties style = ofr.getRowStyle(sStyleName);
if (style!=null) {
// Translates row style properties
// OOo offers style:row-height and style:min-row-height
// In css row heights are always minimal, so both are exported as height
// If neither is specified, the tallest cell rules; this fits with css.
String s = style.getAbsoluteProperty(XMLString.STYLE_ROW_HEIGHT);
// Do not export minimal row height; causes trouble with ie
//if (s==null) { s = style.getAbsoluteProperty(XMLString.STYLE_MIN_ROW_HEIGHT); }
if (s!=null) { info.props.addValue("height",getRowSc().scale(s)); }
}
}
applyStyle(info,row);
}
private void applyCellStyle(String sStyleName, boolean bIsRelative, String sTotalWidth, String sValueType, Element cell, boolean bIsSubTable) {
StyleInfo info = new StyleInfo();
getCellSc().applyStyle(sStyleName,info);
StyleWithProperties style = ofr.getCellStyle(sStyleName);
if (style!=null) {
if (config.tableSize()==XhtmlConfig.ABSOLUTE && !bIsRelative) {
String sEdge = "0";
// Set the cell width. This is calculated as
// "total cell width" - "border" - "padding"
String s = style.getProperty(XMLString.FO_PADDING_LEFT);
if (s!=null) {
sEdge=Calc.add(sEdge,getTableSc().colScale(s));
}
s = style.getProperty(XMLString.FO_PADDING_RIGHT);
if (s!=null) {
sEdge=Calc.add(sEdge,getTableSc().colScale(s));
}
s = style.getProperty(XMLString.FO_PADDING);
if (s!=null) {
sEdge=Calc.add(sEdge,Calc.multiply("200%",getTableSc().colScale(s)));
}
s = style.getProperty(XMLString.FO_BORDER_LEFT);
if (s!=null) {
sEdge=Calc.add(sEdge,getTableSc().colScale(borderWidth(s)));
}
s = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (s!=null) {
sEdge=Calc.add(sEdge,getTableSc().colScale(borderWidth(s)));
}
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) {
sEdge=Calc.add(sEdge,Calc.multiply("200%",getTableSc().colScale(borderWidth(s))));
}
if (sTotalWidth!=null) {
info.props.addValue("width",Calc.sub(getTableSc().colScale(sTotalWidth),sEdge));
}
}
// Automatic horizontal alignment (calc only)
if (ofr.isSpreadsheet() && !"fix".equals(style.getProperty(XMLString.STYLE_TEXT_ALIGN_SOURCE))) {
// Strings go left, other types (float, time, date, percentage, currency, boolean) go right
// The default is string
info.props.addValue("text-align", sValueType==null || "string".equals(sValueType) ? "left" : "right");
}
}
if (!cell.hasChildNodes()) { // hack to handle empty cells even in msie
// info.props.addValue("line-height","1px"); TODO: Reenable this...
cell.appendChild( converter.createTextNode("\u00A0") );
}
if (bIsSubTable) {
// Cannot set height of a subtable, if the subtable does not fill
// the entire cell it is placed at the top
info.props.addValue("vertical-align","top");
// Don't add padding if there's a subtable in the cell!
info.props.addValue("padding","0");
}
applyStyle(info,cell);
}
// TODO: Move me to a more logical place!
public String borderWidth(String sBorder) {
if (sBorder==null || sBorder.equals("none")) { return "0"; }
SimpleInputBuffer in = new SimpleInputBuffer(sBorder);
while (in.peekChar()!='\0') {
// Skip spaces
while(in.peekChar()==' ') { in.getChar(); }
// If it's a number it must be a unit -> get it
if ('0'<=in.peekChar() && in.peekChar()<='9') {
return in.getNumber()+in.getIdentifier();
}
// skip other characters
while (in.peekChar()!=' ' && in.peekChar()!='\0') { in.getChar(); }
}
return "0";
}
}

View file

@ -0,0 +1,115 @@
/************************************************************************
*
* TableStyleConverter.java
*
* Copyright: 2002-2010 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.2 (2010-05-13)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
/**
* This class converts OpenDocument table styles to CSS2 styles.
* Table formatting includes <em>background</em>, <em>alignment</em>,
* <em>margins</em>, and also <em>width</em>, which is considered elsewhere.
*/
public class TableStyleConverter extends StyleWithPropertiesConverterHelper {
/** Create a new <code>TableStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of xhtml to use
*/
public TableStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
// Style maps for tables are currently not supported.
this.styleMap = new XhtmlStyleMap();
this.bConvertStyles = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlTableFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlTableFormatting()==XhtmlConfig.IGNORE_STYLES;
}
/** Get the family of table styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getTableStyles();
}
/** Create default tag name to represent a table object
* @param style to use
* @return the tag name
*/
public String getDefaultTagName(StyleWithProperties style) {
return "table";
}
/** Convert formatting properties for a specific table style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
// Page break
getParSc().cssPageBreak(style, props, bInherit);
// Apply background
getFrameSc().cssBackground(style,props,bInherit);
// Table-specific properties
cssTable(style,props,bInherit);
}
private void cssTable(StyleWithProperties style, CSVList props, boolean bInherit){
// Top and bottom margins
String sMarginTop = style.getAbsoluteProperty(XMLString.FO_MARGIN_TOP);
if (sMarginTop!=null) { props.addValue("margin-top",scale(sMarginTop)); }
else { props.addValue("margin-top","0"); }
String sMarginBottom = style.getAbsoluteProperty(XMLString.FO_MARGIN_BOTTOM);
if (sMarginBottom!=null) { props.addValue("margin-bottom",scale(sMarginBottom)); }
else { props.addValue("margin-bottom","0"); }
// Left and right margins and horizontal alignment
String sAlign = style.getProperty(XMLString.TABLE_ALIGN);
String sMarginLeft = style.getAbsoluteProperty(XMLString.FO_MARGIN_LEFT);
if (sMarginLeft!=null) { sMarginLeft = scale(sMarginLeft); }
String sMarginRight = style.getAbsoluteProperty(XMLString.FO_MARGIN_RIGHT);
if (sMarginRight!=null) { sMarginRight = scale(sMarginRight); }
if ("center".equals(sAlign)) {
sMarginLeft = "auto"; sMarginRight = "auto";
}
else if ("right".equals(sAlign)) {
sMarginLeft = "auto";
}
else if ("left".equals(sAlign)) {
sMarginRight = "auto";
}
if (sMarginLeft!=null) { props.addValue("margin-left",sMarginLeft); }
if (sMarginRight!=null) { props.addValue("margin-right",sMarginRight); }
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,414 @@
/************************************************************************
*
* TextStyleConverter.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2014-10-24)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
import java.util.Hashtable;
import writer2latex.office.FontDeclaration;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.Calc;
import writer2latex.util.ExportNameCollection;
/**
* This class converts OpenDocument text styles to CSS2 styles.
* This includes conversion of text properties in other styles
* (paragraph, cell, graphic and presentation styles).
* <ul><li>TODO: Support CJK and CTL</li>
* <li>TODO: Support style:use-window-font-color ("automatic color")</li>
* <li>TODO: Support style:font-charset (other encoding)</li>
* <li>TODO: Support style:font-size-rel</li>
* <li>TODO: Support text:display and text:condition</li></ul>
*/
public class TextStyleConverter extends StyleWithPropertiesConverterHelper {
// OpenDocument does *not* define the style for links without style name,
// but OOo uses these styles, and so do we if they are available
// (Caveat: OOo does not export "Visited Internet Link" until a link is actually clicked)
private static final String DEFAULT_LINK_STYLE = "Internet link"; // Not "Link"!
private static final String DEFAULT_VISITED_LINK_STYLE = "Visited Internet Link";
// Bookkeeping for anchors
private ExportNameCollection anchorStyleNames = new ExportNameCollection(true);
private ExportNameCollection anchorVisitedStyleNames = new ExportNameCollection(true);
private Hashtable<String, String> anchorCombinedStyleNames = new Hashtable<String, String>();
private Hashtable<String, String> orgAnchorStyleNames = new Hashtable<String, String>();
private Hashtable<String, String> orgAnchorVisitedStyleNames = new Hashtable<String, String>();
// Export font sizes as percentages?
private boolean bRelativeFontSize = false;
private String sFontScaling = "100%";
private String sBaseFontSize = "12pt";
// Use default font?
private boolean bConvertFont = false;
/** Create a new <code>TextStyleConverter</code>
* @param ofr an <code>OfficeReader</code> to read style information from
* @param config the configuration to use
* @param converter the main <code>Converter</code> class
* @param nType the type of XHTML to use
*/
public TextStyleConverter(OfficeReader ofr, XhtmlConfig config, Converter converter, int nType) {
super(ofr,config,converter,nType);
this.styleMap = config.getXTextStyleMap();
this.bConvertStyles = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD;
this.bConvertHard = config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL || config.xhtmlFormatting()==XhtmlConfig.IGNORE_STYLES;
this.bRelativeFontSize = converter.isOPS() && config.relativeFontSize();
this.sFontScaling = config.fontScaling();
StyleWithProperties defaultStyle = ofr.getDefaultParStyle();
if (defaultStyle!=null) {
String sFontSize = defaultStyle.getProperty(XMLString.FO_FONT_SIZE,false);
if (sFontSize!=null) {
sBaseFontSize = sFontSize;
}
}
this.bConvertFont = !config.useDefaultFont();
}
/** Apply a link style, using a combination of two text styles
* @param sStyleName name of the OpenDocument style
* @param sVisitedStyleName name of the OpenDocument style for visited links
* @param info the <code>StyleInfo</code> object to add information to
*/
public void applyAnchorStyle(String sStyleName, String sVisitedStyleName,
StyleInfo info) {
if (sStyleName==null || sVisitedStyleName==null) { return; }
if (sStyleName.length()==0 || sVisitedStyleName.length()==0) { return; }
// Look for a style map
String sDisplayName = ofr.getTextStyles().getDisplayName(sStyleName);
if (styleMap.contains(sDisplayName)) { // class name from config
XhtmlStyleMapItem map = styleMap.get(sDisplayName);
if (!"(none)".equals(map.sCss)) {
info.sClass = map.sCss;
}
return;
}
String sName = sStyleName+sVisitedStyleName;
if (!anchorCombinedStyleNames.containsKey(sName)) {
String sExportName;
// This combination is not seen before, but the base style may be known
// In that case, use the visited style name as well
if (anchorStyleNames.containsName(sStyleName)) {
sExportName = anchorStyleNames.getExportName(sStyleName)
+anchorVisitedStyleNames.getExportName(sVisitedStyleName);
}
else {
sExportName = anchorStyleNames.getExportName(sStyleName);
}
anchorCombinedStyleNames.put(sName,sExportName);
orgAnchorStyleNames.put(sExportName,sStyleName);
orgAnchorVisitedStyleNames.put(sExportName,sVisitedStyleName);
}
info.sClass = anchorCombinedStyleNames.get(sName);
}
/** <p>Convert style information for used styles</p>
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
StringBuilder buf = new StringBuilder();
buf.append(super.getStyleDeclarations(sIndent));
if (bConvertStyles) {
// Export anchor styles
// Default is always the styles "Internet link" and "Visited Internet Link"(?)
StyleWithProperties defaultLinkStyle = (StyleWithProperties)
getStyles().getStyleByDisplayName(DEFAULT_LINK_STYLE);
if (defaultLinkStyle!=null) {
CSVList props = new CSVList(";");
cssText(defaultLinkStyle,props,true);
cssHyperlink(defaultLinkStyle,props);
buf.append(sIndent)
.append("a:link {").append(props.toString()).append("}\n");
}
defaultLinkStyle = (StyleWithProperties)
getStyles().getStyleByDisplayName(DEFAULT_VISITED_LINK_STYLE);
if (defaultLinkStyle!=null) {
CSVList props = new CSVList(";");
cssText(defaultLinkStyle,props,true);
cssHyperlink(defaultLinkStyle,props);
buf.append(sIndent)
.append("a:visited {").append(props.toString()).append("}\n");
}
// Remaining link styles...
Enumeration<String> enumer = anchorCombinedStyleNames.elements();
while (enumer.hasMoreElements()) {
String sExportName = enumer.nextElement();
String sStyleName = orgAnchorStyleNames.get(sExportName);
String sVisitedStyleName = orgAnchorVisitedStyleNames.get(sExportName);
StyleWithProperties style = ofr.getTextStyle(sStyleName);
if (style!=null) {
CSVList props = new CSVList(";");
cssText(style,props,true);
cssHyperlink(style,props);
buf.append(sIndent).append("a.").append(sExportName)
.append(":link {").append(props.toString()).append("}\n");
}
style = ofr.getTextStyle(sVisitedStyleName);
if (style!=null) {
CSVList props = new CSVList(";");
cssText(style,props,true);
cssHyperlink(style,props);
buf.append(sIndent).append("a.").append(sExportName)
.append(":visited {").append(props.toString()).append("}\n");
}
}
}
return buf.toString();
}
/** Get the family of text (character) styles
* @return the style family
*/
public OfficeStyleFamily getStyles() {
return ofr.getTextStyles();
}
/** Create default tag name to represent a text
* @param style to use
* @return the tag name.
*/
public String getDefaultTagName(StyleWithProperties style) {
return "span";
}
/** Convert formatting properties for a specific text style.
* @param style the style to convert
* @param props the <code>CSVList</code> object to add information to
* @param bInherit true if properties should be inherited from parent style(s)
*/
public void applyProperties(StyleWithProperties style, CSVList props, boolean bInherit) {
cssText(style,props,bInherit);
}
////////////////////////////////////////////////////////////////////////////
// OpenDocument text properties
// Text properties can be applied to text, paragraph, cell, graphic and
// presentation styles.
// Language and country attributes are handled elsewhere
// The following attributes are currently not supported:
// - style:use-window-font-color ("automatic color")
// - style:font-charset (other encoding)
// - style:font-size-rel
// - text:display
// - text:condition
// Also all attributes for CJK and CTL text are currently ignored:
// style:font-name-*, style:font-family-*, style:font-family-generic-*,
// style:font-style-name-*, style:font-pitch-*, style:font-charset-*,
// style:font-size-*, style:font-size-rel-*, style:script-type
// The following attributes cannot be supported using CSS2:
// - style:text-outline
// - style:font-relief
// - style:text-line-trough-* (formatting of line through)
// - style:text-underline-* (formatting of underline)
// - style:letter-kerning
// - style:text-combine-*
// - style:text-emphasis
// - style:text-scale
// - style:text-rotation-*
// - fo:hyphenate
// - fo:hyphenation-*
//
public void cssText(StyleWithProperties style, CSVList props, boolean bInherit) {
cssTextCommon(style,props,bInherit);
cssTextBackground(style,props,bInherit);
}
public void cssTextCommon(StyleWithProperties style, CSVList props, boolean bInherit) {
String s=null,s2=null,s3=null,s4=null;
CSVList val;
// Font family
if (bConvertFont && (bInherit || style.getProperty(XMLString.STYLE_FONT_NAME,false)!=null)) {
val = new CSVList(","); // multivalue property!
// Get font family information from font declaration or from style
s = style.getProperty(XMLString.STYLE_FONT_NAME);
if (s!=null) {
FontDeclaration fd = (FontDeclaration) ofr.getFontDeclarations().getStyle(s);
if (fd!=null) {
s = fd.getFontFamily();
s2 = fd.getFontFamilyGeneric();
s3 = fd.getFontPitch();
}
}
else {
s = style.getProperty(XMLString.FO_FONT_FAMILY);
s2 = style.getProperty(XMLString.STYLE_FONT_FAMILY_GENERIC);
s3 = style.getProperty(XMLString.STYLE_FONT_PITCH);
}
// Add the western font family (CJK and CTL is more complicated)
if (s!=null) { val.addValue(s); }
// Add generic font family
if ("fixed".equals(s3)) { val.addValue("monospace"); }
else if ("roman".equals(s2)) { val.addValue("serif"); }
else if ("swiss".equals(s2)) { val.addValue("sans-serif"); }
else if ("modern".equals(s2)) { val.addValue("monospace"); }
else if ("decorative".equals(s2)) { val.addValue("fantasy"); }
else if ("script".equals(s2)) { val.addValue("cursive"); }
else if ("system".equals(s2)) { val.addValue("serif"); } // System default font
if (!val.isEmpty()) { props.addValue("font-family",val.toString()); }
}
// Font style (italics): This property fit with css2
s = style.getProperty(XMLString.FO_FONT_STYLE,bInherit);
if (s!=null) { props.addValue("font-style",s); }
// Font variant (small caps): This property fit with css2
s = style.getProperty(XMLString.FO_FONT_VARIANT,bInherit);
if (s!=null) { props.addValue("font-variant",s); }
// Font weight (bold): This property fit with css2
s = style.getProperty(XMLString.FO_FONT_WEIGHT,bInherit);
if (s!=null) { props.addValue("font-weight",s); }
// Font size: Absolute values of this property fit with css2
// this is handled together with sub- and superscripts (style:text-position)
// First value: sub, super or percentage (raise/lower relative to font height)
// Second value (optional): percentage (relative size);
if (bInherit || style.getProperty(XMLString.FO_FONT_SIZE,false)!=null
|| style.getProperty(XMLString.STYLE_TEXT_POSITION,false)!=null) {
s = style.getAbsoluteProperty(XMLString.FO_FONT_SIZE);
s2 = style.getProperty(XMLString.STYLE_TEXT_POSITION);
if (s2!=null) {
s2 = s2.trim();
int i = s2.indexOf(" ");
if (i>0) { // two values
s3 = s2.substring(0,i);
s4 = s2.substring(i+1);
}
else { // one value
s3 = s2; s4="100%";
}
if (s!=null) {
if (bRelativeFontSize) {
String sFontSize = Calc.divide(Calc.multiply(sFontScaling, Calc.multiply(s4,s)), sBaseFontSize);
if (!"100%".equals(sFontSize)) props.addValue("font-size", sFontSize);
}
else {
props.addValue("font-size",Calc.multiply(s4,scale(s)));
}
}
else {
props.addValue("font-size",s4);
}
if (!"0%".equals(s3)) {
props.addValue("vertical-align",s3);
}
}
else if (s!=null) {
if (bRelativeFontSize) {
String sFontSize = Calc.divide(Calc.multiply(sFontScaling, s),sBaseFontSize);
if (!"100%".equals(sFontSize)) props.addValue("font-size", sFontSize);
}
else {
props.addValue("font-size",scale(s));
}
}
}
// Color: This attribute fit with css2
s = style.getProperty(XMLString.FO_COLOR,bInherit);
if (s!=null) { props.addValue("color",s); }
// Shadow: This attribute fit with css2
// (Currently OOo has only one shadow style, which is saved as 1pt 1pt)
s = style.getProperty(XMLString.FO_TEXT_SHADOW,bInherit);
if (s!=null) { props.addValue("text-shadow",s); }
// Text decoration. Here OOo is more flexible that CSS2.
if (ofr.isOpenDocument()) {
s = style.getProperty(XMLString.STYLE_TEXT_LINE_THROUGH_STYLE,bInherit);
s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE_STYLE,bInherit);
}
else {
s = style.getProperty(XMLString.STYLE_TEXT_CROSSING_OUT,bInherit);
s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE,bInherit);
}
s3 = style.getProperty(XMLString.STYLE_TEXT_BLINKING,bInherit);
// Issue: Since these three properties all maps to the single CSS property
// text-decoration, there is no way to turn on one kind of decoration and
// turn another one off (without creating another inline element).
// If one decoration is turned of, we turn them all off:
if ("none".equals(s) || "none".equals(s2) || "false".equals(s3)) {
props.addValue("text-decoration","none");
}
else { // set the required properties
val = new CSVList(" "); // multivalue property!
if (s!=null && !"none".equals(s)) { val.addValue("line-through"); }
if (s2!=null && !"none".equals(s2)) { val.addValue("underline"); }
if (s3!=null && "true".equals(s3)) { val.addValue("blink"); }
if (!val.isEmpty()) { props.addValue("text-decoration",val.toString()); }
}
// Letter spacing: This property fit with css
s = style.getProperty(XMLString.FO_LETTER_SPACING,bInherit);
if (s!=null) { props.addValue("letter-spacing",scale(s)); }
// Capitalization: This property fit with css
s = style.getProperty(XMLString.FO_TEXT_TRANSFORM,bInherit);
if (s!=null) { props.addValue("text-transform",s); }
}
public void cssTextBackground(StyleWithProperties style, CSVList props, boolean bInherit) {
// Background color: This attribute fit with css when applied to inline text
String s =ofr.isOpenDocument() ?
style.getTextProperty(XMLString.FO_BACKGROUND_COLOR,bInherit) :
style.getTextProperty(XMLString.STYLE_TEXT_BACKGROUND_COLOR,bInherit);
if (s!=null) { props.addValue("background-color",s); }
}
private void cssHyperlink(StyleWithProperties style, CSVList props) {
String s1,s2;
// For hyperlinks, export text-decoration:none even if nothing is defined in source
if (ofr.isOpenDocument()) {
s1 = style.getProperty(XMLString.STYLE_TEXT_LINE_THROUGH_STYLE,true);
s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE_STYLE,true);
}
else {
s1 = style.getProperty(XMLString.STYLE_TEXT_CROSSING_OUT,true);
s2 = style.getProperty(XMLString.STYLE_TEXT_UNDERLINE,true);
}
String s3 = style.getProperty(XMLString.STYLE_TEXT_BLINKING,true);
if (s1==null && s2==null && s3==null) {
props.addValue("text-decoration","none");
}
}
}

View file

@ -0,0 +1,34 @@
/************************************************************************
*
* Xhtml10Converter.java
*
* Copyright: 2002-2008 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.0 (2008-09-09)
*
*/
package writer2latex.xhtml;
public class Xhtml10Converter extends Converter {
public Xhtml10Converter() {
super(XhtmlDocument.XHTML10);
}
}

View file

@ -0,0 +1,34 @@
/************************************************************************
*
* Xhtml11Converter.java
*
* Copyright: 2002-2009 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.2 (2009-05-29)
*
*/
package writer2latex.xhtml;
public class Xhtml11Converter extends Converter {
public Xhtml11Converter() {
super(XhtmlDocument.XHTML11);
}
}

View file

@ -0,0 +1,71 @@
/************************************************************************
*
* BibliographyGenerator.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-20)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import writer2latex.base.BibliographyGenerator;
import writer2latex.office.OfficeReader;
class XhtmlBibliographyGenerator extends BibliographyGenerator {
private Converter converter;
private Element ul; // The container element
private Element currentPar; // The paragraph of the current item
XhtmlBibliographyGenerator(OfficeReader ofr, Converter converter) {
super(ofr,false);
this.converter = converter;
}
/** Populate the bibliography
*
* @param bibliography a text:bibliography element
* @param ul an XHTML list element to contain the code
*/
void populateBibliography(Element bibliography, Element ul) {
this.ul = ul;
generateBibliography(bibliography);
}
@Override protected void insertBibliographyItem(String sStyleName, String sKey) {
Element li = converter.createElement("li");
converter.addTarget(li, "bib"+sKey);
converter.addEpubType(li, "biblioentry");
ul.appendChild(li);
currentPar = converter.getTextCv().createParagraph(li, sStyleName);
}
@Override protected void insertBibliographyItemElement(String sStyleName, String sText) {
if (sStyleName!=null) {
converter.getTextCv().createInline(currentPar, sStyleName).appendChild(converter.createTextNode(sText));
}
else {
currentPar.appendChild(converter.createTextNode(sText));
}
}
}

View file

@ -0,0 +1,466 @@
/************************************************************************
*
* XhtmlConfig.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-06-15)
*
*/
package writer2latex.xhtml;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import writer2latex.api.ComplexOption;
import writer2latex.base.BooleanOption;
import writer2latex.base.IntegerOption;
import writer2latex.base.Option;
import writer2latex.util.Misc;
public class XhtmlConfig extends writer2latex.base.ConfigBase {
// Implement configuration methods
protected int getOptionCount() { return 61; }
protected String getDefaultConfigPath() { return "/writer2latex/xhtml/config/"; }
// Override setOption: To be backwards compatible, we must accept options
// with the prefix xhtml_
public void setOption(String sName,String sValue) {
if (sName.startsWith("xhtml_")) { sName = sName.substring(6); }
// this option has been renamed:
if (sName.equals("keep_image_size")) { sName = "original_image_size"; }
// and later renamed and extended:
if (sName.equals("original_image_size")) {
sName = "image_size";
if (sValue.equals("true")) { sValue = "none"; }
else { sValue="absolute"; }
}
// this option has been renamed and extended:
if (sName.equals("use_list_hack")) {
sName = "list_formatting";
if (sValue.equals("true")) { sValue = "css1_hack"; }
else { sValue = "css1"; }
}
// this option has been renamed and extended
if (sName.equals("ignore_table_dimensions")) {
sName = "table_size";
if (sValue.equals("true")) { sValue="none"; }
else { sValue="absolute"; }
}
super.setOption(sName, sValue);
}
// Formatting
public static final int IGNORE_ALL = 0;
public static final int IGNORE_STYLES = 1;
public static final int IGNORE_HARD = 2;
public static final int CONVERT_ALL = 3;
// List formatting
public static final int CSS1 = 0;
public static final int CSS1_HACK = 1;
public static final int HARD_LABELS = 2;
// Image and table dimensions
public static final int NONE = 0;
public static final int ABSOLUTE = 1;
public static final int RELATIVE = 2;
// Formulas (for XHTML 1.0 strict)
public static final int STARMATH = 0;
public static final int LATEX = 1;
public static final int IMAGE_STARMATH = 2;
public static final int IMAGE_LATEX = 3;
// Page breaks
// public static final int NONE = 0;
public static final int STYLES = 1;
public static final int EXPLICIT = 2;
public static final int ALL = 3;
// Options
private static final int IGNORE_HARD_LINE_BREAKS = 0;
private static final int IGNORE_EMPTY_PARAGRAPHS = 1;
private static final int IGNORE_DOUBLE_SPACES = 2;
private static final int IMAGE_SIZE = 3;
private static final int NO_DOCTYPE = 4;
private static final int ADD_BOM = 5;
private static final int ENCODING = 6;
private static final int USE_NAMED_ENTITIES = 7;
private static final int HEXADECIMAL_ENTITIES = 8;
private static final int PRETTY_PRINT = 9;
private static final int MULTILINGUAL = 10;
private static final int TEMPLATE_IDS = 11;
private static final int SEPARATE_STYLESHEET = 12;
private static final int CUSTOM_STYLESHEET = 13;
private static final int FORMATTING = 14;
private static final int FRAME_FORMATTING = 15;
private static final int SECTION_FORMATTING = 16;
private static final int TABLE_FORMATTING = 17;
private static final int TABLE_SIZE = 18;
private static final int LIST_FORMATTING = 19;
private static final int MAX_WIDTH = 20;
private static final int USE_DEFAULT_FONT = 21;
private static final int DEFAULT_FONT_NAME = 22;
private static final int USE_DUBLIN_CORE = 23;
private static final int NOTES = 24;
private static final int DISPLAY_HIDDEN_TEXT = 25;
private static final int CONVERT_TO_PX = 26;
private static final int SCALING = 27;
private static final int COLUMN_SCALING = 28;
private static final int RELATIVE_FONT_SIZE = 29;
private static final int FONT_SCALING = 30;
private static final int FLOAT_OBJECTS = 31;
private static final int TABSTOP_STYLE = 32;
private static final int FORMULAS = 33;
private static final int ENDNOTES_HEADING = 34;
private static final int FOOTNOTES_HEADING = 35;
private static final int EXTERNAL_TOC_DEPTH = 36;
private static final int INCLUDE_TOC = 37;
private static final int INCLUDE_NCX = 38;
private static final int SPLIT_LEVEL = 39;
private static final int REPEAT_LEVELS = 40;
private static final int PAGE_BREAK_SPLIT = 41;
private static final int SPLIT_AFTER = 42;
private static final int IMAGE_SPLIT = 43;
private static final int COVER_IMAGE = 44;
private static final int EMBED_SVG = 45;
private static final int EMBED_IMG = 46;
private static final int USE_MATHJAX = 47;
private static final int CALC_SPLIT = 48;
private static final int DISPLAY_HIDDEN_SHEETS = 49;
private static final int DISPLAY_HIDDEN_ROWS_COLS = 50;
private static final int DISPLAY_FILTERED_ROWS_COLS = 51;
private static final int APPLY_PRINT_RANGES = 52;
private static final int USE_TITLE_AS_HEADING = 53;
private static final int USE_SHEET_NAMES_AS_HEADINGS = 54;
private static final int SAVE_IMAGES_IN_SUBDIR = 55;
private static final int UPLINK = 56;
private static final int DIRECTORY_ICON = 57;
private static final int DOCUMENT_ICON = 58;
private static final int HEADING_TAGS = 59;
private static final int PAGE_TAGS = 60;
protected ComplexOption xheading = addComplexOption("heading-map");
protected ComplexOption xpar = addComplexOption("paragraph-map");
protected ComplexOption xtext = addComplexOption("text-map");
protected ComplexOption xframe = addComplexOption("frame-map");
protected ComplexOption xlist = addComplexOption("list-map");
protected ComplexOption xattr = addComplexOption("text-attribute-map");
public XhtmlConfig() {
super();
// create options with default values
options[IGNORE_HARD_LINE_BREAKS] = new BooleanOption("ignore_hard_line_breaks","false");
options[IGNORE_EMPTY_PARAGRAPHS] = new BooleanOption("ignore_empty_paragraphs","false");
options[IGNORE_DOUBLE_SPACES] = new BooleanOption("ignore_double_spaces","false");
options[IMAGE_SIZE] = new IntegerOption("image_size","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("relative".equals(sValue)) { nValue = RELATIVE; }
else if ("none".equals(sValue)) { nValue = NONE; }
else if ("original_image_size".equals(sValue)) { nValue = NONE; }
else { nValue = ABSOLUTE; }
}
};
options[NO_DOCTYPE] = new BooleanOption("no_doctype","false");
options[ADD_BOM] = new BooleanOption("add_bom","false");
options[ENCODING] = new Option("encoding","UTF-8");
options[USE_NAMED_ENTITIES] = new BooleanOption("use_named_entities","false");
options[HEXADECIMAL_ENTITIES] = new BooleanOption("hexadecimal_entities","true");
options[PRETTY_PRINT] = new BooleanOption("pretty_print","true");
options[MULTILINGUAL] = new BooleanOption("multilingual","true");
options[TEMPLATE_IDS] = new Option("template_ids","");
options[SEPARATE_STYLESHEET] = new BooleanOption("separate_stylesheet","false");
options[CUSTOM_STYLESHEET] = new Option("custom_stylesheet","");
options[FORMATTING] = new XhtmlFormatOption("formatting","convert_all");
options[FRAME_FORMATTING] = new XhtmlFormatOption("frame_formatting","convert_all");
options[SECTION_FORMATTING] = new XhtmlFormatOption("section_formatting","convert_all");
options[TABLE_FORMATTING] = new XhtmlFormatOption("table_formatting","convert_all");
options[TABLE_SIZE] = new IntegerOption("table_size","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("relative".equals(sValue)) { nValue = RELATIVE; }
else if ("none".equals(sValue)) { nValue = NONE; }
else { nValue = ABSOLUTE; }
}
};
options[LIST_FORMATTING] = new IntegerOption("list_formatting","css1_hack") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("css1_hack".equals(sValue)) { nValue = CSS1_HACK; }
else if ("hard_labels".equals(sValue)) { nValue = HARD_LABELS; }
else { nValue = CSS1; }
}
};
options[MAX_WIDTH] = new Option("max_width","800px");
options[USE_DEFAULT_FONT] = new BooleanOption("use_default_font","false");
options[DEFAULT_FONT_NAME] = new BooleanOption("default_font_name","");
options[USE_DUBLIN_CORE] = new BooleanOption("use_dublin_core","true");
options[NOTES] = new BooleanOption("notes","true");
options[DISPLAY_HIDDEN_TEXT] = new BooleanOption("display_hidden_text", "false");
options[CONVERT_TO_PX] = new BooleanOption("convert_to_px","true");
options[SCALING] = new Option("scaling","100%");
options[COLUMN_SCALING] = new Option("column_scaling","100%");
options[RELATIVE_FONT_SIZE] = new BooleanOption("relative_font_size","false");
options[FONT_SCALING] = new Option("font_scaling","100%");
options[FLOAT_OBJECTS] = new BooleanOption("float_objects","true");
options[TABSTOP_STYLE] = new Option("tabstop_style","");
options[ENDNOTES_HEADING] = new Option("endnotes_heading","");
options[FOOTNOTES_HEADING] = new Option("footnotes_heading","");
options[FORMULAS] = new IntegerOption("formulas","image+starmath") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("latex".equals(sValue)) { nValue = LATEX; }
else if ("image+latex".equals(sValue)) { nValue = IMAGE_LATEX; }
else if ("starmath".equals(sValue)) { nValue = STARMATH; }
else { nValue = IMAGE_STARMATH; }
}
};
options[EXTERNAL_TOC_DEPTH] = new IntegerOption("external_toc_depth","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("auto".equals(sValue)) {
nValue = 0;
}
else {
nValue = Misc.getPosInteger(sValue,1);
}
}
};
options[INCLUDE_TOC] = new BooleanOption("include_toc","false");
options[INCLUDE_NCX] = new BooleanOption("include_ncx","true");
options[SPLIT_LEVEL] = new IntegerOption("split_level","0") {
@Override public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[REPEAT_LEVELS] = new IntegerOption("repeat_levels","5") {
@Override public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[PAGE_BREAK_SPLIT] = new IntegerOption("page_break_split", "none") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("styles".equals(sValue)) { nValue = STYLES; }
else if ("explicit".equals(sValue)) { nValue = EXPLICIT; }
else if ("all".equals(sValue)) { nValue = ALL; }
else { nValue = NONE; }
}
};
options[SPLIT_AFTER] = new IntegerOption("split_after","0") {
@Override public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue, 0);
}
};
options[IMAGE_SPLIT] = new Option("image_split","none");
options[COVER_IMAGE] = new BooleanOption("cover_image","false");
options[EMBED_SVG] = new BooleanOption("embed_svg","false");
options[EMBED_IMG] = new BooleanOption("embed_img","false");
options[USE_MATHJAX] = new BooleanOption("use_mathjax","false");
options[CALC_SPLIT] = new BooleanOption("calc_split","false");
options[DISPLAY_HIDDEN_SHEETS] = new BooleanOption("display_hidden_sheets", "false");
options[DISPLAY_HIDDEN_ROWS_COLS] = new BooleanOption("display_hidden_rows_cols","false");
options[DISPLAY_FILTERED_ROWS_COLS] = new BooleanOption("display_filtered_rows_cols","false");
options[APPLY_PRINT_RANGES] = new BooleanOption("apply_print_ranges","false");
options[USE_TITLE_AS_HEADING] = new BooleanOption("use_title_as_heading","true");
options[USE_SHEET_NAMES_AS_HEADINGS] = new BooleanOption("use_sheet_names_as_headings","true");
options[SAVE_IMAGES_IN_SUBDIR] = new BooleanOption("save_images_in_subdir","false");
options[UPLINK] = new Option("uplink","");
options[DIRECTORY_ICON] = new Option("directory_icon","");
options[DOCUMENT_ICON] = new Option("document_icon","");
options[HEADING_TAGS] = new Option("heading_tags","sections");
options[PAGE_TAGS] = new Option("page_tags","div");
}
protected void readInner(Element elm) {
if (elm.getTagName().equals("xhtml-style-map")) {
String sName = elm.getAttribute("name");
String sFamily = elm.getAttribute("family");
if (sFamily.length()==0) { // try old name
sFamily = elm.getAttribute("class");
}
Map<String,String> attr = new HashMap<String,String>();
String sElement = elm.getAttribute("element");
String sCss = elm.getAttribute("css");
if (sCss.length()==0) { sCss="(none)"; }
attr.put("element", sElement);
attr.put("css", sCss);
String sBlockElement = elm.getAttribute("block-element");
String sBlockCss = elm.getAttribute("block-css");
if (sBlockCss.length()==0) { sBlockCss="(none)"; }
String sBefore = elm.getAttribute("before");
String sAfter = elm.getAttribute("after");
if ("heading".equals(sFamily)) {
attr.put("block-element", sBlockElement);
attr.put("block-css", sBlockCss);
attr.put("before", sBefore);
attr.put("after", sAfter);
xheading.put(sName,attr);
}
if ("paragraph".equals(sFamily)) {
attr.put("block-element", sBlockElement);
attr.put("block-css", sBlockCss);
attr.put("before", sBefore);
attr.put("after", sAfter);
xpar.put(sName,attr);
}
else if ("text".equals(sFamily)) {
attr.put("before", sBefore);
attr.put("after", sAfter);
xtext.put(sName,attr);
}
else if ("frame".equals(sFamily)) {
xframe.put(sName,attr);
}
else if ("list".equals(sFamily)) {
xlist.put(sName,attr);
}
else if ("attribute".equals(sFamily)) {
xattr.put(sName,attr);
}
}
}
protected void writeInner(Document dom) {
writeXStyleMap(dom,xheading,"heading");
writeXStyleMap(dom,xpar,"paragraph");
writeXStyleMap(dom,xtext,"text");
writeXStyleMap(dom,xlist,"list");
writeXStyleMap(dom,xframe,"frame");
writeXStyleMap(dom,xattr,"attribute");
}
private void writeXStyleMap(Document dom, ComplexOption option, String sFamily) {
Iterator<String> iter = option.keySet().iterator();
while (iter.hasNext()) {
String sName = iter.next();
Element smNode = dom.createElement("xhtml-style-map");
smNode.setAttribute("name",sName);
smNode.setAttribute("family",sFamily);
Map<String,String> attr = option.get(sName);
smNode.setAttribute("element",attr.get("element"));
smNode.setAttribute("css",attr.get("css"));
if (attr.containsKey("block-element")) smNode.setAttribute("block-element",attr.get("block-element"));
if (attr.containsKey("block-css")) smNode.setAttribute("block-css",attr.get("block-css"));
if (attr.containsKey("before")) smNode.setAttribute("before",attr.get("before"));
if (attr.containsKey("after")) smNode.setAttribute("after",attr.get("after"));
dom.getDocumentElement().appendChild(smNode);
}
}
// Convenience accessor methods
public boolean ignoreHardLineBreaks() { return ((BooleanOption) options[IGNORE_HARD_LINE_BREAKS]).getValue(); }
public boolean ignoreEmptyParagraphs() { return ((BooleanOption) options[IGNORE_EMPTY_PARAGRAPHS]).getValue(); }
public boolean ignoreDoubleSpaces() { return ((BooleanOption) options[IGNORE_DOUBLE_SPACES]).getValue(); }
public int imageSize() { return ((IntegerOption) options[IMAGE_SIZE]).getValue(); }
public boolean xhtmlNoDoctype() { return ((BooleanOption) options[NO_DOCTYPE]).getValue(); }
public boolean xhtmlAddBOM() { return ((BooleanOption) options[ADD_BOM]).getValue(); }
public String xhtmlEncoding() { return options[ENCODING].getString(); }
public boolean useNamedEntities() { return ((BooleanOption) options[USE_NAMED_ENTITIES]).getValue(); }
public boolean hexadecimalEntities() { return ((BooleanOption) options[HEXADECIMAL_ENTITIES]).getValue(); }
public boolean prettyPrint() { return ((BooleanOption) options[PRETTY_PRINT]).getValue(); }
public boolean multilingual() { return ((BooleanOption) options[MULTILINGUAL]).getValue(); }
public String templateIds() { return options[TEMPLATE_IDS].getString(); }
public boolean separateStylesheet() { return ((BooleanOption) options[SEPARATE_STYLESHEET]).getValue(); }
public String xhtmlCustomStylesheet() { return options[CUSTOM_STYLESHEET].getString(); }
public int xhtmlFormatting() { return ((XhtmlFormatOption) options[FORMATTING]).getValue(); }
public int xhtmlFrameFormatting() { return ((XhtmlFormatOption) options[FRAME_FORMATTING]).getValue(); }
public int xhtmlSectionFormatting() { return ((XhtmlFormatOption) options[SECTION_FORMATTING]).getValue(); }
public int xhtmlTableFormatting() { return ((XhtmlFormatOption) options[TABLE_FORMATTING]).getValue(); }
public int tableSize() { return ((IntegerOption) options[TABLE_SIZE]).getValue(); }
public int listFormatting() { return ((IntegerOption) options[LIST_FORMATTING]).getValue(); }
public String getMaxWidth() { return options[MAX_WIDTH].getString(); }
public boolean useDefaultFont() { return ((BooleanOption) options[USE_DEFAULT_FONT]).getValue(); }
public String defaultFontName() { return options[DEFAULT_FONT_NAME].getString(); }
public boolean xhtmlUseDublinCore() { return ((BooleanOption) options[USE_DUBLIN_CORE]).getValue(); }
public boolean xhtmlNotes() { return ((BooleanOption) options[NOTES]).getValue(); }
public boolean displayHiddenText() { return ((BooleanOption) options[DISPLAY_HIDDEN_TEXT]).getValue(); }
public boolean xhtmlConvertToPx() { return ((BooleanOption) options[CONVERT_TO_PX]).getValue(); }
public String getXhtmlScaling() { return options[SCALING].getString(); }
public String getXhtmlColumnScaling() { return options[COLUMN_SCALING].getString(); }
public boolean relativeFontSize() { return ((BooleanOption) options[RELATIVE_FONT_SIZE]).getValue(); }
public String fontScaling() { return options[FONT_SCALING].getString(); }
public boolean xhtmlFloatObjects() { return ((BooleanOption) options[FLOAT_OBJECTS]).getValue(); }
public String getXhtmlTabstopStyle() { return options[TABSTOP_STYLE].getString(); }
public String getEndnotesHeading() { return options[ENDNOTES_HEADING].getString(); }
public String getFootnotesHeading() { return options[FOOTNOTES_HEADING].getString(); }
public int formulas() { return ((IntegerOption) options[FORMULAS]).getValue(); }
public int externalTocDepth() { return ((IntegerOption) options[EXTERNAL_TOC_DEPTH]).getValue(); }
public boolean includeToc() { return ((BooleanOption) options[INCLUDE_TOC]).getValue(); }
public boolean includeNCX() { return ((BooleanOption) options[INCLUDE_NCX]).getValue(); }
public int getXhtmlSplitLevel() { return ((IntegerOption) options[SPLIT_LEVEL]).getValue(); }
public int getXhtmlRepeatLevels() { return ((IntegerOption) options[REPEAT_LEVELS]).getValue(); }
public int pageBreakSplit() { return ((IntegerOption) options[PAGE_BREAK_SPLIT]).getValue(); }
public int splitAfter() { return ((IntegerOption) options[SPLIT_AFTER]).getValue(); }
public String imageSplit() { return options[IMAGE_SPLIT].getString(); }
public boolean coverImage() { return ((BooleanOption) options[COVER_IMAGE]).getValue(); }
public boolean embedSVG() { return ((BooleanOption) options[EMBED_SVG]).getValue(); }
public boolean embedImg() { return ((BooleanOption) options[EMBED_IMG]).getValue(); }
public boolean useMathJax() { return ((BooleanOption) options[USE_MATHJAX]).getValue(); }
public boolean xhtmlCalcSplit() { return ((BooleanOption) options[CALC_SPLIT]).getValue(); }
public boolean xhtmlDisplayHiddenSheets() { return ((BooleanOption) options[DISPLAY_HIDDEN_SHEETS]).getValue(); }
public boolean displayHiddenRowsCols() { return ((BooleanOption) options[DISPLAY_HIDDEN_ROWS_COLS]).getValue(); }
public boolean displayFilteredRowsCols() { return ((BooleanOption) options[DISPLAY_FILTERED_ROWS_COLS]).getValue(); }
public boolean applyPrintRanges() { return ((BooleanOption) options[APPLY_PRINT_RANGES]).getValue(); }
public boolean xhtmlUseTitleAsHeading() { return ((BooleanOption) options[USE_TITLE_AS_HEADING]).getValue(); }
public boolean xhtmlUseSheetNamesAsHeadings() { return ((BooleanOption) options[USE_SHEET_NAMES_AS_HEADINGS]).getValue(); }
public boolean saveImagesInSubdir() { return ((BooleanOption) options[SAVE_IMAGES_IN_SUBDIR]).getValue(); }
public String getXhtmlUplink() { return options[UPLINK].getString(); }
public String getXhtmlDirectoryIcon() { return options[DIRECTORY_ICON].getString(); }
public String getXhtmlDocumentIcon() { return options[DOCUMENT_ICON].getString(); }
public String getHeadingTags() { return options[HEADING_TAGS].getString(); }
public String getPageTags() { return options[PAGE_TAGS].getString(); }
public XhtmlStyleMap getXParStyleMap() { return getStyleMap(xpar); }
public XhtmlStyleMap getXHeadingStyleMap() { return getStyleMap(xheading); }
public XhtmlStyleMap getXTextStyleMap() { return getStyleMap(xtext); }
public XhtmlStyleMap getXFrameStyleMap() { return getStyleMap(xframe); }
public XhtmlStyleMap getXListStyleMap() { return getStyleMap(xlist); }
public XhtmlStyleMap getXAttrStyleMap() { return getStyleMap(xattr); }
private XhtmlStyleMap getStyleMap(ComplexOption co) {
XhtmlStyleMap map = new XhtmlStyleMap();
for (String sName : co.keySet()) {
Map<String,String> attr = co.get(sName);
String sElement = attr.containsKey("element") ? attr.get("element") : "";
String sCss = attr.containsKey("css") ? attr.get("css") : "";
String sBlockElement = attr.containsKey("block-element") ? attr.get("block-element") : "";
String sBlockCss = attr.containsKey("block-css") ? attr.get("block-css") : "";
String sBefore = attr.containsKey("before") ? attr.get("before") : "";
String sAfter = attr.containsKey("after") ? attr.get("after") : "";
map.put(sName, new XhtmlStyleMapItem(sBlockElement, sBlockCss, sElement, sCss, sBefore, sAfter));
}
return map;
}
}

View file

@ -0,0 +1,483 @@
/************************************************************************
*
* XhtmlConfig.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-2015 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.6 (2015-06-15)
*
*/
package writer2latex.xhtml;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import writer2latex.api.ComplexOption;
import writer2latex.base.BooleanOption;
import writer2latex.base.IntegerOption;
import writer2latex.base.Option;
import writer2latex.util.Misc;
public class XhtmlConfig extends writer2latex.base.ConfigBase {
// Implement configuration methods
<<<<<<< HEAD
protected int getOptionCount() { return 61; }
=======
protected int getOptionCount() { return 60; }
>>>>>>> Added Footer and Header html convertation. Added comments to use html as input for Greenstone project.
protected String getDefaultConfigPath() { return "/writer2latex/xhtml/config/"; }
// Override setOption: To be backwards compatible, we must accept options
// with the prefix xhtml_
public void setOption(String sName,String sValue) {
if (sName.startsWith("xhtml_")) { sName = sName.substring(6); }
// this option has been renamed:
if (sName.equals("keep_image_size")) { sName = "original_image_size"; }
// and later renamed and extended:
if (sName.equals("original_image_size")) {
sName = "image_size";
if (sValue.equals("true")) { sValue = "none"; }
else { sValue="absolute"; }
}
// this option has been renamed and extended:
if (sName.equals("use_list_hack")) {
sName = "list_formatting";
if (sValue.equals("true")) { sValue = "css1_hack"; }
else { sValue = "css1"; }
}
// this option has been renamed and extended
if (sName.equals("ignore_table_dimensions")) {
sName = "table_size";
if (sValue.equals("true")) { sValue="none"; }
else { sValue="absolute"; }
}
super.setOption(sName, sValue);
}
// Formatting
public static final int IGNORE_ALL = 0;
public static final int IGNORE_STYLES = 1;
public static final int IGNORE_HARD = 2;
public static final int CONVERT_ALL = 3;
// List formatting
public static final int CSS1 = 0;
public static final int CSS1_HACK = 1;
public static final int HARD_LABELS = 2;
// Image and table dimensions
public static final int NONE = 0;
public static final int ABSOLUTE = 1;
public static final int RELATIVE = 2;
// Formulas (for XHTML 1.0 strict)
public static final int STARMATH = 0;
public static final int LATEX = 1;
public static final int IMAGE_STARMATH = 2;
public static final int IMAGE_LATEX = 3;
// Page breaks
// public static final int NONE = 0;
public static final int STYLES = 1;
public static final int EXPLICIT = 2;
public static final int ALL = 3;
// Options
private static final int IGNORE_HARD_LINE_BREAKS = 0;
private static final int IGNORE_EMPTY_PARAGRAPHS = 1;
private static final int IGNORE_DOUBLE_SPACES = 2;
private static final int IMAGE_SIZE = 3;
private static final int NO_DOCTYPE = 4;
private static final int ADD_BOM = 5;
private static final int ENCODING = 6;
private static final int USE_NAMED_ENTITIES = 7;
private static final int HEXADECIMAL_ENTITIES = 8;
private static final int PRETTY_PRINT = 9;
private static final int MULTILINGUAL = 10;
private static final int TEMPLATE_IDS = 11;
private static final int SEPARATE_STYLESHEET = 12;
private static final int CUSTOM_STYLESHEET = 13;
private static final int FORMATTING = 14;
private static final int FRAME_FORMATTING = 15;
private static final int SECTION_FORMATTING = 16;
private static final int TABLE_FORMATTING = 17;
private static final int TABLE_SIZE = 18;
private static final int LIST_FORMATTING = 19;
private static final int MAX_WIDTH = 20;
private static final int USE_DEFAULT_FONT = 21;
private static final int DEFAULT_FONT_NAME = 22;
private static final int USE_DUBLIN_CORE = 23;
private static final int NOTES = 24;
private static final int DISPLAY_HIDDEN_TEXT = 25;
private static final int CONVERT_TO_PX = 26;
private static final int SCALING = 27;
private static final int COLUMN_SCALING = 28;
private static final int RELATIVE_FONT_SIZE = 29;
private static final int FONT_SCALING = 30;
private static final int FLOAT_OBJECTS = 31;
private static final int TABSTOP_STYLE = 32;
private static final int FORMULAS = 33;
private static final int ENDNOTES_HEADING = 34;
private static final int FOOTNOTES_HEADING = 35;
private static final int EXTERNAL_TOC_DEPTH = 36;
private static final int INCLUDE_TOC = 37;
private static final int INCLUDE_NCX = 38;
private static final int SPLIT_LEVEL = 39;
private static final int REPEAT_LEVELS = 40;
private static final int PAGE_BREAK_SPLIT = 41;
private static final int SPLIT_AFTER = 42;
private static final int IMAGE_SPLIT = 43;
private static final int COVER_IMAGE = 44;
private static final int EMBED_SVG = 45;
private static final int EMBED_IMG = 46;
private static final int USE_MATHJAX = 47;
private static final int CALC_SPLIT = 48;
private static final int DISPLAY_HIDDEN_SHEETS = 49;
private static final int DISPLAY_HIDDEN_ROWS_COLS = 50;
private static final int DISPLAY_FILTERED_ROWS_COLS = 51;
private static final int APPLY_PRINT_RANGES = 52;
private static final int USE_TITLE_AS_HEADING = 53;
private static final int USE_SHEET_NAMES_AS_HEADINGS = 54;
private static final int SAVE_IMAGES_IN_SUBDIR = 55;
private static final int UPLINK = 56;
private static final int DIRECTORY_ICON = 57;
private static final int DOCUMENT_ICON = 58;
<<<<<<< HEAD
private static final int HEADING_TAGS = 59;
private static final int PAGE_TAGS = 60;
=======
private static final int GREENSTONE_TAGS = 59;
>>>>>>> Added Footer and Header html convertation. Added comments to use html as input for Greenstone project.
protected ComplexOption xheading = addComplexOption("heading-map");
protected ComplexOption xpar = addComplexOption("paragraph-map");
protected ComplexOption xtext = addComplexOption("text-map");
protected ComplexOption xframe = addComplexOption("frame-map");
protected ComplexOption xlist = addComplexOption("list-map");
protected ComplexOption xattr = addComplexOption("text-attribute-map");
public XhtmlConfig() {
super();
// create options with default values
options[IGNORE_HARD_LINE_BREAKS] = new BooleanOption("ignore_hard_line_breaks","false");
options[IGNORE_EMPTY_PARAGRAPHS] = new BooleanOption("ignore_empty_paragraphs","false");
options[IGNORE_DOUBLE_SPACES] = new BooleanOption("ignore_double_spaces","false");
options[IMAGE_SIZE] = new IntegerOption("image_size","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("relative".equals(sValue)) { nValue = RELATIVE; }
else if ("none".equals(sValue)) { nValue = NONE; }
else if ("original_image_size".equals(sValue)) { nValue = NONE; }
else { nValue = ABSOLUTE; }
}
};
options[NO_DOCTYPE] = new BooleanOption("no_doctype","false");
options[ADD_BOM] = new BooleanOption("add_bom","false");
options[ENCODING] = new Option("encoding","UTF-8");
options[USE_NAMED_ENTITIES] = new BooleanOption("use_named_entities","false");
options[HEXADECIMAL_ENTITIES] = new BooleanOption("hexadecimal_entities","true");
options[PRETTY_PRINT] = new BooleanOption("pretty_print","true");
options[MULTILINGUAL] = new BooleanOption("multilingual","true");
options[TEMPLATE_IDS] = new Option("template_ids","");
options[SEPARATE_STYLESHEET] = new BooleanOption("separate_stylesheet","false");
options[CUSTOM_STYLESHEET] = new Option("custom_stylesheet","");
options[FORMATTING] = new XhtmlFormatOption("formatting","convert_all");
options[FRAME_FORMATTING] = new XhtmlFormatOption("frame_formatting","convert_all");
options[SECTION_FORMATTING] = new XhtmlFormatOption("section_formatting","convert_all");
options[TABLE_FORMATTING] = new XhtmlFormatOption("table_formatting","convert_all");
options[TABLE_SIZE] = new IntegerOption("table_size","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("relative".equals(sValue)) { nValue = RELATIVE; }
else if ("none".equals(sValue)) { nValue = NONE; }
else { nValue = ABSOLUTE; }
}
};
options[LIST_FORMATTING] = new IntegerOption("list_formatting","css1_hack") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("css1_hack".equals(sValue)) { nValue = CSS1_HACK; }
else if ("hard_labels".equals(sValue)) { nValue = HARD_LABELS; }
else { nValue = CSS1; }
}
};
options[MAX_WIDTH] = new Option("max_width","800px");
options[USE_DEFAULT_FONT] = new BooleanOption("use_default_font","false");
options[DEFAULT_FONT_NAME] = new BooleanOption("default_font_name","");
options[USE_DUBLIN_CORE] = new BooleanOption("use_dublin_core","true");
options[NOTES] = new BooleanOption("notes","true");
options[DISPLAY_HIDDEN_TEXT] = new BooleanOption("display_hidden_text", "false");
options[CONVERT_TO_PX] = new BooleanOption("convert_to_px","true");
options[SCALING] = new Option("scaling","100%");
options[COLUMN_SCALING] = new Option("column_scaling","100%");
options[RELATIVE_FONT_SIZE] = new BooleanOption("relative_font_size","false");
options[FONT_SCALING] = new Option("font_scaling","100%");
options[FLOAT_OBJECTS] = new BooleanOption("float_objects","true");
options[TABSTOP_STYLE] = new Option("tabstop_style","");
options[ENDNOTES_HEADING] = new Option("endnotes_heading","");
options[FOOTNOTES_HEADING] = new Option("footnotes_heading","");
options[FORMULAS] = new IntegerOption("formulas","image+starmath") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("latex".equals(sValue)) { nValue = LATEX; }
else if ("image+latex".equals(sValue)) { nValue = IMAGE_LATEX; }
else if ("starmath".equals(sValue)) { nValue = STARMATH; }
else { nValue = IMAGE_STARMATH; }
}
};
options[EXTERNAL_TOC_DEPTH] = new IntegerOption("external_toc_depth","auto") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("auto".equals(sValue)) {
nValue = 0;
}
else {
nValue = Misc.getPosInteger(sValue,1);
}
}
};
options[INCLUDE_TOC] = new BooleanOption("include_toc","false");
options[INCLUDE_NCX] = new BooleanOption("include_ncx","true");
options[SPLIT_LEVEL] = new IntegerOption("split_level","0") {
@Override public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[REPEAT_LEVELS] = new IntegerOption("repeat_levels","5") {
@Override public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[PAGE_BREAK_SPLIT] = new IntegerOption("page_break_split", "none") {
@Override public void setString(String sValue) {
super.setString(sValue);
if ("styles".equals(sValue)) { nValue = STYLES; }
else if ("explicit".equals(sValue)) { nValue = EXPLICIT; }
else if ("all".equals(sValue)) { nValue = ALL; }
else { nValue = NONE; }
}
};
options[SPLIT_AFTER] = new IntegerOption("split_after","0") {
@Override public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue, 0);
}
};
options[IMAGE_SPLIT] = new Option("image_split","none");
options[COVER_IMAGE] = new BooleanOption("cover_image","false");
options[EMBED_SVG] = new BooleanOption("embed_svg","false");
options[EMBED_IMG] = new BooleanOption("embed_img","false");
options[USE_MATHJAX] = new BooleanOption("use_mathjax","false");
options[CALC_SPLIT] = new BooleanOption("calc_split","false");
options[DISPLAY_HIDDEN_SHEETS] = new BooleanOption("display_hidden_sheets", "false");
options[DISPLAY_HIDDEN_ROWS_COLS] = new BooleanOption("display_hidden_rows_cols","false");
options[DISPLAY_FILTERED_ROWS_COLS] = new BooleanOption("display_filtered_rows_cols","false");
options[APPLY_PRINT_RANGES] = new BooleanOption("apply_print_ranges","false");
options[USE_TITLE_AS_HEADING] = new BooleanOption("use_title_as_heading","true");
options[USE_SHEET_NAMES_AS_HEADINGS] = new BooleanOption("use_sheet_names_as_headings","true");
options[SAVE_IMAGES_IN_SUBDIR] = new BooleanOption("save_images_in_subdir","false");
options[UPLINK] = new Option("uplink","");
options[DIRECTORY_ICON] = new Option("directory_icon","");
options[DOCUMENT_ICON] = new Option("document_icon","");
<<<<<<< HEAD
options[HEADING_TAGS] = new Option("heading_tags","sections");
options[PAGE_TAGS] = new Option("page_tags","div");
=======
options[GREENSTONE_TAGS] = new Option("greenstone_tags","headings-pages");
>>>>>>> Added Footer and Header html convertation. Added comments to use html as input for Greenstone project.
}
protected void readInner(Element elm) {
if (elm.getTagName().equals("xhtml-style-map")) {
String sName = elm.getAttribute("name");
String sFamily = elm.getAttribute("family");
if (sFamily.length()==0) { // try old name
sFamily = elm.getAttribute("class");
}
Map<String,String> attr = new HashMap<String,String>();
String sElement = elm.getAttribute("element");
String sCss = elm.getAttribute("css");
if (sCss.length()==0) { sCss="(none)"; }
attr.put("element", sElement);
attr.put("css", sCss);
String sBlockElement = elm.getAttribute("block-element");
String sBlockCss = elm.getAttribute("block-css");
if (sBlockCss.length()==0) { sBlockCss="(none)"; }
String sBefore = elm.getAttribute("before");
String sAfter = elm.getAttribute("after");
if ("heading".equals(sFamily)) {
attr.put("block-element", sBlockElement);
attr.put("block-css", sBlockCss);
attr.put("before", sBefore);
attr.put("after", sAfter);
xheading.put(sName,attr);
}
if ("paragraph".equals(sFamily)) {
attr.put("block-element", sBlockElement);
attr.put("block-css", sBlockCss);
attr.put("before", sBefore);
attr.put("after", sAfter);
xpar.put(sName,attr);
}
else if ("text".equals(sFamily)) {
attr.put("before", sBefore);
attr.put("after", sAfter);
xtext.put(sName,attr);
}
else if ("frame".equals(sFamily)) {
xframe.put(sName,attr);
}
else if ("list".equals(sFamily)) {
xlist.put(sName,attr);
}
else if ("attribute".equals(sFamily)) {
xattr.put(sName,attr);
}
}
}
protected void writeInner(Document dom) {
writeXStyleMap(dom,xheading,"heading");
writeXStyleMap(dom,xpar,"paragraph");
writeXStyleMap(dom,xtext,"text");
writeXStyleMap(dom,xlist,"list");
writeXStyleMap(dom,xframe,"frame");
writeXStyleMap(dom,xattr,"attribute");
}
private void writeXStyleMap(Document dom, ComplexOption option, String sFamily) {
Iterator<String> iter = option.keySet().iterator();
while (iter.hasNext()) {
String sName = iter.next();
Element smNode = dom.createElement("xhtml-style-map");
smNode.setAttribute("name",sName);
smNode.setAttribute("family",sFamily);
Map<String,String> attr = option.get(sName);
smNode.setAttribute("element",attr.get("element"));
smNode.setAttribute("css",attr.get("css"));
if (attr.containsKey("block-element")) smNode.setAttribute("block-element",attr.get("block-element"));
if (attr.containsKey("block-css")) smNode.setAttribute("block-css",attr.get("block-css"));
if (attr.containsKey("before")) smNode.setAttribute("before",attr.get("before"));
if (attr.containsKey("after")) smNode.setAttribute("after",attr.get("after"));
dom.getDocumentElement().appendChild(smNode);
}
}
// Convenience accessor methods
public boolean ignoreHardLineBreaks() { return ((BooleanOption) options[IGNORE_HARD_LINE_BREAKS]).getValue(); }
public boolean ignoreEmptyParagraphs() { return ((BooleanOption) options[IGNORE_EMPTY_PARAGRAPHS]).getValue(); }
public boolean ignoreDoubleSpaces() { return ((BooleanOption) options[IGNORE_DOUBLE_SPACES]).getValue(); }
public int imageSize() { return ((IntegerOption) options[IMAGE_SIZE]).getValue(); }
public boolean xhtmlNoDoctype() { return ((BooleanOption) options[NO_DOCTYPE]).getValue(); }
public boolean xhtmlAddBOM() { return ((BooleanOption) options[ADD_BOM]).getValue(); }
public String xhtmlEncoding() { return options[ENCODING].getString(); }
public boolean useNamedEntities() { return ((BooleanOption) options[USE_NAMED_ENTITIES]).getValue(); }
public boolean hexadecimalEntities() { return ((BooleanOption) options[HEXADECIMAL_ENTITIES]).getValue(); }
public boolean prettyPrint() { return ((BooleanOption) options[PRETTY_PRINT]).getValue(); }
public boolean multilingual() { return ((BooleanOption) options[MULTILINGUAL]).getValue(); }
public String templateIds() { return options[TEMPLATE_IDS].getString(); }
public boolean separateStylesheet() { return ((BooleanOption) options[SEPARATE_STYLESHEET]).getValue(); }
public String xhtmlCustomStylesheet() { return options[CUSTOM_STYLESHEET].getString(); }
public int xhtmlFormatting() { return ((XhtmlFormatOption) options[FORMATTING]).getValue(); }
public int xhtmlFrameFormatting() { return ((XhtmlFormatOption) options[FRAME_FORMATTING]).getValue(); }
public int xhtmlSectionFormatting() { return ((XhtmlFormatOption) options[SECTION_FORMATTING]).getValue(); }
public int xhtmlTableFormatting() { return ((XhtmlFormatOption) options[TABLE_FORMATTING]).getValue(); }
public int tableSize() { return ((IntegerOption) options[TABLE_SIZE]).getValue(); }
public int listFormatting() { return ((IntegerOption) options[LIST_FORMATTING]).getValue(); }
public String getMaxWidth() { return options[MAX_WIDTH].getString(); }
public boolean useDefaultFont() { return ((BooleanOption) options[USE_DEFAULT_FONT]).getValue(); }
public String defaultFontName() { return options[DEFAULT_FONT_NAME].getString(); }
public boolean xhtmlUseDublinCore() { return ((BooleanOption) options[USE_DUBLIN_CORE]).getValue(); }
public boolean xhtmlNotes() { return ((BooleanOption) options[NOTES]).getValue(); }
public boolean displayHiddenText() { return ((BooleanOption) options[DISPLAY_HIDDEN_TEXT]).getValue(); }
public boolean xhtmlConvertToPx() { return ((BooleanOption) options[CONVERT_TO_PX]).getValue(); }
public String getXhtmlScaling() { return options[SCALING].getString(); }
public String getXhtmlColumnScaling() { return options[COLUMN_SCALING].getString(); }
public boolean relativeFontSize() { return ((BooleanOption) options[RELATIVE_FONT_SIZE]).getValue(); }
public String fontScaling() { return options[FONT_SCALING].getString(); }
public boolean xhtmlFloatObjects() { return ((BooleanOption) options[FLOAT_OBJECTS]).getValue(); }
public String getXhtmlTabstopStyle() { return options[TABSTOP_STYLE].getString(); }
public String getEndnotesHeading() { return options[ENDNOTES_HEADING].getString(); }
public String getFootnotesHeading() { return options[FOOTNOTES_HEADING].getString(); }
public int formulas() { return ((IntegerOption) options[FORMULAS]).getValue(); }
public int externalTocDepth() { return ((IntegerOption) options[EXTERNAL_TOC_DEPTH]).getValue(); }
public boolean includeToc() { return ((BooleanOption) options[INCLUDE_TOC]).getValue(); }
public boolean includeNCX() { return ((BooleanOption) options[INCLUDE_NCX]).getValue(); }
public int getXhtmlSplitLevel() { return ((IntegerOption) options[SPLIT_LEVEL]).getValue(); }
public int getXhtmlRepeatLevels() { return ((IntegerOption) options[REPEAT_LEVELS]).getValue(); }
public int pageBreakSplit() { return ((IntegerOption) options[PAGE_BREAK_SPLIT]).getValue(); }
public int splitAfter() { return ((IntegerOption) options[SPLIT_AFTER]).getValue(); }
public String imageSplit() { return options[IMAGE_SPLIT].getString(); }
public boolean coverImage() { return ((BooleanOption) options[COVER_IMAGE]).getValue(); }
public boolean embedSVG() { return ((BooleanOption) options[EMBED_SVG]).getValue(); }
public boolean embedImg() { return ((BooleanOption) options[EMBED_IMG]).getValue(); }
public boolean useMathJax() { return ((BooleanOption) options[USE_MATHJAX]).getValue(); }
public boolean xhtmlCalcSplit() { return ((BooleanOption) options[CALC_SPLIT]).getValue(); }
public boolean xhtmlDisplayHiddenSheets() { return ((BooleanOption) options[DISPLAY_HIDDEN_SHEETS]).getValue(); }
public boolean displayHiddenRowsCols() { return ((BooleanOption) options[DISPLAY_HIDDEN_ROWS_COLS]).getValue(); }
public boolean displayFilteredRowsCols() { return ((BooleanOption) options[DISPLAY_FILTERED_ROWS_COLS]).getValue(); }
public boolean applyPrintRanges() { return ((BooleanOption) options[APPLY_PRINT_RANGES]).getValue(); }
public boolean xhtmlUseTitleAsHeading() { return ((BooleanOption) options[USE_TITLE_AS_HEADING]).getValue(); }
public boolean xhtmlUseSheetNamesAsHeadings() { return ((BooleanOption) options[USE_SHEET_NAMES_AS_HEADINGS]).getValue(); }
public boolean saveImagesInSubdir() { return ((BooleanOption) options[SAVE_IMAGES_IN_SUBDIR]).getValue(); }
public String getXhtmlUplink() { return options[UPLINK].getString(); }
public String getXhtmlDirectoryIcon() { return options[DIRECTORY_ICON].getString(); }
public String getXhtmlDocumentIcon() { return options[DOCUMENT_ICON].getString(); }
<<<<<<< HEAD
public String getHeadingTags() { return options[HEADING_TAGS].getString(); }
public String getPageTags() { return options[PAGE_TAGS].getString(); }
=======
public String greenstoneTags() { return options[GREENSTONE_TAGS].getString(); }
>>>>>>> Added Footer and Header html convertation. Added comments to use html as input for Greenstone project.
public XhtmlStyleMap getXParStyleMap() { return getStyleMap(xpar); }
public XhtmlStyleMap getXHeadingStyleMap() { return getStyleMap(xheading); }
public XhtmlStyleMap getXTextStyleMap() { return getStyleMap(xtext); }
public XhtmlStyleMap getXFrameStyleMap() { return getStyleMap(xframe); }
public XhtmlStyleMap getXListStyleMap() { return getStyleMap(xlist); }
public XhtmlStyleMap getXAttrStyleMap() { return getStyleMap(xattr); }
private XhtmlStyleMap getStyleMap(ComplexOption co) {
XhtmlStyleMap map = new XhtmlStyleMap();
for (String sName : co.keySet()) {
Map<String,String> attr = co.get(sName);
String sElement = attr.containsKey("element") ? attr.get("element") : "";
String sCss = attr.containsKey("css") ? attr.get("css") : "";
String sBlockElement = attr.containsKey("block-element") ? attr.get("block-element") : "";
String sBlockCss = attr.containsKey("block-css") ? attr.get("block-css") : "";
String sBefore = attr.containsKey("before") ? attr.get("before") : "";
String sAfter = attr.containsKey("after") ? attr.get("after") : "";
map.put(sName, new XhtmlStyleMapItem(sBlockElement, sBlockCss, sElement, sCss, sBefore, sAfter));
}
return map;
}
}

View file

@ -0,0 +1,997 @@
/************************************************************************
*
* XhtmlDocument.java
*
* Copyright: 2002-2015 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2015-05-05)
*
*/
//TODO: Add named entities outside ISO-latin 1
//TODO: When polyglot markup uses either a textarea or pre element, the text within the element does not begin with a newline.
package writer2latex.xhtml;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.DOMImplementation;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import writer2latex.base.DOMDocument;
import writer2latex.office.XMLString;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* An implementation of <code>Document</code> for
* XHTML documents.
*/
public class XhtmlDocument extends DOMDocument {
/** Constant to identify XHTML 1.0 strict documents */
public static final int XHTML10 = 0;
/** Constant to identify XHTML 1.1 documents */
public static final int XHTML11 = 1;
/** Constant to identify XHTML + MathML documents */
public static final int XHTML_MATHML = 2;
/** Constant to identify HTML5 documents */
public static final int HTML5 = 3;
// Some static data
private static final String[] sExtension = { ".html", ".xhtml", ".xhtml", ".html" };
private static Set<String> blockPrettyPrint;
private static Set<String> conditionalBlockPrettyPrint;
private static Set<String> emptyElements;
private static Set<String> emptyHtml5Elements;
private static String[] entities; // Not convenient to define directly due to a lot of null values
// Type of document
private int nType;
// Configuration
private String sEncoding = "UTF-8";
private boolean bUseNamedEntities = false;
private boolean bHexadecimalEntities = true;
private char cLimit = 65535;
private boolean bNoDoctype = false;
private boolean bAddBOM = false;
private boolean bPrettyPrint = true;
private String sContentId = "content";
private String sHeaderId = "header";
private String sFooterId = "footer";
private String sPanelId = "panel";
// Content
private Element headNode = null;
private Element bodyNode = null;
private Element titleNode = null;
private Element contentNode = null;
private Element panelNode = null;
private Element headerNode = null;
private Element footerNode = null;
// Initialize static data
static {
// Paragraphs and headings always block pretty printing
blockPrettyPrint = new HashSet<String>();
blockPrettyPrint.add("p");
blockPrettyPrint.add("h1");
blockPrettyPrint.add("h2");
blockPrettyPrint.add("h3");
blockPrettyPrint.add("h4");
blockPrettyPrint.add("h5");
blockPrettyPrint.add("h6");
// List items and table cells may block pretty printing, depending on the context
conditionalBlockPrettyPrint = new HashSet<String>();
conditionalBlockPrettyPrint.add("li");
conditionalBlockPrettyPrint.add("th");
conditionalBlockPrettyPrint.add("td");
// These elements are empty
emptyElements = new HashSet<String>();
emptyElements.add("base");
emptyElements.add("meta");
emptyElements.add("link");
emptyElements.add("hr");
emptyElements.add("br");
emptyElements.add("param");
emptyElements.add("img");
emptyElements.add("area");
emptyElements.add("input");
emptyElements.add("col");
// These elements are empty in HTML5
emptyHtml5Elements = new HashSet<String>();
emptyHtml5Elements.add("base");
emptyHtml5Elements.add("meta");
emptyHtml5Elements.add("link");
emptyHtml5Elements.add("hr");
emptyHtml5Elements.add("br");
emptyHtml5Elements.add("param");
emptyHtml5Elements.add("img");
emptyHtml5Elements.add("area");
emptyHtml5Elements.add("input");
emptyHtml5Elements.add("col");
emptyHtml5Elements.add("command");
emptyHtml5Elements.add("embed");
emptyHtml5Elements.add("keygen");
emptyHtml5Elements.add("source");
// Named character entities (currently only those within the ISO latin 1 range)
entities = new String[256];
// Latin 1 symbols
entities[160]="&nbsp;";
entities[161]="&iexcl;";
entities[162]="&cent;";
entities[163]="&pound;";
entities[164]="&curren;";
entities[165]="&yen;";
entities[166]="&brvbar;";
entities[167]="&sect;";
entities[168]="&uml;";
entities[169]="&copy;";
entities[170]="&ordf;";
entities[171]="&laquo;";
entities[172]="&not;";
entities[173]="&shy;";
entities[174]="&reg;";
entities[175]="&macr;";
entities[176]="&deg;";
entities[177]="&plusmn;";
entities[178]="&sup2;";
entities[179]="&sup3;";
entities[180]="&acute;";
entities[181]="&micro;";
entities[182]="&para;";
entities[183]="&middot;";
entities[184]="&cedil;";
entities[185]="&sup1;";
entities[186]="&ordm;";
entities[187]="&raquo;";
entities[188]="&frac14;";
entities[189]="&frac12;";
entities[190]="&frac34;";
entities[191]="&iquest;";
entities[215]="&times;";
entities[247]="&divide;";
// Latin 1 characters
entities[192]="&Agrave;";
entities[193]="&Aacute;";
entities[194]="&Acirc;";
entities[195]="&Atilde;";
entities[196]="&Auml;";
entities[197]="&Aring;";
entities[198]="&AElig;";
entities[199]="&Ccedil;";
entities[200]="&Egrave;";
entities[201]="&Eacute;";
entities[202]="&Ecirc;";
entities[203]="&Euml;";
entities[204]="&Igrave;";
entities[205]="&Iacute;";
entities[206]="&Icirc;";
entities[207]="&Iuml;";
entities[208]="&ETH;";
entities[209]="&Ntilde;";
entities[210]="&Ograve;";
entities[211]="&Oacute;";
entities[212]="&Ocirc;";
entities[213]="&Otilde;";
entities[214]="&Ouml;";
entities[216]="&Oslash;";
entities[217]="&Ugrave;";
entities[218]="&Uacute;";
entities[219]="&Ucirc;";
entities[220]="&Uuml;";
entities[221]="&Yacute;";
entities[222]="&THORN;";
entities[223]="&szlig;";
entities[224]="&agrave;";
entities[225]="&aacute;";
entities[226]="&acirc;";
entities[227]="&atilde;";
entities[228]="&auml;";
entities[229]="&aring;";
entities[230]="&aelig;";
entities[231]="&ccedil;";
entities[232]="&egrave;";
entities[233]="&eacute;";
entities[234]="&ecirc;";
entities[235]="&euml;";
entities[236]="&igrave;";
entities[237]="&iacute;";
entities[238]="&icirc;";
entities[239]="&iuml;";
entities[240]="&eth;";
entities[241]="&ntilde;";
entities[242]="&ograve;";
entities[243]="&oacute;";
entities[244]="&ocirc;";
entities[245]="&otilde;";
entities[246]="&ouml;";
entities[248]="&oslash;";
entities[249]="&ugrave;";
entities[250]="&uacute;";
entities[251]="&ucirc;";
entities[252]="&uuml;";
entities[253]="&yacute;";
entities[254]="&thorn;";
entities[255]="&yuml;";
}
public static final String getExtension(int nType) {
return sExtension[nType];
}
/**
* Constructor. This constructor also creates the DOM (minimal: root, head,
* title and body node only)
* @param name name of this document
* @param nType the type of document
*/
public XhtmlDocument(String name, int nType) {
super(name,sExtension[nType]);
this.nType = nType;
// create DOM
Document contentDOM = null;
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
DOMImplementation domImpl = builder.getDOMImplementation();
String[] sDocType = getDoctypeStrings();
DocumentType doctype = domImpl.createDocumentType("html", sDocType[0], sDocType[1]);
contentDOM = domImpl.createDocument("http://www.w3.org/1999/xhtml","html",doctype);
contentDOM.getDocumentElement().setAttribute("xmlns","http://www.w3.org/1999/xhtml");
// add head, title and body
headNode = contentDOM.createElement("head");
titleNode = contentDOM.createElement("title");
bodyNode = contentDOM.createElement("body");
contentDOM.getDocumentElement().appendChild(headNode);
headNode.appendChild(titleNode);
contentDOM.getDocumentElement().appendChild(bodyNode);
contentNode = bodyNode;
setContentDOM(contentDOM);
}
catch (ParserConfigurationException e) {
// The newDocumentBuilder() method may in theory throw this, but this will not happen
e.printStackTrace();
}
}
@Override public String getMIMEType() {
// Get the real MIME type, not the pseudo ones used by the converter API
// We always produce XHTML, thus
return "application/xhtml+xml";
}
@Override public boolean isMasterDocument() {
return true;
}
@Override public boolean containsMath() {
return bodyNode!=null ? containsMath(bodyNode) : false;
}
public Element getHeadNode() { return headNode; }
public Element getBodyNode() { return bodyNode; }
public Element getTitleNode() { return titleNode; }
public Element getContentNode() { return contentNode; }
public void setContentNode(Element contentNode) { this.contentNode = contentNode; }
public Element getPanelNode() { return panelNode; }
public Element getHeaderNode() { return headerNode; }
public Element getFooterNode() { return footerNode; }
public void createHeaderFooter() {
if (nType==HTML5) {
Element header1 = getContentDOM().createElement("header");
bodyNode.appendChild(header1);
headerNode = getContentDOM().createElement("nav");
header1.appendChild(headerNode);
}
else {
headerNode = getContentDOM().createElement("div");
bodyNode.appendChild(headerNode);
}
headerNode.setAttribute("id",sHeaderId);
contentNode = getContentDOM().createElement("div");
contentNode.setAttribute("id",sContentId);
bodyNode.appendChild(contentNode);
if (nType==HTML5) {
Element footer1 = getContentDOM().createElement("footer");
bodyNode.appendChild(footer1);
footerNode = getContentDOM().createElement("nav");
footer1.appendChild(footerNode);
}
else {
footerNode = getContentDOM().createElement("div");
bodyNode.appendChild(footerNode);
}
footerNode.setAttribute("id",sFooterId);
}
public void setContentDOM(Document doc) {
super.setContentDOM(doc);
collectNodes();
}
/** Does this document contain any math nodes?
*
* @return true if so
*/
public boolean hasMath() {
return hasMath(getContentDOM().getDocumentElement());
}
private boolean hasMath(Element node) {
// Check this element
if (node.getTagName().equals(XMLString.MATH)) {
return true;
}
// Check children
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE && hasMath((Element)child)) {
return true;
}
child = child.getNextSibling();
}
// Found nothing
return false;
}
public void read(InputStream is) throws IOException {
super.read(is);
collectNodes();
}
public void readFromTemplate(XhtmlDocument template) {
// create a new DOM
Document templateDOM = template.getContentDOM();
Document newDOM = null;
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
DOMImplementation domImpl = builder.getDOMImplementation();
String[] sDocType = getDoctypeStrings();
DocumentType doctype = domImpl.createDocumentType("html", sDocType[0], sDocType[1]);
newDOM = domImpl.createDocument("http://www.w3.org/1999/xhtml",
templateDOM.getDocumentElement().getTagName(),doctype);
setContentDOM(newDOM);
// Import attributes on root element
Element templateRoot = templateDOM.getDocumentElement();
Element newRoot = newDOM.getDocumentElement();
NamedNodeMap attributes = templateRoot.getAttributes();
int nCount = attributes.getLength();
for (int i=0; i<nCount; i++) {
Node attrNode = attributes.item(i);
newRoot.setAttribute(attrNode.getNodeName(), attrNode.getNodeValue());
}
// Import all child nodes from template
NodeList children = templateRoot.getChildNodes();
int nLen = children.getLength();
for (int i=0; i<nLen; i++) {
newRoot.appendChild(getContentDOM().importNode(children.item(i),true));
}
// get the entry point nodes
collectNodes();
}
catch (Throwable t) {
t.printStackTrace();
}
}
private String[] getDoctypeStrings() {
// Define publicId and systemId (null for HTML5)
String sPublicId = null;
String sSystemId = null;
switch (nType) {
case XHTML10 :
sPublicId = "-//W3C//DTD XHTML 1.0 Strict//EN";
sSystemId = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
break;
case XHTML11 :
sPublicId = "-//W3C//DTD XHTML 1.1//EN";
sSystemId = "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd";
break;
case XHTML_MATHML :
sPublicId = "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN";
sSystemId = "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd";
//sSystemId = "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd"; (old version)
/* An alternative is to use XHTML + MathML + SVG:
sPublicId = "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN",
sSystemId = "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd"); */
}
return new String[] { sPublicId, sSystemId };
}
private void collectNodes(Element elm) {
String sTagName = elm.getTagName();
if ("head".equals(sTagName)) {
headNode = elm;
}
else if ("body".equals(sTagName)) {
bodyNode = elm;
}
else if ("title".equals(sTagName)) {
titleNode = elm;
}
else {
String sId = elm.getAttribute("id");
if (sContentId.equals(sId)) { contentNode = elm; }
else if (sHeaderId.equals(sId)) { headerNode = elm; }
else if (sFooterId.equals(sId)) { footerNode = elm; }
else if (sPanelId.equals(sId)) { panelNode = elm; }
}
Node child = elm.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
collectNodes((Element)child);
}
child = child.getNextSibling();
}
}
private void collectNodes() {
headNode = null;
bodyNode = null;
titleNode = null;
contentNode = null;
headerNode = null;
footerNode = null;
panelNode = null;
Element elm = getContentDOM().getDocumentElement();
collectNodes(elm);
if (contentNode==null) { contentNode = bodyNode!=null ? bodyNode : elm; }
if (headNode!=null && titleNode==null) {
titleNode = getContentDOM().createElement("title");
headNode.appendChild(titleNode);
}
}
public void setConfig(XhtmlConfig config) {
sEncoding = config.xhtmlEncoding().toUpperCase();
if ("UTF-16".equals(sEncoding)) {
cLimit = 65535;
}
else if ("ISO-8859-1".equals(sEncoding)) {
cLimit = 255;
}
else if ("US-ASCII".equals(sEncoding)) {
cLimit = 127;
}
else {
sEncoding = "UTF-8";
cLimit = 65535;
}
bAddBOM = config.xhtmlAddBOM() && sEncoding.equals("UTF-8");
bNoDoctype = config.xhtmlNoDoctype();
bPrettyPrint = config.prettyPrint();
bUseNamedEntities = config.useNamedEntities();
bHexadecimalEntities = config.hexadecimalEntities();
String[] sTemplateIds = config.templateIds().split(",");
int nIdCount = sTemplateIds.length;
if (nIdCount>0 && sTemplateIds[0].trim().length()>0) sContentId = sTemplateIds[0].trim(); else sContentId = "content";
if (nIdCount>1) sHeaderId = sTemplateIds[1].trim(); else sHeaderId = "header";
if (nIdCount>2) sFooterId = sTemplateIds[2].trim(); else sFooterId = "footer";
if (nIdCount>3) sPanelId = sTemplateIds[3].trim(); else sPanelId = "panel";
}
public String getEncoding() { return sEncoding; }
public String getFileExtension() { return super.getFileExtension(); }
// Optimize the usage of xml:dir and xml:lang attributes
private void optimize(Element node, String sLang, String sDir) {
if (node.hasAttribute("xml:lang")) {
if (node.getAttribute("xml:lang").equals(sLang)) {
node.removeAttribute("xml:lang");
if (node.hasAttribute("lang")) {
node.removeAttribute("lang");
}
}
else {
sLang = node.getAttribute("xml:lang");
}
}
if (node.hasAttribute("xml:dir")) {
if (node.getAttribute("xml:dir").equals(sDir)) {
node.removeAttribute("xml:dir");
}
else {
sDir = node.getAttribute("xml:dir");
}
}
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
optimize((Element)child, sLang, sDir);
}
child = child.getNextSibling();
}
}
/**
* Write out content to the supplied <code>OutputStream</code>.
* (with pretty printing)
* @param os XML <code>OutputStream</code>.
* @throws IOException If any I/O error occurs.
*/
public void write(OutputStream os) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(os,sEncoding);
// Add a BOM if the user desires so
if (bAddBOM) { osw.write("\uFEFF"); }
// Omit XML prolog for pure XHTML 1.0 strict documents (HTML 4 compaitbility)
// and for HTML5 documents (polyglot document)
if (nType!=XHTML10 && nType!=HTML5) {
osw.write("<?xml version=\"1.0\" encoding=\""+sEncoding+"\" ?>\n");
}
// Specify DOCTYPE (the user may require that no DOCTYPE is used;
// this may be desirable for further transformations)
if (!bNoDoctype) {
if (nType==HTML5) {
osw.write("<!DOCTYPE html>\n");
}
else {
DocumentType docType = getContentDOM().getDoctype();
if (docType!=null) {
osw.write("<!DOCTYPE html PUBLIC \"");
osw.write(docType.getPublicId());
osw.write("\" \"");
osw.write(docType.getSystemId());
osw.write("\">\n");
}
}
}
Element doc = getContentDOM().getDocumentElement();
optimize(doc,null,null);
write(doc,bPrettyPrint ? 0 : -1,osw);
osw.flush();
osw.close();
}
private static boolean blockThis(Element node) {
String sTagName = node.getTagName();
if (blockPrettyPrint.contains(sTagName)) {
return true;
}
else if (conditionalBlockPrettyPrint.contains(sTagName)) {
// Block pretty printing if the content is anything but elements that block pretty print
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE && !blockPrettyPrint.contains(child.getNodeName())) {
return true;
}
child = child.getNextSibling();
}
return false;
}
else {
// Other elements block pretty printing if they contain text nodes
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.TEXT_NODE) {
return true;
}
child = child.getNextSibling();
}
return false;
}
}
private boolean isEmpty(String sTagName) {
return nType==HTML5 ? emptyHtml5Elements.contains(sTagName) : emptyElements.contains(sTagName);
}
// Write nodes; we only need element, text and comment nodes
private void write(Node node, int nLevel, OutputStreamWriter osw) throws IOException {
short nType = node.getNodeType();
switch (nType) {
case Node.ELEMENT_NODE:
if (isEmpty(node.getNodeName())) {
// This node must be empty, we ignore child nodes
String sNodeName = node.getNodeName();
if (nLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("<"+sNodeName);
writeAttributes(node,osw);
osw.write(" />");
if (nLevel>=0) { osw.write("\n"); }
}
else if (node.hasChildNodes()) {
int nNextLevel = (nLevel<0 || blockThis((Element)node)) ? -1 : nLevel+1;
// Print start tag
boolean bRedundantElement = !node.hasAttributes() &&
(node.getNodeName().equals("a") || node.getNodeName().equals("span"));
if (!bRedundantElement) {
// Writer2xhtml may produce <a> and <span> without attributes, these are removed here
if (nLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("<"+node.getNodeName());
writeAttributes(node,osw);
osw.write(">");
if (nNextLevel>=0) { osw.write("\n"); }
}
// Print children
Node child = node.getFirstChild();
while (child!=null) {
write(child,nNextLevel,osw);
child = child.getNextSibling();
}
// Print end tag
if (!bRedundantElement) {
if (nNextLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("</"+node.getNodeName()+">");
if (nLevel>=0) { osw.write("\n"); }
}
}
else { // empty element
if (nLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("<"+node.getNodeName());
writeAttributes(node,osw);
// HTML compatibility: use end-tag even if empty
if (nType<=XHTML11 || nType==HTML5) {
osw.write("></"+node.getNodeName()+">");
}
else {
osw.write(" />");
}
if (nLevel>=0) { osw.write("\n"); }
}
break;
case Node.TEXT_NODE:
write(node.getNodeValue(),osw);
break;
case Node.COMMENT_NODE:
if (nLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("<!-- ");
//write(node.getNodeValue(),osw);
osw.write(node.getNodeValue());
osw.write(" -->");
if (nLevel>=0) { osw.write("\n"); }
}
}
private void writeAttributes(Node node, OutputStreamWriter osw) throws IOException {
NamedNodeMap attr = node.getAttributes();
int nLen = attr.getLength();
for (int i=0; i<nLen; i++) {
Node item = attr.item(i);
osw.write(" ");
write(item.getNodeName(),osw);
osw.write("=\"");
writeAttribute(item.getNodeValue(),osw);
osw.write("\"");
}
}
private void writeSpaces(int nCount, OutputStreamWriter osw) throws IOException {
for (int i=0; i<nCount; i++) { osw.write(" "); }
}
private void write(String s, OutputStreamWriter osw) throws IOException {
// Allow null strings, though this means there is a bug somewhere...
if (s==null) { osw.write("null"); return; }
int nLen = s.length();
char c;
for (int i=0; i<nLen; i++) {
c = s.charAt(i);
switch (c) {
case ('<'): osw.write("&lt;"); break;
case ('>'): osw.write("&gt;"); break;
case ('&'): osw.write("&amp;"); break;
default:
write(c,osw);
}
}
}
private void writeAttribute(String s, OutputStreamWriter osw) throws IOException {
int nLen = s.length();
char c;
for (int i=0; i<nLen; i++) {
c = s.charAt(i);
switch (c) {
case ('<'): osw.write("&lt;"); break;
case ('>'): osw.write("&gt;"); break;
case ('&'): osw.write("&amp;"); break;
case ('"'): osw.write("&quot;"); break;
case ('\''): osw.write( nType == XHTML10 ? "&#39;" : "&apos;"); break;
default:
write(c,osw);
}
}
}
private void write(char c, OutputStreamWriter osw) throws IOException {
if (bUseNamedEntities) {
if (c<256 && entities[c]!=null) {
// XHTML has a named entity here
osw.write(entities[c]);
return;
}
String s=getMathMLEntity(c);
if (s!=null && (nType==XHTML_MATHML)) {
// There's a MathML entity to use
osw.write(s);
return;
}
}
if (c>cLimit) {
if (bHexadecimalEntities) {
osw.write("&#x"+Integer.toHexString(c).toUpperCase()+";");
}
else {
osw.write("&#"+Integer.toString(c).toUpperCase()+";");
}
}
else {
osw.write(c);
}
}
// Translate character to MathML entity (contributed by Bruno Mascret)
private String getMathMLEntity(char c) {
switch (c) {
case '\u0192': return "&fnof;";// lettre minuscule latine f hameon
case '\u0391': return "&Alpha;";// lettre majuscule grecque alpha
case '\u0392': return "&Beta;";// lettre majuscule grecque beta
case '\u0393': return "&Gamma;";// lettre majuscule grecque gamma
case '\u0394': return "&Delta;";// lettre majuscule grecque delta
case '\u0395': return "&Epsilon;";// lettre majuscule grecque epsilon
case '\u0396': return "&Zeta;";// lettre majuscule grecque zeta
case '\u0397': return "&Eta;";// lettre majuscule grecque eta
case '\u0398': return "&Theta;";// lettre majuscule grecque theta
case '\u0399': return "&Iota;";// lettre majuscule grecque iota
case '\u039A': return "&Kappa;";// lettre majuscule grecque kappa
case '\u039B': return "&Lambda;";// lettre majuscule grecque lambda
case '\u039C': return "&Mu;";// lettre majuscule grecque mu
case '\u039D': return "&Nu;";// lettre majuscule grecque nu
case '\u039E': return "&Xi;";// lettre majuscule grecque xi
case '\u039F': return "&Omicron;";// lettre majuscule grecque omicron
case '\u03A0': return "&Pi;";// lettre majuscule grecque pi
case '\u03A1': return "&Rho;";// lettre majuscule grecque rho
case '\u03A3': return "&Sigma;";// lettre majuscule grecque sigma (Il n'y pas de caractere Sigmaf ni U+03A2 non plus)
case '\u03A4': return "&Tau;";// lettre majuscule grecque tau
case '\u03A5': return "&Upsilon;";// lettre majuscule grecque upsilon
case '\u03A6': return "&Phi;";// lettre majuscule grecque phi
case '\u03A7': return "&Chi;";// lettre majuscule grecque chi
case '\u03A8': return "&Psi;";// lettre majuscule grecque psi
case '\u03A9': return "&Omega;";// lettre majuscule grecque omega
case '\u03B1': return "&alpha;";// lettre minuscule grecque alpha
case '\u03B2': return "&beta;";// lettre minuscule grecque beta
case '\u03B3': return "&gamma;";// lettre minuscule grecque gamma
case '\u03B4': return "&delta;";// lettre minuscule grecque delta
//case '\u03B4': return "&delta;";// lettre minuscule grecque delta
case '\u03B5': return "&epsilon;";// lettre minuscule grecque epsilon
case '\u03B6': return "&zeta;";// lettre minuscule grecque zeta
case '\u03B7': return "&eta;";// lettre minuscule grecque eta
case '\u03B8': return "&theta;";// lettre minuscule grecque theta
case '\u03B9': return "&iota;";// lettre minuscule grecque iota
case '\u03BA': return "&kappa;";// lettre minuscule grecque kappa
case '\u03BB': return "&lambda;";// lettre minuscule grecque lambda
case '\u03BC': return "&mu;";// lettre minuscule grecque mu
case '\u03BD': return "&nu;";// lettre minuscule grecque nu
case '\u03BE': return "&xi;";// lettre minuscule grecque xi
case '\u03BF': return "&omicron;";// lettre minuscule grecque omicron
case '\u03C0': return "&pi;";// lettre minuscule grecque pi
case '\u03C1': return "&rho;";// lettre minuscule grecque rho
case '\u03C2': return "&sigmaf;";// lettre minuscule grecque final sigma
case '\u03C3': return "&sigma;";// lettre minuscule grecque sigma
case '\u03C4': return "&tau;";// lettre minuscule grecque tau
case '\u03C5': return "&upsilon;";// lettre minuscule grecque upsilon
case '\u03C6': return "&phi;";// lettre minuscule grecque phi
case '\u03C7': return "&chi;";// lettre minuscule grecque chi
case '\u03C8': return "&psi;";// lettre minuscule grecque psi
case '\u03C9': return "&omega;";// lettre minuscule grecque omega
case '\u03D1': return "&thetasym;";// lettre minuscule grecque theta symbol
case '\u03D2': return "&upsih;";// symbole grec upsilon crochet
case '\u03D6': return "&piv;";// symbole grec pi
case '\u2022': return "&bull;";// puce (Ce N'EST PAS la meme chose que l'operateur puce, U+2219)
case '\u2026': return "&hellip;";// points de suspension
case '\u2032': return "&prime;";// prime
case '\u2033': return "&Prime;";// double prime
case '\u203E': return "&oline;";// tiret en chef
case '\u2044': return "&frasl;";// barre de fraction
case '\u2118': return "&weierp;";// fonction elliptique de Weierstrass
case '\u2111': return "&image;";// majuscule I gothique = partie imaginaire
case '\u211C': return "&real;";// majuscule R gothique = partie reelle
case '\u2122': return "&trade;";// symbole marque commerciale
case '\u2135': return "&alefsym;";// symbole alef = premier nombre transfini (Le symbole alef N'EST PAS pareil a la lettre hebreue alef, U+05D0 meme si on pourrait utiliser le meme glyphe pour representer les deux caracteres)
case '\u2190': return "&larr;";// fleche vers la gauche
case '\u2191': return "&uarr;";// fleche vers le haut
case '\u2192': return "&rarr;";// fleche vers la droite
case '\u2193': return "&darr;";// fleche vers le bas
case '\u2194': return "&harr;";// fleche bilaterale
case '\u21B5': return "&crarr;";// fleche vers le bas avec coin vers la gauche = retour de chariot
case '\u21D0': return "&lArr;";// double fleche vers la gauche (ISO 10646 ne dit pas que lArr est la meme chose que la fleche 'est implique par' et n'a pas non plus d'autre caractere pour cette fonction. Alors ? On peut utiliser lArr pour 'est implique par' comme le suggere)
case '\u21D1': return "&uArr;";// double fleche vers le haut
case '\u21D2': return "&rArr;";// double fleche vers la droite (ISO 10646 ne dit pas qu'il s'agit du caractere 'implique' et n'a pas non plus d'autre caractere avec cette fonction. Alors ? On peut utiliser rArr pour 'implique' comme le suggere)
case '\u21D3': return "&dArr;";// double fleche vers le bas
case '\u21D4': return "&hArr;";// double fleche bilaterale
case '\u2200': return "&forall;";// pour tous
case '\u2202': return "&part;";// derivee partielle
case '\u2203': return "&exist;";// il existe
case '\u2205': return "&empty;";// ensemble vide = symbole diametre
case '\u2207': return "&nabla;";// nabla
case '\u2208': return "&isin;";// appartient
case '\u2209': return "&notin;";// n'appartient pas
case '\u220B': return "&ni;";// contient comme element (Est-ce qu'il ne pourrait pas y avoir un nom plus parlant que 'ni' ?)
case '\u220F': return "&prod;";// produit de la famille = signe produit (prod N'EST PAS le meme caractere que U+03A0 'lettre capitale grecque pi' meme si le meme glyphe peut s'utiliser pour les deux)
case '\u2211': return "&sum;";// sommation de la famille (sum N'EST PAS le meme caractere que U+03A3 'ettre capitale grecque sigma' meme si le meme glyphe peut s'utiliser pour les deux)
case '\u2212': return "&minus;";// signe moins
case '\u2217': return "&lowast;";// operateur asterisque
case '\u221A': return "&radic;";// racine carree = signe radical
case '\u221D': return "&prop;";// proportionnel
case '\u221E': return "&infin;";// infini
case '\u2220': return "&ang;";// angle
case '\u2227': return "&and;";// ET logique
case '\u2228': return "&or;";// OU logique
case '\u2229': return "&cap;";// intersection = cap
case '\u222A': return "&cup;";// union = cup
case '\u222B': return "&int;";// integrale
case '\u2234': return "&there4;";// par consequent
case '\u223C': return "&sim;";// operateur tilde = varie avec = similaire (L'operateur tilde N'EST PAS le meme caractere que le tilde U+007E, meme si le meme glyphe peut s'utiliser pour les deux)
case '\u2245': return "&cong;";// approximativement egal
case '\u2248': return "&asymp;";// presque egal = asymptotique
case '\u2260': return "&ne;";// pas egal
case '\u2261': return "&equiv;";// identique
//case '\u2261': return "&equiv;";// identique
case '\u2264': return "&le;";// plus petit ou egal
case '\u2265': return "&ge;";// plus grand ou egal
case '\u2282': return "&sub;";// sous-ensemble de
case '\u2283': return "&sup;";// sur-ensemble de (Remarquez que nsup 'pas un sur-ensemble de' 2285, n'est pas couvert par le codage de la police Symbol. Devrait-il l'etre par symetrie ? Il est dans)
case '\u2284': return "&nsub;";// pas un sous-ensemble de
case '\u2286': return "&sube;";// sous-ensemble ou egal
case '\u2287': return "&supe;";// sur-ensemble de ou egal
case '\u2295': return "&oplus;";// plus cercle = somme directe
case '\u2297': return "&otimes;";// multiplie par cercle = produit vectoriel
case '\u22A5': return "&perp;";// taquet vers le haut = orthogonal = perpendiculaire
case '\u22C5': return "&sdot;";// operateur point (L'operateur point N'EST PAS le meme caractere que le 'point median', U+00B7)
case '\u2308': return "&lceil;";// plafond gauche = anglet gauche
case '\u2309': return "&rceil;";// plafond droite
case '\u230A': return "&lfloor;";// plancher gauche
case '\u230B': return "&rfloor;";// plancher droite
case '\u2329': return "&lang;";// chevron vers la gauche (lang N'EST PAS le meme caractere que U+003C 'inferieur' ou U+2039 'guillemet simple vers la gauche')
case '\u232A': return "&rang;";// chevron vers la droite (rang iN'EST PAS le meme caractere que U+003E 'superieur' ou U+203A 'guillemet simple vers la droite')
case '\u25CA': return "&loz;";// losange
case '\u2660': return "&spades;";// pique noir (Noir semble dire ici rempli par opposition ajoure)
case '\u2663': return "&clubs;";// trefle noir
case '\u2665': return "&hearts;";// coeur noir
case '\u2666': return "&diams;";// carreau noir
// truc pas prevus
case '\u2102': return "&Copf;";// ensemble C des complexes
case '\u2115': return "&Nopf;";// ensemble N des entiers
case '\u211A': return "&Qopf;";// ensemble Q des rationnels
case '\u211D': return "&Ropf;";// ensemble R des reels
case '\u2124': return "&Zopf;";// ensemble R des entiers relatifs
case '\u2223': return "&mid;";// divise
case '\u2224': return "&nmid;";// ne divise pas
case '\u2243': return "&simeq;";// asymptotiquement egal
case '\u2244': return "&nsimeq;";// asymptotiquement egal
case '\u2225': return "&par;";// parallele
case '\u00B1': return "&PlusMinus;";// plus ou moins
case '\u2213': return "&MinusPlus;"; // moins ou plus (different de plus ou moins)
case '\u2494': return "&leqslant;"; // inferieur ou egal incline
case '\u2270': return "&nle;"; //non inferieur ou egal incline
case '\u00AC': return "&not;";// signe not
case '\u00B0': return "&circ;";// petit cercle, operateur concatenation, normalement &deg; mais on va le considere comme circ
case '\u224A': return "&ape;";// approxivativement egal
case '\u002B': return "&plus;"; // signe plus
case '\u00D7': return "&times;"; // signe multiplication (croix)
case '\u003D': return "&equals;"; // signe egal
case '\u226E': return "&nlt;"; // non inferieur
case '\u2A7D': return "&les;"; // inferieur incline = leqslant
case '\u220A': return "&isin;";// appartient
case '\u2216': return "&setminus;";// difference d'ensemble
case '\u2288': return "&nsube;";// ni un sous-ensemble ni egal
case '\u2289': return "&nsupe;";// ni un surensemble ni egal
case '\u2285': return "&nsup;";// non un surensemble de
case '\u301A': return "&lobrk;";// crochet gauche avec barre
case '\u301B': return "&robrk;";// crochet droit avec barre
case '\u2210': return "&coprod;";// coproduit (Pi l'envers)
case '\u222C': return "&Int;";// integrale double
case '\u222D': return "&tint;";// integrale triple
case '\u222E': return "&conint;";// integrale de contour
case '\u222F': return "&Conint;";// integrale de surface
case '\u2230': return "&Cconint;";// integrale de volume
case '\u210F': return "&hbar;";// const de Planck sur 2Pi
case '\u2253': return "&;";// BUG points suspensions diagonale descendant droite
case '\u22EE': return "&vellip;";// points suspensions verticaux
case '\u22EF': return "&ctdot;";// points suspensions horizontaux medians
case '\u22F0': return "&utdot;";// points suspensions diagonale montant droite
case '\u22F1': return "&dtdot;";// points suspensions diagonale descendant droite
case '\u02DA': return "&ring;"; //rond en chef
case '\u00A8': return "&Dot;"; // double point en chef(trema)
case '\u02D9': return "&dot;"; // point en chef
case '\u2015': return "&horbar;"; // barre horizonthale
case '\u00AF': return "&macr;"; // barre horizonthale en chef
case '\u0332': return "&UnderBar;"; // souligne
case '\u2222': return "&angsph;"; // angle spherique
case '\u03F1': return "&rhov;"; // symbole grec rho final
case '\u226B': return "&Gt;"; // tres superieur
case '\u226A': return "&Lt;"; // tres inferieur
default: return null;
}
}
private boolean containsMath(Element node) {
// First check the node itself
if (node.getTagName().equals("math")) {
return true;
}
// The check the children
Node child = node.getFirstChild();
while (child!=null) {
if (child.getNodeType()==Node.ELEMENT_NODE) {
if (containsMath((Element)child)) {
return true;
}
}
child = child.getNextSibling();
}
// And then look no further
return false;
}
}

View file

@ -0,0 +1,42 @@
/************************************************************************
*
* XhtmlFormatOption.java
*
* Copyright: 2002-2008 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.xhtml;
import writer2latex.base.IntegerOption;
class XhtmlFormatOption extends IntegerOption {
public XhtmlFormatOption(String sName, String sDefaultValue) {
super(sName,sDefaultValue);
}
public void setString(String sValue) {
super.setString(sValue);
if ("ignore_styles".equals(sValue)) nValue = XhtmlConfig.IGNORE_STYLES;
else if ("ignore_hard".equals(sValue)) nValue = XhtmlConfig.IGNORE_HARD;
else if ("ignore_all".equals(sValue)) nValue = XhtmlConfig.IGNORE_ALL;
else nValue = XhtmlConfig.CONVERT_ALL;
}
}

View file

@ -0,0 +1,34 @@
/************************************************************************
*
* XhtmlMathMLConverter.java
*
* Copyright: 2002-2008 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.0 (2008-09-09)
*
*/
package writer2latex.xhtml;
public class XhtmlMathMLConverter extends Converter {
public XhtmlMathMLConverter() {
super(XhtmlDocument.XHTML_MATHML);
}
}

View file

@ -0,0 +1,51 @@
/************************************************************************
*
* XhtmlStyleMap.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2014-10-24)
*
*/
package writer2latex.xhtml;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class XhtmlStyleMap {
private Map<String,XhtmlStyleMapItem> items = new HashMap<String,XhtmlStyleMapItem>();
public boolean contains(String sName) {
return sName!=null && items.containsKey(sName);
}
public void put(String sName, XhtmlStyleMapItem item) {
items.put(sName, item);
}
public XhtmlStyleMapItem get(String sName) {
return items.get(sName);
}
public Iterator<String> getNames() {
return items.keySet().iterator();
}
}

View file

@ -0,0 +1,46 @@
/************************************************************************
*
* XhtmlStyleMapItem.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.6 (2014-10-24)
*
*/
package writer2latex.xhtml;
/** This is a simple struct to hold data about a single style map
*/
public class XhtmlStyleMapItem {
public String sBlockElement=null;
public String sBlockCss=null;
public String sElement=null;
public String sCss=null;
public String sBefore=null;
public String sAfter=null;
public XhtmlStyleMapItem(String sBlockElement, String sBlockCss, String sElement, String sCss, String sBefore, String sAfter) {
this.sBlockElement=sBlockElement;
this.sBlockCss=sBlockCss;
this.sElement=sElement;
this.sCss=sCss;
this.sBefore=sBefore;
this.sAfter=sAfter;
}
}

View file

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- cleanxhtml.xml 2010-05-17
This is a sample configuration file for Writer2xhtml.
The options are set to produce a clean XHTML file using
standard XHTML elements, using a custom style sheet for
formatting. -->
<config>
<!-- options -->
<option name="no_doctype" value="false" />
<!-- put url to your own stylesheet here: -->
<option name="custom_stylesheet" value="http://www.w3.org/StyleSheets/Core/Oldstyle" />
<option name="formatting" value="ignore_all" />
<option name="frame_formatting" value="ignore_all" />
<option name="section_formatting" value="ignore_all" />
<option name="table_formatting" value="ignore_all" />
<option name="ignore_table_dimensions" value="true" />
<option name="use_dublin_core" value="true" />
<option name="convert_to_px" value="true" />
<option name="scaling" value="100%" />
<option name="column_scaling" value="100%" />
<option name="split_level" value="0" />
<option name="calc_split" value="false" />
<option name="ignore_hard_line_breaks" value="true" />
<option name="ignore_empty_paragraphs" value="false" />
<option name="ignore_double_spaces" value="true" />
<!-- map OOo paragraph styles to xhtml elements -->
<xhtml-style-map name="Text body" family="paragraph" element="p" css="(none)" />
<xhtml-style-map name="Sender" family="paragraph" element="address" css="(none)" />
<xhtml-style-map name="Preformatted Text" family="paragraph" element="pre" css="(none)" />
<xhtml-style-map name="Quotations" family="paragraph"
block-element="blockquote" block-css="(none)" element="p" css="(none)" />
<xhtml-style-map name="List Heading" family="paragraph" block-element="dl" block-css="(none)" element="dt" css="(none)" />
<xhtml-style-map name="List Contents" family="paragraph" block-element="dl" block-css="(none)" element="dd" css="(none)" />
<xhtml-style-map name="Horizontal Line" family="paragraph" element="hr" css="(none)" />
<!-- map OOo text styles to xhtml elements -->
<xhtml-style-map name="Citation" family="text" element="cite" css="(none)" />
<xhtml-style-map name="Definition" family="text" element="dfn" css="(none)" />
<xhtml-style-map name="Emphasis" family="text" element="em" css="(none)" />
<xhtml-style-map name="Example" family="text" element="samp" css="(none)" />
<xhtml-style-map name="Source Text" family="text" element="code" css="(none)" />
<xhtml-style-map name="Strong Emphasis" family="text" element="strong" css="(none)" />
<xhtml-style-map name="Teletype" family="text" element="tt" css="(none)" />
<xhtml-style-map name="User entry" family="text" element="kbd" css="(none)" />
<xhtml-style-map name="Variable" family="text" element="var" css="(none)" />
<xhtml-style-map name="Footnote anchor" family="text" element="sup" css="(none)" />
<xhtml-style-map name="Endnote anchor" family="text" element="sup" css="(none)" />
<!-- map OOo hard formatting attributes to xhtml elements -->
<xhtml-style-map name="bold" family="attribute" element="b" css="(none)" />
<xhtml-style-map name="italics" family="attribute" element="i" css="(none)" />
<xhtml-style-map name="fixed" family="attribute" element="tt" css="(none)" />
<xhtml-style-map name="superscript" family="attribute" element="sup" css="(none)" />
<xhtml-style-map name="subscript" family="attribute" element="sub" css="(none)" />
<!-- Notes: Writer2xhtml with the above rules support a subset of xhtml elements;
some remarks on other elements:
* The inline elements q, abbr, acronym, big and small are not supported, but
you can add support for those if you define your own styles in OOo and map
them to these elements.
* del, ins, object and map are not currently supported by Writer2xhtml, but
might be in the future
-->
</config>

View file

@ -0,0 +1,87 @@
/************************************************************************
*
* L10n.java
*
* Copyright: 2002-2012 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.4 (2012-03-16)
*
*/
package writer2latex.xhtml.l10n;
import java.util.Locale;
import java.util.ResourceBundle;
/* This class handles localized strings (used for navigation links in the exported document)
* Note that the US-English strings need duplicated due to ResourceBundles' search order.
* Default strings are needed for the special case that neither strings for the document language,
* nor for the system default language are available.
* US-English strings are needed if the document language is English and the system locale is not.
*/
public class L10n {
public final static int UP = 0;
public final static int FIRST = 1;
public final static int PREVIOUS = 2;
public final static int NEXT = 3;
public final static int LAST = 4;
public final static int CONTENTS = 5;
public final static int INDEX = 6;
public final static int HOME = 7;
public final static int DIRECTORY = 8;
public final static int DOCUMENT = 9;
private ResourceBundle resourceBundle = ResourceBundle.getBundle("writer2latex.xhtml.l10n.XhtmlStrings",Locale.getDefault());
private Locale locale = null;
public void setLocale(String sLanguage, String sCountry) {
if (sLanguage!=null) {
if (sCountry!=null) {
locale = new Locale(sLanguage,sCountry);
}
else {
locale = new Locale(sLanguage);
}
}
else {
locale = Locale.getDefault();
}
resourceBundle = ResourceBundle.getBundle("writer2latex.xhtml.l10n.XhtmlStrings",locale);
}
public Locale getLocale() {
return locale;
}
public String get(int nString) {
switch (nString) {
case UP: return resourceBundle.getString("up");
case FIRST : return resourceBundle.getString("first");
case PREVIOUS : return resourceBundle.getString("previous");
case NEXT : return resourceBundle.getString("next");
case LAST : return resourceBundle.getString("last");
case CONTENTS : return resourceBundle.getString("contents");
case INDEX : return resourceBundle.getString("index");
case HOME : return resourceBundle.getString("home");
case DIRECTORY: return resourceBundle.getString("directory");
case DOCUMENT: return resourceBundle.getString("document");
default: return "???";
}
}
}

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Up
first=First
previous=Previous
next=Next
last=Last
contents=Contents
index=Index
home=Home
directory=Directory
document=Document

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Amunt
first=Comen\u00e7ament
previous=Precedent
next=Seg\u00fcent
last=Darrer
contents=Contingut
index=\u00cdndex
home=Arrel
directory=Directori
document=Document

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Nahoru
first=Prvn\u00ed
previous=P\u0159edchoz\u00ed
next=Dal\u0161\u00ed
last=Posledn\u00ed
contents=Obsah
index=Rejst\u0159\u00edk
home=Dom\u016f
directory=Adres\u00e1\u0159 (slo\u017eka)
document=Dokument

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Op
first=F\u00F8rste
previous=Forrige
next=N\u00E6ste
last=Sidste
contents=Indhold
index=Stikord
home=Hjem
directory=Mappe
document=Dokument

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Nach oben
first=Anfang
previous=Vorheriges
next=N\u00e4chstes
last=Ende
contents=Inhalte
index=Index
home=Home
directory=Verzeichnis
document=Dokument

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Up
first=First
previous=Previous
next=Next
last=Last
contents=Contents
index=Index
home=Home
directory=Directory
document=Document

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Arriba
first=Primero
previous=Previo
next=Siguiente
last=\u00daltimo
contents=Contenido
index=\u00cdndice
home=Inicio
directory=Directorio
document=Documento

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=\u0628\u0627\u0644\u0627
first=\u0627\u0648\u0644
previous=\u0642\u0628\u0644\u06cc
next=\u0628\u0639\u062f\u06cc
last=\u0627\u062e\u0631\u06cc\u0646
contents=Contents
index=\u0641\u0647\u0631\u0633\u062a
home=\u062e\u0627\u0646\u0647
directory=\u067e\u0648\u0634\u0647
document=\u0645\u0633\u062a\u0646\u062f

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Yl\u00f6s
first=Ensimm\u00e4inen
previous=Edellinen
next=Seuraava
last=Viimeinen
contents=Sis\u00e4lt\u00f6
index=Indeksi
home=Koti
directory=Hakemisto
document=Dokumentti

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Haut
first=D\u00e9but
previous=Pr\u00e9c\u00e9dent
next=Suivant
last=Dernier
contents=Contenus
index=Index
home=Documents Personnels
directory=R\u00e9pertoire
document=Document

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Up
first=Prvi
previous=Prethodan
next=slijede\u0107i
last=Zadnji
contents=Sadr\u017Eaj
index=Indeks
home=Home
directory=Directory
document=Document

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Su
first=Inizio
previous=Precedente
next=Successivo
last=Fine
contents=Sommario
index=Indice
home=Home
directory=Cartella
document=Documento

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Omhoog
first=Eerste
previous=Vorige
next=Volgende
last=Laatste
contents=Inhoud
index=Index
home=Hoofdpagina
directory=Directory
document=Document

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Opp
first=F\u00f8rste
previous=Forrige
next=Neste
last=Siste
contents=Innhald
index=Register
home=Heim
directory=Mappe
document=Dokument

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=W g\u00f3r\u0119
first=Pierwsza
previous=Poprzednia
next=Nast\u0119pna
last=Ostatnia
contents=Spis tre\u015bci
index=Indeks
home=Pocz\u0105tek
directory=Katalog
document=Dokument

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Acima
first=Primeiro
previous=Anterior
next=Pr\u00f3ximo
last=\u00daltimo
contents=Conte\u00fado
index=\u00cdndice
home=Home
directory=Diret\u00f3rio
document=Documento

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=\u0412\u0432\u0435\u0440\u0445
first=\u041f\u0435\u0440\u0432\u0430\u044f
previous=\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f
next=\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f
last=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f
contents=\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435
index=\u0421\u043f\u0438\u0441\u043e\u043a
home=\u0414\u043e\u043c\u043e\u0439
directory=\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f
document=\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=Yukar\u0131
first=\u0130lk
previous=\u00d6nceki
next=Sonraki
last=Son
contents=\u0130\u00e7indekiler
index=\u0130ndeks
home=Ev
directory=Klas\u00f6r
document=D\u00f6k\u00fcman

View file

@ -0,0 +1,11 @@
# XHTML specific strings for Writer2LaTeX
up=\u041d\u0430\u0433\u043e\u0440\u0443
first=\u041f\u0435\u0440\u0448\u0430
previous=\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u044f
next=\u041d\u0430\u0441\u0442\u0443\u043f\u043d\u0430
last=\u041e\u0441\u0442\u0430\u043d\u043d\u044f
contents=\u0417\u043c\u0456\u0441\u0442
index=\u0421\u043f\u0438\u0441\u043e\u043a
home=\u0414\u043e\u0434\u043e\u043c\u0443
directory=\u0422\u0435\u043a\u0430
document=\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442