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