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.organic.SmartOrganicLayouter;
20  import y.layout.organic.OutputRestriction;
21  import y.layout.ComponentLayouter;
22  import y.option.ConstraintManager;
23  import y.option.DefaultEditorFactory;
24  import y.option.DoubleOptionItem;
25  import y.option.IntOptionItem;
26  import y.option.OptionHandler;
27  import y.option.OptionGroup;
28  import y.option.OptionItem;
29  import y.view.Graph2D;
30  import y.view.Selections;
31  import y.view.hierarchy.HierarchyManager;
32  import y.base.NodeCursor;
33  import y.base.Node;
34  import y.base.NodeMap;
35  import y.util.Maps;
36  
37  import java.awt.Rectangle;
38  
39  /**
40   * This module represents an interactive configurator and launcher for
41   * {@link y.layout.organic.SmartOrganicLayouter}.
42   *
43   *
44   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/layout_advanced_features.html#layout_advanced_features">Section Advanced Layout Concepts</a> in the yFiles for Java Developer's Guide
45   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/smart_organic_layouter.html#smart_organic_layouter">Section Organic Layout Style</a> in the yFiles for Java Developer's Guide
46   */
47  public class SmartOrganicLayoutModule extends LayoutModule
48  {
49    private static final String ACTIVATE_DETERMINISTIC_MODE = "ACTIVATE_DETERMINISTIC_MODE";
50    private static final String VISUAL = "VISUAL";
51    private static final String ALGORITHM = "ALGORITHM";
52    private static final String COMPACTNESS = "COMPACTNESS";
53    private static final String USE_AUTOMATIC_GROUP_NODE_COMPACTION = "USE_AUTOMATIC_GROUP_NODE_COMPACTION";
54    private static final String GROUP_COMPACTNESS = "GROUP_COMPACTNESS";
55    private static final String MAXIMAL_DURATION = "MAXIMAL_DURATION";
56    private static final String OBEY_NODE_SIZES = "OBEY_NODE_SIZES";
57    private static final String CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
58    private static final String ALLOW_NODE_OVERLAPS = "ALLOW_NODE_OVERLAPS";
59    private static final String MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
60    private static final String SCOPE = "SCOPE";
61    private static final String PREFERRED_EDGE_LENGTH = "PREFERRED_EDGE_LENGTH";
62    private static final String SMARTORGANIC = "SMARTORGANIC";
63    private static final String SCOPE_SUBSET = "SUBSET";
64    private static final String SCOPE_MAINLY_SUBSET = "MAINLY_SUBSET";
65    private static final String SCOPE_ALL = "ALL";
66    private static final String QUALITY_TIME_RATIO = "QUALITY_TIME_RATIO";
67    private static final String RESTRICT_OUTPUT = "RESTRICT_OUTPUT";
68    private static final String NONE = "NONE";
69    private static final String OUTPUT_CAGE = "OUTPUT_CAGE";
70    private static final String OUTPUT_CIRCULAR_CAGE = "OUTPUT_CIRCULAR_CAGE";
71    private static final String OUTPUT_ELLIPTICAL_CAGE = "OUTPUT_ELLIPTICAL_CAGE";
72    private static final String OUTPUT_AR = "OUTPUT_AR";
73    private static final String CAGE_X = "CAGE_X";
74    private static final String CAGE_Y = "CAGE_Y";
75    private static final String CAGE_WIDTH = "CAGE_WIDTH";
76    private static final String CAGE_HEIGHT = "CAGE_HEIGHT";
77    private static final String ELLIPTICAL_CAGE_X = "ELLIPTICAL_CAGE_X";
78    private static final String ELLIPTICAL_CAGE_Y = "ELLIPTICAL_CAGE_Y";
79    private static final String ELLIPTICAL_CAGE_WIDTH = "ELLIPTICAL_CAGE_WIDTH";
80    private static final String ELLIPTICAL_CAGE_HEIGHT = "ELLIPTICAL_CAGE_HEIGHT";
81    private static final String CAGE_CENTER_X = "CAGE_CENTER_X";
82    private static final String CAGE_CENTER_Y = "CAGE_CENTER_Y";
83    private static final String CAGE_RADIUS = "CAGE_RADIUS";
84    private static final String CAGE_RATIO = "CAGE_RATIO";
85    private static final String AR_CAGE_USE_VIEW = "AR_CAGE_USE_VIEW";
86    private static final String RECT_CAGE_USE_VIEW = "RECT_CAGE_USE_VIEW";
87    private static final String CIRC_CAGE_USE_VIEW = "CIRC_CAGE_USE_VIEW";
88    private static final String ELL_CAGE_USE_VIEW = "ELL_CAGE_USE_VIEW";
89    private static final String RESTRICTIONS = "RESTRICTIONS";
90    private static final String AVOID_NODE_EDGE_OVERLAPS = "AVOID_NODE_EDGE_OVERLAPS";
91    private static final String GROUPING      = "GROUPING";
92    private static final String GROUP_LAYOUT_POLICY = "GROUP_LAYOUT_POLICY";
93    private static final String IGNORE_GROUPS = "IGNORE_GROUPS";
94    private static final String LAYOUT_GROUPS = "LAYOUT_GROUPS";
95    private static final String FIX_GROUP_BOUNDS    = "FIX_GROUP_BOUNDS";
96    private static final String FIX_GROUP_CONTENTS = "FIX_GROUP_CONTENTS";
97    private static final String USE_AUTO_CLUSTERING = "USE_AUTO_CLUSTERING";
98    private static final String AUTO_CLUSTERING_QUALITY = "AUTO_CLUSTERING_QUALITY";
99  
100 // for the option handler
101   private final static String[] SCOPES =
102   {
103     SCOPE_ALL,
104     SCOPE_MAINLY_SUBSET,
105     SCOPE_SUBSET,
106   };
107 
108 // for the option handler
109   private final String[] GROUPING_POLICIES = new String[]{
110       LAYOUT_GROUPS,
111       FIX_GROUP_CONTENTS,
112       FIX_GROUP_BOUNDS,
113       IGNORE_GROUPS,
114   };
115 
116   private final static String[] OUTPUT_RESTRICTIONS =
117   {
118     NONE,
119     OUTPUT_CAGE,
120     OUTPUT_CIRCULAR_CAGE,
121     OUTPUT_AR,
122     OUTPUT_ELLIPTICAL_CAGE,
123   };
124 
125   private SmartOrganicLayouter organic;
126 
127   public SmartOrganicLayoutModule()
128   {
129     super (SMARTORGANIC,
130            "yWorks Graph Layout Team",
131            "Wrapper for SmartOrganicLayouter");
132     setPortIntersectionCalculatorEnabled(true);
133   }
134 
135   /**
136    * Factory method. Responsible for creating and initializing
137    * the OptionHandler for this module.
138    */
139   protected OptionHandler createOptionHandler()
140   {
141     createOrganic();
142 
143     OptionHandler op = new OptionHandler(getModuleName());
144     ConstraintManager cm = new ConstraintManager(op);
145 
146     op.useSection(VISUAL);
147     op.addEnum(SCOPE,SCOPES,
148                organic.getScope());
149     op.addInt(PREFERRED_EDGE_LENGTH, (int)organic.getPreferredEdgeLength(), 5, 500);
150     op.addBool(CONSIDER_NODE_LABELS,organic.isConsiderNodeLabelsEnabled());
151     op.addBool(ALLOW_NODE_OVERLAPS,organic.isNodeOverlapsAllowed());
152     ConstraintManager.Condition condition = cm.createConditionValueEquals(ALLOW_NODE_OVERLAPS, Boolean.FALSE).or(
153         cm.createConditionValueEquals(CONSIDER_NODE_LABELS, Boolean.TRUE));
154     cm.setEnabledOnCondition(condition, op.addDouble(MINIMAL_NODE_DISTANCE,organic.getMinimalNodeDistance(),0,100,0));
155     op.addBool(AVOID_NODE_EDGE_OVERLAPS, false);
156     cm.setEnabledOnValueEquals(CONSIDER_NODE_LABELS, Boolean.FALSE, ALLOW_NODE_OVERLAPS);
157 
158     op.addDouble(COMPACTNESS,organic.getCompactness(),0,1);
159 
160     op.addBool(USE_AUTO_CLUSTERING, organic.isAutoClusteringEnabled());
161     op.addDouble(AUTO_CLUSTERING_QUALITY, organic.getAutoClusteringQuality(), 0, 1);
162     cm.setEnabledOnValueEquals(USE_AUTO_CLUSTERING, Boolean.TRUE, AUTO_CLUSTERING_QUALITY);
163 
164     op.useSection(RESTRICTIONS);
165 
166     final Object ctrId = new Object();
167     op.addEnum(RESTRICT_OUTPUT, OUTPUT_RESTRICTIONS, 0).setAttribute( DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId );
168 
169     OptionGroup og;
170     og = new OptionGroup();
171     cm.setEnabledOnValueEquals( RESTRICT_OUTPUT, OUTPUT_CAGE, og );
172     og.setAttribute( OptionGroup.ATTRIBUTE_TITLE, OUTPUT_CAGE );
173     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId );
174     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CARD_ID, OUTPUT_CAGE );
175     og.addItem( op.addBool(RECT_CAGE_USE_VIEW, true));
176 
177     condition = cm.createConditionValueEquals(RESTRICT_OUTPUT, OUTPUT_CAGE).and(
178         cm.createConditionValueEquals(RECT_CAGE_USE_VIEW, Boolean.FALSE));
179 
180     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_X, 0.0d) ));
181     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_Y, 0.0d) ));
182     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_WIDTH, 1000.0d) ));
183     op.getItem(RESTRICTIONS, CAGE_WIDTH)
184       .setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
185     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_HEIGHT, 1000.0d) ));
186     op.getItem(RESTRICTIONS, CAGE_HEIGHT)
187       .setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
188 
189     og = new OptionGroup();
190     cm.setEnabledOnValueEquals( RESTRICT_OUTPUT, OUTPUT_CIRCULAR_CAGE, og );
191     og.setAttribute( OptionGroup.ATTRIBUTE_TITLE, OUTPUT_CIRCULAR_CAGE );
192     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId );
193     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CARD_ID, OUTPUT_CIRCULAR_CAGE );
194     og.addItem( op.addBool(CIRC_CAGE_USE_VIEW, true));
195     condition = cm.createConditionValueEquals(RESTRICT_OUTPUT, OUTPUT_CIRCULAR_CAGE).and(
196         cm.createConditionValueEquals(CIRC_CAGE_USE_VIEW, Boolean.FALSE));
197     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_CENTER_X, 0.0d) ));
198     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_CENTER_Y, 0.0d) ));
199     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_RADIUS, 1000.0d) ));
200     op.getItem(RESTRICTIONS,CAGE_RADIUS)
201       .setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
202 
203     og = new OptionGroup();
204     cm.setEnabledOnValueEquals( RESTRICT_OUTPUT, OUTPUT_ELLIPTICAL_CAGE, og );
205     og.setAttribute( OptionGroup.ATTRIBUTE_TITLE, OUTPUT_ELLIPTICAL_CAGE );
206     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId );
207     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CARD_ID, OUTPUT_ELLIPTICAL_CAGE );
208     og.addItem( op.addBool(ELL_CAGE_USE_VIEW, true));
209     condition = cm.createConditionValueEquals(RESTRICT_OUTPUT, OUTPUT_ELLIPTICAL_CAGE).and(
210         cm.createConditionValueEquals(ELL_CAGE_USE_VIEW, Boolean.FALSE));
211     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(ELLIPTICAL_CAGE_X, 0.0d) ));
212     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(ELLIPTICAL_CAGE_Y, 0.0d) ));
213     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(ELLIPTICAL_CAGE_WIDTH, 1000.0d) ));
214     op.getItem(RESTRICTIONS, ELLIPTICAL_CAGE_WIDTH)
215       .setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
216     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(ELLIPTICAL_CAGE_HEIGHT, 1000.0d) ));
217     op.getItem(RESTRICTIONS, ELLIPTICAL_CAGE_HEIGHT)
218       .setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
219 
220     og = new OptionGroup();
221     cm.setEnabledOnValueEquals( RESTRICT_OUTPUT, OUTPUT_AR, og );
222     og.setAttribute( OptionGroup.ATTRIBUTE_TITLE, OUTPUT_AR );
223     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId );
224     og.setAttribute( DefaultEditorFactory.ATTRIBUTE_CARD_ID, OUTPUT_AR );
225     og.addItem( op.addBool(AR_CAGE_USE_VIEW, true));
226     condition = cm.createConditionValueEquals(RESTRICT_OUTPUT, OUTPUT_AR).and(
227         cm.createConditionValueEquals(AR_CAGE_USE_VIEW, Boolean.FALSE));
228     cm.setEnabledOnCondition(condition, og.addItem( op.addDouble(CAGE_RATIO, 1.0d) ));
229 
230     op.useSection(GROUPING);
231     op.addEnum(GROUP_LAYOUT_POLICY, GROUPING_POLICIES, 0);
232     op.addBool(USE_AUTOMATIC_GROUP_NODE_COMPACTION, organic.isAutomaticGroupNodeCompactionEnabled());
233     op.addDouble(GROUP_COMPACTNESS,organic.getGroupNodeCompactness(),0,1);
234     cm.setEnabledOnValueEquals(USE_AUTOMATIC_GROUP_NODE_COMPACTION, Boolean.FALSE, GROUP_COMPACTNESS);
235 //    op.addDouble(GROUP_NODE_COMPACTNESS, organic.getGroupNodeCompactness(), 0, 1);
236 
237 
238     op.useSection(ALGORITHM);
239     OptionItem qualityItem = op.addDouble( QUALITY_TIME_RATIO, organic.getQualityTimeRatio(), 0, 1 );
240     qualityItem.setAttribute( DefaultEditorFactory.ATTRIBUTE_MIN_VALUE_LABEL_TEXT, "SPEED" );
241     qualityItem.setAttribute( DefaultEditorFactory.ATTRIBUTE_MAX_VALUE_LABEL_TEXT, "QUALITY" );
242 
243     op.addInt(MAXIMAL_DURATION,(int)(organic.getMaximumDuration()/1000))
244       .setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(0));
245     op.addBool(ACTIVATE_DETERMINISTIC_MODE,organic.isDeterministic());
246     return op;
247   }
248 
249   /**
250    * Module initialization routine. Typically this method is used to 
251    * configure the underlying algorithm with the options found in the
252    * options handler of this module.
253    */
254   protected void init()
255   {
256     createOrganic();
257 
258     OptionHandler op = getOptionHandler();
259     organic.setPreferredEdgeLength(op.getInt(VISUAL, PREFERRED_EDGE_LENGTH));
260     boolean considerNodeLabels = op.getBool(VISUAL,CONSIDER_NODE_LABELS);
261     organic.setConsiderNodeLabelsEnabled(considerNodeLabels);
262     organic.setNodeOverlapsAllowed(op.getBool(VISUAL, ALLOW_NODE_OVERLAPS) && !considerNodeLabels);
263     organic.setMinimalNodeDistance(op.getDouble(VISUAL, MINIMAL_NODE_DISTANCE));
264     organic.setScope(OptionHandler.getIndex(SCOPES, op.getString(VISUAL,SCOPE)));
265     organic.setCompactness(op.getDouble(VISUAL,COMPACTNESS));
266     organic.setAutomaticGroupNodeCompactionEnabled(op.getBool(USE_AUTOMATIC_GROUP_NODE_COMPACTION));
267     organic.setGroupNodeCompactness(op.getDouble(GROUP_COMPACTNESS));
268     //Doesn't really make sense to ignore node sizes (for certain configurations, this setting
269     //doesn't have an effect anyway)
270     organic.setNodeSizeAware(true);
271     organic.setAutoClusteringEnabled(op.getBool(USE_AUTO_CLUSTERING));
272     organic.setAutoClusteringQuality(op.getDouble(AUTO_CLUSTERING_QUALITY));
273     organic.setNodeEdgeOverlapAvoided(op.getBool(AVOID_NODE_EDGE_OVERLAPS));
274     organic.setDeterministic(op.getBool(ALGORITHM, ACTIVATE_DETERMINISTIC_MODE));
275     organic.setMaximumDuration(1000*op.getInt(ALGORITHM, MAXIMAL_DURATION));
276     organic.setQualityTimeRatio(op.getDouble(ALGORITHM,QUALITY_TIME_RATIO));
277     switch (op.getEnum(RESTRICT_OUTPUT)){
278       case 0:
279         organic.setComponentLayouterEnabled(true);
280         organic.setOutputRestriction( OutputRestriction.NONE);
281         break;
282       case 1: {
283         double x;
284         double y;
285         double w;
286         double h;
287         if (op.getBool(RECT_CAGE_USE_VIEW) && getGraph2DView() != null) {
288           Rectangle visibleRect = getGraph2DView().getVisibleRect();
289           x = visibleRect.x;
290           y = visibleRect.y;
291           w = visibleRect.width;
292           h = visibleRect.height;
293         } else {
294           x = op.getDouble(CAGE_X);
295           y = op.getDouble(CAGE_Y);
296           w = op.getDouble(CAGE_WIDTH);
297           h = op.getDouble(CAGE_HEIGHT);
298         }
299         organic.setOutputRestriction(
300             OutputRestriction.createRectangularCageRestriction(x, y, w, h));
301         organic.setComponentLayouterEnabled(false);
302         break;
303       }
304       case 2:
305       {
306         double x;
307         double y;
308         double radius;
309         if (op.getBool(CIRC_CAGE_USE_VIEW) && getGraph2DView() != null) {
310           Rectangle visibleRect = getGraph2DView().getVisibleRect();
311           x = visibleRect.getCenterX();
312           y = visibleRect.getCenterY();
313           radius = Math.min(visibleRect.width, visibleRect.height) * 0.5d;
314         } else {
315           x = op.getDouble(CAGE_CENTER_X);
316           y = op.getDouble(CAGE_CENTER_Y);
317           radius = op.getDouble(CAGE_RADIUS);
318         }
319         organic.setOutputRestriction( OutputRestriction.createCircularCageRestriction(x, y, radius));
320         organic.setComponentLayouterEnabled(false);
321         break;
322       }
323       case 3:
324       {
325         double ratio;
326         if (op.getBool(AR_CAGE_USE_VIEW) && getGraph2DView() != null) {
327           Rectangle visibleRect = getGraph2DView().getVisibleRect();
328           ratio = visibleRect.getWidth()/visibleRect.getHeight();
329         } else {
330           ratio = op.getDouble(CAGE_RATIO);
331         }
332         organic.setOutputRestriction( OutputRestriction.createAspectRatioRestriction(ratio));
333         organic.setComponentLayouterEnabled(true);
334         ((ComponentLayouter) organic.getComponentLayouter()).setPreferredLayoutSize(ratio * 100, 100);
335         break;
336       }
337       case 4:
338       {
339         double x;
340         double y;
341         double w;
342         double h;
343         if (op.getBool(ELL_CAGE_USE_VIEW) && getGraph2DView() != null) {
344           Rectangle visibleRect = getGraph2DView().getVisibleRect();
345           x = visibleRect.x;
346           y = visibleRect.y;
347           w = visibleRect.width;
348           h = visibleRect.height;
349         } else {
350           x = op.getDouble(ELLIPTICAL_CAGE_X);
351           y = op.getDouble(ELLIPTICAL_CAGE_Y);
352           w = op.getDouble(ELLIPTICAL_CAGE_WIDTH);
353           h = op.getDouble(ELLIPTICAL_CAGE_HEIGHT);
354         }
355         organic.setOutputRestriction(
356             OutputRestriction.createEllipticalCageRestriction(x, y, w, h));
357         organic.setComponentLayouterEnabled(false);
358         break;
359       }
360     }
361   }
362 
363   /**
364    * Main module execution routine. launches the hierarchic layouter.
365    */
366   protected void mainrun()
367   {
368     final OptionHandler handler = getOptionHandler();
369     final int policy = handler.getEnum(GROUP_LAYOUT_POLICY);
370     createOrganic();
371     final Graph2D graph = getGraph2D();
372     try {
373       final boolean grouping = policy != 3 && HierarchyManager.containsGroupNodes(graph);
374       getLayoutExecutor().setConfiguringGrouping(grouping);
375       if (policy == 2 && grouping) {
376         NodeMap nodeMap = Maps.createHashedNodeMap();
377         for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
378           Node node = nodeCursor.node();
379           if (HierarchyManager.getInstance(graph).isGroupNode(node)){
380             nodeMap.set(node, SmartOrganicLayouter.GROUP_NODE_MODE_FIX_BOUNDS);
381           }
382         }
383         graph.addDataProvider(SmartOrganicLayouter.GROUP_NODE_MODE_DATA, nodeMap);
384       } else if (policy == 1 && grouping) {
385         NodeMap nodeMap = Maps.createHashedNodeMap();
386         for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
387           Node node = nodeCursor.node();
388           if (HierarchyManager.getInstance(graph).isGroupNode(node)){
389             nodeMap.set(node, SmartOrganicLayouter.GROUP_NODE_MODE_FIX_CONTENTS);
390           }
391         }
392         graph.addDataProvider(SmartOrganicLayouter.GROUP_NODE_MODE_DATA, nodeMap);
393       }
394       graph.addDataProvider(SmartOrganicLayouter.NODE_SUBSET_DATA,
395           Selections.createSelectionNodeMap(graph));
396       launchLayouter(organic);
397     } finally {
398       graph.removeDataProvider(SmartOrganicLayouter.NODE_SUBSET_DATA);
399       if (policy == 2 || policy == 1) {
400         graph.removeDataProvider(SmartOrganicLayouter.GROUP_NODE_MODE_DATA);
401       }
402       getLayoutExecutor().setConfiguringGrouping(true);
403     }
404   }
405 
406   /**
407    * clean up the module, clear temporarily bound data providers and
408    * references to the wrapped algorithm.
409    */
410   protected void dispose()
411   {
412     organic = null;
413   }
414 
415   private void createOrganic()
416   {
417     if(organic == null)
418     {
419       organic = new SmartOrganicLayouter();      
420     }
421   }
422 }
423