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