/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
+ * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
- *
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import net.sourceforge.phpdt.core.BufferChangedEvent;
import net.sourceforge.phpdt.core.IBuffer;
import net.sourceforge.phpdt.core.IBufferChangedListener;
import net.sourceforge.phpdt.core.IOpenable;
import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filebuffers.ITextFileBufferManager;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.text.Assert;
import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DefaultLineTracker;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
-import org.eclipse.jface.text.ILineTracker;
-import org.eclipse.jface.text.IRegion;
import org.eclipse.swt.widgets.Display;
/**
* Adapts <code>IDocument</code> to <code>IBuffer</code>. Uses the
- * same algorithm as the text widget to determine the buffer's line delimiter.
+ * same algorithm as the text widget to determine the buffer's line delimiter.
* All text inserted into the buffer is converted to this line delimiter.
* This class is <code>public</code> for test purposes only.
*/
public class DocumentAdapter implements IBuffer, IDocumentListener {
-
+
/**
* Internal implementation of a NULL instanceof IBuffer.
*/
static private class NullBuffer implements IBuffer {
-
public void addBufferChangedListener(IBufferChangedListener listener) {}
-
public void append(char[] text) {}
-
public void append(String text) {}
-
public void close() {}
-
- public char getChar(int position) {
- return 0;
- }
-
- public char[] getCharacters() {
- return null;
- }
-
- public String getContents() {
- return null;
- }
-
- public int getLength() {
- return 0;
- }
-
- public IOpenable getOwner() {
- return null;
- }
-
- public String getText(int offset, int length) {
- return null;
- }
-
- public IResource getUnderlyingResource() {
- return null;
- }
-
- public boolean hasUnsavedChanges() {
- return false;
- }
-
- public boolean isClosed() {
- return false;
- }
-
- public boolean isReadOnly() {
- return true;
- }
-
+ public char getChar(int position) { return 0; }
+ public char[] getCharacters() { return null; }
+ public String getContents() { return null; }
+ public int getLength() { return 0; }
+ public IOpenable getOwner() { return null; }
+ public String getText(int offset, int length) { return null; }
+ public IResource getUnderlyingResource() { return null; }
+ public boolean hasUnsavedChanges() { return false; }
+ public boolean isClosed() { return false; }
+ public boolean isReadOnly() { return true; }
public void removeBufferChangedListener(IBufferChangedListener listener) {}
-
public void replace(int position, int length, char[] text) {}
-
public void replace(int position, int length, String text) {}
-
public void save(IProgressMonitor progress, boolean force) throws JavaModelException {}
-
public void setContents(char[] contents) {}
-
public void setContents(String contents) {}
- };
-
-
- /** NULL implementing <code>IBuffer</code> */
- public final static IBuffer NULL= new NullBuffer();
-
-
- /**
- * Executes a document set content call in the ui thread.
- */
- protected class DocumentSetCommand implements Runnable {
-
- private String fContents;
-
- public void run() {
- fDocument.set(fContents);
}
-
- public void set(String contents) {
- fContents= contents;
- Display.getDefault().syncExec(this);
- }
- };
-
- /**
- * Executes a document replace call in the ui thread.
- */
- protected class DocumentReplaceCommand implements Runnable {
-
- private int fOffset;
- private int fLength;
- private String fText;
-
- public void run() {
- try {
- fDocument.replace(fOffset, fLength, fText);
- } catch (BadLocationException x) {
- // ignore
+
+
+ /** NULL implementing <code>IBuffer</code> */
+ public final static IBuffer NULL= new NullBuffer();
+
+
+ /**
+ * Executes a document set content call in the ui thread.
+ */
+ protected class DocumentSetCommand implements Runnable {
+
+ private String fContents;
+
+ public void run() {
+ fDocument.set(fContents);
+ }
+
+ public void set(String contents) {
+ fContents= contents;
+ Display.getDefault().syncExec(this);
}
}
-
- public void replace(int offset, int length, String text) {
- fOffset= offset;
- fLength= length;
- fText= text;
- Display.getDefault().syncExec(this);
+
+ /**
+ * Executes a document replace call in the ui thread.
+ */
+ protected class DocumentReplaceCommand implements Runnable {
+
+ private int fOffset;
+ private int fLength;
+ private String fText;
+
+ public void run() {
+ try {
+ fDocument.replace(fOffset, fLength, fText);
+ } catch (BadLocationException x) {
+ // ignore
+ }
+ }
+
+ public void replace(int offset, int length, String text) {
+ fOffset= offset;
+ fLength= length;
+ fText= text;
+ Display.getDefault().syncExec(this);
+ }
}
- };
-
+
+ private static final boolean DEBUG_LINE_DELIMITERS= true;
+
private IOpenable fOwner;
+ private IFile fFile;
+ private ITextFileBuffer fTextFileBuffer;
private IDocument fDocument;
+
private DocumentSetCommand fSetCmd= new DocumentSetCommand();
private DocumentReplaceCommand fReplaceCmd= new DocumentReplaceCommand();
-
- private Object fProviderKey;
- private PHPDocumentProvider fProvider;
- private String fLineDelimiter;
- private ILineTracker fLineTracker;
-
+
+ private Set fLegalLineDelimiters;
+
private List fBufferListeners= new ArrayList(3);
-
private IStatus fStatus;
-
+
+
/**
* This method is <code>public</code> for test purposes only.
*/
- public DocumentAdapter(IOpenable owner, IDocument document, ILineTracker lineTracker, PHPDocumentProvider provider, Object providerKey) {
-
- Assert.isNotNull(document);
- Assert.isNotNull(lineTracker);
-
+ public DocumentAdapter(IOpenable owner, IFile file) {
+
fOwner= owner;
- fDocument= document;
- fLineTracker= lineTracker;
- fProvider= provider;
- fProviderKey= providerKey;
-
- fDocument.addPrenotifiedDocumentListener(this);
+ fFile= file;
+
+ initialize();
}
-
- /**
- * Sets the status of this document adapter.
- */
- public void setStatus(IStatus status) {
- fStatus= status;
+
+ private void initialize() {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ IPath location= fFile.getFullPath();
+ try {
+ manager.connect(location, new NullProgressMonitor());
+ fTextFileBuffer= manager.getTextFileBuffer(location);
+ fDocument= fTextFileBuffer.getDocument();
+ } catch (CoreException x) {
+ fStatus= x.getStatus();
+ fDocument= manager.createEmptyDocument(location);
+ }
+ fDocument.addPrenotifiedDocumentListener(this);
}
-
+
/**
* Returns the status of this document adapter.
*/
public IStatus getStatus() {
- return fStatus;
+ if (fStatus != null)
+ return fStatus;
+ if (fTextFileBuffer != null)
+ return fTextFileBuffer.getStatus();
+ return null;
}
-
+
/**
* Returns the adapted document.
- *
+ *
* @return the adapted document
*/
public IDocument getDocument() {
return fDocument;
}
-
- /**
- * Returns the line delimiter of this buffer. As a document has a set of
- * valid line delimiters, this set must be reduced to size 1.
- */
- protected String getLineDelimiter() {
-
- if (fLineDelimiter == null) {
-
- try {
- fLineDelimiter= fDocument.getLineDelimiter(0);
- } catch (BadLocationException x) {
- }
-
- if (fLineDelimiter == null) {
- /*
- * Follow up fix for: 1GF5UU0: ITPJUI:WIN2000 - "Organize Imports" in java editor inserts lines in wrong format
- * The line delimiter must always be a legal document line delimiter.
- */
- String sysLineDelimiter= System.getProperty("line.separator"); //$NON-NLS-1$
- String[] delimiters= fDocument.getLegalLineDelimiters();
- Assert.isTrue(delimiters.length > 0);
- for (int i= 0; i < delimiters.length; i++) {
- if (delimiters[i].equals(sysLineDelimiter)) {
- fLineDelimiter= sysLineDelimiter;
- break;
- }
- }
-
- if (fLineDelimiter == null) {
- // system line delimiter is not a legal document line delimiter
- fLineDelimiter= delimiters[0];
- }
- }
- }
-
- return fLineDelimiter;
- }
-
- /**
- * Converts the given string to the line delimiter of this buffer.
- * This method is <code>public</code> for test purposes only.
- */
- public String normalize(String text) {
- fLineTracker.set(text);
-
- int lines= fLineTracker.getNumberOfLines();
- if (lines <= 1)
- return text;
-
- StringBuffer buffer= new StringBuffer(text);
-
- try {
- IRegion previous= fLineTracker.getLineInformation(0);
- for (int i= 1; i < lines; i++) {
- int lastLineEnd= previous.getOffset() + previous.getLength();
- int lineStart= fLineTracker.getLineInformation(i).getOffset();
- fLineTracker.replace(lastLineEnd, lineStart - lastLineEnd, getLineDelimiter());
- buffer.replace(lastLineEnd, lineStart, getLineDelimiter());
- previous= fLineTracker.getLineInformation(i);
- }
-
- // last line
- String delimiter= fLineTracker.getLineDelimiter(lines -1);
- if (delimiter != null && delimiter.length() > 0)
- buffer.replace(previous.getOffset() + previous.getLength(), buffer.length(), getLineDelimiter());
-
- return buffer.toString();
- } catch (BadLocationException x) {
- }
-
- return text;
- }
-
+
/*
* @see IBuffer#addBufferChangedListener(IBufferChangedListener)
*/
if (!fBufferListeners.contains(listener))
fBufferListeners.add(listener);
}
-
+
/*
* @see IBuffer#removeBufferChangedListener(IBufferChangedListener)
*/
Assert.isNotNull(listener);
fBufferListeners.remove(listener);
}
-
+
/*
* @see IBuffer#append(char[])
*/
public void append(char[] text) {
append(new String(text));
}
-
+
/*
- * @see IBuffer#append(String)
+ * @see IBuffer#append(String)
*/
public void append(String text) {
- fReplaceCmd.replace(fDocument.getLength(), 0, normalize(text));
+ if (DEBUG_LINE_DELIMITERS) {
+ validateLineDelimiters(text);
+ }
+ fReplaceCmd.replace(fDocument.getLength(), 0, text);
}
-
+
/*
* @see IBuffer#close()
*/
public void close() {
-
+
if (isClosed())
return;
-
+
IDocument d= fDocument;
fDocument= null;
d.removePrenotifiedDocumentListener(this);
-
+
+ if (fTextFileBuffer != null) {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ try {
+ manager.disconnect(fTextFileBuffer.getLocation(), new NullProgressMonitor());
+ } catch (CoreException x) {
+ // ignore
+ }
+ fTextFileBuffer= null;
+ }
+
fireBufferChanged(new BufferChangedEvent(this, 0, 0, null));
fBufferListeners.clear();
}
-
+
/*
* @see IBuffer#getChar(int)
*/
throw new ArrayIndexOutOfBoundsException();
}
}
-
+
/*
* @see IBuffer#getCharacters()
*/
String content= getContents();
return content == null ? null : content.toCharArray();
}
-
+
/*
* @see IBuffer#getContents()
*/
public String getContents() {
return fDocument.get();
}
-
+
/*
* @see IBuffer#getLength()
*/
public int getLength() {
return fDocument.getLength();
}
-
+
/*
* @see IBuffer#getOwner()
*/
public IOpenable getOwner() {
- return (IOpenable) fOwner;
+ return fOwner;
}
-
+
/*
* @see IBuffer#getText(int, int)
*/
throw new ArrayIndexOutOfBoundsException();
}
}
-
+
/*
* @see IBuffer#getUnderlyingResource()
*/
public IResource getUnderlyingResource() {
- return fProvider != null ? fProvider.getUnderlyingResource(fProviderKey) : null;
+ return fFile;
}
-
+
/*
* @see IBuffer#hasUnsavedChanges()
*/
public boolean hasUnsavedChanges() {
- return fProvider != null ? fProvider.canSaveDocument(fProviderKey) : false;
+ return fTextFileBuffer != null ? fTextFileBuffer.isDirty() : false;
}
-
+
/*
* @see IBuffer#isClosed()
*/
public boolean isClosed() {
return fDocument == null;
}
-
+
/*
* @see IBuffer#isReadOnly()
*/
public boolean isReadOnly() {
IResource resource= getUnderlyingResource();
- return resource == null ? true : resource.isReadOnly();
+ return resource == null ? true : resource.getResourceAttributes().isReadOnly();
}
-
+
/*
* @see IBuffer#replace(int, int, char[])
*/
public void replace(int position, int length, char[] text) {
replace(position, length, new String(text));
}
-
+
/*
* @see IBuffer#replace(int, int, String)
*/
public void replace(int position, int length, String text) {
- fReplaceCmd.replace(position, length, normalize(text));
+ if (DEBUG_LINE_DELIMITERS) {
+ validateLineDelimiters(text);
+ }
+ fReplaceCmd.replace(position, length, text);
}
-
+
/*
* @see IBuffer#save(IProgressMonitor, boolean)
*/
public void save(IProgressMonitor progress, boolean force) throws JavaModelException {
- if (fProvider != null) {
- try {
- fProvider.saveDocumentContent(progress, fProviderKey, fDocument, force);
- } catch (CoreException e) {
- throw new JavaModelException(e);
- }
+ try {
+ if (fTextFileBuffer != null)
+ fTextFileBuffer.commit(progress, force);
+ } catch (CoreException e) {
+ throw new JavaModelException(e);
}
}
-
+
/*
* @see IBuffer#setContents(char[])
*/
public void setContents(char[] contents) {
setContents(new String(contents));
}
-
+
/*
* @see IBuffer#setContents(String)
*/
public void setContents(String contents) {
int oldLength= fDocument.getLength();
-
+
if (contents == null) {
-
+
if (oldLength != 0)
fSetCmd.set(""); //$NON-NLS-1$
-
+
} else {
-
+
// set only if different
- String newContents= normalize(contents);
- int newLength= newContents.length();
-
- if (oldLength != newLength || !newContents.equals(fDocument.get()))
- fSetCmd.set(newContents);
+ if (DEBUG_LINE_DELIMITERS) {
+ validateLineDelimiters(contents);
+ }
+
+ if (!contents.equals(fDocument.get()))
+ fSetCmd.set(contents);
}
}
-
+
+
+ private void validateLineDelimiters(String contents) {
+
+ if (fLegalLineDelimiters == null) {
+ // collect all line delimiters in the document
+ HashSet existingDelimiters= new HashSet();
+
+ for (int i= fDocument.getNumberOfLines() - 1; i >= 0; i-- ) {
+ try {
+ String curr= fDocument.getLineDelimiter(i);
+ if (curr != null) {
+ existingDelimiters.add(curr);
+ }
+ } catch (BadLocationException e) {
+ PHPeclipsePlugin.log(e);
+ }
+ }
+ if (existingDelimiters.isEmpty()) {
+ return; // first insertion of a line delimiter: no test
+ }
+ fLegalLineDelimiters= existingDelimiters;
+
+ }
+
+ DefaultLineTracker tracker= new DefaultLineTracker();
+ tracker.set(contents);
+
+ int lines= tracker.getNumberOfLines();
+ if (lines <= 1)
+ return;
+
+ for (int i= 0; i < lines; i++) {
+ try {
+ String curr= tracker.getLineDelimiter(i);
+ if (curr != null && !fLegalLineDelimiters.contains(curr)) {
+ StringBuffer buf= new StringBuffer("New line delimiter added to new code: "); //$NON-NLS-1$
+ for (int k= 0; k < curr.length(); k++) {
+ buf.append(String.valueOf((int) curr.charAt(k)));
+ }
+ PHPeclipsePlugin.log(new Exception(buf.toString()));
+ }
+ } catch (BadLocationException e) {
+ PHPeclipsePlugin.log(e);
+ }
+ }
+ }
+
/*
* @see IDocumentListener#documentAboutToBeChanged(DocumentEvent)
*/
public void documentChanged(DocumentEvent event) {
fireBufferChanged(new BufferChangedEvent(this, event.getOffset(), event.getLength(), event.getText()));
}
-
+
private void fireBufferChanged(BufferChangedEvent event) {
if (fBufferListeners != null && fBufferListeners.size() > 0) {
Iterator e= new ArrayList(fBufferListeners).iterator();