1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.6. 
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-2008 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.module;
15  
16  import y.layout.circular.CircularLayouter;
17  import y.layout.circular.SingleCycleLayouter;
18  import y.layout.grouping.GroupingKeys;
19  import y.layout.tree.BalloonLayouter;
20  import y.option.OptionHandler;
21  import y.option.ConstraintManager;
22  import y.option.OptionItem;
23  import y.view.Graph2D;
24  import y.view.hierarchy.GroupLayoutConfigurator;
25  import y.module.LayoutModule;
26  
27  /**
28   * This module represents an interactive configurator and launcher for
29   * {@link y.layout.circular.CircularLayouter}.
30   * It is similar to CircularLayoutModule found in the yFiles package y.module.
31   *
32   */
33  public class CircularLayoutModule extends LayoutModule {
34    private static final String CIRCULAR = "CIRCULAR";
35    private static final String ALLOW_OVERLAPS = "ALLOW_OVERLAPS";
36    private static final String COMPACTNESS_FACTOR = "COMPACTNESS_FACTOR";
37    private static final String MAXIMAL_DEVIATION_ANGLE = "MAXIMAL_DEVIATION_ANGLE";
38    private static final String MINIMAL_EDGE_LENGTH = "MINIMAL_EDGE_LENGTH";
39    private static final String PREFERRED_CHILD_WEDGE = "PREFERRED_CHILD_WEDGE";
40    private static final String TREE = "TREE";
41    private static final String FIXED_RADIUS = "FIXED_RADIUS";
42    private static final String CHOOSE_RADIUS_AUTOMATICALLY = "CHOOSE_RADIUS_AUTOMATICALLY";
43    private static final String MINIMAL_NODE_DISTANCE = "MINIMAL_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  
54    private final static String layoutStyles[] = {BCC_COMPACT, BCC_ISOLATED, CIRCULAR_CUSTOM_GROUPS, SINGLE_CYCLE};
55    private final static String PARTITION_LAYOUT_STYLE = "PARTITION_LAYOUT_STYLE";
56    private final static String PARTITION_LAYOUTSTYLE_CYCLIC = "PARTITION_LAYOUTSTYLE_CYCLIC";
57    private final static String PARTITION_LAYOUTSTYLE_DISK = "PARTITION_LAYOUTSTYLE_DISK";
58    private final static String PARTITION_LAYOUTSTYLE_ORGANIC = "PARTITION_LAYOUTSTYLE_ORGANIC";
59  
60    private final static String partitionLayoutStyles[] = {PARTITION_LAYOUTSTYLE_CYCLIC, PARTITION_LAYOUTSTYLE_DISK, PARTITION_LAYOUTSTYLE_ORGANIC};
61  
62    public CircularLayoutModule() {
63      super( CIRCULAR, "yFiles Layout Team",
64          "Circular Layout" );
65    }
66  
67    public OptionHandler createOptionHandler() {
68      CircularLayouter layouter = new CircularLayouter();
69      SingleCycleLayouter cycleLayouter = layouter.getSingleCycleLayouter();
70      BalloonLayouter treeLayouter = layouter.getBalloonLayouter();
71  
72  
73      OptionHandler op = new OptionHandler( getModuleName() );
74  
75      op.useSection( GENERAL );
76      op.addEnum( LAYOUT_STYLE, layoutStyles, layouter.getLayoutStyle() );
77      op.addBool( ACT_ON_SELECTION_ONLY, false );
78      op.addBool( FROM_SKETCH, false );
79  
80      op.useSection( CYCLE );
81      op.addEnum( PARTITION_LAYOUT_STYLE, partitionLayoutStyles, layouter.getPartitionLayoutStyle() );
82      OptionItem mndi = op.addInt( MINIMAL_NODE_DISTANCE, ( int ) cycleLayouter.getMinimalNodeDistance(), 0, 999 );
83      OptionItem crai = op.addBool( CHOOSE_RADIUS_AUTOMATICALLY, cycleLayouter.getAutomaticRadius() );
84      OptionItem fri = op.addInt( FIXED_RADIUS, ( int ) cycleLayouter.getFixedRadius(), 50, 800 );
85  
86      ConstraintManager cm = new ConstraintManager(op);
87      cm.setEnabledOnValueEquals(crai, Boolean.FALSE, fri );
88      cm.setEnabledOnValueEquals(crai, Boolean.TRUE, mndi );
89  
90      op.useSection( TREE );
91      op.addInt( PREFERRED_CHILD_WEDGE, treeLayouter.getPreferredChildWedge(), 1, 359 );
92      op.addInt( MINIMAL_EDGE_LENGTH, treeLayouter.getMinimalEdgeLength(), 5, 400 );
93      op.addInt( MAXIMAL_DEVIATION_ANGLE, layouter.getMaximalDeviationAngle(), 10, 360 );
94      op.addDouble( COMPACTNESS_FACTOR, treeLayouter.getCompactnessFactor(), 0.1, 0.9 );
95      op.addBool( ALLOW_OVERLAPS, treeLayouter.getAllowOverlaps() );
96      cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, PREFERRED_CHILD_WEDGE), true);
97      cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MINIMAL_EDGE_LENGTH), true);
98      cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, MAXIMAL_DEVIATION_ANGLE), true);
99      cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, COMPACTNESS_FACTOR), true);
100     cm.setEnabledOnValueEquals( op.getItem( GENERAL, LAYOUT_STYLE), SINGLE_CYCLE, op.getItem( TREE, ALLOW_OVERLAPS), true);
101     return op;
102   }
103 
104 
105   public void mainrun() {
106     OptionHandler op = getOptionHandler();
107 
108     CircularLayouter layouter = new CircularLayouter();
109 
110     BalloonLayouter treeLayouter = layouter.getBalloonLayouter();
111 
112     if ( op.getString( LAYOUT_STYLE ).equals( BCC_COMPACT ) ) {
113       layouter.setLayoutStyle( CircularLayouter.BCC_COMPACT );
114     } else if ( op.getString( LAYOUT_STYLE ).equals( BCC_ISOLATED ) ) {
115       layouter.setLayoutStyle( CircularLayouter.BCC_ISOLATED );
116     } else if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
117       layouter.setLayoutStyle( CircularLayouter.CIRCULAR_CUSTOM_GROUPS );
118     } else {
119       layouter.setLayoutStyle( CircularLayouter.SINGLE_CYCLE );
120     }
121 
122     layouter.setSubgraphLayouterEnabled( op.getBool( ACT_ON_SELECTION_ONLY ) );
123     layouter.setMaximalDeviationAngle( op.getInt( MAXIMAL_DEVIATION_ANGLE ) );
124     layouter.setFromSketchModeEnabled( op.getBool( FROM_SKETCH));
125 
126 
127     if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_CYCLIC ) ) {
128       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_CYCLIC );
129     } else if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_DISK ) ) {
130       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_DISK );
131     }
132     else if ( op.getString( PARTITION_LAYOUT_STYLE ).equals( PARTITION_LAYOUTSTYLE_ORGANIC ) ) {
133       layouter.setPartitionLayoutStyle( CircularLayouter.PARTITION_LAYOUTSTYLE_ORGANIC );
134     }
135 
136     SingleCycleLayouter cycleLayouter = layouter.getSingleCycleLayouter();
137     cycleLayouter.setMinimalNodeDistance( op.getInt( MINIMAL_NODE_DISTANCE ) );
138     cycleLayouter.setAutomaticRadius( op.getBool( CHOOSE_RADIUS_AUTOMATICALLY ) );
139     cycleLayouter.setFixedRadius( op.getInt( FIXED_RADIUS ) );
140 
141     treeLayouter.setPreferredChildWedge( op.getInt( PREFERRED_CHILD_WEDGE ) );
142     treeLayouter.setMinimalEdgeLength( op.getInt( MINIMAL_EDGE_LENGTH ) );
143     treeLayouter.setCompactnessFactor( op.getDouble( COMPACTNESS_FACTOR ) );
144     treeLayouter.setAllowOverlaps( op.getBool( ALLOW_OVERLAPS ) );
145 
146     // initialize potential grouping information
147     GroupLayoutConfigurator glc = new GroupLayoutConfigurator( getGraph2D() );
148     Graph2D graph = getGraph2D();
149     try {
150       // register grouping relevant DataProviders
151       glc.prepareAll();
152 
153       if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
154         //Set up grouping key for custom layout style
155         //This acts as an adapter for grouping structure to circular grouping keys
156         graph.addDataProvider( CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY,
157             graph.getDataProvider( GroupingKeys.PARENT_NODE_ID_DPKEY ) );
158       }
159 
160       launchLayouter( layouter );
161     } finally {
162       // make sure the DataProviders will always be unregistered
163       if ( op.getString( LAYOUT_STYLE ).equals( CIRCULAR_CUSTOM_GROUPS ) ) {
164         //Remove temporary set up data providers from graph
165         graph.removeDataProvider( CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY );
166       }
167       glc.restoreAll();
168     }
169   }
170 }
171