-package org.simantics.scl.ui.editor;\r
-\r
-\r
-import java.util.Collection;\r
-import java.util.Iterator;\r
-\r
-import org.eclipse.jface.resource.ImageRegistry;\r
-import org.eclipse.jface.text.Document;\r
-import org.eclipse.jface.text.ITextListener;\r
-import org.eclipse.jface.text.Position;\r
-import org.eclipse.jface.text.TextEvent;\r
-import org.eclipse.jface.text.source.Annotation;\r
-import org.eclipse.jface.text.source.AnnotationModel;\r
-import org.eclipse.jface.text.source.AnnotationPainter;\r
-import org.eclipse.jface.text.source.IAnnotationModel;\r
-import org.eclipse.jface.text.source.ISharedTextColors;\r
-import org.eclipse.jface.text.source.OverviewRuler;\r
-import org.eclipse.jface.text.source.SourceViewer;\r
-import org.eclipse.jface.text.source.VerticalRuler;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.RGB;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.simantics.scl.compiler.ErrorMessage;\r
-import org.simantics.scl.compiler.InvalidInputException;\r
-import org.simantics.scl.compiler.SCLCompiler;\r
-import org.simantics.scl.compiler.SCLCompilerConfiguration;\r
-\r
-public class SCLTextEditor extends Composite {\r
-\r
- private static final int DELAY_BEFORE_COMPILATION = 500 /*ms*/;\r
- \r
- SCLCompilerConfiguration configuration;\r
- \r
- SourceViewer viewer;\r
- ImageRegistry imageRegistry;\r
- SCLAnnotationAccess annotationAccess;\r
- ISharedTextColors sharedTextColors;\r
- IAnnotationModel annotationModel; \r
- \r
- public SCLTextEditor(Composite parent, int style, SCLCompilerConfiguration configuration) {\r
- super(parent, style);\r
- setLayout(new FillLayout());\r
- \r
- this.configuration = configuration;\r
- \r
- imageRegistry = new ImageRegistry(parent.getDisplay());\r
- annotationAccess = new SCLAnnotationAccess(imageRegistry);\r
- sharedTextColors = new SharedTextColors(getDisplay());\r
- annotationModel = new AnnotationModel();\r
- \r
- VerticalRuler leftRuler = new VerticalRuler(12, annotationAccess);\r
- leftRuler.setModel(annotationModel);\r
- \r
- OverviewRuler rightRuler = \r
- new OverviewRuler(annotationAccess, 12, sharedTextColors);\r
- rightRuler.setModel(annotationModel);\r
- rightRuler.addAnnotationType("error");\r
- rightRuler.setAnnotationTypeLayer("error", 0);\r
- rightRuler.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));\r
- \r
- viewer = new SourceViewer(this, \r
- leftRuler, rightRuler,\r
- true,\r
- SWT.H_SCROLL | SWT.V_SCROLL);\r
- Document document = new Document();\r
- viewer.setDocument(document, annotationModel);\r
- viewer.setEditable(true);\r
- viewer.configure(new SCLSourceViewerConfiguration(\r
- getDisplay(), sharedTextColors));\r
- \r
- // Annotations to text area\r
- AnnotationPainter annotationPainter = \r
- new AnnotationPainter(viewer, annotationAccess);\r
- annotationPainter.addAnnotationType("error");\r
- annotationPainter.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));\r
- viewer.addPainter(annotationPainter);\r
- annotationModel.addAnnotationModelListener(annotationPainter);\r
- \r
- // Undo support (maybe not needed in workbench?)\r
- viewer.getTextWidget().addKeyListener(new KeyAdapter() {\r
- @Override\r
- public void keyReleased(KeyEvent e) {\r
- }\r
- @Override\r
- public void keyPressed(KeyEvent e) {\r
- if(e.keyCode=='z'&& e.stateMask == SWT.CTRL) {\r
- viewer.getUndoManager().undo();\r
- }\r
- else if(e.keyCode=='y'&& e.stateMask == SWT.CTRL) {\r
- viewer.getUndoManager().redo();\r
- }\r
- }\r
- }); \r
- \r
- // Automatic compilation when text changes\r
- viewer.addTextListener(new ITextListener() { \r
- @Override\r
- public void textChanged(TextEvent event) {\r
- scheduleCompilation(); \r
- }\r
- });\r
- }\r
- \r
- @Override\r
- public void dispose() {\r
- super.dispose();\r
- sharedTextColors.dispose();\r
- } \r
- \r
- @SuppressWarnings("unchecked")\r
- private void removeAnnotations() {\r
- Iterator<Annotation> it = annotationModel.getAnnotationIterator();\r
- while(it.hasNext()) {\r
- Annotation annotation = it.next();\r
- annotationModel.removeAnnotation(annotation);\r
- }\r
- }\r
- \r
- private void setAnnotations(Collection<ErrorMessage> messages) {\r
- removeAnnotations();\r
- for(ErrorMessage message : messages) {\r
- annotationModel.addAnnotation(\r
- new Annotation("error", true, message.getMessage()), \r
- new Position(message.getStart(), message.getStop()-message.getStart()+1)); \r
- }\r
- }\r
- \r
- /**\r
- * Tries to compile current \r
- */\r
- private void compileSync(String code) {\r
- try { \r
- SCLCompiler.compileExpression(configuration, code);\r
- getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- removeAnnotations(); \r
- }\r
- }); \r
- } catch (final InvalidInputException e) {\r
- getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- setAnnotations(e.getErrors()); \r
- }\r
- }); \r
- } catch(Exception e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- Object compilationLock = new Object();\r
- String codeToBeCompiled;\r
- \r
- private synchronized void scheduleCompilation() {\r
- synchronized(compilationLock) {\r
- if(codeToBeCompiled == null) {\r
- new Thread("SCLTextEditor compilation") {\r
- public void run() { \r
- while(true) { \r
- String code;\r
- // Waits until code has remained unmodified for\r
- // time specified by DELAY_BEFORE_COMPILATION. \r
- synchronized(compilationLock) {\r
- do {\r
- code = codeToBeCompiled; \r
- try {\r
- compilationLock.wait(DELAY_BEFORE_COMPILATION);\r
- } catch (InterruptedException e) {\r
- }\r
- } while(!code.equals(codeToBeCompiled));\r
- }\r
- \r
- // Does the actual compilation and updates\r
- // annotations.\r
- compileSync(code);\r
- \r
- // If code was not modified during compilation,\r
- // exits the compilation thread and sets\r
- // codeToBeCompiled null to signal inactivity.\r
- synchronized(compilationLock) {\r
- if(code.equals(codeToBeCompiled)) {\r
- codeToBeCompiled = null;\r
- return;\r
- }\r
- }\r
- } \r
- }\r
- }.start(); \r
- }\r
- codeToBeCompiled = viewer.getDocument().get();\r
- compilationLock.notify();\r
- }\r
- }\r
- \r
- public String getContent() {\r
- final String[] result = new String[1];\r
- getDisplay().syncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- result[0] = viewer.getDocument().get();\r
- }\r
- });\r
- return result[0];\r
- }\r
- \r
- public void setContent(final String content) {\r
- getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- if (viewer.getTextWidget().isDisposed()) return;\r
- viewer.getDocument().set(content);\r
- }\r
- });\r
- }\r
-\r
- private Point storedSelectedRange;\r
-\r
- public void storeSelectedRange() {\r
- storedSelectedRange = viewer.getSelectedRange();\r
- }\r
-\r
- public void restoreSelectedRange() {\r
- if (storedSelectedRange != null) {\r
- viewer.setSelectedRange(storedSelectedRange.x, storedSelectedRange.y);\r
- storedSelectedRange = null;\r
- }\r
- }\r
-\r
-}\r
+package org.simantics.scl.ui.editor;
+
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.ITextListener;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.TextEvent;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.jface.text.source.AnnotationPainter;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.ISharedTextColors;
+import org.eclipse.jface.text.source.OverviewRuler;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.text.source.VerticalRuler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.simantics.scl.compiler.ErrorMessage;
+import org.simantics.scl.compiler.InvalidInputException;
+import org.simantics.scl.compiler.SCLCompiler;
+import org.simantics.scl.compiler.SCLCompilerConfiguration;
+
+public class SCLTextEditor extends Composite {
+
+ private static final int DELAY_BEFORE_COMPILATION = 500 /*ms*/;
+
+ SCLCompilerConfiguration configuration;
+
+ SourceViewer viewer;
+ ImageRegistry imageRegistry;
+ SCLAnnotationAccess annotationAccess;
+ ISharedTextColors sharedTextColors;
+ IAnnotationModel annotationModel;
+
+ public SCLTextEditor(Composite parent, int style, SCLCompilerConfiguration configuration) {
+ super(parent, style);
+ setLayout(new FillLayout());
+
+ this.configuration = configuration;
+
+ imageRegistry = new ImageRegistry(parent.getDisplay());
+ annotationAccess = new SCLAnnotationAccess(imageRegistry);
+ sharedTextColors = new SharedTextColors(getDisplay());
+ annotationModel = new AnnotationModel();
+
+ VerticalRuler leftRuler = new VerticalRuler(12, annotationAccess);
+ leftRuler.setModel(annotationModel);
+
+ OverviewRuler rightRuler =
+ new OverviewRuler(annotationAccess, 12, sharedTextColors);
+ rightRuler.setModel(annotationModel);
+ rightRuler.addAnnotationType("error");
+ rightRuler.setAnnotationTypeLayer("error", 0);
+ rightRuler.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));
+
+ viewer = new SourceViewer(this,
+ leftRuler, rightRuler,
+ true,
+ SWT.H_SCROLL | SWT.V_SCROLL);
+ Document document = new Document();
+ viewer.setDocument(document, annotationModel);
+ viewer.setEditable(true);
+ viewer.configure(new SCLSourceViewerConfiguration(
+ getDisplay(), sharedTextColors));
+
+ // Annotations to text area
+ AnnotationPainter annotationPainter =
+ new AnnotationPainter(viewer, annotationAccess);
+ annotationPainter.addAnnotationType("error");
+ annotationPainter.setAnnotationTypeColor("error", sharedTextColors.getColor(new RGB(255,0,128)));
+ viewer.addPainter(annotationPainter);
+ annotationModel.addAnnotationModelListener(annotationPainter);
+
+ // Undo support (maybe not needed in workbench?)
+ viewer.getTextWidget().addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if(e.keyCode=='z'&& e.stateMask == SWT.CTRL) {
+ viewer.getUndoManager().undo();
+ }
+ else if(e.keyCode=='y'&& e.stateMask == SWT.CTRL) {
+ viewer.getUndoManager().redo();
+ }
+ }
+ });
+
+ // Automatic compilation when text changes
+ viewer.addTextListener(new ITextListener() {
+ @Override
+ public void textChanged(TextEvent event) {
+ scheduleCompilation();
+ }
+ });
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ sharedTextColors.dispose();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void removeAnnotations() {
+ Iterator<Annotation> it = annotationModel.getAnnotationIterator();
+ while(it.hasNext()) {
+ Annotation annotation = it.next();
+ annotationModel.removeAnnotation(annotation);
+ }
+ }
+
+ private void setAnnotations(Collection<ErrorMessage> messages) {
+ removeAnnotations();
+ for(ErrorMessage message : messages) {
+ annotationModel.addAnnotation(
+ new Annotation("error", true, message.getMessage()),
+ new Position(message.getStart(), message.getStop()-message.getStart()+1));
+ }
+ }
+
+ /**
+ * Tries to compile current
+ */
+ private void compileSync(String code) {
+ try {
+ SCLCompiler.compileExpression(configuration, code);
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ removeAnnotations();
+ }
+ });
+ } catch (final InvalidInputException e) {
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ setAnnotations(e.getErrors());
+ }
+ });
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ Object compilationLock = new Object();
+ String codeToBeCompiled;
+
+ private synchronized void scheduleCompilation() {
+ synchronized(compilationLock) {
+ if(codeToBeCompiled == null) {
+ new Thread("SCLTextEditor compilation") {
+ public void run() {
+ while(true) {
+ String code;
+ // Waits until code has remained unmodified for
+ // time specified by DELAY_BEFORE_COMPILATION.
+ synchronized(compilationLock) {
+ do {
+ code = codeToBeCompiled;
+ try {
+ compilationLock.wait(DELAY_BEFORE_COMPILATION);
+ } catch (InterruptedException e) {
+ }
+ } while(!code.equals(codeToBeCompiled));
+ }
+
+ // Does the actual compilation and updates
+ // annotations.
+ compileSync(code);
+
+ // If code was not modified during compilation,
+ // exits the compilation thread and sets
+ // codeToBeCompiled null to signal inactivity.
+ synchronized(compilationLock) {
+ if(code.equals(codeToBeCompiled)) {
+ codeToBeCompiled = null;
+ return;
+ }
+ }
+ }
+ }
+ }.start();
+ }
+ codeToBeCompiled = viewer.getDocument().get();
+ compilationLock.notify();
+ }
+ }
+
+ public String getContent() {
+ final String[] result = new String[1];
+ getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ result[0] = viewer.getDocument().get();
+ }
+ });
+ return result[0];
+ }
+
+ public void setContent(final String content) {
+ getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (viewer.getTextWidget().isDisposed()) return;
+ viewer.getDocument().set(content);
+ }
+ });
+ }
+
+ private Point storedSelectedRange;
+
+ public void storeSelectedRange() {
+ storedSelectedRange = viewer.getSelectedRange();
+ }
+
+ public void restoreSelectedRange() {
+ if (storedSelectedRange != null) {
+ viewer.setSelectedRange(storedSelectedRange.x, storedSelectedRange.y);
+ storedSelectedRange = null;
+ }
+ }
+
+}