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