37f9bbed44fe8b215f21e782fea83c4c1f64732b
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPUnitEditor.java
1 package net.sourceforge.phpeclipse.phpeditor;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8
9 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
10 import net.sourceforge.phpdt.internal.ui.text.ContentAssistPreference;
11 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
12 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionManager;
13 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI;
14 import net.sourceforge.phpdt.internal.ui.text.link.LinkedPositionUI.ExitFlags;
15 import net.sourceforge.phpdt.ui.PreferenceConstants;
16 import net.sourceforge.phpdt.ui.text.JavaTextTools;
17 import net.sourceforge.phpeclipse.PHPCore;
18 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
19 import net.sourceforge.phpeclipse.phpeditor.php.IPHPPartitionScannerConstants;
20
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.Preferences;
24 import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
25 import org.eclipse.jface.action.IMenuManager;
26 import org.eclipse.jface.preference.IPreferenceStore;
27 import org.eclipse.jface.preference.PreferenceConverter;
28 import org.eclipse.jface.text.AbstractHoverInformationControlManager;
29 import org.eclipse.jface.text.BadLocationException;
30 import org.eclipse.jface.text.DocumentCommand;
31 import org.eclipse.jface.text.IDocument;
32 import org.eclipse.jface.text.ILineTracker;
33 import org.eclipse.jface.text.IRegion;
34 import org.eclipse.jface.text.ITextSelection;
35 import org.eclipse.jface.text.ITextViewerExtension;
36 import org.eclipse.jface.text.ITypedRegion;
37 import org.eclipse.jface.text.IWidgetTokenKeeper;
38 import org.eclipse.jface.text.contentassist.ContentAssistant;
39 import org.eclipse.jface.text.contentassist.IContentAssistant;
40 import org.eclipse.jface.text.source.IAnnotationModel;
41 import org.eclipse.jface.text.source.ISourceViewer;
42 import org.eclipse.jface.text.source.IVerticalRuler;
43 import org.eclipse.jface.text.source.SourceViewer;
44 import org.eclipse.jface.text.source.SourceViewerConfiguration;
45 import org.eclipse.jface.util.PropertyChangeEvent;
46 import org.eclipse.swt.SWT;
47 import org.eclipse.swt.custom.StyledText;
48 import org.eclipse.swt.custom.VerifyKeyListener;
49 import org.eclipse.swt.events.VerifyEvent;
50 import org.eclipse.swt.graphics.Color;
51 import org.eclipse.swt.graphics.Point;
52 import org.eclipse.swt.graphics.RGB;
53 import org.eclipse.swt.graphics.Rectangle;
54 import org.eclipse.swt.widgets.Composite;
55 import org.eclipse.swt.widgets.Control;
56 import org.eclipse.swt.widgets.Display;
57 import org.eclipse.swt.widgets.Layout;
58 import org.eclipse.ui.IEditorInput;
59 import org.eclipse.ui.IFileEditorInput;
60 import org.eclipse.ui.actions.ActionContext;
61 import org.eclipse.ui.help.WorkbenchHelp;
62 import org.eclipse.ui.texteditor.IDocumentProvider;
63
64 /**********************************************************************
65 Copyright (c) 2000, 2002 IBM Corp. and others.
66 All rights reserved. This program and the accompanying materials
67 are made available under the terms of the Common Public License v1.0
68 which accompanies this distribution, and is available at
69 http://www.eclipse.org/legal/cpl-v10.html
70
71 Contributors:
72     IBM Corporation - Initial implementation
73     Klaus Hartlage - www.eclipseproject.de
74 **********************************************************************/
75 /**
76  * PHP specific text editor.
77  */
78 public class PHPUnitEditor extends PHPEditor {
79         
80   interface ITextConverter {
81     void customizeDocumentCommand(IDocument document, DocumentCommand command);
82   };
83
84   class AdaptedRulerLayout extends Layout {
85
86     protected int fGap;
87     protected AdaptedSourceViewer fAdaptedSourceViewer;
88
89     protected AdaptedRulerLayout(int gap, AdaptedSourceViewer asv) {
90       fGap = gap;
91       fAdaptedSourceViewer = asv;
92     }
93
94     protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
95       Control[] children = composite.getChildren();
96       Point s = children[children.length - 1].computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);
97       if (fAdaptedSourceViewer.isVerticalRulerVisible())
98         s.x += fAdaptedSourceViewer.getVerticalRuler().getWidth() + fGap;
99       return s;
100     }
101
102     protected void layout(Composite composite, boolean flushCache) {
103       Rectangle clArea = composite.getClientArea();
104       if (fAdaptedSourceViewer.isVerticalRulerVisible()) {
105
106         StyledText textWidget = fAdaptedSourceViewer.getTextWidget();
107         Rectangle trim = textWidget.computeTrim(0, 0, 0, 0);
108         int scrollbarHeight = trim.height;
109
110         IVerticalRuler vr = fAdaptedSourceViewer.getVerticalRuler();
111         int vrWidth = vr.getWidth();
112
113         int orWidth = 0;
114         if (fAdaptedSourceViewer.isOverviewRulerVisible()) {
115           OverviewRuler or = fAdaptedSourceViewer.getOverviewRuler();
116           orWidth = or.getWidth();
117           or.getControl().setBounds(clArea.width - orWidth, scrollbarHeight, orWidth, clArea.height - 3 * scrollbarHeight);
118         }
119
120         textWidget.setBounds(vrWidth + fGap, 0, clArea.width - vrWidth - orWidth - 2 * fGap, clArea.height);
121         vr.getControl().setBounds(0, 0, vrWidth, clArea.height - scrollbarHeight);
122
123       } else {
124         StyledText textWidget = fAdaptedSourceViewer.getTextWidget();
125         textWidget.setBounds(0, 0, clArea.width, clArea.height);
126       }
127     }
128   };
129
130   class AdaptedSourceViewer extends SourceViewer { // extends JavaCorrectionSourceViewer  {
131
132     private List fTextConverters;
133
134     private OverviewRuler fOverviewRuler;
135     private boolean fIsOverviewRulerVisible;
136     /** The viewer's overview ruler hovering controller */
137     private AbstractHoverInformationControlManager fOverviewRulerHoveringController;
138
139     private boolean fIgnoreTextConverters = false;
140
141     private IVerticalRuler fCachedVerticalRuler;
142     private boolean fCachedIsVerticalRulerVisible;
143
144     public AdaptedSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
145       super(parent, ruler, styles); //, CompilationUnitEditor.this);
146
147       fCachedVerticalRuler = ruler;
148       fCachedIsVerticalRulerVisible = (ruler != null);
149       fOverviewRuler = new OverviewRuler(VERTICAL_RULER_WIDTH);
150
151       delayedCreateControl(parent, styles);
152     }
153
154     /*
155      * @see ISourceViewer#showAnnotations(boolean)
156      */
157     public void showAnnotations(boolean show) {
158       fCachedIsVerticalRulerVisible = (show && fCachedVerticalRuler != null);
159       //   super.showAnnotations(show);
160     }
161
162     public IContentAssistant getContentAssistant() {
163       return fContentAssistant;
164     }
165
166     /*
167      * @see ITextOperationTarget#doOperation(int)
168      */
169     public void doOperation(int operation) {
170
171       if (getTextWidget() == null)
172         return;
173
174       switch (operation) {
175         case CONTENTASSIST_PROPOSALS :
176           String msg = fContentAssistant.showPossibleCompletions();
177           setStatusLineErrorMessage(msg);
178           return;
179         case UNDO :
180           fIgnoreTextConverters = true;
181           break;
182         case REDO :
183           fIgnoreTextConverters = true;
184           break;
185       }
186
187       super.doOperation(operation);
188     }
189
190     public void insertTextConverter(ITextConverter textConverter, int index) {
191       throw new UnsupportedOperationException();
192     }
193
194     public void addTextConverter(ITextConverter textConverter) {
195       if (fTextConverters == null) {
196         fTextConverters = new ArrayList(1);
197         fTextConverters.add(textConverter);
198       } else if (!fTextConverters.contains(textConverter))
199         fTextConverters.add(textConverter);
200     }
201
202     public void removeTextConverter(ITextConverter textConverter) {
203       if (fTextConverters != null) {
204         fTextConverters.remove(textConverter);
205         if (fTextConverters.size() == 0)
206           fTextConverters = null;
207       }
208     }
209
210     /*
211      * @see TextViewer#customizeDocumentCommand(DocumentCommand)
212      */
213     protected void customizeDocumentCommand(DocumentCommand command) {
214       super.customizeDocumentCommand(command);
215       if (!fIgnoreTextConverters && fTextConverters != null) {
216         for (Iterator e = fTextConverters.iterator(); e.hasNext();)
217            ((ITextConverter) e.next()).customizeDocumentCommand(getDocument(), command);
218       }
219       fIgnoreTextConverters = false;
220     }
221
222     public IVerticalRuler getVerticalRuler() {
223       return fCachedVerticalRuler;
224     }
225
226     public boolean isVerticalRulerVisible() {
227       return fCachedIsVerticalRulerVisible;
228     }
229
230     public OverviewRuler getOverviewRuler() {
231       return fOverviewRuler;
232     }
233
234     /*
235      * @see TextViewer#createControl(Composite, int)
236      */
237     protected void createControl(Composite parent, int styles) {
238       // do nothing here
239     }
240
241     protected void delayedCreateControl(Composite parent, int styles) {
242       //create the viewer
243       super.createControl(parent, styles);
244
245       Control control = getControl();
246       if (control instanceof Composite) {
247         Composite composite = (Composite) control;
248         composite.setLayout(new AdaptedRulerLayout(GAP_SIZE, this));
249         fOverviewRuler.createControl(composite, this);
250       }
251     }
252
253     protected void ensureOverviewHoverManagerInstalled() {
254       if (fOverviewRulerHoveringController == null && fAnnotationHover != null && fHoverControlCreator != null) {
255         fOverviewRulerHoveringController =
256           new OverviewRulerHoverManager(fOverviewRuler, this, fAnnotationHover, fHoverControlCreator);
257         fOverviewRulerHoveringController.install(fOverviewRuler.getControl());
258       }
259     }
260
261     public void hideOverviewRuler() {
262       fIsOverviewRulerVisible = false;
263       Control control = getControl();
264       if (control instanceof Composite) {
265         Composite composite = (Composite) control;
266         composite.layout();
267       }
268       if (fOverviewRulerHoveringController != null) {
269         fOverviewRulerHoveringController.dispose();
270         fOverviewRulerHoveringController = null;
271       }
272     }
273
274     public void showOverviewRuler() {
275       fIsOverviewRulerVisible = true;
276       Control control = getControl();
277       if (control instanceof Composite) {
278         Composite composite = (Composite) control;
279         composite.layout();
280       }
281       ensureOverviewHoverManagerInstalled();
282     }
283
284     public boolean isOverviewRulerVisible() {
285       return fIsOverviewRulerVisible;
286     }
287
288     /*
289      * @see ISourceViewer#setDocument(IDocument, IAnnotationModel, int, int)
290      */
291     public void setDocument(
292       IDocument document,
293       IAnnotationModel annotationModel,
294       int visibleRegionOffset,
295       int visibleRegionLength) {
296       super.setDocument(document, annotationModel, visibleRegionOffset, visibleRegionLength);
297       fOverviewRuler.setModel(annotationModel);
298     }
299
300     // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
301     public void updateIndentationPrefixes() {
302       SourceViewerConfiguration configuration = getSourceViewerConfiguration();
303       String[] types = configuration.getConfiguredContentTypes(this);
304       for (int i = 0; i < types.length; i++) {
305         String[] prefixes = configuration.getIndentPrefixes(this, types[i]);
306         if (prefixes != null && prefixes.length > 0)
307           setIndentPrefixes(prefixes, types[i]);
308       }
309     }
310
311     /*
312      * @see IWidgetTokenOwner#requestWidgetToken(IWidgetTokenKeeper)
313      */
314     public boolean requestWidgetToken(IWidgetTokenKeeper requester) {
315       if (WorkbenchHelp.isContextHelpDisplayed())
316         return false;
317       return super.requestWidgetToken(requester);
318     }
319
320     /*
321      * @see org.eclipse.jface.text.source.ISourceViewer#configure(org.eclipse.jface.text.source.SourceViewerConfiguration)
322      */
323     public void configure(SourceViewerConfiguration configuration) {
324       super.configure(configuration);
325       //      prependAutoEditStrategy(new SmartBracesAutoEditStrategy(this), IDocument.DEFAULT_CONTENT_TYPE);
326     }
327
328     protected void handleDispose() {
329       fOverviewRuler = null;
330
331       if (fOverviewRulerHoveringController != null) {
332         fOverviewRulerHoveringController.dispose();
333         fOverviewRulerHoveringController = null;
334       }
335
336       super.handleDispose();
337     }
338
339   };
340
341   static class TabConverter implements ITextConverter {
342
343     private int fTabRatio;
344     private ILineTracker fLineTracker;
345
346     public TabConverter() {
347     }
348
349     public void setNumberOfSpacesPerTab(int ratio) {
350       fTabRatio = ratio;
351     }
352
353     public void setLineTracker(ILineTracker lineTracker) {
354       fLineTracker = lineTracker;
355     }
356
357     private int insertTabString(StringBuffer buffer, int offsetInLine) {
358
359       if (fTabRatio == 0)
360         return 0;
361
362       int remainder = offsetInLine % fTabRatio;
363       remainder = fTabRatio - remainder;
364       for (int i = 0; i < remainder; i++)
365         buffer.append(' ');
366       return remainder;
367     }
368
369     public void customizeDocumentCommand(IDocument document, DocumentCommand command) {
370       String text = command.text;
371       if (text == null)
372         return;
373
374       int index = text.indexOf('\t');
375       if (index > -1) {
376
377         StringBuffer buffer = new StringBuffer();
378
379         fLineTracker.set(command.text);
380         int lines = fLineTracker.getNumberOfLines();
381
382         try {
383
384           for (int i = 0; i < lines; i++) {
385
386             int offset = fLineTracker.getLineOffset(i);
387             int endOffset = offset + fLineTracker.getLineLength(i);
388             String line = text.substring(offset, endOffset);
389
390             int position = 0;
391             if (i == 0) {
392               IRegion firstLine = document.getLineInformationOfOffset(command.offset);
393               position = command.offset - firstLine.getOffset();
394             }
395
396             int length = line.length();
397             for (int j = 0; j < length; j++) {
398               char c = line.charAt(j);
399               if (c == '\t') {
400                 position += insertTabString(buffer, position);
401               } else {
402                 buffer.append(c);
403                 ++position;
404               }
405             }
406
407           }
408
409           command.text = buffer.toString();
410
411         } catch (BadLocationException x) {
412         }
413       }
414     }
415   };
416
417   private static class ExitPolicy implements LinkedPositionUI.ExitPolicy {
418
419     final char fExitCharacter;
420
421     public ExitPolicy(char exitCharacter) {
422       fExitCharacter = exitCharacter;
423     }
424
425     /*
426      * @see org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionManager, org.eclipse.swt.events.VerifyEvent, int, int)
427      */
428     public ExitFlags doExit(LinkedPositionManager manager, VerifyEvent event, int offset, int length) {
429
430       if (event.character == fExitCharacter) {
431         if (manager.anyPositionIncludes(offset, length))
432           return new ExitFlags(LinkedPositionUI.COMMIT | LinkedPositionUI.UPDATE_CARET, false);
433         else
434           return new ExitFlags(LinkedPositionUI.COMMIT, true);
435       }
436
437       switch (event.character) {
438         case '\b' :
439           if (manager.getFirstPosition().length == 0)
440             return new ExitFlags(0, false);
441           else
442             return null;
443
444         case '\n' :
445         case '\r' :
446           return new ExitFlags(LinkedPositionUI.COMMIT, true);
447
448         default :
449           return null;
450       }
451     }
452
453   }
454   private class BracketInserter implements VerifyKeyListener, LinkedPositionUI.ExitListener {
455
456     private boolean fCloseBracketsPHP = true;
457     private boolean fCloseStringsPHP = true;
458     private boolean fCloseBracketsHTML = true;
459     private boolean fCloseStringsHTML = true;
460
461     private int fOffset;
462     private int fLength;
463
464     public void setCloseBracketsPHPEnabled(boolean enabled) {
465       fCloseBracketsPHP = enabled;
466     }
467
468     public void setCloseStringsPHPEnabled(boolean enabled) {
469       fCloseStringsPHP = enabled;
470     }
471
472     public void setCloseBracketsHTMLEnabled(boolean enabled) {
473       fCloseBracketsHTML = enabled;
474     }
475
476     public void setCloseStringsHTMLEnabled(boolean enabled) {
477       fCloseStringsHTML = enabled;
478     }
479
480     private boolean hasIdentifierToTheRight(IDocument document, int offset) {
481       try {
482         int end = offset;
483         IRegion endLine = document.getLineInformationOfOffset(end);
484         int maxEnd = endLine.getOffset() + endLine.getLength();
485         while (end != maxEnd && Character.isWhitespace(document.getChar(end)))
486           ++end;
487
488         return end != maxEnd && Scanner.isPHPIdentifierPart(document.getChar(end));
489
490       } catch (BadLocationException e) {
491         // be conservative
492         return true;
493       }
494     }
495
496     private boolean hasIdentifierToTheLeft(IDocument document, int offset) {
497       try {
498         int start = offset;
499         IRegion startLine = document.getLineInformationOfOffset(start);
500         int minStart = startLine.getOffset();
501         while (start != minStart && Character.isWhitespace(document.getChar(start - 1)))
502           --start;
503
504         return start != minStart && Scanner.isPHPIdentifierPart(document.getChar(start - 1));
505
506       } catch (BadLocationException e) {
507         return true;
508       }
509     }
510
511     private boolean hasCharacterToTheRight(IDocument document, int offset, char character) {
512       try {
513         int end = offset;
514         IRegion endLine = document.getLineInformationOfOffset(end);
515         int maxEnd = endLine.getOffset() + endLine.getLength();
516         while (end != maxEnd && Character.isWhitespace(document.getChar(end)))
517           ++end;
518
519         return end != maxEnd && document.getChar(end) == character;
520
521       } catch (BadLocationException e) {
522         // be conservative
523         return true;
524       }
525     }
526
527     /*
528      * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
529      */
530     public void verifyKey(VerifyEvent event) {
531
532       if (!event.doit)
533         return;
534
535       final ISourceViewer sourceViewer = getSourceViewer();
536       IDocument document = sourceViewer.getDocument();
537
538       final Point selection = sourceViewer.getSelectedRange();
539       final int offset = selection.x;
540       final int length = selection.y;
541
542       try {
543         ITypedRegion partition = document.getPartition(offset);
544         String type = partition.getType();
545         if (type.equals(IPHPPartitionScannerConstants.PHP)) {
546           switch (event.character) {
547             case '(' :
548               if (hasCharacterToTheRight(document, offset + length, '('))
549                 return;
550
551               // fall through
552
553             case '[' :
554               if (!fCloseBracketsPHP)
555                 return;
556               if (hasIdentifierToTheRight(document, offset + length))
557                 return;
558
559               // fall through
560
561             case '"' :
562               if (event.character == '"') {
563                 if (!fCloseStringsPHP)
564                   return;
565                 // changed for statements like echo ""  print ""
566                 //    if (hasIdentifierToTheLeft(document, offset) || hasIdentifierToTheRight(document, offset + length))
567                 if (hasIdentifierToTheRight(document, offset + length))
568                   return;
569               }
570
571               //     ITypedRegion partition= document.getPartition(offset);
572               //       if (! IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType()) &&  (partition.getOffset() != offset))
573               //         return;
574
575               final char character = event.character;
576               final char closingCharacter = getPeerCharacter(character);
577               final StringBuffer buffer = new StringBuffer();
578               buffer.append(character);
579               buffer.append(closingCharacter);
580
581               document.replace(offset, length, buffer.toString());
582
583               LinkedPositionManager manager = new LinkedPositionManager(document);
584               manager.addPosition(offset + 1, 0);
585
586               fOffset = offset;
587               fLength = 2;
588
589               LinkedPositionUI editor = new LinkedPositionUI(sourceViewer, manager);
590               editor.setCancelListener(this);
591               editor.setExitPolicy(new ExitPolicy(closingCharacter));
592               editor.setFinalCaretOffset(offset + 2);
593               editor.enter();
594
595               IRegion newSelection = editor.getSelectedRegion();
596               sourceViewer.setSelectedRange(newSelection.getOffset(), newSelection.getLength());
597
598               event.doit = false;
599           }
600         } else if (type.equals(IPHPPartitionScannerConstants.HTML) || type.equals(IDocument.DEFAULT_CONTENT_TYPE)) {
601           switch (event.character) {
602             case '(' :
603               if (hasCharacterToTheRight(document, offset + length, '('))
604                 return;
605
606               // fall through
607
608             case '[' :
609               if (!fCloseBracketsHTML)
610                 return;
611               if (hasIdentifierToTheRight(document, offset + length))
612                 return;
613
614               // fall through
615
616             case '"' :
617               if (event.character == '"') {
618                 if (!fCloseStringsHTML)
619                   return;
620
621                 if (hasIdentifierToTheLeft(document, offset) || hasIdentifierToTheRight(document, offset + length))
622                   return;
623               }
624
625               //     ITypedRegion partition= document.getPartition(offset);
626               //       if (! IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType()) &&  (partition.getOffset() != offset))
627               //         return;
628
629               final char character = event.character;
630               final char closingCharacter = getPeerCharacter(character);
631               final StringBuffer buffer = new StringBuffer();
632               buffer.append(character);
633               buffer.append(closingCharacter);
634
635               document.replace(offset, length, buffer.toString());
636
637               LinkedPositionManager manager = new LinkedPositionManager(document);
638               manager.addPosition(offset + 1, 0);
639
640               fOffset = offset;
641               fLength = 2;
642
643               LinkedPositionUI editor = new LinkedPositionUI(sourceViewer, manager);
644               editor.setCancelListener(this);
645               editor.setExitPolicy(new ExitPolicy(closingCharacter));
646               editor.setFinalCaretOffset(offset + 2);
647               editor.enter();
648
649               IRegion newSelection = editor.getSelectedRegion();
650               sourceViewer.setSelectedRange(newSelection.getOffset(), newSelection.getLength());
651
652               event.doit = false;
653           }
654         }
655       } catch (BadLocationException e) {
656       }
657
658     }
659
660     /*
661      * @see org.phpeclipse.phpdt.internal.ui.text.link.LinkedPositionUI.ExitListener#exit(boolean)
662      */
663     public void exit(boolean accept) {
664       if (accept)
665         return;
666
667       // remove brackets
668       try {
669         final ISourceViewer sourceViewer = getSourceViewer();
670         IDocument document = sourceViewer.getDocument();
671         document.replace(fOffset, fLength, null);
672       } catch (BadLocationException e) {
673       }
674     }
675
676   }
677   /** The editor's paint manager */
678   private PaintManager fPaintManager;
679   /** The editor's bracket painter */
680   private BracketPainter fBracketPainter;
681   /** The editor's bracket matcher */
682   private PHPPairMatcher fBracketMatcher;
683   /** The editor's line painter */
684   private LinePainter fLinePainter;
685   /** The editor's print margin ruler painter */
686   private PrintMarginPainter fPrintMarginPainter;
687   /** The editor's problem painter */
688   private ProblemPainter fProblemPainter;
689   /** The editor's tab converter */
690   private TabConverter fTabConverter;
691   /** History for structure select action */
692   //private SelectionHistory fSelectionHistory;
693
694   /** The preference property change listener for php core. */
695   private IPropertyChangeListener fPropertyChangeListener = new PropertyChangeListener();
696   /** The remembered selection */
697   private ITextSelection fRememberedSelection;
698   /** The remembered php element offset */
699   private int fRememberedElementOffset;
700   /** The bracket inserter. */
701   private BracketInserter fBracketInserter = new BracketInserter();
702
703   private class PropertyChangeListener implements IPropertyChangeListener {
704     /*
705      * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
706      */
707     public void propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) {
708       handlePreferencePropertyChanged(event);
709     }
710   }
711   /* Preference key for code formatter tab size */
712   private final static String CODE_FORMATTER_TAB_SIZE = PHPCore.FORMATTER_TAB_SIZE;
713   /** Preference key for matching brackets */
714   private final static String MATCHING_BRACKETS = PreferenceConstants.EDITOR_MATCHING_BRACKETS;
715   /** Preference key for matching brackets color */
716   private final static String MATCHING_BRACKETS_COLOR = PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR;
717   /** Preference key for highlighting current line */
718   private final static String CURRENT_LINE = PreferenceConstants.EDITOR_CURRENT_LINE;
719   /** Preference key for highlight color of current line */
720   private final static String CURRENT_LINE_COLOR = PreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
721   /** Preference key for showing print marging ruler */
722   private final static String PRINT_MARGIN = PreferenceConstants.EDITOR_PRINT_MARGIN;
723   /** Preference key for print margin ruler color */
724   private final static String PRINT_MARGIN_COLOR = PreferenceConstants.EDITOR_PRINT_MARGIN_COLOR;
725   /** Preference key for print margin ruler column */
726   private final static String PRINT_MARGIN_COLUMN = PreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN;
727   /** Preference key for inserting spaces rather than tabs */
728   private final static String SPACES_FOR_TABS = PreferenceConstants.EDITOR_SPACES_FOR_TABS;
729   /** Preference key for error indication */
730   private final static String ERROR_INDICATION = PreferenceConstants.EDITOR_PROBLEM_INDICATION;
731   /** Preference key for error color */
732   private final static String ERROR_INDICATION_COLOR = PreferenceConstants.EDITOR_PROBLEM_INDICATION_COLOR;
733   /** Preference key for warning indication */
734   private final static String WARNING_INDICATION = PreferenceConstants.EDITOR_WARNING_INDICATION;
735   /** Preference key for warning color */
736   private final static String WARNING_INDICATION_COLOR = PreferenceConstants.EDITOR_WARNING_INDICATION_COLOR;
737   /** Preference key for task indication */
738   private final static String TASK_INDICATION = PreferenceConstants.EDITOR_TASK_INDICATION;
739   /** Preference key for task color */
740   private final static String TASK_INDICATION_COLOR = PreferenceConstants.EDITOR_TASK_INDICATION_COLOR;
741   /** Preference key for bookmark indication */
742   private final static String BOOKMARK_INDICATION = PreferenceConstants.EDITOR_BOOKMARK_INDICATION;
743   /** Preference key for bookmark color */
744   private final static String BOOKMARK_INDICATION_COLOR = PreferenceConstants.EDITOR_BOOKMARK_INDICATION_COLOR;
745   /** Preference key for search result indication */
746   private final static String SEARCH_RESULT_INDICATION = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION;
747   /** Preference key for search result color */
748   private final static String SEARCH_RESULT_INDICATION_COLOR = PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_COLOR;
749   /** Preference key for unknown annotation indication */
750   private final static String UNKNOWN_INDICATION = PreferenceConstants.EDITOR_UNKNOWN_INDICATION;
751   /** Preference key for unknown annotation color */
752   private final static String UNKNOWN_INDICATION_COLOR = PreferenceConstants.EDITOR_UNKNOWN_INDICATION_COLOR;
753   /** Preference key for linked position color */
754   private final static String LINKED_POSITION_COLOR = PreferenceConstants.EDITOR_LINKED_POSITION_COLOR;
755   /** Preference key for shwoing the overview ruler */
756   private final static String OVERVIEW_RULER = PreferenceConstants.EDITOR_OVERVIEW_RULER;
757
758   /** Preference key for error indication in overview ruler */
759   private final static String ERROR_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_ERROR_INDICATION_IN_OVERVIEW_RULER;
760   /** Preference key for warning indication in overview ruler */
761   private final static String WARNING_INDICATION_IN_OVERVIEW_RULER =
762     PreferenceConstants.EDITOR_WARNING_INDICATION_IN_OVERVIEW_RULER;
763   /** Preference key for task indication in overview ruler */
764   private final static String TASK_INDICATION_IN_OVERVIEW_RULER = PreferenceConstants.EDITOR_TASK_INDICATION_IN_OVERVIEW_RULER;
765   /** Preference key for bookmark indication in overview ruler */
766   private final static String BOOKMARK_INDICATION_IN_OVERVIEW_RULER =
767     PreferenceConstants.EDITOR_BOOKMARK_INDICATION_IN_OVERVIEW_RULER;
768   /** Preference key for search result indication in overview ruler */
769   private final static String SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER =
770     PreferenceConstants.EDITOR_SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER;
771   /** Preference key for unknown annotation indication in overview ruler */
772   private final static String UNKNOWN_INDICATION_IN_OVERVIEW_RULER =
773     PreferenceConstants.EDITOR_UNKNOWN_INDICATION_IN_OVERVIEW_RULER;
774   /** Preference key for automatically closing strings */
775   private final static String CLOSE_STRINGS_PHP = PreferenceConstants.EDITOR_CLOSE_STRINGS_PHP;
776   /** Preference key for automatically wrapping Java strings */
777   private final static String WRAP_STRINGS = PreferenceConstants.EDITOR_WRAP_STRINGS;
778   /** Preference key for automatically closing brackets and parenthesis */
779   private final static String CLOSE_BRACKETS_PHP = PreferenceConstants.EDITOR_CLOSE_BRACKETS_PHP;
780   /** Preference key for automatically closing phpdocs and comments */
781   private final static String CLOSE_JAVADOCS = PreferenceConstants.EDITOR_CLOSE_JAVADOCS;
782   /** Preference key for automatically adding phpdoc tags */
783   private final static String ADD_JAVADOC_TAGS = PreferenceConstants.EDITOR_ADD_JAVADOC_TAGS;
784   /** Preference key for automatically formatting phpdocs */
785   private final static String FORMAT_JAVADOCS = PreferenceConstants.EDITOR_FORMAT_JAVADOCS;
786   /** Preference key for automatically closing strings */
787   private final static String CLOSE_STRINGS_HTML = PreferenceConstants.EDITOR_CLOSE_STRINGS_HTML;
788   /** Preference key for automatically closing brackets and parenthesis */
789   private final static String CLOSE_BRACKETS_HTML = PreferenceConstants.EDITOR_CLOSE_BRACKETS_HTML;
790
791   /** Preference key for smart paste */
792   private final static String SMART_PASTE = PreferenceConstants.EDITOR_SMART_PASTE;
793   private final static class AnnotationInfo {
794     public String fColorPreference;
795     public String fOverviewRulerPreference;
796     public String fEditorPreference;
797   };
798
799   private final static Map ANNOTATION_MAP;
800   static {
801
802     AnnotationInfo info;
803     ANNOTATION_MAP = new HashMap();
804
805     info = new AnnotationInfo();
806     info.fColorPreference = TASK_INDICATION_COLOR;
807     info.fOverviewRulerPreference = TASK_INDICATION_IN_OVERVIEW_RULER;
808     info.fEditorPreference = TASK_INDICATION;
809     ANNOTATION_MAP.put(AnnotationType.TASK, info);
810
811     info = new AnnotationInfo();
812     info.fColorPreference = ERROR_INDICATION_COLOR;
813     info.fOverviewRulerPreference = ERROR_INDICATION_IN_OVERVIEW_RULER;
814     info.fEditorPreference = ERROR_INDICATION;
815     ANNOTATION_MAP.put(AnnotationType.ERROR, info);
816
817     info = new AnnotationInfo();
818     info.fColorPreference = WARNING_INDICATION_COLOR;
819     info.fOverviewRulerPreference = WARNING_INDICATION_IN_OVERVIEW_RULER;
820     info.fEditorPreference = WARNING_INDICATION;
821     ANNOTATION_MAP.put(AnnotationType.WARNING, info);
822
823     info = new AnnotationInfo();
824     info.fColorPreference = BOOKMARK_INDICATION_COLOR;
825     info.fOverviewRulerPreference = BOOKMARK_INDICATION_IN_OVERVIEW_RULER;
826     info.fEditorPreference = BOOKMARK_INDICATION;
827     ANNOTATION_MAP.put(AnnotationType.BOOKMARK, info);
828
829     info = new AnnotationInfo();
830     info.fColorPreference = SEARCH_RESULT_INDICATION_COLOR;
831     info.fOverviewRulerPreference = SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER;
832     info.fEditorPreference = SEARCH_RESULT_INDICATION;
833     ANNOTATION_MAP.put(AnnotationType.SEARCH_RESULT, info);
834
835     info = new AnnotationInfo();
836     info.fColorPreference = UNKNOWN_INDICATION_COLOR;
837     info.fOverviewRulerPreference = UNKNOWN_INDICATION_IN_OVERVIEW_RULER;
838     info.fEditorPreference = UNKNOWN_INDICATION;
839     ANNOTATION_MAP.put(AnnotationType.UNKNOWN, info);
840   };
841
842   private final static AnnotationType[] ANNOTATION_LAYERS =
843     new AnnotationType[] {
844       AnnotationType.UNKNOWN,
845       AnnotationType.BOOKMARK,
846       AnnotationType.TASK,
847       AnnotationType.SEARCH_RESULT,
848       AnnotationType.WARNING,
849       AnnotationType.ERROR };
850   /**
851    * Creates a new php unit editor.
852    */
853   public PHPUnitEditor() {
854     super();
855     setDocumentProvider(PHPeclipsePlugin.getDefault().getCompilationUnitDocumentProvider());
856     setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
857     setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
858
859   }
860
861   public void createPartControl(Composite parent) {
862     super.createPartControl(parent);
863
864     fPaintManager = new PaintManager(getSourceViewer());
865
866     LinePainter linePainter;
867     linePainter = new LinePainter(getSourceViewer());
868
869     linePainter.setHighlightColor(new Color(Display.getCurrent(), 225, 235, 224));
870
871     fPaintManager.addPainter(linePainter);
872
873     if (isBracketHighlightingEnabled())
874       startBracketHighlighting();
875     if (isLineHighlightingEnabled())
876       startLineHighlighting();
877     if (isPrintMarginVisible())
878       showPrintMargin();
879
880     Iterator e = ANNOTATION_MAP.keySet().iterator();
881     while (e.hasNext()) {
882       AnnotationType type = (AnnotationType) e.next();
883       if (isAnnotationIndicationEnabled(type))
884         startAnnotationIndication(type);
885     }
886
887     if (isTabConversionEnabled())
888       startTabConversion();
889
890     if (isOverviewRulerVisible())
891       showOverviewRuler();
892
893     Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
894     preferences.addPropertyChangeListener(fPropertyChangeListener);
895
896     IPreferenceStore preferenceStore = getPreferenceStore();
897     boolean closeBracketsPHP = preferenceStore.getBoolean(CLOSE_BRACKETS_PHP);
898     boolean closeStringsPHP = preferenceStore.getBoolean(CLOSE_STRINGS_PHP);
899     boolean closeBracketsHTML = preferenceStore.getBoolean(CLOSE_BRACKETS_HTML);
900     boolean closeStringsHTML = preferenceStore.getBoolean(CLOSE_STRINGS_HTML);
901
902     fBracketInserter.setCloseBracketsPHPEnabled(closeBracketsPHP);
903     fBracketInserter.setCloseStringsPHPEnabled(closeStringsPHP);
904     fBracketInserter.setCloseBracketsHTMLEnabled(closeBracketsHTML);
905     fBracketInserter.setCloseStringsHTMLEnabled(closeStringsHTML);
906
907     ISourceViewer sourceViewer = getSourceViewer();
908     if (sourceViewer instanceof ITextViewerExtension)
909        ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(fBracketInserter);
910
911   }
912
913   private static char getPeerCharacter(char character) {
914     switch (character) {
915       case '(' :
916         return ')';
917
918       case ')' :
919         return '(';
920
921       case '[' :
922         return ']';
923
924       case ']' :
925         return '[';
926
927       case '"' :
928         return character;
929
930       default :
931         throw new IllegalArgumentException();
932     }
933   }
934
935   /*
936    * @see AbstractTextEditor#doSetInput(IEditorInput)
937    */
938   protected void doSetInput(IEditorInput input) throws CoreException {
939     super.doSetInput(input);
940     configureTabConverter();
941   }
942
943   private void startBracketHighlighting() {
944     if (fBracketPainter == null) {
945       ISourceViewer sourceViewer = getSourceViewer();
946       fBracketPainter = new BracketPainter(sourceViewer);
947       fBracketPainter.setHighlightColor(getColor(MATCHING_BRACKETS_COLOR));
948       fPaintManager.addPainter(fBracketPainter);
949     }
950   }
951
952   private void stopBracketHighlighting() {
953     if (fBracketPainter != null) {
954       fPaintManager.removePainter(fBracketPainter);
955       fBracketPainter.deactivate(true);
956       fBracketPainter.dispose();
957       fBracketPainter = null;
958     }
959   }
960
961   private boolean isBracketHighlightingEnabled() {
962     IPreferenceStore store = getPreferenceStore();
963     return store.getBoolean(MATCHING_BRACKETS);
964   }
965
966   private void startLineHighlighting() {
967     if (fLinePainter == null) {
968       ISourceViewer sourceViewer = getSourceViewer();
969       fLinePainter = new LinePainter(sourceViewer);
970       fLinePainter.setHighlightColor(getColor(CURRENT_LINE_COLOR));
971       fPaintManager.addPainter(fLinePainter);
972     }
973   }
974
975   private void stopLineHighlighting() {
976     if (fLinePainter != null) {
977       fPaintManager.removePainter(fLinePainter);
978       fLinePainter.deactivate(true);
979       fLinePainter.dispose();
980       fLinePainter = null;
981     }
982   }
983
984   private boolean isLineHighlightingEnabled() {
985     IPreferenceStore store = getPreferenceStore();
986     return store.getBoolean(CURRENT_LINE);
987   }
988
989   private void showPrintMargin() {
990     if (fPrintMarginPainter == null) {
991       fPrintMarginPainter = new PrintMarginPainter(getSourceViewer());
992       fPrintMarginPainter.setMarginRulerColor(getColor(PRINT_MARGIN_COLOR));
993       fPrintMarginPainter.setMarginRulerColumn(getPreferenceStore().getInt(PRINT_MARGIN_COLUMN));
994       fPaintManager.addPainter(fPrintMarginPainter);
995     }
996   }
997
998   private void hidePrintMargin() {
999     if (fPrintMarginPainter != null) {
1000       fPaintManager.removePainter(fPrintMarginPainter);
1001       fPrintMarginPainter.deactivate(true);
1002       fPrintMarginPainter.dispose();
1003       fPrintMarginPainter = null;
1004     }
1005   }
1006
1007   private boolean isPrintMarginVisible() {
1008     IPreferenceStore store = getPreferenceStore();
1009     return store.getBoolean(PRINT_MARGIN);
1010   }
1011
1012   private void startAnnotationIndication(AnnotationType annotationType) {
1013     if (fProblemPainter == null) {
1014       fProblemPainter = new ProblemPainter(this, getSourceViewer());
1015       fPaintManager.addPainter(fProblemPainter);
1016     }
1017     fProblemPainter.setColor(annotationType, getColor(annotationType));
1018     fProblemPainter.paintAnnotations(annotationType, true);
1019     fProblemPainter.paint(IPainter.CONFIGURATION);
1020   }
1021
1022   private void shutdownAnnotationIndication() {
1023     if (fProblemPainter != null) {
1024
1025       if (!fProblemPainter.isPaintingAnnotations()) {
1026         fPaintManager.removePainter(fProblemPainter);
1027         fProblemPainter.deactivate(true);
1028         fProblemPainter.dispose();
1029         fProblemPainter = null;
1030       } else {
1031         fProblemPainter.paint(IPainter.CONFIGURATION);
1032       }
1033     }
1034   }
1035
1036   private void stopAnnotationIndication(AnnotationType annotationType) {
1037     if (fProblemPainter != null) {
1038       fProblemPainter.paintAnnotations(annotationType, false);
1039       shutdownAnnotationIndication();
1040     }
1041   }
1042
1043   private boolean isAnnotationIndicationEnabled(AnnotationType annotationType) {
1044     IPreferenceStore store = getPreferenceStore();
1045     AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(annotationType);
1046     if (info != null)
1047       return store.getBoolean(info.fEditorPreference);
1048     return false;
1049   }
1050
1051   private boolean isAnnotationIndicationInOverviewRulerEnabled(AnnotationType annotationType) {
1052     IPreferenceStore store = getPreferenceStore();
1053     AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(annotationType);
1054     if (info != null)
1055       return store.getBoolean(info.fOverviewRulerPreference);
1056     return false;
1057   }
1058
1059   private void showAnnotationIndicationInOverviewRuler(AnnotationType annotationType, boolean show) {
1060     AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1061     OverviewRuler ruler = asv.getOverviewRuler();
1062     if (ruler != null) {
1063       ruler.setColor(annotationType, getColor(annotationType));
1064       ruler.showAnnotation(annotationType, show);
1065       ruler.update();
1066     }
1067   }
1068
1069   private void setColorInOverviewRuler(AnnotationType annotationType, Color color) {
1070     AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1071     OverviewRuler ruler = asv.getOverviewRuler();
1072     if (ruler != null) {
1073       ruler.setColor(annotationType, color);
1074       ruler.update();
1075     }
1076   }
1077
1078   private void configureTabConverter() {
1079     if (fTabConverter != null) {
1080       IDocumentProvider provider = getDocumentProvider();
1081       if (provider instanceof PHPDocumentProvider) {
1082         PHPDocumentProvider cup = (PHPDocumentProvider) provider;
1083         fTabConverter.setLineTracker(cup.createLineTracker(getEditorInput()));
1084       }
1085     }
1086   }
1087
1088   private int getTabSize() {
1089     Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
1090     return preferences.getInt(CODE_FORMATTER_TAB_SIZE);
1091   }
1092
1093   private void startTabConversion() {
1094     if (fTabConverter == null) {
1095       fTabConverter = new TabConverter();
1096       configureTabConverter();
1097       fTabConverter.setNumberOfSpacesPerTab(getTabSize());
1098       AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1099       asv.addTextConverter(fTabConverter);
1100       // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
1101       asv.updateIndentationPrefixes();
1102     }
1103   }
1104
1105   private void stopTabConversion() {
1106     if (fTabConverter != null) {
1107       AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1108       asv.removeTextConverter(fTabConverter);
1109       // http://dev.eclipse.org/bugs/show_bug.cgi?id=19270
1110       asv.updateIndentationPrefixes();
1111       fTabConverter = null;
1112     }
1113   }
1114
1115   private boolean isTabConversionEnabled() {
1116     IPreferenceStore store = getPreferenceStore();
1117     return store.getBoolean(SPACES_FOR_TABS);
1118   }
1119
1120   private void showOverviewRuler() {
1121     AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1122     asv.showOverviewRuler();
1123
1124     OverviewRuler overviewRuler = asv.getOverviewRuler();
1125     if (overviewRuler != null) {
1126       for (int i = 0; i < ANNOTATION_LAYERS.length; i++) {
1127         AnnotationType type = ANNOTATION_LAYERS[i];
1128         overviewRuler.setLayer(type, i);
1129         if (isAnnotationIndicationInOverviewRulerEnabled(type))
1130           showAnnotationIndicationInOverviewRuler(type, true);
1131       }
1132     }
1133   }
1134
1135   private void hideOverviewRuler() {
1136     AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1137     asv.hideOverviewRuler();
1138   }
1139
1140   private boolean isOverviewRulerVisible() {
1141     IPreferenceStore store = getPreferenceStore();
1142     return store.getBoolean(OVERVIEW_RULER);
1143   }
1144
1145   private Color getColor(String key) {
1146     RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), key);
1147     return getColor(rgb);
1148   }
1149
1150   private Color getColor(RGB rgb) {
1151     JavaTextTools textTools = PHPeclipsePlugin.getDefault().getJavaTextTools();
1152     return textTools.getColorManager().getColor(rgb);
1153   }
1154
1155   private Color getColor(AnnotationType annotationType) {
1156     AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(annotationType);
1157     if (info != null)
1158       return getColor(info.fColorPreference);
1159     return null;
1160   }
1161
1162   public void dispose() {
1163     ISourceViewer sourceViewer = getSourceViewer();
1164     if (sourceViewer instanceof ITextViewerExtension)
1165        ((ITextViewerExtension) sourceViewer).removeVerifyKeyListener(fBracketInserter);
1166
1167     if (fPropertyChangeListener != null) {
1168       Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
1169       preferences.removePropertyChangeListener(fPropertyChangeListener);
1170       fPropertyChangeListener = null;
1171     }
1172
1173     //    if (fJavaEditorErrorTickUpdater != null) {
1174     //      fJavaEditorErrorTickUpdater.dispose();
1175     //      fJavaEditorErrorTickUpdater= null;
1176     //    }
1177     //          
1178     //    if (fSelectionHistory != null)
1179     //      fSelectionHistory.dispose();
1180
1181     if (fPaintManager != null) {
1182       fPaintManager.dispose();
1183       fPaintManager = null;
1184     }
1185
1186     if (fActionGroups != null)
1187       fActionGroups.dispose();
1188
1189     super.dispose();
1190   }
1191
1192   protected AnnotationType getAnnotationType(String preferenceKey) {
1193     Iterator e = ANNOTATION_MAP.keySet().iterator();
1194     while (e.hasNext()) {
1195       AnnotationType type = (AnnotationType) e.next();
1196       AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(type);
1197       if (info != null) {
1198         if (preferenceKey.equals(info.fColorPreference)
1199           || preferenceKey.equals(info.fEditorPreference)
1200           || preferenceKey.equals(info.fOverviewRulerPreference))
1201           return type;
1202       }
1203     }
1204     return null;
1205   }
1206
1207   /*
1208    * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
1209    */
1210   protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
1211
1212     try {
1213
1214       AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1215       if (asv != null) {
1216
1217         String p = event.getProperty();
1218
1219         if (CLOSE_BRACKETS_PHP.equals(p)) {
1220           fBracketInserter.setCloseBracketsPHPEnabled(getPreferenceStore().getBoolean(p));
1221           return;
1222         }
1223
1224         if (CLOSE_STRINGS_PHP.equals(p)) {
1225           fBracketInserter.setCloseStringsPHPEnabled(getPreferenceStore().getBoolean(p));
1226           return;
1227         }
1228
1229         if (CLOSE_BRACKETS_HTML.equals(p)) {
1230           fBracketInserter.setCloseBracketsHTMLEnabled(getPreferenceStore().getBoolean(p));
1231           return;
1232         }
1233
1234         if (CLOSE_STRINGS_HTML.equals(p)) {
1235           fBracketInserter.setCloseStringsHTMLEnabled(getPreferenceStore().getBoolean(p));
1236           return;
1237         }
1238
1239         if (SPACES_FOR_TABS.equals(p)) {
1240           if (isTabConversionEnabled())
1241             startTabConversion();
1242           else
1243             stopTabConversion();
1244           return;
1245         }
1246
1247         if (MATCHING_BRACKETS.equals(p)) {
1248           if (isBracketHighlightingEnabled())
1249             startBracketHighlighting();
1250           else
1251             stopBracketHighlighting();
1252           return;
1253         }
1254
1255         if (MATCHING_BRACKETS_COLOR.equals(p)) {
1256           if (fBracketPainter != null)
1257             fBracketPainter.setHighlightColor(getColor(MATCHING_BRACKETS_COLOR));
1258           return;
1259         }
1260
1261         if (CURRENT_LINE.equals(p)) {
1262           if (isLineHighlightingEnabled())
1263             startLineHighlighting();
1264           else
1265             stopLineHighlighting();
1266           return;
1267         }
1268
1269         if (CURRENT_LINE_COLOR.equals(p)) {
1270           if (fLinePainter != null) {
1271             stopLineHighlighting();
1272             startLineHighlighting();
1273           }
1274           return;
1275         }
1276
1277         if (PRINT_MARGIN.equals(p)) {
1278           if (isPrintMarginVisible())
1279             showPrintMargin();
1280           else
1281             hidePrintMargin();
1282           return;
1283         }
1284
1285         if (PRINT_MARGIN_COLOR.equals(p)) {
1286           if (fPrintMarginPainter != null)
1287             fPrintMarginPainter.setMarginRulerColor(getColor(PRINT_MARGIN_COLOR));
1288           return;
1289         }
1290
1291         if (PRINT_MARGIN_COLUMN.equals(p)) {
1292           if (fPrintMarginPainter != null)
1293             fPrintMarginPainter.setMarginRulerColumn(getPreferenceStore().getInt(PRINT_MARGIN_COLUMN));
1294           return;
1295         }
1296
1297         if (OVERVIEW_RULER.equals(p)) {
1298           if (isOverviewRulerVisible())
1299             showOverviewRuler();
1300           else
1301             hideOverviewRuler();
1302           return;
1303         }
1304
1305         AnnotationType type = getAnnotationType(p);
1306         if (type != null) {
1307
1308           AnnotationInfo info = (AnnotationInfo) ANNOTATION_MAP.get(type);
1309           if (info.fColorPreference.equals(p)) {
1310             Color color = getColor(type);
1311             if (fProblemPainter != null) {
1312               fProblemPainter.setColor(type, color);
1313               fProblemPainter.paint(IPainter.CONFIGURATION);
1314             }
1315             setColorInOverviewRuler(type, color);
1316             return;
1317           }
1318
1319           if (info.fEditorPreference.equals(p)) {
1320             if (isAnnotationIndicationEnabled(type))
1321               startAnnotationIndication(type);
1322             else
1323               stopAnnotationIndication(type);
1324             return;
1325           }
1326
1327           if (info.fOverviewRulerPreference.equals(p)) {
1328             if (isAnnotationIndicationInOverviewRulerEnabled(type))
1329               showAnnotationIndicationInOverviewRuler(type, true);
1330             else
1331               showAnnotationIndicationInOverviewRuler(type, false);
1332             return;
1333           }
1334         }
1335
1336         IContentAssistant c = asv.getContentAssistant();
1337         if (c instanceof ContentAssistant)
1338           ContentAssistPreference.changeConfiguration((ContentAssistant) c, getPreferenceStore(), event);
1339       }
1340
1341     } finally {
1342       super.handlePreferenceStoreChanged(event);
1343     }
1344   }
1345
1346   /**
1347    * Handles a property change event describing a change
1348    * of the php core's preferences and updates the preference
1349    * related editor properties.
1350    * 
1351    * @param event the property change event
1352    */
1353   protected void handlePreferencePropertyChanged(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) {
1354     AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
1355     if (asv != null) {
1356       String p = event.getProperty();
1357       if (CODE_FORMATTER_TAB_SIZE.equals(p)) {
1358         asv.updateIndentationPrefixes();
1359         if (fTabConverter != null)
1360           fTabConverter.setNumberOfSpacesPerTab(getTabSize());
1361       }
1362     }
1363   }
1364
1365   /*
1366    * @see PHPEditor#createJavaSourceViewer(Composite, IVerticalRuler, int)
1367    */
1368   protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
1369     return new AdaptedSourceViewer(parent, ruler, styles);
1370   }
1371
1372   private boolean isValidSelection(int offset, int length) {
1373     IDocumentProvider provider = getDocumentProvider();
1374     if (provider != null) {
1375       IDocument document = provider.getDocument(getEditorInput());
1376       if (document != null) {
1377         int end = offset + length;
1378         int documentLength = document.getLength();
1379         return 0 <= offset && offset <= documentLength && 0 <= end && end <= documentLength;
1380       }
1381     }
1382     return false;
1383   }
1384
1385   /*
1386    * @see AbstractTextEditor#canHandleMove(IEditorInput, IEditorInput)
1387    */
1388   protected boolean canHandleMove(IEditorInput originalElement, IEditorInput movedElement) {
1389
1390     String oldExtension = ""; //$NON-NLS-1$
1391     if (originalElement instanceof IFileEditorInput) {
1392       IFile file = ((IFileEditorInput) originalElement).getFile();
1393       if (file != null) {
1394         String ext = file.getFileExtension();
1395         if (ext != null)
1396           oldExtension = ext;
1397       }
1398     }
1399
1400     String newExtension = ""; //$NON-NLS-1$
1401     if (movedElement instanceof IFileEditorInput) {
1402       IFile file = ((IFileEditorInput) movedElement).getFile();
1403       if (file != null)
1404         newExtension = file.getFileExtension();
1405     }
1406
1407     return oldExtension.equals(newExtension);
1408   }
1409   
1410         /*
1411          * @see AbstractTextEditor#editorContextMenuAboutToShow(IMenuManager)
1412          */
1413         public void editorContextMenuAboutToShow(IMenuManager menu) {
1414                 super.editorContextMenuAboutToShow(menu);               
1415                                 
1416                 ActionContext context= new ActionContext(getSelectionProvider().getSelection());
1417                 fContextMenuGroup.setContext(context);
1418                 fContextMenuGroup.fillContextMenu(menu);
1419                 fContextMenuGroup.setContext(null);
1420         }
1421 }