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