Skip to content

Commit 1edda6f

Browse files
Merge pull request #78 from davidwatkins73/master
Another attempt at getting visio to work
2 parents e0e4645 + a3ded48 commit 1edda6f

8 files changed

Lines changed: 169 additions & 62 deletions

File tree

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@
121121
<version>1.3.2</version>
122122
</dependency>
123123

124+
<dependency>
125+
<groupId>org.jooq</groupId>
126+
<artifactId>jool</artifactId>
127+
<version>0.9.10</version>
128+
</dependency>
129+
130+
124131

125132
<!-- PROVIDED -->
126133

waltz-common/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
<artifactId>pcollections</artifactId>
2424
</dependency>
2525

26+
<dependency>
27+
<groupId>org.jooq</groupId>
28+
<artifactId>jool</artifactId>
29+
</dependency>
30+
31+
2632
<!-- LOGGING -->
2733

2834
<dependency>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.khartec.waltz.common;
2+
3+
import org.w3c.dom.Document;
4+
import org.w3c.dom.Node;
5+
import org.w3c.dom.NodeList;
6+
7+
import javax.xml.parsers.DocumentBuilderFactory;
8+
import javax.xml.parsers.ParserConfigurationException;
9+
import javax.xml.transform.OutputKeys;
10+
import javax.xml.transform.Transformer;
11+
import javax.xml.transform.TransformerException;
12+
import javax.xml.transform.TransformerFactory;
13+
import javax.xml.transform.dom.DOMSource;
14+
import javax.xml.transform.stream.StreamResult;
15+
import java.io.ByteArrayOutputStream;
16+
import java.io.IOException;
17+
import java.io.OutputStream;
18+
import java.io.OutputStreamWriter;
19+
import java.util.stream.Stream;
20+
21+
public class XmlUtilities {
22+
23+
public static Stream<Node> stream(NodeList nodeList) {
24+
Node[] nodes = new Node[nodeList.getLength()];
25+
26+
for (int i = 0; i < nodeList.getLength(); i++) {
27+
nodes[i] = nodeList.item(i);
28+
}
29+
return Stream.of(nodes);
30+
}
31+
32+
33+
public static String printDocument(Document doc) throws IOException, TransformerException {
34+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
35+
printDocument(doc, baos);
36+
return new String(baos.toByteArray());
37+
}
38+
39+
40+
public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
41+
TransformerFactory tf = TransformerFactory.newInstance();
42+
Transformer transformer = tf.newTransformer();
43+
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
44+
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
45+
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
46+
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
47+
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
48+
49+
transformer.transform(new DOMSource(doc),
50+
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
51+
}
52+
53+
public static DocumentBuilderFactory createNonValidatingDocumentBuilderFactory() throws ParserConfigurationException {
54+
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
55+
56+
factory.setValidating(false);
57+
factory.setNamespaceAware(true);
58+
factory.setFeature("http://xml.org/sax/features/namespaces", false);
59+
factory.setFeature("http://xml.org/sax/features/validation", false);
60+
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
61+
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
62+
63+
return factory;
64+
}
65+
}

waltz-ng/client/capabilities/list-view.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ function controller(capabilities, appCapabilityStore, svgStore, $state) {
2929

3030
svgStore.findByKind('CAPABILITY').then(xs => vm.diagrams = xs);
3131

32-
vm.blockProcessor = block => {
33-
block.parent.onclick = () => $state.go('main.capabilities.view', { id: block.value });
34-
angular.element(block.parent).addClass('clickable');
32+
vm.blockProcessor = b => {
33+
b.block.onclick = () => $state.go('main.capabilities.view', { id: b.value });
34+
angular.element(b.block).addClass('clickable');
3535
};
3636
}
3737

waltz-ng/client/org-units/list-view.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ function controller(orgUnits, tallies, svgStore, $state) {
5151

5252
svgStore.findByKind('ORG_UNIT').then(xs => vm.diagrams = xs);
5353

54-
vm.blockProcessor = block => {
55-
block.parent.onclick = () => $state.go('main.org-units.unit', { id: block.value });
56-
angular.element(block.parent).addClass('clickable');
54+
vm.blockProcessor = b => {
55+
b.block.onclick = () => $state.go('main.org-units.unit', { id: b.value });
56+
angular.element(b.block).addClass('clickable');
5757
};
5858
}
5959

waltz-ng/client/svg-diagram/directives/svg-diagram.js

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,66 +11,28 @@ function resize(elem) {
1111

1212

1313
function controller($scope, $window) {
14-
const blockParsers = {
15-
'draw.io': (diagram, svg) => {
16-
const anchors = svg.find('a');
17-
return _.chain(anchors)
18-
.map(anchor => {
19-
const attr = anchor.attributes['xlink:href'];
20-
if (! attr) return null;
21-
const empId = attr.value;
22-
anchor.removeAttribute('xlink:href');
23-
return {
24-
rawProperty: empId,
25-
parent: anchor,
26-
value: empId,
27-
name: 'xlink:href'
28-
};
29-
})
30-
.compact()
31-
.value();
32-
},
33-
'visio': (diagram, svg) => {
34-
$window.setTimeout(() => resize(svg), 100);
35-
36-
const custProps = svg.find('v:cp');
37-
38-
// get rid of auto generated svg titles
39-
_.each(svg.find('title'), t => t.remove());
40-
41-
return _.chain(custProps)
42-
.filter(cp => cp
43-
&& cp.attributes
44-
&& cp.attributes['v:lbl']
45-
&& cp.attributes['v:lbl'].value == diagram.keyProperty)
46-
.map(cp => {
47-
const valAttr = cp.attributes['v:val'];
48-
const value = valAttr
49-
? valAttr.value.replace(/.*\((.*)\).*/, '$1')
50-
: '';
51-
52-
return {
53-
rawProperty: cp,
54-
parent: cp.parentNode.parentNode,
55-
value,
56-
name: cp.attributes['v:lbl'].value
57-
};
58-
})
59-
.value();
60-
}
61-
};
62-
6314
const vm = this;
6415

6516
angular.element($window)
6617
.on('resize', () => resize($scope.elem));
6718

6819

69-
$scope.$watch('ctrl.diagram', f => {
70-
if (!f) return;
20+
$scope.$watch('ctrl.diagram', diagram => {
21+
if (!diagram) return;
22+
23+
const svg = $scope.elem.append(diagram.svg);
24+
25+
if (diagram.product === 'visio') {
26+
$window.setTimeout(() => resize(svg), 100);
27+
}
28+
29+
const dataProp = 'data-' + diagram.keyProperty;
30+
const dataBlocks = svg.querySelectorAll('[' + dataProp + ']');
7131

72-
const svg = $scope.elem.append(vm.diagram.svg);
73-
const blocks = blockParsers[vm.diagram.product](vm.diagram, svg);
32+
const blocks = _.map(dataBlocks, b => ({
33+
block: b,
34+
value: b.attributes[dataProp].value
35+
}));
7436

7537
_.each(blocks, vm.blockProcessor);
7638
});

waltz-ng/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
"start": "node lib/server-production"
1717
},
1818
"dependencies": {
19-
"angular": "^1.4.4",
20-
"angular-animate": "^1.4.8",
19+
"angular": "1.4.7",
20+
"angular-animate": "1.4.7",
2121
"angular-formly": "^6.24.23",
2222
"angular-formly-templates-bootstrap": "^6.0.0",
2323
"angular-local-storage": "^0.2.2",

waltz-service/src/main/java/com/khartec/waltz/service/svg/SvgDiagramService.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,33 @@
1818
package com.khartec.waltz.service.svg;
1919

2020
import com.khartec.waltz.data.svg.SvgDiagramDao;
21+
import com.khartec.waltz.model.svg.ImmutableSvgDiagram;
2122
import com.khartec.waltz.model.svg.SvgDiagram;
23+
import org.jooq.lambda.Unchecked;
2224
import org.springframework.beans.factory.annotation.Autowired;
2325
import org.springframework.stereotype.Service;
26+
import org.w3c.dom.Document;
27+
import org.w3c.dom.Element;
28+
import org.w3c.dom.NodeList;
29+
import org.xml.sax.InputSource;
30+
import org.xml.sax.SAXException;
2431

32+
import javax.xml.parsers.DocumentBuilder;
33+
import javax.xml.parsers.ParserConfigurationException;
34+
import javax.xml.transform.TransformerException;
35+
import javax.xml.xpath.XPath;
36+
import javax.xml.xpath.XPathConstants;
37+
import javax.xml.xpath.XPathExpressionException;
38+
import javax.xml.xpath.XPathFactory;
39+
import java.io.ByteArrayInputStream;
40+
import java.io.IOException;
2541
import java.util.List;
42+
import java.util.stream.Collectors;
43+
44+
import static com.khartec.waltz.common.XmlUtilities.createNonValidatingDocumentBuilderFactory;
45+
import static com.khartec.waltz.common.XmlUtilities.printDocument;
46+
import static com.khartec.waltz.common.XmlUtilities.stream;
47+
import static java.util.stream.Collectors.toList;
2648

2749
@Service
2850
public class SvgDiagramService {
@@ -34,7 +56,52 @@ public SvgDiagramService(SvgDiagramDao svgDiagramDao) {
3456
this.svgDiagramDao = svgDiagramDao;
3557
}
3658

59+
60+
private String convertProductSpecificSvg(SvgDiagram diagram) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException, TransformerException {
61+
if (diagram.product().equals("visio")) {
62+
return convertVisoSvg(diagram);
63+
} else {
64+
return diagram.svg();
65+
}
66+
}
67+
68+
69+
private String convertVisoSvg(SvgDiagram diagram) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException, TransformerException {
70+
DocumentBuilder builder = createNonValidatingDocumentBuilderFactory().newDocumentBuilder();
71+
InputSource svgSource = new InputSource(new ByteArrayInputStream(diagram.svg().getBytes()));
72+
Document svg = builder.parse(svgSource);
73+
74+
XPath xpath = XPathFactory.newInstance().newXPath();
75+
NodeList nodes = (NodeList) xpath.evaluate("//*", svg, XPathConstants.NODESET);
76+
77+
String key = diagram.keyProperty();
78+
79+
stream(nodes)
80+
.forEach(n -> stream(n.getChildNodes())
81+
.filter(c -> c.getNodeName().contains("custProps"))
82+
.forEach(c -> stream(c.getChildNodes())
83+
.filter(cp -> cp.getNodeName().contains("cp"))
84+
.map(cp -> (Element) cp)
85+
.filter(cp -> key.equals(cp.getAttribute("v:lbl")))
86+
.map(cp -> cp.getAttribute("v:val"))
87+
.map(v -> v.replaceAll("^.*\\((.*)\\)$", "$1"))
88+
.forEach(v -> ((Element) n).setAttribute("data-"+key, v))
89+
)
90+
);
91+
92+
return printDocument(svg);
93+
}
94+
95+
3796
public List<SvgDiagram> findByKind(String kind) {
38-
return svgDiagramDao.findByKind(kind);
97+
return svgDiagramDao.findByKind(kind)
98+
.stream()
99+
.map(Unchecked.function(diag -> {
100+
String updatedSvg = convertProductSpecificSvg(diag);
101+
return ImmutableSvgDiagram.copyOf(diag)
102+
.withSvg(updatedSvg);
103+
}))
104+
.collect(toList());
39105
}
106+
40107
}

0 commit comments

Comments
 (0)