blob: c99ae956cff76c76078dcc57be6d537687e539eb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2013 Formal Mind GmbH and University of Dusseldorf.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Michael Jastram - initial API and implementation
******************************************************************************/
package org.eclipse.rmf.reqif10.pror.editor.util;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.rmf.reqif10.AttributeValue;
import org.eclipse.rmf.reqif10.DatatypeDefinition;
import org.eclipse.rmf.reqif10.EnumValue;
import org.eclipse.rmf.reqif10.SpecHierarchy;
import org.eclipse.rmf.reqif10.SpecObject;
import org.eclipse.rmf.reqif10.Specification;
import org.eclipse.rmf.reqif10.XhtmlContent;
import org.eclipse.rmf.reqif10.common.util.ProrXhtmlSimplifiedHelper;
import org.eclipse.rmf.reqif10.common.util.ReqIF10Util;
import org.eclipse.rmf.reqif10.common.util.ReqIF10XhtmlUtil;
import org.eclipse.rmf.reqif10.pror.configuration.Column;
import org.eclipse.rmf.reqif10.pror.configuration.ProrPresentationConfiguration;
import org.eclipse.rmf.reqif10.pror.configuration.ProrSpecViewConfiguration;
import org.eclipse.rmf.reqif10.pror.configuration.UnifiedColumn;
import org.eclipse.rmf.reqif10.pror.editor.presentation.service.IProrCellRenderer;
import org.eclipse.rmf.reqif10.pror.editor.presentation.service.PresentationEditorInterface;
import org.eclipse.rmf.reqif10.pror.util.ConfigurationUtil;
import org.eclipse.rmf.reqif10.pror.util.ProrUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.google.common.io.Files;
/**
* Once instantiated, it can produce a folder with HTML for the given
* Specification.
*
* @author jastram
*/
public class HTMLPrinter {
private Specification spec;
private AdapterFactory adapterFactory;
private File sourceFolder;
private ProrSpecViewConfiguration config;
private File targetFolder;
/**
* Constructs an HTMLPriter..
*/
public HTMLPrinter(Specification spec, EditingDomain domain,
AdapterFactory adapterFactory) {
this.spec = spec;
this.adapterFactory = adapterFactory;
this.sourceFolder = new File(CommonPlugin.resolve(spec.eResource().getURI())
.trimSegments(1).toFileString());
this.config = ConfigurationUtil.createSpecViewConfiguration(spec,
domain);
}
/**
* Produces a File representing the spec that this object was constructed with,
* located in a temporary folder that also contains related images, if any.
*/
public File print() throws IOException {
targetFolder = createTempFolder();
// Build the HTML
StringBuilder html = new StringBuilder();
createHtmlHeader(html);
html.append("<table>");
createRowHeader(html);
printRecursive(html, 0, spec.getChildren());
html.append("</table>");
// Write the HTML
File htmlFile = new File(targetFolder, spec.getIdentifier() + ".html");
FileWriter writer = new FileWriter(htmlFile);
writer.write(html.toString());
writer.close();
htmlFile.deleteOnExit();
return htmlFile;
}
/**
* Builds the header row.
* @return
*/
private void createRowHeader(StringBuilder html) {
html.append("<tr>");
EList<Column> cols = config.getColumns();
for (Column col : cols) {
html.append("<td><b>" + col.getLabel() + "</b></td>");
}
html.append("</tr>\n");
}
/**
* Creates a temporary folder for the spec. Note that currently there is no cleanup.
*/
private File createTempFolder() throws IOException {
File targetFolder = File.createTempFile("pror-", "");
targetFolder.delete();
targetFolder = new File(targetFolder.getAbsolutePath() + "/");
targetFolder.mkdir();
return targetFolder;
}
private void createHtmlHeader(StringBuilder html) {
String title = ConfigurationUtil.getSpecElementLabel(spec,
adapterFactory);
html.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
html.append("<html>\n");
html.append("<head>\n");
html.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n");
html.append("<meta name=\"GENERATOR\" content=\"ProR (www.pror.org)\">\n");
html.append("<title>" + title + "</title>\n");
html.append("<style type=\"text/css\">\n");
html.append("body {font-family: Arial, sans-serif;}\n");
html.append("h1 {text-align: center;}\n");
html.append("table, th, td { border-bottom: 1px solid #cccccc; }\n");
html.append("td { padding: 2pt; }\n");
html.append("table { border-collapse: collapse; }");
html.append("</style>\n");
html.append("</head>\n\n");
html.append("<body>\n");
html.append("<h1>" + title + "</h1>\n");
}
private void printRecursive(StringBuilder html, int indent,
EList<SpecHierarchy> children) {
for (SpecHierarchy child : children) {
if (child.getObject() != null) {
SpecObject specObject = child.getObject();
boolean first = true;
html.append("<tr>");
for (Column col : config.getColumns()) {
html.append("<td valign='top'>");
// Handle indenting
if (first) {
html.append("<div style='margin-left: " + (indent * 20)
+ "px;'>");
}
AttributeValue av;
if (col instanceof UnifiedColumn) {
av = ReqIF10Util.getAttributeValueForLabel(specObject,
"ReqIF.Text");
if (av == null || ReqIF10Util.getTheValue(av) == null) {
av = ReqIF10Util.getAttributeValueForLabel(
specObject, "ReqIF.ChapterName");
}
} else {
av = ReqIF10Util.getAttributeValueForLabel(specObject,
col.getLabel());
}
DatatypeDefinition dd = ReqIF10Util
.getDatatypeDefinition(av);
ProrPresentationConfiguration configuration = ConfigurationUtil
.getPresentationConfiguration(dd);
Object itemProvider = ProrUtil.getItemProvider(
adapterFactory, configuration);
if (itemProvider instanceof PresentationEditorInterface) {
PresentationEditorInterface presentationEditor = (PresentationEditorInterface) itemProvider;
IProrCellRenderer renderer = presentationEditor
.getCellRenderer(av);
if (renderer != null) {
String content = renderer.doDrawHtmlContent(av);
if (content != null) {
html.append(content);
} else {
html.append(HTMLPrinter.normalizeHtmlString(getValueAsString(av)));
}
}
} else {
html.append(HTMLPrinter.normalizeHtmlString(getValueAsString(av)));
}
if (first) {
first = false;
html.append("</div>");
}
html.append("</td>");
}
html.append("</tr>\n");
}
printRecursive(html, indent + 1, child.getChildren());
}
}
private String getValueAsString(AttributeValue av) {
Object value = av == null ? null : ReqIF10Util.getTheValue(av);
if (value == null) {
return "";
} else if (value instanceof List<?>) {
return listAsString(value);
} else if (value instanceof XhtmlContent) {
return xhtmlAsString((XhtmlContent)value);
} else if (value instanceof GregorianCalendar) {
GregorianCalendar cal = (GregorianCalendar) value;
SimpleDateFormat formatter = new SimpleDateFormat(
"yyyy-MMM-dd hh:mm:ss z");
return formatter.format(cal.getTime());
} else {
return value.toString();
}
}
private String xhtmlAsString(XhtmlContent xhtmlContent) {
String textValue = ProrXhtmlSimplifiedHelper
.xhtmlToSimplifiedString(xhtmlContent);
try {
String xhtmlString = ReqIF10XhtmlUtil
.getXhtmlString(xhtmlContent);
xhtmlString = xhtmlString.replace("<xhtml:", "<");
xhtmlString = xhtmlString.replace("</xhtml:", "</");
textValue = xhtmlString;
// Find and extract embedded images.
Document dom = ReqIF10XhtmlUtil.getXhtmlDom(xhtmlContent);
NodeList tags = dom.getElementsByTagName("xhtml:object");
for (int i = 0; i < tags.getLength(); i++) {
Node xhtmlNode = tags.item(i);
Node dataNode = xhtmlNode.getAttributes().getNamedItem("data");
if (dataNode != null) {
String filename = dataNode.getTextContent();
copyEmbeddedObject(filename);
}
}
} catch (IOException e) {
}
return textValue;
}
/**
* Copy the source file identified by the given filename. This method may
* fail silently to prevent interuption of the HTML printing.
*/
private void copyEmbeddedObject(String filename) {
File fullSourceFolder = sourceFolder;
File fullTargetFolder = targetFolder;
StringTokenizer st = new StringTokenizer(filename, "/");
String token = null;
while (st.hasMoreTokens()) {
token = st.nextToken();
if (! st.hasMoreTokens()) break;
fullSourceFolder = new File (fullSourceFolder, token);
fullTargetFolder = new File(fullTargetFolder, token);
fullTargetFolder.mkdir();
}
File source = new File(fullSourceFolder, token);
File target = new File(fullTargetFolder, token);
try {
Files.copy(source, target);
} catch (IOException e) {
e.printStackTrace();
}
}
private String listAsString(Object value) {
String textValue = "";
for (Iterator<?> i = ((List<?>) ((List<?>) value)).iterator(); i
.hasNext();) {
EnumValue enumValue = (EnumValue) i.next();
textValue += enumValue.getLongName();
if (i.hasNext()) {
textValue += ", ";
}
}
return textValue;
}
/**
* O.T.G.O.T.L.J.C. - david lall
* @Bugfix 456675
* Normalize a string using decimal code to render non-english language characters in html.
* @param inputStr
*/
public static String normalizeHtmlString(String inputStr){
//1. Parameter condition check.
if(inputStr==null || inputStr.trim().length()==0)
return "";
//2. Convert each char of input string to its decimal code & apply formatting.
StringBuilder htmlString = new StringBuilder();
inputStr=inputStr.trim();
for(int i=0;i<inputStr.length();i++){
int decimalValue=(int)inputStr.charAt(i);
if((decimalValue>=48 && decimalValue<=57) || (decimalValue>=65 && decimalValue<=90) || (decimalValue>=97 && decimalValue<=122)){
htmlString.append((char)decimalValue);
}//end of if
else{
htmlString.append("&#"+decimalValue+";");
}//end of else
}//end of for
return htmlString.toString();
}//end of method
}