From 53c15330d7d136e43babbd073e3eb29eb38cbdc6 Mon Sep 17 00:00:00 2001 From: hneemann Date: Tue, 4 Dec 2018 17:57:38 +0100 Subject: [PATCH] adds very basic css formatting to support Adobe Illustrator --- .../shapes/custom/CustomShapeDescription.java | 7 ++++ .../draw/shapes/custom/svg/Context.java | 38 ++++++++++++++++++- .../draw/shapes/custom/svg/SvgImporter.java | 9 ++++- .../draw/shapes/custom/SvgImporterTest.java | 13 ++++--- .../draw/shapes/custom/svg/ContextTest.java | 8 ++++ 5 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java b/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java index 303eb9d6e..6cf1edc4e 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java +++ b/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java @@ -366,6 +366,13 @@ public class CustomShapeDescription implements Iterable c.textAnchor = value); PARSER.put("fill-rule", (c, value) -> c.fillRuleEvenOdd = value.equalsIgnoreCase("evenodd")); + PARSER.put("class", Context::evalClass); } private Transform tr; @@ -41,6 +45,7 @@ class Context { private float fontSize; private String textAnchor; private boolean fillRuleEvenOdd; + private HashMap classesMap; Context() { tr = Transform.IDENTITY; @@ -48,6 +53,7 @@ class Context { stroke = Color.BLACK; fillOpacity = 1; strokeOpacity = 1; + classesMap = new HashMap<>(); } private Context(Context parent) { @@ -60,6 +66,8 @@ class Context { fontSize = parent.fontSize; textAnchor = parent.textAnchor; fillRuleEvenOdd = parent.fillRuleEvenOdd; + classesMap = new HashMap<>(); + classesMap.putAll(parent.classesMap); } Context(Context parent, Element element) throws SvgException { @@ -146,6 +154,34 @@ class Context { return fontSize; } + void addClasses(String classes) { + classes = classes.trim(); + while (classes.startsWith(".")) { + int p1 = classes.indexOf("{"); + int p2 = classes.indexOf("}"); + if (p1 < 0 || p2 < 0) + return; + String key = classes.substring(1, p1); + String val = classes.substring(p1 + 1, p2); + classesMap.put(key, val); + classes = classes.substring(p2 + 1).trim(); + } + } + + String getCssClass(String key) { + return classesMap.get(key); + } + + private static void evalClass(Context c, String value) throws SvgException { + StringTokenizer st = new StringTokenizer(value, ", "); + while (st.hasMoreTokens()) { + String cl = st.nextToken(); + String style = c.getCssClass(cl); + if (style != null) + readStyle(c, style); + } + } + private interface AttrParser { void parse(Context c, String value) throws SvgException; } diff --git a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java index 5c9e7dc45..3a782764d 100644 --- a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java +++ b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java @@ -89,8 +89,13 @@ public class SvgImporter { private void create(CustomShapeDescription csd, NodeList gList, Context c) throws SvgException { for (int i = 0; i < gList.getLength(); i++) { final Node node = gList.item(i); - if (node instanceof Element) - create(csd, (Element) node, c); + if (node instanceof Element) { + final Element element = (Element) node; + if (element.getNodeName().equals("style")) + c.addClasses(element.getTextContent()); + else + create(csd, element, c); + } } } diff --git a/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java b/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java index c1580b44d..38bedfb3a 100644 --- a/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java +++ b/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java @@ -8,7 +8,6 @@ package de.neemann.digital.draw.shapes.custom; import de.neemann.digital.draw.elements.PinException; import de.neemann.digital.draw.graphics.Polygon; import de.neemann.digital.draw.graphics.PolygonParser; -import de.neemann.digital.draw.graphics.Vector; import de.neemann.digital.draw.graphics.VectorInterface; import de.neemann.digital.draw.shapes.Drawable; import de.neemann.digital.draw.shapes.custom.svg.SvgException; @@ -490,9 +489,10 @@ public class SvgImporterTest extends TestCase { new CSDChecker(custom) .checkPolygon("M 0,-10 C 0,-10 15,-10 30,-10 C 70,-10 70,50 35,50 C 20,50 0,50 0,50 L 0,-10 Z") - .checkText(10, 10, "A") - .checkText(10, 10, "B") - .checkText(10, 10, "Y") + .checkPolygon("M 0,-10 C 0,-10 15,-10 30,-10 C 70,-10 70,50 35,50 C 20,50 0,50 0,50 L 0,-10 Z") + .checkText(4, 6, "A") + .checkText(4, 45, "B") + .checkText(45, 25, "Y") .checkPin(0, 0, "A", false) .checkPin(0, 40, "B", false) .checkPin(60, 20, "Y", false) @@ -596,7 +596,10 @@ public class SvgImporterTest extends TestCase { private CSDChecker checkText(int x, int y, String text) { checker.add(d -> { - assertTrue(d instanceof CustomShapeDescription.TextHolder); + assertTrue("Text expected, found " + d.getClass().getSimpleName(), d instanceof CustomShapeDescription.TextHolder); + CustomShapeDescription.TextHolder t = (CustomShapeDescription.TextHolder) d; + assertEquals("text x", x, t.getPos().x); + assertEquals("text y", y, t.getPos().y); }); return this; } diff --git a/src/test/java/de/neemann/digital/draw/shapes/custom/svg/ContextTest.java b/src/test/java/de/neemann/digital/draw/shapes/custom/svg/ContextTest.java index 8c8727a2e..21e96b697 100644 --- a/src/test/java/de/neemann/digital/draw/shapes/custom/svg/ContextTest.java +++ b/src/test/java/de/neemann/digital/draw/shapes/custom/svg/ContextTest.java @@ -27,4 +27,12 @@ public class ContextTest extends TestCase { assertEquals(new Color(0, 0, 0, 127), c.getFilled()); } + + public void testCSS() { + Context c = new Context(); + c.addClasses(" .z{a:1}\n .y{a:2}"); + assertEquals("a:1", c.getCssClass("z")); + assertEquals("a:2", c.getCssClass("y")); + } + } \ No newline at end of file