KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > javaeditor > DocumentAdapter


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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
12 package org.eclipse.jdt.internal.ui.javaeditor;
13
14
15 import java.util.ArrayList JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IPath;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.core.runtime.NullProgressMonitor;
27 import org.eclipse.core.runtime.Status;
28
29 import org.eclipse.core.filebuffers.FileBuffers;
30 import org.eclipse.core.filebuffers.ITextFileBuffer;
31 import org.eclipse.core.filebuffers.ITextFileBufferManager;
32 import org.eclipse.core.filebuffers.LocationKind;
33
34 import org.eclipse.core.resources.IFile;
35 import org.eclipse.core.resources.IResource;
36 import org.eclipse.core.resources.ResourceAttributes;
37
38 import org.eclipse.swt.widgets.Display;
39
40 import org.eclipse.jface.text.BadLocationException;
41 import org.eclipse.jface.text.DefaultLineTracker;
42 import org.eclipse.jface.text.DocumentEvent;
43 import org.eclipse.jface.text.IDocument;
44 import org.eclipse.jface.text.IDocumentListener;
45 import org.eclipse.jface.text.ISynchronizable;
46
47 import org.eclipse.jdt.core.BufferChangedEvent;
48 import org.eclipse.jdt.core.IBuffer;
49 import org.eclipse.jdt.core.IBufferChangedListener;
50 import org.eclipse.jdt.core.IOpenable;
51 import org.eclipse.jdt.core.JavaModelException;
52
53 import org.eclipse.jdt.ui.JavaUI;
54
55 import org.eclipse.jdt.internal.ui.JavaPlugin;
56
57
58 /**
59  * Adapts <code>IDocument</code> to <code>IBuffer</code>. Uses the
60  * same algorithm as the text widget to determine the buffer's line delimiter.
61  * All text inserted into the buffer is converted to this line delimiter.
62  * This class is <code>public</code> for test purposes only.
63  */

64 public class DocumentAdapter implements IBuffer, IDocumentListener {
65
66     /**
67      * Internal implementation of a NULL instanceof IBuffer.
68      */

69     static private class NullBuffer implements IBuffer {
70         public void addBufferChangedListener(IBufferChangedListener listener) {}
71         public void append(char[] text) {}
72         public void append(String JavaDoc text) {}
73         public void close() {}
74         public char getChar(int position) { return 0; }
75         public char[] getCharacters() { return null; }
76         public String JavaDoc getContents() { return null; }
77         public int getLength() { return 0; }
78         public IOpenable getOwner() { return null; }
79         public String JavaDoc getText(int offset, int length) { return null; }
80         public IResource getUnderlyingResource() { return null; }
81         public boolean hasUnsavedChanges() { return false; }
82         public boolean isClosed() { return false; }
83         public boolean isReadOnly() { return true; }
84         public void removeBufferChangedListener(IBufferChangedListener listener) {}
85         public void replace(int position, int length, char[] text) {}
86         public void replace(int position, int length, String JavaDoc text) {}
87         public void save(IProgressMonitor progress, boolean force) throws JavaModelException {}
88         public void setContents(char[] contents) {}
89         public void setContents(String JavaDoc contents) {}
90     }
91
92
93     /** NULL implementing <code>IBuffer</code> */
94     public final static IBuffer NULL= new NullBuffer();
95
96
97     /**
98      * Run the given runnable in the UI thread.
99      *
100      * @param runnable the runnable
101      * @since 3.3
102      */

103     private static final void run(Runnable JavaDoc runnable) {
104         Display currentDisplay= Display.getCurrent();
105         if (currentDisplay != null)
106             runnable.run();
107         else
108             Display.getDefault().syncExec(runnable);
109     }
110
111
112     /**
113      * Executes a document set content call in the UI thread.
114      */

115     protected class DocumentSetCommand implements Runnable JavaDoc {
116
117         private String JavaDoc fContents;
118
119         public void run() {
120             if (!isClosed())
121                 fDocument.set(fContents);
122         }
123
124         public void set(String JavaDoc contents) {
125             fContents= contents;
126             DocumentAdapter.run(this);
127         }
128     }
129
130
131     /**
132      * Executes a document replace call in the UI thread.
133      */

134     protected class DocumentReplaceCommand implements Runnable JavaDoc {
135
136         private int fOffset;
137         private int fLength;
138         private String JavaDoc fText;
139
140         public void run() {
141             try {
142                 if (!isClosed())
143                     fDocument.replace(fOffset, fLength, fText);
144             } catch (BadLocationException x) {
145                 // ignore
146
}
147         }
148
149         public void replace(int offset, int length, String JavaDoc text) {
150             fOffset= offset;
151             fLength= length;
152             fText= text;
153             DocumentAdapter.run(this);
154         }
155     }
156
157         
158     private static final boolean DEBUG_LINE_DELIMITERS= true;
159
160     private IOpenable fOwner;
161     private IFile fFile;
162     private ITextFileBuffer fTextFileBuffer;
163     private IDocument fDocument;
164
165     private DocumentSetCommand fSetCmd= new DocumentSetCommand();
166     private DocumentReplaceCommand fReplaceCmd= new DocumentReplaceCommand();
167
168     private Set JavaDoc fLegalLineDelimiters;
169
170     private List JavaDoc fBufferListeners= new ArrayList JavaDoc(3);
171     private IStatus fStatus;
172
173     /*
174      * @since 3.2
175      */

176     private IPath fPath;
177     
178     /*
179      * @since 3.3
180      */

181     private LocationKind fLocationKind;
182
183
184     /**
185      * Constructs a new document adapter.
186      *
187      * @param owner the owner of this buffer
188      * @param path the path of the file that backs the buffer
189      * @since 3.2
190      */

191     public DocumentAdapter(IOpenable owner, IPath path) {
192         Assert.isLegal(path != null);
193         
194         fOwner= owner;
195         fPath= path;
196         fLocationKind= LocationKind.NORMALIZE;
197         
198         initialize();
199     }
200     
201     /**
202      * Constructs a new document adapter.
203      *
204      * @param owner the owner of this buffer
205      * @param file the <code>IFile</code> that backs the buffer
206      */

207     public DocumentAdapter(IOpenable owner, IFile file) {
208
209         fOwner= owner;
210         fFile= file;
211         fPath= fFile.getFullPath();
212         fLocationKind= LocationKind.IFILE;
213
214         initialize();
215     }
216
217     private void initialize() {
218         ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
219         try {
220             manager.connect(fPath, fLocationKind, new NullProgressMonitor());
221             fTextFileBuffer= manager.getTextFileBuffer(fPath, fLocationKind);
222             fDocument= fTextFileBuffer.getDocument();
223         } catch (CoreException x) {
224             fStatus= x.getStatus();
225             fDocument= manager.createEmptyDocument(fPath, fLocationKind);
226             if (fDocument instanceof ISynchronizable)
227                 ((ISynchronizable)fDocument).setLockObject(new Object JavaDoc());
228         }
229         fDocument.addPrenotifiedDocumentListener(this);
230     }
231
232     /**
233      * Returns the status of this document adapter.
234      *
235      * @return the status
236      */

237     public IStatus getStatus() {
238         if (fStatus != null)
239             return fStatus;
240         if (fTextFileBuffer != null)
241             return fTextFileBuffer.getStatus();
242         return null;
243     }
244
245     /**
246      * Returns the adapted document.
247      *
248      * @return the adapted document
249      */

250     public IDocument getDocument() {
251         return fDocument;
252     }
253
254     /*
255      * @see IBuffer#addBufferChangedListener(IBufferChangedListener)
256      */

257     public void addBufferChangedListener(IBufferChangedListener listener) {
258         Assert.isNotNull(listener);
259         if (!fBufferListeners.contains(listener))
260             fBufferListeners.add(listener);
261     }
262
263     /*
264      * @see IBuffer#removeBufferChangedListener(IBufferChangedListener)
265      */

266     public void removeBufferChangedListener(IBufferChangedListener listener) {
267         Assert.isNotNull(listener);
268         fBufferListeners.remove(listener);
269     }
270
271     /*
272      * @see IBuffer#append(char[])
273      */

274     public void append(char[] text) {
275         append(new String JavaDoc(text));
276     }
277
278     /*
279      * @see IBuffer#append(String)
280      */

281     public void append(String JavaDoc text) {
282         if (DEBUG_LINE_DELIMITERS) {
283             validateLineDelimiters(text);
284         }
285         fReplaceCmd.replace(fDocument.getLength(), 0, text);
286     }
287
288     /*
289      * @see IBuffer#close()
290      */

291     public void close() {
292
293         if (isClosed())
294             return;
295
296         IDocument d= fDocument;
297         fDocument= null;
298         d.removePrenotifiedDocumentListener(this);
299
300         if (fTextFileBuffer != null) {
301             ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
302             try {
303                 manager.disconnect(fPath, fLocationKind, new NullProgressMonitor());
304             } catch (CoreException x) {
305                 // ignore
306
}
307             fTextFileBuffer= null;
308         }
309
310         fireBufferChanged(new BufferChangedEvent(this, 0, 0, null));
311         fBufferListeners.clear();
312     }
313
314     /*
315      * @see IBuffer#getChar(int)
316      */

317     public char getChar(int position) {
318         try {
319             return fDocument.getChar(position);
320         } catch (BadLocationException x) {
321             throw new ArrayIndexOutOfBoundsException JavaDoc();
322         }
323     }
324
325     /*
326      * @see IBuffer#getCharacters()
327      */

328     public char[] getCharacters() {
329         String JavaDoc content= getContents();
330         return content == null ? null : content.toCharArray();
331     }
332
333     /*
334      * @see IBuffer#getContents()
335      */

336     public String JavaDoc getContents() {
337         return fDocument.get();
338     }
339
340     /*
341      * @see IBuffer#getLength()
342      */

343     public int getLength() {
344         return fDocument.getLength();
345     }
346
347     /*
348      * @see IBuffer#getOwner()
349      */

350     public IOpenable getOwner() {
351         return fOwner;
352     }
353
354     /*
355      * @see IBuffer#getText(int, int)
356      */

357     public String JavaDoc getText(int offset, int length) {
358         try {
359             return fDocument.get(offset, length);
360         } catch (BadLocationException x) {
361             throw new ArrayIndexOutOfBoundsException JavaDoc();
362         }
363     }
364
365     /*
366      * @see IBuffer#getUnderlyingResource()
367      */

368     public IResource getUnderlyingResource() {
369         return fFile;
370     }
371
372     /*
373      * @see IBuffer#hasUnsavedChanges()
374      */

375     public boolean hasUnsavedChanges() {
376         return fTextFileBuffer != null ? fTextFileBuffer.isDirty() : false;
377     }
378
379     /*
380      * @see IBuffer#isClosed()
381      */

382     public boolean isClosed() {
383         return fDocument == null;
384     }
385
386     /*
387      * @see IBuffer#isReadOnly()
388      */

389     public boolean isReadOnly() {
390         if (fTextFileBuffer != null)
391             return !fTextFileBuffer.isCommitable();
392         
393         IResource resource= getUnderlyingResource();
394         if (resource == null)
395             return true;
396             
397         final ResourceAttributes attributes= resource.getResourceAttributes();
398         return attributes == null ? false : attributes.isReadOnly();
399     }
400
401     /*
402      * @see IBuffer#replace(int, int, char[])
403      */

404     public void replace(int position, int length, char[] text) {
405         replace(position, length, new String JavaDoc(text));
406     }
407
408     /*
409      * @see IBuffer#replace(int, int, String)
410      */

411     public void replace(int position, int length, String JavaDoc text) {
412         if (DEBUG_LINE_DELIMITERS) {
413             validateLineDelimiters(text);
414         }
415         fReplaceCmd.replace(position, length, text);
416     }
417
418     /*
419      * @see IBuffer#save(IProgressMonitor, boolean)
420      */

421     public void save(IProgressMonitor progress, boolean force) throws JavaModelException {
422         try {
423             if (fTextFileBuffer != null)
424                 fTextFileBuffer.commit(progress, force);
425         } catch (CoreException e) {
426             throw new JavaModelException(e);
427         }
428     }
429
430     /*
431      * @see IBuffer#setContents(char[])
432      */

433     public void setContents(char[] contents) {
434         setContents(new String JavaDoc(contents));
435     }
436
437     /*
438      * @see IBuffer#setContents(String)
439      */

440     public void setContents(String JavaDoc contents) {
441         int oldLength= fDocument.getLength();
442
443         if (contents == null) {
444
445             if (oldLength != 0)
446                 fSetCmd.set(""); //$NON-NLS-1$
447

448         } else {
449
450             // set only if different
451
if (DEBUG_LINE_DELIMITERS) {
452                 validateLineDelimiters(contents);
453             }
454
455             if (!contents.equals(fDocument.get()))
456                 fSetCmd.set(contents);
457         }
458     }
459
460
461     private void validateLineDelimiters(String JavaDoc contents) {
462
463         if (fLegalLineDelimiters == null) {
464             // collect all line delimiters in the document
465
HashSet JavaDoc existingDelimiters= new HashSet JavaDoc();
466
467             for (int i= fDocument.getNumberOfLines() - 1; i >= 0; i-- ) {
468                 try {
469                     String JavaDoc curr= fDocument.getLineDelimiter(i);
470                     if (curr != null) {
471                         existingDelimiters.add(curr);
472                     }
473                 } catch (BadLocationException e) {
474                     JavaPlugin.log(e);
475                 }
476             }
477             if (existingDelimiters.isEmpty()) {
478                 return; // first insertion of a line delimiter: no test
479
}
480             fLegalLineDelimiters= existingDelimiters;
481
482         }
483
484         DefaultLineTracker tracker= new DefaultLineTracker();
485         tracker.set(contents);
486
487         int lines= tracker.getNumberOfLines();
488         if (lines <= 1)
489             return;
490
491         for (int i= 0; i < lines; i++) {
492             try {
493                 String JavaDoc curr= tracker.getLineDelimiter(i);
494                 if (curr != null && !fLegalLineDelimiters.contains(curr)) {
495                     StringBuffer JavaDoc buf= new StringBuffer JavaDoc("WARNING: javaeditor.DocumentAdapter added new line delimiter to code: "); //$NON-NLS-1$
496
for (int k= 0; k < curr.length(); k++) {
497                         if (k > 0)
498                             buf.append(' ');
499                         buf.append((int)curr.charAt(k));
500                     }
501                     IStatus status= new Status(IStatus.WARNING, JavaUI.ID_PLUGIN, IStatus.OK, buf.toString(), new Throwable JavaDoc());
502                     JavaPlugin.log(status);
503                 }
504             } catch (BadLocationException e) {
505                 JavaPlugin.log(e);
506             }
507         }
508     }
509
510     /*
511      * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
512      */

513     public void documentAboutToBeChanged(DocumentEvent event) {
514         // there is nothing to do here
515
}
516
517     /*
518      * @see IDocumentListener#documentChanged(DocumentEvent)
519      */

520     public void documentChanged(DocumentEvent event) {
521         fireBufferChanged(new BufferChangedEvent(this, event.getOffset(), event.getLength(), event.getText()));
522     }
523
524     private void fireBufferChanged(BufferChangedEvent event) {
525         if (fBufferListeners != null && fBufferListeners.size() > 0) {
526             Iterator JavaDoc e= new ArrayList JavaDoc(fBufferListeners).iterator();
527             while (e.hasNext())
528                 ((IBufferChangedListener) e.next()).bufferChanged(event);
529         }
530     }
531 }
532
Popular Tags