#1467296 patch for bug #1454529
[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 (!fCloseBracketsPHP)
1019                                   return;
1020                                 if (hasIdentifierToTheRight(document, offset + length))
1021                                   return;
1022                           // fall through
1023                   case '"':
1024                         if (event.character == '"') {
1025                           if (!fCloseStringsPHPDQ)
1026                                 return;
1027                           // changed for statements like echo "" print ""
1028                           //    if (hasIdentifierToTheLeft(document, offset)
1029                           // ||
1030                           // hasIdentifierToTheRight(document, offset +
1031                           // length))
1032                           if (hasIdentifierToTheRight(document, offset + length))
1033                                 return;
1034                         }
1035                         //     ITypedRegion partition=
1036                         // document.getPartition(offset);
1037                         //       if (!
1038                         // IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())
1039                         // &&
1040                         // (partition.getOffset() != offset))
1041                         //         return;
1042                         final char characterDQ = event.character;
1043                         final char closingCharacterDQ = getPeerCharacter(characterDQ);
1044                         final StringBuffer bufferDQ = new StringBuffer();
1045                         bufferDQ.append(characterDQ);
1046                         bufferDQ.append(closingCharacterDQ);
1047                         document.replace(offset, length, bufferDQ.toString());
1048                         LinkedPositionManager managerDQ = new LinkedPositionManager(document);
1049                         managerDQ.addPosition(offset + 1, 0);
1050                         fOffset = offset;
1051                         fLength = 2;
1052                         LinkedPositionUI editorDQ = new LinkedPositionUI(sourceViewer, managerDQ);
1053                         editorDQ.setCancelListener(this);
1054                         editorDQ.setExitPolicy(new ExitPolicy(closingCharacterDQ));
1055                         editorDQ.setFinalCaretOffset(offset + 2);
1056                         editorDQ.enter();
1057                         IRegion newSelectionDQ = editorDQ.getSelectedRegion();
1058                         sourceViewer.setSelectedRange(newSelectionDQ.getOffset(), newSelectionDQ.getLength());
1059                         event.doit = false;
1060                         break;
1061                   case '\'':
1062                         if (event.character == '\'') {
1063                           if (!fCloseStringsPHPSQ)
1064                                 return;
1065                           // changed for statements like echo "" print ""
1066                           //    if (hasIdentifierToTheLeft(document, offset)
1067                           // ||
1068                           // hasIdentifierToTheRight(document, offset +
1069                           // length))
1070                           if (hasIdentifierToTheRight(document, offset + length))
1071                                 return;
1072                         }
1073                         //     ITypedRegion partition=
1074                         // document.getPartition(offset);
1075                         //       if (!
1076                         // IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())
1077                         // &&
1078                         // (partition.getOffset() != offset))
1079                         //         return;
1080                         final char characterSQ = event.character;
1081                         final char closingCharacterSQ = getPeerCharacter(characterSQ);
1082                         final StringBuffer bufferSQ = new StringBuffer();
1083                         bufferSQ.append(characterSQ);
1084                         bufferSQ.append(closingCharacterSQ);
1085                         document.replace(offset, length, bufferSQ.toString());
1086                         LinkedPositionManager managerSQ = new LinkedPositionManager(document);
1087                         managerSQ.addPosition(offset + 1, 0);
1088                         fOffset = offset;
1089                         fLength = 2;
1090                         LinkedPositionUI editorSQ = new LinkedPositionUI(sourceViewer, managerSQ);
1091                         editorSQ.setCancelListener(this);
1092                         editorSQ.setExitPolicy(new ExitPolicy(closingCharacterSQ));
1093                         editorSQ.setFinalCaretOffset(offset + 2);
1094                         editorSQ.enter();
1095                         IRegion newSelectionSQ = editorSQ.getSelectedRegion();
1096                         sourceViewer.setSelectedRange(newSelectionSQ.getOffset(), newSelectionSQ.getLength());
1097                         event.doit = false;
1098                   case '\r': {  // insert linebreaks and new closing brace after brace and return
1099                         if (!fCloseBracketsPHP) {
1100                           return;
1101                         }
1102                           if (hasCharacterToTheLeft(document,offset,'{') && hasCharacterToTheRight(document,offset,'}')) {
1103                                   String lineDelimiter=StubUtility.getLineDelimiterFor(document);
1104                                   int caretPos=sourceViewer.getTextWidget().getCaretOffset();
1105                                 final StringBuffer buffer = new StringBuffer(lineDelimiter);
1106                                 // get indentation
1107                                 IRegion line = document.getLineInformationOfOffset(offset);
1108                                 String currentLine=document.get(line.getOffset(),line.getLength());
1109                                 int index=0;
1110                                 int max=currentLine.length();
1111                                 StringBuffer indent=new StringBuffer();
1112                                 while (index<max && Character.isWhitespace(currentLine.charAt(index))) {
1113                                         indent.append(currentLine.charAt(index));
1114                                         index++;
1115                                 }
1116                                 buffer.append(indent);
1117                                 JavaHeuristicScanner scanner= new JavaHeuristicScanner(document);
1118                                 JavaIndenter indenter= new JavaIndenter(document, scanner);
1119                                 buffer.append(indenter.createIndent(1));
1120                                 int cursorPos=buffer.length();
1121                                 buffer.append(lineDelimiter);
1122                                 buffer.append(indent);
1123                                 document.replace(offset, length, buffer.toString());
1124                                 sourceViewer.getTextWidget().setCaretOffset(caretPos+cursorPos);
1125                                 event.doit = false;
1126                           }
1127                   }
1128                   }
1129                 }
1130           } catch (BadLocationException e) {
1131           }
1132         }
1133
1134         /*
1135          * @see org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionUI.ExitListener#exit(boolean)
1136          */
1137         public void exit(boolean accept) {
1138           if (accept)
1139                 return;
1140           // remove brackets
1141           try {
1142                 final ISourceViewer sourceViewer = getSourceViewer();
1143                 IDocument document = sourceViewer.getDocument();
1144                 document.replace(fOffset, fLength, null);
1145           } catch (BadLocationException e) {
1146           }
1147         }
1148   }
1149
1150   /** The editor's save policy */
1151   protected ISavePolicy fSavePolicy;
1152
1153   /**
1154    * Listener to annotation model changes that updates the error tick in the tab image
1155    */
1156   private JavaEditorErrorTickUpdater fJavaEditorErrorTickUpdater;
1157
1158   /** The editor's paint manager */
1159   //  private PaintManager fPaintManager;
1160   /** The editor's bracket painter */
1161   //  private BracketPainter fBracketPainter;
1162   /** The editor's bracket matcher */
1163   private PHPPairMatcher fBracketMatcher;
1164
1165   /** The editor's line painter */
1166   //  private LinePainter fLinePainter;
1167   /** The editor's print margin ruler painter */
1168   //  private PrintMarginPainter fPrintMarginPainter;
1169   /** The editor's problem painter */
1170   //  private ProblemPainter fProblemPainter;
1171   /** The editor's tab converter */
1172   private TabConverter fTabConverter;
1173
1174   /** History for structure select action */
1175   //private SelectionHistory fSelectionHistory;
1176   /** The preference property change listener for php core. */
1177   //  private IPropertyChangeListener fPropertyChangeListener = new
1178   // PropertyChangeListener();
1179   /** The remembered java element */
1180   private IJavaElement fRememberedElement;
1181
1182   /**
1183    * The remembered selection.
1184    *
1185    * @since 3.0
1186    */
1187   private RememberedSelection fRememberedSelection = new RememberedSelection();
1188
1189   /** The remembered php element offset */
1190   private int fRememberedElementOffset;
1191
1192   /** The bracket inserter. */
1193   private BracketInserter fBracketInserter = new BracketInserter();
1194
1195   /** The standard action groups added to the menu */
1196   private GenerateActionGroup fGenerateActionGroup;
1197
1198   private CompositeActionGroup fContextMenuGroup;
1199
1200   //  private class PropertyChangeListener implements IPropertyChangeListener {
1201   //    /*
1202   //     * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
1203   //     */
1204   //    public void
1205   // propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent
1206   // event) {
1207   //      handlePreferencePropertyChanged(event);
1208   //    }
1209   //  }
1210   /* Preference key for code formatter tab size */
1211   private final static String CODE_FORMATTER_TAB_SIZE = JavaCore.FORMATTER_TAB_SIZE;
1212
1213   /** Preference key for matching brackets */
1214   //  private final static String MATCHING_BRACKETS = PreferenceConstants.EDITOR_MATCHING_BRACKETS;
1215   /** Preference key for matching brackets color */
1216   //  private final static String MATCHING_BRACKETS_COLOR = PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR;
1217   /** Preference key for highlighting current line */
1218   //  private final static String CURRENT_LINE = PreferenceConstants.EDITOR_CURRENT_LINE;
1219   /** Preference key for highlight color of current line */
1220   //  private final static String CURRENT_LINE_COLOR = PreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
1221   /** Preference key for showing print marging ruler */
1222   //  private final static String PRINT_MARGIN = PreferenceConstants.EDITOR_PRINT_MARGIN;
1223   /** Preference key for print margin ruler color */
1224   //  private final static String PRINT_MARGIN_COLOR = PreferenceConstants.EDITOR_PRINT_MARGIN_COLOR;
1225   /** Preference key for print margin ruler column */
1226   //  private final static String PRINT_MARGIN_COLUMN = PreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN;
1227   /** Preference key for inserting spaces rather than tabs */
1228   private final static String SPACES_FOR_TABS = PreferenceConstants.EDITOR_SPACES_FOR_TABS;
1229
1230   /** Preference key for error indication */
1231   //  private final static String ERROR_INDICATION =
1232   // PreferenceConstants.EDITOR_PROBLEM_INDICATION;
1233   /** Preference key for error color */
1234   //  private final static String ERROR_INDICATION_COLOR =
1235   // PreferenceConstants.EDITOR_PROBLEM_INDICATION_COLOR;
1236   /** Preference key for warning indication */
1237   //  private final static String WARNING_INDICATION =
1238   // PreferenceConstants.EDITOR_WARNING_INDICATION;
1239   /** Preference key for warning color */
1240   //  private final static String WARNING_INDICATION_COLOR =
1241   // PreferenceConstants.EDITOR_WARNING_INDICATION_COLOR;
1242   /** Preference key for task indication */
1243   private final static String TASK_INDICATION = PreferenceConstants.EDITOR_TASK_INDICATION;
1244
1245   /** Preference key for task color */
1246   private final static String TASK_INDICATION_COLOR = PreferenceConstants.EDITOR_TASK_INDICATION_COLOR;
1247
1248   /** Preference key for bookmark indication */
1249   private final static String BOOKMARK_INDICATION = PreferenceConstants.EDITOR_BOOKMARK_INDICATION;
1250
1251   /** Preference key for bookmark color */
1252   private final static String BOOKMARK_INDICATION_COLOR = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_COLOR;
1253
1254   /** Preference key for search result indication */
1255   private final static String SEARCH_RESULT_INDICATION = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION;
1256
1257   /** Preference key for search result color */
1258   private final static String SEARCH_RESULT_INDICATION_COLOR = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_COLOR;
1259
1260   /** Preference key for unknown annotation indication */
1261   private final static String UNKNOWN_INDICATION = PreferenceConstants.EDITOR_UNKNOWN_INDICATION;
1262
1263   /** Preference key for unknown annotation color */
1264   private final static String UNKNOWN_INDICATION_COLOR = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_COLOR;
1265
1266   /** Preference key for linked position color */
1267   private final static String LINKED_POSITION_COLOR = PreferenceConstants.EDITOR_LINKED_POSITION_COLOR;
1268
1269   /** Preference key for shwoing the overview ruler */
1270   private final static String OVERVIEW_RULER = PreferenceConstants.EDITOR_OVERVIEW_RULER;
1271
1272   /** Preference key for error indication in overview ruler */
1273   private final static String ERROR_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_ERROR_INDICATION_IN_OVERVIEW_RULER;
1274
1275   /** Preference key for warning indication in overview ruler */
1276   private final static String WARNING_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_WARNING_INDICATION_IN_OVERVIEW_RULER;
1277
1278   /** Preference key for task indication in overview ruler */
1279   private final static String TASK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_TASK_INDICATION_IN_OVERVIEW_RULER;
1280
1281   /** Preference key for bookmark indication in overview ruler */
1282   private final static String BOOKMARK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_IN_OVERVIEW_RULER;
1283
1284   /** Preference key for search result indication in overview ruler */
1285   private final static String SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER;
1286
1287   /** Preference key for unknown annotation indication in overview ruler */
1288   private final static String UNKNOWN_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_IN_OVERVIEW_RULER;
1289
1290   /** Preference key for automatically closing double quoted strings */
1291   private final static String CLOSE_STRINGS_DQ_PHP = PreferenceConstants.EDITOR_CLOSE_STRINGS_DQ_PHP;
1292
1293   /** Preference key for automatically closing single quoted strings */
1294   private final static String CLOSE_STRINGS_SQ_PHP = PreferenceConstants.EDITOR_CLOSE_STRINGS_SQ_PHP;
1295
1296   /** Preference key for automatically wrapping Java strings */
1297   //  private final static String WRAP_STRINGS = PreferenceConstants.EDITOR_WRAP_STRINGS_DQ;
1298   /** Preference key for automatically closing brackets and parenthesis */
1299   private final static String CLOSE_BRACKETS_PHP = PreferenceConstants.EDITOR_CLOSE_BRACKETS_PHP;
1300
1301   /** Preference key for automatically closing phpdocs and comments */
1302   private final static String CLOSE_JAVADOCS = PreferenceConstants.EDITOR_CLOSE_JAVADOCS;
1303
1304   /** Preference key for automatically adding phpdoc tags */
1305   private final static String ADD_JAVADOC_TAGS = PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS;
1306
1307   /** Preference key for automatically formatting phpdocs */
1308   //  private final static String FORMAT_JAVADOCS = PreferenceConstants.EDITOR_FORMAT_JAVADOCS;
1309   /** Preference key for automatically closing strings */
1310   private final static String CLOSE_STRINGS_HTML = PreferenceConstants.EDITOR_CLOSE_STRINGS_HTML;
1311
1312   /** Preference key for automatically closing brackets and parenthesis */
1313   private final static String CLOSE_BRACKETS_HTML = PreferenceConstants.EDITOR_CLOSE_BRACKETS_HTML;
1314
1315   /** Preference key for smart paste */
1316   private final static String SMART_PASTE = PreferenceConstants.EDITOR_SMART_PASTE;
1317
1318   //  private final static class AnnotationInfo {
1319   //    public String fColorPreference;
1320   //    public String fOverviewRulerPreference;
1321   //    public String fEditorPreference;
1322   //  };
1323   //  private final static Map ANNOTATION_MAP;
1324   //  static {
1325   //
1326   //    AnnotationInfo info;
1327   //    ANNOTATION_MAP = new HashMap();
1328   //
1329   //    info = new AnnotationInfo();
1330   //    info.fColorPreference = TASK_INDICATION_COLOR;
1331   //    info.fOverviewRulerPreference = TASK_INDICATION_IN_OVERVIEW_RULER;
1332   //    info.fEditorPreference = TASK_INDICATION;
1333   //    ANNOTATION_MAP.put(AnnotationType.TASK, info);
1334   //
1335   //    info = new AnnotationInfo();
1336   //    info.fColorPreference = ERROR_INDICATION_COLOR;
1337   //    info.fOverviewRulerPreference = ERROR_INDICATION_IN_OVERVIEW_RULER;
1338   //    info.fEditorPreference = ERROR_INDICATION;
1339   //    ANNOTATION_MAP.put(AnnotationType.ERROR, info);
1340   //
1341   //    info = new AnnotationInfo();
1342   //    info.fColorPreference = WARNING_INDICATION_COLOR;
1343   //    info.fOverviewRulerPreference = WARNING_INDICATION_IN_OVERVIEW_RULER;
1344   //    info.fEditorPreference = WARNING_INDICATION;
1345   //    ANNOTATION_MAP.put(AnnotationType.WARNING, info);
1346   //
1347   //    info = new AnnotationInfo();
1348   //    info.fColorPreference = BOOKMARK_INDICATION_COLOR;
1349   //    info.fOverviewRulerPreference = BOOKMARK_INDICATION_IN_OVERVIEW_RULER;
1350   //    info.fEditorPreference = BOOKMARK_INDICATION;
1351   //    ANNOTATION_MAP.put(AnnotationType.BOOKMARK, info);
1352   //
1353   //    info = new AnnotationInfo();
1354   //    info.fColorPreference = SEARCH_RESULT_INDICATION_COLOR;
1355   //    info.fOverviewRulerPreference =
1356   // SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER;
1357   //    info.fEditorPreference = SEARCH_RESULT_INDICATION;
1358   //    ANNOTATION_MAP.put(AnnotationType.SEARCH, info);
1359   //
1360   //    info = new AnnotationInfo();
1361   //    info.fColorPreference = UNKNOWN_INDICATION_COLOR;
1362   //    info.fOverviewRulerPreference = UNKNOWN_INDICATION_IN_OVERVIEW_RULER;
1363   //    info.fEditorPreference = UNKNOWN_INDICATION;
1364   //    ANNOTATION_MAP.put(AnnotationType.UNKNOWN, info);
1365   //  };
1366   //
1367   //  private final static AnnotationType[] ANNOTATION_LAYERS =
1368   //    new AnnotationType[] {
1369   //      AnnotationType.UNKNOWN,
1370   //      AnnotationType.BOOKMARK,
1371   //      AnnotationType.TASK,
1372   //      AnnotationType.SEARCH,
1373   //      AnnotationType.WARNING,
1374   //      AnnotationType.ERROR };
1375   /**
1376    * Creates a new php unit editor.
1377    */
1378
1379   /**
1380    * Reconciling listeners.
1381    *
1382    * @since 3.0
1383    */
1384   private ListenerList fReconcilingListeners = new ListenerList();
1385
1386   /**
1387    * Mutex for the reconciler. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=63898 for a description of the problem.
1388    * <p>
1389    * TODO remove once the underlying problem is solved.
1390    * </p>
1391    */
1392   private final Object fReconcilerLock = new Object();
1393
1394   public PHPUnitEditor() {
1395         super();
1396         setDocumentProvider(PHPeclipsePlugin.getDefault().getCompilationUnitDocumentProvider());
1397         setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
1398         setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
1399         setOutlinerContextMenuId("#PHPOutlinerContext"); //$NON-NLS-1$
1400         // don't set help contextId, we install our own help context
1401         fSavePolicy = null;
1402         fJavaEditorErrorTickUpdater = new JavaEditorErrorTickUpdater(this);
1403   }
1404
1405   /*
1406    * @see AbstractTextEditor#createActions()
1407    */
1408   protected void createActions() {
1409         super.createActions();
1410         Action action;
1411         //              Action action= new
1412         // TextOperationAction(PHPEditorMessages.getResourceBundle(),
1413         // "CorrectionAssistProposal.", this, CORRECTIONASSIST_PROPOSALS);
1414         // //$NON-NLS-1$
1415         //              action.setActionDefinitionId(PHPEditorActionDefinitionIds.CORRECTION_ASSIST_PROPOSALS);
1416         //              setAction("CorrectionAssistProposal", action); //$NON-NLS-1$
1417         //              markAsStateDependentAction("CorrectionAssistProposal", true);
1418         // //$NON-NLS-1$
1419         //// WorkbenchHelp.setHelp(action,
1420         // IJavaHelpContextIds.QUICK_FIX_ACTION);
1421         action = new ContentAssistAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal.", this); //$NON-NLS-1$
1422         action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
1423         setAction("ContentAssistProposal", action); //$NON-NLS-1$
1424         markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$
1425         //              WorkbenchHelp.setHelp(action,
1426         // IJavaHelpContextIds.CONTENT_ASSIST_ACTION);
1427         //              action = new TextOperationAction(PHPEditorMessages.getResourceBundle(),
1428         //                              "ContentAssistContextInformation.", this,
1429         //                              ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); //$NON-NLS-1$
1430         //              action
1431         //                              .setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
1432         //              setAction("ContentAssistContextInformation", action); //$NON-NLS-1$
1433         //              markAsStateDependentAction("ContentAssistContextInformation", true);
1434         // //$NON-NLS-1$
1435         //              WorkbenchHelp.setHelp(action,
1436         // IJavaHelpContextIds.PARAMETER_HINTS_ACTION);
1437         //              action= new
1438         // TextOperationAction(PHPEditorMessages.getResourceBundle(),
1439         // "ContentAssistCompletePrefix.", this, CONTENTASSIST_COMPLETE_PREFIX);
1440         // //$NON-NLS-1$
1441         //              action.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_COMPLETE_PREFIX);
1442         //              setAction("ContentAssistCompletePrefix", action); //$NON-NLS-1$
1443         //              markAsStateDependentAction("ContentAssistCompletePrefix", true);
1444         // //$NON-NLS-1$
1445         //// WorkbenchHelp.setHelp(action,
1446         // IJavaHelpContextIds.PARAMETER_HINTS_ACTION);
1447         action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX); //$NON-NLS-1$
1448         action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
1449         setAction("Comment", action); //$NON-NLS-1$
1450         markAsStateDependentAction("Comment", true); //$NON-NLS-1$
1451         //              WorkbenchHelp.setHelp(action, IJavaHelpContextIds.COMMENT_ACTION);
1452         action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX); //$NON-NLS-1$
1453         action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
1454         setAction("Uncomment", action); //$NON-NLS-1$
1455         markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
1456         //              WorkbenchHelp.setHelp(action, IJavaHelpContextIds.UNCOMMENT_ACTION);
1457
1458         action = new ToggleCommentAction(PHPEditorMessages.getResourceBundle(), "ToggleComment.", this); //$NON-NLS-1$
1459         action.setActionDefinitionId(PHPEditorActionDefinitionIds.TOGGLE_COMMENT);
1460         setAction("ToggleComment", action); //$NON-NLS-1$
1461         markAsStateDependentAction("ToggleComment", true); //$NON-NLS-1$
1462         //WorkbenchHelp.setHelp(action,
1463         // IJavaHelpContextIds.TOGGLE_COMMENT_ACTION);
1464         configureToggleCommentAction();
1465
1466         action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
1467         action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT);
1468         setAction("Format", action); //$NON-NLS-1$
1469         markAsStateDependentAction("Format", true); //$NON-NLS-1$
1470         markAsSelectionDependentAction("Format", true); //$NON-NLS-1$
1471         //              WorkbenchHelp.setHelp(action, IJavaHelpContextIds.FORMAT_ACTION);
1472
1473         //    action = new AddBlockCommentAction(PHPEditorMessages.getResourceBundle(),
1474         //        "AddBlockComment.", this); //$NON-NLS-1$
1475         //    action
1476         //        .setActionDefinitionId(PHPEditorActionDefinitionIds.ADD_BLOCK_COMMENT);
1477         //    setAction("AddBlockComment", action); //$NON-NLS-1$
1478         //    markAsStateDependentAction("AddBlockComment", true); //$NON-NLS-1$
1479         //    markAsSelectionDependentAction("AddBlockComment", true); //$NON-NLS-1$
1480         //    // WorkbenchHelp.setHelp(action,
1481         //    // IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
1482         //    action = new RemoveBlockCommentAction(
1483         //        PHPEditorMessages.getResourceBundle(), "RemoveBlockComment.", this); //$NON-NLS-1$
1484         //    action
1485         //        .setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_BLOCK_COMMENT);
1486         //    setAction("RemoveBlockComment", action); //$NON-NLS-1$
1487         //    markAsStateDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1488         //    markAsSelectionDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1489         //              WorkbenchHelp.setHelp(action,
1490         // IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
1491                         action= new IndentAction(PHPEditorMessages.getResourceBundle(),
1492          "Indent.", this, false); //$NON-NLS-1$
1493                         action.setActionDefinitionId(PHPEditorActionDefinitionIds.INDENT);
1494                         setAction("Indent", action); //$NON-NLS-1$
1495                         markAsStateDependentAction("Indent", true); //$NON-NLS-1$
1496                         markAsSelectionDependentAction("Indent", true); //$NON-NLS-1$
1497         // WorkbenchHelp.setHelp(action, IJavaHelpContextIds.INDENT_ACTION);
1498         //
1499         //              action= new IndentAction(PHPEditorMessages.getResourceBundle(),
1500         // "Indent.", this, true); //$NON-NLS-1$
1501         //              setAction("IndentOnTab", action); //$NON-NLS-1$
1502         //              markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$
1503         //              markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$
1504         //
1505
1506         action = new AddBlockCommentAction(PHPEditorMessages.getResourceBundle(), "AddBlockComment.", this); //$NON-NLS-1$
1507         action.setActionDefinitionId(PHPEditorActionDefinitionIds.ADD_BLOCK_COMMENT);
1508         setAction("AddBlockComment", action); //$NON-NLS-1$
1509         markAsStateDependentAction("AddBlockComment", true); //$NON-NLS-1$
1510         markAsSelectionDependentAction("AddBlockComment", true); //$NON-NLS-1$
1511         //      WorkbenchHelp.setHelp(action, IJavaHelpContextIds.ADD_BLOCK_COMMENT_ACTION);
1512
1513         action = new RemoveBlockCommentAction(PHPEditorMessages.getResourceBundle(), "RemoveBlockComment.", this); //$NON-NLS-1$
1514         action.setActionDefinitionId(PHPEditorActionDefinitionIds.REMOVE_BLOCK_COMMENT);
1515         setAction("RemoveBlockComment", action); //$NON-NLS-1$
1516         markAsStateDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1517         markAsSelectionDependentAction("RemoveBlockComment", true); //$NON-NLS-1$
1518         //      WorkbenchHelp.setHelp(action, IJavaHelpContextIds.REMOVE_BLOCK_COMMENT_ACTION);
1519
1520         //      action= new IndentAction(PHPEditorMessages.getResourceBundle(), "Indent.", this, false); //$NON-NLS-1$
1521         //      action.setActionDefinitionId(PHPEditorActionDefinitionIds.INDENT);
1522         //      setAction("Indent", action); //$NON-NLS-1$
1523         //      markAsStateDependentAction("Indent", true); //$NON-NLS-1$
1524         //      markAsSelectionDependentAction("Indent", true); //$NON-NLS-1$
1525         //// WorkbenchHelp.setHelp(action, IJavaHelpContextIds.INDENT_ACTION);
1526         //
1527         action = new IndentAction(PHPEditorMessages.getResourceBundle(), "Indent.", this, true); //$NON-NLS-1$
1528         setAction("IndentOnTab", action); //$NON-NLS-1$
1529         markAsStateDependentAction("IndentOnTab", true); //$NON-NLS-1$
1530         markAsSelectionDependentAction("IndentOnTab", true); //$NON-NLS-1$
1531
1532         if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SMART_TAB)) {
1533           // don't replace Shift Right - have to make sure their enablement is
1534           // mutually exclusive
1535           //                    removeActionActivationCode(ITextEditorActionConstants.SHIFT_RIGHT);
1536           setActionActivationCode("IndentOnTab", '\t', -1, SWT.NONE); //$NON-NLS-1$
1537         }
1538         fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
1539         //    ActionGroup rg= new RefactorActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
1540
1541         //      fActionGroups.addGroup(rg);
1542         fActionGroups.addGroup(fGenerateActionGroup);
1543
1544         // We have to keep the context menu group separate to have better control over positioning
1545         fContextMenuGroup = new CompositeActionGroup(new ActionGroup[] { fGenerateActionGroup
1546         //              rg,
1547                 //              new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)
1548                 });
1549
1550   }
1551
1552   /*
1553    * @see JavaEditor#getElementAt(int)
1554    */
1555   protected IJavaElement getElementAt(int offset) {
1556         return getElementAt(offset, true);
1557   }
1558
1559   /**
1560    * Returns the most narrow element including the given offset. If <code>reconcile</code> is <code>true</code> the editor's
1561    * input element is reconciled in advance. If it is <code>false</code> this method only returns a result if the editor's input
1562    * element does not need to be reconciled.
1563    *
1564    * @param offset
1565    *          the offset included by the retrieved element
1566    * @param reconcile
1567    *          <code>true</code> if working copy should be reconciled
1568    */
1569   protected IJavaElement getElementAt(int offset, boolean reconcile) {
1570         IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
1571         ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
1572         if (unit != null) {
1573           try {
1574                 if (reconcile) {
1575                   synchronized (unit) {
1576                         unit.reconcile();
1577                   }
1578                   return unit.getElementAt(offset);
1579                 } else if (unit.isConsistent())
1580                   return unit.getElementAt(offset);
1581           } catch (JavaModelException x) {
1582                 PHPeclipsePlugin.log(x.getStatus());
1583                 // nothing found, be tolerant and go on
1584           }
1585         }
1586         return null;
1587   }
1588
1589   /*
1590    * @see JavaEditor#getCorrespondingElement(IJavaElement)
1591    */
1592   protected IJavaElement getCorrespondingElement(IJavaElement element) {
1593         try {
1594           return EditorUtility.getWorkingCopy(element, true);
1595         } catch (JavaModelException x) {
1596           PHPeclipsePlugin.log(x.getStatus());
1597           // nothing found, be tolerant and go on
1598         }
1599         return null;
1600   }
1601
1602   public void createPartControl(Composite parent) {
1603         super.createPartControl(parent);
1604         //    fPaintManager = new PaintManager(getSourceViewer());
1605         LinePainter linePainter;
1606         linePainter = new LinePainter(getSourceViewer());
1607         linePainter.setHighlightColor(new Color(Display.getCurrent(), 225, 235, 224));
1608         //    fPaintManager.addPainter(linePainter);
1609         //    if (isBracketHighlightingEnabled())
1610         //      startBracketHighlighting();
1611         //    if (isLineHighlightingEnabled())
1612         //      startLineHighlighting();
1613         //    if (isPrintMarginVisible())
1614         //      showPrintMargin();
1615         //    Iterator e = ANNOTATION_MAP.keySet().iterator();
1616         //    while (e.hasNext()) {
1617         //      AnnotationType type = (AnnotationType) e.next();
1618         //      if (isAnnotationIndicationEnabled(type))
1619         //        startAnnotationIndication(type);
1620         //    }
1621         if (isTabConversionEnabled())
1622           startTabConversion();
1623         //    if (isOverviewRulerVisible())
1624         //      showOverviewRuler();
1625         //
1626         //    Preferences preferences =
1627         // PHPeclipsePlugin.getDefault().getPluginPreferences();
1628         //    preferences.addPropertyChangeListener(fPropertyChangeListener);
1629         IPreferenceStore preferenceStore = getPreferenceStore();
1630         boolean closeBracketsPHP = preferenceStore.getBoolean(CLOSE_BRACKETS_PHP);
1631         boolean closeStringsPHPDQ = preferenceStore.getBoolean(CLOSE_STRINGS_DQ_PHP);
1632         boolean closeStringsPHPSQ = preferenceStore.getBoolean(CLOSE_STRINGS_SQ_PHP);
1633         fBracketInserter.setCloseBracketsPHPEnabled(closeBracketsPHP);
1634         fBracketInserter.setCloseStringsPHPDQEnabled(closeStringsPHPDQ);
1635         fBracketInserter.setCloseStringsPHPSQEnabled(closeStringsPHPSQ);
1636         ISourceViewer sourceViewer = getSourceViewer();
1637         if (sourceViewer instanceof ITextViewerExtension)
1638           ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter);
1639   }
1640
1641   private static char getPeerCharacter(char character) {
1642         switch (character) {
1643         case '(':
1644           return ')';
1645         case ')':
1646           return '(';
1647         case '[':
1648           return ']';
1649         case ']':
1650           return '[';
1651         case '"':
1652           return character;
1653         case '\'':
1654           return character;
1655         case '{':
1656                 return '}';
1657         default:
1658           throw new IllegalArgumentException();
1659         }
1660   }
1661
1662   //  private void startBracketHighlighting() {
1663   //    if (fBracketPainter == null) {
1664   //      ISourceViewer sourceViewer = getSourceViewer();
1665   //      fBracketPainter = new BracketPainter(sourceViewer);
1666   //      fBracketPainter.setHighlightColor(getColor(MATCHING_BRACKETS_COLOR));
1667   //      // fPaintManager.addPainter(fBracketPainter);
1668   //    }
1669   //  }
1670   //
1671   //  private void stopBracketHighlighting() {
1672   //    if (fBracketPainter != null) {
1673   //      // fPaintManager.removePainter(fBracketPainter);
1674   //      fBracketPainter.deactivate(true);
1675   //      fBracketPainter.dispose();
1676   //      fBracketPainter = null;
1677   //    }
1678   //  }
1679
1680   //  private boolean isBracketHighlightingEnabled() {
1681   //    IPreferenceStore store = getPreferenceStore();
1682   //    return store.getBoolean(MATCHING_BRACKETS);
1683   //  }
1684
1685   //  private void startLineHighlighting() {
1686   //    if (fLinePainter == null) {
1687   //      ISourceViewer sourceViewer = getSourceViewer();
1688   //      fLinePainter = new LinePainter(sourceViewer);
1689   //      fLinePainter.setHighlightColor(getColor(CURRENT_LINE_COLOR));
1690   //      // fPaintManager.addPainter(fLinePainter);
1691   //    }
1692   //  }
1693
1694   //  private void stopLineHighlighting() {
1695   //    if (fLinePainter != null) {
1696   //      // fPaintManager.removePainter(fLinePainter);
1697   //      fLinePainter.deactivate(true);
1698   //      fLinePainter.dispose();
1699   //      fLinePainter = null;
1700   //    }
1701   //  }
1702
1703   //  private boolean isLineHighlightingEnabled() {
1704   //    IPreferenceStore store = getPreferenceStore();
1705   //    return store.getBoolean(CURRENT_LINE);
1706   //  }
1707
1708   //  private void showPrintMargin() {
1709   //    if (fPrintMarginPainter == null) {
1710   //      fPrintMarginPainter = new PrintMarginPainter(getSourceViewer());
1711   //      fPrintMarginPainter.setMarginRulerColor(getColor(PRINT_MARGIN_COLOR));
1712   //      fPrintMarginPainter.setMarginRulerColumn(getPreferenceStore().getInt(PRINT_MARGIN_COLUMN));
1713   //      // fPaintManager.addPainter(fPrintMarginPainter);
1714   //    }
1715   //  }
1716
1717   //  private void hidePrintMargin() {
1718   //    if (fPrintMarginPainter != null) {
1719   //      // fPaintManager.removePainter(fPrintMarginPainter);
1720   //      fPrintMarginPainter.deactivate(true);
1721   //      fPrintMarginPainter.dispose();
1722   //      fPrintMarginPainter = null;
1723   //    }
1724   //  }
1725
1726   //  private boolean isPrintMarginVisible() {
1727   //    IPreferenceStore store = getPreferenceStore();
1728   //    return store.getBoolean(PRINT_MARGIN);
1729   //  }
1730
1731   private int getTabSize() {
1732         Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
1733         return preferences.getInt(CODE_FORMATTER_TAB_SIZE);
1734   }
1735
1736   private boolean isTabConversionEnabled() {
1737         IPreferenceStore store = getPreferenceStore();
1738         return store.getBoolean(SPACES_FOR_TABS);
1739   }
1740
1741   private Color getColor(String key) {
1742         RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), key);
1743         return getColor(rgb);
1744   }
1745
1746   private Color getColor(RGB rgb) {
1747         JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
1748         return textTools.getColorManager().getColor(rgb);
1749   }
1750
1751   //  private Color getColor(AnnotationType annotationType) {
1752   //    AnnotationInfo info = (AnnotationInfo)
1753   // ANNOTATION_MAP.get(annotationType);
1754   //    if (info != null)
1755   //      return getColor(info.fColorPreference);
1756   //    return null;
1757   //  }
1758   public void dispose() {
1759         ISourceViewer sourceViewer = getSourceViewer();
1760         if (sourceViewer instanceof ITextViewerExtension)
1761           ((ITextViewerExtension) sourceViewer).removeVerifyKeyListener(fBracketInserter);
1762         //    if (fPropertyChangeListener != null) {
1763         //      Preferences preferences =
1764         // PHPeclipsePlugin.getDefault().getPluginPreferences();
1765         //      preferences.removePropertyChangeListener(fPropertyChangeListener);
1766         //      fPropertyChangeListener = null;
1767         //    }
1768         if (fJavaEditorErrorTickUpdater != null) {
1769           fJavaEditorErrorTickUpdater.dispose();
1770           fJavaEditorErrorTickUpdater = null;
1771         }
1772         //    if (fSelectionHistory != null)
1773         //      fSelectionHistory.dispose();
1774         //    if (fPaintManager != null) {
1775         //      fPaintManager.dispose();
1776         //      fPaintManager = null;
1777         //    }
1778         if (fActionGroups != null) {
1779           fActionGroups.dispose();
1780           fActionGroups = null;
1781         }
1782         super.dispose();
1783   }
1784
1785   //  protected AnnotationType getAnnotationType(String preferenceKey) {
1786   //    Iterator e = ANNOTATION_MAP.keySet().iterator();
1787   //    while (e.hasNext()) {
1788   //      AnnotationType type = (AnnotationType) e.next();
1789   //      AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(type);
1790   //      if (info != null) {
1791   //        if (preferenceKey.equals(info.fColorPreference)
1792   //          || preferenceKey.equals(info.fEditorPreference)
1793   //          || preferenceKey.equals(info.fOverviewRulerPreference))
1794   //          return type;
1795   //      }
1796   //    }
1797   //    return null;
1798   //  }
1799   /*
1800    * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
1801    */
1802   protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
1803         try {
1804           AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1805           if (asv != null) {
1806                 String p = event.getProperty();
1807                 if (CLOSE_BRACKETS_PHP.equals(p)) {
1808                   fBracketInserter.setCloseBracketsPHPEnabled(getPreferenceStore().getBoolean(p));
1809                   return;
1810                 }
1811                 if (CLOSE_STRINGS_DQ_PHP.equals(p)) {
1812                   fBracketInserter.setCloseStringsPHPDQEnabled(getPreferenceStore().getBoolean(p));
1813                   return;
1814                 }
1815                 if (CLOSE_STRINGS_SQ_PHP.equals(p)) {
1816                   fBracketInserter.setCloseStringsPHPSQEnabled(getPreferenceStore().getBoolean(p));
1817                   return;
1818                 }
1819                 if (SPACES_FOR_TABS.equals(p)) {
1820                   if (isTabConversionEnabled())
1821                         startTabConversion();
1822                   else
1823                         stopTabConversion();
1824                   return;
1825                 }
1826                 //        if (MATCHING_BRACKETS.equals(p)) {
1827                 //          if (isBracketHighlightingEnabled())
1828                 //            startBracketHighlighting();
1829                 //          else
1830                 //            stopBracketHighlighting();
1831                 //          return;
1832                 //        }
1833                 //        if (MATCHING_BRACKETS_COLOR.equals(p)) {
1834                 //          if (fBracketPainter != null)
1835                 //            fBracketPainter.setHighlightColor(getColor(MATCHING_BRACKETS_COLOR));
1836                 //          return;
1837                 //        }
1838                 //        if (CURRENT_LINE.equals(p)) {
1839                 //          if (isLineHighlightingEnabled())
1840                 //            startLineHighlighting();
1841                 //          else
1842                 //            stopLineHighlighting();
1843                 //          return;
1844                 //        }
1845                 //        if (CURRENT_LINE_COLOR.equals(p)) {
1846                 //          if (fLinePainter != null) {
1847                 //            stopLineHighlighting();
1848                 //            startLineHighlighting();
1849                 //          }
1850                 //          return;
1851                 //        }
1852                 //        if (PRINT_MARGIN.equals(p)) {
1853                 //          if (isPrintMarginVisible())
1854                 //            showPrintMargin();
1855                 //          else
1856                 //            hidePrintMargin();
1857                 //          return;
1858                 //        }
1859                 //        if (PRINT_MARGIN_COLOR.equals(p)) {
1860                 //          if (fPrintMarginPainter != null)
1861                 //            fPrintMarginPainter.setMarginRulerColor(getColor(PRINT_MARGIN_COLOR));
1862                 //          return;
1863                 //        }
1864                 //        if (PRINT_MARGIN_COLUMN.equals(p)) {
1865                 //          if (fPrintMarginPainter != null)
1866                 //            fPrintMarginPainter.setMarginRulerColumn(getPreferenceStore().getInt(PRINT_MARGIN_COLUMN));
1867                 //          return;
1868                 //        }
1869                 //        if (OVERVIEW_RULER.equals(p)) {
1870                 //          if (isOverviewRulerVisible())
1871                 //            showOverviewRuler();
1872                 //          else
1873                 //            hideOverviewRuler();
1874                 //          return;
1875                 //        }
1876                 //        AnnotationType type = getAnnotationType(p);
1877                 //        if (type != null) {
1878                 //
1879                 //          AnnotationInfo info = (AnnotationInfo)
1880                 // ANNOTATION_MAP.get(type);
1881                 //          if (info.fColorPreference.equals(p)) {
1882                 //            Color color = getColor(type);
1883                 //            if (fProblemPainter != null) {
1884                 //              fProblemPainter.setColor(type, color);
1885                 //              fProblemPainter.paint(IPainter.CONFIGURATION);
1886                 //            }
1887                 //            setColorInOverviewRuler(type, color);
1888                 //            return;
1889                 //          }
1890                 //
1891                 //          if (info.fEditorPreference.equals(p)) {
1892                 //            if (isAnnotationIndicationEnabled(type))
1893                 //              startAnnotationIndication(type);
1894                 //            else
1895                 //              stopAnnotationIndication(type);
1896                 //            return;
1897                 //          }
1898                 //
1899                 //          if (info.fOverviewRulerPreference.equals(p)) {
1900                 //            if (isAnnotationIndicationInOverviewRulerEnabled(type))
1901                 //              showAnnotationIndicationInOverviewRuler(type, true);
1902                 //            else
1903                 //              showAnnotationIndicationInOverviewRuler(type, false);
1904                 //            return;
1905                 //          }
1906                 //        }
1907                 IContentAssistant c = asv.getContentAssistant();
1908                 if (c instanceof ContentAssistant)
1909                   ContentAssistPreference.changeConfiguration((ContentAssistant) c, getPreferenceStore(), event);
1910           }
1911         } finally {
1912           super.handlePreferenceStoreChanged(event);
1913         }
1914   }
1915
1916   /*
1917    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent)
1918    */
1919   protected void handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) {
1920         AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1921         if (asv != null) {
1922           String p = event.getProperty();
1923           if (CODE_FORMATTER_TAB_SIZE.equals(p)) {
1924                 asv.updateIndentationPrefixes();
1925                 if (fTabConverter != null)
1926                   fTabConverter.setNumberOfSpacesPerTab(getTabSize());
1927           }
1928         }
1929         super.handlePreferencePropertyChanged(event);
1930   }
1931
1932   /**
1933    * Handles a property change event describing a change of the php core's preferences and updates the preference related editor
1934    * properties.
1935    *
1936    * @param event
1937    *          the property change event
1938    */
1939   //  protected void
1940   // handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent
1941   // event) {
1942   //    AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1943   //    if (asv != null) {
1944   //      String p = event.getProperty();
1945   //      if (CODE_FORMATTER_TAB_SIZE.equals(p)) {
1946   //        asv.updateIndentationPrefixes();
1947   //        if (fTabConverter != null)
1948   //          fTabConverter.setNumberOfSpacesPerTab(getTabSize());
1949   //      }
1950   //    }
1951   //  }
1952   /*
1953    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#createJavaSourceViewer(org.eclipse.swt.widgets.Composite,
1954    *      org.eclipse.jface.text.source.IVerticalRuler, org.eclipse.jface.text.source.IOverviewRuler, boolean, int)
1955    */
1956   protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler,
1957           boolean isOverviewRulerVisible, int styles, IPreferenceStore store) {
1958         return new AdaptedSourceViewer(parent, verticalRuler, overviewRuler, isOverviewRulerVisible, styles, store);
1959   }
1960
1961   //  protected ISourceViewer createJavaSourceViewer(Composite parent,
1962   // IVerticalRuler ruler, int styles) {
1963   //    return new AdaptedSourceViewer(parent, ruler, styles);
1964   //  }
1965   private boolean isValidSelection(int offset, int length) {
1966         IDocumentProvider provider = getDocumentProvider();
1967         if (provider != null) {
1968           IDocument document = provider.getDocument(getEditorInput());
1969           if (document != null) {
1970                 int end = offset + length;
1971                 int documentLength = document.getLength();
1972                 return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength;
1973           }
1974         }
1975         return false;
1976   }
1977
1978   /*
1979    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#getInputElement()
1980    */
1981   protected IJavaElement getInputJavaElement() {
1982         return PHPeclipsePlugin.getDefault().getWorkingCopyManager().getWorkingCopy(getEditorInput());
1983   }
1984
1985   /*
1986    * @see AbstractTextEditor#editorContextMenuAboutToShow(IMenuManager)
1987    */
1988   public void editorContextMenuAboutToShow(IMenuManager menu) {
1989         super.editorContextMenuAboutToShow(menu);
1990         ActionContext context = new ActionContext(getSelectionProvider().getSelection());
1991         fContextMenuGroup.setContext(context);
1992         fContextMenuGroup.fillContextMenu(menu);
1993         fContextMenuGroup.setContext(null);
1994   }
1995
1996   /*
1997    * @see JavaEditor#setOutlinePageInput(JavaOutlinePage, IEditorInput)
1998    */
1999   protected void setOutlinePageInput(JavaOutlinePage page, IEditorInput input) {
2000         if (page != null) {
2001           IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
2002           page.setInput(manager.getWorkingCopy(input));
2003         }
2004   }
2005
2006   /*
2007    * @see AbstractTextEditor#performSaveOperation(WorkspaceModifyOperation, IProgressMonitor)
2008    */
2009   //  protected void performSaveOperation(WorkspaceModifyOperation operation,
2010   // IProgressMonitor progressMonitor) {
2011   //    IDocumentProvider p = getDocumentProvider();
2012   //    if (p instanceof PHPDocumentProvider) {
2013   //      PHPDocumentProvider cp = (PHPDocumentProvider) p;
2014   //      cp.setSavePolicy(fSavePolicy);
2015   //    }
2016   //
2017   //    try {
2018   //      super.performSaveOperation(operation, progressMonitor);
2019   //    } finally {
2020   //      if (p instanceof PHPDocumentProvider) {
2021   //        PHPDocumentProvider cp = (PHPDocumentProvider) p;
2022   //        cp.setSavePolicy(null);
2023   //      }
2024   //    }
2025   //  }
2026   /*
2027    * @see AbstractTextEditor#doSave(IProgressMonitor)
2028    */
2029   public void doSave(IProgressMonitor progressMonitor) {
2030
2031         IDocumentProvider p = getDocumentProvider();
2032         if (p == null) {
2033           // editor has been closed
2034           return;
2035         }
2036
2037         if (p.isDeleted(getEditorInput())) {
2038
2039           if (isSaveAsAllowed()) {
2040
2041                 /*
2042                  * 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors. Changed Behavior to make sure that if called
2043                  * inside a regular save (because of deletion of input element) there is a way to report back to the caller.
2044                  */
2045                 performSaveAs(progressMonitor);
2046
2047           } else {
2048
2049                 /*
2050                  * 1GF5YOX: ITPJUI:ALL - Save of delete file claims it's still there Missing resources.
2051                  */
2052                 Shell shell = getSite().getShell();
2053                 MessageDialog
2054                         .openError(
2055                                 shell,
2056                                 PHPEditorMessages.getString("PHPUnitEditor.error.saving.title1"), PHPEditorMessages.getString("PHPUnitEditor.error.saving.message1")); //$NON-NLS-1$ //$NON-NLS-2$
2057           }
2058
2059         } else {
2060           if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_P_RTRIM_ON_SAVE)) {
2061                 RTrimAction trimAction = new RTrimAction();
2062                 trimAction.setActiveEditor(null, getSite().getPage().getActiveEditor());
2063                 trimAction.run(null);
2064           }
2065
2066           setStatusLineErrorMessage(null);
2067
2068           updateState(getEditorInput());
2069           validateState(getEditorInput());
2070
2071           IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
2072           ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
2073
2074           if (unit != null) {
2075                 synchronized (unit) {
2076                   performSave(false, progressMonitor);
2077                 }
2078           } else
2079                 performSave(false, progressMonitor);
2080         }
2081   }
2082
2083   public boolean isSaveAsAllowed() {
2084         return true;
2085   }
2086
2087   /**
2088    * The compilation unit editor implementation of this <code>AbstractTextEditor</code> method asks the user for the workspace
2089    * path of a file resource and saves the document there. See http://dev.eclipse.org/bugs/show_bug.cgi?id=6295
2090    *
2091    * @param progressMonitor
2092    *          the progress monitor
2093    */
2094   protected void performSaveAs(IProgressMonitor progressMonitor) {
2095
2096         Shell shell = getSite().getShell();
2097         IEditorInput input = getEditorInput();
2098
2099         SaveAsDialog dialog = new SaveAsDialog(shell);
2100
2101         IFile original = (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null;
2102         if (original != null)
2103           dialog.setOriginalFile(original);
2104
2105         dialog.create();
2106
2107         IDocumentProvider provider = getDocumentProvider();
2108         if (provider == null) {
2109           // editor has been programmatically closed while the dialog was open
2110           return;
2111         }
2112
2113         if (provider.isDeleted(input) && original != null) {
2114           String message = PHPEditorMessages.getFormattedString(
2115                   "CompilationUnitEditor.warning.save.delete", new Object[] { original.getName() }); //$NON-NLS-1$
2116           dialog.setErrorMessage(null);
2117           dialog.setMessage(message, IMessageProvider.WARNING);
2118         }
2119
2120         if (dialog.open() == Window.CANCEL) {
2121           if (progressMonitor != null)
2122                 progressMonitor.setCanceled(true);
2123           return;
2124         }
2125
2126         IPath filePath = dialog.getResult();
2127         if (filePath == null) {
2128           if (progressMonitor != null)
2129                 progressMonitor.setCanceled(true);
2130           return;
2131         }
2132
2133         IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
2134         IFile file = workspaceRoot.getFile(filePath);
2135         final IEditorInput newInput = new FileEditorInput(file);
2136
2137         boolean success = false;
2138         try {
2139
2140           provider.aboutToChange(newInput);
2141           getDocumentProvider().saveDocument(progressMonitor, newInput, getDocumentProvider().getDocument(getEditorInput()), true);
2142           success = true;
2143
2144         } catch (CoreException x) {
2145           IStatus status = x.getStatus();
2146           if (status == null || status.getSeverity() != IStatus.CANCEL)
2147                 ErrorDialog
2148                         .openError(
2149                                 shell,
2150                                 PHPEditorMessages.getString("CompilationUnitEditor.error.saving.title2"), PHPEditorMessages.getString("CompilationUnitEditor.error.saving.message2"), x.getStatus()); //$NON-NLS-1$ //$NON-NLS-2$
2151         } finally {
2152           provider.changed(newInput);
2153           if (success)
2154                 setInput(newInput);
2155         }
2156
2157         if (progressMonitor != null)
2158           progressMonitor.setCanceled(!success);
2159   }
2160
2161   /*
2162    * @see AbstractTextEditor#doSetInput(IEditorInput)
2163    */
2164   protected void doSetInput(IEditorInput input) throws CoreException {
2165         super.doSetInput(input);
2166         configureTabConverter();
2167         configureToggleCommentAction();
2168   }
2169
2170   //    /*
2171   //     * @see
2172   // net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#installOverrideIndicator(boolean)
2173   //     * @since 3.0
2174   //     */
2175   //    protected void installOverrideIndicator(boolean waitForReconcilation) {
2176   //            IAnnotationModel model=
2177   // getDocumentProvider().getAnnotationModel(getEditorInput());
2178   //            if (!waitForReconcilation)
2179   //                    super.installOverrideIndicator(false);
2180   //            else {
2181   //                    uninstallOverrideIndicator();
2182   //                    IJavaElement inputElement= getInputJavaElement();
2183   //                    if (model == null || inputElement == null)
2184   //                            return;
2185   //
2186   //                    fOverrideIndicatorManager= new OverrideIndicatorManager(model,
2187   // inputElement, null);
2188   //                    addReconcileListener(fOverrideIndicatorManager);
2189   //            }
2190   //    }
2191   //
2192   //    /*
2193   //     * @see
2194   // net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#uninstallOverrideIndicator()
2195   //     * @since 3.0
2196   //     */
2197   //    protected void uninstallOverrideIndicator() {
2198   //            if (fOverrideIndicatorManager != null)
2199   //                    removeReconcileListener(fOverrideIndicatorManager);
2200   //            super.uninstallOverrideIndicator();
2201   //    }
2202
2203   /**
2204    * Configures the toggle comment action
2205    *
2206    * @since 3.0
2207    */
2208   private void configureToggleCommentAction() {
2209         IAction action = getAction("ToggleComment"); //$NON-NLS-1$
2210         if (action instanceof ToggleCommentAction) {
2211           ISourceViewer sourceViewer = getSourceViewer();
2212           SourceViewerConfiguration configuration = getSourceViewerConfiguration();
2213           ((ToggleCommentAction) action).configure(sourceViewer, configuration);
2214         }
2215   }
2216
2217   //  private void configureTabConverter() {
2218   //    if (fTabConverter != null) {
2219   //      IDocumentProvider provider = getDocumentProvider();
2220   //      if (provider instanceof PHPDocumentProvider) {
2221   //        PHPDocumentProvider cup = (PHPDocumentProvider) provider;
2222   //        fTabConverter.setLineTracker(cup.createLineTracker(getEditorInput()));
2223   //      }
2224   //    }
2225   //  }
2226   private void configureTabConverter() {
2227         if (fTabConverter != null) {
2228           IDocumentProvider provider = getDocumentProvider();
2229           if (provider instanceof ICompilationUnitDocumentProvider) {
2230                 ICompilationUnitDocumentProvider cup = (ICompilationUnitDocumentProvider) provider;
2231                 fTabConverter.setLineTracker(cup.createLineTracker(getEditorInput()));
2232           }
2233         }
2234   }
2235
2236   private void startTabConversion() {
2237         if (fTabConverter == null) {
2238           fTabConverter = new TabConverter();
2239           configureTabConverter();
2240           fTabConverter.setNumberOfSpacesPerTab(getTabSize());
2241           AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
2242           asv.addTextConverter(fTabConverter);
2243           // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
2244           asv.updateIndentationPrefixes();
2245         }
2246   }
2247
2248   private void stopTabConversion() {
2249         if (fTabConverter != null) {
2250           AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
2251           asv.removeTextConverter(fTabConverter);
2252           // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
2253           asv.updateIndentationPrefixes();
2254           fTabConverter = null;
2255         }
2256   }
2257
2258   /*
2259    * @see org.eclipse.ui.texteditor.AbstractTextEditor#performSave(boolean, org.eclipse.core.runtime.IProgressMonitor)
2260    */
2261   protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) {
2262         //    IDocumentProvider p = getDocumentProvider();
2263         //    if (p instanceof PHPDocumentProvider) {
2264         //      PHPDocumentProvider cp = (PHPDocumentProvider) p;
2265         //      cp.setSavePolicy(fSavePolicy);
2266         //    }
2267         //    try {
2268         //      super.performSave(overwrite, progressMonitor);
2269         //    } finally {
2270         //      if (p instanceof PHPDocumentProvider) {
2271         //        PHPDocumentProvider cp = (PHPDocumentProvider) p;
2272         //        cp.setSavePolicy(null);
2273         //      }
2274         //    }
2275
2276         IDocumentProvider p = getDocumentProvider();
2277         if (p instanceof ICompilationUnitDocumentProvider) {
2278           ICompilationUnitDocumentProvider cp = (ICompilationUnitDocumentProvider) p;
2279           cp.setSavePolicy(fSavePolicy);
2280         }
2281         try {
2282           super.performSave(overwrite, progressMonitor);
2283         } finally {
2284           if (p instanceof ICompilationUnitDocumentProvider) {
2285                 ICompilationUnitDocumentProvider cp = (ICompilationUnitDocumentProvider) p;
2286                 cp.setSavePolicy(null);
2287           }
2288         }
2289   }
2290
2291   /*
2292    * @see AbstractTextEditor#doSaveAs
2293    */
2294   public void doSaveAs() {
2295         if (askIfNonWorkbenchEncodingIsOk()) {
2296           super.doSaveAs();
2297         }
2298   }
2299
2300   /**
2301    * Asks the user if it is ok to store in non-workbench encoding.
2302    *
2303    * @return <true>if the user wants to continue
2304    */
2305   private boolean askIfNonWorkbenchEncodingIsOk() {
2306         IDocumentProvider provider = getDocumentProvider();
2307         if (provider instanceof IStorageDocumentProvider) {
2308           IEditorInput input = getEditorInput();
2309           IStorageDocumentProvider storageProvider = (IStorageDocumentProvider) provider;
2310           String encoding = storageProvider.getEncoding(input);
2311           String defaultEncoding = storageProvider.getDefaultEncoding();
2312           if (encoding != null && !encoding.equals(defaultEncoding)) {
2313                 Shell shell = getSite().getShell();
2314                 String title = PHPEditorMessages.getString("PHPUnitEditor.warning.save.nonWorkbenchEncoding.title"); //$NON-NLS-1$
2315                 String msg;
2316                 if (input != null)
2317                   msg = MessageFormat.format(PHPEditorMessages.getString("PHPUnitEditor.warning.save.nonWorkbenchEncoding.message1"),
2318                           new String[] { input.getName(), encoding }); //$NON-NLS-1$
2319                 else
2320                   msg = MessageFormat.format(PHPEditorMessages.getString("PHPUnitEditor.warning.save.nonWorkbenchEncoding.message2"),
2321                           new String[] { encoding }); //$NON-NLS-1$
2322                 return MessageDialog.openQuestion(shell, title, msg);
2323           }
2324         }
2325         return true;
2326   }
2327
2328   /*
2329    * @see net.sourceforge.phpdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled()
2330    * @since 3.0
2331    */
2332   public void aboutToBeReconciled() {
2333
2334         // Notify AST provider
2335         //              PHPeclipsePlugin.getDefault().getASTProvider().aboutToBeReconciled(getInputJavaElement());
2336
2337         // Notify listeners
2338         Object[] listeners = fReconcilingListeners.getListeners();
2339         for (int i = 0, length = listeners.length; i < length; ++i)
2340           ((IJavaReconcilingListener) listeners[i]).aboutToBeReconciled();
2341   }
2342
2343   /*
2344    * @see net.sourceforge.phpdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(CompilationUnit, boolean,
2345    *      IProgressMonitor)
2346    * @since 3.0
2347    */
2348   public void reconciled(CompilationUnit ast, boolean forced, IProgressMonitor progressMonitor) {
2349
2350         // Always notify AST provider
2351         //              PHPeclipsePlugin.getDefault().getASTProvider().reconciled(ast, getInputJavaElement());
2352
2353         // Notify listeners
2354         //              Object[] listeners = fReconcilingListeners.getListeners();
2355         //              for (int i = 0, length= listeners.length; i < length; ++i)
2356         //                      ((IJavaReconcilingListener)listeners[i]).reconciled(ast, forced, progressMonitor);
2357
2358         // Update Java Outline page selection
2359         if (!forced && !progressMonitor.isCanceled()) {
2360           Shell shell = getSite().getShell();
2361           if (shell != null && !shell.isDisposed()) {
2362                 shell.getDisplay().asyncExec(new Runnable() {
2363                   public void run() {
2364                         selectionChanged();
2365                   }
2366                 });
2367           }
2368         }
2369   }
2370
2371   /**
2372    * Returns the updated java element for the old java element.
2373    */
2374   private IJavaElement findElement(IJavaElement element) {
2375         if (element == null)
2376           return null;
2377         IWorkingCopyManager manager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
2378         ICompilationUnit unit = manager.getWorkingCopy(getEditorInput());
2379         if (unit != null) {
2380           try {
2381                 synchronized (unit) {
2382                   unit.reconcile();
2383                 }
2384                 IJavaElement[] findings = unit.findElements(element);
2385                 if (findings != null && findings.length > 0)
2386                   return findings[0];
2387           } catch (JavaModelException x) {
2388                 PHPeclipsePlugin.log(x.getStatus());
2389                 // nothing found, be tolerant and go on
2390           }
2391         }
2392         return null;
2393   }
2394
2395   /**
2396    * Returns the offset of the given Java element.
2397    */
2398   private int getOffset(IJavaElement element) {
2399         if (element instanceof ISourceReference) {
2400           ISourceReference sr = (ISourceReference) element;
2401           try {
2402                 ISourceRange srcRange = sr.getSourceRange();
2403                 if (srcRange != null)
2404                   return srcRange.getOffset();
2405           } catch (JavaModelException e) {
2406           }
2407         }
2408         return -1;
2409   }
2410
2411   /*
2412    * @see AbstractTextEditor#restoreSelection()
2413    */
2414   //  protected void restoreSelection() {
2415   //    try {
2416   //      if (getSourceViewer() == null || fRememberedSelection == null)
2417   //        return;
2418   //      IJavaElement newElement = findElement(fRememberedElement);
2419   //      int newOffset = getOffset(newElement);
2420   //      int delta = (newOffset > -1 && fRememberedElementOffset > -1) ? newOffset
2421   //          - fRememberedElementOffset : 0;
2422   //      if (isValidSelection(delta + fRememberedSelection.getOffset(),
2423   //          fRememberedSelection.getLength()))
2424   //        selectAndReveal(delta + fRememberedSelection.getOffset(),
2425   //            fRememberedSelection.getLength());
2426   //    } finally {
2427   //      fRememberedSelection = null;
2428   //      fRememberedElement = null;
2429   //      fRememberedElementOffset = -1;
2430   //    }
2431   //  }
2432   /**
2433    * Tells whether this is the active editor in the active page.
2434    *
2435    * @return <code>true</code> if this is the active editor in the active page
2436    * @see IWorkbenchPage#getActiveEditor();
2437    */
2438   protected final boolean isActiveEditor() {
2439         IWorkbenchWindow window = getSite().getWorkbenchWindow();
2440         IWorkbenchPage page = window.getActivePage();
2441         if (page == null)
2442           return false;
2443         IEditorPart activeEditor = page.getActiveEditor();
2444         return activeEditor != null && activeEditor.equals(this);
2445   }
2446
2447   /**
2448    * Adds the given listener. Has no effect if an identical listener was not already registered.
2449    *
2450    * @param listener
2451    *          The reconcile listener to be added
2452    * @since 3.0
2453    */
2454   final void addReconcileListener(IJavaReconcilingListener listener) {
2455         synchronized (fReconcilingListeners) {
2456           fReconcilingListeners.add(listener);
2457         }
2458   }
2459
2460   /**
2461    * Removes the given listener. Has no effect if an identical listener was not already registered.
2462    *
2463    * @param listener
2464    *          the reconcile listener to be removed
2465    * @since 3.0
2466    */
2467   final void removeReconcileListener(IJavaReconcilingListener listener) {
2468         synchronized (fReconcilingListeners) {
2469           fReconcilingListeners.remove(listener);
2470         }
2471   }
2472
2473   protected void updateStateDependentActions() {
2474         super.updateStateDependentActions();
2475         fGenerateActionGroup.editorStateChanged();
2476   }
2477
2478   /*
2479    * @see AbstractTextEditor#rememberSelection()
2480    */
2481   protected void rememberSelection() {
2482         fRememberedSelection.remember();
2483   }
2484
2485   /*
2486    * @see AbstractTextEditor#restoreSelection()
2487    */
2488   protected void restoreSelection() {
2489         fRememberedSelection.restore();
2490   }
2491
2492   /*
2493    * @see AbstractTextEditor#canHandleMove(IEditorInput, IEditorInput)
2494    */
2495   protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) {
2496
2497         String oldExtension = ""; //$NON-NLS-1$
2498         if (originalElement instanceof IFileEditorInput) {
2499           IFile file = ((IFileEditorInput) originalElement).getFile();
2500           if (file != null) {
2501                 String ext = file.getFileExtension();
2502                 if (ext != null)
2503                   oldExtension = ext;
2504           }
2505         }
2506
2507         String newExtension = ""; //$NON-NLS-1$
2508         if (movedElement instanceof IFileEditorInput) {
2509           IFile file = ((IFileEditorInput) movedElement).getFile();
2510           if (file != null)
2511                 newExtension = file.getFileExtension();
2512         }
2513
2514         return oldExtension.equals(newExtension);
2515   }
2516
2517   /*
2518    * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#isPrefQuickDiffAlwaysOn()
2519    */
2520   protected boolean isPrefQuickDiffAlwaysOn() {
2521         // reestablishes the behaviour from AbstractDecoratedTextEditor which was hacked by JavaEditor
2522         // to disable the change bar for the class file (attached source) java editor.
2523         IPreferenceStore store = getPreferenceStore();
2524         return store.getBoolean(AbstractDecoratedTextEditorPreferenceConstants.QUICK_DIFF_ALWAYS_ON);
2525   }
2526
2527   /*
2528    * @see net.sourceforge.phpdt.internal.ui.javaeditor.JavaEditor#getAdapter(java.lang.Class)
2529    */
2530   public Object getAdapter(Class required) {
2531         if (SmartBackspaceManager.class.equals(required)) {
2532           if (getSourceViewer() instanceof JavaSourceViewer) {
2533                 return ((JavaSourceViewer) getSourceViewer()).getBackspaceManager();
2534           }
2535         }
2536
2537         return super.getAdapter(required);
2538   }
2539
2540   /**
2541    * Returns the mutex for the reconciler. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=63898 for a description of the problem.
2542    * <p>
2543    * TODO remove once the underlying problem is solved.
2544    * </p>
2545    *
2546    * @return the lock reconcilers may use to synchronize on
2547    */
2548   public Object getReconcilerLock() {
2549         return fReconcilerLock;
2550   }
2551
2552   /*
2553    * (non-Javadoc)
2554    *
2555    * @see org.eclipse.ui.texteditor.AbstractTextEditor#editorSaved()
2556    */
2557   protected void editorSaved() {
2558         super.editorSaved();
2559         ShowExternalPreviewAction a = ShowExternalPreviewAction.getInstance();
2560         if (a != null) {
2561           a.refresh(ShowExternalPreviewAction.PHP_TYPE);
2562         }
2563   }
2564 }