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  
17  import y.base.DataProvider;
18  import y.base.Edge;
19  import y.base.EdgeCursor;
20  
21  import y.layout.LabelRanking;
22  import y.layout.labeling.AbstractLabelingAlgorithm;
23  import y.layout.labeling.GreedyMISLabeling;
24  import y.layout.labeling.MISLabelingAlgorithm;
25  import y.layout.labeling.SALabeling;
26  import y.option.EnumOptionItem;
27  import y.option.MappedListCellRenderer;
28  import y.option.OptionHandler;
29  import y.util.DataProviderAdapter;
30  import y.view.EdgeLabel;
31  import y.view.EdgeRealizer;
32  import y.view.Graph2D;
33  import y.view.NodeLabel;
34  import y.view.YLabel;
35  import y.view.hierarchy.GroupLayoutConfigurator;
36  import java.util.Map;
37  
38  import y.module.YModule;
39  
40  /**
41   * This module represents an interactive configurator and launcher for the
42   * yFiles labeling algorithms. 
43   * It is similar to LabelingModule found in the yFiles package y.module.
44   *
45   */
46  public class LabelingModule extends YModule {
47  
48    private static final String ALLOW_NODE_OVERLAPS = "ALLOW_NODE_OVERLAPS";
49    private static final String AS_IS = "As Is";
50    private static final String INPUT = "INPUT";
51    private static final String CONSIDER_INVISIBLE_LABELS = "CONSIDER_INVISIBLE_LABELS";
52    private static final String ALLOW_EDGE_OVERLAPS = "ALLOW_EDGE_OVERLAPS";
53    private static final String DIVERSE_LABELING = "DIVERSE_LABELING";
54    private static final String QUALITY = "QUALITY";
55    private static final String USE_OPTIMIZATION = "USE_OPTIMIZATION";
56    private static final String USE_POSTPROCESSING = "USE_POSTPROCESSING";
57    private static final String CONSIDER_SELECTED_FEATURES_ONLY = "CONSIDER_SELECTED_FEATURES_ONLY";
58    private static final String SCOPE = "SCOPE";
59    private static final String PLACE_EDGE_LABELS = "PLACE_EDGE_LABELS";
60    private static final String MODEL = "MODEL";
61    private static final String EDGE_LABEL_MODEL = "EDGE_LABEL_MODEL";
62    private static final String UNKNOWN_MODEL_VALUE = "UNKNOWN_MODEL_VALUE";
63    private static final String BEST = "Best";
64    private static final String PLACE_NODE_LABELS = "PLACE_NODE_LABELS";
65    private static final String OPTIMIZATION_BALANCED = "OPTIMIZATION_BALANCED";
66    private static final String OPTIMIZATION_NODE_OVERLAP = "OPTIMIZATION_NODE_OVERLAP";
67    private static final String OPTIMIZATION_LABEL_OVERLAP = "OPTIMIZATION_LABEL_OVERLAP";
68    private static final String OPTIMIZATION_EDGE_OVERLAP = "OPTIMIZATION_EDGE_OVERLAP";
69    private static final String OPTIMIZATION_NONE = "OPTIMIZATION_NONE";
70    private static final String OPTIMIZATION_STRATEGY = "OPTIMIZATION_STRATEGY";
71    
72    private static final String[] optimizationStrategy = {
73        OPTIMIZATION_BALANCED, OPTIMIZATION_NONE, OPTIMIZATION_EDGE_OVERLAP, OPTIMIZATION_LABEL_OVERLAP,
74        OPTIMIZATION_NODE_OVERLAP
75    };
76  
77    public LabelingModule() {
78      super(DIVERSE_LABELING,"yFiles Layout Team","Places Labels");
79    }
80    
81    /** Creates an option handler for this layouter */ 
82    public OptionHandler createOptionHandler() {
83      OptionHandler op = new OptionHandler(getModuleName());
84      op.useSection(SCOPE);
85      op.addBool(PLACE_NODE_LABELS,true);
86      op.addBool(PLACE_EDGE_LABELS,true);
87      op.addBool(CONSIDER_SELECTED_FEATURES_ONLY,false);
88      op.addBool(CONSIDER_INVISIBLE_LABELS,false);
89      op.useSection(QUALITY);
90      op.addBool(USE_OPTIMIZATION, false);
91      op.addEnum(OPTIMIZATION_STRATEGY, optimizationStrategy, 0);
92      op.addBool(ALLOW_NODE_OVERLAPS,false);
93      op.addBool(ALLOW_EDGE_OVERLAPS,true);
94      op.addBool(USE_POSTPROCESSING, false);
95  
96      op.useSection(MODEL);
97      Map map = EdgeLabel.modelToStringMap();
98      Object asIs = AS_IS; 
99      map.put(asIs, asIs);
100     Object best = BEST;
101     map.put(best, best);
102     
103     EnumOptionItem item = 
104       op.addEnum(EDGE_LABEL_MODEL,
105               map.keySet().toArray(),
106               best,
107               new MappedListCellRenderer(map));
108     return op;
109   }
110 
111   public void init() {
112     OptionHandler op = getOptionHandler();
113     DataProvider labelSet = new LabelSetDP(
114       getGraph2D(),
115       op.getBool(CONSIDER_SELECTED_FEATURES_ONLY),
116       op.getBool(PLACE_NODE_LABELS),
117       op.getBool(PLACE_EDGE_LABELS),
118       op.getBool(CONSIDER_INVISIBLE_LABELS));
119     getGraph2D().addDataProvider(INPUT,labelSet);
120 
121     setupEdgeLabelModels(op.get(EDGE_LABEL_MODEL), labelSet);
122   }
123   
124   public void mainrun() {
125     AbstractLabelingAlgorithm al;
126     OptionHandler op = getOptionHandler();
127     if (op.getBool(USE_OPTIMIZATION)){
128       al = new SALabeling();
129     } else {
130       al = new GreedyMISLabeling();
131     }
132     if (al instanceof MISLabelingAlgorithm) {
133       ((MISLabelingAlgorithm) al).setOptimizationStrategy((byte) op.getEnum(OPTIMIZATION_STRATEGY));
134     }
135     al.setProfitModel(new LabelRanking());
136     al.setRemoveNodeOverlaps(!op.getBool(ALLOW_NODE_OVERLAPS));
137     al.setRemoveEdgeOverlaps(!op.getBool(ALLOW_EDGE_OVERLAPS));
138     al.setApplyPostprocessing(op.getBool(USE_POSTPROCESSING));
139     
140     // initialize potential grouping information
141     GroupLayoutConfigurator glc = new GroupLayoutConfigurator(getGraph2D());
142     try {
143       // register grouping relevant DataProviders
144       glc.prepareGroupDataProviders();
145       // launch layouter in buffered mode
146       al.label(getGraph2D(),INPUT);
147     } finally {
148       // make sure the DataProviders will always be unregistered
149       glc.restoreGroupDataProviders();
150     }
151 
152     getGraph2D().removeDataProvider(INPUT);
153     getGraph2D().updateViews();
154   }
155   
156 
157   /**
158    * Selects the labels we want to set.
159    */
160   class LabelSetDP extends DataProviderAdapter
161   {
162     private boolean considerOnlySelected;
163     private Graph2D graph;
164     private boolean nodes;
165     private boolean edges;
166     private boolean unvisible;
167 
168     LabelSetDP(Graph2D g,boolean sel,boolean n,boolean e,boolean uv)
169     {
170       considerOnlySelected = sel;
171       graph = g;
172       nodes = n;
173       edges = e;
174       unvisible = uv;
175     }
176 
177     public boolean getBool(Object o)
178     {
179       YLabel ylabel = (YLabel)o;
180       if (!ylabel.isVisible() && !unvisible) {
181         return false;
182       }  
183       if (o instanceof NodeLabel) {
184         NodeLabel l = (NodeLabel)o;
185         if (l.getModel() == NodeLabel.INTERNAL) return false;
186       }
187       if (considerOnlySelected)
188       {
189         if ((o instanceof NodeLabel) && nodes)
190         {
191           NodeLabel l = (NodeLabel)o;
192           if (graph.isSelected(l.getNode())) {
193             return true;
194           } else {
195             return false;
196           }
197         }
198         if ((o instanceof EdgeLabel) && edges) {
199           EdgeLabel l = (EdgeLabel)o;
200           if (graph.isSelected(l.getEdge())) {
201             return true;
202           } else {
203             return false;        
204         }
205         }
206         return false;
207       } else {
208         if ((o instanceof NodeLabel) && nodes) return true;
209         if ((o instanceof EdgeLabel) && edges) return true;
210         return false;
211       }     
212     }
213   }
214   
215   void setupEdgeLabelModels(Object modelValue, DataProvider labelFilter) {
216     if (AS_IS.equals(modelValue)) {
217       return;
218     }
219     
220     byte model = 0;
221     if (BEST.equals(modelValue)) {
222       model = EdgeLabel.SIDE_SLIDER;
223     } else if (modelValue instanceof Byte) {
224       model = ((Byte)modelValue).byteValue();
225     } else {
226       throw new IllegalArgumentException(UNKNOWN_MODEL_VALUE + modelValue);
227     }
228     
229     Graph2D graph = getGraph2D();
230     for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
231       Edge e = ec.edge();
232       EdgeRealizer er = graph.getRealizer(e);
233       for (int i = 0; i < er.labelCount(); i++) {
234         EdgeLabel label = er.getLabel(i);
235         if (labelFilter.getBool(label)) {
236           label.setModel(model);
237         }
238       }
239     }
240   }
241 }
242 
243