Small improvements in parser
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpeclipse / ui / editor / I18NDocumentProvider.java
1 /*
2  * Copyright (c) 2002-2004 Widespace, OU and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://solareclipse.sourceforge.net/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     Igor Malinin - initial contribution
10  * 
11  * $Id: I18NDocumentProvider.java,v 1.1 2004-09-02 18:26:30 jsurfer Exp $
12  */
13
14 package net.sourceforge.phpeclipse.ui.editor;
15
16 import java.io.ByteArrayInputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.io.Reader;
21 import java.io.UnsupportedEncodingException;
22
23 import org.eclipse.core.resources.IFile;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Status;
28 import org.eclipse.core.runtime.SubProgressMonitor;
29 import org.eclipse.jface.text.IDocument;
30 import org.eclipse.ui.IFileEditorInput;
31 import org.eclipse.ui.IStorageEditorInput;
32 import org.eclipse.ui.PlatformUI;
33 import org.eclipse.ui.dialogs.ContainerGenerator;
34 import org.eclipse.ui.editors.text.FileDocumentProvider;
35 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
36
37 /**
38  * @author Igor Malinin
39  */
40 public class I18NDocumentProvider extends FileDocumentProvider {
41
42         private static final char BOM = 0xFEFF;
43
44         /*
45          * @see org.eclipse.ui.editors.text.StorageDocumentProvider#setDocumentContent(IDocument,
46          *      InputStream, String)
47          */
48         protected void setDocumentContent(IDocument document,
49                         InputStream contentStream, String encoding) throws CoreException {
50                 Reader in = null;
51
52                 try {
53                         if (encoding == null) {
54                                 encoding = getDefaultEncoding();
55                         }
56
57                         in = new InputStreamReader(contentStream, encoding);
58
59                         StringBuffer buffer = new StringBuffer();
60
61                         char[] readBuffer = new char[2048];
62                         int n = in.read(readBuffer);
63                         while (n > 0) {
64                                 buffer.append(readBuffer, 0, n);
65                                 n = in.read(readBuffer);
66                         }
67
68                         if (buffer.length() > 0 && buffer.charAt(0) == BOM) {
69                                 buffer.deleteCharAt(0);
70                         }
71
72                         document.set(buffer.toString());
73                 } catch (IOException x) {
74                         String msg = x.getMessage();
75                         if (msg == null) {
76                                 msg = ""; //$NON-NLS-1$
77                         }
78
79                         IStatus s = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
80                                         IStatus.OK, msg, x);
81
82                         throw new CoreException(s);
83                 } finally {
84                         if (in != null) try {
85                                 in.close();
86                         } catch (IOException x) {
87                         }
88                 }
89         }
90
91         /*
92          * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#doSaveDocument(IProgressMonitor,
93          *      Object, IDocument, boolean)
94          */
95         protected void doSaveDocument(IProgressMonitor monitor, Object element,
96                         IDocument document, boolean overwrite) throws CoreException {
97                 if (!(element instanceof IFileEditorInput)) {
98                         super.doSaveDocument(monitor, element, document, overwrite);
99                         return;
100                 }
101
102                 IFileEditorInput input = (IFileEditorInput) element;
103
104                 try {
105                         String content = document.get();
106
107                         String encoding = getDeclaredEncoding(new ByteArrayInputStream(
108                                         content.getBytes("ISO-8859-1")));
109
110                         if (encoding == null) {
111                                 encoding = super.getEncoding(element);
112                                 if (encoding == null /* || !encoding.startsWith("UTF-16") */) {
113                                         encoding = getDefaultEncoding();
114                                 }
115                         } else {
116                                 setEncoding(element, encoding);
117                         }
118
119                         if (encoding.startsWith("UTF-16")) {
120                                 content = BOM + content;
121                         }
122
123                         InputStream stream;
124                         try {
125                                 stream = new ByteArrayInputStream(content.getBytes(encoding));
126                         } catch (UnsupportedEncodingException e) {
127                                 IStatus s = new Status(
128                                                 IStatus.ERROR,
129                                                 PlatformUI.PLUGIN_ID,
130                                                 IStatus.OK,
131                                                 EditorMessages
132                                                                 .getString("I18NDocumentProvider.error.encoding"),
133                                                 e);
134
135                                 throw new CoreException(s);
136                         }
137
138                         IFile file = input.getFile();
139                         if (file.exists()) {
140                                 FileInfo info = (FileInfo) getElementInfo(element);
141
142                                 if (info != null && !overwrite) {
143                                         checkSynchronizationState(info.fModificationStamp, file);
144                                 }
145
146                                 // inform about the upcoming content change
147                                 fireElementStateChanging(element);
148
149                                 try {
150                                         file.setContents(stream, overwrite, true, monitor);
151                                 } catch (CoreException x) {
152                                         // inform about failure
153                                         fireElementStateChangeFailed(element);
154                                         throw x;
155                                 } catch (RuntimeException x) {
156                                         // inform about failure
157                                         fireElementStateChangeFailed(element);
158                                         throw x;
159                                 }
160
161                                 // If here, the editor state will be flipped to "not dirty".
162                                 // Thus, the state changing flag will be reset.
163
164                                 if (info != null) {
165                                         ResourceMarkerAnnotationModel model = (ResourceMarkerAnnotationModel) info.fModel;
166
167                                         model.updateMarkers(info.fDocument);
168
169                                         info.fModificationStamp = computeModificationStamp(file);
170                                 }
171                         } else {
172                                 try {
173                                         monitor.beginTask(EditorMessages
174                                                         .getString("I18NDocumentProvider.task.saving"), //$NON-NLS-1$
175                                                         2000);
176
177                                         ContainerGenerator generator = new ContainerGenerator(file
178                                                         .getParent().getFullPath());
179
180                                         generator.generateContainer(new SubProgressMonitor(monitor,
181                                                         1000));
182
183                                         file.create(stream, false, new SubProgressMonitor(monitor,
184                                                         1000));
185                                 } finally {
186                                         monitor.done();
187                                 }
188                         }
189                 } catch (IOException x) {
190                         IStatus s = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
191                                         IStatus.OK, x.getMessage(), x);
192
193                         throw new CoreException(s);
194                 }
195         }
196
197         /*
198          * @see org.eclipse.ui.editors.text.IStorageDocumentProvider#getEncoding(Object)
199          */
200         public String getEncoding(Object element) {
201                 String encoding = super.getEncoding(element);
202                 if (encoding != null) {
203                         return encoding;
204                 }
205
206                 if (element instanceof IStorageEditorInput) {
207                         IStorageEditorInput sei = (IStorageEditorInput) element;
208
209                         try {
210                                 InputStream in = sei.getStorage().getContents();
211                                 try {
212                                         encoding = getDeclaredEncoding(in);
213                                 } finally {
214                                         in.close();
215                                 }
216                         } catch (CoreException e) {
217                         } catch (IOException e) {
218                         }
219
220                         if (encoding == null) {
221                                 encoding = getDefaultEncoding();
222                         }
223
224                         setEncoding(element, encoding);
225                 }
226
227                 return encoding;
228         }
229
230         /*
231          * @see org.eclipse.ui.editors.text.IStorageDocumentProvider#setEncoding(Object,
232          *      String)
233          */
234         public void setEncoding(Object element, String encoding) {
235                 if (encoding == null) {
236                         encoding = getDefaultEncoding();
237                 }
238
239                 super.setEncoding(element, encoding);
240         }
241
242         /**
243          * Tries to determine encoding from contents of the stream. Returns <code>null</code>
244          * if encoding is unknown.
245          */
246         public String getDeclaredEncoding(InputStream in) throws IOException {
247                 return getBOMEncoding(in);
248         }
249
250         /**
251          * Tries to determine encoding from the byte order mark. Returns <code>null</code>
252          * if encoding is unknown.
253          */
254         private String getBOMEncoding(InputStream in) throws IOException {
255                 int first = in.read();
256                 if (first < 0) {
257                         return null;
258                 }
259
260                 int second = in.read();
261                 if (second < 0) {
262                         return null;
263                 }
264
265                 // look for the UTF-16 Byte Order Mark (BOM)
266                 if (first == 0xFE && second == 0xFF) {
267                         return "UTF-16BE";
268                 }
269
270                 if (first == 0xFF && second == 0xFE) {
271                         return "UTF-16LE";
272                 }
273
274                 int third = in.read();
275                 if (third < 0) {
276                         return null;
277                 }
278
279                 // look for the UTF-8 BOM
280                 if (first == 0xEF && second == 0xBB && third == 0xBF) {
281                         return "UTF-8";
282                 }
283
284                 return null;
285         }
286 }