]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/elements/EditorStateManager.java
Editing of texts inside SVG elements
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / elements / EditorStateManager.java
1 package org.simantics.diagram.elements;
2
3 import java.awt.geom.Point2D;
4 import java.awt.geom.Rectangle2D;
5 import java.util.LinkedList;
6 import java.util.List;
7
8 import org.simantics.db.common.utils.Logger;
9 import org.simantics.diagram.elements.EditorState.ModificationClass;
10 import org.simantics.g2d.canvas.ICanvasContext;
11 import org.simantics.g2d.element.IElement;
12 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
13 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;
14 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
15 import org.simantics.scl.runtime.function.Function1;
16 import org.simantics.scl.runtime.function.Function2;
17
18 import com.kitfox.svg.SVGDiagram;
19 import com.kitfox.svg.SVGElement;
20 import com.kitfox.svg.SVGException;
21 import com.kitfox.svg.Text;
22 import com.kitfox.svg.Tspan;
23 import com.kitfox.svg.animation.AnimationElement;
24
25 /**
26  * @author Antti Villberg
27  * @since 1.31.0
28  */
29 class EditorStateManager {
30
31         static String TERM_STRING = "-----";
32         static String EDITOR_CLASS = "edit";
33         static String EDITOR_ID = "edit";
34         private SVGNode node;
35
36         private LinkedList<EditorState> editorState = null;
37         private int editorStateIndex = 0;
38
39         EditorStateManager(SVGNode node) {
40                 this.node = node;
41         }
42
43         public boolean isEditMode() {
44                 return editorState != null;
45         }
46
47         public EditorState currentState() {
48                 return editorState.get(editorStateIndex);
49         }
50
51         public int currentHash() {
52                 if(!isEditMode()) return 0;
53                 return currentState().hashCode();
54         }
55
56         public void activateEditMode(SVGDiagram diagram, Text text) {
57
58                 if(isEditMode()) return;
59
60                 if(text.getId().length() == 0) return;
61
62                 EditorState es = new EditorState();
63                 es.base = new EditorStateStatic();
64                 es.base.textElementId = text.getId();
65
66                 Tspan span = (Tspan)text.getContent().get(0);
67                 String currentText = span.getText();
68
69                 SingleElementNode sne = node.getSingleElementNode();
70                 Function1<String,String> fullTextFunction = sne.getParameter("textEditorFullText"); 
71                 if(fullTextFunction != null)
72                         es.currentText = fullTextFunction.apply(es.base.textElementId);
73                 if(es.currentText == null) {
74                         es.currentText = currentText;
75                 }
76
77                 es.caretPosition = es.currentText.length();
78                 es.selectionOtherPosition = 0;
79
80                 // Measure the Y-dimensions of the font
81                 try {
82                         span.setText("Ig");
83                         text.rebuild();
84                         diagram.updateTime(0);
85                         es.base.verticalDimensions = text.getBoundingBox(); 
86                         span.setText(TERM_STRING);
87                         text.rebuild();
88                         diagram.updateTime(0);
89                         es.base.termStringWidth = text.getBoundingBox().getWidth(); 
90                         span.setText(currentText);
91                         text.rebuild();
92                         diagram.updateTime(0);
93                 } catch (SVGException e) {
94                         e.printStackTrace();
95                 }
96
97                 ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node);
98                 IElement ie = DiagramNodeUtil.getElement(ctx, sne);
99
100                 EditDataNode data = EditDataNode.getNode(node);
101                 deactivateEdit(data, null);
102                 TextEditActivation result = new TextEditActivation(0, ie, ctx);
103                 data.setTextEditActivation(result);
104
105                 editorState = new LinkedList<>();
106                 editorState.push(es);
107                 editorStateIndex = 0;
108
109                 paint();
110
111         }
112
113         private TextEditActivation editActivation;
114
115         void applyEdit() {
116                 SingleElementNode sne = node.getSingleElementNode();
117                 EditorState es = currentState();
118                 Function2<String,String,Object> editor = sne.getParameter("textEditor");
119                 if(editor != null) {
120                         editor.apply(es.base.textElementId, es.currentText);
121                 }
122         }
123
124         protected boolean deactivateEdit() {
125                 boolean result = deactivateEdit( editActivation );
126                 result |= editActivation != null;
127                 editActivation = null;
128                 editorState = null;
129                 paint();
130                 return result;
131         }
132
133         protected boolean deactivateEdit(TextEditActivation activation) {
134                 return deactivateEdit( EditDataNode.getNode(node), activation );
135         }
136
137         protected boolean deactivateEdit(EditDataNode data, TextEditActivation activation) {
138                 TextEditActivation previous = data.getTextEditActivation();
139                 if (previous != null && (previous == activation || activation == null)) {
140                         previous.release();
141                         data.setTextEditActivation(null);
142                         return true;
143                 }
144                 return false;
145         }
146
147         protected boolean keyPressed(KeyPressedEvent e) {
148                 if(isEditMode()) {
149                         EditorState es = currentState();
150                         EditorState nes = es.copy();
151                         if(nes.keyPressed(this, e)) {
152                                 if(!isEditMode()) {
153                                         // This key actually terminated editing
154                                         return true;
155                                 }
156                                 if(nes.shouldReplace(es)) {
157                                         es.replace(nes);
158                                 } else {
159                                         while(editorState.size() > (editorStateIndex + 1))
160                                                 editorState.removeLast();
161                                         editorState.add(nes);
162                                         editorStateIndex = editorState.size() - 1;
163                                 }
164                                 return true; 
165                         }
166                 }
167                 return false;
168         }
169
170
171         public boolean tryToStartEditMode(SVGDiagram diagram) {
172                 SVGElement element = diagram.getElement(EDITOR_ID);
173                 if(element != null && element instanceof Text) {
174                         activateEditMode(diagram, (Text)element);
175                         return true;
176                 }
177                 return false;
178         }
179
180         public boolean tryToStartEditMode(SVGDiagram diagram, MouseClickEvent e) {
181
182                 if(diagram != null) {
183
184                         Point2D local = node.controlToLocal( e.controlPosition );
185                         // FIXME: once the event coordinate systems are cleared up, remove this workaround
186                         local = node.parentToLocal(local);
187
188                         double tolerance = 2.0;
189                         Rectangle2D pickRect = new Rectangle2D.Double(local.getX()-tolerance, local.getY()-tolerance, 2*tolerance, 2*tolerance); 
190
191                         try {
192                                 List<?> retVec = diagram.pick(pickRect, null);
193                                 for(int i=0;i<retVec.size();i++) {
194                                         List<?> l = (List<?>)retVec.get(i);
195                                         for(int j=0;j<l.size();j++) {
196                                                 SVGElement element = (SVGElement)l.get(j);      
197                                                 if(element instanceof Tspan) {
198                                                         return true;
199                                                 }
200                                                 if(element instanceof Text) {
201                                                         Text text = (Text)element;
202                                                         if(text.hasAttribute("class", AnimationElement.AT_XML)) {
203                                                                 String clazz = text.getPresAbsolute("class").getStringValue();
204                                                                 if(clazz.contains(EDITOR_CLASS)) {
205                                                                         activateEditMode(diagram, text);
206                                                                         return true;
207                                                                 }
208                                                         }
209                                                 }
210                                         }
211                                 }
212
213                         } catch (SVGException e1) {
214                                 Logger.defaultLogError(e1);
215                         }
216                 }
217
218                 return false;
219
220         }
221
222         boolean applyEditMode(SVGDiagram diagram) throws SVGException {
223
224                 if(isEditMode()) {
225                         EditorState es = currentState();
226                         es.applyEditMode(diagram);
227                         return true;
228                 }
229
230                 return false;
231
232         }
233
234         void paint() {
235                 node.cleanDiagramCache();
236                 node.repaint();
237         }
238
239         void undo() {
240                 while(editorStateIndex > 0 && currentState().modificationClass.equals(ModificationClass.NO_EDIT)) {
241                         editorStateIndex--;
242                 }
243                 if(editorStateIndex > 0)
244                         editorStateIndex--;
245                 paint();
246         }
247
248         void redo() {
249                 while(editorStateIndex < editorState.size() - 1 && currentState().modificationClass.equals(ModificationClass.NO_EDIT)) {
250                         editorStateIndex++;
251                 }
252                 if(editorStateIndex < editorState.size() - 1) {
253                         editorStateIndex++;
254                 }
255                 paint();
256         }
257
258 }