Initial import

git-svn-id: svn://svn.code.sf.net/p/writer2latex/code/trunk@5 f0f2a975-2e09-46c8-9428-3b39399b9f3c
This commit is contained in:
henrikjust 2009-02-20 09:37:06 +00:00
parent 75e32b1e8f
commit b0b66fcae9
252 changed files with 49000 additions and 0 deletions

View file

@ -0,0 +1,231 @@
/************************************************************************
*
* BatchConverterImpl.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-2009 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2009-02-08)
*
*/
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;
/**
* 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.setEncoding(config.xhtmlEncoding());
htmlDoc.setNoDoctype(config.xhtmlNoDoctype());
htmlDoc.setAddBOM(config.xhtmlAddBOM());
htmlDoc.setUseNamedEntities(config.useNamedEntities());
if (template!=null) { htmlDoc.readFromTemplate(template); }
else { htmlDoc.createHeaderFooter(); }
org.w3c.dom.Document htmlDOM = htmlDoc.getContentDOM();
// 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());
htmlDoc.getHeadNode().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());
htmlDoc.getHeadNode().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
htmlDoc.getTitleNode().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,104 @@
/************************************************************************
*
* CellStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.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,628 @@
/************************************************************************
*
* Converter.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-2009 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2009-02-16)
*
*/
package writer2latex.xhtml;
import java.io.File;
import java.io.FileInputStream;
import java.util.ListIterator;
import java.util.LinkedList;
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.NodeList;
import org.w3c.dom.Text;
import writer2latex.api.Config;
import writer2latex.api.ConverterFactory;
//import writer2latex.api.ConverterResult;
import writer2latex.base.ConverterBase;
//import writer2latex.latex.LaTeXDocumentPortion;
//import writer2latex.latex.util.Context;
import writer2latex.office.MIMETypes;
import writer2latex.office.OfficeReader;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.ExportNameCollection;
import writer2latex.util.Misc;
/**
* <p>This class converts an OpenDocument file to an XHTML(+MathML) document<.</p>
*
*/
public class Converter extends ConverterBase {
// Config
private XhtmlConfig config;
public Config getConfig() { 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 xhtml output file(s)
protected int nType = XhtmlDocument.XHTML10; // the doctype
Vector outFiles;
private int nOutFileIndex;
private XhtmlDocument htmlDoc; // current outfile
private Document htmlDOM; // current DOM, usually within htmlDoc
private boolean bNeedHeaderFooter = false;
// Hyperlinks
Hashtable targets = new Hashtable();
LinkedList links = new LinkedList();
// Strip illegal characters from internal hyperlink targets
private ExportNameCollection targetNames = new ExportNameCollection(true);
// Constructor setting the DOCTYPE
public Converter(int nType) {
super();
config = new XhtmlConfig();
this.nType = nType;
}
// override
public void readTemplate(InputStream is) throws IOException {
template = new XhtmlDocument("Template",nType);
template.read(is);
}
public void readTemplate(File file) throws IOException {
readTemplate(new FileInputStream(file));
}
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; }
protected int getOutFileIndex() { return nOutFileIndex; }
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; }
// override
public void convertInner() throws IOException {
sTargetFileName = Misc.trimDocumentName(sTargetFileName,XhtmlDocument.getExtension(nType));
outFiles = new Vector();
nOutFileIndex = -1;
bNeedHeaderFooter = ofr.isSpreadsheet() || ofr.isPresentation() || config.getXhtmlSplitLevel()>0 || config.getXhtmlUplink().length()>0;
l10n = new L10n();
imageLoader.setUseSubdir(config.saveImagesInSubdir());
imageLoader.setDefaultFormat(MIMETypes.PNG);
imageLoader.addAcceptedFormat(MIMETypes.JPEG);
imageLoader.addAcceptedFormat(MIMETypes.GIF);
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);
// Set locale to document language
StyleWithProperties style = ofr.isSpreadsheet() ? ofr.getDefaultCellStyle() : ofr.getDefaultParStyle();
if (style!=null) {
String sLang = style.getProperty(XMLString.FO_LANGUAGE);
String sCountry = style.getProperty(XMLString.FO_COUNTRY);
if (sLang!=null) {
if (sCountry==null) { l10n.setLocale(sLang); }
else { l10n.setLocale(sLang+"-"+sCountry); }
}
}
//NodeList list;
// Traverse the body
Element body = ofr.getContent();
if (ofr.isSpreadsheet()) { tableCv.convertTableContent(body); }
else if (ofr.isPresentation()) { drawCv.convertDrawContent(body); }
else { textCv.convertTextContent(body); }
// Add footnotes and endnotes
textCv.insertFootnotes(htmlDoc.getContentNode());
textCv.insertEndnotes(htmlDoc.getContentNode());
// Resolve links
ListIterator iter = links.listIterator();
while (iter.hasNext()) {
LinkDescriptor ld = (LinkDescriptor) iter.next();
Integer targetIndex = (Integer) 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));
}
}
}
// Export styles (temp.)
for (int i=0; i<=nOutFileIndex; i++) {
Document dom = ((XhtmlDocument) outFiles.get(i)).getContentDOM();
NodeList hlist = dom.getElementsByTagName("head");
Node styles = styleCv.exportStyles(dom);
if (styles!=null) {
hlist.item(0).appendChild(styles);
}
}
// Create headers & footers (if nodes are available)
if (ofr.isSpreadsheet()) {
for (int i=0; i<=nOutFileIndex; i++) {
XhtmlDocument doc = (XhtmlDocument) 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,(String) tableCv.sheetNames.get(j),j);
addNavigationLink(dom,footerPar,(String) tableCv.sheetNames.get(j),j);
}
else {
addInternalNavigationLink(dom,headerPar,(String) tableCv.sheetNames.get(j),"tableheading"+j);
addInternalNavigationLink(dom,footerPar,(String) tableCv.sheetNames.get(j),"tableheading"+j);
}
}
if (header!=null) { header.appendChild(headerPar); }
if (footer!=null) { footer.appendChild(footerPar); }
}
}
else if (ofr.isPresentation() || config.getXhtmlSplitLevel()>0) {
for (int i=0; i<=nOutFileIndex; i++) {
XhtmlDocument doc = (XhtmlDocument) 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 = (XhtmlDocument) 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(" "));
}
}
}
}
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 */
private String getPlainInlineText(Node node) {
StringBuffer buf = new StringBuffer();
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_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, seperate paragraphs with newline
StringBuffer buf = new StringBuffer();
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));
}
child = child.getNextSibling();
}
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 = (XhtmlDocument) outFiles.get(nIndex);
htmlDOM = htmlDoc.getContentDOM();
}
public Element getPanelNode() {
return htmlDoc.getPanelNode();
}
// Prepare next output file
public Element nextOutFile() {
if (nOutFileIndex>=0) { textCv.insertFootnotes(htmlDoc.getContentNode()); }
htmlDoc = new XhtmlDocument(getOutFileName(++nOutFileIndex,false),nType);
htmlDoc.setEncoding(config.xhtmlEncoding());
htmlDoc.setNoDoctype(config.xhtmlNoDoctype());
htmlDoc.setAddBOM(config.xhtmlAddBOM());
htmlDoc.setUseNamedEntities(config.useNamedEntities());
htmlDoc.setXsltPath(config.getXsltPath());
if (template!=null) { htmlDoc.readFromTemplate(template); }
else if (bNeedHeaderFooter) { htmlDoc.createHeaderFooter(); }
outFiles.add(nOutFileIndex,htmlDoc);
convertData.addDocument(htmlDoc);
// Create head + body
htmlDOM = htmlDoc.getContentDOM();
Element rootElement = htmlDOM.getDocumentElement();
styleCv.applyDefaultLanguage(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://www.hj-gym.dk/~hj/writer2latex for more info."),
rootElement.getFirstChild());
// Apply page formatting (using first master page)
if (ofr.getFirstMasterPage()!=null && !ofr.isPresentation()) {
StyleInfo pageInfo = new StyleInfo();
styleCv.getPageSc().applyStyle(ofr.getFirstMasterPage().getName(),pageInfo);
styleCv.getPageSc().applyStyle(pageInfo,htmlDoc.getContentNode());
}
// Add title (required by xhtml)
String sTitle = metaData.getTitle();
if (sTitle==null) { // use filename as fallback
sTitle = htmlDoc.getFileName();
}
htmlDoc.getTitleNode().appendChild( htmlDOM.createTextNode(sTitle) );
// Declare charset (we need this for xhtml 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());
htmlDoc.getHeadNode().appendChild(meta);
}
// "Traditional" meta data
//createMeta("generator","Writer2LaTeX "+Misc.VERSION);
createMeta("description",metaData.getDescription());
createMeta("keywords",metaData.getKeywords());
// Dublin core meta data (optional)
// Format as recommended on dublincore.org
// Declare meta data profile
if (config.xhtmlUseDublinCore()) {
htmlDoc.getHeadNode().setAttribute("profile","http://dublincore.org/documents/dcq-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/");
htmlDoc.getHeadNode().appendChild(dclink);
// Insert the actual meta data
createMeta("DC.title",metaData.getTitle());
// DC.subject actually contains subject+keywords, so we merge them
String sDCSubject = metaData.getSubject();
if (metaData.getSubject().length()>0 && metaData.getKeywords().length()>0) {
sDCSubject+=", ";
}
sDCSubject+=metaData.getKeywords();
createMeta("DC.subject",sDCSubject);
createMeta("DC.description",metaData.getDescription());
createMeta("DC.creator",metaData.getCreator());
createMeta("DC.date",metaData.getDate());
createMeta("DC.language",metaData.getLanguage());
}
// 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());
htmlDoc.getHeadNode().appendChild(htmlStyle);
}
/* later....
if (nSplit>0 && !config.xhtmlIgnoreStyles()) {
Element htmlStyle = htmlDOM.createElement("link");
htmlStyle.setAttribute("rel","stylesheet");
htmlStyle.setAttribute("type","text/css");
htmlStyle.setAttribute("media","all");
htmlStyle.setAttribute("href",oooDoc.getName()+"-styles.css");
htmlHead.appendChild(htmlStyle);
}*/
// Note: For single output file, styles are exported to the doc at the end.
// Recreate nested sections, if any
if (!textCv.sections.isEmpty()) {
Iterator 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();
}
// 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");
// 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) {
anchor.setAttribute("name",sName);
anchor.setAttribute("title",sName); // OOo does not have title...
}
// 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(String sName, String sValue) {
if (sValue==null) { return; }
Element meta = htmlDOM.createElement("meta");
meta.setAttribute("name",sName);
meta.setAttribute("content",sValue);
htmlDoc.getHeadNode().appendChild(meta);
}
}

View file

@ -0,0 +1,92 @@
/************************************************************************
*
* ConverterHelper.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Element;
import writer2latex.office.OfficeReader;
public class ConverterHelper {
protected OfficeReader ofr;
protected XhtmlConfig config;
protected Converter converter;
protected StyleConverter getStyleCv() { return converter.getStyleCv(); }
protected TextStyleConverter getTextSc() { return converter.getStyleCv().getTextSc(); }
protected ParStyleConverter getParSc() { return converter.getStyleCv().getParSc(); }
protected ListStyleConverter getListSc() { return converter.getStyleCv().getListSc(); }
protected SectionStyleConverter getSectionSc() { return converter.getStyleCv().getSectionSc(); }
protected TableStyleConverter getTableSc() { return converter.getStyleCv().getTableSc(); }
protected RowStyleConverter getRowSc() { return converter.getStyleCv().getRowSc(); }
protected CellStyleConverter getCellSc() { return converter.getStyleCv().getCellSc(); }
protected FrameStyleConverter getFrameSc() { return converter.getStyleCv().getFrameSc(); }
protected PresentationStyleConverter getPresentationSc() { return converter.getStyleCv().getPresentationSc(); }
protected PageStyleConverter getPageSc() { return converter.getStyleCv().getPageSc(); }
protected TextConverter getTextCv() { return converter.getTextCv(); }
protected TableConverter getTableCv() { return converter.getTableCv(); }
protected DrawConverter getDrawCv() { return converter.getDrawCv(); }
protected MathConverter getMathCv() { return converter.getMathCv(); }
// TODO: Move to StyleInfo!
protected 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) {
hnode.setAttribute("lang",info.sLang); // HTML4 compatibility
}
}
if (info.sDir!=null) {
hnode.setAttribute("dir",info.sDir);
}
}
public ConverterHelper(OfficeReader ofr, XhtmlConfig config, Converter converter) {
this.ofr = ofr;
this.config = config;
this.converter = converter;
}
}

View file

@ -0,0 +1,939 @@
/************************************************************************
*
* DrawConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-12-15)
*
*/
/* TODO (impress2xhtml)
* Support master page content!
* New option: xhtml_draw_scaling: scale all draw objects this percentage
* (applies to applySize in this class + page size in PageStyleConverter)
* Certain options should have a fixed value for impress2xhtml:
* original_image_size: always false
* xhtml_formatting: always "convert_all"
* xhtml_frame_formatting: always "convert_all"
* xhtml_use_list_hack: always "true" (until list merge is fixed..)
* apply hard draw page background (see below)
* apply z-order for draw objects (frames)
* export notes (part of draw-page)
* export list-style-image for image bullets!
*/
package writer2latex.xhtml;
import java.util.Iterator;
import java.util.Vector;
import java.io.IOException;
import org.xml.sax.SAXException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import writer2latex.xmerge.EmbeddedObject;
//import writer2latex.xmerge.EmbeddedBinaryObject;
import writer2latex.xmerge.EmbeddedXMLObject;
import writer2latex.util.Misc;
import writer2latex.util.CSVList;
import writer2latex.xmerge.BinaryGraphicsDocument;
import writer2latex.office.XMLString;
import writer2latex.office.MIMETypes;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.FormReader;
import writer2latex.office.ControlReader;
//import writer2latex.office.MasterPage;
//import writer2latex.office.PageLayout;
import writer2latex.office.OfficeReader;
//import writer2latex.xhtml.XhtmlStyleMap;
public class DrawConverter extends ConverterHelper {
/** Identifies objects that should be displayed inline.
*/
public static final int INLINE = 0;
/** Identifies objects that should be displayed as floats, either alone
* or with text wrap (using the css attribute float:left or float:right)
*/
public static final int FLOATING = 1;
/** Identifies objects that should be positioned absolute (using the css
* attribute postion:absolute)
*/
public static final int ABSOLUTE = 2;
/** Identifies objects that should be placed centered */
public static final int CENTERED = 3;
private FormReader form = null;
private String sScale;
private boolean bConvertToPx;
private boolean bOriginalImageSize;
// Frames in spreadsheet documents are collected here
private Vector frames = new Vector();
// This flag determines wether to collect frames or insert them immediately
private boolean bCollectFrames = false;
public DrawConverter(OfficeReader ofr, XhtmlConfig config, Converter converter) {
super(ofr,config,converter);
// We can only handle one form; pick an arbitrary one.
// Also we cannot split a form over several files.
Iterator formsIterator = ofr.getForms().getFormsIterator();
if (formsIterator.hasNext() && config.getXhtmlSplitLevel()==0) {
form = (FormReader) formsIterator.next();
}
bCollectFrames = ofr.isSpreadsheet();
sScale = config.getXhtmlScaling();
bConvertToPx = config.xhtmlConvertToPx();
bOriginalImageSize = config.originalImageSize();
}
///////////////////////////////////////////////////////////////////////
// Complete Draw documents/presentations
public void convertDrawContent(Element onode) {
if (!onode.hasChildNodes()) { return; }
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.DRAW_PAGE)) {
handleDrawPage((Element)child,converter.nextOutFile());
}
}
}
}
private void handleDrawPage(Element onode, Element hnode) {
Element div = converter.createElement("div");
hnode.appendChild(div);
// Style it (TODO: Apply hard drawing-page (background) style)
StyleInfo info = new StyleInfo();
getPageSc().applyStyle(onode.getAttribute(XMLString.DRAW_MASTER_PAGE_NAME),info);
info.props.addValue("top","40px"); // Somewhat arbitrary
info.props.addValue("left","0");
info.props.addValue("position","absolute");
applyStyle(info,div);
// Traverse the draw:page
if (!onode.hasChildNodes()) { return; }
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) {
handleDrawElement((Element)child,div,div,ABSOLUTE);
}
}
}
/////////////////////////////////////////////////////////////////////////
// Form document
/** <p>Create form, if there is a form in this document</p>
* @return the form element, or null if there are no forms in the document
*/
public Element createForm() {
if (form==null) return null;
Element htmlForm = converter.createElement("form");
htmlForm.setAttribute("name", form.getAttribute(XMLString.FORM_NAME));
htmlForm.setAttribute("action", form.getAttribute(XMLString.XLINK_HREF));
String sMethod = form.getAttribute(XMLString.FORM_METHOD);
htmlForm.setAttribute("method", sMethod!=null ? sMethod : "get");
return htmlForm;
}
/////////////////////////////////////////////////////////////////////////
// DRAW ELEMENTS
/** <p> A draw element with a hyperlink is represented as two elements,
* eg. <code>&lt;draw:a&gt;&lt;draw:image/&gt;&lt;/draw:a&gt;</code>.
* We thus need methods to switch between the two elements.</p>
* <p> This method takes a <code>draw</code>-element.
* If this element is a hyperlink, the child element is returned.
* Otherwise the argument is returned unchanged.</p>
* @param onode the <code>draw:a</code> element
* @return the corresponding element
*/
public Element getRealDrawElement(Element onode) {
if (XMLString.DRAW_A.equals(onode.getTagName())) {
Node child = onode.getFirstChild();
while (child!=null) {
if (OfficeReader.isDrawElement(child)) { return (Element) child; }
child = child.getNextSibling();
}
return null; // empty anchor
}
return onode;
}
/** <p> A draw element with a hyperlink is represented as two elements,
* eg. <code>&lt;draw:a&gt;&lt;draw:image/&gt;&lt;/draw:a&gt;</code>.
* We thus need methods to switch between the two elements.</p>
* <p> This method takes a <code>draw</code>-element.
* If this element is contained in a hyperlink, the hyperlink is returned.
* Otherwise null is returned.</p>
* @param onode the <code>draw:a</code> element
* @return the hyperlink element, if any
*/
public Element getDrawAnchor(Element onode) {
Element parent = (Element) onode.getParentNode();
// in oasis format, we need to skip the frame as well
if (XMLString.DRAW_FRAME.equals(parent.getTagName())) {
parent = (Element) parent.getParentNode();
}
if (XMLString.DRAW_A.equals(parent.getTagName())) { return parent; }
return null;
}
private Element getFrame(Element onode) {
if (ofr.isOpenDocument()) return (Element) onode.getParentNode();
else return onode;
}
public void flushFrames(Element hnode) {
bCollectFrames = false;
int nCount = frames.size();
for (int i=0; i<nCount; i++) {
handleDrawElement((Element) frames.get(i),hnode,null,CENTERED);
}
frames.clear();
bCollectFrames = true;
}
/** <p>Convert a draw element to xhtml. The presentation depends on the
* parameter <code>nMode</code>:</p>
* <ul><li><code>DrawConverter.INLINE</code>: Presented inline. The hnode
* must accept inline content. An inline container <em>must</em> be
* provided.</li>
* <li><code>DrawConverter.FLOAT</code>: Presented as a float. The hnode
* must accept block/flow content. A block container <em>must</em> be
* provided.</li>
* <li><code>DrawConverter.ABSOLUTE</code>: Presented at an absolute
* position. A block container <em>must</em> be provided.</li>
* </ul>
* <p>Containers for block and inline elements should be supplied.
* The containers may be identical (flow container).</p>
* <p>Note: A draw:text-box will be ignored in inline mode.</p>
* @param onode the draw element
* @param hnodeBlock the xhtml element to attach the converted element to if it's a block element
* @param hnodeInline the xhtml element to attach the converted element to if it's an inline element
* @param nMode identifies how the element should be presented
*/
public void handleDrawElement(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
if (bCollectFrames) {
frames.add(onode);
return;
}
String sName = onode.getNodeName();
if (sName.equals(XMLString.DRAW_OBJECT)) {
handleDrawObject(onode,hnodeBlock,hnodeInline,nMode);
}
else if (sName.equals(XMLString.DRAW_OBJECT_OLE)) {
handleDrawObject(onode,hnodeBlock,hnodeInline,nMode);
}
else if (sName.equals(XMLString.DRAW_IMAGE)) {
handleDrawImage(onode,hnodeBlock,hnodeInline,nMode);
}
else if (sName.equals(XMLString.DRAW_TEXT_BOX)) {
handleDrawTextBox(onode,hnodeBlock,hnodeInline,nMode);
}
else if (sName.equals(XMLString.DRAW_A)) {
Element elm = getRealDrawElement(onode);
if (elm!=null) {
handleDrawElement(elm,hnodeBlock,hnodeInline,nMode);
}
}
else if (sName.equals(XMLString.DRAW_FRAME)) {
// OpenDocument embeds the draw element in a frame element
handleDrawElement(Misc.getFirstChildElement(onode),hnodeBlock,hnodeInline,nMode);
}
else if (sName.equals(XMLString.DRAW_G)) {
handleDrawGroup(onode,hnodeBlock,hnodeInline,nMode);
}
else if (sName.equals(XMLString.DRAW_CONTROL)) {
handleDrawControl(onode,hnodeBlock,hnodeInline,nMode);
}
}
private void handleDrawObject(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
// TODO: Placement if not inline
// 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 sHref = Misc.getAttribute(onode, XMLString.XLINK_HREF);
if (sHref!=null) { // Embedded object in package or linked object
if (ofr.isInPackage(sHref)) { // Embedded object in package
if (sHref.startsWith("#")) { sHref=sHref.substring(1); }
if (sHref.startsWith("./")) { sHref=sHref.substring(2); }
EmbeddedObject object = converter.getEmbeddedObject(sHref);
if (MIMETypes.MATH.equals(object.getType()) || MIMETypes.ODF.equals(object.getType())) { // Formula!
EmbeddedXMLObject xmlObject = (EmbeddedXMLObject) object;
// Document settings = object.getSettingsDOM();
try {
hnode.appendChild(converter.createTextNode(" "));
getMathCv().convert(xmlObject.getContentDOM().getDocumentElement(),hnode);
hnode.appendChild(converter.createTextNode(" "));
}
catch (SAXException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
else { // unsupported object
boolean bIgnore = true;
if (ofr.isOpenDocument()) { // look for replacement image
Element replacementImage = Misc.getChildByTagName(getFrame(onode),XMLString.DRAW_IMAGE);
if (replacementImage!=null) {
handleDrawImage(replacementImage,hnodeBlock,hnodeInline,nMode);
bIgnore = false;
}
}
if (bIgnore) {
hnode.appendChild( converter.createTextNode("[Warning: object ignored]"));
}
}
}
else { // TODO: Linked object
hnode.appendChild( converter.createTextNode("[Warning: Linked object ignored]"));
}
}
else { // flat xml format
Node formula = Misc.getChildByTagName(onode,XMLString.MATH_MATH);
if (formula != null) {
hnode.appendChild(converter.createTextNode(" "));
getMathCv().convert(formula,hnode);
hnode.appendChild(converter.createTextNode(" "));
}
else { // unsupported object
boolean bIgnore = true;
if (ofr.isOpenDocument()) { // look for replacement image
Element replacementImage = Misc.getChildByTagName(getFrame(onode),XMLString.DRAW_IMAGE);
if (replacementImage!=null) {
handleDrawImage(replacementImage,hnodeBlock,hnodeInline,nMode);
bIgnore = false;
}
}
if (bIgnore) {
hnode.appendChild( converter.createTextNode("[Warning: object ignored]"));
}
}
}
}
private void handleDrawImage(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
// Get the image from the ImageLoader
String sFileName = null;
String sHref = Misc.getAttribute(onode,XMLString.XLINK_HREF);
if (sHref!=null && sHref.length()>0 && !ofr.isInPackage(sHref)) {
// Linked image is not yet handled by ImageLoader. This is a temp.
// solution (will go away when ImageLoader is finished)
sFileName = sHref;
// In OpenDocument *package* format ../ means "leave the package"
if (ofr.isOpenDocument() && ofr.isPackageFormat() && sFileName.startsWith("../")) {
sFileName=sFileName.substring(3);
}
//String sExt = sHref.substring(sHref.lastIndexOf(".")).toLowerCase();
}
else { // embedded or base64 encoded image
BinaryGraphicsDocument bgd = converter.getImageLoader().getImage(onode);
if (bgd!=null) {
converter.addDocument(bgd);
sFileName = bgd.getFileName();
}
}
if (sFileName==null) { return; } // TODO: Add warning?
// Create the image (sFileName contains the file name)
Element image = converter.createElement("img");
String sName = Misc.getAttribute(getFrame(onode),XMLString.DRAW_NAME);
converter.addTarget(image,sName+"|graphic");
image.setAttribute("src",sFileName);
// Add alternative text, using either alt.text, name or file name
Element frame = getFrame(onode);
Element desc = Misc.getChildByTagName(frame,XMLString.SVG_DESC);
String sAltText = desc!=null ? Misc.getPCDATA(desc) : (sName!=null ? sName : sFileName);
image.setAttribute("alt",sAltText);
// Now style it
StyleInfo info = new StyleInfo();
String sStyleName = Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME);
getFrameSc().applyStyle(sStyleName,info);
if (!bOriginalImageSize) { applySize(frame,info.props,false); }
// Apply placement
applyPlacement(frame, hnodeBlock, hnodeInline, nMode, image, info);
applyStyle(info,image);
addLink(onode,image);
}
private void handleDrawTextBox(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
// Create the div with id=name
Element textbox = converter.createElement("div");
if (hnodeBlock!=null) {
hnodeBlock.appendChild(textbox);
}
else { // cannot include the div inline, ignore
return;
}
// Add name, if defined
String sName = Misc.getAttribute(getFrame(onode),XMLString.DRAW_NAME);
if (sName!=null) { converter.addTarget(textbox,sName+"|frame"); }
// Now style it
Element frame = getFrame(onode);
StyleInfo info = new StyleInfo();
// Draw frame style
String sStyleName = Misc.getAttribute(frame, XMLString.DRAW_STYLE_NAME);
if (sStyleName!=null) {
getFrameSc().applyStyle(sStyleName,info);
}
// Presentation frame style
sStyleName = Misc.getAttribute(frame, XMLString.PRESENTATION_STYLE_NAME);
if (sStyleName!=null) {
if ("outline".equals(Misc.getAttribute(frame, XMLString.PRESENTATION_CLASS))) {
getPresentationSc().enterOutline(sStyleName);
}
getPresentationSc().applyStyle(sStyleName,info);
}
// Additional text formatting
sStyleName = Misc.getAttribute(frame, XMLString.DRAW_TEXT_STYLE_NAME);
if (sStyleName!=null) {
//getStyleCv().applyParStyle(sStyleName,info);
}
// Apply placement
switch (nMode) {
case INLINE:
break;
case ABSOLUTE:
applySize(frame,info.props,false);
applyPosition(frame,info.props);
break;
case CENTERED:
info.props.addValue("maring-top","2px");
info.props.addValue("maring-bottom","2px");
info.props.addValue("margin-left","auto");
info.props.addValue("margin-right","auto");
applySize(frame,info.props,true);
break;
case FLOATING:
applySize(frame,info.props,true);
StyleWithProperties style = ofr.getFrameStyle(sStyleName);
if (style!=null) {
String sPos = style.getProperty(XMLString.STYLE_HORIZONTAL_POS);
String sWrap = style.getProperty(XMLString.STYLE_WRAP);
if (isLeft(sPos) && mayWrapRight(sWrap)) {
info.props.addValue("float","left");
}
else if (isRight(sPos) && mayWrapLeft(sWrap)) {
info.props.addValue("float","right");
}
else if (isFromLeft(sPos)) {
if (mayWrapRight(sWrap)) {
info.props.addValue("float","left");
}
String sX = frame.getAttribute(XMLString.SVG_X);
if (sX!=null && sX.length()>0) {
info.props.addValue("margin-left",scale(sX));
}
}
}
}
//Finish
applyStyle(info,textbox);
getTextCv().traverseBlockText(onode,textbox);
getPresentationSc().exitOutline();
}
private void handleDrawGroup(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
// TODO: style-name and z-index should be transferred to children
Node child = onode.getFirstChild();
while (child!=null) {
if (OfficeReader.isDrawElement(child)) {
handleDrawElement((Element) child, hnodeBlock, hnodeInline, nMode);
}
child = child.getNextSibling();
}
}
//////////////////////////////////////////////////////////////////////////
// Forms
private void handleDrawControl(Element onode, Element hnodeBlock, Element hnodeInline, int nMode) {
// Get the control, if possible
if (form==null) { return; }
ControlReader control = ofr.isOpenDocument() ?
ofr.getForms().getControl(Misc.getAttribute(onode,XMLString.DRAW_CONTROL)) :
ofr.getForms().getControl(Misc.getAttribute(onode,XMLString.FORM_ID));
if (control==null || control.getOwnerForm()!=form) { return; }
// Create the control element
Element hcontrol = null;
String sType = control.getControlType();
if (XMLString.FORM_TEXT.equals(sType)) {
hcontrol = createInputText(control,false);
}
else if (XMLString.FORM_PASSWORD.equals(sType)) {
hcontrol = createInputText(control,true);
}
else if (XMLString.FORM_FILE.equals(sType)) {
hcontrol = createInputFile(control);
}
else if (XMLString.FORM_IMAGE.equals(sType)) {
hcontrol = createInput(control,"image");
}
else if (XMLString.FORM_HIDDEN.equals(sType)) {
hcontrol = createInput(control,"hidden");
}
else if (XMLString.FORM_CHECKBOX.equals(sType)) {
hcontrol = createInputCheck(control,false);
}
else if (XMLString.FORM_RADIO.equals(sType)) {
hcontrol = createInputCheck(control,true);
}
else if (XMLString.FORM_BUTTON.equals(sType)) {
hcontrol = createInputButton(control);
}
else if (XMLString.FORM_FIXED_TEXT.equals(sType)) {
hcontrol = createLabel(control);
}
else if (XMLString.FORM_TEXTAREA.equals(sType)) {
hcontrol = createTextarea(control);
}
else if (XMLString.FORM_LISTBOX.equals(sType)) {
hcontrol = createSelect(control);
}
// ignore other controls
if (hcontrol!=null) {
Element frame = onode; // controls are *not* contained in a draw:frame!
StyleInfo info = new StyleInfo();
getFrameSc().applyStyle(frame.getAttribute(XMLString.DRAW_STYLE_NAME),info);
applySize(frame,info.props,false);
applyPlacement(frame,hnodeBlock,hnodeInline,nMode,hcontrol,info);
applyStyle(info,hcontrol);
}
}
private Element createInput(ControlReader control, String sType) {
// Create the element
Element input = converter.createElement("input");
input.setAttribute("type",sType);
return input;
}
private Element createInputFile(ControlReader control) {
Element input = converter.createElement("input");
input.setAttribute("type","file");
setCommonAttributes(control,input);
setDisabled(control,input);
setReadonly(control,input);
setValue(control,input);
return input;
}
private Element createInputText(ControlReader control, boolean bPassword) {
Element input = converter.createElement("input");
input.setAttribute("type",bPassword ? "password" : "text");
setCommonAttributes(control,input);
setName(control,input,true);
setValue(control,input);
setMaxLength(control,input);
setDisabled(control,input);
setReadonly(control,input);
return input;
}
private Element createInputCheck(ControlReader control, boolean bRadio) {
Element input = converter.createElement("input");
input.setAttribute("type",bRadio ? "radio" : "checkbox");
setCommonAttributes(control,input);
setName(control,input,true);
setValue(control,input);
setChecked(control,input);
setDisabled(control,input);
setReadonly(control,input);
// Add a label for the check/radio
Element label = converter.createElement("label");
setFor(control,label);
label.appendChild(input);
label.appendChild(converter.createTextNode(control.getTypeAttribute(XMLString.FORM_LABEL)));
return label;
}
private Element createInputButton(ControlReader control) {
Element input = converter.createElement("input");
String sButtonType = control.getTypeAttribute(XMLString.FORM_BUTTON_TYPE);
if ("submit".equals(sButtonType)) {
input.setAttribute("type","submit");
}
else if ("reset".equals(sButtonType)) {
input.setAttribute("type","reset");
}
else { // TODO: url button (using javascript)
input.setAttribute("type","button");
}
setCommonAttributes(control,input);
setName(control,input,true);
input.setAttribute("value",control.getTypeAttribute(XMLString.FORM_LABEL));
setDisabled(control,input);
return input;
}
private Element createLabel(ControlReader control) {
Element label = converter.createElement("label");
setCommonAttributes(control,label);
setFor(control,label);
label.setAttribute("value",control.getTypeAttribute(XMLString.FORM_LABEL));
label.appendChild(converter.createTextNode(control.getTypeAttribute(XMLString.FORM_LABEL)));
return label;
}
private Element createTextarea(ControlReader control) {
Element textarea = converter.createElement("textarea");
setCommonAttributes(control,textarea);
setName(control,textarea,true);
setDisabled(control,textarea);
setReadonly(control,textarea);
// rows & cols are required - but css will override them!
textarea.setAttribute("rows","10");
textarea.setAttribute("cols","5");
// The value attribute should be used as content
String s = control.getTypeAttribute(XMLString.FORM_VALUE);
if (s!=null) {
textarea.appendChild(converter.createTextNode(s));
}
return textarea;
}
private Element createSelect(ControlReader control) {
Element select = converter.createElement("select");
setCommonAttributes(control,select);
setName(control,select,false);
setSize(control,select);
setMultiple(control,select);
setDisabled(control,select);
// Add options
int nCount = control.getItemCount();
for (int i=0; i<nCount; i++) {
String sLabel = control.getItemAttribute(i,XMLString.FORM_LABEL);
boolean bSelected = "true".equals(control.getItemAttribute(i,XMLString.FORM_SELECTED));
Element option = converter.createElement("option");
select.appendChild(option);
if (bSelected) { option.setAttribute("selected","selected"); }
option.appendChild(converter.createTextNode(sLabel));
}
return select;
}
// form helpers
private void setCommonAttributes(ControlReader control, Element hnode) {
setId(control,hnode);
setTitle(control,hnode);
setTabIndex(control,hnode);
}
private void setId(ControlReader control, Element hnode) {
String s = control.getId();
if (s!=null) { hnode.setAttribute("id",s); }
}
private void setName(ControlReader control, Element hnode, boolean bRequired) {
String s = control.getAttribute(XMLString.FORM_NAME);
if (s!=null) { hnode.setAttribute("name",s); }
else if (bRequired) { hnode.setAttribute("name","unknown"); }
}
private void setValue(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_VALUE); // TODO: Correct??
if (s!=null) { hnode.setAttribute("value",s); }
}
private void setTitle(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_TITLE);
if (s!=null) { hnode.setAttribute("title",s); }
}
private void setTabIndex(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_TAB_INDEX);
if (s!=null) { hnode.setAttribute("tabindex",s); }
}
private void setMaxLength(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_MAX_LENGTH);
if (s!=null) { hnode.setAttribute("maxlength",s); }
}
private void setSize(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_SIZE);
if (s!=null) { hnode.setAttribute("size",s); }
}
private void setChecked(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_SELECTED);
if ("true".equals(s)) { hnode.setAttribute("checked","checked"); }
}
private void setMultiple(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_MULTIPLE);
if ("true".equals(s)) { hnode.setAttribute("multiple","multiple"); }
}
private void setDisabled(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_DISABLED);
if ("true".equals(s)) { hnode.setAttribute("disabled","disabled"); }
}
private void setReadonly(ControlReader control, Element hnode) {
String s = control.getTypeAttribute(XMLString.FORM_READONLY);
if ("true".equals(s)) { hnode.setAttribute("readonly","readonly"); }
}
private void setFor(ControlReader control, Element hnode) {
hnode.setAttribute("for",control.getId());
}
///////////////////////////////////////////////////////////////////////////
// Utility methods
// Add link to a draw element
private void addLink(Element onode, Element hnode) {
Element oanchor = getDrawAnchor(onode);
if (oanchor!=null) {
// If xlink:href is empty, there's no point in creating the anchor:
String sHref = oanchor.getAttribute(XMLString.XLINK_HREF);
if (sHref!=null && sHref.length()>0) {
Element hanchor = converter.createLink(oanchor);
hnode.getParentNode().replaceChild(hanchor,hnode);
hanchor.appendChild(hnode);
}
}
}
private void applySize(Element node, CSVList props, boolean bOnlyWidth) {
// The width attribute in css refers to the content width, excluding borders and padding
// We thus have to subtract the borders and padding to get the correct width
StyleWithProperties style = ofr.getFrameStyle(node.getAttribute(XMLString.DRAW_STYLE_NAME));
String sWidth = Misc.getAttribute(node,XMLString.SVG_WIDTH);
if (sWidth.length()>0) {
if (style!=null) {
// Subtract padding
String s = style.getProperty(XMLString.FO_PADDING_LEFT);
if (s!=null) sWidth = Misc.sub(sWidth, s);
s = style.getProperty(XMLString.FO_PADDING_RIGHT);
if (s!=null) sWidth = Misc.sub(sWidth, s);
s = style.getProperty(XMLString.FO_PADDING);
if (s!=null) sWidth = Misc.sub(sWidth, Misc.multiply("200%", s));
// Subtract border
s = style.getProperty(XMLString.FO_BORDER_LEFT);
if (s!=null) sWidth = Misc.sub(sWidth, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (s!=null) sWidth = Misc.sub(sWidth, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) sWidth = Misc.sub(sWidth, Misc.multiply("200%", getTableCv().borderWidth(s)));
}
props.addValue("width",scale(sWidth));
}
String sHeight = Misc.getAttribute(node,XMLString.SVG_HEIGHT);
if (sHeight.length()>0 && !bOnlyWidth) {
if (style!=null) {
// Subtract padding
String s = style.getProperty(XMLString.FO_PADDING_TOP);
if (s!=null) sHeight = Misc.sub(sHeight, s);
s = style.getProperty(XMLString.FO_PADDING_BOTTOM);
if (s!=null) sHeight = Misc.sub(sHeight, s);
s = style.getProperty(XMLString.FO_PADDING);
if (s!=null) sHeight = Misc.sub(sHeight, Misc.multiply("200%", s));
// Subtract border
s = style.getProperty(XMLString.FO_BORDER_TOP);
if (s!=null) sHeight = Misc.sub(sHeight, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER_BOTTOM);
if (s!=null) sHeight = Misc.sub(sHeight, getTableCv().borderWidth(s));
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) sHeight = Misc.sub(sHeight, Misc.multiply("200%", getTableCv().borderWidth(s)));
}
props.addValue("height",scale(sHeight));
}
}
private void applyPosition(Element node, CSVList props) {
// The left and top attributes in css refers to the entire box, including margins
// We thus have to subtract the margins to get correct placement
String sX = node.getAttribute(XMLString.SVG_X);
if (sX.length()==0) sX="0";
String sY = node.getAttribute(XMLString.SVG_Y);
if (sY.length()==0) sY="0";
StyleWithProperties style = ofr.getFrameStyle(node.getAttribute(XMLString.DRAW_STYLE_NAME));
if (style!=null) {
String s = style.getProperty(XMLString.FO_MARGIN_TOP);
if (s!=null) sX=Misc.sub(sX,s);
s = style.getProperty(XMLString.FO_MARGIN_LEFT);
if (s!=null) sY=Misc.sub(sY,s);
}
props.addValue("position","absolute");
if (sX!=null && sX.length()>0) { props.addValue("left",scale(sX)); }
if (sY!=null && sY.length()>0) { props.addValue("top",scale(sY)); }
}
private void applyPlacement(Element onode, Element hnodeBlock,
Element hnodeInline, int nMode, Element object, StyleInfo info) {
switch (nMode) {
case INLINE :
hnodeInline.appendChild(object);
break;
case ABSOLUTE:
applyPosition(onode,info.props);
if (hnodeInline!=null) {
hnodeInline.appendChild(object);
}
else {
Element div = converter.createElement("div");
hnodeBlock.appendChild(div);
div.appendChild(object);
}
break;
case CENTERED:
Element centerdiv = converter.createElement("div");
centerdiv.setAttribute("style","margin:2px 0px 2px 0px");
hnodeBlock.appendChild(centerdiv);
centerdiv.appendChild(object);
break;
case FLOATING:
boolean bWrap = false;
String sAlign = "center";
String sX = null;
String sStyleName = Misc.getAttribute(onode, XMLString.DRAW_STYLE_NAME);
StyleWithProperties style = ofr.getFrameStyle(sStyleName);
if (style!=null) {
String sPos = style.getProperty(XMLString.STYLE_HORIZONTAL_POS);
String sWrap = style.getProperty(XMLString.STYLE_WRAP);
if (isLeft(sPos)) {
bWrap = mayWrapRight(sWrap);
sAlign = "left";
}
else if (isRight(sPos)) {
bWrap = mayWrapLeft(sWrap);
sAlign = "right";
}
else if (isFromLeft(sPos)) {
bWrap = mayWrapRight(sWrap);
sAlign = "left";
sX = onode.getAttribute(XMLString.SVG_X);
}
}
if (bWrap) {
info.props.addValue("float",sAlign);
if (sX!=null && sX.length()>0) { info.props.addValue("margin-left",sX); }
if (hnodeInline!=null) {
hnodeInline.appendChild(object);
}
else {
Element div = converter.createElement("div");
hnodeBlock.appendChild(div);
div.appendChild(object);
}
}
else {
Element div = converter.createElement("div");
hnodeBlock.appendChild(div);
div.appendChild(object);
CSVList props = new CSVList(";");
props.addValue("text-align",sAlign);
if (sX!=null && sX.length()>0) { props.addValue("margin-left",sX); }
div.setAttribute("style",props.toString());
}
}
}
private boolean isLeft(String sHPos) {
return "left".equals(sHPos) || "inside".equals(sHPos);
}
/*private boolean isCenter(String sHPos) {
return "center".equals(sHPos);
}*/
private boolean isRight(String sHPos) {
return "right".equals(sHPos) || "outside".equals(sHPos);
}
private boolean isFromLeft(String sHPos) {
return "from-left".equals(sHPos) || "from-inside".equals(sHPos);
}
private boolean mayWrapLeft(String sWrap) {
return "left".equals(sWrap) || "parallel".equals(sWrap) ||
"dynamic".equals(sWrap) || "run-through".equals(sWrap);
}
private boolean mayWrapRight(String sWrap) {
return "right".equals(sWrap) || "parallel".equals(sWrap) ||
"dynamic".equals(sWrap) || "run-through".equals(sWrap);
}
// TODO: Move to ConverterHelper.java
private String scale(String s) {
if (bConvertToPx) {
return Misc.length2px(Misc.multiply(sScale,Misc.truncateLength(s)));
}
else {
return Misc.multiply(sScale,Misc.truncateLength(s));
}
}
}

View file

@ -0,0 +1,299 @@
/************************************************************************
*
* FrameStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-11-22)
*
*/
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.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) {
StringBuffer buf = new StringBuffer();
buf.append(super.getStyleDeclarations(sIndent));
Enumeration names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = (String) 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("}\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);
StringBuffer out = new StringBuffer();
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') {
out.append(scale(in.getNumber()+in.getIdentifier()));
}
// 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) {
StringBuffer buf = new StringBuffer();
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,154 @@
/************************************************************************
*
* L10n.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-12-16)
*
*/
package writer2latex.xhtml;
// This class handles localized strings (used for navigation)
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 String sLocale="en-US";
public void setLocale(String sLocale) {
if (sLocale!=null) { this.sLocale = sLocale;}
}
public void setLocale(String sLanguage, String sCountry) {
if (sLanguage!=null) {
if (sCountry!=null) { sLocale = sLanguage + "-" + sCountry; }
else { sLocale = sLanguage; }
}
}
public String get(int nString) {
if (sLocale.startsWith("de")) { // german
switch (nString) {
case UP: return "Nach oben";
case FIRST : return "Anfang";
case PREVIOUS : return "Vorheriges";
case NEXT : return "N\u00ccchstes";
case LAST : return "Ende";
case CONTENTS : return "Inhalte";
case INDEX : return "Index";
case HOME : return "Home";
case DIRECTORY: return "Verzeichnis";
case DOCUMENT: return "Dokument";
}
}
if (sLocale.startsWith("fr")) { // french
switch (nString) {
case UP: return "Haut";
case FIRST : return "D\u00e9but";
case PREVIOUS : return "Pr\u00e9c\u00e9dent";
case NEXT : return "Suivant";
case LAST : return "Dernier";
case CONTENTS : return "Contenus";
case INDEX : return "Index";
case HOME : return "Documents Personnels";
case DIRECTORY: return "R\u00e9pertoire";
case DOCUMENT: return "Document";
}
}
if (sLocale.startsWith("da")) { // danish
switch (nString) {
case UP: return "Op";
case FIRST : return "F\u00F8rste";
case PREVIOUS : return "Forrige";
case NEXT : return "N\u00E6ste";
case LAST : return "Sidste";
case CONTENTS : return "Indhold";
case INDEX : return "Stikord";
case HOME : return "Hjem";
case DIRECTORY: return "Mappe";
case DOCUMENT: return "Dokument";
}
}
if (sLocale.startsWith("ru")) { // russian
switch (nString) {
case UP: return "\u0412\u0432\u0435\u0440\u0445";
case FIRST : return "\u041f\u0435\u0440\u0432\u0430\u044f";
case PREVIOUS : return "\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f";
case NEXT : return "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f";
case LAST : return "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f";
case CONTENTS : return "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435";
case INDEX : return "\u0421\u043f\u0438\u0441\u043e\u043a";
case HOME : return "\u0414\u043e\u043c\u043e\u0439";
case DIRECTORY: return "\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f";
case DOCUMENT: return "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442";
}
}
if (sLocale.startsWith("uk")) { // ukrainian
switch (nString) {
case UP: return "\u041d\u0430\u0433\u043e\u0440\u0443";
case FIRST : return "\u041f\u0435\u0440\u0448\u0430";
case PREVIOUS : return "\u041f\u043e\u043f\u0435\u0440\u0435\u0434\u043d\u044f";
case NEXT : return "\u041d\u0430\u0441\u0442\u0443\u043f\u043d\u0430";
case LAST : return "\u041e\u0441\u0442\u0430\u043d\u043d\u044f";
case CONTENTS : return "\u0417\u043c\u0456\u0441\u0442";
case INDEX : return "\u0421\u043f\u0438\u0441\u043e\u043a";
case HOME : return "\u0414\u043e\u0434\u043e\u043c\u0443";
case DIRECTORY: return "\u0422\u0435\u043a\u0430";
case DOCUMENT: return "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442";
}
}
if (sLocale.startsWith("hr")) { // croatian
switch (nString) {
case UP: return "Up";
case FIRST : return "Prvi";
case PREVIOUS : return "Prethodan";
case NEXT : return "slijede\u0107i";
case LAST : return "Zadnji";
case CONTENTS : return "Sadr\u017Eaj";
case INDEX : return "Indeks";
case DIRECTORY: return "Directory";
case DOCUMENT: return "Document";
}
}
// english - default
switch (nString) {
case UP: return "Up";
case FIRST : return "First";
case PREVIOUS : return "Previous";
case NEXT : return "Next";
case LAST: return "Last";
case CONTENTS : return "Contents";
case INDEX : return "Index";
case HOME : return "Home";
case DIRECTORY: return "Directory";
case DOCUMENT: return "Document";
}
return "???";
}
}

View file

@ -0,0 +1,40 @@
/************************************************************************
*
* LinkDescriptor.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-2007 by Henrik Just
*
* All Rights Reserved.
*
* 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,157 @@
/************************************************************************
*
* ListStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-11-22)
*
*/
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)) {
info.sTagName = styleMap.getElement(sDisplayName);
if (!"(none)".equals(styleMap.getCss(sDisplayName))) {
info.sClass = styleMap.getCss(sDisplayName);
}
}
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) {
StringBuffer buf = new StringBuffer();
Enumeration names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = (String) 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("}\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");
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","bullet"); 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+"')"); }
}
// We don't want floats to pass a list to the left (Mozilla and IE both
//handles this terribly!)
props.addValue("clear:left");
}
}

View file

@ -0,0 +1,238 @@
/************************************************************************
*
* MathConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2009 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2009-02-19)
*
*/
package writer2latex.xhtml;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import writer2latex.office.*;
public class MathConverter extends ConverterHelper {
private boolean bSupportMathML;
public MathConverter(OfficeReader ofr, XhtmlConfig config, Converter converter,
boolean bSupportMathML) {
super(ofr,config,converter);
this.bSupportMathML = bSupportMathML;
}
public void convert(Node onode, Node hnode) {
if (bSupportMathML) {
convertNode(onode,hnode);
}
else {
Document htmlDOM = hnode.getOwnerDocument();
NodeList annotationList
= ((Element) onode).getElementsByTagName(XMLString.MATH_ANNOTATION);
if (annotationList.getLength()>0 && annotationList.item(0).hasChildNodes()) {
// Insert the StarMath annotation as a kbd element
Element kbd = htmlDOM.createElement("kbd");
hnode.appendChild(kbd);
NodeList list = annotationList.item(0).getChildNodes();
int nLen = list.getLength();
for (int i=0; i<nLen; i++) {
Node child = list.item(i);
if (child.getNodeType()==Node.TEXT_NODE) {
kbd.appendChild(htmlDOM.createTextNode(child.getNodeValue()));
}
}
}
else {
hnode.appendChild(htmlDOM.createTextNode("[Warning: formula ignored]"));
}
}
}
public void convertNode(Node onode, Node hnode) {
if (onode.getNodeType()==Node.ELEMENT_NODE) {
if (onode.getNodeName().equals(XMLString.MATH_SEMANTICS)) {
// ignore this construction
convertNodeList(onode.getChildNodes(),hnode);
}
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 = hnode.getOwnerDocument().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 = attr.item(i).getNodeName();
if (sName.equals("xmlns:math")) { sName="xmlns"; }
else { sName = stripNamespace(sName); }
String sValue = attr.item(i).getNodeValue();
newNode.setAttribute(sName,replacePrivateChars(sValue));
}
}
convertNodeList(onode.getChildNodes(),newNode);
}
}
else if (onode.getNodeType()==Node.TEXT_NODE) {
String s = replacePrivateChars(onode.getNodeValue());
hnode.appendChild(hnode.getOwnerDocument().createTextNode(s));
}
}
private void convertNodeList(NodeList list, Node hnode) {
if (list==null) { return; }
int nLen = list.getLength();
for (int i=0; i<nLen; i++) {
convertNode(list.item(i),hnode);
}
}
private String stripNamespace(String s) {
int nPos = s.indexOf(':');
return s.substring(nPos+1);
}
// 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();
StringBuffer buf = new StringBuffer(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 named entities 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,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,137 @@
/************************************************************************
*
* PageStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.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;
/**
* 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 only export the background.
*/
public class PageStyleConverter extends StyleConverterHelper {
/** 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);
}
public void applyStyle(String sStyleName, StyleInfo info) {
MasterPage masterPage = ofr.getMasterPage(sStyleName);
String sDisplayName = masterPage.getDisplayName();
if (masterPage!=null) {
if (ofr.isPresentation()) {
// Always generates class name
info.sClass="masterpage"+styleNames.getExportName(sDisplayName);
}
else {
// For text documents only writing direction and background
String sPageLayout = masterPage.getPageLayoutName();
PageLayout pageLayout = ofr.getPageLayout(sPageLayout);
if (pageLayout!=null) {
applyDirection(pageLayout,info);
if (bConvertStyles) {
getFrameSc().cssBackground(pageLayout,info.props,true);
}
}
}
}
}
/** Convert style information for used styles
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
StringBuffer buf = new StringBuffer();
Enumeration names = styleNames.keys();
while (names.hasMoreElements()) {
// This will be master pages for presentations only
String sDisplayName = (String) 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);
}
// The export the results
buf.append(sIndent)
.append(".masterpage").append(styleNames.getExportName(sDisplayName))
.append(" {").append(info.props.toString()).append("}\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)); }
}
}

View file

@ -0,0 +1,195 @@
/************************************************************************
*
* ParStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* 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;
/*
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 paragraphs and headings.
* This also includes conversion of paragraph properties in other styles
* (cell styles).
*/
public class ParStyleConverter extends StyleWithPropertiesConverterHelper {
// Some bookkeeping for headings
private String[] sHeadingStyles = new String[7];
/** 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;
}
// TODO: Remove me, OfficeReader takes care of this
public void setHeadingStyle(int nLevel, String sStyleName) {
if (sHeadingStyles[nLevel]==null) {
sHeadingStyles[nLevel] = sStyleName;
}
}
/** Convert style information for used styles
* @param sIndent a String of spaces to add before each line
*/
public String getStyleDeclarations(String sIndent) {
StringBuffer buf = new StringBuffer();
buf.append(super.getStyleDeclarations(sIndent));
if (bConvertStyles) {
// Styles for headings
for (int i=1; i<=6; i++) {
if (sHeadingStyles[i]!=null) {
StyleWithProperties style = ofr.getParStyle(sHeadingStyles[i]);
if (style!=null) {
CSVList props = new CSVList(";");
applyProperties(style,props,true);
props.addValue("clear","left");
buf.append(sIndent).append("h").append(i)
.append(" {").append(props.toString()).append("}\n");
}
}
}
}
return buf.toString();
}
/** 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) {
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 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
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-11-22)
*
*/
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 outlineStyles = new Hashtable();
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) {
StringBuffer buf = new StringBuffer();
buf.append(super.getStyleDeclarations(sIndent));
Enumeration names = outlineStyleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = (String) 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("}\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(((String[]) outlineStyles.get(sCurrentOutlineStyle))[nLevel]);
}
}
}
}

View file

@ -0,0 +1,80 @@
/************************************************************************
*
* RowStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-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,84 @@
/************************************************************************
*
* SectionStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-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,175 @@
/************************************************************************
*
* StyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-11-22)
*
*/
package writer2latex.xhtml;
//import java.util.Enumeration;
//import java.util.Hashtable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import writer2latex.office.*;
import writer2latex.util.*;
/**
* <p>This class converts OpenDocument styles to CSS2 styles.</p>
* <p>Note that some elements in OpenDocument has attributes that also maps
* to CSS2 properties. Example: the width of a text box.</p>
* <p>Also note, that some OpenDocument style properties cannot be mapped to
* CSS2 without creating an additional inline element.</p>
* <p>The class uses one helper class per OpenDocument style family
* (paragraph, frame etc.)</p>
*/
class StyleConverter extends ConverterHelper {
// Helpers for text styles
private TextStyleConverter textSc;
private ParStyleConverter parSc;
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;
/** <p>Create a new <code>StyleConverter</code></p>
*/
public 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);
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
protected TextStyleConverter getTextSc() { return textSc; }
protected ParStyleConverter getParSc() { return parSc; }
protected ListStyleConverter getListSc() { return listSc; }
protected SectionStyleConverter getSectionSc() { return sectionSc; }
protected TableStyleConverter getTableSc() { return tableSc; }
protected RowStyleConverter getRowSc() { return rowSc; }
protected CellStyleConverter getCellSc() { return cellSc; }
protected FrameStyleConverter getFrameSc() { return frameSc; }
protected PresentationStyleConverter getPresentationSc() { return presentationSc; }
protected PageStyleConverter getPageSc() { return pageSc; }
private StyleWithProperties getDefaultStyle() {
if (ofr.isSpreadsheet()) return ofr.getDefaultCellStyle();
else if (ofr.isPresentation()) return ofr.getDefaultFrameStyle();
else return ofr.getDefaultParStyle();
}
// Apply the default language
public void applyDefaultLanguage(Element node) {
StyleWithProperties style = getDefaultStyle();
if (style!=null) {
StyleInfo info = new StyleInfo();
StyleConverterHelper.applyLang(style,info);
applyStyle(info,node);
}
}
// Export used styles to CSS
public Node exportStyles(Document htmlDOM) {
String sIndent = " ";
StringBuffer buf = new StringBuffer();
// Export default style
if (config.xhtmlCustomStylesheet().length()==0 &&
(config.xhtmlFormatting()==XhtmlConfig.CONVERT_ALL ||
config.xhtmlFormatting()==XhtmlConfig.IGNORE_HARD)) {
// Default paragraph/cell/frame style is applied to the body element
StyleWithProperties defaultStyle = getDefaultStyle();
if (defaultStyle!=null) {
CSVList props = new CSVList(";");
// text properties only!
getTextSc().cssTextCommon(defaultStyle,props,true);
buf.append(sIndent)
.append("body {").append(props.toString()).append("}\n");
}
}
// 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(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));
// Create node
if (buf.length()>0) {
Element htmlStyle = htmlDOM.createElement("style");
htmlStyle.setAttribute("media","all");
htmlStyle.setAttribute("type","text/css");
htmlStyle.appendChild(htmlDOM.createTextNode("\n"));
htmlStyle.appendChild(htmlDOM.createTextNode(buf.toString()));
htmlStyle.appendChild(htmlDOM.createTextNode(" "));
return htmlStyle;
}
else {
return null;
}
}
}

View file

@ -0,0 +1,121 @@
/************************************************************************
*
* StyleConverterHelper.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.xhtml;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.ExportNameCollection;
import writer2latex.util.Misc;
/**
* <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 Misc.length2px(Misc.multiply(sScale,s));
}
else {
return Misc.multiply(sScale,s);
}
}
protected String colScale(String s) {
return scale(Misc.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) { 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,41 @@
/************************************************************************
*
* StyleInfo.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-2007 by Henrik Just
*
* All Rights Reserved.
*
* 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,144 @@
/************************************************************************
*
* StyleWithPropertiesConverterHelper.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-11-22)
*
*/
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) {
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
info.sTagName = styleMap.getElement(sDisplayName);
if (!"(none)".equals(styleMap.getCss(sDisplayName))) {
info.sClass = styleMap.getCss(sDisplayName);
}
}
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) {
StringBuffer buf = new StringBuffer();
Enumeration names = styleNames.keys();
while (names.hasMoreElements()) {
String sDisplayName = (String) 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("}\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,453 @@
/************************************************************************
*
* TableConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-12-15)
*
*/
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.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 sheetNames = new Vector();
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
// IE needs the cellspacing attribute, as it doesn't understand the css border-spacing attribute
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.xhtmlIgnoreTableDimensions()) {
if (view.getRelTableWidth()!=null) {
for (int nCol=0; nCol<nColCount; nCol++) {
Element col = converter.createElement("col");
hnode.appendChild(col);
col.setAttribute("style","width:"+view.getRelColumnWidth(nCol));
}
}
else if (bFirstRowColSpan) {
for (int nCol=0; nCol<nColCount; nCol++) {
Element col = converter.createElement("col");
hnode.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
traverseRows(view,0,nRowCount,hnode);
}
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 && 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)) {
getTextCv().traverseBlockText(cell,td);
}
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), 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
}
}
}
}
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.xhtmlIgnoreTableDimensions()) {
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) {
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.xhtmlIgnoreTableDimensions()) {
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, 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.xhtmlIgnoreTableDimensions()) {
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=Misc.add(sEdge,getTableSc().colScale(s));
}
s = style.getProperty(XMLString.FO_PADDING_RIGHT);
if (s!=null) {
sEdge=Misc.add(sEdge,getTableSc().colScale(s));
}
s = style.getProperty(XMLString.FO_PADDING);
if (s!=null) {
sEdge=Misc.add(sEdge,Misc.multiply("200%",getTableSc().colScale(s)));
}
s = style.getProperty(XMLString.FO_BORDER_LEFT);
if (s!=null) {
sEdge=Misc.add(sEdge,getTableSc().colScale(borderWidth(s)));
}
s = style.getProperty(XMLString.FO_BORDER_RIGHT);
if (s!=null) {
sEdge=Misc.add(sEdge,getTableSc().colScale(borderWidth(s)));
}
s = style.getProperty(XMLString.FO_BORDER);
if (s!=null) {
sEdge=Misc.add(sEdge,Misc.multiply("200%",getTableSc().colScale(borderWidth(s))));
}
if (sTotalWidth!=null) {
info.props.addValue("width",Misc.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') { }
}
return "0";
}
}

View file

@ -0,0 +1,114 @@
/************************************************************************
*
* TableStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.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) {
// 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,432 @@
/************************************************************************
*
* TextStyleConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.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.ExportNameCollection;
import writer2latex.util.Misc;
/**
* 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 anchorCombinedStyleNames = new Hashtable();
private Hashtable orgAnchorStyleNames = new Hashtable();
private Hashtable orgAnchorVisitedStyleNames = new Hashtable();
/** 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;
}
/** 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
if (!"(none)".equals(styleMap.getCss(sDisplayName))) {
info.sClass = styleMap.getCss(sDisplayName);
}
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 = (String)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) {
StringBuffer buf = new StringBuffer();
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 enumer = anchorCombinedStyleNames.elements();
while (enumer.hasMoreElements()) {
String sExportName = (String) enumer.nextElement();
String sStyleName = (String) orgAnchorStyleNames.get(sExportName);
String sVisitedStyleName = (String) 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);
}
// Methods to query individual formatting properties (no inheritance)
// Does this style contain the bold attribute?
public boolean isBold(StyleWithProperties style) {
String s = style.getProperty(XMLString.FO_FONT_WEIGHT,false);
return s!=null && "bold".equals(s);
}
// Does this style contain the italics/oblique attribute?
public boolean isItalics(StyleWithProperties style) {
String s = style.getProperty(XMLString.FO_FONT_STYLE,false);
return s!=null && !"normal".equals(s);
}
// Does this style contain a fixed pitch font?
public boolean isFixed(StyleWithProperties style) {
String s = style.getProperty(XMLString.STYLE_FONT_NAME,false);
String s2 = null;
String s3 = null;
if (s!=null) {
FontDeclaration fd = (FontDeclaration) ofr.getFontDeclarations().getStyle(s);
if (fd!=null) {
s2 = fd.getFontFamilyGeneric();
s3 = fd.getFontPitch();
}
}
else {
s = style.getProperty(XMLString.FO_FONT_FAMILY,false);
s2 = style.getProperty(XMLString.STYLE_FONT_FAMILY_GENERIC,false);
s3 = style.getProperty(XMLString.STYLE_FONT_PITCH,false);
}
if ("fixed".equals(s3)) { return true; }
if ("modern".equals(s2)) { return true; }
return false;
}
// Does this style specify superscript?
public boolean isSuperscript(StyleWithProperties style) {
String sPos = style.getProperty(XMLString.STYLE_TEXT_POSITION,false);
if (sPos==null) return false;
if (sPos.startsWith("sub")) return false;
if (sPos.startsWith("-")) return false;
return true;
}
// Does this style specify subscript?
public boolean isSubscript(StyleWithProperties style) {
String sPos = style.getProperty(XMLString.STYLE_TEXT_POSITION,false);
if (sPos==null) return false;
if (sPos.startsWith("sub")) return true;
if (sPos.startsWith("-")) return true;
return false;
}
////////////////////////////////////////////////////////////////////////////
// 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 (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) { props.addValue("font-size",Misc.multiply(s4,scale(s))); }
else { props.addValue("font-size",s4); }
props.addValue("vertical-align",s3);
}
else if (s!=null) {
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,35 @@
/************************************************************************
*
* Xhtml10Converter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-09)
*
*/
package writer2latex.xhtml;
public class Xhtml10Converter extends Converter {
public Xhtml10Converter() {
super(XhtmlDocument.XHTML10);
}
}

View file

@ -0,0 +1,255 @@
/************************************************************************
*
* 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-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-11-14)
*
*/
package writer2latex.xhtml;
import java.util.Enumeration;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
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 36; }
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"; }
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;
// 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 ORIGINAL_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 CUSTOM_STYLESHEET = 8;
private static final int FORMATTING = 9;
private static final int FRAME_FORMATTING = 10;
private static final int SECTION_FORMATTING = 11;
private static final int TABLE_FORMATTING = 12;
private static final int IGNORE_TABLE_DIMENSIONS = 13;
private static final int USE_DUBLIN_CORE = 14;
private static final int NOTES = 15;
private static final int CONVERT_TO_PX = 16;
private static final int SCALING = 17;
private static final int COLUMN_SCALING = 18;
private static final int FLOAT_OBJECTS = 19;
private static final int TABSTOP_STYLE = 20;
private static final int USE_LIST_HACK = 21;
private static final int SPLIT_LEVEL = 22;
private static final int REPEAT_LEVELS = 23;
private static final int CALC_SPLIT = 24;
private static final int DISPLAY_HIDDEN_SHEETS = 25;
private static final int DISPLAY_HIDDEN_ROWS_COLS = 26;
private static final int DISPLAY_FILTERED_ROWS_COLS = 27;
private static final int APPLY_PRINT_RANGES = 28;
private static final int USE_TITLE_AS_HEADING = 29;
private static final int USE_SHEET_NAMES_AS_HEADINGS = 30;
private static final int XSLT_PATH = 31;
private static final int SAVE_IMAGES_IN_SUBDIR = 32;
private static final int UPLINK = 33;
private static final int DIRECTORY_ICON = 34;
private static final int DOCUMENT_ICON = 35;
protected XhtmlStyleMap xpar = new XhtmlStyleMap();
protected XhtmlStyleMap xtext = new XhtmlStyleMap();
protected XhtmlStyleMap xframe = new XhtmlStyleMap();
protected XhtmlStyleMap xlist = new XhtmlStyleMap();
protected XhtmlStyleMap xattr = new XhtmlStyleMap();
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[ORIGINAL_IMAGE_SIZE] = new BooleanOption("original_image_size","false");
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[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[IGNORE_TABLE_DIMENSIONS] = new BooleanOption("ignore_table_dimensions","false");
options[USE_DUBLIN_CORE] = new BooleanOption("use_dublin_core","true");
options[NOTES] = new BooleanOption("notes","true");
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[FLOAT_OBJECTS] = new BooleanOption("float_objects","true");
options[TABSTOP_STYLE] = new Option("tabstop_style","");
options[USE_LIST_HACK] = new BooleanOption("use_list_hack","false");
options[SPLIT_LEVEL] = new IntegerOption("split_level","0") {
public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
options[REPEAT_LEVELS] = new IntegerOption("repeat_levels","5") {
public void setString(String sValue) {
super.setString(sValue);
nValue = Misc.getPosInteger(sValue,0);
}
};
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[XSLT_PATH] = new Option("xslt_path","");
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","");
}
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");
}
String sBlockElement = elm.getAttribute("block-element");
String sBlockCss = elm.getAttribute("block-css");
if (sBlockCss.length()==0) { sBlockCss="(none)"; }
String sElement = elm.getAttribute("element");
String sCss = elm.getAttribute("css");
if (sCss.length()==0) { sCss="(none)"; }
if ("paragraph".equals(sFamily)) {
xpar.put(sName,sBlockElement,sBlockCss,sElement,sCss);
}
else if ("text".equals(sFamily)) {
xtext.put(sName,sBlockElement,sBlockCss,sElement,sCss);
}
else if ("frame".equals(sFamily)) {
xframe.put(sName,sBlockElement,sBlockCss,sElement,sCss);
}
else if ("list".equals(sFamily)) {
xlist.put(sName,sBlockElement,sBlockCss,sElement,sCss);
}
else if ("attribute".equals(sFamily)) {
xattr.put(sName,sBlockElement,sBlockCss,sElement,sCss);
}
}
}
protected void writeInner(Document dom) {
writeXStyleMap(dom,xpar,"paragraph");
writeXStyleMap(dom,xtext,"text");
writeXStyleMap(dom,xlist,"list");
writeXStyleMap(dom,xframe,"frame");
writeXStyleMap(dom,xframe,"attribute");
}
private void writeXStyleMap(Document dom, XhtmlStyleMap sm, String sFamily) {
Enumeration smEnum = sm.getNames();
while (smEnum.hasMoreElements()) {
String sName = (String) smEnum.nextElement();
Element smNode = dom.createElement("xhtml-style-map");
smNode.setAttribute("name",sName);
smNode.setAttribute("family",sFamily);
smNode.setAttribute("element",sm.getElement(sName));
smNode.setAttribute("css",sm.getCss(sName));
String sBlockElement = sm.getBlockElement(sName);
if (sBlockElement!=null) { smNode.setAttribute("block-element",sm.getCss(sBlockElement)); }
String sBlockCss = sm.getBlockCss(sName);
if (sBlockCss!=null) { smNode.setAttribute("block-css",sm.getCss(sBlockCss)); }
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 boolean originalImageSize() { return ((BooleanOption) options[ORIGINAL_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 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 boolean xhtmlIgnoreTableDimensions() { return ((BooleanOption) options[IGNORE_TABLE_DIMENSIONS]).getValue(); }
public boolean xhtmlUseDublinCore() { return ((BooleanOption) options[USE_DUBLIN_CORE]).getValue(); }
public boolean xhtmlNotes() { return ((BooleanOption) options[NOTES]).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 xhtmlFloatObjects() { return ((BooleanOption) options[FLOAT_OBJECTS]).getValue(); }
public String getXhtmlTabstopStyle() { return options[TABSTOP_STYLE].getString(); }
public boolean xhtmlUseListHack() { return ((BooleanOption) options[USE_LIST_HACK]).getValue(); }
public int getXhtmlSplitLevel() { return ((IntegerOption) options[SPLIT_LEVEL]).getValue(); }
public int getXhtmlRepeatLevels() { return ((IntegerOption) options[REPEAT_LEVELS]).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 String getXsltPath() { return options[XSLT_PATH].getString(); }
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 XhtmlStyleMap getXParStyleMap() { return xpar; }
public XhtmlStyleMap getXTextStyleMap() { return xtext; }
public XhtmlStyleMap getXFrameStyleMap() { return xframe; }
public XhtmlStyleMap getXListStyleMap() { return xlist; }
public XhtmlStyleMap getXAttrStyleMap() { return xattr; }
}

View file

@ -0,0 +1,782 @@
/************************************************************************
*
* XhtmlDocument.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-2009 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2009-02-19)
*
*/
//TODO: Remove redundant lang and dir attributes
//TODO: Add named entities outside ISO-latin 1
package writer2latex.xhtml;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
//import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.DOMImplementation;
//import org.xml.sax.SAXException;
//import org.xml.sax.SAXParseException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
//import javax.xml.parsers.ParserConfigurationException;
import writer2latex.xmerge.DOMDocument;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
/**
* 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 (not used currently) */
public static final int XHTML11 = 1;
/** Constant to identify XHTML + MathML documents */
public static final int XHTML_MATHML = 2;
/** Constant to identify XHTML + MathML documents using the xsl transformations
* from w3c's math working group (http://www.w3.org/Math/XSL/)
*/
public static final int XHTML_MATHML_XSL = 3;
private static final String[] sExtension = { ".html", ".html", ".xhtml", ".xml" };
private static final String[] sEmpty = { "base", "meta", "link", "hr", "br", "param", "img", "area", "input", "col" };
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 char cLimit = 65535;
private boolean bNoDoctype = false;
private boolean bAddBOM = false;
private String sXsltPath = "";
// 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;
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) - unlike the constructors in
* writer2latex.xmerge.DOMDocument.
* @param name <code>Document</code> name.
* @param nType the type of document
*/
public XhtmlDocument(String name, int nType) {
super(name,sExtension[nType]);
this.nType = nType;
// Define publicId and systemId
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 :
case XHTML_MATHML_XSL :
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"); */
}
// create DOM
Document contentDOM = null;
try {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
DOMImplementation domImpl = builder.getDOMImplementation();
DocumentType doctype = domImpl.createDocumentType("html", sPublicId, sSystemId);
contentDOM = domImpl.createDocument("http://www.w3.org/1999/xhtml","html",doctype);
}
catch (Throwable t) {
t.printStackTrace();
}
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);
}
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() {
headerNode = getContentDOM().createElement("div");
headerNode.setAttribute("id","header");
bodyNode.appendChild(headerNode);
contentNode = getContentDOM().createElement("div");
contentNode.setAttribute("id","content");
bodyNode.appendChild(contentNode);
footerNode = getContentDOM().createElement("div");
footerNode.setAttribute("id","footer");
bodyNode.appendChild(footerNode);
}
public void setContentDOM(Document doc) {
super.setContentDOM(doc);
collectNodes();
}
public void read(InputStream is) throws IOException {
super.read(is);
collectNodes();
}
public void readFromTemplate(XhtmlDocument template) {
// Remove all current child nodes
Element root = getContentDOM().getDocumentElement();
Node child = root.getFirstChild();
while (child!=null) {
root.removeChild(child);
child = root.getFirstChild();
}
// Import all child nodes from template
Element templateRoot = template.getContentDOM().getDocumentElement();
NodeList children = templateRoot.getChildNodes();
int nLen = children.getLength();
for (int i=0; i<nLen; i++) {
root.appendChild(getContentDOM().importNode(children.item(i),true));
}
// get the entry point nodes
collectNodes();
}
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 if ("div".equals(sTagName)) {
String sId = elm.getAttribute("id");
if ("content".equals(sId)) { contentNode = elm; }
else if ("header".equals(sId)) { headerNode = elm; }
else if ("footer".equals(sId)) { footerNode = elm; }
else if ("panel".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; }
if (titleNode==null) {
titleNode = getContentDOM().createElement("title");
headNode.appendChild(titleNode);
}
}
public void setEncoding(String s) {
s = s.toUpperCase();
if ("UTF-16".equals(s)) {
sEncoding = s;
cLimit = 65535;
}
else if ("ISO-8859-1".equals(s)) {
sEncoding = s;
cLimit = 255;
}
else if ("US-ASCII".equals(s)) {
sEncoding = s;
cLimit = 127;
}
else {
sEncoding = "UTF-8";
cLimit = 65535;
}
}
public String getEncoding() { return sEncoding; }
public void setNoDoctype(boolean b) { bNoDoctype = b; }
public void setAddBOM(boolean b) { bAddBOM = b; }
public void setUseNamedEntities(boolean b) {
bUseNamedEntities = b;
}
public void setXsltPath(String s) { sXsltPath = s; }
public String getFileExtension() { return super.getFileExtension(); }
/**
* 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 {
// Prepare named entities
prepareEntities();
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 documents (to be browser safe)
if (nType==XHTML_MATHML || nType==XHTML_MATHML_XSL) {
osw.write("<?xml version=\"1.0\" encoding=\""+sEncoding+"\" ?>\n");
}
// Either specify doctype or xsl transformation (the user may require
// that no doctype is used; this may be desirable for further transformations)
if (nType==XHTML_MATHML_XSL) {
// Original url: http://www.w3.org/Math/XSL/pmathml.xsl
// Add trailing slash if needed
String sSlash = sXsltPath.length()>0 && !sXsltPath.endsWith("/") ? "/" : "";
osw.write("<?xml-stylesheet type=\"text/xsl\" href=\""+sXsltPath+sSlash+"pmathml.xsl\"?>\n");
}
else if (!bNoDoctype) {
osw.write("<!DOCTYPE html PUBLIC \"");
osw.write(getContentDOM().getDoctype().getPublicId());
osw.write("\" \"");
osw.write(getContentDOM().getDoctype().getSystemId());
osw.write("\">\n");
}
write(getContentDOM().getDocumentElement(),0,osw);
osw.flush();
osw.close();
}
private boolean isEmpty(String sTagName) {
for (int i=0; i<sEmpty.length; i++) {
if (sEmpty[i].equals(sTagName)) { return true; }
}
return false;
}
// 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 childnodes
if (nLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("<"+node.getNodeName());
writeAttributes(node,osw);
osw.write(" />");
if (nLevel>=0) { osw.write("\n"); }
}
else if (node.hasChildNodes()) {
// Block pretty print from this node?
NodeList list = node.getChildNodes();
int nLen = list.getLength();
boolean bBlockPrettyPrint = false;
if (nLevel>=0) {
for (int i = 0; i < nLen; i++) {
bBlockPrettyPrint |= list.item(i).getNodeType()==Node.TEXT_NODE;
}
}
// Print start tag
if (nLevel>=0) { writeSpaces(nLevel,osw); }
osw.write("<"+node.getNodeName());
writeAttributes(node,osw);
osw.write(">");
if (nLevel>=0 && !bBlockPrettyPrint) { osw.write("\n"); }
// Print children
for (int i = 0; i < nLen; i++) {
int nNextLevel;
if (bBlockPrettyPrint || nLevel<0) { nNextLevel=-1; }
else { nNextLevel=nLevel+1; }
write(list.item(i),nNextLevel,osw);
}
// Print end tag
if (nLevel>=0 && !bBlockPrettyPrint) { 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) {
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(" -->");
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 || nType==XHTML_MATHML_XSL)) {
// There's a MathML entity to use
osw.write(s);
return;
}
}
if (c>cLimit) {
osw.write("&#x"+Integer.toHexString(c).toUpperCase()+";");
}
else {
osw.write(c);
}
}
private static void prepareEntities() {
if (entities==null) {
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;";
}
}
// 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;
}
}
}

View file

@ -0,0 +1,43 @@
/************************************************************************
*
* XhtmlFormatOption.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-08)
*
*/
package writer2latex.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,35 @@
/************************************************************************
*
* XhtmlMathMLConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-09)
*
*/
package writer2latex.xhtml;
public class XhtmlMathMLConverter extends Converter {
public XhtmlMathMLConverter() {
super(XhtmlDocument.XHTML_MATHML);
}
}

View file

@ -0,0 +1,35 @@
/************************************************************************
*
* XhtmlMathMLXSLConverter.java
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright: 2002-2008 by Henrik Just
*
* All Rights Reserved.
*
* Version 1.0 (2008-09-09)
*
*/
package writer2latex.xhtml;
public class XhtmlMathMLXSLConverter extends Converter {
public XhtmlMathMLXSLConverter() {
super(XhtmlDocument.XHTML_MATHML_XSL);
}
}

View file

@ -0,0 +1,69 @@
/************************************************************************
*
* XhtmlStyleMap.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-2003 by Henrik Just
*
* All Rights Reserved.
*
* Version 0.3.2 (2003-11-25)
*
*/
package writer2latex.xhtml;
import java.util.Hashtable;
import java.util.Enumeration;
public class XhtmlStyleMap {
private Hashtable blockElement = new Hashtable();
private Hashtable blockCss = new Hashtable();
private Hashtable element = new Hashtable();
private Hashtable css = new Hashtable();
public void put(String sName, String sBlockElement, String sBlockCss, String sElement, String sCss) {
blockElement.put(sName,sBlockElement);
blockCss.put(sName,sBlockCss);
element.put(sName,sElement);
css.put(sName,sCss);
}
public boolean contains(String sName) {
return sName!=null && element.containsKey(sName);
}
public String getBlockElement(String sName) {
return (String) blockElement.get(sName);
}
public String getBlockCss(String sName) {
return (String) blockCss.get(sName);
}
public String getElement(String sName) {
return (String) element.get(sName);
}
public String getCss(String sName) {
return (String) css.get(sName);
}
public Enumeration getNames() {
return element.keys();
}
}

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- cleanxhtml.xml
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)" />
<!-- 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>