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.view.isometry;
29  
30  import y.base.Edge;
31  import y.base.EdgeCursor;
32  import y.base.Node;
33  import y.base.NodeCursor;
34  import y.layout.PreferredPlacementDescriptor;
35  import y.view.EdgeLabel;
36  import y.view.EdgeRealizer;
37  import y.view.GenericNodeRealizer;
38  import y.view.Graph2D;
39  import y.view.NodeLabel;
40  import y.view.NodeRealizer;
41  import y.view.ProxyShapeNodeRealizer;
42  import y.view.SimpleUserDataHandler;
43  import y.view.YLabel;
44  import y.view.hierarchy.GenericGroupNodeRealizer;
45  import y.view.hierarchy.GroupFeature;
46  import y.view.hierarchy.HierarchyManager;
47  import y.view.hierarchy.ProxyAutoBoundsNodeRealizer;
48  
49  import java.awt.geom.Rectangle2D;
50  import java.util.Map;
51  
52  /**
53   * A factory for isometric realizers.
54   */
55  class IsometryRealizerFactory {
56  
57    /** The name of the configuration of isometric nodes. */
58    private static final String CONFIGURATION_NODE = "com.yworks.isometry.node";
59  
60    /** The name of the configuration of isometric group nodes. */
61    private static final String CONFIGURATION_GROUP = "com.yworks.isometry.group";
62  
63    /** The name of the configuration of isometric edge labels. */
64    private static final String CONFIGURATION_EDGE_LABEL = "com.yworks.isometry.edge_label";
65  
66    /** The name of the configuration of isometric group node labels. */
67    private static final String CONFIGURATION_GROUP_LABEL = "com.yworks.isometry.group_label";
68  
69    public static void initializeConfigurations() {
70      final GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
71  
72      // Create and register a configuration for common nodes.
73      final Map nodeImplMap = factory.createDefaultConfigurationMap();
74      final IsometryNodePainter nodePainter = new IsometryNodePainter();
75      nodeImplMap.put(GenericNodeRealizer.Painter.class, nodePainter);
76      nodeImplMap.put(GenericNodeRealizer.ContainsTest.class, nodePainter);
77      nodeImplMap.put(
78          GenericNodeRealizer.UserDataHandler.class,
79          new SimpleUserDataHandler(SimpleUserDataHandler.EXCEPTION_ON_FAILURE));
80      factory.addConfiguration(CONFIGURATION_NODE, nodeImplMap);
81  
82      // Create and register a configuration for group and folder nodes.
83      final Map groupImplMap = factory.createDefaultConfigurationMap();
84      final IsometryGroupPainter groupPainter = new IsometryGroupPainter(nodePainter);
85      groupImplMap.put(GenericNodeRealizer.Painter.class, groupPainter);
86      groupImplMap.put(GenericNodeRealizer.ContainsTest.class, groupPainter);
87      groupImplMap.put(
88          GenericNodeRealizer.UserDataHandler.class,
89          new SimpleUserDataHandler(SimpleUserDataHandler.EXCEPTION_ON_FAILURE));
90      factory.addConfiguration(CONFIGURATION_GROUP, groupImplMap);
91  
92      // Create and register a configuration for edge labels.
93      final YLabel.Factory edgeLabelFactory = EdgeLabel.getFactory();
94      final Map edgeLabelImplMap = edgeLabelFactory.createDefaultConfigurationMap();
95      final EdgeLabelConfiguration configuration = new EdgeLabelConfiguration();
96      edgeLabelImplMap.put(YLabel.Painter.class, configuration);
97      edgeLabelImplMap.put(YLabel.Layout.class, configuration);
98      edgeLabelImplMap.put(YLabel.BoundsProvider.class, configuration);
99      edgeLabelImplMap.put(
100         YLabel.UserDataHandler.class,
101         new SimpleUserDataHandler(SimpleUserDataHandler.EXCEPTION_ON_FAILURE));
102     edgeLabelFactory.addConfiguration(CONFIGURATION_EDGE_LABEL, edgeLabelImplMap);
103 
104     // Create and register a configuration for node labels.
105     final YLabel.Factory nodeLabelFactory = NodeLabel.getFactory();
106     final Map nodeLabelImplMap = nodeLabelFactory.createDefaultConfigurationMap();
107     final GroupLabelConfiguration configuration1 = new GroupLabelConfiguration();
108     nodeLabelImplMap.put(YLabel.Painter.class, configuration1);
109     nodeLabelImplMap.put(YLabel.Layout.class, configuration1);
110     nodeLabelImplMap.put(YLabel.BoundsProvider.class, configuration1);
111     nodeLabelImplMap.put(
112         YLabel.UserDataHandler.class,
113         new SimpleUserDataHandler(SimpleUserDataHandler.EXCEPTION_ON_FAILURE));
114     nodeLabelFactory.addConfiguration(CONFIGURATION_GROUP_LABEL, nodeLabelImplMap);
115   }
116 
117   private IsometryRealizerFactory() {
118   }
119 
120   /**
121    * Applies isometric configurations for to all nodes and labels of the given graph and adds {@link IsometryData} as
122    * user data.
123    */
124   public static void applyIsometryRealizerDefaults(final Graph2D graph) {
125     final HierarchyManager hierarchyManager = graph.getHierarchyManager();
126 
127     // check all nodes and change the configuration/realizer if necessary
128     for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
129       final Node node = nc.node();
130       final NodeRealizer realizer = graph.getRealizer(node);
131       if (hierarchyManager == null || hierarchyManager.isNormalNode(node)) {
132         GenericNodeRealizer gnr;
133         if (realizer instanceof GenericNodeRealizer) {
134           gnr = (GenericNodeRealizer) realizer;
135         } else {
136           gnr = new GenericNodeRealizer(realizer);
137           graph.setRealizer(node, gnr);
138         }
139         if (gnr.getConfiguration() == null || !CONFIGURATION_NODE.equals(gnr.getConfiguration())) {
140           final IsometryData isometryData = new IsometryData(realizer.getWidth(), realizer.getHeight(), 30, true);
141           gnr.setUserData(isometryData);
142           final Rectangle2D.Double bounds = new Rectangle2D.Double(0, 0, -1, -1);
143           isometryData.calculateViewBounds(bounds);
144           gnr.setSize(bounds.getWidth(), bounds.getHeight());
145           gnr.setConfiguration(CONFIGURATION_NODE);
146         }
147       } else {
148         if (realizer instanceof ProxyShapeNodeRealizer) {
149           final ProxyShapeNodeRealizer proxy = (ProxyShapeNodeRealizer) realizer;
150           for (int i = 0; i < proxy.realizerCount(); i++) {
151             final NodeRealizer delegate = proxy.getRealizer(i);
152             GenericNodeRealizer gnr;
153             if (delegate instanceof GenericNodeRealizer) {
154               gnr = (GenericNodeRealizer) delegate;
155             } else {
156               gnr = new GenericGroupNodeRealizer(delegate);
157               proxy.setRealizer(i, gnr);
158               if (delegate.equals(proxy.getRealizerDelegate())) {
159                 proxy.setRealizerDelegate(gnr);
160               }
161             }
162             if (gnr.getConfiguration() == null || !CONFIGURATION_GROUP.equals(gnr.getConfiguration())) {
163               final IsometryData isometryData = new IsometryData(gnr.getWidth(), gnr.getHeight(), 0, true);
164               gnr.setUserData(isometryData);
165               final Rectangle2D.Double bounds = new Rectangle2D.Double(0, 0, -1, -1);
166               isometryData.calculateViewBounds(bounds);
167               gnr.setSize(bounds.getWidth(), bounds.getHeight());
168               gnr.setConfiguration(CONFIGURATION_GROUP);
169             }
170 
171             if (delegate instanceof GroupFeature) {
172               ((GenericGroupNodeRealizer) gnr).setGroupClosed(((GroupFeature) delegate).isGroupClosed());
173             }
174 
175             setNodeLabelConfiguration(gnr);
176           }
177         } else {
178           GenericNodeRealizer gnr;
179           if (realizer instanceof GenericNodeRealizer) {
180             gnr = (GenericNodeRealizer) realizer;
181           } else {
182             gnr = new GenericGroupNodeRealizer(realizer);
183             if (realizer instanceof GroupFeature) {
184               ((GenericGroupNodeRealizer) gnr).setGroupClosed(((GroupFeature) realizer).isGroupClosed());
185             }
186             graph.setRealizer(node, gnr);
187           }
188           if (gnr.getConfiguration() == null || !CONFIGURATION_GROUP.equals(gnr.getConfiguration())) {
189             final IsometryData isometryData = new IsometryData(gnr.getWidth(), gnr.getHeight(), 0, true);
190             gnr.setUserData(isometryData);
191             final Rectangle2D.Double bounds = new Rectangle2D.Double(0, 0, -1, -1);
192             isometryData.calculateViewBounds(bounds);
193             gnr.setSize(bounds.getWidth(), bounds.getHeight());
194             gnr.setConfiguration(CONFIGURATION_GROUP);
195           }
196 
197           setNodeLabelConfiguration(gnr);
198         }
199         if (hierarchyManager.isFolderNode(node)) {
200           applyIsometryRealizerDefaults((Graph2D) hierarchyManager.getInnerGraph(node));
201         }
202       }
203     }
204 
205     // check all edge labels and change the configuration if necessary
206     for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
207       final Edge edge = ec.edge();
208       final EdgeRealizer realizer = graph.getRealizer(edge);
209       for (int i = 0; i < realizer.labelCount(); i++) {
210         final EdgeLabel label = realizer.getLabel(i);
211         if (label.getConfiguration() == null
212             || !label.getConfiguration().equals(CONFIGURATION_EDGE_LABEL)) {
213           label.setRotationAngle(0);
214           label.setUserData(new IsometryData(label.getWidth(), label.getHeight(), label.getHeight(), isHorizontal(label)));
215           label.setConfiguration(CONFIGURATION_EDGE_LABEL);
216           final PreferredPlacementDescriptor descriptor = new PreferredPlacementDescriptor();
217           descriptor.setAngle(0);
218           descriptor.setAngleReference(PreferredPlacementDescriptor.ANGLE_IS_RELATIVE_TO_EDGE_FLOW);
219           descriptor.setSideReference(PreferredPlacementDescriptor.SIDE_IS_ABSOLUTE_WITH_RIGHT_IN_NORTH);
220           descriptor.setSideOfEdge(PreferredPlacementDescriptor.PLACE_LEFT_OF_EDGE);
221           label.setPreferredPlacementDescriptor(descriptor);
222         }
223       }
224     }
225   }
226 
227   /**
228    * Determines whether or not the given label is orientated horizontally.
229    */
230   private static boolean isHorizontal(final EdgeLabel label) {
231     return label.getOrientedBox().getUpY() == -1 || label.getOrientedBox().getUpY() == 1;
232   }
233 
234   /**
235    * Changes the configuration of the labels that belong to the given realizer.
236    */
237   private static void setNodeLabelConfiguration(final GenericNodeRealizer realizer) {
238     for (int j = 0; j < realizer.labelCount(); j++) {
239       final NodeLabel label = realizer.getLabel(j);
240       if (label.getConfiguration() == null
241           || !label.getConfiguration().equals(CONFIGURATION_GROUP_LABEL)) {
242         label.setUserData(new IsometryData(label.getWidth(), label.getHeight(), 0, true));
243         label.setConfiguration(CONFIGURATION_GROUP_LABEL);
244       }
245     }
246   }
247 
248   /**
249    * Returns the isometry data of the given realizer. For {@link y.view.hierarchy.ProxyAutoBoundsNodeRealizer} the user
250    * data of the delegate is returned.
251    */
252   public static IsometryData getIsometryData(final NodeRealizer realizer) {
253     NodeRealizer nr = realizer;
254     if (realizer instanceof ProxyAutoBoundsNodeRealizer) {
255       ProxyAutoBoundsNodeRealizer proxy = (ProxyAutoBoundsNodeRealizer) realizer;
256       nr = proxy.getRealizerDelegate();
257     }
258 
259     if (nr instanceof GenericNodeRealizer) {
260       return (IsometryData) ((GenericNodeRealizer) nr).getUserData();
261     }
262 
263     return null;
264   }
265 }
266