1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2011 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.layout.module;
15  
16  import y.module.LayoutModule;
17  import y.module.YModule;
18  
19  import y.layout.circular.CircularLayouter;
20  import y.layout.circular.SingleCycleLayouter;
21  import y.layout.tree.BalloonLayouter;
22  import y.option.OptionHandler;
23  import y.option.ConstraintManager;
24  import y.option.OptionItem;
25  import y.view.Graph2D;
26  
27  /**
28   * This module represents an interactive configurator and launcher for
29   * {@link y.layout.circular.CircularLayouter}.
30   * 
31   *
32   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/circular_layouter.html#circular_layouter">Section Circular Layout</a> in the yFiles for Java Developer's Guide
33   */
34  public class CircularLayoutModule extends LayoutModule {
35    private static final String CIRCULAR = "CIRCULAR";
36    private static final String ALLOW_OVERLAPS = "ALLOW_OVERLAPS";
37    private static final String COMPACTNESS_FACTOR = "COMPACTNESS_FACTOR";
38    private static final String MAXIMAL_DEVIATION_ANGLE = "MAXIMAL_DEVIATION_ANGLE";
39    private static final String MINIMAL_EDGE_LENGTH = "MINIMAL_EDGE_LENGTH";
40    private static final String PREFERRED_CHILD_WEDGE = "PREFERRED_CHILD_WEDGE";
41    private static final String TREE = "TREE";
42    private static final String FIXED_RADIUS = "FIXED_RADIUS";
43    private static final String CHOOSE_RADIUS_AUTOMATICALLY = "CHOOSE_RADIUS_AUTOMATICALLY";
44    private static final String MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
45    private static final String MINIMAL_TREE_NODE_DISTANCE = "MINIMAL_TREE_NODE_DISTANCE";
46    private static final String CYCLE = "CYCLE";
47    private static final String ACT_ON_SELECTION_ONLY = "ACT_ON_SELECTION_ONLY";
48    private static final String LAYOUT_STYLE = "LAYOUT_STYLE";
49    private static final String GENERAL = "GENERAL";
50    private static final String SINGLE_CYCLE = "SINGLE_CYCLE";
51    private static final String BCC_ISOLATED = "BCC_ISOLATED";
52    private static final String BCC_COMPACT = "BCC_COMPACT";
53    private static final String CIRCULAR_CUSTOM_GROUPS = "CIRCULAR_CUSTOM_GROUPS";
54    private static final String FROM_SKETCH = "FROM_SKETCH";  
55    private static final String HANDLE_NODE_LABELS = "HANDLE_NODE_LABELS";
56    private static final String PLACE_CHILDREN_ON_COMMON_RADIUS = "PLACE_CHILDREN_ON_COMMON_RADIUS";
57  
58    private final static String[] layoutStyles = {BCC_COMPACT, BCC_ISOLATED, CIRCULAR_CUSTOM_GROUPS, SINGLE_CYCLE};
59    private final static String PARTITION_LAYOUT_STYLE = "PARTITION_LAYOUT_STYLE";
60    private final static String PARTITION_LAYOUTSTYLE_CYCLIC = "PARTITION_LAYOUTSTYLE_CYCLIC";
61    private final static String PARTITION_LAYOUTSTYLE_DISK = "PARTITION_LAYOUTSTYLE_DISK";
62    private final static String PARTITION_LAYOUTSTYLE_ORGANIC = "PARTITION_LAYOUTSTYLE_ORGANIC";
63  
64    private final static String[] partitionLayoutStyles = {PARTITION_LAYOUTSTYLE_CYCLIC, PARTITION_LAYOUTSTYLE_DISK, PARTITION_LAYOUTSTYLE_ORGANIC};
65  
66    public CircularLayoutModule() {
67      super( CIRCULAR, "yFiles Layout Team",
68          "Circular Layout" );
69    }
70  
71    public OptionHandler createOptionHandler() {
72      CircularLayouter layouter = new CircularLayouter();
73      SingleCycleLayouter cycleLayouter = layouter.getSingleCycleLayouter();
74      BalloonLayouter treeLayouter = layouter.getBalloonLayouter();
75  
76  
77      OptionHandler op = new OptionHandler( getModuleName() );
78  
79      op.useSection( GENERAL );
80      op.addEnum( LAYOUT_STYLE, layoutStyles, layouter.getLayoutStyle() );
81      op.addBool( ACT_ON_SELECTION_ONLY, false );
82      op.addBool( FROM_SKETCH, false );
83      op.addBool(HANDLE_NODE_LABELS, false);
84  
85      op.useSection( CYCLE );
86      op.addEnum( PARTITION_LAYOUT_STYLE, partitionLayoutStyles, layouter.getPartitionLayoutStyle() );
87      OptionItem mndi = op.addInt( MINIMAL_NODE_DISTANCE, ( int ) cycleLayouter.getMinimalNodeDistance(), 0, 999 );
88      OptionItem crai = op.addBool( CHOOSE_RADIUS_AUTOMATICALLY, cycleLayouter.getAutomaticRadius() );
89      OptionItem fri = op.addInt( FIXED_RADIUS, ( int ) cycleLayouter.getFixedRadius(), 50, 800 );
90  
91      ConstraintManager cm = new ConstraintManager(op);
92      cm.setEnabledOnValueEquals(crai, Boolean.FALSE, fri );
93      cm.setEnabledOnValueEquals(crai, Boolean.TRUE, mndi );
94  
95      op.useSection( TREE );
96      op.addInt( PREFERRED_CHILD_WEDGE, treeLayouter.getPreferredChildWedge(), 1, 359 );
97      op.addInt( MINIMAL_EDGE_LENGTH, treeLayouter.getMinimalEdgeLength(), 5, 400 );
98      op.addInt( MAXIMAL_DEVIATION_ANGLE, layouter.getMaximalDeviationAngle(), 10, 360 );
99      op.addDouble( COMPACTNESS_FACTOR, treeLayouter.getCompactnessFactor(), 0.1, 0.9 );
100     op.addInt( MINIMAL_TREE_NODE_DISTANCE, treeLayouter.getMinimalNodeDistance(), 0, 100 );
101     op.addBool( ALLOW_OVERLAPS, treeLayouter.getAllowOverlaps() );
102     op.addBool(PLACE_CHILDREN_ON_COMMON_RADIUS, true );
103     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MINIMAL_TREE_NODE_DISTANCE), true);
104     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, PLACE_CHILDREN_ON_COMMON_RADIUS), true);
105     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, PREFERRED_CHILD_WEDGE), true);
106     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MINIMAL_EDGE_LENGTH), true);
107     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MAXIMAL_DEVIATION_ANGLE), true);
108     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, COMPACTNESS_FACTOR), true);
109     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, ALLOW_OVERLAPS), true);
110     return op;
111   }
112 
113 
114   public void mainrun() {
115     OptionHandler op = getOptionHandler();
116 
117     CircularLayouter layouter = new CircularLayouter();
118 
119     BalloonLayouter treeLayouter = layouter.getBalloonLayouter();
120 
121     if ( op.getString( LAYOUT_STYLE ).equals( BCC_COMPACT ) ) {
122       layouter.setLayoutStyle( CircularLayouter.BCC_COMPACT );
123     } else if ( op.getString( LAYOUT_STYLE ).equals( BCC_ISOLATED ) ) {
124       layouter.setLayoutStyle( CircularLayouter.BCC_ISOLATED );
125     } else if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
126       layouter.setLayoutStyle( CircularLayouter.CIRCULAR_CUSTOM_GROUPS );
127     } else {
128       layouter.setLayoutStyle( CircularLayouter.SINGLE_CYCLE );
129     }
130 
131     layouter.setSubgraphLayouterEnabled( op.getBool( ACT_ON_SELECTION_ONLY ) );
132     layouter.setMaximalDeviationAngle( op.getInt( MAXIMAL_DEVIATION_ANGLE ) );
133     layouter.setFromSketchModeEnabled( op.getBool( FROM_SKETCH));   
134     layouter.setPlaceChildrenOnCommonRadiusEnabled(op.getBool(PLACE_CHILDREN_ON_COMMON_RADIUS));
135     layouter.setConsiderNodeLabelsEnabled(op.getBool(HANDLE_NODE_LABELS));
136     
137     if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_CYCLIC ) ) {
138       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_CYCLIC );
139     } else if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_DISK ) ) {
140       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_DISK );
141     }
142     else if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_ORGANIC ) ) {
143       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_ORGANIC );
144     }
145 
146     SingleCycleLayouter cycleLayouter = layouter.getSingleCycleLayouter();
147     cycleLayouter.setMinimalNodeDistance( op.getInt( MINIMAL_NODE_DISTANCE ) );
148     cycleLayouter.setAutomaticRadius( op.getBool( CHOOSE_RADIUS_AUTOMATICALLY ) );
149     cycleLayouter.setFixedRadius( op.getInt( FIXED_RADIUS ) );
150 
151     treeLayouter.setPreferredChildWedge( op.getInt( PREFERRED_CHILD_WEDGE ) );
152     treeLayouter.setMinimalEdgeLength( op.getInt( MINIMAL_EDGE_LENGTH ) );
153     treeLayouter.setCompactnessFactor( op.getDouble( COMPACTNESS_FACTOR ) );
154     treeLayouter.setAllowOverlaps( op.getBool( ALLOW_OVERLAPS ) );
155     treeLayouter.setMinimalNodeDistance(op.getInt(MINIMAL_TREE_NODE_DISTANCE));
156 
157     Graph2D graph = getGraph2D();
158     if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
159       //Set up grouping key for custom layout style
160       //This acts as an adapter for grouping structure to circular grouping keys
161       if ( graph.getHierarchyManager() != null ) {
162         graph.addDataProvider( CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY,
163             graph.getHierarchyManager().getParentNodeIdDataProvider() );
164       }
165     }
166     try {
167       launchLayouter( layouter );
168     } finally {
169       // make sure the DataProviders will always be unregistered
170       if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
171         //Remove temporary set up data providers from graph
172         graph.removeDataProvider( CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY );
173       }
174     }
175   }
176 }