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