]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.ui.editor/src/org/simantics/scl/ui/editor/SCLTextEditor.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.ui.editor / src / org / simantics / scl / ui / editor / SCLTextEditor.java
1 package org.simantics.scl.ui.editor;\r
2 \r
3 \r
4 import java.util.Collection;\r
5 import java.util.Iterator;\r
6 \r
7 import org.eclipse.jface.resource.ImageRegistry;\r
8 import org.eclipse.jface.text.Document;\r
9 import org.eclipse.jface.text.ITextListener;\r
10 import org.eclipse.jface.text.Position;\r
11 import org.eclipse.jface.text.TextEvent;\r
12 import org.eclipse.jface.text.source.Annotation;\r
13 import org.eclipse.jface.text.source.AnnotationModel;\r
14 import org.eclipse.jface.text.source.AnnotationPainter;\r
15 import org.eclipse.jface.text.source.IAnnotationModel;\r
16 import org.eclipse.jface.text.source.ISharedTextColors;\r
17 import org.eclipse.jface.text.source.OverviewRuler;\r
18 import org.eclipse.jface.text.source.SourceViewer;\r
19 import org.eclipse.jface.text.source.VerticalRuler;\r
20 import org.eclipse.swt.SWT;\r
21 import org.eclipse.swt.events.KeyAdapter;\r
22 import org.eclipse.swt.events.KeyEvent;\r
23 import org.eclipse.swt.graphics.Point;\r
24 import org.eclipse.swt.graphics.RGB;\r
25 import org.eclipse.swt.layout.FillLayout;\r
26 import org.eclipse.swt.widgets.Composite;\r
27 import org.simantics.scl.compiler.ErrorMessage;\r
28 import org.simantics.scl.compiler.InvalidInputException;\r
29 import org.simantics.scl.compiler.SCLCompiler;\r
30 import org.simantics.scl.compiler.SCLCompilerConfiguration;\r
31 \r
32 public class SCLTextEditor extends Composite {\r
33 \r
34     private static final int DELAY_BEFORE_COMPILATION = 500 /*ms*/;\r
35     \r
36     SCLCompilerConfiguration configuration;\r
37     \r
38     SourceViewer viewer;\r
39     ImageRegistry imageRegistry;\r
40     SCLAnnotationAccess annotationAccess;\r
41     ISharedTextColors sharedTextColors;\r
42     IAnnotationModel annotationModel;    \r
43     \r
44     public SCLTextEditor(Composite parent, int style, SCLCompilerConfiguration configuration) {\r
45         super(parent, style);\r
46         setLayout(new FillLayout());\r
47         \r
48         this.configuration = configuration;\r
49         \r
50         imageRegistry = new ImageRegistry(parent.getDisplay());\r
51         annotationAccess = new SCLAnnotationAccess(imageRegistry);\r
52         sharedTextColors = new SharedTextColors(getDisplay());\r
53         annotationModel = new AnnotationModel();\r
54         \r
55         VerticalRuler leftRuler = new VerticalRuler(12, annotationAccess);\r
56         leftRuler.setModel(annotationModel);\r
57         \r
58         OverviewRuler rightRuler = \r
59             new OverviewRuler(annotationAccess, 12, sharedTextColors);\r
60         rightRuler.setModel(annotationModel);\r
61         rightRuler.addAnnotationType("error");\r
62         rightRuler.setAnnotationTypeLayer("error", 0);\r
63         rightRuler.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));\r
64         \r
65         viewer = new SourceViewer(this, \r
66                 leftRuler, rightRuler,\r
67                 true,\r
68                 SWT.H_SCROLL | SWT.V_SCROLL);\r
69         Document document = new Document();\r
70         viewer.setDocument(document, annotationModel);\r
71         viewer.setEditable(true);\r
72         viewer.configure(new SCLSourceViewerConfiguration(\r
73                 getDisplay(), sharedTextColors));\r
74         \r
75         // Annotations to text area\r
76         AnnotationPainter annotationPainter = \r
77             new AnnotationPainter(viewer, annotationAccess);\r
78         annotationPainter.addAnnotationType("error");\r
79         annotationPainter.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));\r
80         viewer.addPainter(annotationPainter);\r
81         annotationModel.addAnnotationModelListener(annotationPainter);\r
82         \r
83         // Undo support (maybe not needed in workbench?)\r
84         viewer.getTextWidget().addKeyListener(new KeyAdapter() {\r
85             @Override\r
86             public void keyReleased(KeyEvent e) {\r
87             }\r
88             @Override\r
89             public void keyPressed(KeyEvent e) {\r
90                 if(e.keyCode=='z'&& e.stateMask == SWT.CTRL) {\r
91                     viewer.getUndoManager().undo();\r
92                 }\r
93                 else if(e.keyCode=='y'&& e.stateMask == SWT.CTRL) {\r
94                     viewer.getUndoManager().redo();\r
95                 }\r
96             }\r
97         });        \r
98         \r
99         // Automatic compilation when text changes\r
100         viewer.addTextListener(new ITextListener() {            \r
101             @Override\r
102             public void textChanged(TextEvent event) {\r
103                 scheduleCompilation();                \r
104             }\r
105         });\r
106     }\r
107     \r
108     @Override\r
109     public void dispose() {\r
110         super.dispose();\r
111         sharedTextColors.dispose();\r
112     }    \r
113     \r
114     @SuppressWarnings("unchecked")\r
115     private void removeAnnotations() {\r
116         Iterator<Annotation> it = annotationModel.getAnnotationIterator();\r
117         while(it.hasNext()) {\r
118             Annotation annotation = it.next();\r
119             annotationModel.removeAnnotation(annotation);\r
120         }\r
121     }\r
122     \r
123     private void setAnnotations(Collection<ErrorMessage> messages) {\r
124         removeAnnotations();\r
125         for(ErrorMessage message : messages) {\r
126             annotationModel.addAnnotation(\r
127                     new Annotation("error", true, message.getMessage()), \r
128                     new Position(message.getStart(), message.getStop()-message.getStart()+1));   \r
129         }\r
130     }\r
131     \r
132     /**\r
133      * Tries to compile current \r
134      */\r
135     private void compileSync(String code) {\r
136         try {            \r
137             SCLCompiler.compileExpression(configuration, code);\r
138             getDisplay().asyncExec(new Runnable() {\r
139                 @Override\r
140                 public void run() {\r
141                     removeAnnotations();                    \r
142                 }\r
143             });            \r
144         } catch (final InvalidInputException e) {\r
145             getDisplay().asyncExec(new Runnable() {\r
146                 @Override\r
147                 public void run() {\r
148                     setAnnotations(e.getErrors());                    \r
149                 }\r
150             });            \r
151         } catch(Exception e) {\r
152             e.printStackTrace();\r
153         }\r
154     }\r
155 \r
156     Object compilationLock = new Object();\r
157     String codeToBeCompiled;\r
158     \r
159     private synchronized void scheduleCompilation() {\r
160         synchronized(compilationLock) {\r
161             if(codeToBeCompiled == null) {\r
162                 new Thread("SCLTextEditor compilation") {\r
163                     public void run() {                        \r
164                         while(true) {     \r
165                             String code;\r
166                             // Waits until code has remained unmodified for\r
167                             // time specified by DELAY_BEFORE_COMPILATION. \r
168                             synchronized(compilationLock) {\r
169                                 do {\r
170                                     code = codeToBeCompiled;  \r
171                                     try {\r
172                                         compilationLock.wait(DELAY_BEFORE_COMPILATION);\r
173                                     } catch (InterruptedException e) {\r
174                                     }\r
175                                 } while(!code.equals(codeToBeCompiled));\r
176                             }\r
177                             \r
178                             // Does the actual compilation and updates\r
179                             // annotations.\r
180                             compileSync(code);\r
181                             \r
182                             // If code was not modified during compilation,\r
183                             // exits the compilation thread and sets\r
184                             // codeToBeCompiled null to signal inactivity.\r
185                             synchronized(compilationLock) {\r
186                                 if(code.equals(codeToBeCompiled)) {\r
187                                     codeToBeCompiled = null;\r
188                                     return;\r
189                                 }\r
190                             }\r
191                         }                        \r
192                     }\r
193                 }.start();            \r
194             }\r
195             codeToBeCompiled = viewer.getDocument().get();\r
196             compilationLock.notify();\r
197         }\r
198     }\r
199     \r
200     public String getContent() {\r
201         final String[] result = new String[1];\r
202         getDisplay().syncExec(new Runnable() {\r
203             @Override\r
204             public void run() {\r
205                 result[0] = viewer.getDocument().get();\r
206             }\r
207         });\r
208         return result[0];\r
209     }\r
210     \r
211     public void setContent(final String content) {\r
212         getDisplay().asyncExec(new Runnable() {\r
213             @Override\r
214             public void run() {\r
215                 if (viewer.getTextWidget().isDisposed()) return;\r
216                 viewer.getDocument().set(content);\r
217             }\r
218         });\r
219     }\r
220 \r
221     private Point storedSelectedRange;\r
222 \r
223     public void storeSelectedRange() {\r
224         storedSelectedRange = viewer.getSelectedRange();\r
225     }\r
226 \r
227     public void restoreSelectedRange() {\r
228         if (storedSelectedRange != null) {\r
229             viewer.setSelectedRange(storedSelectedRange.x, storedSelectedRange.y);\r
230             storedSelectedRange = null;\r
231         }\r
232     }\r
233 \r
234 }\r