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.module;
29  
30  import y.module.LayoutModule;
31  import y.module.YModule;
32  
33  import y.layout.ComponentLayouter;
34  import y.layout.organic.OrganicLayouter;
35  import y.option.OptionHandler;
36  import y.view.Graph2D;
37  import y.view.Selections;
38  import y.view.hierarchy.HierarchyManager;
39  
40  /**
41   * This module represents an interactive configurator and launcher for
42   * {@link y.layout.organic.OrganicLayouter}.
43   *
44   */
45  public class OrganicLayoutModule extends LayoutModule {
46    //// Module 'Smart Organic Module'
47    protected static final String MODULE_ORGANIC = "ORGANIC";
48    
49    //// Section 'Visual'
50    protected static final String SECTION_VISUAL = "VISUAL";
51    // Section 'Visual' items
52    protected static final String ITEM_SPHERE_OF_ACTION = "SPHERE_OF_ACTION";
53    protected static final String VALUE_ALL = "ALL";
54    protected static final String VALUE_MAINLY_SELECTION = "MAINLY_SELECTION";
55    protected static final String VALUE_ONLY_SELECTION = "ONLY_SELECTION";
56    protected static final String ITEM_INITIAL_PLACEMENT = "INITIAL_PLACEMENT";
57    protected static final String VALUE_RANDOM = "RANDOM";
58    protected static final String VALUE_AT_ORIGIN = "AT_ORIGIN";
59    protected static final String VALUE_AS_IS = "AS_IS";
60    protected static final String ITEM_PREFERRED_EDGE_LENGTH = "PREFERRED_EDGE_LENGTH";
61    protected static final String ITEM_OBEY_NODE_SIZES = "OBEY_NODE_SIZES";
62    protected static final String ITEM_ATTRACTION = "ATTRACTION";
63    protected static final String ITEM_REPULSION = "REPULSION";
64    protected static final String ITEM_GRAVITY_FACTOR = "GRAVITY_FACTOR";
65    protected static final String ITEM_ACTIVATE_TREE_BEAUTIFIER = "ACTIVATE_TREE_BEAUTIFIER";
66    
67    //// Section 'Algorithm'
68    protected static final String SECTION_ALGORITHM = "ALGORITHM";
69    // Section 'Algorithm' items
70    protected static final String ITEM_ITERATION_FACTOR = "ITERATION_FACTOR";
71    protected static final String ITEM_MAXIMAL_DURATION = "MAXIMAL_DURATION";
72    protected static final String ITEM_ACTIVATE_DETERMINISTIC_MODE = "ACTIVATE_DETERMINISTIC_MODE";
73    protected static final String ITEM_ALLOW_MULTI_THREADING = "ALLOW_MULTI_THREADING";
74    
75    //// Section 'Grouping'
76    protected static final String SECTION_GROUPING = "GROUPING";
77    // Section 'Grouping' items
78    protected static final String ITEM_GROUP_LAYOUT_POLICY = "GROUP_LAYOUT_POLICY";
79    protected static final String VALUE_LAYOUT_GROUPS = "LAYOUT_GROUPS";
80    protected static final String VALUE_FIX_GROUPS = "FIX_GROUPS";
81    protected static final String VALUE_IGNORE_GROUPS = "IGNORE_GROUPS";
82    protected static final String ITEM_GROUP_NODE_COMPACTNESS = "GROUP_NODE_COMPACTNESS";
83  
84    /**
85     * Creates an instance of this module.
86     */
87    public OrganicLayoutModule() {
88      super(MODULE_ORGANIC, "yFiles Layout Team", "Wrapper for OrganicLayouter");
89    }
90  
91    /**
92     * Creates an OptionHandler and adds the option items used by this module.
93     * @return the created <code>OptionHandler</code> providing module related options
94     */
95    protected OptionHandler createOptionHandler() {
96      final OptionHandler options = new OptionHandler(getModuleName());
97      // Defaults provider
98      final OrganicLayouter defaults = new OrganicLayouter();
99  
100     //// Section 'Visual'
101     options.useSection(SECTION_VISUAL);
102     // Populate section
103     options.addEnum(ITEM_SPHERE_OF_ACTION, new String[]{
104         VALUE_ALL,
105         VALUE_MAINLY_SELECTION,
106         VALUE_ONLY_SELECTION
107     }, defaults.getSphereOfAction());
108     options.addEnum(ITEM_INITIAL_PLACEMENT, new String[]{
109         VALUE_RANDOM,
110         VALUE_AT_ORIGIN,
111         VALUE_AS_IS
112     }, defaults.getInitialPlacement());
113     options.addInt(ITEM_PREFERRED_EDGE_LENGTH, (int) defaults.getPreferredEdgeLength(), 0, 500);
114     options.addBool(ITEM_OBEY_NODE_SIZES, defaults.getObeyNodeSize());
115     options.addInt(ITEM_ATTRACTION, defaults.getAttraction(), 0, 2);
116     options.addInt(ITEM_REPULSION, defaults.getRepulsion(), 0, 2);
117     options.addDouble(ITEM_GRAVITY_FACTOR, defaults.getGravityFactor(), -0.2, 2, 1);
118     options.addBool(ITEM_ACTIVATE_TREE_BEAUTIFIER, defaults.getActivateTreeBeautifier());
119     
120     //// Section 'Algorithm'
121     options.useSection(SECTION_ALGORITHM);
122     // Populate section
123     options.addDouble(ITEM_ITERATION_FACTOR, defaults.getIterationFactor());
124     options.addInt(ITEM_MAXIMAL_DURATION, (int) (defaults.getMaximumDuration() / 1000));
125     options.addBool(ITEM_ACTIVATE_DETERMINISTIC_MODE, defaults.getActivateDeterministicMode());
126     options.addBool(ITEM_ALLOW_MULTI_THREADING, true);
127     
128     //// Section 'Grouping'
129     options.useSection(SECTION_GROUPING);
130     // Populate section
131     options.addEnum(ITEM_GROUP_LAYOUT_POLICY, new String[]{
132         VALUE_LAYOUT_GROUPS,
133         VALUE_FIX_GROUPS,
134         VALUE_IGNORE_GROUPS
135     }, 0);
136     options.addDouble(ITEM_GROUP_NODE_COMPACTNESS, defaults.getGroupNodeCompactness(), 0, 1);
137     
138     return options;
139   }
140 
141   /**
142    * Main module execution routine.
143    * Launches the module's underlying algorithm on the module's graph based on user options.
144    */
145   protected void mainrun() {
146     final OrganicLayouter organic = new OrganicLayouter();
147 
148     final OptionHandler options = getOptionHandler();
149     configure(organic, options);
150 
151     final Graph2D graph = getGraph2D();
152     prepareGraph(graph, options);
153     try{
154       launchLayouter(organic);
155     } finally {
156       restoreGraph(graph, options);
157     }
158   }
159 
160   /**
161    * Prepares a <code>graph</code> depending on the given options for the
162    * module's layout algorithm.
163    * <br>
164    * Additional resources created by this method have to be freed up by calling
165    * {@link #restoreGraph(y.view.Graph2D, y.option.OptionHandler)} after
166    * layout calculation.  
167    * @param graph the graph to be prepared
168    * @param options the options for the module's layout algorithm
169    */
170   protected void prepareGraph(final Graph2D graph, final OptionHandler options) {
171     // backup existing data providers to prevent loss of user settings
172     backupDataProvider(graph, OrganicLayouter.SPHERE_OF_ACTION_NODES);
173     graph.addDataProvider(OrganicLayouter.SPHERE_OF_ACTION_NODES, Selections.createSelectionNodeMap(graph));
174   }
175 
176   /**
177    * Restores the given <code>graph</code> by freeing up resources created by
178    * {@link #prepareGraph(y.view.Graph2D, y.option.OptionHandler)}.
179    * @param graph the graph for which <code>prepareGraph</code> has been called
180    * @param options the options for the module's layout algorithm
181    */
182   protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
183     // remove the data providers set by this module by restoring the initial state
184     restoreDataProvider(graph, OrganicLayouter.SPHERE_OF_ACTION_NODES);
185   }
186 
187   /**
188    * Configures the module's layout algorithm according to the given options.
189    * <p>
190    * Important: This method does also depend on the <code>Graph2D</code>
191    * of this module in addition to the method's parameters.
192    * </p>
193    * @param organic the <code>OrganicLayouter</code> to be configured
194    * @param options the layout options to set
195    */
196   protected void configure(final OrganicLayouter organic, final OptionHandler options) {
197     organic.setPreferredEdgeLength(options.getInt(SECTION_VISUAL, ITEM_PREFERRED_EDGE_LENGTH));
198     organic.setMaximumDuration(1000 * options.getInt(SECTION_ALGORITHM, ITEM_MAXIMAL_DURATION));
199     
200     final String ip = options.getString(SECTION_VISUAL, ITEM_INITIAL_PLACEMENT);
201     if (VALUE_RANDOM.equals(ip)) {
202       organic.setInitialPlacement(OrganicLayouter.RANDOM);
203     } else if (VALUE_AT_ORIGIN.equals(ip)) {
204       organic.setInitialPlacement(OrganicLayouter.ZERO);
205     } else {
206       // else if AS_IS.equals(ip)
207       organic.setInitialPlacement(OrganicLayouter.AS_IS);
208     }
209     
210     final String sp = options.getString(SECTION_VISUAL, ITEM_SPHERE_OF_ACTION);
211     if (VALUE_ALL.equals(sp)) {
212       organic.setSphereOfAction(OrganicLayouter.ALL);
213     } else if (VALUE_MAINLY_SELECTION.equals(sp)) {
214       organic.setSphereOfAction(OrganicLayouter.MAINLY_SELECTION);
215     } else {
216       // if VALUE_ONLY_SELECTION.equals(sp)
217       organic.setSphereOfAction(OrganicLayouter.ONLY_SELECTION);
218     }
219 
220     organic.setGravityFactor(options.getDouble(SECTION_VISUAL, ITEM_GRAVITY_FACTOR));
221     organic.setObeyNodeSize(options.getBool(SECTION_VISUAL, ITEM_OBEY_NODE_SIZES));
222     organic.setIterationFactor(options.getDouble(SECTION_ALGORITHM, ITEM_ITERATION_FACTOR));
223     organic.setActivateTreeBeautifier(options.getBool(SECTION_VISUAL, ITEM_ACTIVATE_TREE_BEAUTIFIER));
224     organic.setActivateDeterministicMode(options.getBool(SECTION_ALGORITHM, ITEM_ACTIVATE_DETERMINISTIC_MODE));
225     organic.setMultiThreadingAllowed(options.getBool(SECTION_ALGORITHM, ITEM_ALLOW_MULTI_THREADING));
226     organic.setAttraction(options.getInt(SECTION_VISUAL, ITEM_ATTRACTION));
227     organic.setRepulsion(2-options.getInt(SECTION_VISUAL, ITEM_REPULSION));
228     organic.setGroupNodeCompactness(options.getDouble(SECTION_GROUPING, ITEM_GROUP_NODE_COMPACTNESS));
229     ((ComponentLayouter) organic.getComponentLayouter()).setStyle(ComponentLayouter.STYLE_MULTI_ROWS);
230     
231     if (HierarchyManager.containsGroupNodes(getGraph2D())) {
232       if (options.get(SECTION_GROUPING, ITEM_GROUP_LAYOUT_POLICY).equals(VALUE_FIX_GROUPS)) {
233         organic.setGroupNodePolicy(OrganicLayouter.FIXED_GROUPS_POLICY);
234       } else if (options.get(SECTION_GROUPING, ITEM_GROUP_LAYOUT_POLICY).equals(VALUE_IGNORE_GROUPS)) {
235         organic.setGroupNodePolicy(OrganicLayouter.IGNORE_GROUPS_POLICY);
236       } else {
237         organic.setGroupNodePolicy(OrganicLayouter.LAYOUT_GROUPS_POLICY);
238       }
239     }
240   }
241 }
242