| /******************************************************************************* |
| * Copyright (c) 2001, 2004 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.ui.internal.provisional.style; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.IDocumentExtension3; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.ITextViewerExtension5; |
| import org.eclipse.jface.text.ITypedRegion; |
| import org.eclipse.jface.text.Region; |
| import org.eclipse.jface.text.TextUtilities; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.swt.custom.LineStyleEvent; |
| import org.eclipse.swt.custom.StyleRange; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| import org.eclipse.wst.sse.core.internal.util.Debug; |
| import org.eclipse.wst.sse.ui.internal.ExtendedConfigurationBuilder; |
| import org.eclipse.wst.sse.ui.internal.Logger; |
| import org.eclipse.wst.sse.ui.internal.SSEUIPlugin; |
| import org.eclipse.wst.sse.ui.internal.preferences.EditorPreferenceNames; |
| import org.eclipse.wst.sse.ui.internal.util.EditorUtility; |
| |
| /** |
| * This class is to directly mediate between the Structured Document data |
| * structure and the text widget's text and events. It assumes there only the |
| * model is interested in text events, and all other views will work from that |
| * model. Changes to the text widgets input can cause changes in the model, |
| * which in turn cause changes to the widget's display. |
| * |
| */ |
| public class Highlighter implements IHighlighter { |
| |
| /** |
| * A utility class to do various color manipulations |
| */ |
| private class YUV_RGBConverter { |
| /** |
| * This class "holds" the YUV values corresponding to RGB color |
| */ |
| private class YUV { |
| |
| class NormalizedRGB { |
| double blue; |
| double green; |
| private final double maxRGB = 256.0; |
| double red; |
| |
| public NormalizedRGB(RGB rgb) { |
| // first normalize to between 0 - 1 |
| red = rgb.red / maxRGB; |
| green = rgb.green / maxRGB; |
| blue = rgb.blue / maxRGB; |
| |
| red = gammaNormalized(red); |
| green = gammaNormalized(green); |
| blue = gammaNormalized(blue); |
| |
| } |
| } |
| |
| private NormalizedRGB normalizedRGB; |
| |
| RGB originalRGB; |
| private double u = -1; |
| private double v = -1; |
| private double y = -1; |
| |
| private YUV() { |
| super(); |
| } |
| |
| public YUV(double y, double u, double v) { |
| this(); |
| this.y = y; |
| this.u = u; |
| this.v = v; |
| } |
| |
| public YUV(RGB rgb) { |
| this(); |
| originalRGB = rgb; |
| normalizedRGB = new NormalizedRGB(rgb); |
| // force calculations |
| getY(); |
| getV(); |
| getU(); |
| } |
| |
| /** |
| * normalize to "average" gamma 2.2222 or 1/0.45 |
| */ |
| double gammaNormalized(double colorComponent) { |
| if (colorComponent < 0.018) { |
| return colorComponent * 0.45; |
| } |
| else { |
| return 1.099 * Math.pow(colorComponent, 0.45) - 0.099; |
| } |
| } |
| |
| /** |
| * @return RGB based on original RGB and current YUV values; |
| */ |
| public RGB getRGB() { |
| RGB result = null; |
| double r = getY() + 1.14 * getV(); |
| double g = getY() - 0.395 * getU() - 0.58 * getV(); |
| double b = getY() + 2.032 * getU(); |
| |
| int red = (int) (inverseGammaNormalized(r) * 256); |
| int green = (int) (inverseGammaNormalized(g) * 256); |
| int blue = (int) (inverseGammaNormalized(b) * 256); |
| if (red < 0) |
| red = 0; |
| else if (red > 255) |
| red = 255; |
| if (green < 0) |
| green = 0; |
| else if (green > 255) |
| green = 255; |
| if (blue < 0) |
| blue = 0; |
| else if (blue > 255) |
| blue = 255; |
| |
| result = new RGB(red, green, blue); |
| return result; |
| } |
| |
| public double getU() { |
| if (u == -1) { |
| u = 0.4949 * (normalizedRGB.blue - getY()); |
| } |
| return u; |
| |
| } |
| |
| public double getV() { |
| if (v == -1) { |
| v = 0.877 * (normalizedRGB.red - getY()); |
| } |
| return v; |
| } |
| |
| public double getY() { |
| if (y == -1) { |
| y = 0.299 * normalizedRGB.red + 0.587 * normalizedRGB.green + 0.114 * normalizedRGB.blue; |
| } |
| return y; |
| } |
| |
| double inverseGammaNormalized(double colorComponent) { |
| if (colorComponent < 0.018) { |
| return colorComponent * .222; |
| } |
| else { |
| return Math.pow(((.9099 * colorComponent + 0.09)), 2.22); |
| } |
| } |
| |
| } |
| |
| public YUV_RGBConverter() { |
| super(); |
| } |
| |
| public double calculateYComponent(Color targetColor) { |
| return new YUV(targetColor.getRGB()).getY(); |
| } |
| |
| public RGB transformRGB(RGB originalRGB, double scaleFactor, double target) { |
| RGB transformedRGB = null; |
| // CCIR601 yuv = new CCIR601(originalRGB); |
| YUV yuv = new YUV(originalRGB); |
| double y = yuv.getY(); |
| // zero is black, one is white |
| if (y < target) { |
| // is "dark" make lighter |
| y = y + ((target - y) * scaleFactor); |
| } |
| else { |
| // is "light" make darker |
| y = y - ((y - target) * scaleFactor); |
| } |
| // yuv.setY(y); |
| YUV newYUV = new YUV(y, yuv.getU(), yuv.getV()); |
| // CCIR601 newYUV = new CCIR601(y, yuv.getCb601(), |
| // yuv.getCr601()); |
| transformedRGB = newYUV.getRGB(); |
| return transformedRGB; |
| } |
| |
| public RGB transformRGBToGrey(RGB originalRGB, double scaleFactor, double target) { |
| RGB transformedRGB = null; |
| // we left the "full" API method signature, but this |
| // version does not take into account originalRGB, though |
| // it might someday. |
| // for now, we'll simply make the new RGB grey, either a little |
| // lighter, or a little darker than background. |
| double y = 0; |
| double mid = 0.5; |
| // zero is black, one is white |
| if (target < mid) { |
| // is "dark" make lighter |
| y = target + scaleFactor; |
| } |
| else { |
| // is "light" make darker |
| y = target - scaleFactor; |
| } |
| int c = (int) Math.round(y * 255); |
| // just to gaurd against mis-use, or scale's values greater |
| // than mid point (and possibly rounding error) |
| if (c > 255) |
| c = 255; |
| if (c < 0) |
| c = 0; |
| transformedRGB = new RGB(c, c, c); |
| return transformedRGB; |
| } |
| } |
| |
| private final boolean DEBUG = false; |
| private final StyleRange[] EMPTY_STYLE_RANGE = new StyleRange[0]; |
| private static final String LINE_STYLE_PROVIDER_EXTENDED_ID = "linestyleprovider"; //$NON-NLS-1$ |
| |
| private IPropertyChangeListener fForegroundScaleListener = new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (EditorPreferenceNames.READ_ONLY_FOREGROUND_SCALE.equals(event.getProperty())) { |
| IPreferenceStore editorStore = SSEUIPlugin.getDefault().getPreferenceStore(); |
| readOnlyForegroundScaleFactor = editorStore.getInt(EditorPreferenceNames.READ_ONLY_FOREGROUND_SCALE); |
| disposeColorTable(); |
| refreshDisplay(); |
| } |
| } |
| }; |
| private List fHoldStyleResults; |
| private String fPartitioning = IDocumentExtension3.DEFAULT_PARTITIONING; |
| |
| private int fSavedLength = -1; |
| private int fSavedOffset = -1; |
| private StyleRange[] fSavedRanges = null; |
| |
| private IStructuredDocument fStructuredDocument; |
| private Map fTableOfProviders; |
| |
| private Map fExtendedProviders; |
| |
| protected final LineStyleProvider NOOP_PROVIDER = new LineStyleProviderForNoOp(); |
| |
| private double readOnlyBackgroundScaleFactor = 10; |
| private Hashtable readOnlyColorTable; |
| double readOnlyForegroundScaleFactor = 30; |
| |
| private YUV_RGBConverter rgbConverter; |
| private ITextViewer textViewer; |
| private StyledText textWidget; |
| |
| public Highlighter() { |
| super(); |
| } |
| |
| protected void addEmptyRange(int start, int length, Collection holdResults) { |
| StyleRange result = new StyleRange(); |
| result.start = start; |
| result.length = length; |
| holdResults.add(result); |
| } |
| |
| /** |
| * Registers a given line style provider for a particular partition type. |
| * If there is already a line style provider registered for this type, the |
| * new line style provider is registered instead of the old one. |
| * |
| * @param partitionType |
| * the partition type under which to register |
| * @param the |
| * line style provider to register, or <code>null</code> to |
| * remove an existing one |
| */ |
| public void addProvider(String partitionType, LineStyleProvider provider) { |
| getTableOfProviders().put(partitionType, provider); |
| } |
| |
| /** |
| * Adjust the style ranges' start and length so that they refer to the |
| * textviewer widget's range instead of the textviewer's document range. |
| * |
| * @param ranges |
| * @param adjustment |
| */ |
| protected void adjust(StyleRange[] ranges, int adjustment) { |
| ITextViewer viewer = getTextViewer(); |
| |
| if (adjustment != 0) { |
| // just use the adjustment value |
| // convert document regions back to widget regions |
| for (int i = 0; i < ranges.length; i++) { |
| // just adjust the range using the given adjustment |
| ranges[i].start += adjustment; |
| } |
| } |
| else if (viewer instanceof ITextViewerExtension5) { |
| // use ITextViewerExtension5 |
| ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; |
| |
| // convert document regions back to widget regions |
| for (int i = 0; i < ranges.length; i++) { |
| // get document range, taking into account folding |
| // regions in viewer |
| IRegion region = extension.modelRange2WidgetRange(new Region(ranges[i].start, ranges[i].length)); |
| if (region != null) { |
| ranges[i].start = region.getOffset(); |
| ranges[i].length = region.getLength(); |
| } // else what happens if region is not found?! |
| } |
| } |
| } |
| |
| |
| /** |
| * @deprecated - Read Only areas have unchanged background colors |
| */ |
| void adjustBackground(StyleRange styleRange) { |
| RGB oldRGB = null; |
| Color oldColor = styleRange.background; |
| if (oldColor == null) { |
| oldColor = getTextWidget().getBackground(); |
| } |
| oldRGB = oldColor.getRGB(); |
| Color newColor = getCachedColorFor(oldRGB); |
| if (newColor == null) { |
| double target = getRGBConverter().calculateYComponent(oldColor); |
| // if background is "light" make it darker, and vice versa |
| if (target < 0.5) |
| target = 1.0; |
| else |
| target = 0.0; |
| RGB newRGB = getRGBConverter().transformRGB(oldRGB, readOnlyBackgroundScaleFactor / 100.0, target); |
| |
| cacheColor(oldRGB, newRGB); |
| newColor = getCachedColorFor(oldRGB); |
| } |
| styleRange.background = newColor; |
| } |
| |
| private void adjustForeground(StyleRange styleRange) { |
| RGB oldRGB = null; |
| // Color oldColor = styleRange.foreground; |
| Color oldColor = styleRange.background; |
| if (oldColor == null) { |
| // oldRGB = getTextWidget().getForeground().getRGB(); |
| oldColor = getTextWidget().getBackground(); |
| oldRGB = oldColor.getRGB(); |
| } |
| else { |
| oldRGB = oldColor.getRGB(); |
| } |
| Color newColor = getCachedColorFor(oldRGB); |
| if (newColor == null) { |
| // make text "closer to" background lumanence |
| double target = getRGBConverter().calculateYComponent(oldColor); |
| RGB newRGB = getRGBConverter().transformRGBToGrey(oldRGB, readOnlyForegroundScaleFactor / 100.0, target); |
| |
| // save conversion, so calculations only need to be done once |
| cacheColor(oldRGB, newRGB); |
| newColor = getCachedColorFor(oldRGB); |
| } |
| styleRange.foreground = newColor; |
| } |
| |
| /** |
| * Cache read-only color. |
| * |
| * @param oldRGB |
| * @param newColor |
| */ |
| private void cacheColor(RGB oldRGB, RGB newColor) { |
| if (readOnlyColorTable == null) { |
| readOnlyColorTable = new Hashtable(); |
| } |
| readOnlyColorTable.put(oldRGB, newColor); |
| } |
| |
| /** |
| * @param result |
| * @return |
| */ |
| private StyleRange[] convertReadOnlyRegions(StyleRange[] result, int start, int length) { |
| IStructuredDocument structuredDocument = getDocument(); |
| |
| /** |
| * (dmw) For client/provider simplicity (and consistent look and feel) |
| * we'll handle readonly regions in one spot, here in the Highlighter. |
| * Currently it is a fair assumption that each readonly region will be |
| * on an ITextRegion boundary, so we combine consecutive styles when |
| * found to be equivalent. Plus, for now, we'll just adjust |
| * foreground. Eventually will use a "dimming" algrorithm to adjust |
| * color's satuation/brightness. |
| */ |
| if (structuredDocument.containsReadOnly(start, length)) { |
| // something is read-only in the line, so go through each style, |
| // and adjust |
| for (int i = 0; i < result.length; i++) { |
| StyleRange styleRange = result[i]; |
| if (structuredDocument.containsReadOnly(styleRange.start, styleRange.length)) { |
| adjustForeground(styleRange); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Clear out the readOnlyColorTable |
| */ |
| void disposeColorTable() { |
| if (readOnlyColorTable != null) { |
| readOnlyColorTable.clear(); |
| } |
| readOnlyColorTable = null; |
| } |
| |
| /** |
| * This method is just to get existing read-only colors. |
| */ |
| private Color getCachedColorFor(RGB oldRGB) { |
| Color result = null; |
| |
| if (readOnlyColorTable != null) { |
| RGB readOnlyRGB = (RGB) readOnlyColorTable.get(oldRGB); |
| result = EditorUtility.getColor(readOnlyRGB); |
| } |
| |
| return result; |
| } |
| |
| protected IStructuredDocument getDocument() { |
| return fStructuredDocument; |
| } |
| |
| /** |
| * Adjust the given widget offset and length so that they are the |
| * textviewer document's offset and length, taking into account what is |
| * actually visible in the document. |
| * |
| * @param offset |
| * @param length |
| * @return a region containing the offset and length within the |
| * textviewer's document or null if the offset is not within the |
| * document |
| */ |
| private IRegion getDocumentRangeFromWidgetRange(int offset, int length) { |
| IRegion styleRegion = null; |
| ITextViewer viewer = getTextViewer(); |
| if (viewer instanceof ITextViewerExtension5) { |
| // get document range, taking into account folding regions in |
| // viewer |
| ITextViewerExtension5 extension = (ITextViewerExtension5) viewer; |
| styleRegion = extension.widgetRange2ModelRange(new Region(offset, length)); |
| } |
| else { |
| // get document range, taking into account viewer visible region |
| // get visible region in viewer |
| IRegion vr = null; |
| if (viewer != null) |
| vr = viewer.getVisibleRegion(); |
| else |
| vr = new Region(0, getDocument().getLength()); |
| |
| // if offset is not within visible region, then we don't really |
| // care |
| if (offset <= vr.getLength()) { |
| // Adjust the offset to be within visible region |
| styleRegion = new Region(offset + vr.getOffset(), length); |
| } |
| } |
| return styleRegion; |
| } |
| |
| |
| private Map getExtendedProviders() { |
| if (fExtendedProviders == null) { |
| fExtendedProviders = new HashMap(3); |
| } |
| return fExtendedProviders; |
| } |
| |
| /** |
| * Method getProviderFor. |
| * |
| * @param typedRegion |
| * @return LineStyleProvider |
| */ |
| private LineStyleProvider getProviderFor(ITypedRegion typedRegion) { |
| String type = typedRegion.getType(); |
| LineStyleProvider result = (LineStyleProvider) fTableOfProviders.get(type); |
| if (result == null) { |
| // NOT YET FINALIZED - DO NOT CONSIDER AS API |
| synchronized (getExtendedProviders()) { |
| if (!getExtendedProviders().containsKey(type)) { |
| LineStyleProvider provider = (LineStyleProvider) ExtendedConfigurationBuilder.getInstance().getConfiguration(LINE_STYLE_PROVIDER_EXTENDED_ID, type); |
| getExtendedProviders().put(type, provider); |
| if (provider != null) { |
| provider.init(getDocument(), this); |
| } |
| result = provider; |
| } |
| else { |
| result = (LineStyleProvider) getExtendedProviders().get(type); |
| } |
| } |
| } |
| if (result == null) { |
| result = NOOP_PROVIDER; |
| } |
| return result; |
| } |
| |
| private YUV_RGBConverter getRGBConverter() { |
| if (rgbConverter == null) { |
| rgbConverter = new YUV_RGBConverter(); |
| } |
| return rgbConverter; |
| } |
| |
| private Map getTableOfProviders() { |
| if (fTableOfProviders == null) { |
| fTableOfProviders = new HashMap(); |
| } |
| return fTableOfProviders; |
| } |
| |
| /** |
| * Returns the textViewer. |
| * |
| * @return ITextViewer |
| */ |
| public ITextViewer getTextViewer() { |
| return textViewer; |
| } |
| |
| /** |
| * @return |
| */ |
| protected StyledText getTextWidget() { |
| return textWidget; |
| } |
| |
| /** |
| * Installs highlighter support on the given text viewer. |
| * |
| * @param textViewer |
| * the text viewer on which content assist will work |
| */ |
| public void install(ITextViewer newTextViewer) { |
| this.textViewer = newTextViewer; |
| |
| IPreferenceStore editorStore = SSEUIPlugin.getDefault().getPreferenceStore(); |
| editorStore.addPropertyChangeListener(fForegroundScaleListener); |
| readOnlyForegroundScaleFactor = editorStore.getInt(EditorPreferenceNames.READ_ONLY_FOREGROUND_SCALE); |
| |
| if (textWidget != null) { |
| textWidget.removeLineStyleListener(this); |
| } |
| textWidget = newTextViewer.getTextWidget(); |
| if (textWidget != null) { |
| textWidget.addLineStyleListener(this); |
| } |
| |
| refreshDisplay(); |
| } |
| |
| public StyleRange[] lineGetStyle(int eventLineOffset, int eventLineLength) { |
| StyleRange[] eventStyles = EMPTY_STYLE_RANGE; |
| try { |
| if (getDocument() == null || eventLineLength == 0) { |
| // getDocument() == null |
| // during initialization, this is sometimes called before our |
| // structured |
| // is set, in which case we set styles to be the empty style |
| // range |
| // (event.styles can not be null) |
| |
| // eventLineLength == 0 |
| // we sometimes get odd requests from the very last CRLF in |
| // the |
| // document |
| // it has no length, and there is no node for it! |
| eventStyles = EMPTY_STYLE_RANGE; |
| } |
| else { |
| /* |
| * LineStyleProviders work using absolute document offsets. To |
| * support visible regions, adjust the requested range up to |
| * the full document offsets. |
| */ |
| IRegion styleRegion = getDocumentRangeFromWidgetRange(eventLineOffset, eventLineLength); |
| if (styleRegion != null) { |
| int start = styleRegion.getOffset(); |
| int length = styleRegion.getLength(); |
| |
| ITypedRegion[] partitions = TextUtilities.computePartitioning(getDocument(), fPartitioning, start, length, false); |
| eventStyles = prepareStyleRangesArray(partitions, start, length); |
| |
| // If there is a subtext offset, the style ranges must be |
| // adjusted to the expected |
| // offsets |
| // just check if eventLineOffset is different than start |
| // then adjust, otherwise u can leave it alone |
| // unless there is special handling for |
| // itextviewerextension5? |
| if (start != eventLineOffset) { |
| int offset = 0; |
| // figure out visible region to use for adjustment |
| // only adjust if need to |
| if (!(getTextViewer() instanceof ITextViewerExtension5)) { |
| IRegion vr = getTextViewer().getVisibleRegion(); |
| if (vr != null) { |
| offset = vr.getOffset(); |
| } |
| } |
| adjust(eventStyles, -offset); |
| } |
| |
| // for debugging only |
| if (DEBUG) { |
| if (!valid(eventStyles, eventLineOffset, eventLineLength)) { |
| Logger.log(Logger.WARNING, "Highlighter::lineGetStyle found invalid styles at offset " + eventLineOffset); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| } |
| |
| } |
| catch (Exception e) { |
| // if ANY exception occurs during highlighting, |
| // just return "no highlighting" |
| eventStyles = EMPTY_STYLE_RANGE; |
| if (Debug.syntaxHighlighting) { |
| System.out.println("Exception during highlighting!"); //$NON-NLS-1$ |
| } |
| } |
| |
| return eventStyles; |
| } |
| |
| /** |
| * A passthrough method that extracts relevant data from the |
| * LineStyleEvent and passes it along. This method was separated for |
| * performance testing purposes. |
| * |
| * @see org.eclipse.swt.custom.LineStyleListener#lineGetStyle(LineStyleEvent) |
| */ |
| public void lineGetStyle(LineStyleEvent event) { |
| int offset = event.lineOffset; |
| int length = event.lineText.length(); |
| |
| /* |
| * For some reason, we are sometimes asked for the same style range |
| * over and over again. This was found to happen during 'revert' of a |
| * file with one line in it that is 40K long! So, while we don't know |
| * root cause, caching the styled ranges in case the exact same |
| * request is made multiple times seems like cheap insurance. |
| */ |
| if (offset == fSavedOffset && length == fSavedLength && fSavedRanges != null) { |
| event.styles = fSavedRanges; |
| } |
| else { |
| // need to assign this array here, or else the field won't get |
| // updated |
| event.styles = lineGetStyle(offset, length); |
| // now saved "cached data" for repeated requests which are exaclty |
| // same |
| fSavedOffset = offset; |
| fSavedLength = length; |
| fSavedRanges = event.styles; |
| } |
| } |
| |
| /** |
| * Note: its very important this method never return null, which is why |
| * the final null check is in a finally clause |
| */ |
| |
| protected StyleRange[] prepareStyleRangesArray(ITypedRegion[] partitions, int start, int length) { |
| |
| StyleRange[] result = EMPTY_STYLE_RANGE; |
| |
| if (fHoldStyleResults == null) { |
| fHoldStyleResults = new ArrayList(partitions.length); |
| } |
| else { |
| fHoldStyleResults.clear(); |
| } |
| |
| // TODO: make some of these instance variables to prevent creation on |
| // stack |
| LineStyleProvider currentLineStyleProvider = null; |
| boolean handled = false; |
| for (int i = 0; i < partitions.length; i++) { |
| ITypedRegion currentPartition = partitions[i]; |
| currentLineStyleProvider = getProviderFor(currentPartition); |
| currentLineStyleProvider.init(getDocument(), this); |
| handled = currentLineStyleProvider.prepareRegions(currentPartition, currentPartition.getOffset(), currentPartition.getLength(), fHoldStyleResults); |
| if (Debug.syntaxHighlighting && !handled) { |
| System.out.println("Did not handle highlighting in Highlighter inner while"); //$NON-NLS-1$ |
| } |
| } |
| |
| int resultSize = fHoldStyleResults.size(); |
| if (resultSize > 0) { |
| result = (StyleRange[]) fHoldStyleResults.toArray(new StyleRange[fHoldStyleResults.size()]); |
| } |
| else { |
| result = EMPTY_STYLE_RANGE; |
| } |
| result = convertReadOnlyRegions(result, start, length); |
| return result; |
| } |
| |
| public void refreshDisplay() { |
| if (textWidget != null && !textWidget.isDisposed()) |
| textWidget.redraw(); |
| } |
| |
| /** |
| */ |
| public void refreshDisplay(int start, int length) { |
| if (textWidget != null && !textWidget.isDisposed()) |
| textWidget.redrawRange(start, length, true); |
| } |
| |
| public void removeProvider(String partitionType) { |
| getTableOfProviders().remove(partitionType); |
| } |
| |
| public void setDocument(IStructuredDocument structuredDocument) { |
| fStructuredDocument = structuredDocument; |
| } |
| |
| public void setDocumentPartitioning(String partitioning) { |
| if (partitioning != null) { |
| fPartitioning = partitioning; |
| } |
| else { |
| fPartitioning = IDocumentExtension3.DEFAULT_PARTITIONING; |
| } |
| } |
| |
| /** |
| * Uninstalls highlighter support from the text viewer it has previously |
| * be installed on. |
| */ |
| public void uninstall() { |
| if (textWidget != null && !textWidget.isDisposed()) { |
| textWidget.removeLineStyleListener(this); |
| } |
| textWidget = null; |
| |
| Collection providers = getTableOfProviders().values(); |
| Iterator iterator = providers.iterator(); |
| while (iterator.hasNext()) { |
| LineStyleProvider lineStyleProvider = (LineStyleProvider) iterator.next(); |
| lineStyleProvider.release(); |
| // this remove probably isn't strictly needed, since |
| // typically highlighter instance as a whole will go |
| // away ... but in case that ever changes, this seems like |
| // a better style. |
| iterator.remove(); |
| } |
| |
| synchronized (getExtendedProviders()) { |
| providers = new ArrayList(getExtendedProviders().values()); |
| getExtendedProviders().clear(); |
| } |
| iterator = providers.iterator(); |
| while (iterator.hasNext()) { |
| LineStyleProvider lineStyleProvider = (LineStyleProvider) iterator.next(); |
| if (lineStyleProvider != null) { |
| lineStyleProvider.release(); |
| iterator.remove(); |
| } |
| } |
| |
| IPreferenceStore editorStore = SSEUIPlugin.getDefault().getPreferenceStore(); |
| editorStore.removePropertyChangeListener(fForegroundScaleListener); |
| disposeColorTable(); |
| |
| // clear out cached variables (d282894) |
| fSavedOffset = -1; |
| fSavedLength = -1; |
| fSavedRanges = null; |
| } |
| |
| /** |
| * Purely a debugging aide. |
| */ |
| private boolean valid(StyleRange[] eventStyles, int startOffset, int lineLength) { |
| boolean result = false; |
| if (eventStyles != null) { |
| if (eventStyles.length > 0) { |
| StyleRange first = eventStyles[0]; |
| StyleRange last = eventStyles[eventStyles.length - 1]; |
| if (startOffset > first.start) { |
| result = false; |
| } |
| else { |
| int lineEndOffset = startOffset + lineLength; |
| int lastOffset = last.start + last.length; |
| if (lastOffset > lineEndOffset) { |
| result = false; |
| } |
| else { |
| result = true; |
| } |
| } |
| } |
| else { |
| // a zero length array is ok |
| result = true; |
| } |
| } |
| return result; |
| } |
| } |