fixed "replace all" bug
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / DocumentAdapter.java
index 70e1767..85dacc1 100644 (file)
@@ -13,26 +13,34 @@ package net.sourceforge.phpeclipse.phpeditor;
 
 
 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;
 
 
@@ -49,158 +57,125 @@ 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 {
+               /** NULL implementing <code>IBuffer</code> */
+               public final static IBuffer NULL= new NullBuffer();
+                       
                
-               private int fOffset;
-               private int fLength;
-               private String fText;
+               /**
+                *  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 run() {
-                       try {
-                               fDocument.replace(fOffset, fLength, fText);
-                       } catch (BadLocationException x) {
-                               // ignore
+                       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;
+               fFile= file;
                
-               fDocument.addPrenotifiedDocumentListener(this);
+               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;
        }
        
        /**
@@ -211,80 +186,7 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
        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)
         */
@@ -313,7 +215,10 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
         * @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);
        }
        
        /*
@@ -328,6 +233,16 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
                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();
        }
@@ -369,7 +284,7 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
         * @see IBuffer#getOwner()
         */
        public IOpenable getOwner() {
-               return (IOpenable) fOwner;
+               return fOwner;
        }
        
        /*
@@ -387,14 +302,14 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
         * @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;
        }
        
        /*
@@ -423,19 +338,21 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
         * @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);
                }
        }
        
@@ -460,14 +377,62 @@ public class DocumentAdapter implements IBuffer, IDocumentListener {
                } else {
                        
                        // set only if different
-                       String newContents= normalize(contents);
-                       int newLength= newContents.length();
+                       if (DEBUG_LINE_DELIMITERS) {
+                               validateLineDelimiters(contents);
+                       }
                        
-                       if (oldLength != newLength || !newContents.equals(fDocument.get()))
-                               fSetCmd.set(newContents);
+                       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)
         */