import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGeneratorContext;
import org.apache.batik.svggen.SVGGraphics2D;
+import org.apache.batik.svggen.SVGIDGenerator;
import org.simantics.Simantics;
import org.simantics.datatypes.literal.GUID;
import org.simantics.db.ReadGraph;
import org.simantics.diagram.elements.TextGridNode;
import org.simantics.diagram.elements.TextNode;
import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.ui.DiagramModelHints;
import org.simantics.g2d.canvas.Hints;
import org.simantics.g2d.canvas.ICanvasContext;
import org.simantics.g2d.diagram.DiagramHints;
import org.simantics.g2d.diagram.IDiagram;
import org.simantics.g2d.diagram.handler.DataElementMap;
+import org.simantics.g2d.diagram.participant.ElementPainter.SelectionShapeNode;
import org.simantics.g2d.diagram.participant.Selection;
import org.simantics.g2d.element.IElement;
import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;
return true;
}
+
+ static class UniqueIDGenerator extends SVGIDGenerator{
+
+ String overallId;
+ public UniqueIDGenerator(String overallId) {
+ super();
+ this.overallId = overallId;
+ }
+
+ @Override
+ public String generateID(String prefix) {
+ return super.generateID(overallId+prefix);
+ }
+
+ }
+
static class Generator extends SVGGraphics2D {
int elemLevel = 0;
}
public Generator(Document document) {
+ this(document,null);
+ }
+ public Generator(Document document, String id) {
super(document);
// prevent batik comment in each g-element
getGeneratorContext().setComment(null);
+ if (id != null)
+ getGeneratorContext().setIDGenerator(new UniqueIDGenerator(id));
}
@Override
}
+
+
private static String renderSVG0(double width, double height, ICanvasContext ctx, Function1<Set<?>, Map<?, ?>> mappingFunction) {
// Get a DOMImplementation.
Document document = domImpl.createDocument(svgNS, "svg", null);
// Create an instance of the SVG Generator.
- SVGGraphics2D svgGenerator = new Generator(document);
+ IDiagram d = ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
+ Resource r = d.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
+ SVGGraphics2D svgGenerator;
+ if (r != null)
+ svgGenerator = new Generator(document,r.toString());
+ else
+ svgGenerator = new Generator(document);
RenderSVGContext result = new RenderSVGContext();
if (selection != null) {
// This prevents workbench selection from being left over.
// Also prevents scene graph crap from being left on the screen.
- IDiagram d = ctx.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);
- selection.setSelection(0, d.getElements());
+ selection.setSelection(0, d.getElements());
}
G2DSceneGraph sg = ctx.getSceneGraph();
result.append(ALL_SECTIONS, "</g>");
StringBuilder res = new StringBuilder();
- res.append("<svg width=\"100%\" height=\"100%\" stroke=\"black\">");
+ if (width > 0 && height > 0 ) {
+ res.append("<svg width=\"" + width +"px\" height=\""+height+"px\" stroke=\"black\" xmlns=\"http://www.w3.org/2000/svg\">");
+ } else {
+ res.append("<svg width=\"100%\" height=\"100%\" stroke=\"black\" xmlns=\"http://www.w3.org/2000/svg\">");
+ }
res.append("<g transform=\"matrix(").append(matrix[0]).append(",").append(matrix[1]).append(",").append(matrix[2]).append(",").append(matrix[3]).append(",").append(matrix[4]).append(",").append(matrix[5]).append(")\">");
res.append(result.get(MAIN_SECTION));
res.append(result.get(SELECTION_SECTION));
private String getKey(SingleElementNode node) {
String key;
if(node.getKey() != null) {
- if (mappings.containsKey(node.getKey()))
+ if (mappings.containsKey(node.getKey())) {
key = mappings.get(node.getKey()).toString();
- else
+ key = escape(key);
+ } else {
key = node.getKey().toString();
+ key = escape(key);
+ }
} else {
key = Long.toString(node.getId());
}
return key;
}
+
+ private String escape(String key) {
+ // Keys may contain '<' '>' characters, which causes errors in browser SVG handling.
+ return org.apache.commons.lang.StringEscapeUtils.escapeHtml(key);
+ }
+
+ private String removeElem(String xml, String elemStart) {
+ // FIXME: This is rather nasty and error prone way of removing elements from XML string.
+ // This only supports elements with /> end element tag. Elements ends with </elem name> are not supported!
+ int start = xml.indexOf("<"+elemStart);
+ if (start>=0) {
+ int end = xml.indexOf(">",start);
+ if (end >= 0) {
+ if (start > 0)
+ return xml.substring(0,start)+xml.substring(end+1);
+ else
+ return xml.substring(end+1);
+ }
+ }
+ return null;
+ }
@Override
public void enter(IG2DNode node) {
parentBuilder.append(MAIN_SECTION, "\n<g transform=\"" + m + "\">");
}
}
- parentBuilder.append(MAIN_SECTION, svg.getSVGText());
+ String svgContent = svg.getSVGText();
+ // SVGNode content may contain SVG/XML elements, which break browser compatibility
+ int start = svgContent.indexOf("<svg");
+ if (start >= 0)
+ svgContent = svgContent.substring(start);
+ else {
+ String s = removeElem(svgContent, "?xml");
+ if (s != null) {
+ svgContent = "<g>"+s+"</g>";
+ s = removeElem(svgContent, "!DOCTYPE");
+ if (s != null)
+ svgContent = s;
+ }
+ }
+ parentBuilder.append(MAIN_SECTION, svgContent);
if (!at.isIdentity()) {
parentBuilder.append(MAIN_SECTION, "\n</g>");
}
parentBuilder.append(ALL_SECTIONS, "\n<g transform=\"" + m + "\">");
}
}
+ } else if (node instanceof TextNode) {
+ TextNode text = (TextNode)node;
+
+ SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class);
+ if(parentSEN != null) {
+
+ text.setShowSelection(false);
+ Element doc = renderSVGNode(svgGenerator, (IG2DNode)node);
+ String svg = printSVGDocument(doc);
+ parentBuilder.append(MAIN_SECTION, svg);
+
+ RenderSVGContext parentBuilder2 = getParentBuilder(parentSEN);
+
+ String key = getKey(parentSEN);
+ text.setShowSelection(true);
+ doc = renderSVGNode(svgGenerator, (IG2DNode)node);
+ svg = printSVGDocument(doc);
+
+ parentBuilder2.append(SELECTION_SECTION, "\n<g style=\"visibility:hidden\" class=\"selection\" id=\"" + key + "\">");
+ parentBuilder2.append(SELECTION_SECTION, svg);
+ parentBuilder2.append(SELECTION_SECTION, "\n</g>");
+ parentBuilder2.append(SELECTION_MASK_SECTION, "\n<g class=\"selectionMask\" id=\"" + key /*+ "\" transform=\"" + matrixString + "\"*/+ "\">");
+ Rectangle2D rect = text.getBounds();
+ // NaN
+ if(rect.getHeight() == rect.getHeight() && rect.getWidth() == rect.getWidth()) {
+ parentBuilder2.append(SELECTION_MASK_SECTION,"<rect style=\"fill:#fff\" opacity=\"" + OPACITY + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," x=\"" + rect.getX() + "\" y=\"" + rect.getY() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," width=\"" + rect.getWidth() + "\" height=\"" + rect.getHeight() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION,"></rect>");
+ }
+ parentBuilder2.append(SELECTION_MASK_SECTION,"\n</g>");
+
+ }
} else if (!(node instanceof RouteGraphNode) && !(node instanceof LinkNode)){
try {
Element doc = renderSVGNode(svgGenerator, (IG2DNode)node);
if (!hasContent)
return;
String svg = printSVGDocument(doc);
- parentBuilder.append(MAIN_SECTION, "<g class=\"" +node.getSimpleClassName() +"\">");
- parentBuilder.append(MAIN_SECTION, svg);
- parentBuilder.append(MAIN_SECTION, "\n</g>");
+ if (node instanceof SelectionShapeNode) {
+ SingleElementNode parentSEN = (SingleElementNode)NodeUtil.getNearestParentOfType(node, SingleElementNode.class);
+ if(parentSEN != null) {
+ String key = getKey(parentSEN);
+ RenderSVGContext parentBuilder2 = getParentBuilder(parentSEN);
+ parentBuilder2.append(SELECTION_SECTION, "\n<g style=\"visibility:hidden\" class=\"selection\" id=\"" + key + "\">");
+ parentBuilder2.append(SELECTION_SECTION, svg);
+ parentBuilder2.append(SELECTION_SECTION, "\n</g>");
+
+ parentBuilder2.append(SELECTION_MASK_SECTION, "\n<g class=\"selectionMask\" id=\"" + key /*+ "\" transform=\"" + matrixString + "\"*/+ "\">");
+ Rectangle2D rect = node.getBounds();
+ // NaN
+ if(rect.getHeight() == rect.getHeight() && rect.getWidth() == rect.getWidth()) {
+ parentBuilder2.append(SELECTION_MASK_SECTION,"<rect style=\"fill:#fff\" opacity=\"" + OPACITY + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," x=\"" + rect.getX() + "\" y=\"" + rect.getY() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION," width=\"" + rect.getWidth() + "\" height=\"" + rect.getHeight() + "\"");
+ parentBuilder2.append(SELECTION_MASK_SECTION,"></rect>");
+ }
+ parentBuilder2.append(SELECTION_MASK_SECTION,"\n</g>");
+ }
+ } else {
+ parentBuilder.append(MAIN_SECTION, "<g class=\"" +node.getSimpleClassName() +"\">");
+ parentBuilder.append(MAIN_SECTION, svg);
+ parentBuilder.append(MAIN_SECTION, "\n</g>");
+ }
} catch (Exception e) {
// TODO: There are nodes that do not behave well when rendered to SVG. For backwards compatibility, we don't handle the exceptions.
}