1
28 package demo.view.viewmode;
29
30 import demo.view.DemoBase;
31 import y.base.Edge;
32 import y.base.Node;
33 import y.base.YCursor;
34 import y.base.YList;
35 import y.geom.OrientedRectangle;
36 import y.geom.YPoint;
37 import y.geom.YRectangle;
38 import y.layout.LabelCandidate;
39 import y.view.Graph2D;
40 import y.view.HitInfo;
41 import y.view.HitInfoFactories;
42 import y.view.SmartEdgeLabelModel;
43 import y.view.SmartNodeLabelModel;
44 import y.option.OptionHandler;
45 import y.view.DefaultLabelConfiguration;
46 import y.view.EdgeLabel;
47 import y.view.EdgeRealizer;
48 import y.view.EditMode;
49 import y.view.LabelSnapContext;
50 import y.view.MoveLabelMode;
51 import y.view.NodeLabel;
52 import y.view.NodeRealizer;
53 import y.view.PopupMode;
54 import y.view.YLabel;
55
56 import javax.swing.AbstractAction;
57 import javax.swing.JPopupMenu;
58 import java.awt.Color;
59 import java.awt.Dimension;
60 import java.awt.EventQueue;
61 import java.awt.RenderingHints;
62 import java.awt.event.ActionEvent;
63 import java.util.Locale;
64 import java.util.Map;
65
66
67
90 public class SmartLabelModelDemo extends DemoBase {
91 private static final Color LABEL_LINE_COLOR = new Color(153, 204, 255, 255);
92 private static final Color LABEL_BACKGROUND_COLOR = Color.WHITE;
93 private static final String AUTO_FLIPPING_CONFIG = "AutoFlipConfig";
94 private boolean fractionMetricsForSizeCalculationEnabled;
95
96 public SmartLabelModelDemo() {
97 this(null);
98 }
99
100 public SmartLabelModelDemo( final String helpFilePath ) {
101 loadInitialGraph();
102 addHelpPane(helpFilePath);
103 }
104
105
108 protected void loadInitialGraph() {
109 loadGraph("resource/SmartLabelModelDemo.graphml");
110 }
111
112 protected void initialize() {
113 super.initialize();
114 view.setPreferredSize(new Dimension(700, 650));
115 view.setHitInfoFactory(new HitInfoFactories.DefaultHitInfoFactory(view) {
116 public HitInfo createHitInfo(
117 final double x, final double y,
118 final int types,
119 final boolean firstHitOnly
120 ) {
121 return createHitInfo(getView(), getGraph(), x, y, types, firstHitOnly);
122 }
123 });
124
125 view.getRenderingHints().put(
127 RenderingHints.KEY_FRACTIONALMETRICS,
128 RenderingHints.VALUE_FRACTIONALMETRICS_ON);
129 fractionMetricsForSizeCalculationEnabled = YLabel.isFractionMetricsForSizeCalculationEnabled();
132 YLabel.setFractionMetricsForSizeCalculationEnabled(true);
133 }
134
135
139 public void dispose() {
140 YLabel.setFractionMetricsForSizeCalculationEnabled(fractionMetricsForSizeCalculationEnabled);
141 }
142
143
148 protected void configureDefaultRealizers() {
149 super.configureDefaultRealizers();
150
151 NodeRealizer nodeRealizer = view.getGraph2D().getDefaultNodeRealizer();
152 nodeRealizer.setSize(200, 100);
153 final NodeLabel nodeLabel = nodeRealizer.getLabel();
154 nodeLabel.setText("Smart Node Label");
155 nodeLabel.setLineColor(LABEL_LINE_COLOR);
156 nodeLabel.setBackgroundColor(LABEL_BACKGROUND_COLOR);
157 final SmartNodeLabelModel nodeLabelModel = new SmartNodeLabelModel();
158 nodeLabel.setLabelModel(nodeLabelModel, nodeLabelModel.getDefaultParameter());
159
160 final YLabel.Factory factory = EdgeLabel.getFactory();
161 final Map defaultConfigImplementationsMap = factory.createDefaultConfigurationMap();
162 DefaultLabelConfiguration customLabelConfig = new DefaultLabelConfiguration();
163 customLabelConfig.setAutoFlippingEnabled(true);
164 defaultConfigImplementationsMap.put(YLabel.Painter.class, customLabelConfig);
165 defaultConfigImplementationsMap.put(YLabel.Layout.class, customLabelConfig);
166 defaultConfigImplementationsMap.put(YLabel.BoundsProvider.class, customLabelConfig);
167 factory.addConfiguration(AUTO_FLIPPING_CONFIG, defaultConfigImplementationsMap);
168
169 EdgeRealizer edgeRealizer = view.getGraph2D().getDefaultEdgeRealizer();
170 final EdgeLabel edgeLabel = edgeRealizer.getLabel();
171 edgeLabel.setText("Smart Edge Label");
172 edgeLabel.setLineColor(LABEL_LINE_COLOR);
173 edgeLabel.setBackgroundColor(LABEL_BACKGROUND_COLOR);
174 final SmartEdgeLabelModel edgeLabelModel = new SmartEdgeLabelModel();
175 edgeLabel.setLabelModel(edgeLabelModel, edgeLabelModel.createDiscreteModelParameter(SmartEdgeLabelModel.POSITION_CENTER));
176 edgeLabel.setConfiguration(AUTO_FLIPPING_CONFIG);
177 }
178
179
184 protected EditMode createEditMode() {
185 final EditMode mode = super.createEditMode();
186 mode.setCyclicSelectionEnabled(true); mode.setPopupMode(new DemoPopupMode());
188 final SnappingConfiguration snappingConfiguration = DemoBase.createDefaultSnappingConfiguration();
189 snappingConfiguration.configureView(view);
190 snappingConfiguration.configureEditMode(mode);
191
192 final LabelSnapContext snapContext = new LabelSnapContext(view);
194 ((MoveLabelMode) mode.getMoveLabelMode()).setSnapContext(snapContext);
195 snapContext.setNodeLabelSnapDistance(10);
196 snapContext.setEdgeLabelSnapDistance(30);
197 snapContext.setSnapLineColor(Color.BLUE);
198
199 return mode;
200 }
201
202
206 public static void main( final String[] args ) {
207 EventQueue.invokeLater(new Runnable() {
208 public void run() {
209 Locale.setDefault(Locale.ENGLISH);
210 initLnF();
211 (new SmartLabelModelDemo("resource/smartlabelmodeldemo.html")).start();
212 }
213 });
214 }
215
216
217
220 private static final class DemoPopupMode extends PopupMode {
221
226 public JPopupMenu getNodePopup( final Node node ) {
227 JPopupMenu pm = new JPopupMenu();
228 pm.add(new AbstractAction("Add Label") {
229 public void actionPerformed(ActionEvent e) {
230 if (node == null) {
231 return;
232 }
233
234 final SmartNodeLabelModel nodeLabelModel = new SmartNodeLabelModel();
235 final NodeLabel label = new NodeLabel("Smart Node Label");
236 label.setLineColor(LABEL_LINE_COLOR);
237 label.setBackgroundColor(LABEL_BACKGROUND_COLOR);
238 label.setLabelModel(nodeLabelModel, nodeLabelModel.getDefaultParameter());
239 getGraph2D().getRealizer(node).addLabel(label);
240 getGraph2D().updateViews();
241 }
242 });
243 return pm;
244 }
245
246
253 public JPopupMenu getNodeLabelPopup( final NodeLabel label ) {
254 JPopupMenu pm = new JPopupMenu();
255 pm.add(new AbstractAction("Edit Label") {
256 public void actionPerformed(ActionEvent e) {
257 if (label == null) {
258 return;
259 }
260
261 LabelOptionHandler oh = new LabelOptionHandler(label, getGraph2D());
262 oh.showEditor(null, OptionHandler.OK_CANCEL_BUTTONS);
263 }
264 });
265 return pm;
266 }
267
268
273 public JPopupMenu getEdgePopup( final Edge edge ) {
274 JPopupMenu pm = new JPopupMenu();
275 pm.add(new AbstractAction("Add Label") {
276 public void actionPerformed(ActionEvent e) {
277 if (edge == null) {
278 return;
279 }
280
281 final SmartEdgeLabelModel edgeLabelModel = new SmartEdgeLabelModel();
282 final EdgeLabel label = new EdgeLabel("Smart Edge Label");
283 label.setConfiguration(AUTO_FLIPPING_CONFIG);
284 label.setLineColor(LABEL_LINE_COLOR);
285 label.setBackgroundColor(LABEL_BACKGROUND_COLOR);
286 label.setLabelModel(edgeLabelModel, edgeLabelModel.getDefaultParameter());
287 getGraph2D().getRealizer(edge).addLabel(label);
288
289 final Object parameter = calculateBestParameter(edge, label);
290 if (parameter != null) {
291 label.setModelParameter(parameter);
292 }
293 getGraph2D().updateViews();
294 }
295 });
296 return pm;
297 }
298
299
306 public JPopupMenu getEdgeLabelPopup( final EdgeLabel label ) {
307 JPopupMenu pm = new JPopupMenu();
308 pm.add(new AbstractAction("Edit Label") {
309 public void actionPerformed(ActionEvent e) {
310 if (label == null) {
311 return;
312 }
313
314 LabelOptionHandler oh = new LabelOptionHandler(label, getGraph2D());
315 oh.showEditor(null, OptionHandler.OK_CANCEL_BUTTONS);
316 }
317 });
318 return pm;
319 }
320
321
329 private Object calculateBestParameter( final Edge e, final EdgeLabel label ) {
330 if (lastPressEvent == null) {
331 return null;
332 }
333
334 YList occupiedRectList = new YList();
336 Graph2D graph = view.getGraph2D();
337 EdgeRealizer er = graph.getRealizer(e);
338 for (int i = 0, n = er.labelCount(); i < n; ++i) {
339 EdgeLabel el = er.getLabel(i);
340 if (el != label) {
341 occupiedRectList.add(el.getOrientedBox());
342 }
343 }
344
345 final YPoint mousePressedEventLocation = new YPoint(
347 view.toWorldCoordX(lastPressEvent.getX()),
348 view.toWorldCoordY(lastPressEvent.getY()));
349 double minDist = Double.MAX_VALUE;
350 LabelCandidate chosen = null;
351 YList candidates = label.getLabelModel().getLabelCandidates(
352 label, er, er.getSourceRealizer(), er.getTargetRealizer());
353 for (YCursor cu = candidates.cursor(); cu.ok(); cu.next()) {
354 LabelCandidate lc = (LabelCandidate) cu.current();
355
356 boolean isOccupied = false;
357 YRectangle bBox = lc.getBox().getBoundingBox();
358 for (YCursor cur = occupiedRectList.cursor(); cur.ok() && !isOccupied; cur.next()) {
359 if (OrientedRectangle.intersects((OrientedRectangle) cur.current(), bBox, 0)) {
360 isOccupied = true;
361 break;
362 }
363 }
364
365 if (!isOccupied) {
366 double dist = YPoint.distance(mousePressedEventLocation, lc.getBox().getCenter());
367 if (dist < minDist) {
368 minDist = dist;
369 chosen = lc;
370 }
371 }
372 }
373
374 return chosen == null ? null : chosen.getModelParameter();
375 }
376 }
377
378
383 private static final class LabelOptionHandler extends OptionHandler {
384 static final String LABEL_TEXT = "Label Text";
385 static final String FONT_SIZE = "Font Size";
386 static final String ROTATION_ANGLE = "Rotation Angle";
387 static final String AUTO_ROTATION = "Auto Rotation";
388
389 private final YLabel label;
390 private final Graph2D graph;
391 private final boolean isEdgeLabel;
392
393
399 LabelOptionHandler( final YLabel label, final Graph2D graph ) {
400 super("Label Options");
401 this.label = label;
402 this.graph = graph;
403 this.isEdgeLabel = label instanceof EdgeLabel;
404 addString(LABEL_TEXT, label.getText(), 5);
405 addInt(FONT_SIZE, label.getFontSize());
406 int value = 0;
407 if (isEdgeLabel) {
408 final EdgeLabel el = (EdgeLabel) label;
409 if (el.getLabelModel() instanceof SmartEdgeLabelModel) {
410 value = toDegrees(2*Math.PI - SmartEdgeLabelModel.getAngle(el.getModelParameter()));
415 }
416 } else {
417 value = toDegrees(label.getOrientedBox().getAngle());
418 }
419 while (value < 0) {
420 value += 360;
421 }
422 addInt(ROTATION_ANGLE, value, 0, 360);
423 if (isEdgeLabel) {
424 final EdgeLabel el = (EdgeLabel) label;
425 if (el.getLabelModel() instanceof SmartEdgeLabelModel) {
426 SmartEdgeLabelModel model = (SmartEdgeLabelModel) el.getLabelModel();
427 addBool(AUTO_ROTATION, model.isAutoRotationEnabled());
428 }
429 }
430 }
431
432 public void commitValues() {
433 super.commitValues();
434 label.setText(getString(LABEL_TEXT));
435 label.setFontSize(getInt(FONT_SIZE));
436
437 final OrientedRectangle box = label.getOrientedBox();
438 final YPoint center = box.getCenter();
439 box.setAngle(Math.toRadians(getInt(ROTATION_ANGLE)));
440 box.setCenter(center);
441
442 if (isEdgeLabel && ((EdgeLabel) label).getLabelModel() instanceof SmartEdgeLabelModel) {
443 final EdgeLabel el = (EdgeLabel) label;
444 final EdgeRealizer er = el.getRealizer();
445 final SmartEdgeLabelModel model = (SmartEdgeLabelModel) el.getLabelModel();
446 model.setAutoRotationEnabled(getBool(AUTO_ROTATION));
447 el.setModelParameter(model.createRelativeModelParameter(
448 box,
449 er,
450 er.getSourceRealizer(),
451 er.getTargetRealizer()));
452 } else {
453 label.setModelParameter(label.getBestModelParameterForBounds(box));
454 }
455
456 graph.updateViews();
457 }
458
459 private static int toDegrees( final double angle ) {
460 return ((int) Math.rint(Math.toDegrees(angle))) % 360;
461 }
462 }
463 }
464