1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation 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://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor;
14 import java.util.ArrayList;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
20 import net.sourceforge.phpdt.core.BufferChangedEvent;
21 import net.sourceforge.phpdt.core.IBuffer;
22 import net.sourceforge.phpdt.core.IBufferChangedListener;
23 import net.sourceforge.phpdt.core.IOpenable;
24 import net.sourceforge.phpdt.core.JavaModelException;
25 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
27 import org.eclipse.core.filebuffers.FileBuffers;
28 import org.eclipse.core.filebuffers.ITextFileBuffer;
29 import org.eclipse.core.filebuffers.ITextFileBufferManager;
30 import org.eclipse.core.resources.IFile;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.runtime.CoreException;
33 import org.eclipse.core.runtime.IPath;
34 import org.eclipse.core.runtime.IProgressMonitor;
35 import org.eclipse.core.runtime.IStatus;
36 import org.eclipse.core.runtime.NullProgressMonitor;
38 //import org.eclipse.jface.text.Assert;
39 import org.eclipse.core.runtime.Assert;
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.swt.widgets.Display;
48 * Adapts <code>IDocument</code> to <code>IBuffer</code>. Uses the same
49 * algorithm as the text widget to determine the buffer's line delimiter. All
50 * text inserted into the buffer is converted to this line delimiter. This class
51 * is <code>public</code> for test purposes only.
53 public class DocumentAdapter implements IBuffer, IDocumentListener {
56 * Internal implementation of a NULL instanceof IBuffer.
58 static private class NullBuffer implements IBuffer {
59 public void addBufferChangedListener(IBufferChangedListener listener) {
62 public void append(char[] text) {
65 public void append(String text) {
71 public char getChar(int position) {
75 public char[] getCharacters() {
79 public String getContents() {
83 public int getLength() {
87 public IOpenable getOwner() {
91 public String getText(int offset, int length) {
95 public IResource getUnderlyingResource() {
99 public boolean hasUnsavedChanges() {
103 public boolean isClosed() {
107 public boolean isReadOnly() {
111 public void removeBufferChangedListener(IBufferChangedListener listener) {
114 public void replace(int position, int length, char[] text) {
117 public void replace(int position, int length, String text) {
120 public void save(IProgressMonitor progress, boolean force)
121 throws JavaModelException {
124 public void setContents(char[] contents) {
127 public void setContents(String contents) {
131 /** NULL implementing <code>IBuffer</code> */
132 public final static IBuffer NULL = new NullBuffer();
135 * Executes a document set content call in the ui thread.
137 protected class DocumentSetCommand implements Runnable {
139 private String fContents;
142 fDocument.set(fContents);
145 public void set(String contents) {
146 fContents = contents;
147 Display.getDefault().syncExec(this);
152 * Executes a document replace call in the ui thread.
154 protected class DocumentReplaceCommand implements Runnable {
160 private String fText;
164 fDocument.replace(fOffset, fLength, fText);
165 } catch (BadLocationException x) {
170 public void replace(int offset, int length, String text) {
174 Display.getDefault().syncExec(this);
178 private static final boolean DEBUG_LINE_DELIMITERS = true;
180 private IOpenable fOwner;
184 private ITextFileBuffer fTextFileBuffer;
186 private IDocument fDocument;
188 private DocumentSetCommand fSetCmd = new DocumentSetCommand();
190 private DocumentReplaceCommand fReplaceCmd = new DocumentReplaceCommand();
192 private Set fLegalLineDelimiters;
194 private List fBufferListeners = new ArrayList(3);
196 private IStatus fStatus;
199 * This method is <code>public</code> for test purposes only.
201 public DocumentAdapter(IOpenable owner, IFile file) {
209 private void initialize() {
210 ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
211 IPath location = fFile.getFullPath();
213 manager.connect(location, new NullProgressMonitor());
214 fTextFileBuffer = manager.getTextFileBuffer(location);
215 fDocument = fTextFileBuffer.getDocument();
216 } catch (CoreException x) {
217 fStatus = x.getStatus();
218 fDocument = manager.createEmptyDocument(location);
220 fDocument.addPrenotifiedDocumentListener(this);
224 * Returns the status of this document adapter.
226 public IStatus getStatus() {
229 if (fTextFileBuffer != null)
230 return fTextFileBuffer.getStatus();
235 * Returns the adapted document.
237 * @return the adapted document
239 public IDocument getDocument() {
244 * @see IBuffer#addBufferChangedListener(IBufferChangedListener)
246 public void addBufferChangedListener(IBufferChangedListener listener) {
247 Assert.isNotNull(listener);
248 if (!fBufferListeners.contains(listener))
249 fBufferListeners.add(listener);
253 * @see IBuffer#removeBufferChangedListener(IBufferChangedListener)
255 public void removeBufferChangedListener(IBufferChangedListener listener) {
256 Assert.isNotNull(listener);
257 fBufferListeners.remove(listener);
261 * @see IBuffer#append(char[])
263 public void append(char[] text) {
264 append(new String(text));
268 * @see IBuffer#append(String)
270 public void append(String text) {
271 if (DEBUG_LINE_DELIMITERS) {
272 validateLineDelimiters(text);
274 fReplaceCmd.replace(fDocument.getLength(), 0, text);
278 * @see IBuffer#close()
280 public void close() {
285 IDocument d = fDocument;
287 d.removePrenotifiedDocumentListener(this);
289 if (fTextFileBuffer != null) {
290 ITextFileBufferManager manager = FileBuffers
291 .getTextFileBufferManager();
293 manager.disconnect(fTextFileBuffer.getLocation(),
294 new NullProgressMonitor());
295 } catch (CoreException x) {
298 fTextFileBuffer = null;
301 fireBufferChanged(new BufferChangedEvent(this, 0, 0, null));
302 fBufferListeners.clear();
306 * @see IBuffer#getChar(int)
308 public char getChar(int position) {
310 return fDocument.getChar(position);
311 } catch (BadLocationException x) {
312 throw new ArrayIndexOutOfBoundsException();
317 * @see IBuffer#getCharacters()
319 public char[] getCharacters() {
320 String content = getContents();
321 return content == null ? null : content.toCharArray();
325 * @see IBuffer#getContents()
327 public String getContents() {
328 return fDocument.get();
332 * @see IBuffer#getLength()
334 public int getLength() {
335 return fDocument.getLength();
339 * @see IBuffer#getOwner()
341 public IOpenable getOwner() {
346 * @see IBuffer#getText(int, int)
348 public String getText(int offset, int length) {
350 return fDocument.get(offset, length);
351 } catch (BadLocationException x) {
352 throw new ArrayIndexOutOfBoundsException();
357 * @see IBuffer#getUnderlyingResource()
359 public IResource getUnderlyingResource() {
364 * @see IBuffer#hasUnsavedChanges()
366 public boolean hasUnsavedChanges() {
367 return fTextFileBuffer != null ? fTextFileBuffer.isDirty() : false;
371 * @see IBuffer#isClosed()
373 public boolean isClosed() {
374 return fDocument == null;
378 * @see IBuffer#isReadOnly()
380 public boolean isReadOnly() {
381 IResource resource = getUnderlyingResource();
382 return resource == null ? true : resource.getResourceAttributes()
387 * @see IBuffer#replace(int, int, char[])
389 public void replace(int position, int length, char[] text) {
390 replace(position, length, new String(text));
394 * @see IBuffer#replace(int, int, String)
396 public void replace(int position, int length, String text) {
397 if (DEBUG_LINE_DELIMITERS) {
398 validateLineDelimiters(text);
400 fReplaceCmd.replace(position, length, text);
404 * @see IBuffer#save(IProgressMonitor, boolean)
406 public void save(IProgressMonitor progress, boolean force)
407 throws JavaModelException {
409 if (fTextFileBuffer != null)
410 fTextFileBuffer.commit(progress, force);
411 } catch (CoreException e) {
412 throw new JavaModelException(e);
417 * @see IBuffer#setContents(char[])
419 public void setContents(char[] contents) {
420 setContents(new String(contents));
424 * @see IBuffer#setContents(String)
426 public void setContents(String contents) {
427 int oldLength = fDocument.getLength();
429 if (contents == null) {
432 fSetCmd.set(""); //$NON-NLS-1$
436 // set only if different
437 if (DEBUG_LINE_DELIMITERS) {
438 validateLineDelimiters(contents);
441 if (!contents.equals(fDocument.get()))
442 fSetCmd.set(contents);
446 private void validateLineDelimiters(String contents) {
448 if (fLegalLineDelimiters == null) {
449 // collect all line delimiters in the document
450 HashSet existingDelimiters = new HashSet();
452 for (int i = fDocument.getNumberOfLines() - 1; i >= 0; i--) {
454 String curr = fDocument.getLineDelimiter(i);
456 existingDelimiters.add(curr);
458 } catch (BadLocationException e) {
459 PHPeclipsePlugin.log(e);
462 if (existingDelimiters.isEmpty()) {
463 return; // first insertion of a line delimiter: no test
465 fLegalLineDelimiters = existingDelimiters;
469 DefaultLineTracker tracker = new DefaultLineTracker();
470 tracker.set(contents);
472 int lines = tracker.getNumberOfLines();
476 for (int i = 0; i < lines; i++) {
478 String curr = tracker.getLineDelimiter(i);
479 if (curr != null && !fLegalLineDelimiters.contains(curr)) {
480 StringBuffer buf = new StringBuffer(
481 "New line delimiter added to new code: "); //$NON-NLS-1$
482 for (int k = 0; k < curr.length(); k++) {
483 buf.append(String.valueOf((int) curr.charAt(k)));
485 PHPeclipsePlugin.log(new Exception(buf.toString()));
487 } catch (BadLocationException e) {
488 PHPeclipsePlugin.log(e);
494 * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
496 public void documentAboutToBeChanged(DocumentEvent event) {
497 // there is nothing to do here
501 * @see IDocumentListener#documentChanged(DocumentEvent)
503 public void documentChanged(DocumentEvent event) {
504 fireBufferChanged(new BufferChangedEvent(this, event.getOffset(), event
505 .getLength(), event.getText()));
508 private void fireBufferChanged(BufferChangedEvent event) {
509 if (fBufferListeners != null && fBufferListeners.size() > 0) {
510 Iterator e = new ArrayList(fBufferListeners).iterator();
512 ((IBufferChangedListener) e.next()).bufferChanged(event);