blob: 2b80125bf44eb8536fe535fb4cf60b0fd0e27a90 [file] [log] [blame]
david_williamscfdb2cd2004-11-11 08:37:49 +00001/*******************************************************************************
nitind68e6e502008-04-21 22:43:09 +00002 * Copyright (c) 2001, 2008 IBM Corporation and others.
david_williamscfdb2cd2004-11-11 08:37:49 +00003 * 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 * Jens Lukowski/Innoopract - initial renaming/restructuring
11 *
12 *******************************************************************************/
david_williams4ad020f2005-04-18 08:00:30 +000013package org.eclipse.wst.sse.ui.internal.provisional.style;
david_williamscfdb2cd2004-11-11 08:37:49 +000014
15import java.util.Collection;
16import java.util.HashMap;
17
18import org.eclipse.jface.preference.IPreferenceStore;
19import org.eclipse.jface.text.ITypedRegion;
20import org.eclipse.jface.text.TextAttribute;
nitind68e6e502008-04-21 22:43:09 +000021import org.eclipse.jface.text.source.ISourceViewer;
david_williamscfdb2cd2004-11-11 08:37:49 +000022import org.eclipse.jface.util.IPropertyChangeListener;
23import org.eclipse.jface.util.PropertyChangeEvent;
24import org.eclipse.swt.SWT;
25import org.eclipse.swt.custom.StyleRange;
26import org.eclipse.swt.graphics.RGB;
david_williams4ad020f2005-04-18 08:00:30 +000027import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
28import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
29import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
30import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection;
31import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
david_williams2aecf082005-04-13 05:03:21 +000032import org.eclipse.wst.sse.core.internal.util.Debug;
david_williamsf3680f02005-04-13 22:43:54 +000033import org.eclipse.wst.sse.ui.internal.preferences.ui.ColorHelper;
34import org.eclipse.wst.sse.ui.internal.util.EditorUtility;
david_williamscfdb2cd2004-11-11 08:37:49 +000035
36
37public abstract class AbstractLineStyleProvider {
38 private class PropertyChangeListener implements IPropertyChangeListener {
39 /*
40 * (non-Javadoc)
41 *
42 * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
43 */
44 public void propertyChange(PropertyChangeEvent event) {
45 // have to do it this way so others can override the method
46 handlePropertyChange(event);
47 }
48 }
49
nitind68e6e502008-04-21 22:43:09 +000050 protected IStructuredDocument fDocument;
51 protected Highlighter fHighlighter;
david_williamscfdb2cd2004-11-11 08:37:49 +000052 private boolean fInitialized;
nitind68e6e502008-04-21 22:43:09 +000053 protected PropertyChangeListener fPreferenceListener = new PropertyChangeListener();
david_williamscfdb2cd2004-11-11 08:37:49 +000054
nitind68e6e502008-04-21 22:43:09 +000055 //private ISourceViewer fSourceViewer = null;
56 protected ReconcilerHighlighter fRecHighlighter = null;
57
58 /** Contains all text attributes pertaining to this line style provider */
david_williamscfdb2cd2004-11-11 08:37:49 +000059 private HashMap fTextAttributes = null;
60
61 // we keep track of LogMessage to avoid writing hundreds of messages,
62 // but still give a hint that something is wrong with attributeProviders
63 // and/or regions.
64 // It's only written in the case of a program error, but there's no use
65 // adding
66 // salt to the wound.
nitindf8e77632005-09-07 23:49:25 +000067 // private boolean wroteOneLogMessage;
david_williamscfdb2cd2004-11-11 08:37:49 +000068 /**
69 */
70 protected AbstractLineStyleProvider() {
71 }
72
david_williamscfdb2cd2004-11-11 08:37:49 +000073 /**
74 * Looks up the colorKey in the preference store and adds the style
75 * information to list of TextAttributes
76 *
77 * @param colorKey
78 */
79 protected void addTextAttribute(String colorKey) {
80 if (getColorPreferences() != null) {
nitindf8e77632005-09-07 23:49:25 +000081 String prefString = getColorPreferences().getString(colorKey);
david_williamscfdb2cd2004-11-11 08:37:49 +000082 String[] stylePrefs = ColorHelper.unpackStylePreferences(prefString);
83 if (stylePrefs != null) {
84 RGB foreground = ColorHelper.toRGB(stylePrefs[0]);
85 RGB background = ColorHelper.toRGB(stylePrefs[1]);
86 boolean bold = Boolean.valueOf(stylePrefs[2]).booleanValue();
nitind215bf3b2006-12-12 07:09:12 +000087 boolean italic = Boolean.valueOf(stylePrefs[3]).booleanValue();
88 boolean strikethrough = Boolean.valueOf(stylePrefs[4]).booleanValue();
89 boolean underline = Boolean.valueOf(stylePrefs[5]).booleanValue();
90 int style = SWT.NORMAL;
91 if (bold) {
92 style = style | SWT.BOLD;
93 }
94 if (italic) {
95 style = style | SWT.ITALIC;
96 }
97 if (strikethrough) {
98 style = style | TextAttribute.STRIKETHROUGH;
99 }
100 if (underline) {
101 style = style | TextAttribute.UNDERLINE;
102 }
103
104 TextAttribute createTextAttribute = createTextAttribute(foreground, background, style);
105 getTextAttributes().put(colorKey, createTextAttribute);
david_williamscfdb2cd2004-11-11 08:37:49 +0000106 }
107 }
108 }
109
110 protected void commonInit(IStructuredDocument document, Highlighter highlighter) {
111
112 fDocument = document;
113 fHighlighter = highlighter;
114 }
115
116 /**
117 * this version does "trim" regions to match request
118 */
nitindf8e77632005-09-07 23:49:25 +0000119 private StyleRange createStyleRange(ITextRegionCollection flatNode, ITextRegion region, TextAttribute attr, int startOffset, int length) {
david_williamscfdb2cd2004-11-11 08:37:49 +0000120 int start = flatNode.getStartOffset(region);
121 if (start < startOffset)
122 start = startOffset;
nitind68e6e502008-04-21 22:43:09 +0000123
124 // Base the text end offset off of the, possibly adjusted, start
nitindc3f7f2e2009-04-22 06:36:27 +0000125 int textEnd = start + region.getTextLength();
david_williamscfdb2cd2004-11-11 08:37:49 +0000126 int maxOffset = startOffset + length;
nitind68e6e502008-04-21 22:43:09 +0000127
128 int end = flatNode.getEndOffset(region);
129 // Use the end of the text in the region to avoid applying background color to trailing whitespace
130 if(textEnd < end)
131 end = textEnd;
david_williamscfdb2cd2004-11-11 08:37:49 +0000132 // instead of end-start?
133 if (end > maxOffset)
134 end = maxOffset;
135 StyleRange result = new StyleRange(start, end - start, attr.getForeground(), attr.getBackground(), attr.getStyle());
nitind215bf3b2006-12-12 07:09:12 +0000136 if((attr.getStyle() & TextAttribute.STRIKETHROUGH) != 0) {
137 result.strikeout = true;
138 }
139 if((attr.getStyle() & TextAttribute.UNDERLINE) != 0) {
140 result.underline = true;
141 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000142 return result;
143
144 }
145
146 protected TextAttribute createTextAttribute(RGB foreground, RGB background, boolean bold) {
147 return new TextAttribute((foreground != null) ? EditorUtility.getColor(foreground) : null, (background != null) ? EditorUtility.getColor(background) : null, bold ? SWT.BOLD : SWT.NORMAL);
148 }
149
nitind215bf3b2006-12-12 07:09:12 +0000150 protected TextAttribute createTextAttribute(RGB foreground, RGB background, int style) {
151 return new TextAttribute((foreground != null) ? EditorUtility.getColor(foreground) : null, (background != null) ? EditorUtility.getColor(background) : null, style);
152 }
153
nitindf8e77632005-09-07 23:49:25 +0000154 abstract protected TextAttribute getAttributeFor(ITextRegion region);
nitind85be41e2007-10-15 19:27:03 +0000155
156 protected TextAttribute getAttributeFor(ITextRegionCollection collection, ITextRegion region) {
157 return getAttributeFor(region);
158 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000159
nitindf8e77632005-09-07 23:49:25 +0000160 abstract protected IPreferenceStore getColorPreferences();
david_williamscfdb2cd2004-11-11 08:37:49 +0000161
162 protected IStructuredDocument getDocument() {
163 return fDocument;
164 }
nsandonatoe955e0f2008-10-06 16:08:20 +0000165
166 public void setDocument(IStructuredDocument document) {
167 fDocument = document;
168 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000169
170 /**
171 */
172 protected Highlighter getHighlighter() {
173 return fHighlighter;
174 }
175
176 /**
david_williamscfdb2cd2004-11-11 08:37:49 +0000177 * Returns the hashtable containing all the text attributes for this line
178 * style provider. Lazily creates a hashtable if one has not already been
179 * created.
180 *
181 * @return
182 */
183 protected HashMap getTextAttributes() {
184 if (fTextAttributes == null) {
185 fTextAttributes = new HashMap();
nitindf8e77632005-09-07 23:49:25 +0000186 loadColors();
david_williamscfdb2cd2004-11-11 08:37:49 +0000187 }
188 return fTextAttributes;
189 }
190
191 protected void handlePropertyChange(PropertyChangeEvent event) {
192 // force a full update of the text viewer
nitind68e6e502008-04-21 22:43:09 +0000193 if(fRecHighlighter != null)
194 fRecHighlighter.refreshDisplay();
david_williamscfdb2cd2004-11-11 08:37:49 +0000195 }
196
197 public void init(IStructuredDocument structuredDocument, Highlighter highlighter) {
198
199 commonInit(structuredDocument, highlighter);
200
201 if (isInitialized())
202 return;
203
204 registerPreferenceManager();
205
206 setInitialized(true);
207 }
nitind68e6e502008-04-21 22:43:09 +0000208
209 public void init(IStructuredDocument structuredDocument, ISourceViewer sourceViewer) {
210 init(structuredDocument, (Highlighter) null);
211 }
212
213 public void init(IStructuredDocument structuredDocument, ReconcilerHighlighter highlighter) {
214 fDocument = structuredDocument;
215 fRecHighlighter = highlighter;
216
217 if(isInitialized())
218 return;
219
220 registerPreferenceManager();
221
222 setInitialized(true);
223 }
david_williamscfdb2cd2004-11-11 08:37:49 +0000224
225 /**
nitind85be41e2007-10-15 19:27:03 +0000226 * @deprecated - left because it's public, but we aren't adapters any more
david_williamscfdb2cd2004-11-11 08:37:49 +0000227 */
228 public boolean isAdapterForType(java.lang.Object type) {
nitind85be41e2007-10-15 19:27:03 +0000229 return type == LineStyleProvider.class;
david_williamscfdb2cd2004-11-11 08:37:49 +0000230 }
231
232 /**
233 * Returns the initialized.
234 *
235 * @return boolean
236 */
237 public boolean isInitialized() {
238 return fInitialized;
239 }
nitindf8e77632005-09-07 23:49:25 +0000240
241 abstract protected void loadColors();
david_williamscfdb2cd2004-11-11 08:37:49 +0000242
243 public boolean prepareRegions(ITypedRegion typedRegion, int lineRequestStart, int lineRequestLength, Collection holdResults) {
244 final int partitionStartOffset = typedRegion.getOffset();
245 final int partitionLength = typedRegion.getLength();
246 IStructuredDocumentRegion structuredDocumentRegion = getDocument().getRegionAtCharacterOffset(partitionStartOffset);
247 boolean handled = false;
248
249 handled = prepareTextRegions(structuredDocumentRegion, partitionStartOffset, partitionLength, holdResults);
250
251 return handled;
252 }
253
254 /**
255 * @param region
256 * @param start
257 * @param length
258 * @param holdResults
259 * @return
260 */
261 private boolean prepareTextRegion(ITextRegionCollection blockedRegion, int partitionStartOffset, int partitionLength, Collection holdResults) {
262 boolean handled = false;
263 final int partitionEndOffset = partitionStartOffset + partitionLength - 1;
264 ITextRegion region = null;
265 ITextRegionList regions = blockedRegion.getRegions();
266 int nRegions = regions.size();
267 StyleRange styleRange = null;
268 for (int i = 0; i < nRegions; i++) {
269 region = regions.get(i);
270 TextAttribute attr = null;
271 TextAttribute previousAttr = null;
272 if (blockedRegion.getStartOffset(region) > partitionEndOffset)
273 break;
274 if (blockedRegion.getEndOffset(region) <= partitionStartOffset)
275 continue;
276
277 if (region instanceof ITextRegionCollection) {
278 handled = prepareTextRegion((ITextRegionCollection) region, partitionStartOffset, partitionLength, holdResults);
279 } else {
280
nitind85be41e2007-10-15 19:27:03 +0000281 attr = getAttributeFor(blockedRegion, region);
david_williamscfdb2cd2004-11-11 08:37:49 +0000282 if (attr != null) {
283 handled = true;
284 // if this region's attr is the same as previous one, then
285 // just adjust the previous style range
286 // instead of creating a new instance of one
287 // note: to use 'equals' in this case is important, since
288 // sometimes
289 // different instances of attributes are associated with a
290 // region, even the
291 // the attribute has the same values.
292 // TODO: this needs to be improved to handle readonly
293 // regions correctly
294 if ((styleRange != null) && (previousAttr != null) && (previousAttr.equals(attr))) {
295 styleRange.length += region.getLength();
296 } else {
297 styleRange = createStyleRange(blockedRegion, region, attr, partitionStartOffset, partitionLength);
298 holdResults.add(styleRange);
299 // technically speaking, we don't need to update
300 // previousAttr
301 // in the other case, because the other case is when
302 // it hasn't changed
303 previousAttr = attr;
304 }
305 } else {
306 previousAttr = null;
307 }
308 }
309 }
310 return handled;
311 }
312
313 private boolean prepareTextRegions(IStructuredDocumentRegion structuredDocumentRegion, int partitionStartOffset, int partitionLength, Collection holdResults) {
314 boolean handled = false;
315 final int partitionEndOffset = partitionStartOffset + partitionLength - 1;
316 while (structuredDocumentRegion != null && structuredDocumentRegion.getStartOffset() <= partitionEndOffset) {
317 ITextRegion region = null;
318 ITextRegionList regions = structuredDocumentRegion.getRegions();
319 int nRegions = regions.size();
320 StyleRange styleRange = null;
321 for (int i = 0; i < nRegions; i++) {
322 region = regions.get(i);
323 TextAttribute attr = null;
324 TextAttribute previousAttr = null;
325 if (structuredDocumentRegion.getStartOffset(region) > partitionEndOffset)
326 break;
327 if (structuredDocumentRegion.getEndOffset(region) <= partitionStartOffset)
328 continue;
329
330 if (region instanceof ITextRegionCollection) {
nitind68e6e502008-04-21 22:43:09 +0000331 boolean handledCollection = (prepareTextRegion((ITextRegionCollection) region, partitionStartOffset, partitionLength, holdResults));
332 handled = (!handled) ? handledCollection : handled;
david_williamscfdb2cd2004-11-11 08:37:49 +0000333 } else {
334
nitind85be41e2007-10-15 19:27:03 +0000335 attr = getAttributeFor(structuredDocumentRegion, region);
david_williamscfdb2cd2004-11-11 08:37:49 +0000336 if (attr != null) {
337 handled = true;
338 // if this region's attr is the same as previous one,
339 // then just adjust the previous style range
340 // instead of creating a new instance of one
341 // note: to use 'equals' in this case is important,
342 // since sometimes
343 // different instances of attributes are associated
344 // with a region, even the
345 // the attribute has the same values.
346 // TODO: this needs to be improved to handle readonly
347 // regions correctly
348 if ((styleRange != null) && (previousAttr != null) && (previousAttr.equals(attr))) {
349 styleRange.length += region.getLength();
350 } else {
351 styleRange = createStyleRange(structuredDocumentRegion, region, attr, partitionStartOffset, partitionLength);
352 holdResults.add(styleRange);
353 // technically speaking, we don't need to update
354 // previousAttr
355 // in the other case, because the other case is
356 // when it hasn't changed
357 previousAttr = attr;
358 }
359 } else {
360 previousAttr = null;
361 }
362 }
363
364 if (Debug.syntaxHighlighting && !handled) {
365 System.out.println("not handled in prepareRegions"); //$NON-NLS-1$
366 }
367 }
368 structuredDocumentRegion = structuredDocumentRegion.getNext();
369 }
370 return handled;
371 }
372
nitind68e6e502008-04-21 22:43:09 +0000373 protected void registerPreferenceManager() {
david_williamscfdb2cd2004-11-11 08:37:49 +0000374 IPreferenceStore pref = getColorPreferences();
375 if (pref != null) {
376 pref.addPropertyChangeListener(fPreferenceListener);
377 }
378 }
379
380 public void release() {
381 unRegisterPreferenceManager();
nitindf8e77632005-09-07 23:49:25 +0000382 if (fTextAttributes != null) {
383 fTextAttributes.clear();
384 fTextAttributes = null;
385 }
amywuc39f3462007-01-24 01:20:19 +0000386 setInitialized(false);
david_williamscfdb2cd2004-11-11 08:37:49 +0000387 }
388
389 /**
390 * Sets the initialized.
391 *
392 * @param initialized
393 * The initialized to set
394 */
nitindf8e77632005-09-07 23:49:25 +0000395 private void setInitialized(boolean initialized) {
david_williamscfdb2cd2004-11-11 08:37:49 +0000396 this.fInitialized = initialized;
397 }
398
nitind68e6e502008-04-21 22:43:09 +0000399 protected void unRegisterPreferenceManager() {
david_williamscfdb2cd2004-11-11 08:37:49 +0000400 IPreferenceStore pref = getColorPreferences();
401 if (pref != null) {
402 pref.removePropertyChangeListener(fPreferenceListener);
403 }
404 }
405}