w2phtml/src/main/java/writer2latex/xhtml/style/FrameStyleParser.java

313 lines
13 KiB
Java

/************************************************************************
*
* FrameStyleConverter.java
*
* Copyright: 2002-2014 by Henrik Just
*
* This file is part of Writer2LaTeX.
*
* Writer2LaTeX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Writer2LaTeX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Writer2LaTeX. If not, see <http://www.gnu.org/licenses/>.
*
* Version 1.4 (2014-09-16)
*
*/
package writer2latex.xhtml.style;
import java.util.Enumeration;
import writer2latex.office.OfficeReader;
import writer2latex.office.OfficeStyleFamily;
import writer2latex.office.StyleWithProperties;
import writer2latex.office.XMLString;
import writer2latex.util.CSVList;
import writer2latex.util.Calc;
//import writer2latex.util.Misc;
import writer2latex.util.SimpleInputBuffer;
import writer2latex.xhtml.Converter;
import writer2latex.xhtml.XhtmlConfig;
import writer2latex.xhtml.style.properties.Properties;
/**
* 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 FrameStyleParser extends StyleWithPropertiesParser {
/** 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 FrameStyleParser(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 composeStyleDeclarations() {
if (!bConvertStyles) {
return "";
}
StringBuilder buf = new StringBuilder();
buf.append(super.composeStyleDeclarations());
Enumeration<String> names = styleNames.keys();
while (names.hasMoreElements()) {
String displayName = names.nextElement();
buf.append(composeDeclaration(displayName));
}
return buf.toString();
}
public String composeDeclaration(String displayName) {
String declaration = "";
StyleWithProperties style = (StyleWithProperties) getStyles().getStyleByDisplayName(displayName);
String declarationBlock = composeDeclarationBlock(displayName);
String selector = composeSelector(displayName);
if (!style.isAutomatic() && !selector.isEmpty() && !declarationBlock.isEmpty()) {
declaration = createDeclaration(selector, declarationBlock);
}
return declaration;
}
private String composeSelector(String displayName) {
styleNames.addName(displayName);
return getStyleTag() + "." + getClassNamePrefix() + styleNames.getName(displayName) + " p ";
}
public String composeDeclarationBlock( String sDisplayName) {
StyleWithProperties style = (StyleWithProperties) getStyles().getStyleByDisplayName(sDisplayName);
Properties props = new Properties(";");
getFrameSc().cssMargins(style, props, true);
getParSP().cssPar(style, props, true);
getTextSP().cssTextCommon(style, props, true);
return props.toString();
}
/** 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 getStyleTag() {
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, Properties props, boolean bInherit) {
cssBox(style,props,bInherit);
getTextSP().cssTextCommon(style,props,bInherit); // only in presentations
}
////////////////////////////////////////////////////////////////////////////
// OpenDocument frame properties
public void cssBox(StyleWithProperties style, Properties 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, Properties props, boolean bInherit){
// *Absolute* values fit with css
String s;
if (bInherit || style.hasProperty(XMLString.FO_MARGIN_LEFT)) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_LEFT);
if (s!=null) { props.addProperty("margin-left",scale(s)); }
else { props.addProperty("margin-left","0"); }
}
if (bInherit || style.hasProperty(XMLString.FO_MARGIN_RIGHT)) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_RIGHT);
if (s!=null) { props.addProperty("margin-right",scale(s)); }
else { props.addProperty("margin-right","0"); }
}
if (bInherit || style.hasProperty(XMLString.FO_MARGIN_TOP)) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_TOP);
if (s!=null) { props.addProperty("margin-top",scale(s)); }
else { props.addProperty("margin-top","0"); }
}
if (bInherit || style.hasProperty(XMLString.FO_MARGIN_BOTTOM)) {
s = style.getAbsoluteProperty(XMLString.FO_MARGIN_BOTTOM);
if (s!=null) { props.addProperty("margin-bottom",scale(s)); }
else { props.addProperty("margin-bottom","0"); }
}
}
public void cssBorder(StyleWithProperties style, Properties 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.addProperty("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.addProperty("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.addProperty("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.addProperty("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.addProperty("border-right",borderScale(s)); bHasBorder=true; }
}
}
// Default to no border:
if (bInherit && !bHasBorder) { props.addProperty("border","none"); }
}
public void cssPadding(StyleWithProperties style, Properties 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.addProperty("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.addProperty("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.addProperty("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.addProperty("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.addProperty("padding-right",scale(s)); bRight=true; }
}
if (bInherit) { // must specify padding
if (!bTop && !bBottom && !bLeft && !bRight) {
props.addProperty("padding","0");
}
else {
if (!bTop) { props.addProperty("padding-top","0"); }
if (!bBottom) { props.addProperty("padding-bottom","0"); }
if (!bLeft) { props.addProperty("padding-left","0"); }
if (!bRight) { props.addProperty("padding-right","0"); }
}
}
}
}
// parapgrah styles need this for special treatment of background color
public void cssBackgroundCommon(StyleWithProperties style, Properties props, boolean bInherit){
// Background image:
String sUrl = style.getBackgroundImageProperty(XMLString.XLINK_HREF);
if (sUrl!=null) { // currently only support for linked image
props.addProperty("background-image","url("+escapeUrl(sUrl)+")");
String sRepeat = style.getBackgroundImageProperty(XMLString.STYLE_REPEAT);
if ("no-repeat".equals(sRepeat) || "stretch".equals(sRepeat)) {
props.addProperty("background-repeat","no-repeat");
}
else {
props.addProperty("background-repeat","repeat");
}
String sPosition = style.getBackgroundImageProperty(XMLString.STYLE_POSITION);
if (sPosition!=null) { props.addProperty("background-position",sPosition); }
}
}
public void cssBackground(StyleWithProperties style, Properties props, boolean bInherit){
// Background color: Same as in css
String s = style.getProperty(XMLString.FO_BACKGROUND_COLOR,bInherit);
if (s!=null) { props.addProperty("background-color",s); }
cssBackgroundCommon(style,props,bInherit);
}
// Scale the border with while preserving the rest of the attribute
public String borderScale(String sBorder) {
SimpleInputBuffer in = new SimpleInputBuffer(sBorder);
StringBuilder out = new StringBuilder();
while (in.peekChar()!='\0') {
// Skip spaces
while(in.peekChar()==' ') { out.append(" "); in.getChar(); }
// If it's a number it must be a unit -> convert it
if ('0'<=in.peekChar() && in.peekChar()<='9') {
String sDim = scale(in.getNumber()+in.getIdentifier());
// Do not output a border less than 1px wide - some browsers will render it invisible
out.append(Calc.isLessThan(sDim, "1px") ? "1px" : sDim);
}
// skip other characters
while (in.peekChar()!=' ' && in.peekChar()!='\0') {
out.append(in.getChar());
}
}
return out.toString();
}
// Must escape certain characters in the url property
private String escapeUrl(String sUrl) {
StringBuilder buf = new StringBuilder();
int nLen = sUrl.length();
for (int i=0; i<nLen; i++) {
char c = sUrl.charAt(i);
if (c=='\'' || c=='"' || c=='(' || c==')' || c==',' || c==' ') {
buf.append("\\");
}
buf.append(c);
}
return buf.toString();
}
}