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