]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.scl.ui.editor/src/org/simantics/scl/ui/editor/SCLTextEditor.java b/bundles/org.simantics.scl.ui.editor/src/org/simantics/scl/ui/editor/SCLTextEditor.java
new file mode 100644 (file)
index 0000000..28ff84a
--- /dev/null
@@ -0,0 +1,234 @@
+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