blob: 9ecda9bce14a0ed8059ec1390cdafab70537c1bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2013, 2014 Original authors 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:
* Original authors and others - initial API and implementation
* Dirk Fauth <dirk.fauth@googlemail.com> - Added image scaling
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.util;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
public class GUIHelper {
private static final String KEY_PREFIX = GUIHelper.class.getCanonicalName() + "."; //$NON-NLS-1$
// Color
public static final Color COLOR_GRAY = Display.getDefault().getSystemColor(SWT.COLOR_GRAY);
public static final Color COLOR_WHITE = Display.getDefault().getSystemColor(SWT.COLOR_WHITE);
public static final Color COLOR_DARK_GRAY = Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY);
public static final Color COLOR_BLACK = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
public static final Color COLOR_BLUE = Display.getDefault().getSystemColor(SWT.COLOR_BLUE);
public static final Color COLOR_RED = Display.getDefault().getSystemColor(SWT.COLOR_RED);
public static final Color COLOR_YELLOW = Display.getDefault().getSystemColor(SWT.COLOR_YELLOW);
public static final Color COLOR_GREEN = Display.getDefault().getSystemColor(SWT.COLOR_GREEN);
public static final Color COLOR_LIST_BACKGROUND = Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
public static final Color COLOR_LIST_FOREGROUND = Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
public static final Color COLOR_LIST_SELECTION = Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION);
public static final Color COLOR_LIST_SELECTION_TEXT = Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT);
public static final Color COLOR_WIDGET_BACKGROUND = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
public static final Color COLOR_WIDGET_FOREGROUND = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND);
public static final Color COLOR_TITLE_INACTIVE_BACKGROUND = Display.getDefault().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND);
public static final Color COLOR_WIDGET_BORDER = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_BORDER);
public static final Color COLOR_WIDGET_DARK_SHADOW = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
public static final Color COLOR_WIDGET_LIGHT_SHADOW = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
public static final Color COLOR_WIDGET_NORMAL_SHADOW = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
public static final Color COLOR_WIDGET_HIGHLIGHT_SHADOW = Display.getDefault().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
public static Color getColor(RGB rgb) {
return getColor(rgb.red, rgb.green, rgb.blue);
}
public static Color getColor(int red, int green, int blue) {
String key = getColorKey(red, green, blue);
if (JFaceResources.getColorRegistry().hasValueFor(key)) {
return JFaceResources.getColorRegistry().get(key);
} else {
JFaceResources.getColorRegistry().put(key, new RGB(red, green, blue));
return getColor(key);
}
}
public static Color getColor(String key) {
return JFaceResources.getColorRegistry().get(key);
}
private static String getColorKey(int red, int green, int blue) {
return KEY_PREFIX + "_COLOR_" + red + "_" + green + "_" + blue; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
// Font
public static final Font DEFAULT_FONT = Display.getDefault().getSystemFont();
public static final int DEFAULT_RESIZE_HANDLE_SIZE = 4;
public static final int DEFAULT_MIN_DISPLAY_SIZE = 5;
public static final int DEFAULT_ANTIALIAS = SWT.DEFAULT;;
public static final int DEFAULT_TEXT_ANTIALIAS = SWT.DEFAULT;;
public static Font getFont(FontData... fontDatas) {
StringBuilder keyBuilder = new StringBuilder();
for (FontData fontData : fontDatas) {
keyBuilder.append(fontData.toString());
}
String key = keyBuilder.toString();
if (JFaceResources.getFontRegistry().hasValueFor(key)) {
return JFaceResources.getFont(key);
} else {
JFaceResources.getFontRegistry().put(key, fontDatas);
return JFaceResources.getFont(key);
}
}
public static Font getFont(String key) {
return JFaceResources.getFont(key);
}
// Image
private static final String[] IMAGE_DIRS = new String[] { "org/eclipse/nebula/widgets/nattable/images/", "" }; //$NON-NLS-1$ //$NON-NLS-2$
private static final String[] IMAGE_EXTENSIONS = new String[] { ".png", ".gif" }; //$NON-NLS-1$ //$NON-NLS-2$
/**
* This method extracts the base filename out of the given {@link URL} and
* uses it as key to search for the {@link Image} in the
* {@link ImageRegistry}. If the {@link Image} is not yet present it will
* create the {@link Image} instance and register it automatically. On
* creating and registering it will respect dpi scaling.
*
* @param url
* The {@link URL} of the image for initial loading.
* @return The {@link Image} representation of an image external to
* NatTable.
*
* @see #getImageByURL(String, URL)
*/
public static Image getImageByURL(URL url) {
String basename = url.toString();
basename = basename.substring(basename.lastIndexOf('/') + 1, basename.lastIndexOf('.'));
return getImageByURL(basename, url);
}
/**
* This method returns the {@link Image} that is registered for the given
* key. If there is no {@link Image} registered for that key already, it
* will create and register the {@link Image} that can be loaded by the
* given {@link URL}.
* <p>
* This method returns an {@link Image} that matches the dpi settings. If
* the dpi of an axis is bigger than 96 it will search for an image for the
* bigger dpi. For this the filenames need to carry the dpi information.
* </p>
* <p>
* For example if you request <i>checkbox.png</i> this method will search
* for a scaled version relative to the requested image. The following will
* give an example on the scaled files:
* <ul>
* <li>checkbox.png</li>
* <li>checkbox_120_120.png</li>
* <li>checkbox_128_128.png</li>
* <li>checkbox_144_144.png</li>
* <li>checkbox_192_192.png</li>
* <li>checkbox_288_288.png</li>
* </ul>
* </p>
* <p>
* If the matching scaled version is not found, it will automatically
* upscale the base image.
* </p>
* <p>
* Note: If you want to get the image later again you can directly use
* <code>JFaceResources.getImage(key)</code>.
* </p>
*
* @param key
* The key under which the resource is registered in the image
* registry.
* @param url
* The {@link URL} of the image for initial loading.
* @return The {@link Image} representation of an image external to
* NatTable.
*/
public static Image getImageByURL(String key, URL url) {
Image image = JFaceResources.getImage(key);
if (image == null) {
if (needScaling()) {
// modify url to contain scaling information in filename
// create the matching URL for the scaled image
String urlString = url.toString();
int extIndex = urlString.lastIndexOf('.');
String ext = urlString.substring(extIndex, urlString.length());
String base = urlString.substring(0, extIndex);
// check if there is a upscaled image available
try {
URL scaleURL = new URL(base + getScalingImageSuffix() + ext);
URLConnection con = scaleURL.openConnection();
con.connect();
// as the connection could be established, the file exists
// this check is working in plain SWT aswell as in the OSGi
// context
JFaceResources.getImageRegistry().put(key, ImageDescriptor.createFromURL(scaleURL));
} catch (IOException e) {
// if there is no upscaled image available, we upscale
// ourself
ImageData imageData = ImageDescriptor.createFromURL(url).getImageData();
imageData = imageData.scaledTo(
convertHorizontalPixelToDpi(imageData.width),
convertVerticalPixelToDpi(imageData.height));
JFaceResources.getImageRegistry().put(key, new Image(Display.getDefault(), imageData));
}
}
else {
JFaceResources.getImageRegistry().put(key, ImageDescriptor.createFromURL(url));
}
image = JFaceResources.getImage(key);
}
return image;
}
public static URL getScaledImageURL(URL url) {
if (needScaling()) {
// modify url to contain scaling information in filename
// create the matching URL for the scaled image
String urlString = url.toString();
int extIndex = urlString.lastIndexOf('.');
String ext = urlString.substring(extIndex, urlString.length());
String base = urlString.substring(0, extIndex);
// check if there is a upscaled image available
try {
URL scaleURL = new URL(base + getScalingImageSuffix() + ext);
URLConnection con = scaleURL.openConnection();
con.connect();
// as the connection could be established, the file exists
// this check is working in plain SWT aswell as in the OSGi
// context
return scaleURL;
} catch (IOException e) {
// do nothing, there is no upscaled image available, so we
// simply use the given URL
}
}
// scaling is not necessary, so just return the given URL
return url;
}
/**
* Returns the {@link Image} representation of a NatTable internal image
* resource.
* <p>
* For upscaling this method checks whether there is a upscaled version of
* the image available, otherwise it will upscale the existing image and
* store that in the registry for further use.
* </p>
*
* @param imageName
* The filename of the image (without extension).
* @return The {@link Image} representation of the internal NatTable image
* resource or <code>null</code> if there is no image found for the
* given name at the internal image resource location.
*/
public static Image getImage(String imageName) {
Image image = JFaceResources.getImage(imageName);
if (image == null) {
URL imageUrl = getInternalImageUrl(imageName);
if (imageUrl != null) {
ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(imageUrl);
if (needScaling() && !imageUrl.getFile().contains(getScalingImageSuffix())) {
// we need to upscale the image but we have no scaled
// version, therefore we manually perform an upscale
// it won't look nice but at least it is upscaled
ImageData imageData = imageDescriptor.getImageData();
imageData = imageData.scaledTo(
convertHorizontalPixelToDpi(imageData.width),
convertVerticalPixelToDpi(imageData.height));
JFaceResources.getImageRegistry().put(imageName, new Image(Display.getDefault(), imageData));
}
else {
JFaceResources.getImageRegistry().put(imageName, imageDescriptor.createImage());
}
image = JFaceResources.getImage(imageName);
}
}
return image;
}
/**
* Returns the {@link ImageDescriptor} for a NatTable internal image
* resource.
*
* @param imageName
* The filename of the image (without extension).
* @return The {@link ImageDescriptor} of the internal NatTable image
* resource or <code>null</code> if there is no image found for the
* given name at the internal image resource location.
*/
public static ImageDescriptor getImageDescriptor(String imageName) {
ImageDescriptor imageDescriptor = null;
URL imageUrl = getInternalImageUrl(imageName);
if (imageUrl != null) {
imageDescriptor = ImageDescriptor.createFromURL(imageUrl);
}
return imageDescriptor;
}
/**
* Searches for the image with the given filename in the NatTable internal
* image resource folder with file extensions <i>.png</i> and <i>.gif</i>.
*
* @param imageName
* The filename of the image (without extension)
* @return The URL of the internal NatTable image or <code>null</code> if
* there is no image found for the given name at the internal image
* resource location.
*/
public static URL getInternalImageUrl(String imageName) {
for (String dir : IMAGE_DIRS) {
for (String ext : IMAGE_EXTENSIONS) {
// TODO remove direct scaling information addition
// add search for scaled image
// e.g. imageName = checkbox -->
// org/eclipse/nebula/widgets/nattable/images/checkbox_128_128.png
URL url = null;
if (needScaling()) {
url = GUIHelper.class.getClassLoader().getResource(
dir + imageName + getScalingImageSuffix() + ext);
}
// no scaling needed or no already scaled image found
// search for the image without scaling extension
if (url == null) {
url = GUIHelper.class.getClassLoader().getResource(dir + imageName + ext);
}
if (url != null) {
return url;
}
}
}
return null;
}
/**
* <b>WARNING: DO NOT USE THIS METHOD AS IT IS MIGHT CAUSE RESOURCE HANDLING
* ISSUES!!!<b/>
*
* @deprecated This method does not work correctly since it uses
* {@link ImageData#toString()}
*/
@Deprecated
public static Image getImage(ImageData data) {
if (JFaceResources.getImage(data.toString()) == null) {
JFaceResources.getImageRegistry().put(data.toString(), ImageDescriptor.createFromImageData(data));
}
return JFaceResources.getImage(data.toString());
}
// Sequence
private static final AtomicLong atomicLong = new AtomicLong(0);
public static String getSequenceNumber() {
long id = atomicLong.addAndGet(1);
return String.valueOf(id);
}
/**
* Blend the two colour values returning a value that is halfway between
* them.
*
* @param val1
* the first value
* @param val2
* the second value
* @return the blended colour
*/
public static RGB blend(final RGB val1, final RGB val2) {
final int red = blend(val1.red, val2.red);
final int green = blend(val1.green, val2.green);
final int blue = blend(val1.blue, val2.blue);
return new RGB(red, green, blue);
}
/**
* Blend the two colour values returning a value that is halfway between
* them.
*
* @param temp1
* the first value
* @param temp2
* the second value
* @return the blended int value
*/
private static int blend(final int temp1, final int temp2) {
return (Math.abs(temp1 - temp2) / 2) + Math.min(temp1, temp2);
}
// DPI scaling
private static float[] dpiFactor = new float[] { 1.0f, 1.25f, 1.33f, 1.5f, 2.0f, 3.0f };
/**
* Returns the factor for scaling calculations of pixels regarding the DPI.
*
* @param dpi
* The DPI for which the factor is requested.
* @return The factor for dpi scaling calculations.
*/
public static float getDpiFactor(int dpi) {
float factor = 1.0f;
switch (dpi) {
case 96:
factor = dpiFactor[0];
break;
case 120:
factor = dpiFactor[1];
break;
case 128:
factor = dpiFactor[2];
break;
case 144:
factor = dpiFactor[3];
break;
case 192:
factor = dpiFactor[4];
break;
case 288:
factor = dpiFactor[5];
break;
}
return factor;
}
/**
* @return <code>true</code> if either the horizontal or the vertical DPI
* value is bigger than 96.
*/
public static boolean needScaling() {
return (getDpiX() > 96 || getDpiY() > 96);
}
/**
* @return The horizontal dots per inch of the default display.
*/
public static int getDpiX() {
return Display.getDefault().getDPI().x;
}
/**
* @return The vertical dots per inch of the default display.
*/
public static int getDpiY() {
return Display.getDefault().getDPI().y;
}
/**
* @return The suffix that is used to mark an image as upscaled image.
*/
public static String getScalingImageSuffix() {
return "_" + getDpiX() + "_" + getDpiY(); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Converts the given amount of pixels to a DPI scaled value using the
* factor for the horizontal DPI value.
*
* @param pixel
* the amount of pixels to convert.
* @return The converted pixels.
*/
public static int convertHorizontalPixelToDpi(int pixel) {
return Float.valueOf(pixel * getDpiFactor(getDpiX())).intValue();
}
/**
* Converts the given DPI scaled value to a pixel value using the factor for
* the horizontal DPI.
*
* @param dpi
* the DPI value to convert.
* @return The pixel value related to the given DPI
*/
public static int convertHorizontalDpiToPixel(int dpi) {
return Float.valueOf(dpi / getDpiFactor(getDpiY())).intValue();
}
/**
* Converts the given amount of pixels to a DPI scaled value using the
* factor for the vertical DPI.
*
* @param pixel
* the amount of pixels to convert.
* @return The converted pixels.
*/
public static int convertVerticalPixelToDpi(int pixel) {
return Float.valueOf(pixel * getDpiFactor(getDpiX())).intValue();
}
/**
* Converts the given DPI scaled value to a pixel value using the factor for
* the vertical DPI.
*
* @param dpi
* the DPI value to convert.
* @return The pixel value related to the given DPI
*/
public static int convertVerticalDpiToPixel(int dpi) {
return Float.valueOf(dpi / getDpiFactor(getDpiY())).intValue();
}
}