Bug 13336 fixed: In SciNotes it was not possible to complete brackets only at eol
[scilab.git] / scilab / modules / scinotes / src / java / org / scilab / modules / scinotes / HelpOnTypingManager.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - Calixte DENIZET
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.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.scinotes;
14
15 import java.awt.event.KeyListener;
16 import java.awt.event.KeyEvent;
17
18 import javax.swing.text.BadLocationException;
19
20 import org.scilab.modules.commons.xml.XConfiguration;
21
22 /**
23  * This class handles the help on typing
24  * @author Calixte DENIZET
25  */
26 public final class HelpOnTypingManager implements KeyListener {
27
28     private static HelpOnTypingManager instance;
29     private boolean openers;
30     private boolean keywords;
31
32     /**
33      * Constructor
34      */
35     private HelpOnTypingManager() {
36         super();
37         instance = this;
38         openers = SciNotesOptions.getSciNotesDisplay().autoCompleteOpeners;
39         keywords = SciNotesOptions.getSciNotesDisplay().autoCompleteKeywords;
40     }
41
42     /**
43      * Clean
44      */
45     public static void close() {
46         instance = null;
47     }
48
49     /**
50      * @return the singleton instance of HelpOnTypingManager
51      */
52     public static HelpOnTypingManager getInstance() {
53         if (instance == null) {
54             instance = new HelpOnTypingManager();
55         }
56
57         return instance;
58     }
59
60     /**
61      * @param b true if autocompletion on '(', '{', ...
62      */
63     public void enableOpeners(boolean b) {
64         openers = b;
65         SciNotesOptions.getSciNotesDisplay().autoCompleteOpeners = b;
66         XConfiguration.set(XConfiguration.getXConfigurationDocument(), SciNotesOptions.DISPLAYPATH + "/@auto-complete-openers", Boolean.toString(b));
67     }
68
69     /**
70      * @param b true if autocompletion on 'if', 'function', ...
71      */
72     public void enableKeywords(boolean b) {
73         keywords = b;
74         SciNotesOptions.getSciNotesDisplay().autoCompleteKeywords = b;
75         XConfiguration.set(XConfiguration.getXConfigurationDocument(), SciNotesOptions.DISPLAYPATH + "/@auto-complete-keywords", Boolean.toString(b));
76     }
77
78     /**
79      * @return true if help on typing is active
80      */
81     public boolean isActive() {
82         return openers || keywords;
83     }
84
85     /**
86      * @return true if help on typing for the openers is active
87      */
88     public boolean isOpenersActive() {
89         return openers;
90     }
91
92     /**
93      * @return true if help on typing for the openers is active
94      */
95     public boolean isKeywordsActive() {
96         return keywords;
97     }
98
99     /**
100      * Nothing !
101      * @param e the event
102      */
103     public void keyPressed(KeyEvent e) { }
104
105     /**
106      * Nothing !
107      * @param e the event
108      */
109     public void keyReleased(KeyEvent e) { }
110
111     /**
112      * Called when a key is typed
113      * @param e the event
114      */
115     public void keyTyped(KeyEvent e) {
116         char c = e.getKeyChar();
117         ScilabEditorPane textPane = ScilabEditorPane.getFocusedPane();
118         ScilabDocument doc = (ScilabDocument) textPane.getDocument();
119         if (isActive() && c != KeyEvent.CHAR_UNDEFINED && textPane.getSelectionStart() == textPane.getSelectionEnd()) {
120             int pos = textPane.getCaretPosition();
121             if (c == ' ' && e.getModifiers() == 0) {
122                 int end = doc.getDefaultRootElement().getElement(doc.getDefaultRootElement().getElementIndex(pos)).getEndOffset() - 1;
123                 /* the following test is used to know if an insertion in the line is done */
124                 if (pos == end) {
125                     try {
126                         doc.insertString(pos, " ", null);
127                         e.consume();
128                         KeywordEvent kwe = textPane.getKeywordEvent(pos);
129                         int[] ret;
130                         String kw;
131                         switch (kwe.getType()) {
132                         case ScilabLexerConstants.OSKEYWORD :
133                             kw = doc.getText(kwe.getStart(), kwe.getLength());
134                             if ("if".equals(kw)) {
135                                 if (complete("end", textPane, doc, pos)) {
136                                     doc.insertString(pos + 1, " then\nend", null);
137                                     ret = textPane.getIndentManager().indentDoc(pos + 1, pos + 9);
138                                     textPane.setCaretPosition(ret[0]);
139                                 }
140                             } else if (!"end".equals(kw)) {
141                                 if (complete("end", textPane, doc, pos)) {
142                                     doc.insertString(pos + 1, "\nend", null);
143                                     ret = textPane.getIndentManager().indentDoc(pos + 1, pos + 4);
144                                     textPane.setCaretPosition(ret[0]);
145                                 }
146                             }
147                             break;
148                         case ScilabLexerConstants.SKEYWORD :
149                             kw = doc.getText(kwe.getStart(), kwe.getLength());
150                             if ("elseif".equals(kw)) {
151                                 doc.insertString(pos + 1, " then", null);
152                                 textPane.setCaretPosition(pos + 1);
153                             }
154                             break;
155                         case ScilabLexerConstants.FKEYWORD :
156                             /* We have 'function' or 'endfunction' */
157                             if ("f".equals(doc.getText(kwe.getStart(), 1)) && complete("endfunction", textPane, doc, pos)) {
158                                 doc.insertString(pos + 1, "()\nendfunction", null);
159                                 textPane.getIndentManager().indentDoc(pos + 3, pos + 14);
160                                 textPane.setCaretPosition(pos + 1);
161                             }
162                             break;
163                         default :
164                         }
165                     } catch (BadLocationException exc) {
166                         System.err.println(exc);
167                     }
168                 }
169             } else if (openers) {
170                 if (SciNotesOptions.getSciNotesPreferences().completeAtEOL) {
171                     int end = doc.getDefaultRootElement().getElement(doc.getDefaultRootElement().getElementIndex(pos)).getEndOffset() - 1;
172                     if (pos != end) {
173                         return;
174                     }
175                 }
176
177                 try {
178                     String str;
179                     switch (c) {
180                     case '(' :
181                         if (complete(')', textPane, doc, pos)) {
182                             str = "()";
183                         } else {
184                             return;
185                         }
186                         break;
187                     case '[' :
188                         if (complete(']', textPane, doc, pos)) {
189                             str = "[]";
190                         } else {
191                             return;
192                         }
193                         break;
194                     case '{' :
195                         if (complete('}', textPane, doc, pos)) {
196                             str = "{}";
197                         } else {
198                             return;
199                         }
200                         break;
201                     case '\"' :
202                         str = "\"\"";
203                         break;
204                     default :
205                         return;
206                     }
207
208                     doc.insertString(pos, str, null);
209                     e.consume();
210                     textPane.setCaretPosition(pos + 1);
211                 } catch (BadLocationException exc) {
212                     System.err.println(exc);
213                 }
214             }
215         }
216     }
217
218     private static boolean complete(char next, ScilabEditorPane pane, ScilabDocument doc, int pos) throws BadLocationException {
219         MatchingBlockManager matchLR = pane.getMatchingBlockManager(true);
220         MatchingBlockScanner scanner = matchLR.getScanner();
221         MatchingBlockScanner.MatchingPositions mpos = scanner.getNextBlock(pos, true);
222         if (mpos != null) {
223             char mc = doc.getText(mpos.secondB, 1).charAt(0);
224             if (mc != next) {
225                 return true;
226             }
227
228             return false;
229         }
230
231         return true;
232     }
233
234     private static boolean complete(String next, ScilabEditorPane pane, ScilabDocument doc, int pos) throws BadLocationException {
235         MatchingBlockManager matchLR = pane.getMatchingBlockManager(true);
236         MatchingBlockScanner scanner = matchLR.getScanner();
237         MatchingBlockScanner.MatchingPositions mpos = scanner.getNextBlock(pos, true);
238         if (mpos != null) {
239             String ms = doc.getText(mpos.secondB, mpos.secondE - mpos.secondB);
240             if (!next.equals(ms)) {
241                 return true;
242             }
243
244             return false;
245         }
246
247         return true;
248     }
249 }