1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.layout.multipage;
29  
30  import y.base.DataProvider;
31  import y.base.Edge;
32  import y.base.Graph;
33  import y.base.GraphFactory;
34  import y.base.Node;
35  import y.base.NodeMap;
36  import y.geom.YDimension;
37  import y.geom.YPoint;
38  import y.geom.YPointCursor;
39  import y.layout.EdgeLabelLayout;
40  import y.layout.LayoutGraph;
41  import y.layout.NodeLabelLayout;
42  import y.layout.multipage.EdgeInfo;
43  import y.layout.multipage.EdgeLabelInfo;
44  import y.layout.multipage.ElementInfoManager;
45  import y.layout.multipage.MultiPageLayout;
46  import y.layout.multipage.NodeInfo;
47  import y.layout.multipage.NodeLabelInfo;
48  import y.util.GraphCopier;
49  import y.util.Maps;
50  import y.view.EdgeLabel;
51  import y.view.EdgeRealizer;
52  import y.view.Graph2D;
53  import y.view.NodeLabel;
54  import y.view.NodeRealizer;
55  import y.view.ShapeNodeRealizer;
56  import y.view.hierarchy.DefaultHierarchyGraphFactory;
57  import y.view.hierarchy.HierarchyManager;
58  
59  import java.awt.Color;
60  import java.util.Map;
61  
62  /**
63   * Builds {@link Graph2D} page graphs from a {@link MultiPageLayout} instance.
64   *
65   * @see y.layout.multipage.MultiPageLayout
66   */
67  public class MultiPageGraph2DBuilder {
68    /**
69     * DataProvider-Key used to store the ids of the referencing node elements, see
70     * {@link y.layout.multipage.NodeInfo#getReferencingNode()}.
71     * The DataProvider is automatically added to the Graph2D page representation.
72     */
73    private static final Object REFERENCING_NODE_ID_DPKEY =
74            "demo.layout.multipage.MultiPageGraph2DBuilder.REFERENCING_NODE_ID_DPKEY";
75  
76    private static final Object NODE_INFO_DPKEY =
77            "demo.layout.multipage.MultiPageGraph2DBuilder.NODE_INFO_DPKEY";
78  
79  
80    private Graph2D model;
81    private MultiPageLayout layout;
82    private GraphCopier.CopyFactory copyFactory;
83  
84    /**
85     * Creates a new instance.
86     *
87     * @param model the underlying graph.
88     * @param layout the result of the page layout applied to the model.
89     */
90    public MultiPageGraph2DBuilder(Graph2D model, MultiPageLayout layout) {
91      this.model = model;
92      this.layout = layout;
93    }
94  
95    public void reset(Graph2D model, MultiPageLayout layout) {
96      this.model = model;
97      this.layout = layout;
98      this.copyFactory = null;
99    }
100 
101   /**
102    * Returns the copy factory that is used to create the Graph2D elements.
103    *
104    * @return the copy factory used to create the Graph2D elements.
105    */
106   private GraphCopier.CopyFactory getCopyFactory() {
107     return copyFactory;
108   }
109 
110   /**
111    * Returns the result of the page layout applied to the model.
112    *
113    * @return the page layout.
114    * @see #getModel()
115    */
116   public MultiPageLayout getLayout() {
117     return layout;
118   }
119 
120   /**
121    * Returns the underlying graph.
122    * 
123    * @return the underlying graph.
124    */
125   public Graph2D getModel() {
126     return model;
127   }
128 
129   /**
130    * Returns the ID of the specified node.
131    * 
132    * @param node the node whose ID is retrieved.
133    * @return the ID of the specified node or <code>null</code> if the node
134    * does not belong to a page graph created by
135    * <code>MultiPageGraph2DBuilder</code>.
136    */
137   public Object getNodeId( final Node node ) {
138     final Graph graph = node.getGraph();
139     if (graph != null) {
140       final DataProvider dp = graph.getDataProvider(NODE_INFO_DPKEY);
141       if (dp != null) {
142         final NodeInfo info = (NodeInfo) dp.get(node);
143         if (info != null) {
144           return info.getId();
145         }
146       }
147     }
148     return null;
149   }
150 
151   public byte getNodeType( final Node node ) {
152     final Graph graph = node.getGraph();
153     if (graph != null) {
154       final DataProvider dp = graph.getDataProvider(NODE_INFO_DPKEY);
155       if (dp != null) {
156         final NodeInfo info = (NodeInfo) dp.get(node);
157         if (info != null) {
158           return info.getType();
159         }
160       }
161     }
162     return -1;
163   }
164 
165   public int getPageNo( final Node node ) {
166     final Graph graph = node.getGraph();
167     if (graph != null) {
168       final DataProvider dp = graph.getDataProvider(NODE_INFO_DPKEY);
169       if (dp != null) {
170         final NodeInfo info = (NodeInfo) dp.get(node);
171         if (info != null) {
172           return info.getPageNo();
173         }
174       }
175     }
176     return -1;
177   }
178 
179   public int getReferencedPageNo( final Node node ) {
180     final Graph graph = node.getGraph();
181     if (graph != null) {
182       final DataProvider dp = graph.getDataProvider(NODE_INFO_DPKEY);
183       if (dp != null) {
184         final NodeInfo info = (NodeInfo) dp.get(node);
185         if (info != null) {
186           final Node mpRef = info.getReferencingNode();
187           if (mpRef != null) {
188             final NodeInfo mpRefInfo = layout.getNodeInfo(mpRef);
189             return mpRefInfo.getPageNo();
190           }
191         }
192       }
193     }
194     return -1;
195   }
196 
197   public Object getReferencingNodeId( final Node node ) {
198     final Graph graph = node.getGraph();
199     if (graph != null) {
200       final DataProvider dp = graph.getDataProvider(REFERENCING_NODE_ID_DPKEY);
201       if (dp != null) {
202         return dp.get(node);
203       }
204     }
205     return null;
206   }
207 
208   /**
209    * Creates a <code>Graph2D</code> representation for the specified page.
210    *
211    * @param page the <code>Graph2D</code> to store the specified page.
212    * @param pageNo the number of the page that should be transformed to a Graph2D
213    * @return a <code>Graph2D</code> that represents the specified page.
214    */
215   public Graph2D createPageView( final Graph2D page, final int pageNo ) {
216     copyFactory = page.getGraphCopyFactory();
217     final GraphCopier graphCopier = new GraphCopier(new MyGraphCopyFactory());
218     graphCopier.copy(getLayout().getPage(pageNo), page);
219     return page;
220   }
221 
222   /**
223    * Callback method for adding a connector node (a node of type {@link NodeInfo#TYPE_CONNECTOR})
224    * to the Graph2D (including the configuration of its realizer).
225    *
226    * @param sourceNode the source node (a node on a page of the MultiPageLayout) that should be replicated.
227    * @param targetGraph the new node should be added to this graph.
228    * @return the added connector node.
229    *
230    * @see NodeInfo#TYPE_CONNECTOR
231    * @see #getLayout()
232    */
233   protected Node createConnectorNode( final Node sourceNode, final Graph2D targetGraph ) {
234     final NodeInfo info = getLayout().getNodeInfo(sourceNode);
235     final Node connector = getCopyFactory().copyNode(targetGraph, sourceNode);
236     final YPoint center = targetGraph.getCenter(connector);
237     final YDimension size = targetGraph.getSize(connector);
238 
239     targetGraph.setRealizer(connector, new ShapeNodeRealizer(ShapeNodeRealizer.ROUND_RECT));
240     targetGraph.getRealizer(connector).setFillColor(Color.YELLOW);
241     final Object referencingNodeID = getLayout().getNodeInfo(info.getReferencingNode()).getId();
242     ((NodeMap) targetGraph.getDataProvider(REFERENCING_NODE_ID_DPKEY)).set(connector, referencingNodeID);
243     addLabels(sourceNode, targetGraph.getRealizer(connector), getLayout());
244     targetGraph.setSize(connector, size);
245     targetGraph.setCenter(connector, center);
246 
247     return connector;
248   }
249 
250   /**
251    * Callback method for adding a
252    * {@link NodeInfo#TYPE_PROXY_REFERENCE proxy reference} node
253    * to the graph (including the configuration of its realizer).
254    *
255    * @param sourceNode the source node (a node on a page of the MultiPageLayout) that should be replicated.
256    * @param targetGraph the new node should be added to this graph.
257    * @return the newly added proxy reference node.
258    *
259    * @see NodeInfo#TYPE_PROXY_REFERENCE
260    * @see NodeInfo#TYPE_PROXY
261    * @see #createProxyNode(y.base.Node, y.view.Graph2D)
262    * @see #getLayout()
263    */
264   protected Node createProxyReferenceNode( final Node sourceNode, final Graph2D targetGraph ) {
265     final NodeInfo info = getLayout().getNodeInfo(sourceNode);
266     final Node pageNode = getCopyFactory().copyNode(targetGraph, sourceNode);
267     final YPoint center = targetGraph.getCenter(pageNode);
268     final YDimension size = targetGraph.getSize(pageNode);
269 
270     final NodeInfo referencingNodeInfo = getLayout().getNodeInfo(
271         info.getReferencingNode());
272     targetGraph.setRealizer(pageNode, new ShapeNodeRealizer(ShapeNodeRealizer.ELLIPSE));
273     targetGraph.getRealizer(pageNode).setFillColor(Color.GREEN);
274     targetGraph.setLabelText(pageNode, "p " + (referencingNodeInfo.getPageNo() + 1)); 
275     final Object referencingNodeID = getLayout().getNodeInfo(info.getReferencingNode()).getId();
276     ((NodeMap) targetGraph.getDataProvider(REFERENCING_NODE_ID_DPKEY)).set(pageNode, referencingNodeID);
277     targetGraph.setSize(pageNode, size);
278     targetGraph.setCenter(pageNode, center);
279 
280     return pageNode;
281   }
282 
283   /**
284    * Callback method for adding a {@link NodeInfo#TYPE_PROXY proxy} node
285    * to the graph (including the configuration of its realizer).
286    *
287    * @param sourceNode the source node (a node on a page of the MultiPageLayout) that should be replicated.
288    * @param targetGraph the new node should be added to this graph.
289    * @return the newly added proxy node.
290    *
291    * @see NodeInfo#TYPE_PROXY
292    * @see NodeInfo#TYPE_PROXY_REFERENCE
293    * @see #createProxyReferenceNode(y.base.Node, y.view.Graph2D)
294    * @see #getLayout()
295    */
296   protected Node createProxyNode( final Node sourceNode, final Graph2D targetGraph ) {
297     final NodeInfo info = getLayout().getNodeInfo(sourceNode);
298     final Node proxy = getCopyFactory().copyNode(targetGraph, sourceNode);
299     final YPoint center = targetGraph.getCenter(proxy);
300     final YDimension size = targetGraph.getSize(proxy);
301 
302     targetGraph.setRealizer(proxy, new ShapeNodeRealizer(ShapeNodeRealizer.ROUND_RECT));
303     targetGraph.getRealizer(proxy).setFillColor(Color.LIGHT_GRAY);
304     final Object referencingNodeID = getLayout().getNodeInfo(info.getReferencingNode()).getId();
305     ((NodeMap) targetGraph.getDataProvider(REFERENCING_NODE_ID_DPKEY)).set(proxy, referencingNodeID);
306     addLabels(sourceNode, targetGraph.getRealizer(proxy), getLayout());
307     targetGraph.setSize(proxy, size);
308     targetGraph.setCenter(proxy, center);
309 
310     return proxy;
311   }
312 
313   /**
314    * Callback method for adding a group node to the Graph2D (including the configuration of its realizer).
315    *
316    * @param sourceNode the source node (a node on a page of the MultiPageLayout) that should be replicated.
317    * @param targetGraph the new node should be added to this graph.
318    * @return the added group node.
319    *
320    * @see NodeInfo#TYPE_GROUP
321    * @see #getLayout()
322    */
323   protected Node createGroupNode(final Node sourceNode, final Graph2D targetGraph) {
324     final NodeInfo info = getLayout().getNodeInfo(sourceNode);
325     final Node groupNode = getCopyFactory().copyNode(targetGraph, sourceNode);
326     final YPoint center = targetGraph.getCenter(groupNode);
327     final YDimension size = targetGraph.getSize(groupNode);
328 
329     final NodeInfo representingNodeInfo = getLayout().getNodeInfo(info.getRepresentedNode());
330     targetGraph.setRealizer(groupNode, getRealizer((Node) representingNodeInfo.getId()));
331     targetGraph.setSize(groupNode, size);
332     targetGraph.setCenter(groupNode, center);
333 
334     return groupNode;
335   }
336 
337   /**
338    * Callback method for adding a normal node (a node of type {@link NodeInfo#TYPE_NORMAL})
339    * to the Graph2D (including the configuration of its realizer).
340    *
341    * @param sourceNode the source node (a node on a page of the MultiPageLayout) that should be replicated.
342    * @param targetGraph the new node should be added to this graph.
343    * @return the added node.
344    *
345    * @see NodeInfo#TYPE_NORMAL
346    * @see #getLayout()
347    */
348   protected Node createNormalNode(final Node sourceNode, final Graph2D targetGraph) {
349     final NodeInfo info = getLayout().getNodeInfo(sourceNode);
350     final Node node = getCopyFactory().copyNode(targetGraph, sourceNode);
351     final YPoint center = targetGraph.getCenter(node);
352     final YDimension size = targetGraph.getSize(node);
353 
354     final NodeInfo representingNodeInfo = getLayout().getNodeInfo(info.getRepresentedNode());
355     targetGraph.setRealizer(node, getRealizer((Node) representingNodeInfo.getId()));
356     addLabels(sourceNode, targetGraph.getRealizer(node), getLayout());
357     targetGraph.setSize(node, size);
358     targetGraph.setCenter(node, center);
359 
360     return node;
361   }
362 
363   /**
364    * Callback method for adding a normal edge (an edge of type {@link y.layout.multipage.EdgeInfo#TYPE_NORMAL})
365    * to the Graph2D (including the configuration of its realizer).
366    *
367    * @param sourceEdge the source edge (an edge on a page of the MultiPageLayout) that should be replicated.
368    * @param newSource the source of the new edge.
369    * @param newTarget the target of the new edge.
370    * @param targetGraph the new edge should be added to this graph.
371    * @return the added edge.
372    *
373    * @see EdgeInfo#TYPE_NORMAL
374    * @see #getLayout()
375    */
376   protected Edge createNormalEdge(final Edge sourceEdge, final Node newSource, final Node newTarget,
377                                   final Graph2D targetGraph) {
378     final EdgeInfo edgeInfo = getLayout().getEdgeInfo(sourceEdge);
379     final Edge newEdge = getCopyFactory().copyEdge(targetGraph, newSource, newTarget, sourceEdge);
380 
381     final EdgeRealizer realizer = createCopyOfRealizer((Edge) edgeInfo.getId());
382     if (realizer != null) {
383       addLabels(sourceEdge, realizer, getLayout());
384       applyRealizer(newEdge, targetGraph, realizer);
385     }
386 
387     return newEdge;
388   }
389 
390   /**
391    * Callback method for adding a
392    * {@link EdgeInfo#TYPE_PROXY_REFERENCE proxy reference} edge
393    * to the graph (including the configuration of its realizer).
394    *
395    * @param sourceEdge the source edge (an edge on a page of the MultiPageLayout) that should be replicated.
396    * @param newSource the source of the new edge.
397    * @param newTarget the target of the new edge.
398    * @param targetGraph the new edge should be added to this graph.
399    * @return the newly added proxy reference edge.
400    *
401    * @see EdgeInfo#TYPE_PROXY_REFERENCE
402    * @see #getLayout()
403    */
404   protected Edge createProxyReferenceEdge( final Edge sourceEdge, final Node newSource, final Node newTarget,
405                                            final Graph2D targetGraph ) {
406     final EdgeInfo edgeInfo = getLayout().getEdgeInfo(sourceEdge);
407     final Edge newEdge = getCopyFactory().copyEdge(targetGraph, newSource, newTarget, sourceEdge);
408 
409     final EdgeRealizer realizer = createCopyOfRealizer((Edge) edgeInfo.getId());
410     if (realizer != null) {
411       addLabels(sourceEdge, realizer, getLayout());
412       applyRealizer(newEdge, targetGraph, realizer);
413     }
414 
415     return newEdge;
416   }
417 
418   /**
419    * Callback method for adding a {@link EdgeInfo#TYPE_CONNECTOR connector} edge
420    * to the graph (including the configuration of its realizer).
421    *
422    * @param sourceEdge the source edge (an edge on a page of the MultiPageLayout) that should be replicated.
423    * @param newSource the source of the new edge.
424    * @param newTarget the target of the new edge.
425    * @param targetGraph the new edge should be added to this graph.
426    * @return the newly added connector edge.
427    *
428    * @see EdgeInfo#TYPE_CONNECTOR
429    * @see #getLayout()
430    */
431   protected Edge createConnectorEdge(final Edge sourceEdge, final Node newSource, final Node newTarget,
432                                      final Graph2D targetGraph) {
433     final EdgeInfo edgeInfo = getLayout().getEdgeInfo(sourceEdge);
434     final Edge newEdge = getCopyFactory().copyEdge(targetGraph, newSource, newTarget, sourceEdge);
435 
436     final Object representingEdgeId = getLayout().getEdgeInfo(edgeInfo.getRepresentedEdge()).getId();
437     final Edge origEdge = (Edge) representingEdgeId;
438     final EdgeRealizer origRealizerCopy = createCopyOfRealizer(origEdge);
439     addLabels(sourceEdge, origRealizerCopy, getLayout());
440     applyRealizer(newEdge, targetGraph, origRealizerCopy);
441     return newEdge;
442   }
443 
444   /**
445    * Callback method for adding a {@link EdgeInfo#TYPE_PROXY proxy} edge
446    * to the graph (including the configuration of its realizer).
447    *
448    * @param sourceEdge the source edge (an edge on a page of the MultiPageLayout) that should be replicated.
449    * @param newSource the source of the new edge.
450    * @param newTarget the target of the new edge.
451    * @param targetGraph the new edge should be added to this graph.
452    * @return the newly added proxy edge.
453    *
454    * @see EdgeInfo#TYPE_PROXY
455    * @see #getLayout()
456    */
457   protected Edge createProxyEdge( final Edge sourceEdge, final Node newSource, final Node newTarget,
458                                   final Graph2D targetGraph ) {
459     final EdgeInfo edgeInfo = getLayout().getEdgeInfo(sourceEdge);
460     final Edge newEdge = getCopyFactory().copyEdge(targetGraph, newSource, newTarget, sourceEdge);
461 
462     final EdgeRealizer realizer = createCopyOfRealizer((Edge) edgeInfo.getId());
463     if (realizer != null) {
464       addLabels(sourceEdge, realizer, getLayout());
465       applyRealizer(newEdge, targetGraph, realizer);
466     }
467 
468     return newEdge;
469   }
470 
471   private static NodeRealizer getRealizer(final Node origNode) {
472     final Graph2D graph = (Graph2D) origNode.getGraph();
473     final NodeRealizer realizer = graph.getRealizer(origNode);
474     return realizer.createCopy();
475   }
476 
477   private static void addLabels(final Node source, final NodeRealizer targetRealizer, final ElementInfoManager infoManager) {
478     //remove existing labels
479     for (int i = targetRealizer.labelCount(); i --> 0;) {
480       targetRealizer.removeLabel(i);
481     }
482 
483     //add labels of source to target realizer
484     final LayoutGraph sourceGraph = (LayoutGraph) source.getGraph();
485     final NodeLabelLayout[] nll = sourceGraph.getNodeLabelLayout(source);
486     for (int i = 0; i < nll.length; i++) {
487       final NodeLabelInfo labelInfo = infoManager.getNodeLabelInfo(nll[i]);
488       final NodeLabel origLabel = (NodeLabel) labelInfo.getId();
489       final NodeLabel newLabel = (NodeLabel) origLabel.clone();
490       newLabel.setModelParameter(nll[i].getModelParameter());
491       targetRealizer.setLabel(newLabel);
492     }
493   }
494 
495   private static void applyRealizer(final Edge e, final Graph2D g, final EdgeRealizer realizer) {
496     if (realizer == null) {
497       return;
498     }
499 
500     realizer.clearPoints();
501     for (YPointCursor cur = g.getPoints(e).points(); cur.ok(); cur.next()) {
502       final YPoint p = cur.point();
503       realizer.addPoint(p.x, p.y);
504     }
505     realizer.setSourcePoint(g.getSourcePointRel(e));
506     realizer.setTargetPoint(g.getTargetPointRel(e));
507     g.setRealizer(e, realizer);
508   }
509 
510   private static EdgeRealizer createCopyOfRealizer(Edge e) {
511     if (e.getGraph() != null && e.getGraph() instanceof Graph2D) {
512       final Graph2D origGraph = (Graph2D) e.getGraph();
513       final EdgeRealizer realizer = origGraph.getRealizer(e);
514       return realizer.createCopy();
515     } else {
516       return null;
517     }
518   }
519 
520   private static void addLabels(final Edge source, final EdgeRealizer targetRealizer, final ElementInfoManager infoManager) {
521     //remove existing labels
522     while (targetRealizer.labelCount() > 0) {
523       targetRealizer.removeLabel(targetRealizer.getLabel());
524     }
525 
526     //add labels of source to target realizer
527     final LayoutGraph sourceGraph = (LayoutGraph) source.getGraph();
528     final EdgeLabelLayout[] ell = sourceGraph.getEdgeLabelLayout(source);
529     for (int i = 0; i < ell.length; i++) {
530       final EdgeLabelInfo labelInfo = infoManager.getEdgeLabelInfo(ell[i]);
531       final EdgeLabel origLabel = (EdgeLabel) labelInfo.getId();
532       final EdgeLabel newLabel = (EdgeLabel) origLabel.clone();
533       newLabel.setModelParameter(ell[i].getModelParameter());
534       targetRealizer.addLabel(newLabel);
535     }
536   }
537 
538   private class MyGraphCopyFactory implements GraphCopier.CopyFactory {
539     public Node copyNode(Graph targetGraph, Node originalNode) {
540       final NodeInfo info = getLayout().getNodeInfo(originalNode);
541       final Graph2D targetGraph2D = (Graph2D) targetGraph;
542 
543       Node graph2DNode;
544       if (info.getType() == NodeInfo.TYPE_NORMAL) {
545         graph2DNode = createNormalNode(originalNode, targetGraph2D);
546       } else if (info.getType() == NodeInfo.TYPE_GROUP) {
547         graph2DNode = createGroupNode(originalNode, targetGraph2D);
548       } else if (info.getType() == NodeInfo.TYPE_CONNECTOR) {
549         graph2DNode = createConnectorNode(originalNode, targetGraph2D);
550       } else if (info.getType() == NodeInfo.TYPE_PROXY) {
551         graph2DNode = createProxyNode(originalNode, targetGraph2D);
552       } else {
553         graph2DNode = createProxyReferenceNode(originalNode, targetGraph2D);
554       }
555       ((NodeMap) targetGraph.getDataProvider(NODE_INFO_DPKEY)).set(graph2DNode, info);
556 
557       return graph2DNode;
558     }
559 
560     public Edge copyEdge(Graph targetGraph, Node newSource, Node newTarget, Edge sourceEdge) {
561       final EdgeInfo edgeInfo = getLayout().getEdgeInfo(sourceEdge);
562       final Graph2D targetGraph2D = (Graph2D) targetGraph;
563 
564       Edge newEdge;
565       if (edgeInfo.getType() == EdgeInfo.TYPE_CONNECTOR) {
566         newEdge = createConnectorEdge(sourceEdge, newSource, newTarget, targetGraph2D);
567       } else  if (edgeInfo.getType() == EdgeInfo.TYPE_PROXY_REFERENCE) {
568         newEdge = createProxyReferenceEdge(sourceEdge, newSource, newTarget, targetGraph2D);
569       } else if (edgeInfo.getType() == EdgeInfo.TYPE_PROXY) {
570         newEdge = createProxyEdge(sourceEdge, newSource, newTarget, targetGraph2D);
571       } else {
572         newEdge = createNormalEdge(sourceEdge, newSource, newTarget, targetGraph2D);
573       }
574 
575       return newEdge;
576     }
577 
578     public Graph createGraph() {
579       final Graph2D graph = (Graph2D) getCopyFactory().createGraph();
580       if (graph.getHierarchyManager() == null) {
581         final HierarchyManager hm = new HierarchyManager(graph);
582         final GraphFactory baseFactory = getModel().getHierarchyManager().getGraphFactory();
583         if (baseFactory instanceof DefaultHierarchyGraphFactory) {
584           hm.setGraphFactory(baseFactory);
585         }
586       }
587 
588       return graph;
589     }
590 
591     public void preCopyGraphData(Graph sourceGraph, Graph targetGraph) {
592       targetGraph.addDataProvider(NODE_INFO_DPKEY, Maps.createHashedNodeMap());
593       targetGraph.addDataProvider(REFERENCING_NODE_ID_DPKEY, Maps.createHashedNodeMap());
594       getCopyFactory().preCopyGraphData(sourceGraph, targetGraph);
595     }
596 
597     public void postCopyGraphData(Graph sourceGraph, Graph targetGraph, Map nodeMap, Map edgeMap) {
598       getCopyFactory().postCopyGraphData(sourceGraph, targetGraph, nodeMap, edgeMap);
599     }
600   }
601 }
602