/******************************************************************************* | |
* Copyright (c) 2011 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 | |
*******************************************************************************/ | |
package org.eclipse.wst.css.ui.internal.text.hover; | |
import org.eclipse.jface.text.AbstractInformationControl; | |
import org.eclipse.jface.text.AbstractReusableInformationControlCreator; | |
import org.eclipse.jface.text.IDocument; | |
import org.eclipse.jface.text.IInformationControl; | |
import org.eclipse.jface.text.IInformationControlCreator; | |
import org.eclipse.jface.text.IInformationControlExtension2; | |
import org.eclipse.jface.text.IRegion; | |
import org.eclipse.jface.text.ITextHover; | |
import org.eclipse.jface.text.ITextHoverExtension; | |
import org.eclipse.jface.text.ITextHoverExtension2; | |
import org.eclipse.jface.text.ITextViewer; | |
import org.eclipse.jface.text.Region; | |
import org.eclipse.swt.graphics.Color; | |
import org.eclipse.swt.graphics.Point; | |
import org.eclipse.swt.graphics.RGB; | |
import org.eclipse.swt.widgets.Composite; | |
import org.eclipse.swt.widgets.Shell; | |
import org.eclipse.wst.css.core.internal.provisional.document.ICSSPrimitiveValue; | |
import org.eclipse.wst.sse.core.StructuredModelManager; | |
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; | |
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; | |
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; | |
import org.w3c.dom.css.CSSPrimitiveValue; | |
import org.w3c.dom.css.RGBColor; | |
public class CSSColorHover implements ITextHover, ITextHoverExtension, ITextHoverExtension2 { | |
private IInformationControlCreator fInformationControlCreator; | |
public CSSColorHover() { | |
} | |
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) { | |
final IDocument document = textViewer.getDocument(); | |
if (document instanceof IStructuredDocument) { | |
IStructuredModel model = StructuredModelManager.getModelManager().getModelForRead((IStructuredDocument) document); | |
try { | |
final IndexedRegion region = model.getIndexedRegion(hoverRegion.getOffset()); | |
if (region instanceof ICSSPrimitiveValue) { | |
return getColorValue((ICSSPrimitiveValue) region); | |
} | |
} | |
finally { | |
if (model != null) | |
model.releaseFromRead(); | |
} | |
} | |
return null; | |
} | |
public IInformationControlCreator getHoverControlCreator() { | |
if (fInformationControlCreator == null) { | |
fInformationControlCreator = new CSSColorInformationControlCreator(); | |
} | |
return fInformationControlCreator; | |
} | |
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { | |
Object result = getHoverInfo2(textViewer, hoverRegion); | |
return result != null ? result.toString() : null; | |
} | |
/** | |
* Gets an {@link RGB} color value from the primitive value | |
* | |
* @param value the primitive CSS value | |
* @return an RGB value if it can be extracted from the primitive | |
*/ | |
private RGB getColorValue(ICSSPrimitiveValue value) { | |
if (value.getParentNode() instanceof RGBColor) { | |
value = (ICSSPrimitiveValue) value.getParentNode(); | |
} | |
RGB rgb = null; | |
switch (value.getPrimitiveType()) { | |
case CSSPrimitiveValue.CSS_RGBCOLOR: | |
rgb = getRGB((RGBColor) value); | |
break; | |
case ICSSPrimitiveValue.CSS_HASH: | |
rgb = getRGBFromHex(value.getStringValue()); | |
break; | |
case CSSPrimitiveValue.CSS_IDENT: | |
rgb = CSSColorNames.getInstance().getRGB(value.getStringValue()); | |
break; | |
} | |
return rgb; | |
} | |
/** | |
* Converts a hex string (either 3-digit or 6-digit notation) into an {@link RGB}. Any | |
* invalid hex color will result in a null RGB value. | |
* @param hex rgb value in hexadecimal notation (3- or 6-digit) | |
* @return an {@link RGB} based on the hexadecimal value. <code>null</code> if the | |
* rgb value is invalid | |
*/ | |
private RGB getRGBFromHex(String hex) { | |
try { | |
final int length = hex.length(); | |
if (length == 4) { // convert 3-digit notation | |
final int r = Integer.parseInt(hex.substring(1, 2), 16); | |
final int g = Integer.parseInt(hex.substring(2, 3), 16); | |
final int b = Integer.parseInt(hex.substring(3, 4), 16); | |
return new RGB((r << 4) | r, (g << 4) | g, (b << 4) | b); | |
} | |
else if (length == 7) { // convert 6-digit notation | |
return new RGB(Integer.parseInt(hex.substring(1, 3), 16), Integer.parseInt(hex.substring(3, 5), 16), Integer.parseInt(hex.substring(5, 7), 16)); | |
} | |
} | |
catch (NumberFormatException e) {} // Invalid hexcode used | |
return null; | |
} | |
/** | |
* Provides an {@link RGB} based on an {@link RGBColor} | |
* @param color The {@link RGBColor} to extra RGB information from | |
* @return an {@link RGB} based on an {@link RGBColor} | |
*/ | |
private RGB getRGB(RGBColor color) { | |
final int red = getColorInt(color.getRed()); | |
final int green = getColorInt(color.getGreen()); | |
final int blue = getColorInt(color.getBlue()); | |
if (red >= 0 && green >= 0 && blue >= 0) | |
return new RGB(red, green, blue); | |
return null; | |
} | |
private int getColorInt(CSSPrimitiveValue value) { | |
if (value.getPrimitiveType() == CSSPrimitiveValue.CSS_PERCENTAGE) { // Percentage of 255 | |
final float percentage = value.getFloatValue(CSSPrimitiveValue.CSS_NUMBER); | |
return capIntValue((int) (percentage / 100 * 255)); | |
} | |
else if (value.getPrimitiveType() == ICSSPrimitiveValue.CSS_INTEGER) { | |
return capIntValue((int) value.getFloatValue(CSSPrimitiveValue.CSS_NUMBER)); | |
} | |
return -1; | |
} | |
/** | |
* Caps the integer value between the ranges of 0 and 255, inclusive. | |
* @param value integer value to cap | |
* @return a value between 0 and 255, inclusive | |
*/ | |
private int capIntValue(int value) { | |
if (value > 255) value = 255; | |
else if (value < 0) value = 0; | |
return value; | |
} | |
public IRegion getHoverRegion(ITextViewer textViewer, int offset) { | |
final IDocument document = textViewer.getDocument(); | |
if (document instanceof IStructuredDocument) { | |
IStructuredModel model = StructuredModelManager.getModelManager().getModelForRead((IStructuredDocument) document); | |
try { | |
IndexedRegion region = model.getIndexedRegion(offset); | |
if (region instanceof ICSSPrimitiveValue) { | |
// Shift the hover region to the rgb() function instead of the individual numbers | |
if (((ICSSPrimitiveValue) region).getParentNode() instanceof RGBColor) { | |
region = (IndexedRegion) ((ICSSPrimitiveValue) region).getParentNode(); | |
} | |
} | |
if (region != null) { | |
return new Region(region.getStartOffset(), region.getLength()); | |
} | |
} | |
finally { | |
if (model != null) | |
model.releaseFromRead(); | |
} | |
} | |
return null; | |
} | |
private class CSSColorInformationControlCreator extends AbstractReusableInformationControlCreator { | |
protected IInformationControl doCreateInformationControl(Shell parent) { | |
return new CSSColorInformationControl(parent); | |
} | |
} | |
/** | |
* An information control that simply displays color information. | |
* The control takes an {@link RGB} input value and sets its background | |
* to the corresponding color. | |
* | |
*/ | |
private class CSSColorInformationControl extends AbstractInformationControl implements IInformationControlExtension2 { | |
private Color fColor; | |
CSSColorInformationControl(Shell shell) { | |
super(shell, false); | |
create(); | |
} | |
public Point computeSizeConstraints(int widthInChars, int heightInChars) { | |
return new Point(50, 50); | |
} | |
public boolean hasContents() { | |
return fColor != null; | |
} | |
protected void createContent(Composite parent) { | |
} | |
public void setInformation(String information) { | |
} | |
public void dispose() { | |
if (fColor != null) { | |
fColor.dispose(); | |
fColor = null; | |
} | |
super.dispose(); | |
} | |
public void setInput(Object input) { | |
if (input instanceof RGB) { | |
RGB rgb = (RGB) input; | |
if (fColor == null || !rgb.equals(fColor.getRGB())) { | |
if (fColor != null) { // Cleanup any old color | |
fColor.dispose(); | |
} | |
fColor = new Color(getShell().getDisplay(), rgb); | |
setBackgroundColor(fColor); | |
} | |
} | |
} | |
public IInformationControlCreator getInformationPresenterControlCreator() { | |
return new CSSColorInformationControlCreator(); | |
} | |
} | |
} |