KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > editors > text > FileDocumentProvider


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.editors.text;
12
13 import java.io.ByteArrayInputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.io.Reader JavaDoc;
17 import java.io.SequenceInputStream JavaDoc;
18 import java.nio.ByteBuffer JavaDoc;
19 import java.nio.CharBuffer JavaDoc;
20 import java.nio.charset.CharacterCodingException JavaDoc;
21 import java.nio.charset.Charset JavaDoc;
22 import java.nio.charset.CharsetEncoder JavaDoc;
23 import java.nio.charset.CodingErrorAction JavaDoc;
24 import java.nio.charset.IllegalCharsetNameException JavaDoc;
25 import java.nio.charset.UnmappableCharacterException JavaDoc;
26 import java.nio.charset.UnsupportedCharsetException JavaDoc;
27
28 import org.eclipse.swt.widgets.Display;
29
30 import org.eclipse.core.runtime.Assert;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.core.runtime.IPath;
33 import org.eclipse.core.runtime.IProgressMonitor;
34 import org.eclipse.core.runtime.IStatus;
35 import org.eclipse.core.runtime.MultiStatus;
36 import org.eclipse.core.runtime.OperationCanceledException;
37 import org.eclipse.core.runtime.Platform;
38 import org.eclipse.core.runtime.QualifiedName;
39 import org.eclipse.core.runtime.Status;
40 import org.eclipse.core.runtime.SubProgressMonitor;
41 import org.eclipse.core.runtime.content.IContentDescription;
42 import org.eclipse.core.runtime.content.IContentType;
43 import org.eclipse.core.runtime.jobs.ISchedulingRule;
44 import org.eclipse.core.runtime.preferences.IScopeContext;
45 import org.eclipse.core.runtime.preferences.InstanceScope;
46
47 import org.eclipse.core.resources.IFile;
48 import org.eclipse.core.resources.IResource;
49 import org.eclipse.core.resources.IResourceChangeEvent;
50 import org.eclipse.core.resources.IResourceChangeListener;
51 import org.eclipse.core.resources.IResourceDelta;
52 import org.eclipse.core.resources.IResourceDeltaVisitor;
53 import org.eclipse.core.resources.IResourceRuleFactory;
54 import org.eclipse.core.resources.IResourceStatus;
55 import org.eclipse.core.resources.IWorkspace;
56 import org.eclipse.core.resources.ProjectScope;
57 import org.eclipse.core.resources.ResourcesPlugin;
58
59 import org.eclipse.core.filebuffers.manipulation.ContainerCreator;
60
61 import org.eclipse.jface.operation.IRunnableContext;
62
63 import org.eclipse.jface.text.IDocument;
64 import org.eclipse.jface.text.IDocumentExtension4;
65 import org.eclipse.jface.text.source.IAnnotationModel;
66
67 import org.eclipse.ui.IEditorInput;
68 import org.eclipse.ui.IFileEditorInput;
69 import org.eclipse.ui.IWorkbench;
70 import org.eclipse.ui.IWorkbenchWindow;
71 import org.eclipse.ui.PlatformUI;
72 import org.eclipse.ui.internal.editors.text.NLSUtility;
73 import org.eclipse.ui.internal.editors.text.WorkspaceOperationRunner;
74 import org.eclipse.ui.part.FileEditorInput;
75 import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel;
76 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
77
78
79 /**
80  * Shared document provider specialized for file resources (<code>IFile</code>).
81  * <p>
82  * This class may be instantiated or be subclassed.</p>
83  */

84 public class FileDocumentProvider extends StorageDocumentProvider {
85
86     /**
87      * Qualified name for the encoding key.
88      *
89      * @since 2.1
90      */

91     private static final QualifiedName ENCODING_KEY = new QualifiedName(EditorsUI.PLUGIN_ID, "encoding"); //$NON-NLS-1$
92
/**
93      * Constant denoting UTF-8 encoding.
94      * @since 3.0
95      */

96     private static final String JavaDoc CHARSET_UTF_8= "UTF-8"; //$NON-NLS-1$
97

98
99     /**
100      * The runnable context for that provider.
101      * @since 3.0
102      */

103     private WorkspaceOperationRunner fOperationRunner;
104     /**
105      * The scheduling rule factory.
106      * @since 3.0
107      */

108     private IResourceRuleFactory fResourceRuleFactory;
109
110     /**
111      * Runnable encapsulating an element state change. This runnable ensures
112      * that a element change failed message is sent out to the element state listeners
113      * in case an exception occurred.
114      *
115      * @since 2.0
116      */

117     protected class SafeChange implements Runnable JavaDoc {
118
119         /** The input that changes. */
120         private IFileEditorInput fInput;
121
122         /**
123          * Creates a new safe runnable for the given input.
124          *
125          * @param input the input
126          */

127         public SafeChange(IFileEditorInput input) {
128             fInput= input;
129         }
130
131         /**
132          * Execute the change.
133          * Subclass responsibility.
134          *
135          * @param input the input
136          * @throws Exception an exception in case of error
137          */

138         protected void execute(IFileEditorInput input) throws Exception JavaDoc {
139         }
140
141         /*
142          * @see java.lang.Runnable#run()
143          */

144         public void run() {
145
146             if (getElementInfo(fInput) == null) {
147                 fireElementStateChangeFailed(fInput);
148                 return;
149             }
150
151             try {
152                 execute(fInput);
153             } catch (Exception JavaDoc e) {
154                 fireElementStateChangeFailed(fInput);
155             }
156         }
157     }
158
159
160     /**
161      * Synchronizes the document with external resource changes.
162      */

163     protected class FileSynchronizer implements IResourceChangeListener, IResourceDeltaVisitor {
164
165         /** The file editor input. */
166         protected IFileEditorInput fFileEditorInput;
167         /**
168          * A flag indicating whether this synchronizer is installed or not.
169          *
170          * @since 2.1
171          */

172         protected boolean fIsInstalled= false;
173
174         /**
175          * Creates a new file synchronizer. Is not yet installed on a resource.
176          *
177          * @param fileEditorInput the editor input to be synchronized
178          */

179         public FileSynchronizer(IFileEditorInput fileEditorInput) {
180             fFileEditorInput= fileEditorInput;
181         }
182
183         /**
184          * Creates a new file synchronizer which is not yet installed on a resource.
185          *
186          * @param fileEditorInput the editor input to be synchronized
187          * @deprecated use <code>FileSynchronizer(IFileEditorInput)</code>
188          */

189         public FileSynchronizer(FileEditorInput fileEditorInput) {
190             fFileEditorInput= fileEditorInput;
191         }
192
193         /**
194          * Returns the file wrapped by the file editor input.
195          *
196          * @return the file wrapped by the editor input associated with that synchronizer
197          */

198         protected IFile getFile() {
199             return fFileEditorInput.getFile();
200         }
201
202         /**
203          * Installs the synchronizer on the input's file.
204          */

205         public void install() {
206             getFile().getWorkspace().addResourceChangeListener(this);
207             fIsInstalled= true;
208         }
209
210         /**
211          * Uninstalls the synchronizer from the input's file.
212          */

213         public void uninstall() {
214             getFile().getWorkspace().removeResourceChangeListener(this);
215             fIsInstalled= false;
216         }
217
218         /*
219          * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
220          */

221         public void resourceChanged(IResourceChangeEvent e) {
222             IResourceDelta delta= e.getDelta();
223             try {
224                 if (delta != null && fIsInstalled)
225                     delta.accept(this);
226             } catch (CoreException x) {
227                 handleCoreException(x, "FileDocumentProvider.resourceChanged"); //$NON-NLS-1$
228
}
229         }
230
231         /*
232          * @see IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
233          */

234         public boolean visit(IResourceDelta delta) throws CoreException {
235             if (delta == null)
236                 return false;
237
238             delta= delta.findMember(getFile().getFullPath());
239
240             if (delta == null)
241                 return false;
242
243             Runnable JavaDoc runnable= null;
244
245             switch (delta.getKind()) {
246                 case IResourceDelta.CHANGED:
247                     FileInfo info= (FileInfo) getElementInfo(fFileEditorInput);
248                     if (info == null || info.fCanBeSaved)
249                         break;
250
251                     boolean isSynchronized= computeModificationStamp(getFile()) == info.fModificationStamp;
252                     if ((IResourceDelta.ENCODING & delta.getFlags()) != 0 && isSynchronized) {
253                         runnable= new SafeChange(fFileEditorInput) {
254                             protected void execute(IFileEditorInput input) throws Exception JavaDoc {
255                                 handleElementContentChanged(input);
256                             }
257                         };
258                     }
259
260                     if (runnable == null && (IResourceDelta.CONTENT & delta.getFlags()) != 0 && !isSynchronized) {
261                         runnable= new SafeChange(fFileEditorInput) {
262                             protected void execute(IFileEditorInput input) throws Exception JavaDoc {
263                                 handleElementContentChanged(input);
264                             }
265                         };
266                     }
267                     break;
268
269                 case IResourceDelta.REMOVED:
270                     if ((IResourceDelta.MOVED_TO & delta.getFlags()) != 0) {
271                         final IPath path= delta.getMovedToPath();
272                         runnable= new SafeChange(fFileEditorInput) {
273                             protected void execute(IFileEditorInput input) throws Exception JavaDoc {
274                                 handleElementMoved(input, path);
275                             }
276                         };
277                     } else {
278                         info= (FileInfo) getElementInfo(fFileEditorInput);
279                         if (info != null && !info.fCanBeSaved) {
280                             runnable= new SafeChange(fFileEditorInput) {
281                                 protected void execute(IFileEditorInput input) throws Exception JavaDoc {
282                                     handleElementDeleted(input);
283                                 }
284                             };
285                         }
286                     }
287                     break;
288             }
289
290             if (runnable != null)
291                 update(runnable);
292
293             return false;
294         }
295
296         /**
297          * Posts the update code "behind" the running operation.
298          *
299          * @param runnable the update code
300          */

301         protected void update(Runnable JavaDoc runnable) {
302
303             if (runnable instanceof SafeChange)
304                 fireElementStateChanging(fFileEditorInput);
305
306             IWorkbench workbench= PlatformUI.getWorkbench();
307             IWorkbenchWindow[] windows= workbench.getWorkbenchWindows();
308             if (windows != null && windows.length > 0) {
309                 Display display= windows[0].getShell().getDisplay();
310                 display.asyncExec(runnable);
311             } else {
312                 runnable.run();
313             }
314         }
315     }
316
317
318
319     /**
320      * Bundle of all required information to allow files as underlying document resources.
321      */

322     protected class FileInfo extends StorageInfo {
323
324         /** The file synchronizer. */
325         public FileSynchronizer fFileSynchronizer;
326         /** The time stamp at which this provider changed the file. */
327         public long fModificationStamp= IResource.NULL_STAMP;
328         /**
329          * Tells whether the file on disk has a BOM.
330          */

331         private boolean fHasBOM;
332
333         /**
334          * Creates and returns a new file info.
335          *
336          * @param document the document
337          * @param model the annotation model
338          * @param fileSynchronizer the file synchronizer
339          */

340         public FileInfo(IDocument document, IAnnotationModel model, FileSynchronizer fileSynchronizer) {
341             super(document, model);
342             fFileSynchronizer= fileSynchronizer;
343         }
344     }
345
346
347     /**
348      * Creates and returns a new document provider.
349      */

350     public FileDocumentProvider() {
351         super();
352         fResourceRuleFactory= ResourcesPlugin.getWorkspace().getRuleFactory();
353     }
354
355     /**
356      * Overrides <code>StorageDocumentProvider#setDocumentContent(IDocument, IEditorInput)</code>.
357      *
358      * @see StorageDocumentProvider#setDocumentContent(IDocument, IEditorInput)
359      * @deprecated use file encoding based version
360      * @since 2.0
361      */

362     protected boolean setDocumentContent(IDocument document, IEditorInput editorInput) throws CoreException {
363         if (editorInput instanceof IFileEditorInput) {
364             IFile file= ((IFileEditorInput) editorInput).getFile();
365             InputStream JavaDoc stream= file.getContents(false);
366             try {
367                 setDocumentContent(document, stream);
368             } finally {
369                 try {
370                     stream.close();
371                 } catch (IOException JavaDoc x) {
372                 }
373             }
374             return true;
375         }
376         return super.setDocumentContent(document, editorInput);
377     }
378
379     /*
380      * @see StorageDocumentProvider#setDocumentContent(IDocument, IEditorInput, String)
381      * @since 2.0
382      */

383     protected boolean setDocumentContent(IDocument document, IEditorInput editorInput, String JavaDoc encoding) throws CoreException {
384         if (editorInput instanceof IFileEditorInput) {
385             IFile file= ((IFileEditorInput) editorInput).getFile();
386             InputStream JavaDoc contentStream= file.getContents(false);
387             try {
388
389                 FileInfo info= (FileInfo)getElementInfo(editorInput);
390                 boolean removeBOM= false;
391                 if (CHARSET_UTF_8.equals(encoding)) {
392                     if (info != null)
393                         removeBOM= info.fHasBOM;
394                     else
395                         removeBOM= hasBOM(editorInput);
396                 }
397
398                 /*
399                  * XXX:
400                  * This is a workaround for a corresponding bug in Java readers and writer,
401                  * see: http://developer.java.sun.com/developer/bugParade/bugs/4508058.html
402                  */

403                 if (removeBOM) {
404                     int n= 0;
405                     do {
406                         int bytes= contentStream.read(new byte[IContentDescription.BOM_UTF_8.length]);
407                         if (bytes == -1)
408                             throw new IOException JavaDoc();
409                         n += bytes;
410                     } while (n < IContentDescription.BOM_UTF_8.length);
411                 }
412
413                 setDocumentContent(document, contentStream, encoding);
414
415             } catch (IOException JavaDoc ex) {
416                 String JavaDoc message= (ex.getMessage() != null ? ex.getMessage() : ""); //$NON-NLS-1$
417
IStatus s= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, message, ex);
418                 throw new CoreException(s);
419             } finally {
420                 try {
421                     contentStream.close();
422                 } catch (IOException JavaDoc e1) {
423                 }
424             }
425             return true;
426         }
427         return super.setDocumentContent(document, editorInput, encoding);
428     }
429
430     /*
431      * @see AbstractDocumentProvider#createAnnotationModel(Object)
432      */

433     protected IAnnotationModel createAnnotationModel(Object JavaDoc element) throws CoreException {
434         if (element instanceof IFileEditorInput) {
435             IFileEditorInput input= (IFileEditorInput) element;
436             return new ResourceMarkerAnnotationModel(input.getFile());
437         }
438
439         return super.createAnnotationModel(element);
440     }
441
442     /**
443      * Checks whether the given resource has been changed on the
444      * local file system by comparing the actual time stamp with the
445      * cached one. If the resource has been changed, a <code>CoreException</code>
446      * is thrown.
447      *
448      * @param cachedModificationStamp the cached modification stamp
449      * @param resource the resource to check
450      * @throws org.eclipse.core.runtime.CoreException if resource has been changed on the file system
451      */

452     protected void checkSynchronizationState(long cachedModificationStamp, IResource resource) throws CoreException {
453         if (cachedModificationStamp != computeModificationStamp(resource)) {
454             Status status= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IResourceStatus.OUT_OF_SYNC_LOCAL, TextEditorMessages.FileDocumentProvider_error_out_of_sync, null);
455             throw new CoreException(status);
456         }
457     }
458
459     /**
460      * Computes the initial modification stamp for the given resource.
461      *
462      * @param resource the resource
463      * @return the modification stamp
464      */

465     protected long computeModificationStamp(IResource resource) {
466         long modificationStamp= resource.getModificationStamp();
467
468         IPath path= resource.getLocation();
469         if (path == null)
470             return modificationStamp;
471
472         modificationStamp= path.toFile().lastModified();
473         return modificationStamp;
474     }
475
476     /*
477      * @see IDocumentProvider#getModificationStamp(Object)
478      */

479     public long getModificationStamp(Object JavaDoc element) {
480
481         if (element instanceof IFileEditorInput) {
482             IFileEditorInput input= (IFileEditorInput) element;
483             return computeModificationStamp(input.getFile());
484         }
485
486         return super.getModificationStamp(element);
487     }
488
489     /*
490      * @see IDocumentProvider#getSynchronizationStamp(Object)
491      */

492     public long getSynchronizationStamp(Object JavaDoc element) {
493
494         if (element instanceof IFileEditorInput) {
495             FileInfo info= (FileInfo) getElementInfo(element);
496             if (info != null)
497                 return info.fModificationStamp;
498         }
499
500         return super.getSynchronizationStamp(element);
501     }
502
503     /*
504      * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#doSynchronize(java.lang.Object)
505      * @since 3.0
506      */

507     protected void doSynchronize(Object JavaDoc element, IProgressMonitor monitor) throws CoreException {
508         if (element instanceof IFileEditorInput) {
509
510             IFileEditorInput input= (IFileEditorInput) element;
511
512             FileInfo info= (FileInfo) getElementInfo(element);
513             if (info != null) {
514
515                 if (info.fFileSynchronizer != null) {
516                     info.fFileSynchronizer.uninstall();
517                     refreshFile(input.getFile(), monitor);
518                     info.fFileSynchronizer.install();
519                 } else {
520                     refreshFile(input.getFile(), monitor);
521                 }
522
523                 handleElementContentChanged((IFileEditorInput) element);
524             }
525             return;
526
527         }
528         super.doSynchronize(element, monitor);
529     }
530
531     /*
532      * @see IDocumentProvider#isDeleted(Object)
533      */

534     public boolean isDeleted(Object JavaDoc element) {
535
536         if (element instanceof IFileEditorInput) {
537             IFileEditorInput input= (IFileEditorInput) element;
538
539             IPath path= input.getFile().getLocation();
540             if (path == null)
541                 return true;
542
543             return !path.toFile().exists();
544         }
545
546         return super.isDeleted(element);
547     }
548
549     /*
550      * @see AbstractDocumentProvider#doSaveDocument(IProgressMonitor, Object, IDocument, boolean)
551      */

552     protected void doSaveDocument(IProgressMonitor monitor, Object JavaDoc element, IDocument document, boolean overwrite) throws CoreException {
553         if (element instanceof IFileEditorInput) {
554
555             IFileEditorInput input= (IFileEditorInput) element;
556             String JavaDoc encoding= null;
557
558             FileInfo info= (FileInfo) getElementInfo(element);
559             IFile file= input.getFile();
560             encoding= getCharsetForNewFile(file, document, info);
561
562             Charset JavaDoc charset;
563             try {
564                 charset= Charset.forName(encoding);
565             } catch (UnsupportedCharsetException JavaDoc ex) {
566                 String JavaDoc message= NLSUtility.format(TextEditorMessages.DocumentProvider_error_unsupported_encoding_message_arg, encoding);
567                 IStatus s= new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, message, ex);
568                 throw new CoreException(s);
569             } catch (IllegalCharsetNameException JavaDoc ex) {
570                 String JavaDoc message= NLSUtility.format(TextEditorMessages.DocumentProvider_error_illegal_encoding_message_arg, encoding);
571                 IStatus s= new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, IStatus.OK, message, ex);
572                 throw new CoreException(s);
573             }
574
575             CharsetEncoder JavaDoc encoder= charset.newEncoder();
576             encoder.onMalformedInput(CodingErrorAction.REPLACE);
577             encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
578
579             InputStream JavaDoc stream;
580
581             try {
582                 byte[] bytes;
583                 ByteBuffer JavaDoc byteBuffer= encoder.encode(CharBuffer.wrap(document.get()));
584                 if (byteBuffer.hasArray())
585                     bytes= byteBuffer.array();
586                 else {
587                     bytes= new byte[byteBuffer.limit()];
588                     byteBuffer.get(bytes);
589                 }
590                 stream= new ByteArrayInputStream JavaDoc(bytes, 0, byteBuffer.limit());
591             } catch (CharacterCodingException JavaDoc ex) {
592                 Assert.isTrue(ex instanceof UnmappableCharacterException JavaDoc);
593                 String JavaDoc message= NLSUtility.format(TextEditorMessages.DocumentProvider_error_charset_mapping_failed_message_arg, encoding);
594                 IStatus s= new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, EditorsUI.CHARSET_MAPPING_FAILED, message, null);
595                 throw new CoreException(s);
596             }
597
598             /*
599              * XXX:
600              * This is a workaround for a corresponding bug in Java readers and writer,
601              * see: http://developer.java.sun.com/developer/bugParade/bugs/4508058.html
602              */

603             if (info != null && info.fHasBOM && CHARSET_UTF_8.equals(encoding))
604                 stream= new SequenceInputStream JavaDoc(new ByteArrayInputStream JavaDoc(IContentDescription.BOM_UTF_8), stream);
605
606             if (file.exists()) {
607
608                 if (info != null && !overwrite)
609                     checkSynchronizationState(info.fModificationStamp, file);
610
611                 // inform about the upcoming content change
612
fireElementStateChanging(element);
613                 try {
614                     file.setContents(stream, overwrite, true, monitor);
615                 } catch (CoreException x) {
616                     // inform about failure
617
fireElementStateChangeFailed(element);
618                     throw x;
619                 } catch (RuntimeException JavaDoc x) {
620                     // inform about failure
621
fireElementStateChangeFailed(element);
622                     throw x;
623                 }
624
625                 // If here, the editor state will be flipped to "not dirty".
626
// Thus, the state changing flag will be reset.
627

628                 if (info != null) {
629
630                     ResourceMarkerAnnotationModel model= (ResourceMarkerAnnotationModel) info.fModel;
631                     if (model != null)
632                         model.updateMarkers(info.fDocument);
633
634                     info.fModificationStamp= computeModificationStamp(file);
635                 }
636
637             } else {
638                 try {
639                     monitor.beginTask(TextEditorMessages.FileDocumentProvider_task_saving, 2000);
640                     ContainerCreator creator = new ContainerCreator(file.getWorkspace(), file.getParent().getFullPath());
641                     creator.createContainer(new SubProgressMonitor(monitor, 1000));
642                     file.create(stream, false, new SubProgressMonitor(monitor, 1000));
643                 }
644                 finally {
645                     monitor.done();
646                 }
647             }
648
649         } else {
650             super.doSaveDocument(monitor, element, document, overwrite);
651         }
652     }
653
654     /*
655      * @since 3.0
656      */

657     private String JavaDoc getCharsetForNewFile(IFile targetFile, IDocument document, FileInfo info) {
658         // User-defined encoding has first priority
659
String JavaDoc encoding;
660         try {
661             encoding= targetFile.getCharset(false);
662         } catch (CoreException ex) {
663             encoding= null;
664         }
665         if (encoding != null)
666             return encoding;
667
668         // Probe content
669
Reader JavaDoc reader= new DocumentReader(document);
670         try {
671             QualifiedName[] options= new QualifiedName[] { IContentDescription.CHARSET, IContentDescription.BYTE_ORDER_MARK };
672             IContentDescription description= Platform.getContentTypeManager().getDescriptionFor(reader, targetFile.getName(), options);
673             if (description != null) {
674                 encoding= description.getCharset();
675                 if (encoding != null)
676                     return encoding;
677             }
678         } catch (IOException JavaDoc ex) {
679             // continue with next strategy
680
} finally {
681             try {
682                 reader.close();
683             } catch (IOException JavaDoc x) {
684             }
685         }
686
687         // Use file's encoding if the file has a BOM
688
if (info != null && info.fHasBOM)
689             return info.fEncoding;
690
691         // Use parent chain
692
try {
693             return targetFile.getParent().getDefaultCharset();
694         } catch (CoreException ex) {
695             // Use global default
696
return ResourcesPlugin.getEncoding();
697         }
698     }
699
700     /*
701      * @see AbstractDocumentProvider#createElementInfo(Object)
702      */

703     protected ElementInfo createElementInfo(Object JavaDoc element) throws CoreException {
704         if (element instanceof IFileEditorInput) {
705
706             IFileEditorInput input= (IFileEditorInput) element;
707
708             try {
709                 refreshFile(input.getFile());
710             } catch (CoreException x) {
711                 handleCoreException(x, TextEditorMessages.FileDocumentProvider_createElementInfo);
712             }
713
714             IDocument d= null;
715             IStatus s= null;
716
717             try {
718                 d= createDocument(element);
719             } catch (CoreException x) {
720                 handleCoreException(x, TextEditorMessages.FileDocumentProvider_createElementInfo);
721                 s= x.getStatus();
722                 d= createEmptyDocument();
723             }
724             
725             // Set the initial line delimiter
726
if (d instanceof IDocumentExtension4) {
727                 String JavaDoc initalLineDelimiter= getLineDelimiterPreference(input.getFile());
728                 if (initalLineDelimiter != null)
729                     ((IDocumentExtension4)d).setInitialLineDelimiter(initalLineDelimiter);
730             }
731
732             IAnnotationModel m= createAnnotationModel(element);
733             FileSynchronizer f= new FileSynchronizer(input);
734             f.install();
735
736             FileInfo info= new FileInfo(d, m, f);
737             info.fModificationStamp= computeModificationStamp(input.getFile());
738             info.fStatus= s;
739             info.fEncoding= getPersistedEncoding(element);
740        &nb