KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > javaeditor > SemanticHighlightingManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.ui.javaeditor;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.List JavaDoc;
16
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.custom.StyleRange;
19 import org.eclipse.swt.graphics.Color;
20 import org.eclipse.swt.graphics.RGB;
21
22 import org.eclipse.jface.preference.IPreferenceStore;
23 import org.eclipse.jface.preference.PreferenceConverter;
24 import org.eclipse.jface.resource.StringConverter;
25 import org.eclipse.jface.util.IPropertyChangeListener;
26 import org.eclipse.jface.util.PropertyChangeEvent;
27
28 import org.eclipse.jface.text.Position;
29 import org.eclipse.jface.text.Region;
30 import org.eclipse.jface.text.TextAttribute;
31
32 import org.eclipse.jdt.ui.text.IColorManager;
33 import org.eclipse.jdt.ui.text.IColorManagerExtension;
34 import org.eclipse.jdt.ui.text.JavaSourceViewerConfiguration;
35
36 import org.eclipse.jdt.internal.ui.text.JavaPresentationReconciler;
37
38 /**
39  * Semantic highlighting manager
40  *
41  * @since 3.0
42  */

43 public class SemanticHighlightingManager implements IPropertyChangeListener {
44
45     /**
46      * Highlighting.
47      */

48     static class Highlighting { // TODO: rename to HighlightingStyle
49

50         /** Text attribute */
51         private TextAttribute fTextAttribute;
52         /** Enabled state */
53         private boolean fIsEnabled;
54
55         /**
56          * Initialize with the given text attribute.
57          * @param textAttribute The text attribute
58          * @param isEnabled the enabled state
59          */

60         public Highlighting(TextAttribute textAttribute, boolean isEnabled) {
61             setTextAttribute(textAttribute);
62             setEnabled(isEnabled);
63         }
64
65         /**
66          * @return Returns the text attribute.
67          */

68         public TextAttribute getTextAttribute() {
69             return fTextAttribute;
70         }
71
72         /**
73          * @param textAttribute The background to set.
74          */

75         public void setTextAttribute(TextAttribute textAttribute) {
76             fTextAttribute= textAttribute;
77         }
78
79         /**
80          * @return the enabled state
81          */

82         public boolean isEnabled() {
83             return fIsEnabled;
84         }
85
86         /**
87          * @param isEnabled the new enabled state
88          */

89         public void setEnabled(boolean isEnabled) {
90             fIsEnabled= isEnabled;
91         }
92     }
93
94     /**
95      * Highlighted Positions.
96      */

97     static class HighlightedPosition extends Position {
98
99         /** Highlighting of the position */
100         private Highlighting fStyle;
101
102         /** Lock object */
103         private Object JavaDoc fLock;
104
105         /**
106          * Initialize the styled positions with the given offset, length and foreground color.
107          *
108          * @param offset The position offset
109          * @param length The position length
110          * @param highlighting The position's highlighting
111          * @param lock The lock object
112          */

113         public HighlightedPosition(int offset, int length, Highlighting highlighting, Object JavaDoc lock) {
114             super(offset, length);
115             fStyle= highlighting;
116             fLock= lock;
117         }
118
119         /**
120          * @return Returns a corresponding style range.
121          */

122         public StyleRange createStyleRange() {
123             int len= 0;
124             if (fStyle.isEnabled())
125                 len= getLength();
126
127             TextAttribute textAttribute= fStyle.getTextAttribute();
128             int style= textAttribute.getStyle();
129             int fontStyle= style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL);
130             StyleRange styleRange= new StyleRange(getOffset(), len, textAttribute.getForeground(), textAttribute.getBackground(), fontStyle);
131             styleRange.strikeout= (style & TextAttribute.STRIKETHROUGH) != 0;
132             styleRange.underline= (style & TextAttribute.UNDERLINE) != 0;
133
134             return styleRange;
135         }
136
137         /**
138          * Uses reference equality for the highlighting.
139          *
140          * @param off The offset
141          * @param len The length
142          * @param highlighting The highlighting
143          * @return <code>true</code> iff the given offset, length and highlighting are equal to the internal ones.
144          */

145         public boolean isEqual(int off, int len, Highlighting highlighting) {
146             synchronized (fLock) {
147                 return !isDeleted() && getOffset() == off && getLength() == len && fStyle == highlighting;
148             }
149         }
150
151         /**
152          * Is this position contained in the given range (inclusive)? Synchronizes on position updater.
153          *
154          * @param off The range offset
155          * @param len The range length
156          * @return <code>true</code> iff this position is not delete and contained in the given range.
157          */

158         public boolean isContained(int off, int len) {
159             synchronized (fLock) {
160                 return !isDeleted() && off <= getOffset() && off + len >= getOffset() + getLength();
161             }
162         }
163
164         public void update(int off, int len) {
165             synchronized (fLock) {
166                 super.setOffset(off);
167                 super.setLength(len);
168             }
169         }
170
171         /*
172          * @see org.eclipse.jface.text.Position#setLength(int)
173          */

174         public void setLength(int length) {
175             synchronized (fLock) {
176                 super.setLength(length);
177             }
178         }
179
180         /*
181          * @see org.eclipse.jface.text.Position#setOffset(int)
182          */

183         public void setOffset(int offset) {
184             synchronized (fLock) {
185                 super.setOffset(offset);
186             }
187         }
188
189         /*
190          * @see org.eclipse.jface.text.Position#delete()
191          */

192         public void delete() {
193             synchronized (fLock) {
194                 super.delete();
195             }
196         }
197
198         /*
199          * @see org.eclipse.jface.text.Position#undelete()
200          */

201         public void undelete() {
202             synchronized (fLock) {
203                 super.undelete();
204             }
205         }
206
207         /**
208          * @return Returns the highlighting.
209          */

210         public Highlighting getHighlighting() {
211             return fStyle;
212         }
213     }
214
215     /**
216      * Highlighted ranges.
217      */

218     public static class HighlightedRange extends Region {
219         /** The highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}. */
220         private String JavaDoc fKey;
221
222         /**
223          * Initialize with the given offset, length and highlighting key.
224          *
225          * @param offset
226          * @param length
227          * @param key the highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}
228          */

229         public HighlightedRange(int offset, int length, String JavaDoc key) {
230             super(offset, length);
231             fKey= key;
232         }
233
234         /**
235          * @return the highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}
236          */

237         public String JavaDoc getKey() {
238             return fKey;
239         }
240
241         /*
242          * @see org.eclipse.jface.text.Region#equals(java.lang.Object)
243          */

244         public boolean equals(Object JavaDoc o) {
245             return super.equals(o) && o instanceof HighlightedRange && fKey.equals(((HighlightedRange)o).getKey());
246         }
247
248         /*
249          * @see org.eclipse.jface.text.Region#hashCode()
250          */

251         public int hashCode() {
252             return super.hashCode() | fKey.hashCode();
253         }
254     }
255
256     /** Semantic highlighting presenter */
257     private SemanticHighlightingPresenter fPresenter;
258     /** Semantic highlighting reconciler */
259     private SemanticHighlightingReconciler fReconciler;
260
261     /** Semantic highlightings */
262     private SemanticHighlighting[] fSemanticHighlightings;
263     /** Highlightings */
264     private Highlighting[] fHighlightings;
265
266     /** The editor */
267     private JavaEditor fEditor;
268     /** The source viewer */
269     private JavaSourceViewer fSourceViewer;
270     /** The color manager */
271     private IColorManager fColorManager;
272     /** The preference store */
273     private IPreferenceStore fPreferenceStore;
274     /** The source viewer configuration */
275     private JavaSourceViewerConfiguration fConfiguration;
276     /** The presentation reconciler */
277     private JavaPresentationReconciler fPresentationReconciler;
278
279     /** The hard-coded ranges */
280     private HighlightedRange[][] fHardcodedRanges;
281
282     /**
283      * Install the semantic highlighting on the given editor infrastructure
284      *
285      * @param editor The Java editor
286      * @param sourceViewer The source viewer
287      * @param colorManager The color manager
288      * @param preferenceStore The preference store
289      */

290     public void install(JavaEditor editor, JavaSourceViewer sourceViewer, IColorManager colorManager, IPreferenceStore preferenceStore) {
291         fEditor= editor;
292         fSourceViewer= sourceViewer;
293         fColorManager= colorManager;
294         fPreferenceStore= preferenceStore;
295         if (fEditor != null) {
296             fConfiguration= editor.createJavaSourceViewerConfiguration();
297             fPresentationReconciler= (JavaPresentationReconciler) fConfiguration.getPresentationReconciler(sourceViewer);
298         } else {
299             fConfiguration= null;
300             fPresentationReconciler= null;
301         }
302
303         fPreferenceStore.addPropertyChangeListener(this);
304
305         if (isEnabled())
306             enable();
307     }
308
309     /**
310      * Install the semantic highlighting on the given source viewer infrastructure. No reconciliation will be performed.
311      *
312      * @param sourceViewer the source viewer
313      * @param colorManager the color manager
314      * @param preferenceStore the preference store
315      * @param hardcodedRanges the hard-coded ranges to be highlighted
316      */

317     public void install(JavaSourceViewer sourceViewer, IColorManager colorManager, IPreferenceStore preferenceStore, HighlightedRange[][] hardcodedRanges) {
318         fHardcodedRanges= hardcodedRanges;
319         install(null, sourceViewer, colorManager, preferenceStore);
320     }
321
322     /**
323      * Enable semantic highlighting.
324      */

325     private void enable() {
326         initializeHighlightings();
327
328         fPresenter= new SemanticHighlightingPresenter();
329         fPresenter.install(fSourceViewer, fPresentationReconciler);
330
331         if (fEditor != null) {
332             fReconciler= new SemanticHighlightingReconciler();
333             fReconciler.install(fEditor, fSourceViewer, fPresenter, fSemanticHighlightings, fHighlightings);
334         } else {
335             fPresenter.updatePresentation(null, createHardcodedPositions(), new HighlightedPosition[0]);
336         }
337     }
338
339     /**
340      * Computes the hard-coded positions from the hard-coded ranges
341      *
342      * @return the hard-coded positions
343      */

344     private HighlightedPosition[] createHardcodedPositions() {
345         List JavaDoc positions= new ArrayList JavaDoc();
346         for (int i= 0; i < fHardcodedRanges.length; i++) {
347             HighlightedRange range= null;
348             Highlighting hl= null;
349             for (int j= 0; j < fHardcodedRanges[i].length; j++ ) {
350                 hl= getHighlighting(fHardcodedRanges[i][j].getKey());
351                 if (hl.isEnabled()) {
352                     range= fHardcodedRanges[i][j];
353                     break;
354                 }
355             }
356
357             if (range != null)
358                 positions.add(fPresenter.createHighlightedPosition(range.getOffset(), range.getLength(), hl));
359         }
360         return (HighlightedPosition[]) positions.toArray(new HighlightedPosition[positions.size()]);
361     }
362
363     /**
364      * Returns the highlighting corresponding to the given key.
365      *
366      * @param key the highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}
367      * @return the corresponding highlighting
368      */

369     private Highlighting getHighlighting(String JavaDoc key) {
370         for (int i= 0; i < fSemanticHighlightings.length; i++) {
371             SemanticHighlighting semanticHighlighting= fSemanticHighlightings[i];
372             if (key.equals(semanticHighlighting.getPreferenceKey()))
373                 return fHighlightings[i];
374         }
375         return null;
376     }
377
378     /**
379      * Uninstall the semantic highlighting
380      */

381     public void uninstall() {
382         disable();
383
384         if (fPreferenceStore != null) {
385             fPreferenceStore.removePropertyChangeListener(this);
386             fPreferenceStore= null;
387         }
388
389         fEditor= null;
390         fSourceViewer= null;
391         fColorManager= null;
392         fConfiguration= null;
393         fPresentationReconciler= null;
394         fHardcodedRanges= null;
395     }
396
397     /**
398      * Disable semantic highlighting.
399      */

400     private void disable() {
401         if (fReconciler != null) {
402             fReconciler.uninstall();
403             fReconciler= null;
404         }
405
406         if (fPresenter != null) {
407             fPresenter.uninstall();
408             fPresenter= null;
409         }
410
411         if (fSemanticHighlightings != null)
412             disposeHighlightings();
413     }
414
415     /**
416      * @return <code>true</code> iff semantic highlighting is enabled in the preferences
417      */

418     private boolean isEnabled() {
419         return SemanticHighlightings.isEnabled(fPreferenceStore);
420     }
421
422     /**
423      * Initialize semantic highlightings.
424      */

425     private void initializeHighlightings() {
426         fSemanticHighlightings= SemanticHighlightings.getSemanticHighlightings();
427         fHighlightings= new Highlighting[fSemanticHighlightings.length];
428
429         for (int i= 0, n= fSemanticHighlightings.length; i < n; i++) {
430             SemanticHighlighting semanticHighlighting= fSemanticHighlightings[i];
431             String JavaDoc colorKey= SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
432             addColor(colorKey);
433
434             String JavaDoc boldKey= SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
435             int style= fPreferenceStore.getBoolean(boldKey) ? SWT.BOLD : SWT.NORMAL;
436
437             String JavaDoc italicKey= SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
438             if (fPreferenceStore.getBoolean(italicKey))
439                 style |= SWT.ITALIC;
440
441             String JavaDoc strikethroughKey= SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
442             if (fPreferenceStore.getBoolean(strikethroughKey))
443                 style |= TextAttribute.STRIKETHROUGH;
444
445             String JavaDoc underlineKey= SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
446             if (fPreferenceStore.getBoolean(underlineKey))
447                 style |= TextAttribute.UNDERLINE;
448
449             boolean isEnabled= fPreferenceStore.getBoolean(SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting));
450
451             fHighlightings[i]= new Highlighting(new TextAttribute(fColorManager.getColor(PreferenceConverter.getColor(fPreferenceStore, colorKey)), null, style), isEnabled);
452         }
453     }
454
455     /**
456      * Dispose the semantic highlightings.
457      */

458     private void disposeHighlightings() {
459         for (int i= 0, n= fSemanticHighlightings.length; i < n; i++)
460             removeColor(SemanticHighlightings.getColorPreferenceKey(fSemanticHighlightings[i]));
461
462         fSemanticHighlightings= null;
463         fHighlightings= null;
464     }
465
466     /*
467      * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
468      */

469     public void propertyChange(PropertyChangeEvent event) {
470         handlePropertyChangeEvent(event);
471     }
472
473     /**
474      * Handle the given property change event
475      *
476      * @param event The event
477      */

478     private void handlePropertyChangeEvent(PropertyChangeEvent event) {
479         if (fPreferenceStore == null)
480             return; // Uninstalled during event notification
481

482         if (fConfiguration != null)
483             fConfiguration.handlePropertyChangeEvent(event);
484
485         if (SemanticHighlightings.affectsEnablement(fPreferenceStore, event)) {
486             if (isEnabled())
487                 enable();
488             else
489                 disable();
490         }
491
492         if (!isEnabled())
493             return;
494         
495         boolean refreshNeeded= false;
496
497         for (int i= 0, n= fSemanticHighlightings.length; i < n; i++) {
498             SemanticHighlighting semanticHighlighting= fSemanticHighlightings[i];
499
500             String JavaDoc colorKey= SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
501             if (colorKey.equals(event.getProperty())) {
502                 adaptToTextForegroundChange(fHighlightings[i], event);
503                 fPresenter.highlightingStyleChanged(fHighlightings[i]);
504                 refreshNeeded= true;
505                 continue;
506             }
507
508             String JavaDoc boldKey= SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
509             if (boldKey.equals(event.getProperty())) {
510                 adaptToTextStyleChange(fHighlightings[i], event, SWT.BOLD);
511                 fPresenter.highlightingStyleChanged(fHighlightings[i]);
512                 refreshNeeded= true;
513                 continue;
514             }
515
516             String JavaDoc italicKey= SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
517             if (italicKey.equals(event.getProperty())) {
518                 adaptToTextStyleChange(fHighlightings[i], event, SWT.ITALIC);
519                 fPresenter.highlightingStyleChanged(fHighlightings[i]);
520                 refreshNeeded= true;
521                 continue;
522             }
523
524             String JavaDoc strikethroughKey= SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
525             if (strikethroughKey.equals(event.getProperty())) {
526                 adaptToTextStyleChange(fHighlightings[i], event, TextAttribute.STRIKETHROUGH);
527                 fPresenter.highlightingStyleChanged(fHighlightings[i]);
528                 refreshNeeded= true;
529                 continue;
530             }
531
532             String JavaDoc underlineKey= SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
533             if (underlineKey.equals(event.getProperty())) {
534                 adaptToTextStyleChange(fHighlightings[i], event, TextAttribute.UNDERLINE);
535                 fPresenter.highlightingStyleChanged(fHighlightings[i]);
536                 refreshNeeded= true;
537                 continue;
538             }
539
540             String JavaDoc enabledKey= SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting);
541             if (enabledKey.equals(event.getProperty())) {
542                 adaptToEnablementChange(fHighlightings[i], event);
543                 fPresenter.highlightingStyleChanged(fHighlightings[i]);
544                 refreshNeeded= true;
545                 continue;
546             }
547         }
548         
549         if (refreshNeeded && fReconciler != null)
550             fReconciler.refresh();
551     }
552
553     private void adaptToEnablementChange(Highlighting highlighting, PropertyChangeEvent event) {
554         Object JavaDoc value= event.getNewValue();
555         boolean eventValue;
556         if (value instanceof Boolean JavaDoc)
557             eventValue= ((Boolean JavaDoc) value).booleanValue();
558         else if (IPreferenceStore.TRUE.equals(value))
559             eventValue= true;
560         else
561             eventValue= false;
562         highlighting.setEnabled(eventValue);
563     }
564
565     private void adaptToTextForegroundChange(Highlighting highlighting, PropertyChangeEvent event) {
566         RGB rgb= null;
567
568         Object JavaDoc value= event.getNewValue();
569         if (value instanceof RGB)
570             rgb= (RGB) value;
571         else if (value instanceof String JavaDoc)
572             rgb= StringConverter.asRGB((String JavaDoc) value);
573
574         if (rgb != null) {
575
576             String JavaDoc property= event.getProperty();
577             Color color= fColorManager.getColor(property);
578
579             if ((color == null || !rgb.equals(color.getRGB())) && fColorManager instanceof IColorManagerExtension) {
580                 IColorManagerExtension ext= (IColorManagerExtension) fColorManager;
581                 ext.unbindColor(property);
582                 ext.bindColor(property, rgb);
583                 color= fColorManager.getColor(property);
584             }
585
586             TextAttribute oldAttr= highlighting.getTextAttribute();
587             highlighting.setTextAttribute(new TextAttribute(color, oldAttr.getBackground(), oldAttr.getStyle()));
588         }
589     }
590
591     private void adaptToTextStyleChange(Highlighting highlighting, PropertyChangeEvent event, int styleAttribute) {
592         boolean eventValue= false;
593         Object JavaDoc value= event.getNewValue();
594         if (value instanceof Boolean JavaDoc)
595             eventValue= ((Boolean JavaDoc) value).booleanValue();
596         else if (IPreferenceStore.TRUE.equals(value))
597             eventValue= true;
598
599         TextAttribute oldAttr= highlighting.getTextAttribute();
600         boolean activeValue= (oldAttr.getStyle() & styleAttribute) == styleAttribute;
601
602         if (activeValue != eventValue)
603             highlighting.setTextAttribute(new TextAttribute(oldAttr.getForeground(), oldAttr.getBackground(), eventValue ? oldAttr.getStyle() | styleAttribute : oldAttr.getStyle() & ~styleAttribute));
604     }
605
606     private void addColor(String JavaDoc colorKey) {
607         if (fColorManager != null && colorKey != null && fColorManager.getColor(colorKey) == null) {
608             RGB rgb= PreferenceConverter.getColor(fPreferenceStore, colorKey);
609             if (fColorManager instanceof IColorManagerExtension) {
610                 IColorManagerExtension ext= (IColorManagerExtension) fColorManager;
611                 ext.unbindColor(colorKey);
612                 ext.bindColor(colorKey, rgb);
613             }
614         }
615     }
616
617     private void removeColor(String JavaDoc colorKey) {
618         if (fColorManager instanceof IColorManagerExtension)
619             ((IColorManagerExtension) fColorManager).unbindColor(colorKey);
620     }
621
622     /**
623      * Returns this hightlighter's reconciler.
624      *
625      * @return the semantic highlighter reconciler or <code>null</code> if none
626      * @since 3.3
627      */

628     public SemanticHighlightingReconciler getReconciler() {
629         return fReconciler;
630     }
631 }
632
Popular Tags