]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/elements/TextElementNoBounds.java
Fixed Path2D creation to work with overlapping RoutePoints
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / elements / TextElementNoBounds.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.elements;
13
14 import java.awt.Color;
15 import java.awt.Font;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Rectangle2D;
18 import java.util.function.Consumer;
19
20 import org.simantics.g2d.canvas.ICanvasContext;
21 import org.simantics.g2d.diagram.DiagramUtils;
22 import org.simantics.g2d.diagram.IDiagram;
23 import org.simantics.g2d.element.ElementHints;
24 import org.simantics.g2d.element.ElementUtils;
25 import org.simantics.g2d.element.IElement;
26 import org.simantics.g2d.element.SceneGraphNodeKey;
27 import org.simantics.g2d.element.handler.HandleMouseEvent;
28 import org.simantics.g2d.element.handler.SceneGraph;
29 import org.simantics.g2d.utils.Alignment;
30 import org.simantics.scenegraph.g2d.G2DParentNode;
31 import org.simantics.scenegraph.g2d.events.MouseEvent;
32 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;
33 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;
34 import org.simantics.utils.datastructures.hints.IHintContext.Key;
35
36 /**
37  * ElementHandler for text elements
38  * In-line editing supported.
39  * 
40  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
41  */
42 public class TextElementNoBounds implements SceneGraph, HandleMouseEvent {
43
44     private static final long serialVersionUID = -148784588840819612L;
45
46     public static final TextElementNoBounds INSTANCE         = new TextElementNoBounds();
47
48     public static final Key                 SG_NODE          = new SceneGraphNodeKey(TextNode.class, "TEXT_SG_NODE");
49     
50     protected static final double DEFAULT_PADDING_X = 0.5;
51     protected static final double DEFAULT_PADDING_Y = 0.5;
52     protected static final double SCALE = 0.235;
53
54     protected final double originX;
55     protected final double originY;
56     protected final Alignment horizontalAlignment;
57     protected final Alignment verticalAlignment;
58     protected final double borderWidth;
59     protected final boolean editable;
60     protected final double paddingX;
61     protected final double paddingY;
62
63
64     public TextElementNoBounds() {
65         this(0, 0, Alignment.LEADING, 0);
66     }
67
68     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment) {
69         this(originX, originY, horizontalAlignment, 0);
70     }
71
72     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth) {
73         this(originX, originY, horizontalAlignment, borderWidth, DEFAULT_PADDING_X, DEFAULT_PADDING_Y, true);
74     }
75     
76     public TextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable) {
77         if (horizontalAlignment == null)
78             throw new NullPointerException("null horizontal alignment");
79
80         this.originX = originX;
81         this.originY = originY;
82         this.horizontalAlignment = horizontalAlignment;
83         this.verticalAlignment = Alignment.BASELINE;
84         this.borderWidth = borderWidth;
85         this.editable = editable;
86         this.paddingX = paddingX;
87         this.paddingY = paddingY;
88     }
89     
90
91     @Override
92     public void init(final IElement e, G2DParentNode parent) {
93         TextNode node = getOrCreateTextNode(e, parent);
94
95         Font font = ElementUtils.getTextFont(e);
96         Color color = ElementUtils.getTextColor(e);
97         Color fillColor = ElementUtils.getFillColor(e);
98         Color borderColor = ElementUtils.getBorderColor(e, Color.BLACK);
99         String text = ElementUtils.getText(e);
100         AffineTransform at = ElementUtils.getTransform(e);
101         Alignment hAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, horizontalAlignment);
102         Alignment vAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_VERTICAL_ALIGN, verticalAlignment);
103         Double borderWidth = ElementUtils.getHintOrDefault(e, MonitorClass.KEY_BORDER_WIDTH, this.borderWidth);
104
105         node.init(text, font, color, originX, originY, SCALE);
106         node.setBackgroundColor(fillColor);
107         node.setBorderColor(borderColor);
108         node.setHorizontalAlignment((byte) hAlign.ordinal());
109         node.setVerticalAlignment((byte) vAlign.ordinal());
110         node.setPadding(paddingX, paddingY);
111         node.setBorderWidth(borderWidth.floatValue());
112         node.setEditable(editable);
113         if (at != null)
114             node.setTransform(at);
115         
116         if(Boolean.TRUE.equals(ElementUtils.getHintOrDefault(e, ElementHints.KEY_RESIZABLE, false))) {
117             Rectangle2D bounds = e.getHint(ElementHints.KEY_BOUNDS);
118             if(bounds != null) {
119                 node.setTargetBounds(bounds);
120                 node.setWrapText(true);
121             }
122         }
123     }
124     
125     protected TextNode getOrCreateTextNode(IElement e, G2DParentNode parent) {
126         return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", TextNode.class, new TextNodeCallBack(e));
127     }
128     
129     private class TextNodeCallBack implements Consumer<TextNode> {
130         
131         IElement e;
132         
133         public TextNodeCallBack(IElement e) {
134             this.e = e;
135         }
136         
137         @Override
138         public void accept(TextNode node) {
139             node.setTextListener(new ITextListener() {
140                 @Override
141                 public void textChanged() {}
142
143                 @Override
144                 public void textEditingStarted() {}
145
146                 @Override
147                 public void textEditingCancelled() {
148                     TextNode node = (TextNode) e.getHint(SG_NODE);
149                     if (node != null)
150                         endEdit(node);
151                 }
152
153                 @Override
154                 public void textEditingEnded() {
155                     TextNode node = (TextNode) e.getHint(SG_NODE);
156                     if (node == null)
157                         return;
158                     //System.out.println("Node text changed: " + node.getText());
159                     ElementUtils.setText(e, node.getText());
160                     IDiagram diagram = ElementUtils.getDiagram(e);
161                     DiagramUtils.synchronizeHintsToBackend(diagram, e);
162                     endEdit(node);
163                 }
164             });
165         }
166     }
167
168     @Override
169     public void cleanup(IElement e) {
170         ElementUtils.removePossibleNode(e, SG_NODE);
171     }
172
173     // FIXME: hazardous with TextElementHandler.INSTANCE
174     TextEditActivation editActivation = null;
175
176     @Override
177     public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) {
178         if (me instanceof MouseEnterEvent) {
179             e.setHint(ElementHints.KEY_HOVER, true);
180         } else if (me instanceof MouseExitEvent) {
181             e.setHint(ElementHints.KEY_HOVER, false);
182         }
183
184         return false;
185     }
186
187     protected void endEdit(TextNode node) {
188         if (editActivation != null) {
189             editActivation.release();
190             editActivation = null;
191
192             node.setEditMode(false);
193             node.repaint();
194         }
195     }
196
197     @Override
198     public int hashCode() {
199         final int prime = 31;
200         int result = 1;
201         long temp;
202         temp = Double.doubleToLongBits(borderWidth);
203         result = prime * result + (int) (temp ^ (temp >>> 32));
204         result = prime * result + horizontalAlignment.hashCode();
205         temp = Double.doubleToLongBits(originX);
206         result = prime * result + (int) (temp ^ (temp >>> 32));
207         temp = Double.doubleToLongBits(originY);
208         result = prime * result + (int) (temp ^ (temp >>> 32));
209         temp = Double.doubleToLongBits(paddingX);
210         result = prime * result + (int) (temp ^ (temp >>> 32));
211         temp = Double.doubleToLongBits(paddingY);
212         result = prime * result + (int) (temp ^ (temp >>> 32));
213         return result;
214     }
215
216     @Override
217     public boolean equals(Object obj) {
218         if (this == obj)
219             return true;
220         if (obj == null)
221             return false;
222         if (getClass() != obj.getClass())
223             return false;
224         TextElementNoBounds other = (TextElementNoBounds) obj;
225         if (Double.doubleToLongBits(borderWidth) != Double.doubleToLongBits(other.borderWidth))
226             return false;
227         if (horizontalAlignment != other.horizontalAlignment)
228             return false;
229         if (Double.doubleToLongBits(originX) != Double.doubleToLongBits(other.originX))
230             return false;
231         if (Double.doubleToLongBits(originY) != Double.doubleToLongBits(other.originY))
232             return false;
233         if (Double.doubleToLongBits(paddingX) != Double.doubleToLongBits(other.paddingX))
234             return false;
235         if (Double.doubleToLongBits(paddingY) != Double.doubleToLongBits(other.paddingY))
236             return false;
237         return true;
238     }
239     
240     
241
242 }