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