new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPUnitEditor.java
index 63c79a4..833c8f8 100644 (file)
@@ -1,16 +1,23 @@
 package net.sourceforge.phpeclipse.phpeditor;
 
+import java.lang.reflect.InvocationTargetException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.ISourceRange;
+import net.sourceforge.phpdt.core.ISourceReference;
+import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
 import net.sourceforge.phpdt.internal.ui.text.ContentAssistPreference;
 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager;
 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI;
 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI.ExitFlags;
+import net.sourceforge.phpdt.ui.IWorkingCopyManager;
 import net.sourceforge.phpdt.ui.PreferenceConstants;
 import net.sourceforge.phpdt.ui.text.JavaTextTools;
 import net.sourceforge.phpeclipse.PHPCore;
@@ -18,11 +25,18 @@ import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants;
 
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Preferences;
 import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IMessageProvider;
 import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferenceConverter;
 import org.eclipse.jface.text.BadLocationException;
@@ -39,9 +53,9 @@ import org.eclipse.jface.text.contentassist.IContentAssistant;
 import org.eclipse.jface.text.source.IOverviewRuler;
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.jface.text.source.IVerticalRuler;
-import org.eclipse.jface.text.source.SourceViewer;
 import org.eclipse.jface.text.source.SourceViewerConfiguration;
 import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.swt.custom.VerifyKeyListener;
 import org.eclipse.swt.events.VerifyEvent;
 import org.eclipse.swt.graphics.Color;
@@ -53,8 +67,11 @@ import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IFileEditorInput;
 import org.eclipse.ui.actions.ActionContext;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.dialogs.SaveAsDialog;
 import org.eclipse.ui.editors.text.IStorageDocumentProvider;
 import org.eclipse.ui.help.WorkbenchHelp;
+import org.eclipse.ui.part.FileEditorInput;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 
 /**********************************************************************
@@ -334,7 +351,7 @@ public class PHPUnitEditor extends PHPEditor {
   //
   //  };
 
-  class AdaptedSourceViewer extends SourceViewer {
+  class AdaptedSourceViewer extends JavaSourceViewer {
 
     private List fTextConverters;
     private boolean fIgnoreTextConverters = false;
@@ -577,12 +594,12 @@ public class PHPUnitEditor extends PHPEditor {
 
   }
 
-  //  private static class BracketLevel {
-  //    int fOffset;
-  //    int fLength;
-  //    LinkedPositionManager fManager;
-  //    LinkedPositionUI fEditor;
-  //  };
+  private static class BracketLevel {
+    int fOffset;
+    int fLength;
+    LinkedPositionManager fManager;
+    LinkedPositionUI fEditor;
+  };
 
   private class BracketInserter implements VerifyKeyListener, LinkedPositionUI.ExitListener {
 
@@ -807,6 +824,12 @@ public class PHPUnitEditor extends PHPEditor {
     }
 
   }
+
+  /** The editor's save policy */
+  protected ISavePolicy fSavePolicy;
+  /** Listener to annotation model changes that updates the error tick in the tab image */
+  private JavaEditorErrorTickUpdater fJavaEditorErrorTickUpdater;
+
   /** The editor's paint manager */
   //  private PaintManager fPaintManager;
   /** The editor's bracket painter */
@@ -826,6 +849,8 @@ public class PHPUnitEditor extends PHPEditor {
 
   /** The preference property change listener for php core. */
   //  private IPropertyChangeListener fPropertyChangeListener = new PropertyChangeListener();
+  /** The remembered java element */
+  private IJavaElement fRememberedElement;
   /** The remembered selection */
   private ITextSelection fRememberedSelection;
   /** The remembered php element offset */
@@ -988,7 +1013,63 @@ public class PHPUnitEditor extends PHPEditor {
     setDocumentProvider(PHPeclipsePlugin.getDefault().getCompilationUnitDocumentProvider());
     setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
     setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
+    setOutlinerContextMenuId("#PHPOutlinerContext"); //$NON-NLS-1$
+    // don't set help contextId, we install our own help context
+    fSavePolicy = null;
 
+    fJavaEditorErrorTickUpdater = new JavaEditorErrorTickUpdater(this);
+  }
+
+  /*
+        * @see JavaEditor#getElementAt(int)
+        */
+  protected IJavaElement getElementAt(int offset) {
+    return getElementAt(offset, true);
+  }
+
+  /**
+   * Returns the most narrow element including the given offset.  If <code>reconcile</code>
+   * is <code>true</code> the editor's input element is reconciled in advance. If it is 
+   * <code>false</code> this method only returns a result if the editor's input element
+   * does not need to be reconciled.
+   * 
+   * @param offset the offset included by the retrieved element
+   * @param reconcile <code>true</code> if working copy should be reconciled
+   */
+  protected IJavaElement getElementAt(int offset, boolean reconcile) {
+    IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
+    ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
+
+    if (unit != null) {
+      try {
+        if (reconcile) {
+          synchronized (unit) {
+            unit.reconcile();
+          }
+          return unit.getElementAt(offset);
+        } else if (unit.isConsistent())
+          return unit.getElementAt(offset);
+
+      } catch (JavaModelException x) {
+        PHPeclipsePlugin.log(x.getStatus());
+        // nothing found, be tolerant and go on
+      }
+    }
+
+    return null;
+  }
+
+  /*
+   * @see JavaEditor#getCorrespondingElement(IJavaElement)
+   */
+  protected IJavaElement getCorrespondingElement(IJavaElement element) {
+    try {
+      return EditorUtility.getWorkingCopy(element, true);
+    } catch (JavaModelException x) {
+      PHPeclipsePlugin.log(x.getStatus());
+      // nothing found, be tolerant and go on
+    }
+    return null;
   }
 
   public void createPartControl(Composite parent) {
@@ -1039,8 +1120,8 @@ public class PHPUnitEditor extends PHPEditor {
 
     ISourceViewer sourceViewer = getSourceViewer();
     if (sourceViewer instanceof ITextViewerExtension)
-       ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter);
-
+       ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter);                       
+                       
   }
 
   private static char getPeerCharacter(char character) {
@@ -1064,7 +1145,86 @@ public class PHPUnitEditor extends PHPEditor {
         throw new IllegalArgumentException();
     }
   }
+  /**
+        * The compilation unit editor implementation of this  <code>AbstractTextEditor</code>
+        * method asks the user for the workspace path of a file resource and saves the document
+        * there. See http://dev.eclipse.org/bugs/show_bug.cgi?id=6295
+        */
+  protected void performSaveAs(IProgressMonitor progressMonitor) {
+
+    Shell shell = getSite().getShell();
+    IEditorInput input = getEditorInput();
+
+    SaveAsDialog dialog = new SaveAsDialog(shell);
+
+    IFile original = (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null;
+    if (original != null)
+      dialog.setOriginalFile(original);
+
+    dialog.create();
 
+    IDocumentProvider provider = getDocumentProvider();
+    if (provider == null) {
+      // editor has been programmatically closed while the dialog was open
+      return;
+    }
+
+    if (provider.isDeleted(input) && original != null) {
+      String message = PHPEditorMessages.getFormattedString("CompilationUnitEditor.warning.save.delete", new Object[] { original.getName()}); //$NON-NLS-1$
+      dialog.setErrorMessage(null);
+      dialog.setMessage(message, IMessageProvider.WARNING);
+    }
+
+    if (dialog.open() == Dialog.CANCEL) {
+      if (progressMonitor != null)
+        progressMonitor.setCanceled(true);
+      return;
+    }
+
+    IPath filePath = dialog.getResult();
+    if (filePath == null) {
+      if (progressMonitor != null)
+        progressMonitor.setCanceled(true);
+      return;
+    }
+
+    IWorkspace workspace = ResourcesPlugin.getWorkspace();
+    IFile file = workspace.getRoot().getFile(filePath);
+    final IEditorInput newInput = new FileEditorInput(file);
+
+    WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+      public void execute(final IProgressMonitor monitor) throws CoreException {
+        getDocumentProvider().saveDocument(monitor, newInput, getDocumentProvider().getDocument(getEditorInput()), true);
+      }
+    };
+
+    boolean success = false;
+    try {
+
+      provider.aboutToChange(newInput);
+      new ProgressMonitorDialog(shell).run(false, true, op);
+      success = true;
+
+    } catch (InterruptedException x) {
+    } catch (InvocationTargetException x) {
+
+      Throwable t = x.getTargetException();
+      if (t instanceof CoreException) {
+        CoreException cx = (CoreException) t;
+        ErrorDialog.openError(shell, PHPEditorMessages.getString("CompilationUnitEditor.error.saving.title2"), PHPEditorMessages.getString("CompilationUnitEditor.error.saving.message2"), cx.getStatus()); //$NON-NLS-1$ //$NON-NLS-2$
+      } else {
+        MessageDialog.openError(shell, PHPEditorMessages.getString("CompilationUnitEditor.error.saving.title3"), PHPEditorMessages.getString("CompilationUnitEditor.error.saving.message3") + t.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$
+      }
+
+    } finally {
+      provider.changed(newInput);
+      if (success)
+        setInput(newInput);
+    }
+
+    if (progressMonitor != null)
+      progressMonitor.setCanceled(!success);
+  }
   /*
    * @see AbstractTextEditor#doSetInput(IEditorInput)
    */
@@ -1303,11 +1463,11 @@ public class PHPUnitEditor extends PHPEditor {
     //      fPropertyChangeListener = null;
     //    }
 
-    //    if (fJavaEditorErrorTickUpdater != null) {
-    //      fJavaEditorErrorTickUpdater.dispose();
-    //      fJavaEditorErrorTickUpdater= null;
-    //    }
-    //         
+    if (fJavaEditorErrorTickUpdater != null) {
+      fJavaEditorErrorTickUpdater.dispose();
+      fJavaEditorErrorTickUpdater = null;
+    }
+
     //    if (fSelectionHistory != null)
     //      fSelectionHistory.dispose();
 
@@ -1429,13 +1589,13 @@ public class PHPUnitEditor extends PHPEditor {
           return;
         }
 
-        if (OVERVIEW_RULER.equals(p)) {
-          if (isOverviewRulerVisible())
-            showOverviewRuler();
-          else
-            hideOverviewRuler();
-          return;
-        }
+        //        if (OVERVIEW_RULER.equals(p)) {
+        //          if (isOverviewRulerVisible())
+        //            showOverviewRuler();
+        //          else
+        //            hideOverviewRuler();
+        //          return;
+        //        }
 
         //        AnnotationType type = getAnnotationType(p);
         //        if (type != null) {
@@ -1579,6 +1739,35 @@ public class PHPUnitEditor extends PHPEditor {
   }
 
   /*
+   * @see JavaEditor#setOutlinePageInput(JavaOutlinePage, IEditorInput)
+   */
+  protected void setOutlinePageInput(JavaOutlinePage page, IEditorInput input) {
+    if (page != null) {
+      IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
+      page.setInput(manager.getWorkingCopy(input));
+    }
+  }
+
+  /*
+   * @see AbstractTextEditor#performSaveOperation(WorkspaceModifyOperation, IProgressMonitor)
+   */
+  protected void performSaveOperation(WorkspaceModifyOperation operation, IProgressMonitor progressMonitor) {
+    IDocumentProvider p = getDocumentProvider();
+    if (p instanceof PHPDocumentProvider) {
+      PHPDocumentProvider cp = (PHPDocumentProvider) p;
+      cp.setSavePolicy(fSavePolicy);
+    }
+
+    try {
+      super.performSaveOperation(operation, progressMonitor);
+    } finally {
+      if (p instanceof PHPDocumentProvider) {
+        PHPDocumentProvider cp = (PHPDocumentProvider) p;
+        cp.setSavePolicy(null);
+      }
+    }
+  }
+  /*
    * @see AbstractTextEditor#doSaveAs
    */
   public void doSaveAs() {
@@ -1664,4 +1853,109 @@ public class PHPUnitEditor extends PHPEditor {
     }
     return true;
   }
+  /*
+        * @see IReconcilingParticipant#reconciled()
+        */
+  public void reconciled() {
+    if (synchronizeOutlineOnCursorMove()) {
+      Shell shell = getSite().getShell();
+      if (shell != null && !shell.isDisposed()) {
+        shell.getDisplay().asyncExec(new Runnable() {
+          public void run() {
+            synchronizeOutlinePageSelection();
+          }
+        });
+      }
+    }
+  }
+
+  private boolean synchronizeOutlineOnCursorMove() {
+    return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE);
+  }
+  protected void updateStateDependentActions() {
+    super.updateStateDependentActions();
+    fGenerateActionGroup.editorStateChanged();
+  }
+
+  /**
+   * Returns the updated java element for the old java element.
+   */
+  private IJavaElement findElement(IJavaElement element) {
+
+    if (element == null)
+      return null;
+
+    IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
+    ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
+
+    if (unit != null) {
+      try {
+
+        synchronized (unit) {
+          unit.reconcile();
+        }
+        IJavaElement[] findings = unit.findElements(element);
+        if (findings != null && findings.length > 0)
+          return findings[0];
+
+      } catch (JavaModelException x) {
+        PHPeclipsePlugin.log(x.getStatus());
+        // nothing found, be tolerant and go on
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Returns the offset of the given Java element.
+   */
+  private int getOffset(IJavaElement element) {
+    if (element instanceof ISourceReference) {
+      ISourceReference sr = (ISourceReference) element;
+      try {
+        ISourceRange srcRange = sr.getSourceRange();
+        if (srcRange != null)
+          return srcRange.getOffset();
+      } catch (JavaModelException e) {
+      }
+    }
+    return -1;
+  }
+
+  /*
+   * @see AbstractTextEditor#rememberSelection()
+   */
+  protected void rememberSelection() {
+    ISelectionProvider sp = getSelectionProvider();
+    fRememberedSelection = (sp == null ? null : (ITextSelection) sp.getSelection());
+    if (fRememberedSelection != null) {
+      fRememberedElement = getElementAt(fRememberedSelection.getOffset(), true);
+      fRememberedElementOffset = getOffset(fRememberedElement);
+    }
+  }
+
+  /*
+   * @see AbstractTextEditor#restoreSelection()
+   */
+  protected void restoreSelection() {
+
+    try {
+
+      if (getSourceViewer() == null || fRememberedSelection == null)
+        return;
+
+      IJavaElement newElement = findElement(fRememberedElement);
+      int newOffset = getOffset(newElement);
+      int delta = (newOffset > -1 && fRememberedElementOffset > -1) ? newOffset - fRememberedElementOffset : 0;
+      if (isValidSelection(delta + fRememberedSelection.getOffset(), fRememberedSelection.getLength()))
+        selectAndReveal(delta + fRememberedSelection.getOffset(), fRememberedSelection.getLength());
+
+    } finally {
+      fRememberedSelection = null;
+      fRememberedElement = null;
+      fRememberedElementOffset = -1;
+    }
+  }
+
 }