Preferences: continue to connect SciNotes
[scilab.git] / scilab / modules / scinotes / src / java / org / scilab / modules / scinotes / ScilabEditorKit.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-en.txt
10  *
11  */
12
13 package org.scilab.modules.scinotes;
14
15 import java.io.BufferedReader;
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.IOException;
19 import java.io.InputStreamReader;
20 import java.io.Reader;
21 import java.nio.CharBuffer;
22 import java.nio.charset.CharacterCodingException;
23 import java.nio.charset.Charset;
24 import java.nio.charset.CharsetDecoder;
25 import java.nio.charset.CodingErrorAction;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import javax.swing.text.BadLocationException;
30 import javax.swing.text.DefaultEditorKit;
31 import javax.swing.text.Document;
32 import javax.swing.text.ViewFactory;
33
34 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
35 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
36 import org.scilab.modules.scinotes.actions.EncodingAction;
37 import org.scilab.modules.scinotes.utils.ConfigSciNotesManager;
38 import org.scilab.modules.scinotes.utils.SciNotesMessages;
39
40 /**
41  * The class ScilabEditorKit provides the minimal things needed to render
42  * a Scilab's document.
43  * @author Calixte DENIZET
44  */
45 public class ScilabEditorKit extends DefaultEditorKit {
46
47     private static final long serialVersionUID = 8005575461386086815L;
48
49     /**
50      * The mimetype for a scilab code
51      */
52     public static final String MIMETYPE = "text/scilab";
53     private static final int BUFFERCAPACITY = 8192;
54     public static final String[] ENCODINGS = new String[] {"utf-8", "windows-1252", "iso-8859-1"};
55     private static final Map<String, Integer> encPos = new HashMap<String, Integer>(ENCODINGS.length);
56
57     static {
58         for (int i = 0; i < ENCODINGS.length; i++) {
59             encPos.put(ENCODINGS[i], i);
60         }
61     }
62
63     private final char[] buffer = new char[BUFFERCAPACITY];
64
65     private ScilabContext preferences;
66     private boolean plain;
67
68     /**
69      * Default constructor
70      */
71     public ScilabEditorKit() {
72         super();
73     }
74
75     /**
76      * Constructor
77      * @param plain is true to use a plain view (no line-wrapping)
78      */
79     public ScilabEditorKit(boolean plain) {
80         super();
81         this.plain = plain;
82     }
83
84     public boolean isPlain() {
85         return plain;
86     }
87
88     /**
89      * @return the mime type
90      */
91     public String getContentType() {
92         return MIMETYPE;
93     }
94
95     /**
96      * @return a new ScilabDocument
97      */
98     public Document createDefaultDocument() {
99         return new ScilabDocument();
100     }
101
102     /**
103      * @return the context associated with the ScilabDocument
104      */
105     public ScilabContext getStylePreferences() {
106         if (preferences == null) {
107             preferences = new ScilabContext(plain);
108         }
109
110         return preferences;
111     }
112
113     /**
114      * Set the context to render the document
115      * @param prefs the context to use
116      */
117     public void setStylePreferences(ScilabContext prefs) {
118         preferences = prefs;
119     }
120
121     /**
122      * @return the ViewFactory used to create a View to render a ScilabDocument
123      */
124     public ViewFactory getViewFactory() {
125         return getStylePreferences();
126     }
127
128     /**
129      * @param file the file to test
130      * @return the corresponding charset if exists
131      * @throws IOExecption if I/O problems are met
132      * @throws CharacterCodingException if no charset is found
133      */
134     public static Charset tryToGuessEncoding(File file) throws IOException, CharacterCodingException {
135         for (int i = 0; i < ENCODINGS.length; i++) {
136             if (tryToGuessEncoding(file, Charset.forName(ENCODINGS[i]))) {
137                 return Charset.forName(ENCODINGS[i]);
138             }
139         }
140
141         throw new CharacterCodingException();
142     }
143
144     /**
145      * @param file the file to test
146      * @param charset the charset to test
147      * @return true if the file can be decoded with the charset
148      * @throws IOExecption if I/O problems are met
149      */
150     public static boolean tryToGuessEncoding(File file, Charset charset) throws IOException {
151         char[] cbuf = new char[BUFFERCAPACITY];
152         CharsetDecoder decoder = charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT);
153         FileInputStream fis = new FileInputStream(file);
154         InputStreamReader inReader = new InputStreamReader(fis, decoder);
155         BufferedReader bufReader = new BufferedReader(inReader);
156         try {
157             while (bufReader.read(cbuf) != -1);
158             fis.close();
159             inReader.close();
160             bufReader.close();
161             return true;
162         } catch (Exception e) { }
163
164         return false;
165     }
166
167     /**
168      * The read method is used to read the file and to write its contents
169      * in the document at position pos
170      * @param file the file to read
171      * @param doc the Document where to write
172      * @param pos position where to write
173      * @throws CharacterCodingException if an unreadable char is encountered
174      * @throws IOException if a problem is encountered in reading the stream
175      * @throws BadLocationException if the pos is invalid
176      */
177     public void read(SciNotes editor, File file, Document doc, int pos) throws IOException, BadLocationException {
178         Charset charset = Charset.forName(SciNotesOptions.getSciNotesPreferences().encoding);
179         try {
180             charset = tryToGuessEncoding(file);
181         } catch (CharacterCodingException e) {
182             ScilabModalDialog.show(editor, SciNotesMessages.CANNOT_GUESS_ENCODING, SciNotesMessages.SCINOTES_ERROR, IconType.ERROR_ICON);
183         }
184         ((ScilabDocument) doc).setEncoding(charset.toString());
185         EncodingAction.updateEncodingMenu((ScilabDocument) doc);
186         FileInputStream fis = new FileInputStream(file);
187         InputStreamReader isr = new InputStreamReader(fis, charset);
188         BufferedReader br = new BufferedReader(isr);
189         read(br, doc, pos);
190         try {
191             br.close();
192         } catch (IOException e) { }
193     }
194
195     /**
196      * The read method is used to read the Reader and to write its contents
197      * in the document at position pos
198      * @param in the Reader to read
199      * @param doc the Document where to write
200      * @param pos position where to write
201      * @throws IOException if a problem is encountered in reading the stream
202      * @throws BadLocationException if the pos is invalid
203      */
204     public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
205         DocString docString = read(in);
206         ((ScilabDocument) doc).setEOL(docString.eol);
207         ((ScilabDocument) doc).setBinary(docString.isBinary);
208         doc.insertString(pos, docString.content, null);
209     }
210
211     /**
212      * The read method is used to read the Reader and to write its contents
213      * in the document at position pos
214      * @param in the Reader to read
215      * @throws IOException if a problem is encountered in reading the stream
216      */
217     public DocString read(Reader in) throws IOException {
218         int nch;
219         int i;
220         int prev;
221         int inc = 0;
222         boolean win = false;
223         boolean mac = false;
224         boolean first = true;
225         boolean binary = false;
226         DocString docString = new DocString();
227         StringBuilder sbuf = new StringBuilder(buffer.length);
228         while ((nch = in.read(buffer, 0, buffer.length)) != -1) {
229             if (first) {
230                 /* We try to know if we have a binary file
231                    The rule is : two \0 in the first 8ko : it's binary ! */
232                 CharBuffer cb = CharBuffer.wrap(buffer);
233                 byte[] bytes = Charset.forName("utf-8").encode(cb).array();
234                 for (i = 0; i < nch; i++) {
235                     if (bytes[i] == 0 ) {
236                         inc++;
237                         if (inc == 2) {
238                             binary = true;
239                             break;
240                         }
241                     }
242                 }
243                 first = false;
244             }
245
246             prev = 0;
247             if (!binary) {
248                 for (i = 0; i < nch - 1; i++) {
249                     if (buffer[i] == '\r') {
250                         buffer[i] = '\n';
251                         sbuf.append(buffer, prev, i - prev + 1);
252                         if (buffer[i + 1] == '\n') {
253                             i++;
254                             if (!win && !mac) {
255                                 docString.eol = ScilabDocument.EOLWIN;
256                                 win = true;
257                             }
258                         } else {
259                             if (!win && !mac) {
260                                 docString.eol = ScilabDocument.EOLMAC;
261                                 mac = true;
262                             }
263                         }
264
265                         prev = i + 1;
266                     }
267                 }
268
269                 if (i == nch - 1) {
270                     if (buffer[i] == '\r') {
271                         if (!win && !mac) {
272                             docString.eol = ScilabDocument.EOLMAC;
273                         }
274                         buffer[i] = '\n';
275                     }
276                     sbuf.append(buffer, prev, i - prev + 1);
277                 }
278             } else {
279                 sbuf.append(buffer, 0, nch);
280             }
281         }
282         if (!win && !mac) {
283             docString.eol = ScilabDocument.EOLUNIX;
284         }
285
286         docString.isBinary = inc == 2;
287         docString.content = sbuf.toString();
288
289         return docString;
290     }
291
292     public static class DocString {
293
294         public String eol;
295         public boolean isBinary;
296         public String content;
297
298         DocString() { }
299     }
300 }