/* * Copyright 2012 Odysseus Software GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.odysseus.ithaka.digraph.io.graphml.yfiles; import java.awt.Font; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import de.odysseus.ithaka.digraph.Digraph; import de.odysseus.ithaka.digraph.DigraphProvider; import de.odysseus.ithaka.digraph.io.graphml.GraphMLExporter; import de.odysseus.ithaka.digraph.io.graphml.GraphMLProperty; import de.odysseus.ithaka.digraph.io.graphml.GraphMLPropertyDomain; import de.odysseus.ithaka.digraph.io.graphml.GraphMLProvider; import de.odysseus.ithaka.digraph.io.graphml.SimpleGraphMLProvider; import de.odysseus.ithaka.digraph.layout.DigraphLayoutArc; import de.odysseus.ithaka.digraph.layout.DigrpahLayoutBuilder; import de.odysseus.ithaka.digraph.layout.DigraphLayoutNode; public class YFilesGraphML<V, E> { private static final String SCHEMA_LOCATION = "http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd"; private final LayoutTree<V, E> layoutTree; private final SimpleGraphMLProvider<DigraphLayoutNode<V>, DigraphLayoutArc<V,E>, Digraph<? extends DigraphLayoutNode<V>,? extends DigraphLayoutArc<V,E>>> provider; static abstract class GraphMLPropertyDelegate<S, T> implements GraphMLProperty<T> { final GraphMLProperty<S> property; public GraphMLPropertyDelegate(GraphMLProperty<S> property) { this.property = property; } @Override public GraphMLPropertyDomain getDomain() { return property.getDomain(); } @Override public String getNamespaceURI() { return property.getNamespaceURI(); } @Override public String getPrefix() { return property.getPrefix(); } @Override public void writeKey(XMLStreamWriter writer, String id) throws XMLStreamException { property.writeKey(writer, id); } } public YFilesGraphML( Digraph<V, E> digraph, DigrpahLayoutBuilder<V, E> builder, LabelResolver<? super V> labels, Font font) { this(digraph, builder, labels, null, font, font); } public YFilesGraphML( Digraph<V, E> digraph, DigrpahLayoutBuilder<V, E> builder, LabelResolver<? super V> nodeLabels, LabelResolver<? super E> edgeLabels, Font nodeFont, Font edgeFont) { this(digraph, null, builder, nodeLabels, edgeLabels, nodeFont, edgeFont, false); } public YFilesGraphML( Digraph<V, E> digraph, DigraphProvider<V, Digraph<V,E>> subgraphs, DigrpahLayoutBuilder<V, E> builder, LabelResolver<? super V> nodeLabels, Font nodeFont, boolean groupNodes) { this(digraph, subgraphs, builder, nodeLabels, null, nodeFont, null, groupNodes); } public YFilesGraphML( Digraph<V, E> digraph, DigraphProvider<V, Digraph<V,E>> subgraphs, DigrpahLayoutBuilder<V, E> builder, LabelResolver<? super V> nodeLabels, LabelResolver<? super E> edgeLabels, Font nodeFont, Font edgeFont, boolean groupNodes) { this(digraph, subgraphs, new SimpleGraphMLProvider<V, E, Digraph<V,E>>(), builder, nodeLabels, edgeLabels, nodeFont, edgeFont, groupNodes); } public YFilesGraphML( Digraph<V, E> digraph, DigraphProvider<V, Digraph<V,E>> subgraphs, GraphMLProvider<V, E, Digraph<V,E>> delegate, DigrpahLayoutBuilder<V, E> builder, LabelResolver<? super V> nodeLabels, LabelResolver<? super E> edgeLabels, Font nodeFont, Font edgeFont, boolean groupNodes) { this( delegate, new LayoutTree<V, E>(digraph, subgraphs, builder, nodeLabels, nodeFont), new NodeGraphicsProperty<V>(nodeLabels, nodeFont, subgraphs, groupNodes), new EdgeGraphicsProperty<V, E>(edgeLabels, edgeFont)); } public YFilesGraphML( GraphMLProvider<V, E, Digraph<V,E>> delegate, LayoutTree<V, E> layoutTree, NodeGraphicsProperty<V> nodeGraphics, EdgeGraphicsProperty<V, E> edgeGraphics) { this.layoutTree = layoutTree; this.provider = new SimpleGraphMLProvider<DigraphLayoutNode<V>, DigraphLayoutArc<V,E>, Digraph<? extends DigraphLayoutNode<V>,? extends DigraphLayoutArc<V,E>>>(SCHEMA_LOCATION); for (final GraphMLProperty<Digraph<V,E>> graphProperty : delegate.getGraphProperties()) { provider.addGraphProperty(new GraphMLPropertyDelegate<Digraph<V,E>, Digraph<? extends DigraphLayoutNode<V>,? extends DigraphLayoutArc<V,E>>>(graphProperty) { @Override public void writeData(XMLStreamWriter writer, String id, Digraph<? extends DigraphLayoutNode<V>, ? extends DigraphLayoutArc<V, E>> value) throws XMLStreamException { property.writeData(writer, id, findDigraph(YFilesGraphML.this.layoutTree, value)); } Digraph<V,E> findDigraph(LayoutTree<V, E> layoutTree, Digraph<? extends DigraphLayoutNode<V>, ? extends DigraphLayoutArc<V, E>> layoutGraph) { if (layoutTree.getLayout().getLayoutGraph() == layoutGraph) { return layoutTree.getDigraph(); } for (V subtreeVertex : layoutTree.subtreeVertices()) { Digraph<V,E> result = findDigraph(layoutTree.getSubtree(subtreeVertex), layoutGraph); if (result != null) { return result; } } return null; } }); } for (final GraphMLProperty<V> nodeProperty : delegate.getNodeProperties()) { provider.addNodeProperty(new GraphMLPropertyDelegate<V, DigraphLayoutNode<V>>(nodeProperty) { @Override public void writeData(XMLStreamWriter writer, String id, DigraphLayoutNode<V> value) throws XMLStreamException { property.writeData(writer, id, value.getVertex()); } }); } for (final GraphMLProperty<E> edgeProperty : delegate.getEdgeProperties()) { provider.addEdgeProperty(new GraphMLPropertyDelegate<E, DigraphLayoutArc<V,E>>(edgeProperty) { @Override public void writeData(XMLStreamWriter writer, String id, DigraphLayoutArc<V,E> value) throws XMLStreamException { property.writeData(writer, id, value.getEdge()); } }); } provider.addNodeProperty(nodeGraphics); provider.addEdgeProperty(edgeGraphics); } private DigraphProvider<? super DigraphLayoutNode<V>, Digraph<? extends DigraphLayoutNode<V>, ? extends DigraphLayoutArc<V, E>>> getSubgraphProvider() { return new DigraphProvider<DigraphLayoutNode<V>, Digraph<? extends DigraphLayoutNode<V>,? extends DigraphLayoutArc<V,E>>>() { @Override public Digraph<? extends DigraphLayoutNode<V>, ? extends DigraphLayoutArc<V, E>> get(DigraphLayoutNode<V> node) { LayoutTree<V, E> subtree = layoutTree.find(node.getVertex()); return subtree == null ? null : subtree.getLayout().getLayoutGraph(); } }; } public void export(XMLStreamWriter writer) throws XMLStreamException { new GraphMLExporter().export(provider, layoutTree.getLayout().getLayoutGraph(), getSubgraphProvider(), writer); } }