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