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