| UmlClassLabelEditMode.java |
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.view.uml;
29
30 import y.base.Node;
31 import y.base.NodeList;
32 import y.geom.YPoint;
33 import y.view.Graph2D;
34 import y.view.HitInfo;
35 import y.view.NodeLabel;
36 import y.view.NodeRealizer;
37 import y.view.ViewMode;
38
39 import java.beans.PropertyChangeEvent;
40 import java.beans.PropertyChangeListener;
41
42 /**
43 * Custom {@link ViewMode} for special label handling of the UML class nodes:
44 * <ul>
45 * <li>The labels for the name, the attributes and the operations open a label editor when double-clicked.</li>
46 * <li>The labels for attribute and operation caption are not editable.</li>
47 * <li>An {@link UmlClassLabelEditMode.LabelChangeHandler label change handler} changes the text of the label after
48 * editing.</li>
49 * </ul>
50 */
51 class UmlClassLabelEditMode extends ViewMode {
52
53 /**
54 * Reacts to double-clicks on labels for the name, the attributes and the operations by presenting a label editor.
55 * Reacts to single-clicks on labels for attributes or operations to select the label.
56 *
57 * @param x the x-coordinate of the mouse event in world coordinates.
58 * @param y the y-coordinate of the mouse event in world coordinates.
59 */
60 public void mouseClicked(double x, double y) {
61 final HitInfo hitInfo = getHitInfo(x, y);
62 final NodeRealizer singleClickedNode = getSingleClickedNode(hitInfo);
63 if (singleClickedNode != null) {
64 if (UmlClassLabelSupport.selectListItemAt(singleClickedNode, x, y)) {
65 view.updateView();
66 }
67 }
68
69 final NodeLabel doubleClickedLabel = getDoubleClickedLabel(hitInfo, x, y);
70 if (doubleClickedLabel != null && !UmlClassLabelSupport.isCaptionLabel(doubleClickedLabel)) {
71 // Caption labels are not editable.
72 editLabel(doubleClickedLabel);
73 }
74 }
75
76 /**
77 * Returns the label at the given location if it has been double clicked; null otherwise.
78 */
79 private NodeLabel getDoubleClickedLabel(final HitInfo hitInfo, final double x, final double y) {
80 if (lastClickEvent != null && lastClickEvent.getClickCount() == 2) {
81 if (hitInfo.hasHitNodeLabels()) {
82 return hitInfo.getHitNodeLabel();
83 } else if (hitInfo.hasHitNodes()) {
84 final NodeRealizer realizer = view.getGraph2D().getRealizer(hitInfo.getHitNode());
85 for (int i = realizer.labelCount(); i-- > 0; ) {
86 final NodeLabel label = realizer.getLabel(i);
87 if (label.contains(x, y)) {
88 return label;
89 }
90 }
91 }
92 }
93 return null;
94 }
95
96 /**
97 * Returns the node realizer at the given position if it has been single clicked; null otherwise.
98 */
99 private NodeRealizer getSingleClickedNode(final HitInfo hitInfo) {
100 if (hitInfo.hasHitNodeLabels()) {
101 return hitInfo.getHitNodeLabel().getRealizer();
102 } else if (hitInfo.hasHitNodes()) {
103 return view.getGraph2D().getRealizer(hitInfo.getHitNode());
104 } else {
105 return null;
106 }
107 }
108
109 /**
110 * Opens the given label with an label editor
111 */
112 private void editLabel(final NodeLabel label) {
113 if (!UmlClassLabelSupport.isCaptionLabel(label)) {
114 final YPoint location = label.getTextLocation();
115 view.openLabelEditor(label, location.getX(), location.getY(), new LabelChangeHandler(), true, false);
116 }
117 }
118
119 /**
120 * This handler listens for label changes and adjusts the node size to
121 * the label size.
122 */
123 private class LabelChangeHandler implements PropertyChangeListener {
124 public void propertyChange(PropertyChangeEvent e) {
125 final Object source = e.getSource();
126 if (source instanceof NodeLabel) {
127 final Graph2D graph = getGraph2D();
128 final NodeLabel label = (NodeLabel) source;
129 final Node node = label.getNode();
130 final NodeRealizer realizer = graph.getRealizer(node);
131
132 // Do not allow an empty name label.
133 graph.firePreEvent();
134 graph.backupRealizers(new NodeList(node).nodes());
135 graph.backupRealizers(node.edges());
136 try {
137 if ("".equals(e.getNewValue())) {
138 // Remove empty label.
139 label.setText(" ");
140 final UmlClassAnimation animation = new UmlClassRemoveItemButton.RemoveItemAnimation(view, realizer, true);
141 animation.play();
142 } else {
143 // Set the text of the label.
144 label.setText((String) e.getNewValue());
145 UmlClassLabelSupport.updateLabelText(realizer, label);
146 UmlClassLabelSupport.selectLabel(realizer, label);
147 UmlClassLabelSupport.updateRealizerSize(realizer);
148 }
149 } finally {
150 graph.firePostEvent();
151 }
152 }
153 }
154 }
155 }