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