1
14 package demo.view.viewmode;
15
16 import demo.view.DemoBase;
17 import y.base.Edge;
18 import y.base.Node;
19 import y.base.YCursor;
20 import y.base.YList;
21 import y.geom.OrientedRectangle;
22 import y.geom.YPoint;
23 import y.geom.YRectangle;
24 import y.layout.LabelCandidate;
25 import y.view.Graph2D;
26 import y.view.HitInfo;
27 import y.view.HitInfoFactories;
28 import y.view.SmartEdgeLabelModel;
29 import y.view.SmartNodeLabelModel;
30 import y.option.OptionHandler;
31 import y.view.DefaultLabelConfiguration;
32 import y.view.EdgeLabel;
33 import y.view.EdgeRealizer;
34 import y.view.EditMode;
35 import y.view.LabelSnapContext;
36 import y.view.MoveLabelMode;
37 import y.view.NodeLabel;
38 import y.view.NodeRealizer;
39 import y.view.PopupMode;
40 import y.view.YLabel;
41
42 import javax.swing.AbstractAction;
43 import javax.swing.JPopupMenu;
44 import java.awt.Color;
45 import java.awt.Dimension;
46 import java.awt.EventQueue;
47 import java.awt.RenderingHints;
48 import java.awt.event.ActionEvent;
49 import java.util.Locale;
50 import java.util.Map;
51
52
53
76 public class SmartLabelModelDemo extends DemoBase {
77 private static final Color LABEL_LINE_COLOR = new Color(153, 204, 255, 255);
78 private static final Color LABEL_BACKGROUND_COLOR = Color.WHITE;
79 private static final String AUTO_FLIPPING_CONFIG = "AutoFlipConfig";
80 private boolean fractionMetricsForSizeCalculationEnabled;
81
82 public SmartLabelModelDemo() {
83 this(null);
84 }
85
86 public SmartLabelModelDemo( final String helpFilePath ) {
87 loadInitialGraph();
88 addHelpPane(helpFilePath);
89 }
90
91
94 protected void loadInitialGraph() {
95 loadGraph("resource/SmartLabelModelDemo.graphml");
96 }
97
98 protected void initialize() {
99 super.initialize();
100 view.setPreferredSize(new Dimension(700, 650));
101 view.setHitInfoFactory(new HitInfoFactories.DefaultHitInfoFactory(view) {
102 public HitInfo createHitInfo(
103 final double x, final double y,
104 final int types,
105 final boolean firstHitOnly
106 ) {
107 return createHitInfo(getView(), getGraph(), x, y, types, firstHitOnly);
108 }
109 });
110
111 view.getRenderingHints().put(
113 RenderingHints.KEY_FRACTIONALMETRICS,
114 RenderingHints.VALUE_FRACTIONALMETRICS_ON);
115 fractionMetricsForSizeCalculationEnabled = YLabel.isFractionMetricsForSizeCalculationEnabled();
118 YLabel.setFractionMetricsForSizeCalculationEnabled(true);
119 }
120
121
125 public void dispose() {
126 YLabel.setFractionMetricsForSizeCalculationEnabled(fractionMetricsForSizeCalculationEnabled);
127 }
128
129
134 protected void configureDefaultRealizers() {
135 super.configureDefaultRealizers();
136
137 NodeRealizer nodeRealizer = view.getGraph2D().getDefaultNodeRealizer();
138 nodeRealizer.setSize(200, 100);
139 final NodeLabel nodeLabel = nodeRealizer.getLabel();
140 nodeLabel.setText("Smart Node Label");
141 nodeLabel.setLineColor(LABEL_LINE_COLOR);
142 nodeLabel.setBackgroundColor(LABEL_BACKGROUND_COLOR);
143 final SmartNodeLabelModel nodeLabelModel = new SmartNodeLabelModel();
144 nodeLabel.setLabelModel(nodeLabelModel);
145 nodeLabel.setModelParameter(nodeLabelModel.getDefaultParameter());
146
147 final YLabel.Factory factory = EdgeLabel.getFactory();
148 final Map defaultConfigImplementationsMap = factory.createDefaultConfigurationMap();
149 DefaultLabelConfiguration customLabelConfig = new DefaultLabelConfiguration();
150 customLabelConfig.setAutoFlippingEnabled(true);
151 defaultConfigImplementationsMap.put(YLabel.Painter.class, customLabelConfig);
152 defaultConfigImplementationsMap.put(YLabel.Layout.class, customLabelConfig);
153 defaultConfigImplementationsMap.put(YLabel.BoundsProvider.class, customLabelConfig);
154 factory.addConfiguration(AUTO_FLIPPING_CONFIG, defaultConfigImplementationsMap);
155
156 EdgeRealizer edgeRealizer = view.getGraph2D().getDefaultEdgeRealizer();
157 final EdgeLabel edgeLabel = edgeRealizer.getLabel();
158 edgeLabel.setText("Smart Edge Label");
159 edgeLabel.setLineColor(LABEL_LINE_COLOR);
160 edgeLabel.setBackgroundColor(LABEL_BACKGROUND_COLOR);
161 final SmartEdgeLabelModel edgeLabelModel = new SmartEdgeLabelModel();
162 edgeLabel.setLabelModel(edgeLabelModel);
163 edgeLabel.setModelParameter(edgeLabelModel.createDiscreteModelParameter(SmartEdgeLabelModel.POSITION_CENTER));
164 edgeLabel.setConfiguration(AUTO_FLIPPING_CONFIG);
165 }
166
167
172 protected EditMode createEditMode() {
173 final EditMode mode = super.createEditMode();
174 mode.setCyclicSelectionEnabled(true); mode.setPopupMode(new DemoPopupMode());
176 final SnappingConfiguration snappingConfiguration = DemoBase.createDefaultSnappingConfiguration();
177 snappingConfiguration.configureView(view);
178 snappingConfiguration.configureEditMode(mode);
179
180 final LabelSnapContext snapContext = new LabelSnapContext(view);
182 ((MoveLabelMode) mode.getMoveLabelMode()).setSnapContext(snapContext);
183 snapContext.setNodeLabelSnapDistance(10);
184 snapContext.setEdgeLabelSnapDistance(30);
185 snapContext.setSnapLineColor(Color.BLUE);
186
187 return mode;
188 }
189
190
194 public static void main( final String[] args ) {
195 EventQueue.invokeLater(new Runnable() {
196 public void run() {
197 Locale.setDefault(Locale.ENGLISH);
198 initLnF();
199 (new SmartLabelModelDemo("resource/smartlabelmodeldemo.html")).start();
200 }
201 });
202 }
203
204
205
208 private static final class DemoPopupMode extends PopupMode {
209
214 public JPopupMenu getNodePopup( final Node node ) {
215 JPopupMenu pm = new JPopupMenu();
216 pm.add(new AbstractAction("Add Label") {
217 public void actionPerformed(ActionEvent e) {
218 if (node == null) {
219 return;
220 }
221
222 final SmartNodeLabelModel nodeLabelModel = new SmartNodeLabelModel();
223 final NodeLabel label = new NodeLabel("Smart Node Label");
224 label.setLineColor(LABEL_LINE_COLOR);
225 label.setBackgroundColor(LABEL_BACKGROUND_COLOR);
226 label.setLabelModel(nodeLabelModel);
227 label.setModelParameter(nodeLabelModel.getDefaultParameter());
228 getGraph2D().getRealizer(node).addLabel(label);
229 getGraph2D().updateViews();
230 }
231 });
232 return pm;
233 }
234
235
242 public JPopupMenu getNodeLabelPopup( final NodeLabel label ) {
243 JPopupMenu pm = new JPopupMenu();
244 pm.add(new AbstractAction("Edit Label") {
245 public void actionPerformed(ActionEvent e) {
246 if (label == null) {
247 return;
248 }
249
250 LabelOptionHandler oh = new LabelOptionHandler(label, getGraph2D());
251 oh.showEditor(null, OptionHandler.OK_CANCEL_BUTTONS);
252 }
253 });
254 return pm;
255 }
256
257
262 public JPopupMenu getEdgePopup( final Edge edge ) {
263 JPopupMenu pm = new JPopupMenu();
264 pm.add(new AbstractAction("Add Label") {
265 public void actionPerformed(ActionEvent e) {
266 if (edge == null) {
267 return;
268 }
269
270 final SmartEdgeLabelModel edgeLabelModel = new SmartEdgeLabelModel();
271 final EdgeLabel label = new EdgeLabel("Smart Edge Label");
272 label.setConfiguration(AUTO_FLIPPING_CONFIG);
273 label.setLineColor(LABEL_LINE_COLOR);
274 label.setBackgroundColor(LABEL_BACKGROUND_COLOR);
275 label.setLabelModel(edgeLabelModel);
276 label.setModelParameter(edgeLabelModel.getDefaultParameter());
277 getGraph2D().getRealizer(edge).addLabel(label);
278
279 final Object parameter = calculateBestParameter(edge, label);
280 if (parameter != null) {
281 label.setModelParameter(parameter);
282 }
283 getGraph2D().updateViews();
284 }
285 });
286 return pm;
287 }
288
289
296 public JPopupMenu getEdgeLabelPopup( final EdgeLabel label ) {
297 JPopupMenu pm = new JPopupMenu();
298 pm.add(new AbstractAction("Edit Label") {
299 public void actionPerformed(ActionEvent e) {
300 if (label == null) {
301 return;
302 }
303
304 LabelOptionHandler oh = new LabelOptionHandler(label, getGraph2D());
305 oh.showEditor(null, OptionHandler.OK_CANCEL_BUTTONS);
306 }
307 });
308 return pm;
309 }
310
311
319 private Object calculateBestParameter( final Edge e, final EdgeLabel label ) {
320 if (lastPressEvent == null) {
321 return null;
322 }
323
324 YList occupiedRectList = new YList();
326 Graph2D graph = view.getGraph2D();
327 EdgeRealizer er = graph.getRealizer(e);
328 for (int i = 0, n = er.labelCount(); i < n; ++i) {
329 EdgeLabel el = er.getLabel(i);
330 if (el != label) {
331 occupiedRectList.add(el.getOrientedBox());
332 }
333 }
334
335 final YPoint mousePressedEventLocation = new YPoint(
337 view.toWorldCoordX(lastPressEvent.getX()),
338 view.toWorldCoordY(lastPressEvent.getY()));
339 double minDist = Double.MAX_VALUE;
340 LabelCandidate chosen = null;
341 YList candidates = label.getLabelModel().getLabelCandidates(
342 label, er, er.getSourceRealizer(), er.getTargetRealizer());
343 for (YCursor cu = candidates.cursor(); cu.ok(); cu.next()) {
344 LabelCandidate lc = (LabelCandidate) cu.current();
345
346 boolean isOccupied = false;
347 YRectangle bBox = lc.getBox().getBoundingBox();
348 for (YCursor cur = occupiedRectList.cursor(); cur.ok() && !isOccupied; cur.next()) {
349 if (OrientedRectangle.intersects((OrientedRectangle) cur.current(), bBox, 0)) {
350 isOccupied = true;
351 break;
352 }
353 }
354
355 if (!isOccupied) {
356 double dist = YPoint.distance(mousePressedEventLocation, lc.getBox().getCenter());
357 if (dist < minDist) {
358 minDist = dist;
359 chosen = lc;
360 }
361 }
362 }
363
364 return chosen == null ? null : chosen.getModelParameter();
365 }
366 }
367
368
373 private static final class LabelOptionHandler extends OptionHandler {
374 static final String LABEL_TEXT = "Label Text";
375 static final String FONT_SIZE = "Font Size";
376 static final String ROTATION_ANGLE = "Rotation Angle";
377 static final String AUTO_ROTATION = "Auto Rotation";
378
379 private final YLabel label;
380 private final Graph2D graph;
381 private final boolean isEdgeLabel;
382
383
389 LabelOptionHandler( final YLabel label, final Graph2D graph ) {
390 super("Label Options");
391 this.label = label;
392 this.graph = graph;
393 this.isEdgeLabel = label instanceof EdgeLabel;
394 addString(LABEL_TEXT, label.getText(), 5);
395 addInt(FONT_SIZE, label.getFontSize());
396 int value = 0;
397 if (isEdgeLabel) {
398 final EdgeLabel el = (EdgeLabel) label;
399 if (el.getLabelModel() instanceof SmartEdgeLabelModel) {
400 value = toDegrees(2*Math.PI - SmartEdgeLabelModel.getAngle(el.getModelParameter()));
405 }
406 } else {
407 value = toDegrees(label.getOrientedBox().getAngle());
408 }
409 while (value < 0) {
410 value += 360;
411 }
412 addInt(ROTATION_ANGLE, value, 0, 360);
413 if (isEdgeLabel) {
414 final EdgeLabel el = (EdgeLabel) label;
415 if (el.getLabelModel() instanceof SmartEdgeLabelModel) {
416 SmartEdgeLabelModel model = (SmartEdgeLabelModel) el.getLabelModel();
417 addBool(AUTO_ROTATION, model.isAutoRotationEnabled());
418 }
419 }
420 }
421
422 public void commitValues() {
423 super.commitValues();
424 label.setText(getString(LABEL_TEXT));
425 label.setFontSize(getInt(FONT_SIZE));
426
427 final OrientedRectangle box = label.getOrientedBox();
428 final YPoint center = box.getCenter();
429 box.setAngle(Math.toRadians(getInt(ROTATION_ANGLE)));
430 box.setCenter(center);
431
432 if (isEdgeLabel && ((EdgeLabel) label).getLabelModel() instanceof SmartEdgeLabelModel) {
433 final EdgeLabel el = (EdgeLabel) label;
434 final EdgeRealizer er = el.getRealizer();
435 final SmartEdgeLabelModel model = (SmartEdgeLabelModel) el.getLabelModel();
436 model.setAutoRotationEnabled(getBool(AUTO_ROTATION));
437 el.setModelParameter(model.createRelativeModelParameter(
438 box,
439 er,
440 er.getSourceRealizer(),
441 er.getTargetRealizer()));
442 } else {
443 label.setModelParameter(label.getBestModelParameterForBounds(box));
444 }
445
446 graph.updateViews();
447 }
448
449 private static int toDegrees( final double angle ) {
450 return ((int) Math.rint(Math.toDegrees(angle))) % 360;
451 }
452 }
453 }