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