cb11b794c4968b912f6aa3363117d1f826c239c8
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / console / SwingScilabConsole.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2007-2008 - INRIA - Vincent Couvert
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.gui.bridge.console;
14
15 import java.awt.Dimension;
16 import java.awt.Toolkit;
17 import java.awt.datatransfer.Clipboard;
18 import java.awt.datatransfer.DataFlavor;
19 import java.awt.datatransfer.StringSelection;
20 import java.awt.datatransfer.UnsupportedFlavorException;
21 import java.awt.event.FocusEvent;
22 import java.awt.event.FocusListener;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.io.IOException;
26 import java.util.StringTokenizer;
27
28 import javax.swing.JEditorPane;
29 import javax.swing.JPanel;
30 import javax.swing.JTextPane;
31 import javax.swing.SwingUtilities;
32 import javax.swing.text.BadLocationException;
33 import javax.swing.text.Document;
34 import javax.swing.text.StyleContext;
35 import javax.swing.text.StyledDocument;
36
37 import org.scilab.modules.action_binding.InterpreterManagement;
38 import org.scilab.modules.console.OneCharKeyEventListener;
39 import org.scilab.modules.console.SciConsole;
40 import org.scilab.modules.console.SciHistoryManager;
41 import org.scilab.modules.console.SciOutputView;
42 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
43 import org.scilab.modules.gui.bridge.menuitem.SwingScilabMenuItem;
44 import org.scilab.modules.gui.console.SimpleConsole;
45 import org.scilab.modules.gui.events.callback.ScilabCallBack;
46 import org.scilab.modules.gui.utils.ConfigManager;
47 import org.scilab.modules.gui.utils.Position;
48 import org.scilab.modules.gui.utils.Size;
49 import org.scilab.modules.history_manager.HistoryManagement;
50 import org.scilab.modules.localization.Messages;
51
52 import com.artenum.rosetta.interfaces.ui.InputCommandView;
53 import com.artenum.rosetta.util.StringConstants;
54
55 /**
56  * Swing implementation for Scilab Console in GUIs
57  * @author Vincent COUVERT
58  */
59 public class SwingScilabConsole extends SciConsole implements SimpleConsole {
60
61     private static final long serialVersionUID = 1L;
62
63     /**
64      * Constructor
65      */
66     public SwingScilabConsole() {
67         super(ConfigManager.getUserConfigFile());
68
69         SwingScilabContextMenu menu = new SwingScilabContextMenu();
70
71         SwingScilabMenuItem cutMenu = new SwingScilabMenuItem();
72         cutMenu.setText(Messages.gettext("Cut"));
73         cutMenu.setCallback(ScilabCallBack.createCallback(
74                                 "org.scilab.modules.gui.bridge.CallScilabBridge.cutConsoleSelection",
75                                 ScilabCallBack.JAVA));
76         cutMenu.setMnemonic('U');
77
78         SwingScilabMenuItem copyMenu = new SwingScilabMenuItem();
79         copyMenu.setText(Messages.gettext("Copy"));
80         copyMenu.setCallback(ScilabCallBack.createCallback(
81                                  "org.scilab.modules.gui.bridge.CallScilabBridge.copyConsoleSelection",
82                                  ScilabCallBack.JAVA));
83         copyMenu.setMnemonic('C');
84
85         SwingScilabMenuItem pasteMenu = new SwingScilabMenuItem();
86         pasteMenu.setText(Messages.gettext("Paste"));
87         pasteMenu.setCallback(ScilabCallBack.createCallback(
88                                   "org.scilab.modules.gui.bridge.CallScilabBridge.pasteClipboardIntoConsole",
89                                   ScilabCallBack.JAVA));
90         pasteMenu.setMnemonic('P');
91
92         SwingScilabMenuItem clearHistoryMenu = new SwingScilabMenuItem();
93         clearHistoryMenu.setText(Messages.gettext("Clear History"));
94         clearHistoryMenu.setCallback(ScilabCallBack.createCallback(
95                                          "org.scilab.modules.gui.bridge.CallScilabBridge.clearHistory",
96                                          ScilabCallBack.JAVA));
97         clearHistoryMenu.setMnemonic('H');
98
99         SwingScilabMenuItem clearMenu = new SwingScilabMenuItem();
100         clearMenu.setText(Messages.gettext("Clear Console"));
101         clearMenu.setCallback(ScilabCallBack.createCallback(
102                                   "org.scilab.modules.gui.bridge.CallScilabBridge.clear",
103                                   ScilabCallBack.JAVA));
104         clearMenu.setMnemonic('O');
105
106         SwingScilabMenuItem selectMenu = new SwingScilabMenuItem();
107         selectMenu.setText(Messages.gettext("Select All"));
108         selectMenu.setCallback(ScilabCallBack.createCallback(
109                                    "org.scilab.modules.gui.bridge.CallScilabBridge.selectAllConsoleContents",
110                                    ScilabCallBack.JAVA));
111         selectMenu.setMnemonic('S');
112
113
114         final SwingScilabMenuItem helpMenu = new SwingScilabMenuItem();
115         helpMenu.setText(Messages.gettext("Help on a selected keyword"));
116         helpMenu.setCallback(ScilabCallBack.createCallback(
117                                  "org.scilab.modules.gui.bridge.CallScilabBridge.helpOnTheKeyword",
118                                  ScilabCallBack.JAVA));
119         helpMenu.setMnemonic('M');
120         PropertyChangeListener listener = new PropertyChangeListener() {
121                 public void propertyChange(PropertyChangeEvent arg0) {
122                     String keyword = getSelectedText();
123                     if (keyword == null || keyword.length() == 0) {
124                         helpMenu.setText(Messages.gettext("Help about a selected text"));
125                     } else {
126                         int nbOfDisplayedOnlyXChar=10;
127                         if (keyword.length() > nbOfDisplayedOnlyXChar) {
128                             keyword = keyword.substring(0, nbOfDisplayedOnlyXChar) + "...";
129                         }
130                         helpMenu.setText(Messages.gettext("Help about '") +keyword+"'");
131                     }
132                 }
133             };
134         helpMenu.addPropertyChangeListener(listener);
135
136         final SwingScilabMenuItem evalWithEchoMenu = new SwingScilabMenuItem();
137         evalWithEchoMenu.setText(Messages.gettext("Evaluate selection with echo"));
138         evalWithEchoMenu.setCallback(ScilabCallBack.createCallback("org.scilab.modules.gui.bridge.CallScilabBridge.evaluateSelectionWithEcho",
139                                                                    ScilabCallBack.JAVA));
140         evalWithEchoMenu.setMnemonic('E');
141         listener = new PropertyChangeListener() {
142                 public void propertyChange(PropertyChangeEvent arg0) {
143                     String str = getSelectedText();
144                     evalWithEchoMenu.setEnabled(str != null && !str.isEmpty());
145                 }
146             };
147         evalWithEchoMenu.addPropertyChangeListener(listener);
148
149         final SwingScilabMenuItem evalWithNoEchoMenu = new SwingScilabMenuItem();
150         evalWithNoEchoMenu.setText(Messages.gettext("Evaluate selection with no echo"));
151         evalWithNoEchoMenu.setCallback(ScilabCallBack.createCallback("org.scilab.modules.gui.bridge.CallScilabBridge.evaluateSelectionWithNoEcho",
152                                                                      ScilabCallBack.JAVA));
153         evalWithNoEchoMenu.setMnemonic('N');
154         listener = new PropertyChangeListener() {
155                 public void propertyChange(PropertyChangeEvent arg0) {
156                     String str = getSelectedText();
157                     evalWithNoEchoMenu.setEnabled(str != null && !str.isEmpty());
158                 }
159             };
160         evalWithEchoMenu.addPropertyChangeListener(listener);
161
162         menu.add(cutMenu);
163         menu.add(copyMenu);
164         menu.add(pasteMenu);
165
166         menu.addSeparator();
167
168         menu.add(clearHistoryMenu);
169         menu.add(clearMenu);
170
171         menu.addSeparator();
172
173         menu.add(selectMenu);
174         menu.addSeparator();
175
176         menu.add(evalWithEchoMenu);
177         menu.add(evalWithNoEchoMenu);
178         menu.addSeparator();
179
180         menu.add(helpMenu);
181
182         ((JEditorPane) getConfiguration().getOutputView()).setComponentPopupMenu(menu);
183         ((JTextPane) getConfiguration().getInputCommandView()).setComponentPopupMenu(menu);
184         ((JPanel) getConfiguration().getPromptView()).setComponentPopupMenu(menu);
185
186         ((JTextPane) getConfiguration().getInputCommandView()).requestFocus();
187
188         addFocusListener(new FocusListener() {
189                 public void focusGained(FocusEvent e) {
190                     ((JTextPane) getConfiguration().getInputCommandView()).requestFocus();
191                 }
192
193                 public void focusLost(FocusEvent e) { }
194             });
195     }
196
197     /**
198      * Displays data in the console
199      * @param dataToDisplay the data to be displayed
200      * @see fr.scilab.console.HelpBrowser#display(java.lang.String)
201      */
202     public void display(String dataToDisplay) {
203         this.getConfiguration().getOutputView().append(dataToDisplay);
204     }
205
206     /**
207      * This method is used to display the prompt
208      */
209     public void displayPrompt() {
210         SwingUtilities.invokeLater(new Runnable() {
211                 public void run() {
212                     InputCommandView inputCmdView = SwingScilabConsole.this.getConfiguration().getInputCommandView();
213
214                     // Show the prompt
215                     SwingScilabConsole.this.getConfiguration().getPromptView().setVisible(true);
216
217                     // Show the input command view and its hidden components
218                     inputCmdView.setEditable(true);
219                     ((JTextPane) inputCmdView).setCaretColor(((JTextPane) inputCmdView).getForeground());
220                     ((JTextPane) inputCmdView).getCaret().setVisible(true);
221                     setToHome();
222                 }
223             });
224
225         ((SciOutputView) this.getConfiguration().getOutputView()).resetLastEOL();
226
227         updateScrollPosition();
228     }
229
230     /**
231      * Unblock the console if needed
232      */
233     public void unblock() {
234         if (getCanReadUserInputValue().availablePermits() == 0) {
235             setUserInputValue((int) 'n');
236         }
237     }
238
239     /**
240      * Reads one user input char
241      * @return the data entered by the user
242      * @see fr.scilab.console.HelpBrowser#getCharWithoutOutput()
243      */
244     public int getCharWithoutOutput() {
245         int retChar;
246
247         updateScrollPosition();
248
249         // Avoids reading of an empty buffer
250         try {
251             ((SciConsole) this).getCanReadUserInputValue().acquire();
252         } catch (InterruptedException e) {
253             // TODO Auto-generated catch block
254             e.printStackTrace();
255         }
256
257         this.getConfiguration().getPromptView().setVisible(false);
258         this.getConfiguration().getInputCommandView().setEditable(false);
259
260         // Add a keylistener which will set the returned char
261         OneCharKeyEventListener keyListener = new OneCharKeyEventListener(this);
262         ((JTextPane) this.getConfiguration().getInputCommandView()).addKeyListener(keyListener);
263         ((JEditorPane) this.getConfiguration().getOutputView()).addKeyListener(keyListener);
264
265         // Reads the buffer
266         retChar = this.getUserInputValue();
267         ((SciConsole) this).getCanReadUserInputValue().release();
268
269         // Remove the "more" message and replace it by an empty line
270         this.clear(-1);
271         this.display(StringConstants.NEW_LINE);
272
273         // Remove the key listener
274         ((JTextPane) this.getConfiguration().getInputCommandView()).removeKeyListener(keyListener);
275         ((JEditorPane) this.getConfiguration().getOutputView()).removeKeyListener(keyListener);
276
277         this.getConfiguration().getPromptView().setVisible(true);
278         this.getConfiguration().getInputCommandView().setEditable(true);
279
280         // Send back the focus the the input view
281         this.getConfiguration().getInputCommandView().reset();
282         this.getConfiguration().getInputCommandView().requestFocus();
283
284         final JTextPane cmdView = (JTextPane) this.getConfiguration().getInputCommandView();
285         SwingUtilities.invokeLater(new Runnable() {
286                 public void run() {
287                     cmdView.getCaret().setVisible(true);
288                 }
289             });
290
291         return retChar;
292     }
293
294     /**
295      * Draw a console
296      */
297     public void draw() {
298         super.setVisible(true);
299         super.doLayout();
300     }
301
302     /**
303      * Gets the dimensions (width and height) of a Scilab console
304      * @return the size of the console
305      */
306     public Size getDims() {
307         return new Size(super.getWidth(), super.getHeight());
308     }
309
310     /**
311      * Gets the position (X-coordinate and Y-coordinates) of a Scilab console
312      * @return the position of the console
313      */
314     public Position getPosition() {
315         return new Position(this.getX(), this.getY());
316     }
317
318     /**
319      * Gets the visibility status of a console
320      * @return the visibility status of the console (true if the console is visible, false if not)
321      */
322     public boolean isVisible() {
323         return super.isVisible();
324     }
325
326     /**
327      * Sets the dimensions (width and height) of a Scilab console
328      * @param newSize the size we want to set to the console
329      */
330     public void setDims(Size newSize) {
331         this.setPreferredSize(new Dimension(newSize.getWidth(), newSize.getHeight()));
332     }
333
334     /**
335      * Sets the position (X-coordinate and Y-coordinate) of a Scilab console
336      * @param newPosition the position we want to set to the console
337      */
338     public void setPosition(Position newPosition) {
339         this.setLocation(newPosition.getX(), newPosition.getY());
340     }
341
342     /**
343      * Sets the visibility status of a Scilab console
344      * @param newVisibleState the visibility status we want to set to the console
345      */
346     public void setVisible(boolean newVisibleState) {
347         super.setVisible(newVisibleState);
348     }
349
350     /**
351      * Clears the Console
352      */
353     public void clear() {
354         super.clear();
355     }
356
357     /**
358      * Sets the prompt displayed in the console
359      * @param prompt the prompt to be displayed in the console
360      */
361     public void setPrompt(String prompt) {
362         this.getConfiguration().getPromptView().setDefaultPrompt(prompt);
363     }
364
365     /**
366      * Clear the commands history
367      */
368     public void clearHistory() {
369         ((SciHistoryManager) this.getConfiguration().getHistoryManager()).reset();
370     }
371
372     /**
373      * Paste clipboard contents in Console input line
374      */
375     public void pasteClipboard() {
376         // Gets the contents of the clipboard
377         Toolkit toolkit = Toolkit.getDefaultToolkit();
378         Clipboard systemClipboard = toolkit.getSystemClipboard();
379
380         // Verify that clibpboard data is of text type
381         boolean dataAvailable;
382         try {
383             dataAvailable = systemClipboard.isDataFlavorAvailable(DataFlavor.stringFlavor);
384         } catch (IllegalStateException exception) {
385             return;
386         }
387
388         // Exit if text data not available
389         if (!dataAvailable) {
390             return;
391         }
392
393         // Read data
394         String clipboardContents = null;
395         try {
396             clipboardContents = (String) systemClipboard.getData(DataFlavor.stringFlavor);
397         } catch (UnsupportedFlavorException e1) {
398             // Should never be here
399             e1.printStackTrace();
400         } catch (IOException e1) {
401             // Should never be here
402             e1.printStackTrace();
403         }
404
405         JTextPane input = ((JTextPane) this.getConfiguration().getInputCommandView());
406         StyledDocument doc = input.getStyledDocument();
407
408         // If some text selected then it is replaced
409         if (input.getSelectedText() != null) {
410             try {
411                 doc.remove(input.getSelectionStart(), input.getSelectionEnd() - input.getSelectionStart());
412             } catch (BadLocationException e) {
413                 // TODO Auto-generated catch block
414                 e.printStackTrace();
415             }
416         }
417         // Insert clipboard contents
418         try {
419             doc.insertString(((JTextPane) this.getConfiguration().getInputCommandView()).getCaretPosition(),
420                              clipboardContents, doc.getStyle(StyleContext.DEFAULT_STYLE));
421         } catch (BadLocationException e) {
422             // TODO Auto-generated catch block
423             e.printStackTrace();
424         }
425     }
426
427     /**
428      * Select all the console contents
429      */
430     public void selectAll() {
431         JEditorPane output = (JEditorPane) this.getConfiguration().getOutputView();
432         output.setSelectionStart(0);
433         output.setSelectionEnd(output.getText().length());
434         // TODO should also select the prompt and the input
435     }
436
437     /**
438      * Return the selected text in the console
439      * @return The selected text in the console
440      */
441     private String getSelectedText() {
442         JEditorPane output = (JEditorPane) this.getConfiguration().getOutputView();
443         JTextPane input = (JTextPane) this.getConfiguration().getInputCommandView();
444
445         String selection = "";
446         if (output.getSelectedText() != null) {
447             selection += output.getSelectedText();
448         }
449         // TODO should also copy the prompt
450         if (input.getSelectedText() != null) {
451             selection += input.getSelectedText();
452         }
453         return selection;
454
455     }
456
457     /**
458      * Launch the help on the selected text into the Console
459      */
460     public void helpOnTheKeyword() {
461         String keyword = getSelectedText();
462         /* Double the quote/double quote in order to avoid
463          * and error with the call of help()
464          */
465         keyword=keyword.replaceAll("'", "''");
466         keyword=keyword.replaceAll("\"", "\"\"");
467
468         /* @TODO: Check if it is possible to call directly
469          * from the Java engine the help
470          * Last time I check, we needed some information
471          * provided by the Scilab native engine
472          */
473         InterpreterManagement.requestScilabExec("help('"+keyword+"')");
474     }
475
476     /**
477      * Evaluate the selection with echo
478      */
479     public void evaluateSelectionWithEcho() {
480         String selection = getSelectedText();
481         if (selection.compareTo("") != 0) {
482             StringTokenizer tokens = new StringTokenizer(selection, "\n");
483             String[] lines = new String[tokens.countTokens()];
484             int i = 0;
485             while (tokens.hasMoreTokens()) {
486                 lines[i++] = tokens.nextToken();
487             }
488             HistoryManagement.appendLinesToScilabHistory(lines, lines.length);
489             sendCommandsToScilab(selection, true, false);
490         }
491     }
492
493     /**
494      * Evaluate the selection with no echo
495      */
496     public void evaluateSelectionWithNoEcho() {
497         sendCommandsToScilab(getSelectedText(), false, false);
498     }
499
500     /**
501      * Put the console selected text in the clipboard
502      */
503     public void copyToClipboard() {
504         String selection = getSelectedText();
505         Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selection), null);
506     }
507
508     /**
509      * Cut selected text in the Console input line
510      */
511     public void cutSelection() {
512         JTextPane input = (JTextPane) this.getConfiguration().getInputCommandView();
513         StyledDocument doc = input.getStyledDocument();
514
515         // If some text selected then it is replaced
516         if (input.getSelectedText() != null) {
517             try {
518                 /* Put the selection in the clipboard */
519                 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(input.getSelectedText()), null);
520                 /* Remove selected text */
521                 doc.remove(input.getSelectionStart(), input.getSelectionEnd() - input.getSelectionStart());
522             } catch (BadLocationException e) {
523                 // TODO Auto-generated catch block
524                 e.printStackTrace();
525             }
526         }
527     }
528
529     /**
530      * Set the maximum number of lines stored in the Output
531      * @param nbLines the number of lines
532      */
533     public void setMaxOutputSize(int nbLines) {
534         ((SciOutputView) this.getConfiguration().getOutputView()).setMaxSize(nbLines);
535     }
536 }