| /******************************************************************************* |
| * Copyright (c) 2008 Standards for Technology in Automotive Retail and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * David Carver (STAR) - initial api and implementation |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.xsl.ui.internal.style; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.ITypedRegion; |
| import org.eclipse.jface.text.TextAttribute; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StyleRange; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.ui.texteditor.ChainedPreferenceStore; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; |
| import org.eclipse.wst.sse.ui.internal.preferences.ui.ColorHelper; |
| import org.eclipse.wst.sse.ui.internal.provisional.style.AbstractLineStyleProvider; |
| import org.eclipse.wst.sse.ui.internal.provisional.style.Highlighter; |
| import org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider; |
| import org.eclipse.wst.sse.ui.internal.provisional.style.ReconcilerHighlighter; |
| import org.eclipse.wst.sse.ui.internal.util.EditorUtility; |
| import org.eclipse.wst.xml.ui.internal.XMLUIPlugin; |
| import org.eclipse.wst.xml.ui.internal.style.IStyleConstantsXML; |
| import org.eclipse.wst.xsl.ui.internal.XSLUIPlugin; |
| |
| /** |
| * This implements a Syntax Line Style Provider for XSL. It leverages some |
| * information from the XML Syntax Coloring, but adds specific coloring for XSL |
| * specific elements and attributes. |
| * |
| * @author David Carver |
| * @since 1.0 |
| * |
| */ |
| public class LineStyleProviderForXSL extends AbstractLineStyleProvider implements LineStyleProvider { |
| |
| protected IStructuredDocument structuredDocument; |
| protected Highlighter highlighter; |
| private boolean initialized; |
| protected ReconcilerHighlighter recHighlighter = null; |
| |
| private IPreferenceStore xmlPreferenceStore = null; |
| private IPreferenceStore xslPreferenceStore = null; |
| private IPreferenceStore combinedPreferenceStore = null; |
| private IPropertyChangeListener preferenceListener = new PropertyChangeListener(); |
| |
| private class PropertyChangeListener implements IPropertyChangeListener { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) |
| */ |
| public void propertyChange(PropertyChangeEvent event) { |
| // have to do it this way so others can override the method |
| handlePropertyChange(event); |
| } |
| } |
| |
| @Override |
| protected void commonInit(IStructuredDocument document, |
| Highlighter highlighter) { |
| |
| structuredDocument = document; |
| this.highlighter = highlighter; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @seeorg.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider# |
| * prepareRegions(org.eclipse.jface.text.ITypedRegion, int, int, |
| * java.util.Collection) |
| */ |
| @Override |
| public boolean prepareRegions(ITypedRegion typedRegion, |
| int lineRequestStart, int lineRequestLength, Collection holdResults) { |
| final int partitionStartOffset = typedRegion.getOffset(); |
| final int partitionLength = typedRegion.getLength(); |
| IStructuredDocumentRegion structuredDocumentRegion = getDocument() |
| .getRegionAtCharacterOffset(partitionStartOffset); |
| boolean handled = false; |
| |
| handled = prepareTextRegions(structuredDocumentRegion, |
| partitionStartOffset, partitionLength, holdResults); |
| |
| return handled; |
| } |
| |
| /** |
| * @param region |
| * @param start |
| * @param length |
| * @param holdResults |
| * @return |
| */ |
| protected boolean prepareTextRegion(ITextRegionCollection blockedRegion, |
| int partitionStartOffset, int partitionLength, |
| Collection holdResults) { |
| boolean handled = false; |
| final int partitionEndOffset = partitionStartOffset + partitionLength |
| - 1; |
| ITextRegion region = null; |
| ITextRegionList regions = blockedRegion.getRegions(); |
| StyleRange styleRange = null; |
| |
| for (int i = 0; i < regions.size(); i++) { |
| region = regions.get(i); |
| TextAttribute attr = null; |
| TextAttribute previousAttr = null; |
| if (blockedRegion.getStartOffset(region) > partitionEndOffset) |
| break; |
| if (blockedRegion.getEndOffset(region) <= partitionStartOffset) |
| continue; |
| |
| if (region instanceof ITextRegionCollection) { |
| handled = prepareTextRegion((ITextRegionCollection) region, |
| partitionStartOffset, partitionLength, holdResults); |
| } else { |
| |
| attr = getAttributeFor(blockedRegion, region); |
| if (attr != null) { |
| handled = true; |
| styleRange = applyStyleRange(blockedRegion, |
| partitionStartOffset, partitionLength, holdResults, |
| region, styleRange, attr, previousAttr); |
| } else { |
| previousAttr = null; |
| } |
| } |
| } |
| return handled; |
| } |
| |
| private StyleRange applyStyleRange(ITextRegionCollection blockedRegion, |
| int partitionStartOffset, int partitionLength, |
| Collection holdResults, ITextRegion region, StyleRange styleRange, |
| TextAttribute attr, TextAttribute previousAttr) { |
| if (equalsPreviousAttribute(styleRange, attr, previousAttr)) { |
| styleRange.length += region.getLength(); |
| } else { |
| styleRange = createStyleRange(blockedRegion, region, attr, |
| partitionStartOffset, partitionLength); |
| holdResults.add(styleRange); |
| previousAttr = attr; |
| } |
| return styleRange; |
| } |
| |
| private boolean equalsPreviousAttribute(StyleRange styleRange, |
| TextAttribute attr, TextAttribute previousAttr) { |
| return (styleRange != null) && (previousAttr != null) |
| && (previousAttr.equals(attr)); |
| } |
| |
| protected boolean prepareTextRegions( |
| IStructuredDocumentRegion structuredDocumentRegion, |
| int partitionStartOffset, int partitionLength, |
| Collection holdResults) { |
| boolean handled = false; |
| final int partitionEndOffset = partitionStartOffset + partitionLength |
| - 1; |
| while (structuredDocumentRegion != null |
| && structuredDocumentRegion.getStartOffset() <= partitionEndOffset) { |
| ITextRegion region = null; |
| ITextRegionList regions = structuredDocumentRegion.getRegions(); |
| |
| StyleRange styleRange = null; |
| for (int i = 0; i < regions.size(); i++) { |
| region = regions.get(i); |
| TextAttribute attr = null; |
| TextAttribute previousAttr = null; |
| if (structuredDocumentRegion.getStartOffset(region) > partitionEndOffset) |
| break; |
| if (structuredDocumentRegion.getEndOffset(region) <= partitionStartOffset) |
| continue; |
| |
| if (region instanceof ITextRegionCollection) { |
| boolean handledCollection = (prepareTextRegion( |
| (ITextRegionCollection) region, |
| partitionStartOffset, partitionLength, holdResults)); |
| handled = (!handled) ? handledCollection : handled; |
| } else { |
| attr = getAttributeFor(structuredDocumentRegion, region); |
| if (attr == null) { |
| previousAttr = null; |
| } else { |
| handled = true; |
| styleRange = applyStyleRange(structuredDocumentRegion, |
| partitionStartOffset, partitionLength, |
| holdResults, region, styleRange, attr, |
| previousAttr); |
| } |
| } |
| } |
| structuredDocumentRegion = structuredDocumentRegion.getNext(); |
| } |
| return handled; |
| } |
| |
| private StyleRange createStyleRange( |
| ITextRegionCollection textRegionCollection, ITextRegion textRegion, |
| TextAttribute attr, int startOffset, int length) { |
| int startingOffset = textRegionCollection.getStartOffset(textRegion); |
| if (startingOffset < startOffset) |
| startingOffset = startOffset; |
| |
| int textEnd = startingOffset |
| + textRegionCollection.getText(textRegion).length(); |
| int maxOffset = startOffset + length; |
| int endingOffset = textRegionCollection.getEndOffset(textRegion); |
| |
| if (textEnd < endingOffset) |
| endingOffset = textEnd; |
| if (endingOffset > maxOffset) |
| endingOffset = maxOffset; |
| StyleRange result = new StyleRange(startingOffset, endingOffset |
| - startingOffset, attr.getForeground(), attr.getBackground(), |
| attr.getStyle()); |
| if ((attr.getStyle() & TextAttribute.STRIKETHROUGH) != 0) { |
| result.strikeout = true; |
| } |
| if ((attr.getStyle() & TextAttribute.UNDERLINE) != 0) { |
| result.underline = true; |
| } |
| return result; |
| |
| } |
| |
| @Override |
| protected TextAttribute getAttributeFor(ITextRegionCollection collection, |
| ITextRegion textRegion) { |
| if (textRegion == null) { |
| return XMLTextAttributeMap.getInstance() |
| .getTextAttributeMap().get(IStyleConstantsXML.CDATA_TEXT); |
| } |
| |
| String type = textRegion.getType(); |
| if (collection.getText().contains("xsl:")) { |
| return getXSLAttribute(type); |
| } |
| |
| return getXMLAttribute(type); |
| } |
| |
| private TextAttribute getXSLAttribute(String type) { |
| Map<String, String> regionMap = XSLRegionMap.getInstance() |
| .getRegionMap(); |
| Map<String, TextAttribute> textAttributes = XSLTextAttributeMap |
| .getInstance().getTextAttributeMap(); |
| return getTextAttribute(type, regionMap, textAttributes); |
| } |
| |
| private TextAttribute getXMLAttribute(String type) { |
| Map<String, String> regionMap = XMLRegionMap.getInstance() |
| .getRegionMap(); |
| Map<String, TextAttribute> textAttributes = XMLTextAttributeMap |
| .getInstance().getTextAttributeMap(); |
| |
| return getTextAttribute(type, regionMap, textAttributes); |
| } |
| |
| private TextAttribute getTextAttribute(String type, |
| Map<String, String> regionMap, |
| Map<String, TextAttribute> textAttrMap) { |
| return textAttrMap.get(regionMap.get(type)); |
| } |
| |
| @Override |
| protected void handlePropertyChange(PropertyChangeEvent event) { |
| String styleKey = null; |
| if (event == null) |
| return; |
| |
| String prefKey = event.getProperty(); |
| // check if preference changed is a style preference |
| if (IStyleConstantsXSL.TAG_NAME.equals(prefKey)) { |
| styleKey = IStyleConstantsXSL.TAG_NAME; |
| } |
| if (IStyleConstantsXSL.TAG_BORDER.equals(prefKey)) { |
| styleKey = IStyleConstantsXSL.TAG_BORDER; |
| } |
| if (IStyleConstantsXSL.TAG_ATTRIBUTE_NAME.equals(prefKey)) { |
| styleKey = IStyleConstantsXSL.TAG_ATTRIBUTE_NAME; |
| } |
| if (IStyleConstantsXSL.TAG_ATTRIBUTE_VALUE.equals(prefKey)) { |
| styleKey = IStyleConstantsXSL.TAG_ATTRIBUTE_VALUE; |
| } |
| if (styleKey == null) |
| return; |
| |
| if (styleKey != null) { |
| // overwrite style preference with new value |
| addTextAttribute(styleKey); |
| } |
| |
| if(recHighlighter != null) |
| recHighlighter.refreshDisplay(); |
| |
| } |
| |
| /** |
| * Looks up the colorKey in the preference store and adds the style |
| * information to list of TextAttributes |
| * |
| * @param colorKey |
| */ |
| @Override |
| protected void addTextAttribute(String colorKey) { |
| if (getColorPreferences() != null) { |
| String prefString = getColorPreferences().getString(colorKey); |
| String[] stylePrefs = ColorHelper.unpackStylePreferences(prefString); |
| if (stylePrefs != null) { |
| RGB foreground = ColorHelper.toRGB(stylePrefs[0]); |
| RGB background = ColorHelper.toRGB(stylePrefs[1]); |
| boolean bold = Boolean.valueOf(stylePrefs[2]).booleanValue(); |
| boolean italic = Boolean.valueOf(stylePrefs[3]).booleanValue(); |
| boolean strikethrough = Boolean.valueOf(stylePrefs[4]).booleanValue(); |
| boolean underline = Boolean.valueOf(stylePrefs[5]).booleanValue(); |
| int style = SWT.NORMAL; |
| if (bold) { |
| style = style | SWT.BOLD; |
| } |
| if (italic) { |
| style = style | SWT.ITALIC; |
| } |
| if (strikethrough) { |
| style = style | TextAttribute.STRIKETHROUGH; |
| } |
| if (underline) { |
| style = style | TextAttribute.UNDERLINE; |
| } |
| |
| updateTextAttribute(colorKey, foreground, background, style); |
| } |
| } |
| } |
| |
| private void updateTextAttribute(String colorKey, RGB foreground, |
| RGB background, int style) { |
| TextAttribute createTextAttribute = createTextAttribute(foreground, background, style); |
| |
| TextAttribute textAttribute = |
| XSLTextAttributeMap.getInstance().getTextAttributeMap().get(colorKey); |
| if (textAttribute != null) { |
| XSLTextAttributeMap.getInstance().getTextAttributeMap().put(colorKey, createTextAttribute); |
| return; |
| } |
| |
| textAttribute = |
| XMLTextAttributeMap.getInstance().getTextAttributeMap().get(colorKey); |
| if (textAttribute != null) { |
| XMLTextAttributeMap.getInstance().getTextAttributeMap().put(colorKey, createTextAttribute); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.wst.sse.ui.internal.provisional.style.LineStyleProvider#init |
| * (org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument, |
| * org.eclipse.wst.sse.ui.internal.provisional.style.Highlighter) |
| */ |
| @Override |
| public void init(IStructuredDocument document, Highlighter highlighter) { |
| commonInit(structuredDocument, highlighter); |
| |
| if (isInitialized()) |
| return; |
| |
| registerPreferenceManager(); |
| |
| setInitialized(true); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.wst.sse.ui.internal.provisional.style.AbstractLineStyleProvider |
| * # |
| * init(org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument |
| * , org.eclipse.jface.text.source.ISourceViewer) |
| */ |
| @Override |
| public void init(IStructuredDocument structuredDocument, |
| ISourceViewer sourceViewer) { |
| init(structuredDocument, (Highlighter) null); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.wst.sse.ui.internal.provisional.style.AbstractLineStyleProvider |
| * # |
| * init(org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument |
| * , |
| * org.eclipse.wst.sse.ui.internal.provisional.style.ReconcilerHighlighter) |
| */ |
| @Override |
| public void init(IStructuredDocument structuredDocument, |
| ReconcilerHighlighter highlighter) { |
| this.structuredDocument = structuredDocument; |
| recHighlighter = highlighter; |
| |
| if (isInitialized()) |
| return; |
| |
| registerPreferenceManager(); |
| |
| setInitialized(true); |
| } |
| |
| @Override |
| public void release() { |
| unRegisterPreferenceManager(); |
| setInitialized(false); |
| } |
| |
| @Override |
| protected void unRegisterPreferenceManager() { |
| IPreferenceStore pref = getColorPreferences(); |
| if (pref != null) { |
| pref.removePropertyChangeListener(preferenceListener); |
| } |
| } |
| |
| @Override |
| protected void registerPreferenceManager() { |
| IPreferenceStore pref = getColorPreferences(); |
| if (pref != null) { |
| pref.addPropertyChangeListener(preferenceListener ); |
| } |
| } |
| |
| /** |
| * Returns the initialized. |
| * |
| * @return boolean |
| */ |
| @Override |
| public boolean isInitialized() { |
| return initialized; |
| } |
| |
| /** |
| * Sets the initialized. |
| * |
| * @param initialized |
| * The initialized to set |
| */ |
| private void setInitialized(boolean initialized) { |
| this.initialized = initialized; |
| } |
| |
| @Override |
| protected IStructuredDocument getDocument() { |
| return structuredDocument; |
| } |
| |
| /** |
| */ |
| @Override |
| protected Highlighter getHighlighter() { |
| return highlighter; |
| } |
| |
| @Override |
| protected IPreferenceStore getColorPreferences() { |
| if (xmlPreferenceStore == null) { |
| xmlPreferenceStore = XMLUIPlugin.getDefault().getPreferenceStore(); |
| } |
| if (xslPreferenceStore == null) { |
| xslPreferenceStore = XSLUIPlugin.getDefault().getPreferenceStore(); |
| } |
| combinedPreferenceStore = new ChainedPreferenceStore(new IPreferenceStore[] { xmlPreferenceStore, xslPreferenceStore }); |
| return combinedPreferenceStore; |
| } |
| |
| @Override |
| protected TextAttribute createTextAttribute(RGB foreground, RGB background, boolean bold) { |
| return new TextAttribute((foreground != null) ? EditorUtility.getColor(foreground) : null, (background != null) ? EditorUtility.getColor(background) : null, bold ? SWT.BOLD : SWT.NORMAL); |
| } |
| |
| @Override |
| protected TextAttribute createTextAttribute(RGB foreground, RGB background, int style) { |
| return new TextAttribute((foreground != null) ? EditorUtility.getColor(foreground) : null, (background != null) ? EditorUtility.getColor(background) : null, style); |
| } |
| |
| @Override |
| protected TextAttribute getAttributeFor(ITextRegion region) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| @Override |
| protected void loadColors() { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| } |