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