1 package org.simantics.scl.ui.editor;
\r
4 import java.util.Collection;
\r
5 import java.util.Iterator;
\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
32 public class SCLTextEditor extends Composite {
\r
34 private static final int DELAY_BEFORE_COMPILATION = 500 /*ms*/;
\r
36 SCLCompilerConfiguration configuration;
\r
38 SourceViewer viewer;
\r
39 ImageRegistry imageRegistry;
\r
40 SCLAnnotationAccess annotationAccess;
\r
41 ISharedTextColors sharedTextColors;
\r
42 IAnnotationModel annotationModel;
\r
44 public SCLTextEditor(Composite parent, int style, SCLCompilerConfiguration configuration) {
\r
45 super(parent, style);
\r
46 setLayout(new FillLayout());
\r
48 this.configuration = configuration;
\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
55 VerticalRuler leftRuler = new VerticalRuler(12, annotationAccess);
\r
56 leftRuler.setModel(annotationModel);
\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
65 viewer = new SourceViewer(this,
\r
66 leftRuler, rightRuler,
\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
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
83 // Undo support (maybe not needed in workbench?)
\r
84 viewer.getTextWidget().addKeyListener(new KeyAdapter() {
\r
86 public void keyReleased(KeyEvent e) {
\r
89 public void keyPressed(KeyEvent e) {
\r
90 if(e.keyCode=='z'&& e.stateMask == SWT.CTRL) {
\r
91 viewer.getUndoManager().undo();
\r
93 else if(e.keyCode=='y'&& e.stateMask == SWT.CTRL) {
\r
94 viewer.getUndoManager().redo();
\r
99 // Automatic compilation when text changes
\r
100 viewer.addTextListener(new ITextListener() {
\r
102 public void textChanged(TextEvent event) {
\r
103 scheduleCompilation();
\r
109 public void dispose() {
\r
111 sharedTextColors.dispose();
\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
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
133 * Tries to compile current
\r
135 private void compileSync(String code) {
\r
137 SCLCompiler.compileExpression(configuration, code);
\r
138 getDisplay().asyncExec(new Runnable() {
\r
140 public void run() {
\r
141 removeAnnotations();
\r
144 } catch (final InvalidInputException e) {
\r
145 getDisplay().asyncExec(new Runnable() {
\r
147 public void run() {
\r
148 setAnnotations(e.getErrors());
\r
151 } catch(Exception e) {
\r
152 e.printStackTrace();
\r
156 Object compilationLock = new Object();
\r
157 String codeToBeCompiled;
\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
166 // Waits until code has remained unmodified for
\r
167 // time specified by DELAY_BEFORE_COMPILATION.
\r
168 synchronized(compilationLock) {
\r
170 code = codeToBeCompiled;
\r
172 compilationLock.wait(DELAY_BEFORE_COMPILATION);
\r
173 } catch (InterruptedException e) {
\r
175 } while(!code.equals(codeToBeCompiled));
\r
178 // Does the actual compilation and updates
\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
195 codeToBeCompiled = viewer.getDocument().get();
\r
196 compilationLock.notify();
\r
200 public String getContent() {
\r
201 final String[] result = new String[1];
\r
202 getDisplay().syncExec(new Runnable() {
\r
204 public void run() {
\r
205 result[0] = viewer.getDocument().get();
\r
211 public void setContent(final String content) {
\r
212 getDisplay().asyncExec(new Runnable() {
\r
214 public void run() {
\r
215 if (viewer.getTextWidget().isDisposed()) return;
\r
216 viewer.getDocument().set(content);
\r
221 private Point storedSelectedRange;
\r
223 public void storeSelectedRange() {
\r
224 storedSelectedRange = viewer.getSelectedRange();
\r
227 public void restoreSelectedRange() {
\r
228 if (storedSelectedRange != null) {
\r
229 viewer.setSelectedRange(storedSelectedRange.x, storedSelectedRange.y);
\r
230 storedSelectedRange = null;
\r