Added some more tests,a nd reformtted the code a little.
[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.2 2006-10-21 23:13:54 pombredanne 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)
85                                 try {
86                                         in.close();
87                                 } catch (IOException x) {
88                                 }
89                 }
90         }
91
92         /*
93          * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#doSaveDocument(IProgressMonitor,
94          *      Object, IDocument, boolean)
95          */
96         protected void doSaveDocument(IProgressMonitor monitor, Object element,
97                         IDocument document, boolean overwrite) throws CoreException {
98                 if (!(element instanceof IFileEditorInput)) {
99                         super.doSaveDocument(monitor, element, document, overwrite);
100                         return;
101                 }
102
103                 IFileEditorInput input = (IFileEditorInput) element;
104
105                 try {
106                         String content = document.get();
107
108                         String encoding = getDeclaredEncoding(new ByteArrayInputStream(
109                                         content.getBytes("ISO-8859-1")));
110
111                         if (encoding == null) {
112                                 encoding = super.getEncoding(element);
113                                 if (encoding == null /* || !encoding.startsWith("UTF-16") */) {
114                                         encoding = getDefaultEncoding();
115                                 }
116                         } else {
117                                 setEncoding(element, encoding);
118                         }
119
120                         if (encoding.startsWith("UTF-16")) {
121                                 content = BOM + content;
122                         }
123
124                         InputStream stream;
125                         try {
126                                 stream = new ByteArrayInputStream(content.getBytes(encoding));
127                         } catch (UnsupportedEncodingException e) {
128                                 IStatus s = new Status(
129                                                 IStatus.ERROR,
130                                                 PlatformUI.PLUGIN_ID,
131                                                 IStatus.OK,
132                                                 EditorMessages
133                                                                 .getString("I18NDocumentProvider.error.encoding"),
134                                                 e);
135
136                                 throw new CoreException(s);
137                         }
138
139                         IFile file = input.getFile();
140                         if (file.exists()) {
141                                 FileInfo info = (FileInfo) getElementInfo(element);
142
143                                 if (info != null && !overwrite) {
144                                         checkSynchronizationState(info.fModificationStamp, file);
145                                 }
146
147                                 // inform about the upcoming content change
148                                 fireElementStateChanging(element);
149
150                                 try {
151                                         file.setContents(stream, overwrite, true, monitor);
152                                 } catch (CoreException x) {
153                                         // inform about failure
154                                         fireElementStateChangeFailed(element);
155                                         throw x;
156                                 } catch (RuntimeException x) {
157                                         // inform about failure
158                                         fireElementStateChangeFailed(element);
159                                         throw x;
160                                 }
161
162                                 // If here, the editor state will be flipped to "not dirty".
163                                 // Thus, the state changing flag will be reset.
164
165                                 if (info != null) {
166                                         ResourceMarkerAnnotationModel model = (ResourceMarkerAnnotationModel) info.fModel;
167
168                                         model.updateMarkers(info.fDocument);
169
170                                         info.fModificationStamp = computeModificationStamp(file);
171                                 }
172                         } else {
173                                 try {
174                                         monitor.beginTask(EditorMessages
175                                                         .getString("I18NDocumentProvider.task.saving"), //$NON-NLS-1$
176                                                         2000);
177
178                                         ContainerGenerator generator = new ContainerGenerator(file
179                                                         .getParent().getFullPath());
180
181                                         generator.generateContainer(new SubProgressMonitor(monitor,
182                                                         1000));
183
184                                         file.create(stream, false, new SubProgressMonitor(monitor,
185                                                         1000));
186                                 } finally {
187                                         monitor.done();
188                                 }
189                         }
190                 } catch (IOException x) {
191                         IStatus s = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
192                                         IStatus.OK, x.getMessage(), x);
193
194                         throw new CoreException(s);
195                 }
196         }
197
198         /*
199          * @see org.eclipse.ui.editors.text.IStorageDocumentProvider#getEncoding(Object)
200          */
201         public String getEncoding(Object element) {
202                 String encoding = super.getEncoding(element);
203                 if (encoding != null) {
204                         return encoding;
205                 }
206
207                 if (element instanceof IStorageEditorInput) {
208                         IStorageEditorInput sei = (IStorageEditorInput) element;
209
210                         try {
211                                 InputStream in = sei.getStorage().getContents();
212                                 try {
213                                         encoding = getDeclaredEncoding(in);
214                                 } finally {
215                                         in.close();
216                                 }
217                         } catch (CoreException e) {
218                         } catch (IOException e) {
219                         }
220
221                         if (encoding == null) {
222                                 encoding = getDefaultEncoding();
223                         }
224
225                         setEncoding(element, encoding);
226                 }
227
228                 return encoding;
229         }
230
231         /*
232          * @see org.eclipse.ui.editors.text.IStorageDocumentProvider#setEncoding(Object,
233          *      String)
234          */
235         public void setEncoding(Object element, String encoding) {
236                 if (encoding == null) {
237                         encoding = getDefaultEncoding();
238                 }
239
240                 super.setEncoding(element, encoding);
241         }
242
243         /**
244          * Tries to determine encoding from contents of the stream. Returns
245          * <code>null</code> if encoding is unknown.
246          */
247         public String getDeclaredEncoding(InputStream in) throws IOException {
248                 return getBOMEncoding(in);
249         }
250
251         /**
252          * Tries to determine encoding from the byte order mark. Returns
253          * <code>null</code> if encoding is unknown.
254          */
255         private String getBOMEncoding(InputStream in) throws IOException {
256                 int first = in.read();
257                 if (first < 0) {
258                         return null;
259                 }
260
261                 int second = in.read();
262                 if (second < 0) {
263                         return null;
264                 }
265
266                 // look for the UTF-16 Byte Order Mark (BOM)
267                 if (first == 0xFE && second == 0xFF) {
268                         return "UTF-16BE";
269                 }
270
271                 if (first == 0xFF && second == 0xFE) {
272                         return "UTF-16LE";
273                 }
274
275                 int third = in.read();
276                 if (third < 0) {
277                         return null;
278                 }
279
280                 // look for the UTF-8 BOM
281                 if (first == 0xEF && second == 0xBB && third == 0xBF) {
282                         return "UTF-8";
283                 }
284
285                 return null;
286         }
287 }