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