Action borrowed from cfeclipse: "remove trailing spaces at end of file"
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPUnitEditor.java
1 package net.sourceforge.phpeclipse.phpeditor;
2
3 import java.text.MessageFormat;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9
10 import net.sourceforge.phpdt.core.ICompilationUnit;
11 import net.sourceforge.phpdt.core.IJavaElement;
12 import net.sourceforge.phpdt.core.IJavaProject;
13 import net.sourceforge.phpdt.core.IMember;
14 import net.sourceforge.phpdt.core.ISourceRange;
15 import net.sourceforge.phpdt.core.ISourceReference;
16 import net.sourceforge.phpdt.core.JavaCore;
17 import net.sourceforge.phpdt.core.JavaModelException;
18 import net.sourceforge.phpdt.core.dom.CompilationUnit;
19 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
20 import net.sourceforge.phpdt.internal.ui.actions.AddBlockCommentAction;
21 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
22 import net.sourceforge.phpdt.internal.ui.actions.IndentAction;
23 import net.sourceforge.phpdt.internal.ui.actions.RemoveBlockCommentAction;
24 import net.sourceforge.phpdt.internal.ui.text.ContentAssistPreference;
25 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
26 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
27 import net.sourceforge.phpdt.internal.ui.text.SmartBackspaceManager;
28 import net.sourceforge.phpdt.internal.ui.text.SmartSemicolonAutoEditStrategy;
29 import net.sourceforge.phpdt.internal.ui.text.comment.CommentFormattingContext;
30 import net.sourceforge.phpdt.internal.ui.text.java.IJavaReconcilingListener;
31 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager;
32 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI;
33 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI.ExitFlags;
34 import net.sourceforge.phpdt.ui.IWorkingCopyManager;
35 import net.sourceforge.phpdt.ui.PreferenceConstants;
36 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
37 import net.sourceforge.phpdt.ui.text.JavaTextTools;
38 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
39 import net.sourceforge.phpeclipse.phpeditor.actions.RTrimAction;
40 import net.sourceforge.phpeclipse.ui.editor.ShowExternalPreviewAction;
41
42 import org.eclipse.core.internal.runtime.ListenerList;
43 import org.eclipse.core.resources.IFile;
44 import org.eclipse.core.resources.IWorkspaceRoot;
45 import org.eclipse.core.resources.ResourcesPlugin;
46 import org.eclipse.core.runtime.CoreException;
47 import org.eclipse.core.runtime.IPath;
48 import org.eclipse.core.runtime.IProgressMonitor;
49 import org.eclipse.core.runtime.IStatus;
50 import org.eclipse.core.runtime.Preferences;
51 import org.eclipse.jface.action.Action;
52 import org.eclipse.jface.action.IAction;
53 import org.eclipse.jface.action.IMenuManager;
54 import org.eclipse.jface.dialogs.ErrorDialog;
55 import org.eclipse.jface.dialogs.IMessageProvider;
56 import org.eclipse.jface.dialogs.MessageDialog;
57 import org.eclipse.jface.preference.IPreferenceStore;
58 import org.eclipse.jface.preference.PreferenceConverter;
59 import org.eclipse.jface.text.BadLocationException;
60 import org.eclipse.jface.text.DocumentCommand;
61 import org.eclipse.jface.text.IAutoEditStrategy;
62 import org.eclipse.jface.text.IDocument;
63 import org.eclipse.jface.text.ILineTracker;
64 import org.eclipse.jface.text.IRegion;
65 import org.eclipse.jface.text.ITextOperationTarget;
66 import org.eclipse.jface.text.ITextViewerExtension;
67 import org.eclipse.jface.text.ITypedRegion;
68 import org.eclipse.jface.text.IWidgetTokenKeeper;
69 import org.eclipse.jface.text.contentassist.ContentAssistant;
70 import org.eclipse.jface.text.contentassist.IContentAssistant;
71 import org.eclipse.jface.text.formatter.FormattingContextProperties;
72 import org.eclipse.jface.text.formatter.IFormattingContext;
73 import org.eclipse.jface.text.source.IOverviewRuler;
74 import org.eclipse.jface.text.source.ISourceViewer;
75 import org.eclipse.jface.text.source.IVerticalRuler;
76 import org.eclipse.jface.text.source.SourceViewerConfiguration;
77 import org.eclipse.jface.util.PropertyChangeEvent;
78 import org.eclipse.jface.window.Window;
79 import org.eclipse.swt.SWT;
80 import org.eclipse.swt.custom.VerifyKeyListener;
81 import org.eclipse.swt.events.VerifyEvent;
82 import org.eclipse.swt.graphics.Color;
83 import org.eclipse.swt.graphics.Point;
84 import org.eclipse.swt.graphics.RGB;
85 import org.eclipse.swt.widgets.Composite;
86 import org.eclipse.swt.widgets.Display;
87 import org.eclipse.swt.widgets.Shell;
88 import org.eclipse.ui.IEditorInput;
89 import org.eclipse.ui.IEditorPart;
90 import org.eclipse.ui.IFileEditorInput;
91 import org.eclipse.ui.IWorkbenchPage;
92 import org.eclipse.ui.IWorkbenchWindow;
93 import org.eclipse.ui.actions.ActionContext;
94 import org.eclipse.ui.actions.ActionGroup;
95 import org.eclipse.ui.dialogs.SaveAsDialog;
96 import org.eclipse.ui.editors.text.IStorageDocumentProvider;
97 import org.eclipse.ui.help.WorkbenchHelp;
98 import org.eclipse.ui.part.FileEditorInput;
99 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
100 import org.eclipse.ui.texteditor.ContentAssistAction;
101 import org.eclipse.ui.texteditor.IDocumentProvider;
102 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
103 import org.eclipse.ui.texteditor.TextOperationAction;
104
105 /*******************************************************************************
106  * Copyright (c) 2000, 2002 IBM Corp. and others. All rights reserved. This
107  * program and the accompanying materials are made available under the terms of
108  * the Common Public License v1.0 which accompanies this distribution, and is
109  * available at http://www.eclipse.org/legal/cpl-v10.html
110  * 
111  * Contributors: IBM Corporation - Initial implementation 
112  * www.phpeclipse.de
113  ******************************************************************************/
114 /**
115  * PHP specific text editor.
116  */
117 public class PHPUnitEditor extends PHPEditor { //implements
118   // IJavaReconcilingListener {
119   interface ITextConverter {
120     void customizeDocumentCommand(IDocument document, DocumentCommand command);
121   };
122
123   //  class AdaptedSourceViewer extends JavaSourceViewer {
124   //    private List fTextConverters;
125   //
126   //    private boolean fIgnoreTextConverters = false;
127   //
128   //    // private JavaCorrectionAssistant fCorrectionAssistant;
129   //    public AdaptedSourceViewer(Composite parent, IVerticalRuler verticalRuler,
130   //        IOverviewRuler overviewRuler, boolean showAnnotationsOverview,
131   //        int styles, IPreferenceStore store) {
132   //      super(parent, verticalRuler, overviewRuler, showAnnotationsOverview,
133   //          styles, store);
134   //    }
135   //
136   //    // public AdaptedSourceViewer(Composite parent,
137   //    // IVerticalRuler verticalRuler, IOverviewRuler overviewRuler,
138   //    // boolean showAnnotationsOverview, int styles) {
139   //    // super(parent, verticalRuler, overviewRuler,
140   //    // showAnnotationsOverview, styles);
141   //    // }
142   //    public IContentAssistant getContentAssistant() {
143   //      return fContentAssistant;
144   //    }
145   //
146   //    /*
147   //     * @see ITextOperationTarget#doOperation(int)
148   //     */
149   //    public void doOperation(int operation) {
150   //      if (getTextWidget() == null)
151   //        return;
152   //      switch (operation) {
153   //      case CONTENTASSIST_PROPOSALS:
154   //        String msg = fContentAssistant.showPossibleCompletions();
155   //        setStatusLineErrorMessage(msg);
156   //        return;
157   //      // case CORRECTIONASSIST_PROPOSALS:
158   //      // fCorrectionAssistant.showPossibleCompletions();
159   //      // return;
160   //      case UNDO:
161   //        fIgnoreTextConverters = true;
162   //        break;
163   //      case REDO:
164   //        fIgnoreTextConverters = true;
165   //        break;
166   //      }
167   //      super.doOperation(operation);
168   //    }
169   //
170   //    /*
171   //     * @see ITextOperationTarget#canDoOperation(int)
172   //     */
173   //    public boolean canDoOperation(int operation) {
174   //      // if (operation == CORRECTIONASSIST_PROPOSALS)
175   //      // return isEditable();
176   //      return super.canDoOperation(operation);
177   //    }
178   //
179   //    /*
180   //     * @see TextViewer#handleDispose()
181   //     */
182   //    protected void handleDispose() {
183   //      // if (fCorrectionAssistant != null) {
184   //      // fCorrectionAssistant.uninstall();
185   //      // fCorrectionAssistant= null;
186   //      // }
187   //      super.handleDispose();
188   //    }
189   //
190   //    public void insertTextConverter(ITextConverter textConverter, int index) {
191   //      throw new UnsupportedOperationException();
192   //    }
193   //
194   //    public void addTextConverter(ITextConverter textConverter) {
195   //      if (fTextConverters == null) {
196   //        fTextConverters = new ArrayList(1);
197   //        fTextConverters.add(textConverter);
198   //      } else if (!fTextConverters.contains(textConverter))
199   //        fTextConverters.add(textConverter);
200   //    }
201   //
202   //    public void removeTextConverter(ITextConverter textConverter) {
203   //      if (fTextConverters != null) {
204   //        fTextConverters.remove(textConverter);
205   //        if (fTextConverters.size() == 0)
206   //          fTextConverters = null;
207   //      }
208   //    }
209   //
210   //    /*
211   //     * @see TextViewer#customizeDocumentCommand(DocumentCommand)
212   //     */
213   //    protected void customizeDocumentCommand(DocumentCommand command) {
214   //      super.customizeDocumentCommand(command);
215   //      if (!fIgnoreTextConverters && fTextConverters != null) {
216   //        for (Iterator e = fTextConverters.iterator(); e.hasNext();)
217   //          ((ITextConverter) e.next()).customizeDocumentCommand(getDocument(),
218   //              command);
219   //      }
220   //      fIgnoreTextConverters = false;
221   //    }
222   //
223   //    // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
224   //    public void updateIndentationPrefixes() {
225   //      SourceViewerConfiguration configuration = getSourceViewerConfiguration();
226   //      String[] types = configuration.getConfiguredContentTypes(this);
227   //      for (int i = 0; i < types.length; i++) {
228   //        String[] prefixes = configuration.getIndentPrefixes(this, types[i]);
229   //        if (prefixes != null && prefixes.length > 0)
230   //          setIndentPrefixes(prefixes, types[i]);
231   //      }
232   //    }
233   //
234   //    /*
235   //     * @see IWidgetTokenOwner#requestWidgetToken(IWidgetTokenKeeper)
236   //     */
237   //    public boolean requestWidgetToken(IWidgetTokenKeeper requester) {
238   //      if (WorkbenchHelp.isContextHelpDisplayed())
239   //        return false;
240   //      return super.requestWidgetToken(requester);
241   //    }
242   //
243   //// /*
244   //// * @see org.eclipse.jface.text.source.ISourceViewer#configure(org.eclipse.jface.text.source.SourceViewerConfiguration)
245   //// */
246   //// public void configure(SourceViewerConfiguration configuration) {
247   //// super.configure(configuration);
248   //// // fCorrectionAssistant= new
249   //// // JavaCorrectionAssistant(CompilationUnitEditor.this);
250   //// // fCorrectionAssistant.install(this);
251   //// //TODO install SmartBracesAutoEditStrategy
252   //// // prependAutoEditStrategy(new SmartBracesAutoEditStrategy(this),
253   //// // IDocument.DEFAULT_CONTENT_TYPE);
254   //// }
255   //    public void configure(SourceViewerConfiguration configuration) {
256   //            super.configure(configuration);
257   //// fCorrectionAssistant= new JavaCorrectionAssistant(CompilationUnitEditor.this);
258   //// fCorrectionAssistant.install(this);
259   //            IAutoEditStrategy smartSemi= new SmartSemicolonAutoEditStrategy(IPHPPartitions.PHP_PARTITIONING);
260   //            prependAutoEditStrategy(smartSemi, IDocument.DEFAULT_CONTENT_TYPE);
261   //            prependAutoEditStrategy(smartSemi, IPHPPartitions.PHP_STRING_DQ);
262   //            prependAutoEditStrategy(smartSemi, IPHPPartitions.PHP_STRING_SQ);
263   //// prependAutoEditStrategy(smartSemi, IPHPPartitions.JAVA_CHARACTER);
264   //    }
265   //  };
266   class AdaptedSourceViewer extends JavaSourceViewer {
267
268     private List fTextConverters;
269
270     private boolean fIgnoreTextConverters = false;
271
272     //    private JavaCorrectionAssistant fCorrectionAssistant;
273
274     public AdaptedSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler,
275         boolean showAnnotationsOverview, int styles, IPreferenceStore store) {
276       super(parent, verticalRuler, overviewRuler, showAnnotationsOverview, styles, store);
277     }
278
279     public IContentAssistant getContentAssistant() {
280       return fContentAssistant;
281     }
282
283     /*
284      * @see ITextOperationTarget#doOperation(int)
285      */
286     public void doOperation(int operation) {
287
288       if (getTextWidget() == null)
289         return;
290
291       switch (operation) {
292       case CONTENTASSIST_PROPOSALS:
293         String msg = fContentAssistant.showPossibleCompletions();
294         setStatusLineErrorMessage(msg);
295         return;
296       //      case CORRECTIONASSIST_PROPOSALS:
297       //        msg = fCorrectionAssistant.showPossibleCompletions();
298       //        setStatusLineErrorMessage(msg);
299       //        return;
300       case UNDO:
301         fIgnoreTextConverters = true;
302         super.doOperation(operation);
303         fIgnoreTextConverters = false;
304         return;
305       case REDO:
306         fIgnoreTextConverters = true;
307         super.doOperation(operation);
308         fIgnoreTextConverters = false;
309         return;
310       }
311
312       super.doOperation(operation);
313     }
314
315     /*
316      * @see ITextOperationTarget#canDoOperation(int)
317      */
318     public boolean canDoOperation(int operation) {
319       //      if (operation == CORRECTIONASSIST_PROPOSALS)
320       //        return isEditable();
321
322       return super.canDoOperation(operation);
323     }
324
325     /*
326      * @see org.eclipse.jface.text.source.ISourceViewerExtension2#unconfigure()
327      * @since 3.0
328      */
329     public void unconfigure() {
330       //      if (fCorrectionAssistant != null) {
331       //        fCorrectionAssistant.uninstall();
332       //        fCorrectionAssistant = null;
333       //      }
334       super.unconfigure();
335     }
336
337     public void insertTextConverter(ITextConverter textConverter, int index) {
338       throw new UnsupportedOperationException();
339     }
340
341     public void addTextConverter(ITextConverter textConverter) {
342       if (fTextConverters == null) {
343         fTextConverters = new ArrayList(1);
344         fTextConverters.add(textConverter);
345       } else if (!fTextConverters.contains(textConverter))
346         fTextConverters.add(textConverter);
347     }
348
349     public void removeTextConverter(ITextConverter textConverter) {
350       if (fTextConverters != null) {
351         fTextConverters.remove(textConverter);
352         if (fTextConverters.size() == 0)
353           fTextConverters = null;
354       }
355     }
356
357     /*
358      * @see TextViewer#customizeDocumentCommand(DocumentCommand)
359      */
360     protected void customizeDocumentCommand(DocumentCommand command) {
361       super.customizeDocumentCommand(command);
362       if (!fIgnoreTextConverters && fTextConverters != null) {
363         for (Iterator e = fTextConverters.iterator(); e.hasNext();)
364           ((ITextConverter) e.next()).customizeDocumentCommand(getDocument(), command);
365       }
366     }
367
368     // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
369     public void updateIndentationPrefixes() {
370       SourceViewerConfiguration configuration = getSourceViewerConfiguration();
371       String[] types = configuration.getConfiguredContentTypes(this);
372       for (int i = 0; i < types.length; i++) {
373         String[] prefixes = configuration.getIndentPrefixes(this, types[i]);
374         if (prefixes != null && prefixes.length > 0)
375           setIndentPrefixes(prefixes, types[i]);
376       }
377     }
378
379     /*
380      * @see IWidgetTokenOwner#requestWidgetToken(IWidgetTokenKeeper)
381      */
382     public boolean requestWidgetToken(IWidgetTokenKeeper requester) {
383       if (WorkbenchHelp.isContextHelpDisplayed())
384         return false;
385       return super.requestWidgetToken(requester);
386     }
387
388     /*
389      * @see IWidgetTokenOwnerExtension#requestWidgetToken(IWidgetTokenKeeper, int)
390      * @since 3.0
391      */
392     public boolean requestWidgetToken(IWidgetTokenKeeper requester, int priority) {
393       if (WorkbenchHelp.isContextHelpDisplayed())
394         return false;
395       return super.requestWidgetToken(requester, priority);
396     }
397
398     /*
399      * @see org.eclipse.jface.text.source.ISourceViewer#configure(org.eclipse.jface.text.source.SourceViewerConfiguration)
400      */
401     public void configure(SourceViewerConfiguration configuration) {
402       super.configure(configuration);
403       //      fCorrectionAssistant = new JavaCorrectionAssistant(CompilationUnitEditor.this);
404       //      fCorrectionAssistant.install(this);
405       IAutoEditStrategy smartSemi = new SmartSemicolonAutoEditStrategy(IPHPPartitions.PHP_PARTITIONING);
406       prependAutoEditStrategy(smartSemi, IDocument.DEFAULT_CONTENT_TYPE);
407       prependAutoEditStrategy(smartSemi, IPHPPartitions.PHP_STRING_DQ);
408       prependAutoEditStrategy(smartSemi, IPHPPartitions.PHP_STRING_SQ);
409     }
410
411     /*
412      * @see org.eclipse.jface.text.source.SourceViewer#createFormattingContext()
413      * @since 3.0
414      */
415     public IFormattingContext createFormattingContext() {
416       IFormattingContext context = new CommentFormattingContext();
417
418       Map preferences;
419       IJavaElement inputJavaElement = getInputJavaElement();
420       IJavaProject javaProject = inputJavaElement != null ? inputJavaElement.getJavaProject() : null;
421       if (javaProject == null)
422         preferences = new HashMap(JavaCore.getOptions());
423       else
424         preferences = new HashMap(javaProject.getOptions(true));
425
426       context.storeToMap(PreferenceConstants.getPreferenceStore(), preferences, false);
427       context.setProperty(FormattingContextProperties.CONTEXT_PREFERENCES, preferences);
428
429       return context;
430     }
431   }
432
433   /**
434    * Remembers data related to the current selection to be able to restore it later.
435    * 
436    * @since 3.0
437    */
438   private class RememberedSelection {
439     /** The remembered selection start. */
440     private RememberedOffset fStartOffset = new RememberedOffset();
441
442     /** The remembered selection end. */
443     private RememberedOffset fEndOffset = new RememberedOffset();
444
445     /**
446      * Remember current selection.
447      */
448     public void remember() {
449       /*
450        * https://bugs.eclipse.org/bugs/show_bug.cgi?id=52257 This method may be called inside an async call posted to the UI thread,
451        * so protect against intermediate disposal of the editor.
452        */
453       ISourceViewer viewer = getSourceViewer();
454       if (viewer != null) {
455         IRegion selection = getSignedSelection(viewer);
456         int startOffset = selection.getOffset();
457         int endOffset = startOffset + selection.getLength();
458
459         fStartOffset.setOffset(startOffset);
460         fEndOffset.setOffset(endOffset);
461       }
462     }
463
464     /**
465      * Restore remembered selection.
466      */
467     public void restore() {
468       /*
469        * https://bugs.eclipse.org/bugs/show_bug.cgi?id=52257 This method may be called inside an async call posted to the UI thread,
470        * so protect against intermediate disposal of the editor.
471        */
472       if (getSourceViewer() == null)
473         return;
474
475       try {
476
477         int startOffset, endOffset;
478         int revealStartOffset, revealEndOffset;
479         if (showsHighlightRangeOnly()) {
480           IJavaElement newStartElement = fStartOffset.getElement();
481           startOffset = fStartOffset.getRememberedOffset(newStartElement);
482           revealStartOffset = fStartOffset.getRevealOffset(newStartElement, startOffset);
483           if (revealStartOffset == -1)
484             startOffset = -1;
485
486           IJavaElement newEndElement = fEndOffset.getElement();
487           endOffset = fEndOffset.getRememberedOffset(newEndElement);
488           revealEndOffset = fEndOffset.getRevealOffset(newEndElement, endOffset);
489           if (revealEndOffset == -1)
490             endOffset = -1;
491         } else {
492           startOffset = fStartOffset.getOffset();
493           revealStartOffset = startOffset;
494           endOffset = fEndOffset.getOffset();
495           revealEndOffset = endOffset;
496         }
497
498         if (startOffset == -1) {
499           startOffset = endOffset; // fallback to caret offset
500           revealStartOffset = revealEndOffset;
501         }
502
503         if (endOffset == -1) {
504           endOffset = startOffset; // fallback to other offset
505           revealEndOffset = revealStartOffset;
506         }
507
508         IJavaElement element;
509         if (endOffset == -1) {
510           // fallback to element selection
511           element = fEndOffset.getElement();
512           if (element == null)
513             element = fStartOffset.getElement();
514           if (element != null)
515             setSelection(element);
516           return;
517         }
518
519         if (isValidSelection(revealStartOffset, revealEndOffset - revealStartOffset)
520             && isValidSelection(startOffset, endOffset - startOffset))
521           selectAndReveal(startOffset, endOffset - startOffset, revealStartOffset, revealEndOffset - revealStartOffset);
522       } finally {
523         fStartOffset.clear();
524         fEndOffset.clear();
525       }
526     }
527
528     private boolean isValidSelection(int offset, int length) {
529       IDocumentProvider provider = getDocumentProvider();
530       if (provider != null) {
531         IDocument document = provider.getDocument(getEditorInput());
532         if (document != null) {
533           int end = offset + length;
534           int documentLength = document.getLength();
535           return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength;
536         }
537       }
538       return false;
539     }
540
541   }
542
543   /**
544    * Remembers additional data for a given offset to be able restore it later.
545    * 
546    * @since 3.0
547    */
548   private class RememberedOffset {
549     /** Remembered line for the given offset */
550     private int fLine;
551
552     /** Remembered column for the given offset */
553     private int fColumn;
554
555     /** Remembered Java element for the given offset */
556     private IJavaElement fElement;
557
558     /** Remembered Java element line for the given offset */
559     private int fElementLine;
560
561     /**
562      * Store visual properties of the given offset.
563      * 
564      * @param offset
565      *          Offset in the document
566      */
567     public void setOffset(int offset) {
568       try {
569         IDocument document = getSourceViewer().getDocument();
570         fLine = document.getLineOfOffset(offset);
571         fColumn = offset - document.getLineOffset(fLine);
572         fElement = getElementAt(offset, true);
573
574         fElementLine = -1;
575         if (fElement instanceof IMember) {
576           ISourceRange range = ((IMember) fElement).getNameRange();
577           if (range != null)
578             fElementLine = document.getLineOfOffset(range.getOffset());
579         }
580         if (fElementLine == -1)
581           fElementLine = document.getLineOfOffset(getOffset(fElement));
582       } catch (BadLocationException e) {
583         // should not happen
584         PHPeclipsePlugin.log(e);
585         clear();
586       } catch (JavaModelException e) {
587         // should not happen
588         PHPeclipsePlugin.log(e.getStatus());
589         clear();
590       }
591     }
592
593     /**
594      * Return offset recomputed from stored visual properties.
595      * 
596      * @return Offset in the document
597      */
598     public int getOffset() {
599       IJavaElement newElement = getElement();
600
601       int offset = getRememberedOffset(newElement);
602
603       if (offset != -1 && !containsOffset(newElement, offset) && (offset == 0 || !containsOffset(newElement, offset - 1)))
604         return -1;
605
606       return offset;
607     }
608
609     /**
610      * Return offset recomputed from stored visual properties.
611      * 
612      * @param newElement
613      *          Enclosing element
614      * @return Offset in the document
615      */
616     public int getRememberedOffset(IJavaElement newElement) {
617       try {
618         if (newElement == null)
619           return -1;
620
621         IDocument document = getSourceViewer().getDocument();
622         int newElementLine = -1;
623         if (newElement instanceof IMember) {
624           ISourceRange range = ((IMember) newElement).getNameRange();
625           if (range != null)
626             newElementLine = document.getLineOfOffset(range.getOffset());
627         }
628         if (newElementLine == -1)
629           newElementLine = document.getLineOfOffset(getOffset(newElement));
630         if (newElementLine == -1)
631           return -1;
632
633         int newLine = fLine + newElementLine - fElementLine;
634         if (newLine < 0 || newLine >= document.getNumberOfLines())
635           return -1;
636         int maxColumn = document.getLineLength(newLine);
637         String lineDelimiter = document.getLineDelimiter(newLine);
638         if (lineDelimiter != null)
639           maxColumn = maxColumn - lineDelimiter.length();
640         int offset;
641         if (fColumn > maxColumn)
642           offset = document.getLineOffset(newLine) + maxColumn;
643         else
644           offset = document.getLineOffset(newLine) + fColumn;
645
646         return offset;
647       } catch (BadLocationException e) {
648         // should not happen
649         PHPeclipsePlugin.log(e);
650         return -1;
651       } catch (JavaModelException e) {
652         // should not happen
653         PHPeclipsePlugin.log(e.getStatus());
654         return -1;
655       }
656     }
657
658     /**
659      * Returns the offset used to reveal the given element based on the given selection offset.
660      * 
661      * @param element
662      *          the element
663      * @param offset
664      *          the selection offset
665      * @return the offset to reveal the given element based on the given selection offset
666      */
667     public int getRevealOffset(IJavaElement element, int offset) {
668       if (element == null || offset == -1)
669         return -1;
670
671       if (containsOffset(element, offset)) {
672         if (offset > 0) {
673           IJavaElement alternateElement = getElementAt(offset, false);
674           if (element.getHandleIdentifier().equals(alternateElement.getParent().getHandleIdentifier()))
675             return offset - 1; // Solves test case 2 from https://bugs.eclipse.org/bugs/show_bug.cgi?id=47727#c3
676         }
677         return offset;
678       } else if (offset > 0 && containsOffset(element, offset - 1))
679         return offset - 1; // Solves test case 1 from https://bugs.eclipse.org/bugs/show_bug.cgi?id=47727#c3
680
681       return -1;
682     }
683
684     /**
685      * Return Java element recomputed from stored visual properties.
686      * 
687      * @return Java element
688      */
689     public IJavaElement getElement() {
690       if (fElement == null)
691         return null;
692
693       return findElement(fElement);
694     }
695
696     /**
697      * Clears the stored position
698      */
699     public void clear() {
700       fLine = -1;
701       fColumn = -1;
702       fElement = null;
703       fElementLine = -1;
704     }
705
706     /**
707      * Does the given Java element contain the given offset?
708      * 
709      * @param element
710      *          Java element
711      * @param offset
712      *          Offset
713      * @return <code>true</code> iff the Java element contains the offset
714      */
715     private boolean containsOffset(IJavaElement element, int offset) {
716       int elementOffset = getOffset(element);
717       int elementLength = getLength(element);
718       return (elementOffset > -1 && elementLength > -1) ? (offset >= elementOffset && offset < elementOffset + elementLength)
719           : false;
720     }
721
722     /**
723      * Returns the offset of the given Java element.
724      * 
725      * @param element
726      *          Java element
727      * @return Offset of the given Java element
728      */
729     private int getOffset(IJavaElement element) {
730       if (element instanceof ISourceReference) {
731         ISourceReference sr = (ISourceReference) element;
732         try {
733           ISourceRange srcRange = sr.getSourceRange();
734           if (srcRange != null)
735             return srcRange.getOffset();
736         } catch (JavaModelException e) {
737         }
738       }
739       return -1;
740     }
741
742     /**
743      * Returns the length of the given Java element.
744      * 
745      * @param element
746      *          Java element
747      * @return Length of the given Java element
748      */
749     private int getLength(IJavaElement element) {
750       if (element instanceof ISourceReference) {
751         ISourceReference sr = (ISourceReference) element;
752         try {
753           ISourceRange srcRange = sr.getSourceRange();
754           if (srcRange != null)
755             return srcRange.getLength();
756         } catch (JavaModelException e) {
757         }
758       }
759       return -1;
760     }
761
762     /**
763      * Returns the updated java element for the old java element.
764      * 
765      * @param element
766      *          Old Java element
767      * @return Updated Java element
768      */
769     private IJavaElement findElement(IJavaElement element) {
770
771       if (element == null)
772         return null;
773
774       IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
775       ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
776
777       if (unit != null) {
778         try {
779
780           synchronized (unit) {
781             //                                          unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
782             unit.reconcile();
783           }
784           IJavaElement[] findings = unit.findElements(element);
785           if (findings != null && findings.length > 0)
786             return findings[0];
787
788         } catch (JavaModelException x) {
789           PHPeclipsePlugin.log(x.getStatus());
790           // nothing found, be tolerant and go on
791         }
792       }
793
794       return null;
795     }
796
797   }
798
799   static class TabConverter implements ITextConverter {
800     private int fTabRatio;
801
802     private ILineTracker fLineTracker;
803
804     public TabConverter() {
805     }
806
807     public void setNumberOfSpacesPerTab(int ratio) {
808       fTabRatio = ratio;
809     }
810
811     public void setLineTracker(ILineTracker lineTracker) {
812       fLineTracker = lineTracker;
813     }
814
815     private int insertTabString(StringBuffer buffer, int offsetInLine) {
816       if (fTabRatio == 0)
817         return 0;
818       int remainder = offsetInLine % fTabRatio;
819       remainder = fTabRatio - remainder;
820       for (int i = 0; i < remainder; i++)
821         buffer.append(' ');
822       return remainder;
823     }
824
825     public void customizeDocumentCommand(IDocument document, DocumentCommand command) {
826       String text = command.text;
827       if (text == null)
828         return;
829       int index = text.indexOf('\t');
830       if (index > -1) {
831         StringBuffer buffer = new StringBuffer();
832         fLineTracker.set(command.text);
833         int lines = fLineTracker.getNumberOfLines();
834         try {
835           for (int i = 0; i < lines; i++) {
836             int offset = fLineTracker.getLineOffset(i);
837             int endOffset = offset + fLineTracker.getLineLength(i);
838             String line = text.substring(offset, endOffset);
839             int position = 0;
840             if (i == 0) {
841               IRegion firstLine = document.getLineInformationOfOffset(command.offset);
842               position = command.offset - firstLine.getOffset();
843             }
844             int length = line.length();
845             for (int j = 0; j < length; j++) {
846               char c = line.charAt(j);
847               if (c == '\t') {
848                 position += insertTabString(buffer, position);
849               } else {
850                 buffer.append(c);
851                 ++position;
852               }
853             }
854           }
855           command.text = buffer.toString();
856         } catch (BadLocationException x) {
857         }
858       }
859     }
860   };
861
862   private static class ExitPolicy implements LinkedPositionUI.ExitPolicy {
863     final char fExitCharacter;
864
865     public ExitPolicy(char exitCharacter) {
866       fExitCharacter = exitCharacter;
867     }
868
869     /*
870      * @see org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionManager,
871      *      org.eclipse.swt.events.VerifyEvent, int, int)
872      */
873     public ExitFlags doExit(LinkedPositionManager manager, VerifyEvent event, int offset, int length) {
874       if (event.character == fExitCharacter) {
875         if (manager.anyPositionIncludes(offset, length))
876           return new ExitFlags(LinkedPositionUI.COMMIT | LinkedPositionUI.UPDATE_CARET, false);
877         else
878           return new ExitFlags(LinkedPositionUI.COMMIT, true);
879       }
880       switch (event.character) {
881       case '\b':
882         if (manager.getFirstPosition().length == 0)
883           return new ExitFlags(0, false);
884         else
885           return null;
886       case '\n':
887       case '\r':
888         return new ExitFlags(LinkedPositionUI.COMMIT, true);
889       default:
890         return null;
891       }
892     }
893   }
894
895   private static class BracketLevel {
896     int fOffset;
897
898     int fLength;
899
900     LinkedPositionManager fManager;
901
902     LinkedPositionUI fEditor;
903   };
904
905   private class BracketInserter implements VerifyKeyListener, LinkedPositionUI.ExitListener {
906     private boolean fCloseBracketsPHP = true;
907
908     private boolean fCloseStringsPHPDQ = true;
909
910     private boolean fCloseStringsPHPSQ = true;
911
912     private boolean fCloseBracketsHTML = true;
913
914     private boolean fCloseStringsHTML = true;
915
916     private int fOffset;
917
918     private int fLength;
919
920     public void setCloseBracketsPHPEnabled(boolean enabled) {
921       fCloseBracketsPHP = enabled;
922     }
923
924     public void setCloseStringsPHPDQEnabled(boolean enabled) {
925       fCloseStringsPHPDQ = enabled;
926     }
927
928     public void setCloseStringsPHPSQEnabled(boolean enabled) {
929       fCloseStringsPHPSQ = enabled;
930     }
931
932     public void setCloseBracketsHTMLEnabled(boolean enabled) {
933       fCloseBracketsHTML = enabled;
934     }
935
936     public void setCloseStringsHTMLEnabled(boolean enabled) {
937       fCloseStringsHTML = enabled;
938     }
939
940     private boolean hasIdentifierToTheRight(IDocument document, int offset) {
941       try {
942         int end = offset;
943         IRegion endLine = document.getLineInformationOfOffset(end);
944         int maxEnd = endLine.getOffset() + endLine.getLength();
945         while (end != maxEnd && Character.isWhitespace(document.getChar(end)))
946           ++end;
947         return end != maxEnd && Scanner.isPHPIdentifierPart(document.getChar(end));
948       } catch (BadLocationException e) {
949         // be conservative
950         return true;
951       }
952     }
953
954     private boolean hasIdentifierToTheLeft(IDocument document, int offset) {
955       try {
956         int start = offset;
957         IRegion startLine = document.getLineInformationOfOffset(start);
958         int minStart = startLine.getOffset();
959         while (start != minStart && Character.isWhitespace(document.getChar(start - 1)))
960           --start;
961         return start != minStart && Scanner.isPHPIdentifierPart(document.getChar(start - 1));
962       } catch (BadLocationException e) {
963         return true;
964       }
965     }
966
967     private boolean hasCharacterToTheRight(IDocument document, int offset, char character) {
968       try {
969         int end = offset;
970         IRegion endLine = document.getLineInformationOfOffset(end);
971         int maxEnd = endLine.getOffset() + endLine.getLength();
972         while (end != maxEnd && Character.isWhitespace(document.getChar(end)))
973           ++end;
974         return end != maxEnd && document.getChar(end) == character;
975       } catch (BadLocationException e) {
976         // be conservative
977         return true;
978       }
979     }
980
981     /*
982      * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
983      */
984     public void verifyKey(VerifyEvent event) {
985       if (!event.doit)
986         return;
987       final ISourceViewer sourceViewer = getSourceViewer();
988       IDocument document = sourceViewer.getDocument();
989       final Point selection = sourceViewer.getSelectedRange();
990       final int offset = selection.x;
991       final int length = selection.y;
992       try {
993         ITypedRegion partition = document.getPartition(offset);
994         String type = partition.getType();
995         if (type.equals(IPHPPartitions.PHP_PARTITIONING) || type.equals(IDocument.DEFAULT_CONTENT_TYPE)) {
996           // you will get IDocument.DEFAULT_CONTENT_TYPE for both PHP and HTML area
997           switch (event.character) {
998           case '(':
999             if (hasCharacterToTheRight(document, offset + length, '('))
1000               return;
1001           // fall through
1002           case '[':
1003             if (!fCloseBracketsPHP)
1004               return;
1005             if (hasIdentifierToTheRight(document, offset + length))
1006               return;
1007           // fall through
1008           case '"':
1009             if (event.character == '"') {
1010               if (!fCloseStringsPHPDQ)
1011                 return;
1012               // changed for statements like echo "" print ""
1013               //    if (hasIdentifierToTheLeft(document, offset)
1014               // ||
1015               // hasIdentifierToTheRight(document, offset +
1016               // length))
1017               if (hasIdentifierToTheRight(document, offset + length))
1018                 return;
1019             }
1020             //     ITypedRegion partition=
1021             // document.getPartition(offset);
1022             //       if (!
1023             // IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())
1024             // &&
1025             // (partition.getOffset() != offset))
1026             //         return;
1027             final char characterDQ = event.character;
1028             final char closingCharacterDQ = getPeerCharacter(characterDQ);
1029             final StringBuffer bufferDQ = new StringBuffer();
1030             bufferDQ.append(characterDQ);
1031             bufferDQ.append(closingCharacterDQ);
1032             document.replace(offset, length, bufferDQ.toString());
1033             LinkedPositionManager managerDQ = new LinkedPositionManager(document);
1034             managerDQ.addPosition(offset + 1, 0);
1035             fOffset = offset;
1036             fLength = 2;
1037             LinkedPositionUI editorDQ = new LinkedPositionUI(sourceViewer, managerDQ);
1038             editorDQ.setCancelListener(this);
1039             editorDQ.setExitPolicy(new ExitPolicy(closingCharacterDQ));
1040             editorDQ.setFinalCaretOffset(offset + 2);
1041             editorDQ.enter();
1042             IRegion newSelectionDQ = editorDQ.getSelectedRegion();
1043             sourceViewer.setSelectedRange(newSelectionDQ.getOffset(), newSelectionDQ.getLength());
1044             event.doit = false;
1045             break;
1046           //          fall through
1047           case '\'':
1048             if (event.character == '\'') {
1049               if (!fCloseStringsPHPSQ)
1050                 return;
1051               // changed for statements like echo "" print ""
1052               //    if (hasIdentifierToTheLeft(document, offset)
1053               // ||
1054               // hasIdentifierToTheRight(document, offset +
1055               // length))
1056               if (hasIdentifierToTheRight(document, offset + length))
1057                 return;
1058             }
1059             //     ITypedRegion partition=
1060             // document.getPartition(offset);
1061             //       if (!
1062             // IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())
1063             // &&
1064             // (partition.getOffset() != offset))
1065             //         return;
1066             final char characterSQ = event.character;
1067             final char closingCharacterSQ = getPeerCharacter(characterSQ);
1068             final StringBuffer bufferSQ = new StringBuffer();
1069             bufferSQ.append(characterSQ);
1070             bufferSQ.append(closingCharacterSQ);
1071             document.replace(offset, length, bufferSQ.toString());
1072             LinkedPositionManager managerSQ = new LinkedPositionManager(document);
1073             managerSQ.addPosition(offset + 1, 0);
1074             fOffset = offset;
1075             fLength = 2;
1076             LinkedPositionUI editorSQ = new LinkedPositionUI(sourceViewer, managerSQ);
1077             editorSQ.setCancelListener(this);
1078             editorSQ.setExitPolicy(new ExitPolicy(closingCharacterSQ));
1079             editorSQ.setFinalCaretOffset(offset + 2);
1080             editorSQ.enter();
1081             IRegion newSelectionSQ = editorSQ.getSelectedRegion();
1082             sourceViewer.setSelectedRange(newSelectionSQ.getOffset(), newSelectionSQ.getLength());
1083             event.doit = false;
1084           }
1085         }
1086         //        } else if (type.equals(IPHPPartitions.HTML)) {
1087         //          switch (event.character) {
1088         //          case '(':
1089         //            if (hasCharacterToTheRight(document, offset + length, '('))
1090         //              return;
1091         //          // fall through
1092         //          case '[':
1093         //            if (!fCloseBracketsHTML)
1094         //              return;
1095         //            if (hasIdentifierToTheRight(document, offset + length))
1096         //              return;
1097         //          // fall through
1098         //          case '"':
1099         //            if (event.character == '"') {
1100         //              if (!fCloseStringsHTML)
1101         //                return;
1102         //              if (hasIdentifierToTheLeft(document, offset)
1103         //                  || hasIdentifierToTheRight(document, offset + length))
1104         //                return;
1105         //            }
1106         //            // ITypedRegion partition=
1107         //            // document.getPartition(offset);
1108         //            // if (!
1109         //            // IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())
1110         //            // &&
1111         //            // (partition.getOffset() != offset))
1112         //            // return;
1113         //            final char character = event.character;
1114         //            final char closingCharacter = getPeerCharacter(character);
1115         //            final StringBuffer buffer = new StringBuffer();
1116         //            buffer.append(character);
1117         //            buffer.append(closingCharacter);
1118         //            document.replace(offset, length, buffer.toString());
1119         //            LinkedPositionManager manager = new LinkedPositionManager(document);
1120         //            manager.addPosition(offset + 1, 0);
1121         //            fOffset = offset;
1122         //            fLength = 2;
1123         //            LinkedPositionUI editor = new LinkedPositionUI(sourceViewer,
1124         //                manager);
1125         //            editor.setCancelListener(this);
1126         //            editor.setExitPolicy(new ExitPolicy(closingCharacter));
1127         //            editor.setFinalCaretOffset(offset + 2);
1128         //            editor.enter();
1129         //            IRegion newSelection = editor.getSelectedRegion();
1130         //            sourceViewer.setSelectedRange(newSelection.getOffset(),
1131         //                newSelection.getLength());
1132         //            event.doit = false;
1133         //          }
1134         //        }
1135       } catch (BadLocationException e) {
1136       }
1137     }
1138
1139     /*
1140      * @see org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionUI.ExitListener#exit(boolean)
1141      */
1142     public void exit(boolean accept) {
1143       if (accept)
1144         return;
1145       // remove brackets
1146       try {
1147         final ISourceViewer sourceViewer = getSourceViewer();
1148         IDocument document = sourceViewer.getDocument();
1149         document.replace(fOffset, fLength, null);
1150       } catch (BadLocationException e) {
1151       }
1152     }
1153   }
1154
1155   /** The editor's save policy */
1156   protected ISavePolicy fSavePolicy;
1157
1158   /**
1159    * Listener to annotation model changes that updates the error tick in the tab image
1160    */
1161   private JavaEditorErrorTickUpdater fJavaEditorErrorTickUpdater;
1162
1163   /** The editor's paint manager */
1164   //  private PaintManager fPaintManager;
1165   /** The editor's bracket painter */
1166   //  private BracketPainter fBracketPainter;
1167   /** The editor's bracket matcher */
1168   private PHPPairMatcher fBracketMatcher;
1169
1170   /** The editor's line painter */
1171   //  private LinePainter fLinePainter;
1172   /** The editor's print margin ruler painter */
1173   //  private PrintMarginPainter fPrintMarginPainter;
1174   /** The editor's problem painter */
1175   //  private ProblemPainter fProblemPainter;
1176   /** The editor's tab converter */
1177   private TabConverter fTabConverter;
1178
1179   /** History for structure select action */
1180   //private SelectionHistory fSelectionHistory;
1181   /** The preference property change listener for php core. */
1182   //  private IPropertyChangeListener fPropertyChangeListener = new
1183   // PropertyChangeListener();
1184   /** The remembered java element */
1185   private IJavaElement fRememberedElement;
1186
1187   /**
1188    * The remembered selection.
1189    * 
1190    * @since 3.0
1191    */
1192   private RememberedSelection fRememberedSelection = new RememberedSelection();
1193
1194   /** The remembered php element offset */
1195   private int fRememberedElementOffset;
1196
1197   /** The bracket inserter. */
1198   private BracketInserter fBracketInserter = new BracketInserter();
1199
1200   /** The standard action groups added to the menu */
1201   private GenerateActionGroup fGenerateActionGroup;
1202
1203   private CompositeActionGroup fContextMenuGroup;
1204
1205   //  private class PropertyChangeListener implements IPropertyChangeListener {
1206   //    /*
1207   //     * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
1208   //     */
1209   //    public void
1210   // propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent
1211   // event) {
1212   //      handlePreferencePropertyChanged(event);
1213   //    }
1214   //  }
1215   /* Preference key for code formatter tab size */
1216   private final static String CODE_FORMATTER_TAB_SIZE = JavaCore.FORMATTER_TAB_SIZE;
1217
1218   /** Preference key for matching brackets */
1219   //  private final static String MATCHING_BRACKETS = PreferenceConstants.EDITOR_MATCHING_BRACKETS;
1220   /** Preference key for matching brackets color */
1221   //  private final static String MATCHING_BRACKETS_COLOR = PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR;
1222   /** Preference key for highlighting current line */
1223   //  private final static String CURRENT_LINE = PreferenceConstants.EDITOR_CURRENT_LINE;
1224   /** Preference key for highlight color of current line */
1225   //  private final static String CURRENT_LINE_COLOR = PreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
1226   /** Preference key for showing print marging ruler */
1227   //  private final static String PRINT_MARGIN = PreferenceConstants.EDITOR_PRINT_MARGIN;
1228   /** Preference key for print margin ruler color */
1229   //  private final static String PRINT_MARGIN_COLOR = PreferenceConstants.EDITOR_PRINT_MARGIN_COLOR;
1230   /** Preference key for print margin ruler column */
1231   //  private final static String PRINT_MARGIN_COLUMN = PreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN;
1232   /** Preference key for inserting spaces rather than tabs */
1233   private final static String SPACES_FOR_TABS = PreferenceConstants.EDITOR_SPACES_FOR_TABS;
1234
1235   /** Preference key for error indication */
1236   //  private final static String ERROR_INDICATION =
1237   // PreferenceConstants.EDITOR_PROBLEM_INDICATION;
1238   /** Preference key for error color */
1239   //  private final static String ERROR_INDICATION_COLOR =
1240   // PreferenceConstants.EDITOR_PROBLEM_INDICATION_COLOR;
1241   /** Preference key for warning indication */
1242   //  private final static String WARNING_INDICATION =
1243   // PreferenceConstants.EDITOR_WARNING_INDICATION;
1244   /** Preference key for warning color */
1245   //  private final static String WARNING_INDICATION_COLOR =
1246   // PreferenceConstants.EDITOR_WARNING_INDICATION_COLOR;
1247   /** Preference key for task indication */
1248   private final static String TASK_INDICATION = PreferenceConstants.EDITOR_TASK_INDICATION;
1249
1250   /** Preference key for task color */
1251   private final static String TASK_INDICATION_COLOR = PreferenceConstants.EDITOR_TASK_INDICATION_COLOR;
1252
1253   /** Preference key for bookmark indication */
1254   private final static String BOOKMARK_INDICATION = PreferenceConstants.EDITOR_BOOKMARK_INDICATION;
1255
1256   /** Preference key for bookmark color */
1257   private final static String BOOKMARK_INDICATION_COLOR = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_COLOR;
1258
1259   /** Preference key for search result indication */
1260   private final static String SEARCH_RESULT_INDICATION = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION;
1261
1262   /** Preference key for search result color */
1263   private final static String SEARCH_RESULT_INDICATION_COLOR = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_COLOR;
1264
1265   /** Preference key for unknown annotation indication */
1266   private final static String UNKNOWN_INDICATION = PreferenceConstants.EDITOR_UNKNOWN_INDICATION;
1267
1268   /** Preference key for unknown annotation color */
1269   private final static String UNKNOWN_INDICATION_COLOR = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_COLOR;
1270
1271   /** Preference key for linked position color */
1272   private final static String LINKED_POSITION_COLOR = PreferenceConstants.EDITOR_LINKED_POSITION_COLOR;
1273
1274   /** Preference key for shwoing the overview ruler */
1275   private final static String OVERVIEW_RULER = PreferenceConstants.EDITOR_OVERVIEW_RULER;
1276
1277   /** Preference key for error indication in overview ruler */
1278   private final static String ERROR_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_ERROR_INDICATION_IN_OVERVIEW_RULER;
1279
1280   /** Preference key for warning indication in overview ruler */
1281   private final static String WARNING_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_WARNING_INDICATION_IN_OVERVIEW_RULER;
1282
1283   /** Preference key for task indication in overview ruler */
1284   private final static String TASK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_TASK_INDICATION_IN_OVERVIEW_RULER;
1285
1286   /** Preference key for bookmark indication in overview ruler */
1287   private final static String BOOKMARK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_IN_OVERVIEW_RULER;
1288
1289   /** Preference key for search result indication in overview ruler */
1290   private final static String SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER;
1291
1292   /** Preference key for unknown annotation indication in overview ruler */
1293   private final static String UNKNOWN_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_IN_OVERVIEW_RULER;
1294
1295   /** Preference key for automatically closing double quoted strings */
1296   private final static String CLOSE_STRINGS_DQ_PHP = PreferenceConstants.EDITOR_CLOSE_STRINGS_DQ_PHP;
1297
1298   /** Preference key for automatically closing single quoted strings */
1299   private final static String CLOSE_STRINGS_SQ_PHP = PreferenceConstants.EDITOR_CLOSE_STRINGS_SQ_PHP;
1300
1301   /** Preference key for automatically wrapping Java strings */
1302   //  private final static String WRAP_STRINGS = PreferenceConstants.EDITOR_WRAP_STRINGS_DQ;
1303   /** Preference key for automatically closing brackets and parenthesis */
1304   private final static String CLOSE_BRACKETS_PHP = PreferenceConstants.EDITOR_CLOSE_BRACKETS_PHP;
1305
1306   /** Preference key for automatically closing phpdocs and comments */
1307   private final static String CLOSE_JAVADOCS = PreferenceConstants.EDITOR_CLOSE_JAVADOCS;
1308
1309   /** Preference key for automatically adding phpdoc tags */
1310   private final static String ADD_JAVADOC_TAGS = PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS;
1311
1312   /** Preference key for automatically formatting phpdocs */
1313   //  private final static String FORMAT_JAVADOCS = PreferenceConstants.EDITOR_FORMAT_JAVADOCS;
1314   /** Preference key for automatically closing strings */
1315   private final static String CLOSE_STRINGS_HTML = PreferenceConstants.EDITOR_CLOSE_STRINGS_HTML;
1316
1317   /** Preference key for automatically closing brackets and parenthesis */
1318   private final static String CLOSE_BRACKETS_HTML = PreferenceConstants.EDITOR_CLOSE_BRACKETS_HTML;
1319
1320   /** Preference key for smart paste */
1321   private final static String SMART_PASTE = PreferenceConstants.EDITOR_SMART_PASTE;
1322
1323   //  private final static class AnnotationInfo {
1324   //    public String fColorPreference;
1325   //    public String fOverviewRulerPreference;
1326   //    public String fEditorPreference;
1327   //  };
1328   //  private final static Map ANNOTATION_MAP;
1329   //  static {
1330   //
1331   //    AnnotationInfo info;
1332   //    ANNOTATION_MAP = new HashMap();
1333   //
1334   //    info = new AnnotationInfo();
1335   //    info.fColorPreference = TASK_INDICATION_COLOR;
1336   //    info.fOverviewRulerPreference = TASK_INDICATION_IN_OVERVIEW_RULER;
1337   //    info.fEditorPreference = TASK_INDICATION;
1338   //    ANNOTATION_MAP.put(AnnotationType.TASK, info);
1339   //
1340   //    info = new AnnotationInfo();
1341   //    info.fColorPreference = ERROR_INDICATION_COLOR;
1342   //    info.fOverviewRulerPreference = ERROR_INDICATION_IN_OVERVIEW_RULER;
1343   //    info.fEditorPreference = ERROR_INDICATION;
1344   //    ANNOTATION_MAP.put(AnnotationType.ERROR, info);
1345   //
1346   //    info = new AnnotationInfo();
1347   //    info.fColorPreference = WARNING_INDICATION_COLOR;
1348   //    info.fOverviewRulerPreference = WARNING_INDICATION_IN_OVERVIEW_RULER;
1349   //    info.fEditorPreference = WARNING_INDICATION;
1350   //    ANNOTATION_MAP.put(AnnotationType.WARNING, info);
1351   //
1352   //    info = new AnnotationInfo();
1353   //    info.fColorPreference = BOOKMARK_INDICATION_COLOR;
1354   //    info.fOverviewRulerPreference = BOOKMARK_INDICATION_IN_OVERVIEW_RULER;
1355   //    info.fEditorPreference = BOOKMARK_INDICATION;
1356   //    ANNOTATION_MAP.put(AnnotationType.BOOKMARK, info);
1357   //
1358   //    info = new AnnotationInfo();
1359   //    info.fColorPreference = SEARCH_RESULT_INDICATION_COLOR;
1360   //    info.fOverviewRulerPreference =
1361   // SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER;
1362   //    info.fEditorPreference = SEARCH_RESULT_INDICATION;
1363   //    ANNOTATION_MAP.put(AnnotationType.SEARCH, info);
1364   //
1365   //    info = new AnnotationInfo();
1366   //    info.fColorPreference = UNKNOWN_INDICATION_COLOR;
1367   //    info.fOverviewRulerPreference = UNKNOWN_INDICATION_IN_OVERVIEW_RULER;
1368   //    info.fEditorPreference = UNKNOWN_INDICATION;
1369   //    ANNOTATION_MAP.put(AnnotationType.UNKNOWN, info);
1370   //  };
1371   //
1372   //  private final static AnnotationType[] ANNOTATION_LAYERS =
1373   //    new AnnotationType[] {
1374   //      AnnotationType.UNKNOWN,
1375   //      AnnotationType.BOOKMARK,
1376   //      AnnotationType.TASK,
1377   //      AnnotationType.SEARCH,
1378   //      AnnotationType.WARNING,
1379   //      AnnotationType.ERROR };
1380   /**
1381    * Creates a new php unit editor.
1382    */
1383
1384   /**
1385    * Reconciling listeners.
1386    * 
1387    * @since 3.0
1388    */
1389   private ListenerList fReconcilingListeners = new ListenerList();
1390
1391   /**
1392    * Mutex for the reconciler. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=63898 for a description of the problem.
1393    * <p>
1394    * TODO remove once the underlying problem is solved.
1395    * </p>
1396    */
1397   private final Object fReconcilerLock = new Object();
1398
1399   public PHPUnitEditor() {
1400     super();
1401     setDocumentProvider(PHPeclipsePlugin.getDefault().getCompilationUnitDocumentProvider());
1402     setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
1403     setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
1404     setOutlinerContextMenuId("#PHPOutlinerContext"); //$NON-NLS-1$
1405     // don't set help contextId, we install our own help context
1406     fSavePolicy = null;
1407     fJavaEditorErrorTickUpdater = new JavaEditorErrorTickUpdater(this);
1408   }
1409
1410   /*
1411    * @see AbstractTextEditor#createActions()
1412    */
1413   protected void createActions() {
1414     super.createActions();
1415     Action action;
1416     //          Action action= new
1417     // TextOperationAction(PHPEditorMessages.getResourceBundle(),
1418     // "CorrectionAssistProposal.", this, CORRECTIONASSIST_PROPOSALS);
1419     // //$NON-NLS-1$
1420     //          action.setActionDefinitionId(PHPEditorActionDefinitionIds.CORRECTION_ASSIST_PROPOSALS);
1421     //          setAction("CorrectionAssistProposal", action); //$NON-NLS-1$
1422     //          markAsStateDependentAction("CorrectionAssistProposal", true);
1423     // //$NON-NLS-1$
1424     //// WorkbenchHelp.setHelp(action,
1425     // IJavaHelpContextIds.QUICK_FIX_ACTION);
1426     action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$
1427     action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
1428     setAction("ContentAssistProposal", action); //$NON-NLS-1$
1429     markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
1430     //          WorkbenchHelp.setHelp(action,
1431     // IJavaHelpContextIds.CONTENT_ASSIST_ACTION);
1432     //          action = new TextOperationAction(PHPEditorMessages.getResourceBundle(),
1433     //                          "ContentAssistContextInformation.", this,
1434     //                          ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$
1435     //          action
1436     //                          .setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
1437     //          setAction("ContentAssistContextInformation", action); //$NON-NLS-1$
1438     //          markAsStateDependentAction("ContentAssistContextInformation", true);
1439     // //$NON-NLS-1$
1440     //          WorkbenchHelp.setHelp(action,
1441     // IJavaHelpContextIds.PARAMETER_HINTS_ACTION);
1442     //          action= new
1443     // TextOperationAction(PHPEditorMessages.getResourceBundle(),
1444     // "ContentAssistCompletePrefix.", this, CONTENTASSIST_COMPLETE_PREFIX);
1445     // //$NON-NLS-1$
1446     //          action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_COMPLETE_PREFIX);
1447     //          setAction("ContentAssistCompletePrefix", action); //$NON-NLS-1$
1448     //          markAsStateDependentAction("ContentAssistCompletePrefix", true);
1449     // //$NON-NLS-1$
1450     //// WorkbenchHelp.setHelp(action,
1451     // IJavaHelpContextIds.PARAMETER_HINTS_ACTION);
1452     action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX); //$NON-NLS-1$
1453     action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
1454     setAction("Comment", action); //$NON-NLS-1$
1455     markAsStateDependentAction("Comment", true); //$NON-NLS-1$
1456     //          WorkbenchHelp.setHelp(action, IJavaHelpContextIds.COMMENT_ACTION);
1457     action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX); //$NON-NLS-1$
1458     action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
1459     setAction("Uncomment", action); //$NON-NLS-1$
1460     markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
1461     //          WorkbenchHelp.setHelp(action, IJavaHelpContextIds.UNCOMMENT_ACTION);
1462
1463     action = new ToggleCommentAction(PHPEditorMessages.getResourceBundle(), "ToggleComment.", this); //$NON-NLS-1$
1464     action.setActionDefinitionId(PHPEditorActionDefinitionIds.TOGGLE_COMMENT);
1465     setAction("ToggleComment", action); //$NON-NLS-1$
1466     markAsStateDependentAction("ToggleComment", true); //$NON-NLS-1$
1467     //WorkbenchHelp.setHelp(action,
1468     // IJavaHelpContextIds.TOGGLE_COMMENT_ACTION);
1469     configureToggleCommentAction();
1470
1471     action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
1472     action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT);
1473     setAction("Format", action); //$NON-NLS-1$
1474     markAsStateDependentAction("Format", true); //$NON-NLS-1$
1475     markAsSelectionDependentAction("Format", true); //$NON-NLS-1$               
1476     //          WorkbenchHelp.setHelp(action, IJavaHelpContextIds.FORMAT_ACTION);
1477
1478     //    action = new AddBlockCommentAction(PHPEditorMessages.getResourceBundle(),
1479     //        "AddBlockComment.", this); //$NON-NLS-1$
1480     //    action
1481     //        .setActionDefinitionId(PHPEditorActionDefinitionIds.ADD_BLOCK_COMMENT);
1482     //    setAction("AddBlockComment", action); //$NON-NLS-1$
1483     //    markAsStateDependentAction("AddBlockComment", true); //$NON-NLS-1$
1484     //    markAsSelectionDependentAction("AddBlockComment", true); //$NON-NLS-1$
1485     //    // WorkbenchHelp.setHelp(action,
1486     //    // IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
1487     //    action = new RemoveBlockCommentAction(
1488     //        PHPEditorMessages.getResourceBundle(), "RemoveBlockComment.", this); //$NON-NLS-1$
1489     //    action
1490     //        .setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_BLOCK_COMMENT);
1491     //    setAction("RemoveBlockComment", action); //$NON-NLS-1$
1492     //    markAsStateDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1493     //    markAsSelectionDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1494     //          WorkbenchHelp.setHelp(action,
1495     // IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
1496     //          action= new IndentAction(PHPEditorMessages.getResourceBundle(),
1497     // "Indent.", this, false); //$NON-NLS-1$
1498     //          action.setActionDefinitionId(PHPEditorActionDefinitionIds.INDENT);
1499     //          setAction("Indent", action); //$NON-NLS-1$
1500     //          markAsStateDependentAction("Indent", true); //$NON-NLS-1$
1501     //          markAsSelectionDependentAction("Indent", true); //$NON-NLS-1$
1502     //// WorkbenchHelp.setHelp(action, IJavaHelpContextIds.INDENT_ACTION);
1503     //          
1504     //          action= new IndentAction(PHPEditorMessages.getResourceBundle(),
1505     // "Indent.", this, true); //$NON-NLS-1$
1506     //          setAction("IndentOnTab", action); //$NON-NLS-1$
1507     //          markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$
1508     //          markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$
1509     //          
1510
1511     action = new AddBlockCommentAction(PHPEditorMessages.getResourceBundle(), "AddBlockComment.", this); //$NON-NLS-1$
1512     action.setActionDefinitionId(PHPEditorActionDefinitionIds.ADD_BLOCK_COMMENT);
1513     setAction("AddBlockComment", action); //$NON-NLS-1$
1514     markAsStateDependentAction("AddBlockComment", true); //$NON-NLS-1$
1515     markAsSelectionDependentAction("AddBlockComment", true); //$NON-NLS-1$              
1516     //  WorkbenchHelp.setHelp(action, IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
1517
1518     action = new RemoveBlockCommentAction(PHPEditorMessages.getResourceBundle(), "RemoveBlockComment.", this); //$NON-NLS-1$
1519     action.setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_BLOCK_COMMENT);
1520     setAction("RemoveBlockComment", action); //$NON-NLS-1$
1521     markAsStateDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1522     markAsSelectionDependentAction("RemoveBlockComment", true); //$NON-NLS-1$           
1523     //  WorkbenchHelp.setHelp(action, IJavaHelpContextIds.REMOVE_BLOCK_COMMENT_ACTION);
1524
1525     //  action= new IndentAction(PHPEditorMessages.getResourceBundle(), "Indent.", this, false); //$NON-NLS-1$
1526     //  action.setActionDefinitionId(PHPEditorActionDefinitionIds.INDENT);
1527     //  setAction("Indent", action); //$NON-NLS-1$
1528     //  markAsStateDependentAction("Indent", true); //$NON-NLS-1$
1529     //  markAsSelectionDependentAction("Indent", true); //$NON-NLS-1$
1530     //// WorkbenchHelp.setHelp(action, IJavaHelpContextIds.INDENT_ACTION);
1531     //  
1532     action = new IndentAction(PHPEditorMessages.getResourceBundle(), "Indent.", this, true); //$NON-NLS-1$
1533     setAction("IndentOnTab", action); //$NON-NLS-1$
1534     markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$
1535     markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$
1536
1537     if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SMART_TAB)) {
1538       // don't replace Shift Right - have to make sure their enablement is
1539       // mutually exclusive
1540       //                        removeActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT);
1541       setActionActivationCode("IndentOnTab", '\t', -1, SWT.NONE); //$NON-NLS-1$
1542     }
1543     fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
1544     //    ActionGroup rg= new RefactorActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
1545
1546     //  fActionGroups.addGroup(rg);
1547     fActionGroups.addGroup(fGenerateActionGroup);
1548
1549     // We have to keep the context menu group separate to have better control over positioning
1550     fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup
1551     //          rg,
1552         //              new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)
1553         });
1554
1555   }
1556
1557   /*
1558    * @see JavaEditor#getElementAt(int)
1559    */
1560   protected IJavaElement getElementAt(int offset) {
1561     return getElementAt(offset, true);
1562   }
1563
1564   /**
1565    * Returns the most narrow element including the given offset. If <code>reconcile</code> is <code>true</code> the editor's
1566    * input element is reconciled in advance. If it is <code>false</code> this method only returns a result if the editor's input
1567    * element does not need to be reconciled.
1568    * 
1569    * @param offset
1570    *          the offset included by the retrieved element
1571    * @param reconcile
1572    *          <code>true</code> if working copy should be reconciled
1573    */
1574   protected IJavaElement getElementAt(int offset, boolean reconcile) {
1575     IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
1576     ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
1577     if (unit != null) {
1578       try {
1579         if (reconcile) {
1580           synchronized (unit) {
1581             unit.reconcile();
1582           }
1583           return unit.getElementAt(offset);
1584         } else if (unit.isConsistent())
1585           return unit.getElementAt(offset);
1586       } catch (JavaModelException x) {
1587         PHPeclipsePlugin.log(x.getStatus());
1588         // nothing found, be tolerant and go on
1589       }
1590     }
1591     return null;
1592   }
1593
1594   /*
1595    * @see JavaEditor#getCorrespondingElement(IJavaElement)
1596    */
1597   protected IJavaElement getCorrespondingElement(IJavaElement element) {
1598     try {
1599       return EditorUtility.getWorkingCopy(element, true);
1600     } catch (JavaModelException x) {
1601       PHPeclipsePlugin.log(x.getStatus());
1602       // nothing found, be tolerant and go on
1603     }
1604     return null;
1605   }
1606
1607   public void createPartControl(Composite parent) {
1608     super.createPartControl(parent);
1609     //    fPaintManager = new PaintManager(getSourceViewer());
1610     LinePainter linePainter;
1611     linePainter = new LinePainter(getSourceViewer());
1612     linePainter.setHighlightColor(new Color(Display.getCurrent(), 225, 235, 224));
1613     //    fPaintManager.addPainter(linePainter);
1614     //    if (isBracketHighlightingEnabled())
1615     //      startBracketHighlighting();
1616     //    if (isLineHighlightingEnabled())
1617     //      startLineHighlighting();
1618     //    if (isPrintMarginVisible())
1619     //      showPrintMargin();
1620     //    Iterator e = ANNOTATION_MAP.keySet().iterator();
1621     //    while (e.hasNext()) {
1622     //      AnnotationType type = (AnnotationType) e.next();
1623     //      if (isAnnotationIndicationEnabled(type))
1624     //        startAnnotationIndication(type);
1625     //    }
1626     if (isTabConversionEnabled())
1627       startTabConversion();
1628     //    if (isOverviewRulerVisible())
1629     //      showOverviewRuler();
1630     //
1631     //    Preferences preferences =
1632     // PHPeclipsePlugin.getDefault().getPluginPreferences();
1633     //    preferences.addPropertyChangeListener(fPropertyChangeListener);
1634     IPreferenceStore preferenceStore = getPreferenceStore();
1635     boolean closeBracketsPHP = preferenceStore.getBoolean(CLOSE_BRACKETS_PHP);
1636     boolean closeStringsPHPDQ = preferenceStore.getBoolean(CLOSE_STRINGS_DQ_PHP);
1637     boolean closeStringsPHPSQ = preferenceStore.getBoolean(CLOSE_STRINGS_SQ_PHP);
1638     boolean closeBracketsHTML = preferenceStore.getBoolean(CLOSE_BRACKETS_HTML);
1639     boolean closeStringsHTML = preferenceStore.getBoolean(CLOSE_STRINGS_HTML);
1640     fBracketInserter.setCloseBracketsPHPEnabled(closeBracketsPHP);
1641     fBracketInserter.setCloseStringsPHPDQEnabled(closeStringsPHPDQ);
1642     fBracketInserter.setCloseStringsPHPSQEnabled(closeStringsPHPSQ);
1643     fBracketInserter.setCloseBracketsHTMLEnabled(closeBracketsHTML);
1644     fBracketInserter.setCloseStringsHTMLEnabled(closeStringsHTML);
1645     ISourceViewer sourceViewer = getSourceViewer();
1646     if (sourceViewer instanceof ITextViewerExtension)
1647       ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter);
1648   }
1649
1650   private static char getPeerCharacter(char character) {
1651     switch (character) {
1652     case '(':
1653       return ')';
1654     case ')':
1655       return '(';
1656     case '[':
1657       return ']';
1658     case ']':
1659       return '[';
1660     case '"':
1661       return character;
1662     case '\'':
1663       return character;
1664     default:
1665       throw new IllegalArgumentException();
1666     }
1667   }
1668
1669   //  private void startBracketHighlighting() {
1670   //    if (fBracketPainter == null) {
1671   //      ISourceViewer sourceViewer = getSourceViewer();
1672   //      fBracketPainter = new BracketPainter(sourceViewer);
1673   //      fBracketPainter.setHighlightColor(getColor(MATCHING_BRACKETS_COLOR));
1674   //      // fPaintManager.addPainter(fBracketPainter);
1675   //    }
1676   //  }
1677   //
1678   //  private void stopBracketHighlighting() {
1679   //    if (fBracketPainter != null) {
1680   //      // fPaintManager.removePainter(fBracketPainter);
1681   //      fBracketPainter.deactivate(true);
1682   //      fBracketPainter.dispose();
1683   //      fBracketPainter = null;
1684   //    }
1685   //  }
1686
1687   //  private boolean isBracketHighlightingEnabled() {
1688   //    IPreferenceStore store = getPreferenceStore();
1689   //    return store.getBoolean(MATCHING_BRACKETS);
1690   //  }
1691
1692   //  private void startLineHighlighting() {
1693   //    if (fLinePainter == null) {
1694   //      ISourceViewer sourceViewer = getSourceViewer();
1695   //      fLinePainter = new LinePainter(sourceViewer);
1696   //      fLinePainter.setHighlightColor(getColor(CURRENT_LINE_COLOR));
1697   //      // fPaintManager.addPainter(fLinePainter);
1698   //    }
1699   //  }
1700
1701   //  private void stopLineHighlighting() {
1702   //    if (fLinePainter != null) {
1703   //      // fPaintManager.removePainter(fLinePainter);
1704   //      fLinePainter.deactivate(true);
1705   //      fLinePainter.dispose();
1706   //      fLinePainter = null;
1707   //    }
1708   //  }
1709
1710   //  private boolean isLineHighlightingEnabled() {
1711   //    IPreferenceStore store = getPreferenceStore();
1712   //    return store.getBoolean(CURRENT_LINE);
1713   //  }
1714
1715   //  private void showPrintMargin() {
1716   //    if (fPrintMarginPainter == null) {
1717   //      fPrintMarginPainter = new PrintMarginPainter(getSourceViewer());
1718   //      fPrintMarginPainter.setMarginRulerColor(getColor(PRINT_MARGIN_COLOR));
1719   //      fPrintMarginPainter.setMarginRulerColumn(getPreferenceStore().getInt(PRINT_MARGIN_COLUMN));
1720   //      // fPaintManager.addPainter(fPrintMarginPainter);
1721   //    }
1722   //  }
1723
1724   //  private void hidePrintMargin() {
1725   //    if (fPrintMarginPainter != null) {
1726   //      // fPaintManager.removePainter(fPrintMarginPainter);
1727   //      fPrintMarginPainter.deactivate(true);
1728   //      fPrintMarginPainter.dispose();
1729   //      fPrintMarginPainter = null;
1730   //    }
1731   //  }
1732
1733   //  private boolean isPrintMarginVisible() {
1734   //    IPreferenceStore store = getPreferenceStore();
1735   //    return store.getBoolean(PRINT_MARGIN);
1736   //  }
1737
1738   private int getTabSize() {
1739     Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
1740     return preferences.getInt(CODE_FORMATTER_TAB_SIZE);
1741   }
1742
1743   private boolean isTabConversionEnabled() {
1744     IPreferenceStore store = getPreferenceStore();
1745     return store.getBoolean(SPACES_FOR_TABS);
1746   }
1747
1748   private Color getColor(String key) {
1749     RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), key);
1750     return getColor(rgb);
1751   }
1752
1753   private Color getColor(RGB rgb) {
1754     JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
1755     return textTools.getColorManager().getColor(rgb);
1756   }
1757
1758   //  private Color getColor(AnnotationType annotationType) {
1759   //    AnnotationInfo info = (AnnotationInfo)
1760   // ANNOTATION_MAP.get(annotationType);
1761   //    if (info != null)
1762   //      return getColor(info.fColorPreference);
1763   //    return null;
1764   //  }
1765   public void dispose() {
1766     ISourceViewer sourceViewer = getSourceViewer();
1767     if (sourceViewer instanceof ITextViewerExtension)
1768       ((ITextViewerExtension) sourceViewer).removeVerifyKeyListener(fBracketInserter);
1769     //    if (fPropertyChangeListener != null) {
1770     //      Preferences preferences =
1771     // PHPeclipsePlugin.getDefault().getPluginPreferences();
1772     //      preferences.removePropertyChangeListener(fPropertyChangeListener);
1773     //      fPropertyChangeListener = null;
1774     //    }
1775     if (fJavaEditorErrorTickUpdater != null) {
1776       fJavaEditorErrorTickUpdater.dispose();
1777       fJavaEditorErrorTickUpdater = null;
1778     }
1779     //    if (fSelectionHistory != null)
1780     //      fSelectionHistory.dispose();
1781     //    if (fPaintManager != null) {
1782     //      fPaintManager.dispose();
1783     //      fPaintManager = null;
1784     //    }
1785     if (fActionGroups != null) {
1786       fActionGroups.dispose();
1787       fActionGroups = null;
1788     }
1789     super.dispose();
1790   }
1791
1792   //  protected AnnotationType getAnnotationType(String preferenceKey) {
1793   //    Iterator e = ANNOTATION_MAP.keySet().iterator();
1794   //    while (e.hasNext()) {
1795   //      AnnotationType type = (AnnotationType) e.next();
1796   //      AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(type);
1797   //      if (info != null) {
1798   //        if (preferenceKey.equals(info.fColorPreference)
1799   //          || preferenceKey.equals(info.fEditorPreference)
1800   //          || preferenceKey.equals(info.fOverviewRulerPreference))
1801   //          return type;
1802   //      }
1803   //    }
1804   //    return null;
1805   //  }
1806   /*
1807    * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
1808    */
1809   protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
1810     try {
1811       AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1812       if (asv != null) {
1813         String p = event.getProperty();
1814         if (CLOSE_BRACKETS_PHP.equals(p)) {
1815           fBracketInserter.setCloseBracketsPHPEnabled(getPreferenceStore().getBoolean(p));
1816           return;
1817         }
1818         if (CLOSE_STRINGS_DQ_PHP.equals(p)) {
1819           fBracketInserter.setCloseStringsPHPDQEnabled(getPreferenceStore().getBoolean(p));
1820           return;
1821         }
1822         if (CLOSE_STRINGS_SQ_PHP.equals(p)) {
1823           fBracketInserter.setCloseStringsPHPSQEnabled(getPreferenceStore().getBoolean(p));
1824           return;
1825         }
1826         if (CLOSE_BRACKETS_HTML.equals(p)) {
1827           fBracketInserter.setCloseBracketsHTMLEnabled(getPreferenceStore().getBoolean(p));
1828           return;
1829         }
1830         if (CLOSE_STRINGS_HTML.equals(p)) {
1831           fBracketInserter.setCloseStringsHTMLEnabled(getPreferenceStore().getBoolean(p));
1832           return;
1833         }
1834         if (SPACES_FOR_TABS.equals(p)) {
1835           if (isTabConversionEnabled())
1836             startTabConversion();
1837           else
1838             stopTabConversion();
1839           return;
1840         }
1841         //        if (MATCHING_BRACKETS.equals(p)) {
1842         //          if (isBracketHighlightingEnabled())
1843         //            startBracketHighlighting();
1844         //          else
1845         //            stopBracketHighlighting();
1846         //          return;
1847         //        }
1848         //        if (MATCHING_BRACKETS_COLOR.equals(p)) {
1849         //          if (fBracketPainter != null)
1850         //            fBracketPainter.setHighlightColor(getColor(MATCHING_BRACKETS_COLOR));
1851         //          return;
1852         //        }
1853         //        if (CURRENT_LINE.equals(p)) {
1854         //          if (isLineHighlightingEnabled())
1855         //            startLineHighlighting();
1856         //          else
1857         //            stopLineHighlighting();
1858         //          return;
1859         //        }
1860         //        if (CURRENT_LINE_COLOR.equals(p)) {
1861         //          if (fLinePainter != null) {
1862         //            stopLineHighlighting();
1863         //            startLineHighlighting();
1864         //          }
1865         //          return;
1866         //        }
1867         //        if (PRINT_MARGIN.equals(p)) {
1868         //          if (isPrintMarginVisible())
1869         //            showPrintMargin();
1870         //          else
1871         //            hidePrintMargin();
1872         //          return;
1873         //        }
1874         //        if (PRINT_MARGIN_COLOR.equals(p)) {
1875         //          if (fPrintMarginPainter != null)
1876         //            fPrintMarginPainter.setMarginRulerColor(getColor(PRINT_MARGIN_COLOR));
1877         //          return;
1878         //        }
1879         //        if (PRINT_MARGIN_COLUMN.equals(p)) {
1880         //          if (fPrintMarginPainter != null)
1881         //            fPrintMarginPainter.setMarginRulerColumn(getPreferenceStore().getInt(PRINT_MARGIN_COLUMN));
1882         //          return;
1883         //        }
1884         //        if (OVERVIEW_RULER.equals(p)) {
1885         //          if (isOverviewRulerVisible())
1886         //            showOverviewRuler();
1887         //          else
1888         //            hideOverviewRuler();
1889         //          return;
1890         //        }
1891         //        AnnotationType type = getAnnotationType(p);
1892         //        if (type != null) {
1893         //
1894         //          AnnotationInfo info = (AnnotationInfo)
1895         // ANNOTATION_MAP.get(type);
1896         //          if (info.fColorPreference.equals(p)) {
1897         //            Color color = getColor(type);
1898         //            if (fProblemPainter != null) {
1899         //              fProblemPainter.setColor(type, color);
1900         //              fProblemPainter.paint(IPainter.CONFIGURATION);
1901         //            }
1902         //            setColorInOverviewRuler(type, color);
1903         //            return;
1904         //          }
1905         //
1906         //          if (info.fEditorPreference.equals(p)) {
1907         //            if (isAnnotationIndicationEnabled(type))
1908         //              startAnnotationIndication(type);
1909         //            else
1910         //              stopAnnotationIndication(type);
1911         //            return;
1912         //          }
1913         //
1914         //          if (info.fOverviewRulerPreference.equals(p)) {
1915         //            if (isAnnotationIndicationInOverviewRulerEnabled(type))
1916         //              showAnnotationIndicationInOverviewRuler(type, true);
1917         //            else
1918         //              showAnnotationIndicationInOverviewRuler(type, false);
1919         //            return;
1920         //          }
1921         //        }
1922         IContentAssistant c = asv.getContentAssistant();
1923         if (c instanceof ContentAssistant)
1924           ContentAssistPreference.changeConfiguration((ContentAssistant) c, getPreferenceStore(), event);
1925       }
1926     } finally {
1927       super.handlePreferenceStoreChanged(event);
1928     }
1929   }
1930
1931   /*
1932    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent)
1933    */
1934   protected void handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) {
1935     AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1936     if (asv != null) {
1937       String p = event.getProperty();
1938       if (CODE_FORMATTER_TAB_SIZE.equals(p)) {
1939         asv.updateIndentationPrefixes();
1940         if (fTabConverter != null)
1941           fTabConverter.setNumberOfSpacesPerTab(getTabSize());
1942       }
1943     }
1944     super.handlePreferencePropertyChanged(event);
1945   }
1946
1947   /**
1948    * Handles a property change event describing a change of the php core's preferences and updates the preference related editor
1949    * properties.
1950    * 
1951    * @param event
1952    *          the property change event
1953    */
1954   //  protected void
1955   // handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent
1956   // event) {
1957   //    AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1958   //    if (asv != null) {
1959   //      String p = event.getProperty();
1960   //      if (CODE_FORMATTER_TAB_SIZE.equals(p)) {
1961   //        asv.updateIndentationPrefixes();
1962   //        if (fTabConverter != null)
1963   //          fTabConverter.setNumberOfSpacesPerTab(getTabSize());
1964   //      }
1965   //    }
1966   //  }
1967   /*
1968    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#createJavaSourceViewer(org.eclipse.swt.widgets.Composite,
1969    *      org.eclipse.jface.text.source.IVerticalRuler, org.eclipse.jface.text.source.IOverviewRuler, boolean, int)
1970    */
1971   protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler,
1972       boolean isOverviewRulerVisible, int styles, IPreferenceStore store) {
1973     return new AdaptedSourceViewer(parent, verticalRuler, overviewRuler, isOverviewRulerVisible, styles, store);
1974   }
1975
1976   //  protected ISourceViewer createJavaSourceViewer(Composite parent,
1977   // IVerticalRuler ruler, int styles) {
1978   //    return new AdaptedSourceViewer(parent, ruler, styles);
1979   //  }
1980   private boolean isValidSelection(int offset, int length) {
1981     IDocumentProvider provider = getDocumentProvider();
1982     if (provider != null) {
1983       IDocument document = provider.getDocument(getEditorInput());
1984       if (document != null) {
1985         int end = offset + length;
1986         int documentLength = document.getLength();
1987         return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength;
1988       }
1989     }
1990     return false;
1991   }
1992
1993   /*
1994    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#getInputElement()
1995    */
1996   protected IJavaElement getInputJavaElement() {
1997     return PHPeclipsePlugin.getDefault().getWorkingCopyManager().getWorkingCopy(getEditorInput());
1998   }
1999
2000   /*
2001    * @see AbstractTextEditor#editorContextMenuAboutToShow(IMenuManager)
2002    */
2003   public void editorContextMenuAboutToShow(IMenuManager menu) {
2004     super.editorContextMenuAboutToShow(menu);
2005     ActionContext context = new ActionContext(getSelectionProvider().getSelection());
2006     fContextMenuGroup.setContext(context);
2007     fContextMenuGroup.fillContextMenu(menu);
2008     fContextMenuGroup.setContext(null);
2009   }
2010
2011   /*
2012    * @see JavaEditor#setOutlinePageInput(JavaOutlinePage, IEditorInput)
2013    */
2014   protected void setOutlinePageInput(JavaOutlinePage page, IEditorInput input) {
2015     if (page != null) {
2016       IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
2017       page.setInput(manager.getWorkingCopy(input));
2018     }
2019   }
2020
2021   /*
2022    * @see AbstractTextEditor#performSaveOperation(WorkspaceModifyOperation, IProgressMonitor)
2023    */
2024   //  protected void performSaveOperation(WorkspaceModifyOperation operation,
2025   // IProgressMonitor progressMonitor) {
2026   //    IDocumentProvider p = getDocumentProvider();
2027   //    if (p instanceof PHPDocumentProvider) {
2028   //      PHPDocumentProvider cp = (PHPDocumentProvider) p;
2029   //      cp.setSavePolicy(fSavePolicy);
2030   //    }
2031   //
2032   //    try {
2033   //      super.performSaveOperation(operation, progressMonitor);
2034   //    } finally {
2035   //      if (p instanceof PHPDocumentProvider) {
2036   //        PHPDocumentProvider cp = (PHPDocumentProvider) p;
2037   //        cp.setSavePolicy(null);
2038   //      }
2039   //    }
2040   //  }
2041   /*
2042    * @see AbstractTextEditor#doSave(IProgressMonitor)
2043    */
2044   public void doSave(IProgressMonitor progressMonitor) {
2045
2046     IDocumentProvider p = getDocumentProvider();
2047     if (p == null) {
2048       // editor has been closed
2049       return;
2050     }
2051
2052     if (p.isDeleted(getEditorInput())) {
2053
2054       if (isSaveAsAllowed()) {
2055
2056         /*
2057          * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors. Changed Behavior to make sure that if called
2058          * inside a regular save (because of deletion of input element) there is a way to report back to the caller.
2059          */
2060         performSaveAs(progressMonitor);
2061
2062       } else {
2063
2064         /*
2065          * 1GF5YOX: ITPJUI:ALL - Save of delete file claims it's still there Missing resources.
2066          */
2067         Shell shell = getSite().getShell();
2068         MessageDialog
2069             .openError(
2070                 shell,
2071                 PHPEditorMessages.getString("PHPUnitEditor.error.saving.title1"), PHPEditorMessages.getString("PHPUnitEditor.error.saving.message1")); //$NON-NLS-1$ //$NON-NLS-2$
2072       }
2073
2074     } else {
2075       if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_P_RTRIM_ON_SAVE)) {
2076         RTrimAction trimAction = new RTrimAction();
2077         trimAction.setActiveEditor(null, getSite().getPage().getActiveEditor());
2078         trimAction.run(null);  
2079       }
2080
2081       setStatusLineErrorMessage(null);
2082
2083       updateState(getEditorInput());
2084       validateState(getEditorInput());
2085
2086       IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
2087       ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
2088
2089       if (unit != null) {
2090         synchronized (unit) {
2091           performSave(false, progressMonitor);
2092         }
2093       } else
2094         performSave(false, progressMonitor);
2095     }
2096   }
2097
2098   public boolean isSaveAsAllowed() {
2099     return true;
2100   }
2101
2102   /**
2103    * The compilation unit editor implementation of this <code>AbstractTextEditor</code> method asks the user for the workspace
2104    * path of a file resource and saves the document there. See http://dev.eclipse.org/bugs/show_bug.cgi?id=6295
2105    * 
2106    * @param progressMonitor
2107    *          the progress monitor
2108    */
2109   protected void performSaveAs(IProgressMonitor progressMonitor) {
2110
2111     Shell shell = getSite().getShell();
2112     IEditorInput input = getEditorInput();
2113
2114     SaveAsDialog dialog = new SaveAsDialog(shell);
2115
2116     IFile original = (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null;
2117     if (original != null)
2118       dialog.setOriginalFile(original);
2119
2120     dialog.create();
2121
2122     IDocumentProvider provider = getDocumentProvider();
2123     if (provider == null) {
2124       // editor has been programmatically closed while the dialog was open
2125       return;
2126     }
2127
2128     if (provider.isDeleted(input) && original != null) {
2129       String message = PHPEditorMessages.getFormattedString(
2130           "CompilationUnitEditor.warning.save.delete", new Object[] { original.getName() }); //$NON-NLS-1$
2131       dialog.setErrorMessage(null);
2132       dialog.setMessage(message, IMessageProvider.WARNING);
2133     }
2134
2135     if (dialog.open() == Window.CANCEL) {
2136       if (progressMonitor != null)
2137         progressMonitor.setCanceled(true);
2138       return;
2139     }
2140
2141     IPath filePath = dialog.getResult();
2142     if (filePath == null) {
2143       if (progressMonitor != null)
2144         progressMonitor.setCanceled(true);
2145       return;
2146     }
2147
2148     IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
2149     IFile file = workspaceRoot.getFile(filePath);
2150     final IEditorInput newInput = new FileEditorInput(file);
2151
2152     boolean success = false;
2153     try {
2154
2155       provider.aboutToChange(newInput);
2156       getDocumentProvider().saveDocument(progressMonitor, newInput, getDocumentProvider().getDocument(getEditorInput()), true);
2157       success = true;
2158
2159     } catch (CoreException x) {
2160       IStatus status = x.getStatus();
2161       if (status == null || status.getSeverity() != IStatus.CANCEL)
2162         ErrorDialog
2163             .openError(
2164                 shell,
2165                 PHPEditorMessages.getString("CompilationUnitEditor.error.saving.title2"), PHPEditorMessages.getString("CompilationUnitEditor.error.saving.message2"), x.getStatus()); //$NON-NLS-1$ //$NON-NLS-2$
2166     } finally {
2167       provider.changed(newInput);
2168       if (success)
2169         setInput(newInput);
2170     }
2171
2172     if (progressMonitor != null)
2173       progressMonitor.setCanceled(!success);
2174   }
2175
2176   /*
2177    * @see AbstractTextEditor#doSetInput(IEditorInput)
2178    */
2179   protected void doSetInput(IEditorInput input) throws CoreException {
2180     super.doSetInput(input);
2181     configureTabConverter();
2182     configureToggleCommentAction();
2183   }
2184
2185   //    /*
2186   //     * @see
2187   // net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#installOverrideIndicator(boolean)
2188   //     * @since 3.0
2189   //     */
2190   //    protected void installOverrideIndicator(boolean waitForReconcilation) {
2191   //            IAnnotationModel model=
2192   // getDocumentProvider().getAnnotationModel(getEditorInput());
2193   //            if (!waitForReconcilation)
2194   //                    super.installOverrideIndicator(false);
2195   //            else {
2196   //                    uninstallOverrideIndicator();
2197   //                    IJavaElement inputElement= getInputJavaElement();
2198   //                    if (model == null || inputElement == null)
2199   //                            return;
2200   //                    
2201   //                    fOverrideIndicatorManager= new OverrideIndicatorManager(model,
2202   // inputElement, null);
2203   //                    addReconcileListener(fOverrideIndicatorManager);
2204   //            }
2205   //    }
2206   //    
2207   //    /*
2208   //     * @see
2209   // net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#uninstallOverrideIndicator()
2210   //     * @since 3.0
2211   //     */
2212   //    protected void uninstallOverrideIndicator() {
2213   //            if (fOverrideIndicatorManager != null)
2214   //                    removeReconcileListener(fOverrideIndicatorManager);
2215   //            super.uninstallOverrideIndicator();
2216   //    }
2217
2218   /**
2219    * Configures the toggle comment action
2220    * 
2221    * @since 3.0
2222    */
2223   private void configureToggleCommentAction() {
2224     IAction action = getAction("ToggleComment"); //$NON-NLS-1$
2225     if (action instanceof ToggleCommentAction) {
2226       ISourceViewer sourceViewer = getSourceViewer();
2227       SourceViewerConfiguration configuration = getSourceViewerConfiguration();
2228       ((ToggleCommentAction) action).configure(sourceViewer, configuration);
2229     }
2230   }
2231
2232   //  private void configureTabConverter() {
2233   //    if (fTabConverter != null) {
2234   //      IDocumentProvider provider = getDocumentProvider();
2235   //      if (provider instanceof PHPDocumentProvider) {
2236   //        PHPDocumentProvider cup = (PHPDocumentProvider) provider;
2237   //        fTabConverter.setLineTracker(cup.createLineTracker(getEditorInput()));
2238   //      }
2239   //    }
2240   //  }
2241   private void configureTabConverter() {
2242     if (fTabConverter != null) {
2243       IDocumentProvider provider = getDocumentProvider();
2244       if (provider instanceof ICompilationUnitDocumentProvider) {
2245         ICompilationUnitDocumentProvider cup = (ICompilationUnitDocumentProvider) provider;
2246         fTabConverter.setLineTracker(cup.createLineTracker(getEditorInput()));
2247       }
2248     }
2249   }
2250
2251   private void startTabConversion() {
2252     if (fTabConverter == null) {
2253       fTabConverter = new TabConverter();
2254       configureTabConverter();
2255       fTabConverter.setNumberOfSpacesPerTab(getTabSize());
2256       AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
2257       asv.addTextConverter(fTabConverter);
2258       // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
2259       asv.updateIndentationPrefixes();
2260     }
2261   }
2262
2263   private void stopTabConversion() {
2264     if (fTabConverter != null) {
2265       AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
2266       asv.removeTextConverter(fTabConverter);
2267       // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
2268       asv.updateIndentationPrefixes();
2269       fTabConverter = null;
2270     }
2271   }
2272
2273   /*
2274    * @see org.eclipse.ui.texteditor.AbstractTextEditor#performSave(boolean, org.eclipse.core.runtime.IProgressMonitor)
2275    */
2276   protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) {
2277     //    IDocumentProvider p = getDocumentProvider();
2278     //    if (p instanceof PHPDocumentProvider) {
2279     //      PHPDocumentProvider cp = (PHPDocumentProvider) p;
2280     //      cp.setSavePolicy(fSavePolicy);
2281     //    }
2282     //    try {
2283     //      super.performSave(overwrite, progressMonitor);
2284     //    } finally {
2285     //      if (p instanceof PHPDocumentProvider) {
2286     //        PHPDocumentProvider cp = (PHPDocumentProvider) p;
2287     //        cp.setSavePolicy(null);
2288     //      }
2289     //    }
2290
2291     IDocumentProvider p = getDocumentProvider();
2292     if (p instanceof ICompilationUnitDocumentProvider) {
2293       ICompilationUnitDocumentProvider cp = (ICompilationUnitDocumentProvider) p;
2294       cp.setSavePolicy(fSavePolicy);
2295     }
2296     try {
2297       super.performSave(overwrite, progressMonitor);
2298     } finally {
2299       if (p instanceof ICompilationUnitDocumentProvider) {
2300         ICompilationUnitDocumentProvider cp = (ICompilationUnitDocumentProvider) p;
2301         cp.setSavePolicy(null);
2302       }
2303     }
2304   }
2305
2306   /*
2307    * @see AbstractTextEditor#doSaveAs
2308    */
2309   public void doSaveAs() {
2310     if (askIfNonWorkbenchEncodingIsOk()) {
2311       super.doSaveAs();
2312     }
2313   }
2314
2315   /**
2316    * Asks the user if it is ok to store in non-workbench encoding.
2317    * 
2318    * @return <true>if the user wants to continue
2319    */
2320   private boolean askIfNonWorkbenchEncodingIsOk() {
2321     IDocumentProvider provider = getDocumentProvider();
2322     if (provider instanceof IStorageDocumentProvider) {
2323       IEditorInput input = getEditorInput();
2324       IStorageDocumentProvider storageProvider = (IStorageDocumentProvider) provider;
2325       String encoding = storageProvider.getEncoding(input);
2326       String defaultEncoding = storageProvider.getDefaultEncoding();
2327       if (encoding != null && !encoding.equals(defaultEncoding)) {
2328         Shell shell = getSite().getShell();
2329         String title = PHPEditorMessages.getString("PHPUnitEditor.warning.save.nonWorkbenchEncoding.title"); //$NON-NLS-1$
2330         String msg;
2331         if (input != null)
2332           msg = MessageFormat.format(PHPEditorMessages.getString("PHPUnitEditor.warning.save.nonWorkbenchEncoding.message1"),
2333               new String[] { input.getName(), encoding }); //$NON-NLS-1$
2334         else
2335           msg = MessageFormat.format(PHPEditorMessages.getString("PHPUnitEditor.warning.save.nonWorkbenchEncoding.message2"),
2336               new String[] { encoding }); //$NON-NLS-1$
2337         return MessageDialog.openQuestion(shell, title, msg);
2338       }
2339     }
2340     return true;
2341   }
2342
2343   /*
2344    * @see net.sourceforge.phpdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled()
2345    * @since 3.0
2346    */
2347   public void aboutToBeReconciled() {
2348
2349     // Notify AST provider
2350     //          PHPeclipsePlugin.getDefault().getASTProvider().aboutToBeReconciled(getInputJavaElement());
2351
2352     // Notify listeners
2353     Object[] listeners = fReconcilingListeners.getListeners();
2354     for (int i = 0, length = listeners.length; i < length; ++i)
2355       ((IJavaReconcilingListener) listeners[i]).aboutToBeReconciled();
2356   }
2357
2358   /*
2359    * @see net.sourceforge.phpdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(CompilationUnit, boolean,
2360    *      IProgressMonitor)
2361    * @since 3.0
2362    */
2363   public void reconciled(CompilationUnit ast, boolean forced, IProgressMonitor progressMonitor) {
2364
2365     // Always notify AST provider
2366     //          PHPeclipsePlugin.getDefault().getASTProvider().reconciled(ast, getInputJavaElement());
2367
2368     // Notify listeners
2369     //          Object[] listeners = fReconcilingListeners.getListeners();
2370     //          for (int i = 0, length= listeners.length; i < length; ++i)
2371     //                  ((IJavaReconcilingListener)listeners[i]).reconciled(ast, forced, progressMonitor);
2372
2373     // Update Java Outline page selection
2374     if (!forced && !progressMonitor.isCanceled()) {
2375       Shell shell = getSite().getShell();
2376       if (shell != null && !shell.isDisposed()) {
2377         shell.getDisplay().asyncExec(new Runnable() {
2378           public void run() {
2379             selectionChanged();
2380           }
2381         });
2382       }
2383     }
2384   }
2385
2386   /**
2387    * Returns the updated java element for the old java element.
2388    */
2389   private IJavaElement findElement(IJavaElement element) {
2390     if (element == null)
2391       return null;
2392     IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
2393     ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
2394     if (unit != null) {
2395       try {
2396         synchronized (unit) {
2397           unit.reconcile();
2398         }
2399         IJavaElement[] findings = unit.findElements(element);
2400         if (findings != null && findings.length > 0)
2401           return findings[0];
2402       } catch (JavaModelException x) {
2403         PHPeclipsePlugin.log(x.getStatus());
2404         // nothing found, be tolerant and go on
2405       }
2406     }
2407     return null;
2408   }
2409
2410   /**
2411    * Returns the offset of the given Java element.
2412    */
2413   private int getOffset(IJavaElement element) {
2414     if (element instanceof ISourceReference) {
2415       ISourceReference sr = (ISourceReference) element;
2416       try {
2417         ISourceRange srcRange = sr.getSourceRange();
2418         if (srcRange != null)
2419           return srcRange.getOffset();
2420       } catch (JavaModelException e) {
2421       }
2422     }
2423     return -1;
2424   }
2425
2426   /*
2427    * @see AbstractTextEditor#restoreSelection()
2428    */
2429   //  protected void restoreSelection() {
2430   //    try {
2431   //      if (getSourceViewer() == null || fRememberedSelection == null)
2432   //        return;
2433   //      IJavaElement newElement = findElement(fRememberedElement);
2434   //      int newOffset = getOffset(newElement);
2435   //      int delta = (newOffset > -1 && fRememberedElementOffset > -1) ? newOffset
2436   //          - fRememberedElementOffset : 0;
2437   //      if (isValidSelection(delta + fRememberedSelection.getOffset(),
2438   //          fRememberedSelection.getLength()))
2439   //        selectAndReveal(delta + fRememberedSelection.getOffset(),
2440   //            fRememberedSelection.getLength());
2441   //    } finally {
2442   //      fRememberedSelection = null;
2443   //      fRememberedElement = null;
2444   //      fRememberedElementOffset = -1;
2445   //    }
2446   //  }
2447   /**
2448    * Tells whether this is the active editor in the active page.
2449    * 
2450    * @return <code>true</code> if this is the active editor in the active page
2451    * @see IWorkbenchPage#getActiveEditor();
2452    */
2453   protected final boolean isActiveEditor() {
2454     IWorkbenchWindow window = getSite().getWorkbenchWindow();
2455     IWorkbenchPage page = window.getActivePage();
2456     if (page == null)
2457       return false;
2458     IEditorPart activeEditor = page.getActiveEditor();
2459     return activeEditor != null && activeEditor.equals(this);
2460   }
2461
2462   /**
2463    * Adds the given listener. Has no effect if an identical listener was not already registered.
2464    * 
2465    * @param listener
2466    *          The reconcile listener to be added
2467    * @since 3.0
2468    */
2469   final void addReconcileListener(IJavaReconcilingListener listener) {
2470     synchronized (fReconcilingListeners) {
2471       fReconcilingListeners.add(listener);
2472     }
2473   }
2474
2475   /**
2476    * Removes the given listener. Has no effect if an identical listener was not already registered.
2477    * 
2478    * @param listener
2479    *          the reconcile listener to be removed
2480    * @since 3.0
2481    */
2482   final void removeReconcileListener(IJavaReconcilingListener listener) {
2483     synchronized (fReconcilingListeners) {
2484       fReconcilingListeners.remove(listener);
2485     }
2486   }
2487
2488   protected void updateStateDependentActions() {
2489     super.updateStateDependentActions();
2490     fGenerateActionGroup.editorStateChanged();
2491   }
2492
2493   /*
2494    * @see AbstractTextEditor#rememberSelection()
2495    */
2496   protected void rememberSelection() {
2497     fRememberedSelection.remember();
2498   }
2499
2500   /*
2501    * @see AbstractTextEditor#restoreSelection()
2502    */
2503   protected void restoreSelection() {
2504     fRememberedSelection.restore();
2505   }
2506
2507   /*
2508    * @see AbstractTextEditor#canHandleMove(IEditorInput, IEditorInput)
2509    */
2510   protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) {
2511
2512     String oldExtension = ""; //$NON-NLS-1$
2513     if (originalElement instanceof IFileEditorInput) {
2514       IFile file = ((IFileEditorInput) originalElement).getFile();
2515       if (file != null) {
2516         String ext = file.getFileExtension();
2517         if (ext != null)
2518           oldExtension = ext;
2519       }
2520     }
2521
2522     String newExtension = ""; //$NON-NLS-1$
2523     if (movedElement instanceof IFileEditorInput) {
2524       IFile file = ((IFileEditorInput) movedElement).getFile();
2525       if (file != null)
2526         newExtension = file.getFileExtension();
2527     }
2528
2529     return oldExtension.equals(newExtension);
2530   }
2531
2532   /*
2533    * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#isPrefQuickDiffAlwaysOn()
2534    */
2535   protected boolean isPrefQuickDiffAlwaysOn() {
2536     // reestablishes the behaviour from AbstractDecoratedTextEditor which was hacked by JavaEditor
2537     // to disable the change bar for the class file (attached source) java editor.
2538     IPreferenceStore store = getPreferenceStore();
2539     return store.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON);
2540   }
2541
2542   /*
2543    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#getAdapter(java.lang.Class)
2544    */
2545   public Object getAdapter(Class required) {
2546     if (SmartBackspaceManager.class.equals(required)) {
2547       if (getSourceViewer() instanceof JavaSourceViewer) {
2548         return ((JavaSourceViewer) getSourceViewer()).getBackspaceManager();
2549       }
2550     }
2551
2552     return super.getAdapter(required);
2553   }
2554
2555   /**
2556    * Returns the mutex for the reconciler. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=63898 for a description of the problem.
2557    * <p>
2558    * TODO remove once the underlying problem is solved.
2559    * </p>
2560    * 
2561    * @return the lock reconcilers may use to synchronize on
2562    */
2563   public Object getReconcilerLock() {
2564     return fReconcilerLock;
2565   }
2566
2567   /*
2568    * (non-Javadoc)
2569    * 
2570    * @see org.eclipse.ui.texteditor.AbstractTextEditor#editorSaved()
2571    */
2572   protected void editorSaved() {
2573     super.editorSaved();
2574     ShowExternalPreviewAction a = ShowExternalPreviewAction.getInstance();
2575     if (a != null) {
2576       a.refresh(ShowExternalPreviewAction.PHP_TYPE);
2577     }
2578   }
2579 }