]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
5b5b3aff7f9eace2f45c29650a3a71ad43d3f410
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2010 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.sysdyn.ui.properties.widgets.expressions;\r
13 \r
14 import java.util.List;\r
15 \r
16 import org.eclipse.jface.layout.GridDataFactory;\r
17 import org.eclipse.jface.layout.GridLayoutFactory;\r
18 import org.eclipse.jface.resource.JFaceResources;\r
19 import org.eclipse.jface.resource.LocalResourceManager;\r
20 import org.eclipse.jface.text.Document;\r
21 import org.eclipse.jface.text.IDocument;\r
22 import org.eclipse.jface.text.PaintManager;\r
23 import org.eclipse.jface.text.Position;\r
24 import org.eclipse.jface.text.source.Annotation;\r
25 import org.eclipse.jface.text.source.AnnotationModel;\r
26 import org.eclipse.jface.text.source.AnnotationPainter;\r
27 import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;\r
28 import org.eclipse.jface.text.source.IAnnotationAccess;\r
29 import org.eclipse.jface.text.source.MatchingCharacterPainter;\r
30 import org.eclipse.jface.text.source.SourceViewer;\r
31 import org.eclipse.swt.SWT;\r
32 import org.eclipse.swt.custom.StyledText;\r
33 import org.eclipse.swt.custom.VerifyKeyListener;\r
34 import org.eclipse.swt.events.FocusEvent;\r
35 import org.eclipse.swt.events.FocusListener;\r
36 import org.eclipse.swt.events.KeyEvent;\r
37 import org.eclipse.swt.events.KeyListener;\r
38 import org.eclipse.swt.events.VerifyEvent;\r
39 import org.eclipse.swt.graphics.Color;\r
40 import org.eclipse.swt.graphics.Point;\r
41 import org.eclipse.swt.graphics.RGB;\r
42 import org.eclipse.swt.widgets.Composite;\r
43 import org.eclipse.swt.widgets.Table;\r
44 import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;\r
45 import org.simantics.sysdyn.ui.utils.SyntaxError;\r
46 \r
47 /**\r
48  * Field for displaying a part of an expression. Expression field uses SourceViewer\r
49  * to display annotations and other visual elements just like any other\r
50  * source viewer in eclipse.\r
51  * \r
52  * @author Teemu Lempinen\r
53  * @author Tuomas Miettinen\r
54  *\r
55  */\r
56 public class ExpressionField extends Composite {\r
57 \r
58     protected SourceViewer                  _sourceViewer;\r
59     protected IDocument                     _document;\r
60     protected AnnotationModel               _annotationModel;\r
61     \r
62     public static final String MISSING_LINK = "MissingLink";\r
63     public static final String NO_SUCH_VARIABLE = "NoSuchVariable";\r
64     public static final String SYNTAX_ERROR = "SyntaxError";\r
65     public static final String SYNTAX_WARNING = "SyntaxWarning";\r
66 \r
67     String oldExpression;\r
68 \r
69     IAnnotationAccess annotationAccess = new DefaultMarkerAnnotationAccess();\r
70 \r
71     ExpressionFieldConfiguration expressionFieldConfiguration;\r
72     \r
73     private final LocalResourceManager resourceManager;\r
74     private final RGB warningRGB = new RGB(255,215,0);\r
75     private final RGB errorRGB = new RGB(255,0,0);\r
76 \r
77     /**\r
78      * Create a new expression field\r
79      * @param parent\r
80      * @param style\r
81      */\r
82     public ExpressionField(Composite parent, int style, Table allowedVariables, boolean allowFunctions, ExpressionWidgetInput input) {\r
83         super(parent, style);\r
84         \r
85         // Create a ResourceManager to dispose images when the widget is disposed.\r
86         this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), this);\r
87         \r
88         GridLayoutFactory.fillDefaults().applyTo(this);\r
89         \r
90         int styles = SWT.V_SCROLL\r
91         | SWT.MULTI\r
92         | SWT.FULL_SELECTION\r
93         | SWT.WRAP;\r
94 \r
95         _document = new Document();\r
96         _document.set("");\r
97 \r
98         _annotationModel = new AnnotationModel();\r
99         _annotationModel.connect(_document);\r
100 \r
101         _sourceViewer = new SourceViewer(this,\r
102 \r
103                 null,\r
104                 null,\r
105                 true,\r
106                 styles);\r
107         \r
108         // Configuration for color management\r
109         expressionFieldConfiguration = new ExpressionFieldConfiguration(\r
110                 new LocalResourceManager(JFaceResources.getResources(), _sourceViewer.getControl()), \r
111                 allowedVariables, allowFunctions, input);\r
112         _sourceViewer.configure(expressionFieldConfiguration);\r
113         AnnotationPainter painter = new AnnotationPainter(_sourceViewer, annotationAccess);\r
114         _sourceViewer.addPainter(painter);\r
115 \r
116         // Annotation types\r
117         Color warningColor =  resourceManager.createColor(warningRGB);\r
118         Color errorColor = resourceManager.createColor(errorRGB);\r
119         painter.addAnnotationType(MISSING_LINK);\r
120         painter.setAnnotationTypeColor(MISSING_LINK, warningColor);\r
121         painter.addAnnotationType(NO_SUCH_VARIABLE);\r
122         painter.setAnnotationTypeColor(NO_SUCH_VARIABLE, errorColor);\r
123         painter.addAnnotationType(SYNTAX_ERROR);\r
124         painter.setAnnotationTypeColor(SYNTAX_ERROR, errorColor);        \r
125         painter.addAnnotationType(SYNTAX_WARNING);\r
126         painter.setAnnotationTypeColor(SYNTAX_WARNING, warningColor);\r
127         \r
128         _sourceViewer.setDocument(_document, _annotationModel);\r
129 \r
130         GridDataFactory.fillDefaults().grab(true, true).applyTo(_sourceViewer.getControl());\r
131 \r
132         // Parenthesis matching\r
133         PaintManager paintManager = new PaintManager(_sourceViewer);\r
134         MatchingCharacterPainter matchingCharacterPainter = new MatchingCharacterPainter(_sourceViewer,\r
135                 new DefaultCharacterPairMatcher( new char[] {'(', ')', '{', '}', '[', ']'} ));\r
136         matchingCharacterPainter.setColor(resourceManager.createColor(new RGB(160, 160, 160)));\r
137         paintManager.addPainter(matchingCharacterPainter);\r
138         \r
139         \r
140         // Listener for canceling editing. ESC -> revert back to original text\r
141         _sourceViewer.getTextWidget().addKeyListener(new KeyListener() {\r
142 \r
143             @Override\r
144             public void keyReleased(KeyEvent e) {\r
145             }\r
146 \r
147             @Override\r
148             public void keyPressed(KeyEvent e) {\r
149                 // Check if the expression field has an active completion assistant\r
150                                 if (!isAssistSessionActive()) {\r
151                                         if(e.keyCode == SWT.ESC && getExpression() != null) {\r
152                             ((StyledText)e.widget).setText(oldExpression);\r
153                             ((StyledText)e.widget).setSelection(getExpression().length());\r
154                                         }\r
155                 }   \r
156             }\r
157         });\r
158        \r
159         /* Focus listener saving and restoring selections\r
160          * When focus is lost, current selection is saved, but the selection is removed.\r
161          * When focus is gained back, the selection is restored\r
162          */\r
163         _sourceViewer.getTextWidget().addFocusListener(new FocusListener() {\r
164             \r
165             Point selection = null;\r
166             @Override\r
167             public void focusLost(FocusEvent e) {\r
168                 selection = ((StyledText)e.widget).getSelection();\r
169                 ((StyledText)e.widget).setSelection(0);\r
170             }\r
171             \r
172             @Override\r
173             public void focusGained(FocusEvent e) {\r
174                 if(selection != null)\r
175                     ((StyledText)e.widget).setSelection(selection);\r
176             }\r
177         });\r
178         \r
179         _sourceViewer.appendVerifyKeyListener(new VerifyKeyListener() {\r
180                         @Override\r
181                         public void verifyKey(VerifyEvent event) {\r
182                                 // Check for Ctrl+Spacebar\r
183                                 if (event.stateMask == SWT.CTRL && event.character == ' ') {\r
184                                         // Check if source viewer is able to perform operation\r
185                                         if (_sourceViewer.canDoOperation(SourceViewer.CONTENTASSIST_PROPOSALS)) {\r
186                                                 // Perform operation\r
187                                                 _sourceViewer.doOperation(SourceViewer.CONTENTASSIST_PROPOSALS);\r
188                                         }\r
189                                         // Veto this key press to avoid further processing\r
190                                         event.doit = false;\r
191                                 }\r
192                         }\r
193 \r
194                 });\r
195         \r
196     }\r
197 \r
198     /**\r
199      * Returns the {@link SourceViewer} of this ExpressionField\r
200      * @return Returns the {@link SourceViewer} of this ExpressionField\r
201      */\r
202     public SourceViewer getSourceViewer() {\r
203         return this._sourceViewer;\r
204     }\r
205     \r
206         public boolean isAssistSessionActive() {\r
207                 return expressionFieldConfiguration.isAssistSessionActive();\r
208         }\r
209 \r
210     /**\r
211      * Sets missing link annotations to given positions\r
212      * @param positions Positions for missing link annotations\r
213      */\r
214     public void setMissingLinkAnnotations(List<Position> positions){\r
215         for(Position p : positions) {\r
216             Annotation annotation = new Annotation(false);\r
217             annotation.setType(MISSING_LINK);\r
218             annotation.setText("No link to this variable");\r
219             _annotationModel.addAnnotation(annotation, p);        \r
220         }\r
221     }\r
222     \r
223     /**\r
224      * Sets no such variable annotations to given positions\r
225      * @param positions Positions for no such variable annotations\r
226      */\r
227     public void setNoSuchVariableAnnotations(List<Position> positions){\r
228         for(Position p : positions) {\r
229             Annotation annotation = new Annotation(false);\r
230             annotation.setType(NO_SUCH_VARIABLE);\r
231             annotation.setText("No such variable in model");\r
232             _annotationModel.addAnnotation(annotation, p);        \r
233         }\r
234     }\r
235 \r
236     \r
237     /**\r
238      * Sets a syntax error annoattion to the expression field\r
239      * @param syntaxError\r
240      */\r
241     public void setSyntaxError(SyntaxError syntaxError) {\r
242         Annotation annotation = new Annotation(false);\r
243         annotation.setType(syntaxError.getType());\r
244         annotation.setText(syntaxError.getMessage());\r
245         Position p = new Position(syntaxError.getStart(_document), syntaxError.getOffset(_document));\r
246         _annotationModel.addAnnotation(annotation, p);      \r
247     }\r
248 \r
249     /**\r
250      * Resets all annotations\r
251      */\r
252     public void resetAnnotations() {\r
253         _annotationModel.removeAllAnnotations();\r
254     }\r
255     \r
256     /**\r
257      * Sets an expression to this expression field\r
258      * @param expression\r
259      */\r
260     public void setExpression(String expression) {\r
261         _document.set(expression);\r
262         this.oldExpression = expression;\r
263     }\r
264 \r
265     /**\r
266      * Returns the expression of this expression field\r
267      * @return\r
268      */\r
269     public String getExpression() {\r
270         return this._document.get();\r
271     }\r
272 \r
273     /**\r
274      * Returns the current selection\r
275      * @return current selection\r
276      */\r
277     public Point getSelection() {\r
278         return _sourceViewer.getSelectedRange();\r
279     }\r
280 \r
281     /**\r
282      * Set selection for this expression field. The length of the selection is 0\r
283      * @param selection Selection location\r
284      */\r
285     public void setSelection(int selection) {\r
286         this._sourceViewer.setSelectedRange(selection, 0);\r
287     }\r
288 \r
289     public IDocument getDocument() {\r
290         return _document;\r
291     }\r
292 \r
293     /**\r
294      * Focus to this expression field\r
295      */\r
296     public void focus() {\r
297         this._sourceViewer.getTextWidget().forceFocus();\r
298     }\r
299 \r
300 }\r