1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.7. 
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-2009 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  public class CircularLayoutModule extends LayoutModule {
33    private static final String CIRCULAR = "CIRCULAR";
34    private static final String ALLOW_OVERLAPS = "ALLOW_OVERLAPS";
35    private static final String COMPACTNESS_FACTOR = "COMPACTNESS_FACTOR";
36    private static final String MAXIMAL_DEVIATION_ANGLE = "MAXIMAL_DEVIATION_ANGLE";
37    private static final String MINIMAL_EDGE_LENGTH = "MINIMAL_EDGE_LENGTH";
38    private static final String PREFERRED_CHILD_WEDGE = "PREFERRED_CHILD_WEDGE";
39    private static final String TREE = "TREE";
40    private static final String FIXED_RADIUS = "FIXED_RADIUS";
41    private static final String CHOOSE_RADIUS_AUTOMATICALLY = "CHOOSE_RADIUS_AUTOMATICALLY";
42    private static final String MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
43    private static final String MINIMAL_TREE_NODE_DISTANCE = "MINIMAL_TREE_NODE_DISTANCE";
44    private static final String CYCLE = "CYCLE";
45    private static final String ACT_ON_SELECTION_ONLY = "ACT_ON_SELECTION_ONLY";
46    private static final String LAYOUT_STYLE = "LAYOUT_STYLE";
47    private static final String GENERAL = "GENERAL";
48    private static final String SINGLE_CYCLE = "SINGLE_CYCLE";
49    private static final String BCC_ISOLATED = "BCC_ISOLATED";
50    private static final String BCC_COMPACT = "BCC_COMPACT";
51    private static final String CIRCULAR_CUSTOM_GROUPS = "CIRCULAR_CUSTOM_GROUPS";
52    private static final String FROM_SKETCH = "FROM_SKETCH";  
53    private static final String HANDLE_NODE_LABELS = "HANDLE_NODE_LABELS";
54    private static final String PLACE_CHILDREN_ON_COMMON_RADIUS = "PLACE_CHILDREN_ON_COMMON_RADIUS";
55  
56    private final static String[] layoutStyles = {BCC_COMPACT, BCC_ISOLATED, CIRCULAR_CUSTOM_GROUPS, SINGLE_CYCLE};
57    private final static String PARTITION_LAYOUT_STYLE = "PARTITION_LAYOUT_STYLE";
58    private final static String PARTITION_LAYOUTSTYLE_CYCLIC = "PARTITION_LAYOUTSTYLE_CYCLIC";
59    private final static String PARTITION_LAYOUTSTYLE_DISK = "PARTITION_LAYOUTSTYLE_DISK";
60    private final static String PARTITION_LAYOUTSTYLE_ORGANIC = "PARTITION_LAYOUTSTYLE_ORGANIC";
61  
62    private final static String[] partitionLayoutStyles = {PARTITION_LAYOUTSTYLE_CYCLIC, PARTITION_LAYOUTSTYLE_DISK, PARTITION_LAYOUTSTYLE_ORGANIC};
63  
64    public CircularLayoutModule() {
65      super( CIRCULAR, "yFiles Layout Team",
66          "Circular Layout" );
67    }
68  
69    public OptionHandler createOptionHandler() {
70      CircularLayouter layouter = new CircularLayouter();
71      SingleCycleLayouter cycleLayouter = layouter.getSingleCycleLayouter();
72      BalloonLayouter treeLayouter = layouter.getBalloonLayouter();
73  
74  
75      OptionHandler op = new OptionHandler( getModuleName() );
76  
77      op.useSection( GENERAL );
78      op.addEnum( LAYOUT_STYLE, layoutStyles, layouter.getLayoutStyle() );
79      op.addBool( ACT_ON_SELECTION_ONLY, false );
80      op.addBool( FROM_SKETCH, false );
81      op.addBool(HANDLE_NODE_LABELS, false);
82  
83      op.useSection( CYCLE );
84      op.addEnum( PARTITION_LAYOUT_STYLE, partitionLayoutStyles, layouter.getPartitionLayoutStyle() );
85      OptionItem mndi = op.addInt( MINIMAL_NODE_DISTANCE, ( int ) cycleLayouter.getMinimalNodeDistance(), 0, 999 );
86      OptionItem crai = op.addBool( CHOOSE_RADIUS_AUTOMATICALLY, cycleLayouter.getAutomaticRadius() );
87      OptionItem fri = op.addInt( FIXED_RADIUS, ( int ) cycleLayouter.getFixedRadius(), 50, 800 );
88  
89      ConstraintManager cm = new ConstraintManager(op);
90      cm.setEnabledOnValueEquals(crai, Boolean.FALSE, fri );
91      cm.setEnabledOnValueEquals(crai, Boolean.TRUE, mndi );
92  
93      op.useSection( TREE );
94      op.addInt( PREFERRED_CHILD_WEDGE, treeLayouter.getPreferredChildWedge(), 1, 359 );
95      op.addInt( MINIMAL_EDGE_LENGTH, treeLayouter.getMinimalEdgeLength(), 5, 400 );
96      op.addInt( MAXIMAL_DEVIATION_ANGLE, layouter.getMaximalDeviationAngle(), 10, 360 );
97      op.addDouble( COMPACTNESS_FACTOR, treeLayouter.getCompactnessFactor(), 0.1, 0.9 );
98      op.addInt( MINIMAL_TREE_NODE_DISTANCE, treeLayouter.getMinimalNodeDistance(), 0, 100 );
99      op.addBool( ALLOW_OVERLAPS, treeLayouter.getAllowOverlaps() );
100     op.addBool(PLACE_CHILDREN_ON_COMMON_RADIUS, true );
101     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MINIMAL_TREE_NODE_DISTANCE), true);
102     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, PLACE_CHILDREN_ON_COMMON_RADIUS), true);
103     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, PREFERRED_CHILD_WEDGE), true);
104     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MINIMAL_EDGE_LENGTH), true);
105     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MAXIMAL_DEVIATION_ANGLE), true);
106     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, COMPACTNESS_FACTOR), true);
107     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, ALLOW_OVERLAPS), true);
108     return op;
109   }
110 
111 
112   public void mainrun() {
113     OptionHandler op = getOptionHandler();
114 
115     CircularLayouter layouter = new CircularLayouter();
116 
117     BalloonLayouter treeLayouter = layouter.getBalloonLayouter();
118 
119     if ( op.getString( LAYOUT_STYLE ).equals( BCC_COMPACT ) ) {
120       layouter.setLayoutStyle( CircularLayouter.BCC_COMPACT );
121     } else if ( op.getString( LAYOUT_STYLE ).equals( BCC_ISOLATED ) ) {
122       layouter.setLayoutStyle( CircularLayouter.BCC_ISOLATED );
123     } else if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
124       layouter.setLayoutStyle( CircularLayouter.CIRCULAR_CUSTOM_GROUPS );
125     } else {
126       layouter.setLayoutStyle( CircularLayouter.SINGLE_CYCLE );
127     }
128 
129     layouter.setSubgraphLayouterEnabled( op.getBool( ACT_ON_SELECTION_ONLY ) );
130     layouter.setMaximalDeviationAngle( op.getInt( MAXIMAL_DEVIATION_ANGLE ) );
131     layouter.setFromSketchModeEnabled( op.getBool( FROM_SKETCH));   
132     layouter.setPlaceChildrenOnCommonRadiusEnabled(op.getBool(PLACE_CHILDREN_ON_COMMON_RADIUS));
133     layouter.setConsiderNodeLabelsEnabled(op.getBool(HANDLE_NODE_LABELS));
134     
135     if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_CYCLIC ) ) {
136       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_CYCLIC );
137     } else if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_DISK ) ) {
138       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_DISK );
139     }
140     else if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_ORGANIC ) ) {
141       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_ORGANIC );
142     }
143 
144     SingleCycleLayouter cycleLayouter = layouter.getSingleCycleLayouter();
145     cycleLayouter.setMinimalNodeDistance( op.getInt( MINIMAL_NODE_DISTANCE ) );
146     cycleLayouter.setAutomaticRadius( op.getBool( CHOOSE_RADIUS_AUTOMATICALLY ) );
147     cycleLayouter.setFixedRadius( op.getInt( FIXED_RADIUS ) );
148 
149     treeLayouter.setPreferredChildWedge( op.getInt( PREFERRED_CHILD_WEDGE ) );
150     treeLayouter.setMinimalEdgeLength( op.getInt( MINIMAL_EDGE_LENGTH ) );
151     treeLayouter.setCompactnessFactor( op.getDouble( COMPACTNESS_FACTOR ) );
152     treeLayouter.setAllowOverlaps( op.getBool( ALLOW_OVERLAPS ) );
153     treeLayouter.setMinimalNodeDistance(op.getInt(MINIMAL_TREE_NODE_DISTANCE));
154 
155     Graph2D graph = getGraph2D();
156     if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
157       //Set up grouping key for custom layout style
158       //This acts as an adapter for grouping structure to circular grouping keys
159       if ( graph.getHierarchyManager() != null ) {
160         graph.addDataProvider( CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY,
161             graph.getHierarchyManager().getParentNodeIdDataProvider() );
162       }
163     }
164     try {
165       launchLayouter( layouter );
166     } finally {
167       // make sure the DataProviders will always be unregistered
168       if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
169         //Remove temporary set up data providers from graph
170         graph.removeDataProvider( CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY );
171       }
172     }
173   }
174 }