]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.ui/src/org/simantics/scl/ui/console/AbstractCommandConsole.java
Added SCL Script Output console view.
[simantics/platform.git] / bundles / org.simantics.scl.ui / src / org / simantics / scl / ui / console / AbstractCommandConsole.java
index 8039d4662a0d67c6c55a4e93b9fabb55ed8585fb..a98d65715c7fa89a652ac6a0293667027bfda51a 100644 (file)
@@ -11,6 +11,7 @@ import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.core.runtime.preferences.InstanceScope;
 import org.eclipse.jface.preference.IPersistentPreferenceStore;
 import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.FontDescriptor;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.resource.LocalResourceManager;
 import org.eclipse.jface.window.DefaultToolTip;
@@ -18,9 +19,6 @@ import org.eclipse.jface.window.ToolTip;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.StyleRange;
 import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.custom.VerifyKeyListener;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.VerifyEvent;
 import org.eclipse.swt.events.VerifyListener;
 import org.eclipse.swt.graphics.Color;
@@ -33,11 +31,13 @@ import org.eclipse.swt.layout.FormAttachment;
 import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.layout.FormLayout;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Sash;
 import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.simantics.scl.runtime.tuple.Tuple2;
 
 /**
  * A console with input and output area that can be embedded
@@ -46,6 +46,11 @@ import org.eclipse.ui.preferences.ScopedPreferenceStore;
  */
 public abstract class AbstractCommandConsole extends Composite {
 
+    /**
+     * Use this option mask to hide and disable the console input field.
+     */
+    public static final int HIDE_INPUT = 1 << 0;
+
     public static final String PLUGIN_ID = "org.simantics.scl.ui";
 
     public static final int COMMAND_HISTORY_SIZE = 50;
@@ -53,7 +58,9 @@ public abstract class AbstractCommandConsole extends Composite {
     public static final int SASH_HEIGHT = 3;
     
     LocalResourceManager resourceManager;
-    
+
+    protected final int options;
+
     StyledText output;
     Sash sash;
     protected StyledText input;
@@ -63,7 +70,8 @@ public abstract class AbstractCommandConsole extends Composite {
     
     protected Color greenColor;
     protected Color redColor;
-    
+    protected Font textFont;
+
     ArrayList<String> commandHistory = new ArrayList<String>();
     int commandHistoryPos = 0;
     
@@ -73,29 +81,33 @@ public abstract class AbstractCommandConsole extends Composite {
     Shell tip = null;
     Label label = null;
     */
-    
-    public AbstractCommandConsole(Composite parent, int style) {
-        super(parent, style);      
+
+    public AbstractCommandConsole(Composite parent, int style, int options) {
+        super(parent, style);
+        this.options = options;
         createControl();
     }
-    
+
     @Override
     public boolean setFocus() {
-        return input.setFocus();
+        return input != null ? input.setFocus() : output.setFocus();
     }
-    
+
     protected boolean canExecuteCommand() {
         return true;
     }
 
+    private boolean hasOption(int mask) {
+        return (options & mask) != 0;
+    }
+
     private void createControl() {
         resourceManager = new LocalResourceManager(JFaceResources.getResources(), this);
         greenColor = resourceManager.createColor(new RGB(0, 128, 0));
         redColor = resourceManager.createColor(new RGB(172, 0, 0));
-        
+        textFont = resourceManager.createFont( FontDescriptor.createFrom("Courier New", 12, SWT.NONE) );
+
         setLayout(new FormLayout());
-        
-        Font textFont = new Font(getDisplay(),"Courier New",12,SWT.NONE);
 
         // Sash
         sash = new Sash(this, /*SWT.BORDER |*/ SWT.HORIZONTAL);
@@ -115,121 +127,111 @@ public abstract class AbstractCommandConsole extends Composite {
         // Upper
         output = new StyledText(this, SWT.MULTI /*| SWT.READ_ONLY*/ | SWT.V_SCROLL | SWT.H_SCROLL);
         output.setFont(textFont);
-        {
-            FormData formData = new FormData();
-            formData.top = new FormAttachment(0);      
-            formData.bottom = new FormAttachment(sash);
-            formData.left = new FormAttachment(0);
-            formData.right = new FormAttachment(100);
-            output.setLayoutData(formData);
-        }
+        output.setLayoutData( formData(0, sash, 0, 100) );
         output.addVerifyListener(new VerifyListener() {
             @Override
             public void verifyText(VerifyEvent e) {
                 if(outputModiLock)
                     return;
-                input.append(e.text);
-                input.setFocus();
-                input.setCaretOffset(input.getText().length());
+                if (input != null) {
+                    input.append(e.text);
+                    input.setFocus();
+                    input.setCaretOffset(input.getText().length());
+                }
                 e.doit = false;
             }
         });
 
-        // Deco
-        StyledText deco = new StyledText(this, SWT.MULTI | SWT.READ_ONLY);   
+        if (hasOption(HIDE_INPUT)) {
+            sash.setLayoutData( formData(new Tuple2(100, 0), null, 0, 100, 0) );
+            layout(true);
+        } else {
+            createInputArea();
+        }
+
+        readPreferences();
+
+        addListener(SWT.Dispose, event -> {
+            try {
+                writePreferences();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        });
+    }
+
+    protected void createInputArea() {
+        // "> " Decoration
+        StyledText deco = new StyledText(this, SWT.MULTI | SWT.READ_ONLY);
         deco.setFont(textFont);
         deco.setEnabled(false);
         GC gc = new GC(deco);
         int inputLeftPos = gc.getFontMetrics().getAverageCharWidth()*2;
+        gc.dispose();
         deco.setText(">");
-        {
-            FormData formData = new FormData();
-            formData.top = new FormAttachment(sash);
-            formData.bottom = new FormAttachment(100);
-            formData.left = new FormAttachment(0);
-            formData.right = new FormAttachment(0, inputLeftPos);
-            deco.setLayoutData(formData);
-        }
-        
-        // Input area        
-        input = new StyledText(this, SWT.MULTI);        
+        deco.setLayoutData( formData(sash, 100, 0, new Tuple2(0, inputLeftPos)) );
+
+        // Input area
+        input = new StyledText(this, SWT.MULTI);
         input.setFont(textFont);
-        {
-            FormData formData = new FormData();
-            formData.top = new FormAttachment(sash);
-            formData.bottom = new FormAttachment(100);
-            formData.left = new FormAttachment(0, inputLeftPos);
-            formData.right = new FormAttachment(100);
-            input.setLayoutData(formData);
-        }
+        input.setLayoutData( formData(sash, 100, new Tuple2(0, inputLeftPos), 100) );
         adjustInputSize("");
-        input.addVerifyKeyListener(new VerifyKeyListener() {
-            
-            @Override
-            public void verifyKey(VerifyEvent event) {
-                switch(event.keyCode) {
-                case SWT.KEYPAD_CR:
-                case SWT.CR:
-                    if((event.stateMask & SWT.CTRL) == 0) {
-                        if(canExecuteCommand())
-                            execute();
-                        event.doit = false;
+        input.addVerifyKeyListener(event -> {
+            switch(event.keyCode) {
+            case SWT.KEYPAD_CR:
+            case SWT.CR:
+                if((event.stateMask & SWT.CTRL) == 0) {
+                    if(canExecuteCommand())
+                        execute();
+                    event.doit = false;
+                }
+                break;
+            case SWT.ARROW_UP:
+            case SWT.ARROW_DOWN: 
+                if((event.stateMask & SWT.CTRL) != 0) {
+                    int targetHistoryPos = commandHistoryPos;
+                    if(event.keyCode == SWT.ARROW_UP) {
+                        if(commandHistoryPos <= 0)
+                            return;
+                        --targetHistoryPos;
                     }
-                    break;
-                case SWT.ARROW_UP:
-                case SWT.ARROW_DOWN: 
-                    if((event.stateMask & SWT.CTRL) != 0) {
-                        int targetHistoryPos = commandHistoryPos;
-                        if(event.keyCode == SWT.ARROW_UP) {
-                            if(commandHistoryPos <= 0)
-                                return;
-                            --targetHistoryPos;
-                        }
-                        else {
-                            if(commandHistoryPos >= commandHistory.size()-1)
-                                return;
-                            ++targetHistoryPos;
-                        }
-                        setInputText(commandHistory.get(targetHistoryPos));
-                        commandHistoryPos = targetHistoryPos;
-                        event.doit = false;
+                    else {
+                        if(commandHistoryPos >= commandHistory.size()-1)
+                            return;
+                        ++targetHistoryPos;
                     }
-                    break;                
-//                case SWT.ESC:
-//                    setInputText("");
-//                    commandHistoryPos = commandHistory.size();
-//                    break;
-                }
-            }
-            
-        });        
-        input.addVerifyListener(new VerifyListener() {
-            @Override
-            public void verifyText(VerifyEvent e) {
-                if(e.text.contains("\n")) {
-                    int lineId = input.getLineAtOffset(e.start);
-                    int lineOffset = input.getOffsetAtLine(lineId);
-                    int indentAmount;
-                    for(indentAmount=0;
-                            lineOffset+indentAmount < input.getCharCount() && 
-                            input.getTextRange(lineOffset+indentAmount, 1).equals(" ");
-                            ++indentAmount);
-                    StringBuilder indent = new StringBuilder();
-                    indent.append('\n');
-                    for(int i=0;i<indentAmount;++i)
-                        indent.append(' ');
-                    e.text = e.text.replace("\n", indent);
+                    setInputText(commandHistory.get(targetHistoryPos));
+                    commandHistoryPos = targetHistoryPos;
+                    event.doit = false;
                 }
+                break;
+//            case SWT.ESC:
+//                setInputText("");
+//                commandHistoryPos = commandHistory.size();
+//                break;
             }
         });
-        input.addModifyListener(new ModifyListener() {
-            @Override
-            public void modifyText(ModifyEvent e) {
-                adjustInputSize(input.getText());
-                commandHistoryPos = commandHistory.size();
-                //asyncValidate();
+        input.addVerifyListener(e -> {
+            if(e.text.contains("\n")) {
+                int lineId = input.getLineAtOffset(e.start);
+                int lineOffset = input.getOffsetAtLine(lineId);
+                int indentAmount;
+                for(indentAmount=0;
+                        lineOffset+indentAmount < input.getCharCount() && 
+                        input.getTextRange(lineOffset+indentAmount, 1).equals(" ");
+                        ++indentAmount);
+                StringBuilder indent = new StringBuilder();
+                indent.append('\n');
+                for(int i=0;i<indentAmount;++i)
+                    indent.append(' ');
+                e.text = e.text.replace("\n", indent);
             }
         });
+        input.addModifyListener(e -> {
+            adjustInputSize(input.getText());
+            commandHistoryPos = commandHistory.size();
+            //asyncValidate();
+        });
         Listener hoverListener = new Listener() {
             
             DefaultToolTip toolTip = new DefaultToolTip(input, ToolTip.RECREATE, true);
@@ -285,30 +287,42 @@ public abstract class AbstractCommandConsole extends Composite {
                         toolTipVisible = false;
                     }
                     return;
-                }                
-            }            
+                }
+            }
         };
         input.addListener(SWT.MouseHover, hoverListener);
         input.addListener(SWT.MouseMove, hoverListener);
         input.addListener(SWT.MouseExit, hoverListener);
-        
-        readPreferences();
-        
-        addListener(SWT.Dispose, new Listener() {
-            
-            @Override
-            public void handleEvent(Event event) {
-                try {
-                    writePreferences();
-                } catch (IOException e) {
-                    e.printStackTrace();
-               }
-            }
-            
-        });
-        
     }
-    
+
+    private FormData formData(Object top, Object bottom, Object left, Object right) {
+        return formData(top, bottom, left, right, null);
+    }
+
+    private FormData formData(Object top, Object bottom, Object left, Object right, Integer height) {
+        FormData d = new FormData();
+        d.top = formAttachment(top);
+        d.bottom = formAttachment(bottom);
+        d.left = formAttachment(left);
+        d.right = formAttachment(right);
+        d.height = height != null ? (Integer) height : SWT.DEFAULT;
+        return d;
+    }
+
+    private FormAttachment formAttachment(Object o) {
+        if (o == null)
+            return null;
+        if (o instanceof Control)
+            return new FormAttachment((Control) o);
+        if (o instanceof Integer)
+            return new FormAttachment((Integer) o);
+        if (o instanceof Tuple2) {
+            Tuple2 t = (Tuple2) o;
+            return new FormAttachment((Integer) t.c0, (Integer) t.c1);
+        }
+        throw new IllegalArgumentException("argument not supported: " + o);
+    }
+
     private int getOffsetInInput(int x, int y) {
         int offset;
         try {
@@ -327,6 +341,8 @@ public abstract class AbstractCommandConsole extends Composite {
     }
     
     public void setInputText(String text) {
+        if (input == null)
+            return;
         input.setText(text);
         input.setCaretOffset(text.length());
         adjustInputSize(text);
@@ -345,20 +361,17 @@ public abstract class AbstractCommandConsole extends Composite {
         
     };
     
-    Job preValidationJob = new Job("SCL input validation") {        
+    Job preValidationJob = new Job("SCL input validation") {
         @Override
         protected IStatus run(IProgressMonitor monitor) {
             if(!input.isDisposed()) {
-                input.getDisplay().asyncExec(new Runnable() {
-                    @Override
-                    public void run() {
-                        if(!input.isDisposed()) {
-                            validatedText = input.getText();
-                            validationJob.setPriority(Job.BUILD);
-                            validationJob.schedule();
-                        }                     
-                    }                    
-                });                
+                input.getDisplay().asyncExec(() -> {
+                    if(!input.isDisposed()) {
+                        validatedText = input.getText();
+                        validationJob.setPriority(Job.BUILD);
+                        validationJob.schedule();
+                    }
+                });
             }
             
             return Status.OK_STATUS;
@@ -391,19 +404,14 @@ public abstract class AbstractCommandConsole extends Composite {
     }
     
     private void setInputHeight(int inputHeight) {
-        FormData formData = new FormData();
-        formData.top = new FormAttachment(100, -inputHeight);
-        formData.left = new FormAttachment(0);
-        formData.right = new FormAttachment(100);
-        formData.height = SASH_HEIGHT;
-        sash.setLayoutData(formData);
+        sash.setLayoutData( formData(new Tuple2(100, -inputHeight), null, 0, 100, SASH_HEIGHT) );
         AbstractCommandConsole.this.layout(true);
     }
 
     private StringBuilder outputBuffer = new StringBuilder();
     private ArrayList<StyleRange> styleRanges = new ArrayList<StyleRange>();
     private volatile boolean outputScheduled = false;
-    
+
     public void appendOutput(final String text, final Color foreground, final Color background) {
         synchronized (outputBuffer) {
             styleRanges.add(new StyleRange(outputBuffer.length(), text.length(), foreground, background));
@@ -413,40 +421,37 @@ public abstract class AbstractCommandConsole extends Composite {
             outputScheduled = true;
             final Display display = Display.getDefault();
             if(display.isDisposed()) return;
-            display.asyncExec(new Runnable() {
-                @Override
-                public void run() {
-                    if(output.isDisposed()) return;
-                    String outputText;
-                    StyleRange[] styleRangeArray;
-                    synchronized(outputBuffer) {
-                        outputScheduled = false;
-                        
-                        outputText = outputBuffer.toString();
-                        outputBuffer = new StringBuilder();
-                        
-                        styleRangeArray = styleRanges.toArray(new StyleRange[styleRanges.size()]);
-                        styleRanges.clear();
-                    }
-                    int pos = output.getCharCount();
+            display.asyncExec(() -> {
+                if(output.isDisposed()) return;
+                String outputText;
+                StyleRange[] styleRangeArray;
+                synchronized(outputBuffer) {
+                    outputScheduled = false;
 
-                    outputModiLock = true;
-                    output.replaceTextRange(pos, 0, outputText);
-                    outputModiLock = false;
-                    
-                    for(StyleRange styleRange : styleRangeArray) {
-                        styleRange.start += pos;
-                        output.setStyleRange(styleRange);
-                    }
+                    outputText = outputBuffer.toString();
+                    outputBuffer = new StringBuilder();
+
+                    styleRangeArray = styleRanges.toArray(new StyleRange[styleRanges.size()]);
+                    styleRanges.clear();
+                }
+                int pos = output.getCharCount();
 
-                    output.setCaretOffset(output.getCharCount());
-                    output.showSelection();
+                outputModiLock = true;
+                output.replaceTextRange(pos, 0, outputText);
+                outputModiLock = false;
+
+                for(StyleRange styleRange : styleRangeArray) {
+                    styleRange.start += pos;
+                    output.setStyleRange(styleRange);
                 }
+
+                output.setCaretOffset(output.getCharCount());
+                output.showSelection();
             });
         }
     }
-    
-    private void execute() {        
+
+    private void execute() {
         String command = input.getText().trim();
         if(command.isEmpty())
             return;
@@ -514,7 +519,7 @@ public abstract class AbstractCommandConsole extends Composite {
                 if(input.isDisposed())
                     return;
                 if(!input.getText().equals(forCommand))
-                    return;                
+                    return;
                 syncSetErrorAnnotations(forCommand, annotations);
             }
         });