
cz.vutbr.fit.layout.io.HTMLOutputOperator Maven / Gradle / Ivy
/**
* HTMLOutputOperator.java
*
* Created on 12. 1. 2016, 11:42:43 by burgetr
*/
package cz.vutbr.fit.layout.io;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cz.vutbr.fit.layout.api.Parameter;
import cz.vutbr.fit.layout.impl.BaseOperator;
import cz.vutbr.fit.layout.impl.ParameterBoolean;
import cz.vutbr.fit.layout.impl.ParameterString;
import cz.vutbr.fit.layout.model.Area;
import cz.vutbr.fit.layout.model.AreaTree;
import cz.vutbr.fit.layout.model.Border;
import cz.vutbr.fit.layout.model.Box;
import cz.vutbr.fit.layout.model.Color;
import cz.vutbr.fit.layout.model.ContentRect;
import cz.vutbr.fit.layout.model.Page;
import cz.vutbr.fit.layout.model.Rectangular;
import cz.vutbr.fit.layout.model.Box.Type;
/**
* This operator serializes the area tree to an HTML file.
*
* @author burgetr
*/
public class HTMLOutputOperator extends BaseOperator
{
/** Default length unit */
protected static final String UNIT = "px";
/** Should we produce the HTML header and footer? */
protected boolean produceHeader;
/** Should we produce the box tree only or should we rely on the area tree? */
protected boolean boxTreeOnly;
/** Path to the output file/ */
protected String filename;
public HTMLOutputOperator()
{
produceHeader = true;
boxTreeOnly = false;
filename = "out.html";
}
public HTMLOutputOperator(String filename, boolean produceHeader, boolean boxTreeOnly)
{
this.filename = filename;
this.produceHeader = produceHeader;
this.boxTreeOnly = boxTreeOnly;
}
@Override
public String getId()
{
return "FitLayout.Tools.HTMLOutput";
}
@Override
public String getName()
{
return "HTML serialization of the area tree";
}
@Override
public String getDescription()
{
return "Serializes the area tree to an HTML file";
}
@Override
public String getCategory()
{
return "output";
}
@Override
public List defineParams()
{
List ret = new ArrayList<>(3);
ret.add(new ParameterString("filename"));
ret.add(new ParameterBoolean("produceHeader"));
ret.add(new ParameterBoolean("boxTreeOnly"));
return ret;
}
public boolean getProduceHeader()
{
return produceHeader;
}
public void setProduceHeader(boolean produceHeader)
{
this.produceHeader = produceHeader;
}
public boolean getBoxTreeOnly()
{
return boxTreeOnly;
}
public void setBoxTreeOnly(boolean boxTreeOnly)
{
this.boxTreeOnly = boxTreeOnly;
}
public String getFilename()
{
return filename;
}
public void setFilename(String filename)
{
this.filename = filename;
}
//=====================================================================================================
@Override
public void apply(AreaTree atree)
{
apply(atree, atree.getRoot());
}
@Override
public void apply(AreaTree atree, Area root)
{
try
{
Page page = (Page) getServiceManager().getArtifactRepository().getArtifact(atree.getParentIri());
PrintWriter out = new PrintWriter(filename);
if (boxTreeOnly)
dumpTo(page, out);
else
dumpTo(atree, page, out);
out.close();
} catch (FileNotFoundException e) {
System.err.println("Couldn't create output HTML file " + filename);
}
}
//=====================================================================================================
/**
* Formats the complete area tree to an output stream.
* @param tree the area tree to be printed
* @param out a writer to be used for output
*/
public void dumpTo(AreaTree tree, Page sourcePage, PrintWriter out)
{
if (produceHeader)
{
out.println("");
out.println("");
out.println("");
if (sourcePage != null)
out.println("" + sourcePage.getTitle() + " ");
out.println("");
out.println("");
out.println("");
out.println("");
out.println("");
}
recursiveDumpArea(tree.getRoot(), 1, out);
if (produceHeader)
{
out.println("");
out.println("");
}
}
/**
* Formats the complete box tree to an output stream.
* @param page the page box tree to be printed
* @param out a writer to be used for output
*/
public void dumpTo(Page page, PrintWriter out)
{
if (produceHeader)
{
out.println("");
out.println("");
out.println("");
out.println("" + page.getTitle() + " ");
out.println("");
out.println("");
out.println("");
out.println("");
out.println("");
}
recursiveDumpBoxes(page.getRoot(), 1, out);
if (produceHeader)
{
out.println("");
out.println("");
}
}
//=====================================================================
private void recursiveDumpArea(Area a, int level, java.io.PrintWriter p)
{
String tagName = "div";
String stag = "<" + tagName
+ " id=\"a" + a.getId() + "\""
+ " style=\"" + getAreaStyle(a) + "\""
+ ">";
String etag = "" + tagName + ">";
if (a.getChildCount() > 0)
{
indent(level, p);
p.println(stag);
for (int i = 0; i < a.getChildCount(); i++)
recursiveDumpArea(a.getChildAt(i), level+1, p);
indent(level, p);
p.println(etag);
}
else
{
indent(level, p);
p.println(stag);
dumpAreaBoxes(a, p, level+1);
indent(level, p);
p.println(etag);
}
}
private void dumpAreaBoxes(Area a, java.io.PrintWriter p, int level)
{
List boxes = a.getBoxes();
for (Box box : boxes)
{
if (box.getType() == Type.TEXT_CONTENT)
{
indent(level, p);
String stag = "";
p.print(stag);
p.print(HTMLEntities(box.getText()));
p.println("");
}
else
{
Style style = getBoxStyle(a, box);
style.put("width", getContentWidth(box), "px");
style.put("height", getContentHeight(box), "px");
String stag = "";
indent(level, p);
p.println(stag);
for (int i = 0; i < box.getChildCount(); i++)
recursiveDumpBoxes(box.getChildAt(i), level + 1, p);
indent(level, p);
p.println("");
}
}
}
private void recursiveDumpBoxes(Box box, int level, java.io.PrintWriter p)
{
if (box.getType() == Type.TEXT_CONTENT)
{
indent(level, p);
String stag = "";
p.print(stag);
p.print(HTMLEntities(box.getText()));
p.println("");
}
else
{
Style style = getBoxStyle(box.getParent(), box);
style.put("width", getContentWidth(box), "px");
style.put("height", getContentHeight(box), "px");
String stag = "";
indent(level, p);
p.println(stag);
for (int i = 0; i < box.getChildCount(); i++)
recursiveDumpBoxes(box.getChildAt(i), level + 1, p);
indent(level, p);
p.println("");
}
}
protected String getAreaStyle(Area a)
{
Area parent = a.getParent();
int px = 0;
int py = 0;
if (parent != null)
{
px = parent.getX1();
py = parent.getY1();
Border bleft = parent.getBorderStyle(Border.Side.LEFT);
if (bleft != null)
px += bleft.getWidth();
Border btop = parent.getBorderStyle(Border.Side.TOP);
if (btop != null)
py += btop.getWidth();
}
int bw = 0;
int bh = 0;
Style style = new Style();
style.put("position", "absolute");
String bgcol = colorString(a.getBackgroundColor());
if (!bgcol.isEmpty())
style.put("background", bgcol);
for (Border.Side side : Border.Side.values())
{
Border bstyle = a.getBorderStyle(side);
String brd = getBorderStyle(bstyle);
if (!brd.isEmpty())
{
style.put("border-" + side.toString(), brd);
if (side == Border.Side.LEFT || side == Border.Side.RIGHT)
bw += bstyle.getWidth();
else if (side == Border.Side.TOP || side == Border.Side.BOTTOM)
bh += bstyle.getWidth();
}
}
style.put("left", a.getX1() - px, UNIT);
style.put("top", a.getY1() - py, UNIT);
style.put("width", a.getWidth() - bw, UNIT);
style.put("height", a.getHeight() - bh, UNIT);
return style.toString();
}
protected Style getBoxStyle(ContentRect parent, Box box)
{
int px = 0;
int py = 0;
if (parent != null)
{
px = parent.getX1() + parent.getBorderStyle(Border.Side.LEFT).getWidth();
py = parent.getY1() + parent.getBorderStyle(Border.Side.TOP).getWidth();
}
return getBoxStyle(box, px, py);
}
protected Style getBoxStyle(Box box, int px, int py)
{
Rectangular pos = box.getVisualBounds();
Style style = new Style();
style.put("position", "absolute");
style.put("top", (pos.getY1() - py), UNIT);
style.put("left", (pos.getX1() - px), UNIT);
style.put("color", (colorString(box.getColor())));
String bgcol = colorString(box.getBackgroundColor());
if (!bgcol.isEmpty())
style.put("background", bgcol);
style.put("font-family", box.getFontFamily());
style.put("font-size", box.getTextStyle().getFontSize(), UNIT);
style.put("font-weight", ((box.getTextStyle().getFontWeight() < 0.5f)?"normal":"bold"));
style.put("font-style", ((box.getTextStyle().getFontStyle() < 0.5f)?"normal":"italic"));
String deco = "";
if (box.getTextStyle().getUnderline() >= 0.5f)
deco += "underline";
if (box.getTextStyle().getLineThrough() >= 0.5f)
deco += " line-through";
if (deco.isEmpty())
deco = "none";
style.put("text-decoration", deco);
for (Border.Side side : Border.Side.values())
{
String brd = getBorderStyle(box.getBorderStyle(side));
if (!brd.isEmpty())
style.put("border-" + side.toString(), brd);
}
return style;
}
private String getBorderStyle(Border border)
{
if (border != null && border.getStyle() != Border.Style.NONE && border.getWidth() > 0)
{
StringBuilder ret = new StringBuilder();
ret.append(border.getWidth()).append(UNIT);
ret.append(' ').append(border.getStyle().toString().toLowerCase());
ret.append(' ').append(colorString(border.getColor()));
return ret.toString();
}
else
return "";
}
private int getContentWidth(Box box)
{
return box.getWidth() - box.getLeftBorder() - box.getRightBorder();
}
private int getContentHeight(Box box)
{
return box.getHeight() - box.getTopBorder() - box.getBottomBorder();
}
private void indent(int level, java.io.PrintWriter p)
{
String ind = "";
for (int i = 0; i < level*4; i++) ind = ind + ' ';
p.print(ind);
}
private String colorString(Color color)
{
if (color == null)
return "";
else
return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());
}
/**
* Converts the CSS specification rgb(r,g,b) to #rrggbb
* @param spec the CSS color specification
* @return a #rrggbb string
*/
public String colorString(String spec)
{
if (spec.startsWith("rgb("))
{
String s = spec.substring(4, spec.length() - 1);
String[] lst = s.split(",");
try {
int r = Integer.parseInt(lst[0].trim());
int g = Integer.parseInt(lst[1].trim());
int b = Integer.parseInt(lst[2].trim());
return String.format("#%02x%02x%02x", r, g, b);
} catch (NumberFormatException e) {
return null;
}
}
else
return spec;
}
private String HTMLEntities(String s)
{
return s.replaceAll(">", ">").replaceAll("<", "<").replaceAll("&", "&");
}
/**
* Element style representation.
*
* @author burgetr
*/
protected class Style extends HashMap
{
private static final long serialVersionUID = 1L;
public void put(String key, int value, String unit)
{
put(key, value + unit);
}
public void put(String key, float value, String unit)
{
put(key, value + unit);
}
@Override
public String toString()
{
StringBuilder ret = new StringBuilder();
for (Map.Entry entry : entrySet())
{
ret.append(entry.getKey()).append(':').append(entry.getValue()).append(';');
}
return ret.toString();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy