Browse Source
* commit '94c85f7d3405a94db058f75fc53727902a501465': REPORT-27037 alphafine快捷键不生效,无法使用research/10.0
zhouping
5 years ago
48 changed files with 8179 additions and 0 deletions
@ -0,0 +1,2 @@
|
||||
源码地址:https://github.com/bulenkov/iconloader <br> |
||||
版本:1.0 |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,39 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader; |
||||
|
||||
import apple.awt.CImage; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class AppleHiDPIScaledImage { |
||||
public static BufferedImage create(int width, int height, int imageType) { |
||||
return new CImage.HiDPIScaledImage(width, height, imageType) { |
||||
@Override |
||||
protected void drawIntoImage(BufferedImage image, float scale) { |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public static boolean is(Image image) { |
||||
return image instanceof CImage.HiDPIScaledImage; |
||||
} |
||||
} |
@ -0,0 +1,484 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader; |
||||
|
||||
import com.bulenkov.iconloader.util.GraphicsUtil; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.font.FontRenderContext; |
||||
import java.awt.font.GlyphVector; |
||||
import java.awt.geom.AffineTransform; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.BufferedImageOp; |
||||
import java.awt.image.ImageObserver; |
||||
import java.awt.image.RenderedImage; |
||||
import java.awt.image.renderable.RenderableImage; |
||||
import java.text.AttributedCharacterIterator; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
class HiDPIScaledGraphics extends Graphics2D { |
||||
protected final Graphics2D myPeer; |
||||
private BufferedImage myImage; |
||||
|
||||
public HiDPIScaledGraphics(Graphics g, BufferedImage image) { |
||||
myImage = image; |
||||
myPeer = (Graphics2D) g; |
||||
scale(2, 2); |
||||
GraphicsUtil.setupAAPainting(myPeer); |
||||
} |
||||
|
||||
@Override |
||||
public void draw3DRect(int x, int y, int width, int height, boolean raised) { |
||||
myPeer.draw3DRect(x, y, width, height, raised); |
||||
} |
||||
|
||||
@Override |
||||
public void fill3DRect(int x, int y, int width, int height, boolean raised) { |
||||
myPeer.fill3DRect(x, y, width, height, raised); |
||||
} |
||||
|
||||
@Override |
||||
public void draw(Shape s) { |
||||
myPeer.draw(s); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { |
||||
return myPeer.drawImage(img, xform, obs); |
||||
} |
||||
|
||||
@Override |
||||
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { |
||||
myPeer.drawImage(img, op, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void drawRenderedImage(RenderedImage img, AffineTransform xform) { |
||||
myPeer.drawRenderedImage(img, xform); |
||||
} |
||||
|
||||
@Override |
||||
public void drawRenderableImage(RenderableImage img, AffineTransform xform) { |
||||
myPeer.drawRenderableImage(img, xform); |
||||
} |
||||
|
||||
@Override |
||||
public void drawString(String str, int x, int y) { |
||||
myPeer.drawString(str, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void drawString(String str, float x, float y) { |
||||
myPeer.drawString(str, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void drawString(AttributedCharacterIterator iterator, int x, int y) { |
||||
myPeer.drawString(iterator, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void drawString(AttributedCharacterIterator iterator, float x, float y) { |
||||
myPeer.drawString(iterator, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void drawGlyphVector(GlyphVector g, float x, float y) { |
||||
myPeer.drawGlyphVector(g, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void fill(Shape s) { |
||||
myPeer.fill(s); |
||||
} |
||||
|
||||
@Override |
||||
public boolean hit(Rectangle rect, Shape s, boolean onStroke) { |
||||
return myPeer.hit(rect, s, onStroke); |
||||
} |
||||
|
||||
@Override |
||||
public GraphicsConfiguration getDeviceConfiguration() { |
||||
return myPeer.getDeviceConfiguration(); |
||||
} |
||||
|
||||
@Override |
||||
public void setComposite(Composite comp) { |
||||
myPeer.setComposite(comp); |
||||
} |
||||
|
||||
@Override |
||||
public void setPaint(Paint paint) { |
||||
myPeer.setPaint(paint); |
||||
} |
||||
|
||||
@Override |
||||
public void setStroke(Stroke s) { |
||||
myPeer.setStroke(s); |
||||
} |
||||
|
||||
@Override |
||||
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { |
||||
myPeer.setRenderingHint(hintKey, hintValue); |
||||
} |
||||
|
||||
@Override |
||||
public Object getRenderingHint(RenderingHints.Key hintKey) { |
||||
return myPeer.getRenderingHint(hintKey); |
||||
} |
||||
|
||||
@Override |
||||
public void setRenderingHints(Map<?, ?> hints) { |
||||
myPeer.setRenderingHints(hints); |
||||
} |
||||
|
||||
@Override |
||||
public void addRenderingHints(Map<?, ?> hints) { |
||||
myPeer.addRenderingHints(hints); |
||||
} |
||||
|
||||
@Override |
||||
public RenderingHints getRenderingHints() { |
||||
return myPeer.getRenderingHints(); |
||||
} |
||||
|
||||
@Override |
||||
public void translate(int x, int y) { |
||||
myPeer.translate(x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void translate(double tx, double ty) { |
||||
myPeer.translate(tx, ty); |
||||
} |
||||
|
||||
@Override |
||||
public void rotate(double theta) { |
||||
myPeer.rotate(theta); |
||||
} |
||||
|
||||
@Override |
||||
public void rotate(double theta, double x, double y) { |
||||
myPeer.rotate(theta, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void scale(double sx, double sy) { |
||||
myPeer.scale(sx, sy); |
||||
} |
||||
|
||||
@Override |
||||
public void shear(double shx, double shy) { |
||||
myPeer.shear(shx, shy); |
||||
} |
||||
|
||||
@Override |
||||
public void transform(AffineTransform Tx) { |
||||
myPeer.transform(Tx); |
||||
} |
||||
|
||||
@Override |
||||
public void setTransform(AffineTransform Tx) { |
||||
myPeer.setTransform(Tx); |
||||
} |
||||
|
||||
@Override |
||||
public AffineTransform getTransform() { |
||||
return myPeer.getTransform(); |
||||
} |
||||
|
||||
@Override |
||||
public Paint getPaint() { |
||||
return myPeer.getPaint(); |
||||
} |
||||
|
||||
@Override |
||||
public Composite getComposite() { |
||||
return myPeer.getComposite(); |
||||
} |
||||
|
||||
@Override |
||||
public void setBackground(Color color) { |
||||
myPeer.setBackground(color); |
||||
} |
||||
|
||||
@Override |
||||
public Color getBackground() { |
||||
return myPeer.getBackground(); |
||||
} |
||||
|
||||
@Override |
||||
public Stroke getStroke() { |
||||
return myPeer.getStroke(); |
||||
} |
||||
|
||||
@Override |
||||
public void clip(Shape s) { |
||||
myPeer.clip(s); |
||||
} |
||||
|
||||
@Override |
||||
public FontRenderContext getFontRenderContext() { |
||||
return myPeer.getFontRenderContext(); |
||||
} |
||||
|
||||
@Override |
||||
public Graphics create() { |
||||
Graphics g = myPeer.create(); |
||||
return g; |
||||
} |
||||
|
||||
@Override |
||||
public Graphics create(int x, int y, int width, int height) { |
||||
return myPeer.create(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public Color getColor() { |
||||
return myPeer.getColor(); |
||||
} |
||||
|
||||
@Override |
||||
public void setColor(Color c) { |
||||
myPeer.setColor(c); |
||||
} |
||||
|
||||
@Override |
||||
public void setPaintMode() { |
||||
myPeer.setPaintMode(); |
||||
} |
||||
|
||||
@Override |
||||
public void setXORMode(Color c1) { |
||||
myPeer.setXORMode(c1); |
||||
} |
||||
|
||||
@Override |
||||
public Font getFont() { |
||||
return myPeer.getFont(); |
||||
} |
||||
|
||||
@Override |
||||
public void setFont(Font font) { |
||||
myPeer.setFont(font); |
||||
} |
||||
|
||||
@Override |
||||
public FontMetrics getFontMetrics() { |
||||
return myPeer.getFontMetrics(); |
||||
} |
||||
|
||||
@Override |
||||
public FontMetrics getFontMetrics(Font f) { |
||||
return myPeer.getFontMetrics(f); |
||||
} |
||||
|
||||
@Override |
||||
public Rectangle getClipBounds() { |
||||
return myPeer.getClipBounds(); |
||||
} |
||||
|
||||
@Override |
||||
public void clipRect(int x, int y, int width, int height) { |
||||
myPeer.clipRect(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void setClip(int x, int y, int width, int height) { |
||||
myPeer.setClip(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public Shape getClip() { |
||||
return myPeer.getClip(); |
||||
} |
||||
|
||||
@Override |
||||
public void setClip(Shape clip) { |
||||
myPeer.setClip(clip); |
||||
} |
||||
|
||||
@Override |
||||
public void copyArea(int x, int y, int width, int height, int dx, int dy) { |
||||
myPeer.copyArea(x, y, width, height, dx, dy); |
||||
} |
||||
|
||||
@Override |
||||
public void drawLine(int x1, int y1, int x2, int y2) { |
||||
myPeer.drawLine(x1, y1, x2, y2); |
||||
} |
||||
|
||||
@Override |
||||
public void fillRect(int x, int y, int width, int height) { |
||||
myPeer.fillRect(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void drawRect(int x, int y, int width, int height) { |
||||
myPeer.drawRect(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void clearRect(int x, int y, int width, int height) { |
||||
myPeer.clearRect(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { |
||||
myPeer.drawRoundRect(x, y, width, height, arcWidth, arcHeight); |
||||
} |
||||
|
||||
@Override |
||||
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { |
||||
myPeer.fillRoundRect(x, y, width, height, arcWidth, arcHeight); |
||||
} |
||||
|
||||
@Override |
||||
public void drawOval(int x, int y, int width, int height) { |
||||
myPeer.drawOval(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void fillOval(int x, int y, int width, int height) { |
||||
myPeer.fillOval(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { |
||||
myPeer.drawArc(x, y, width, height, startAngle, arcAngle); |
||||
} |
||||
|
||||
@Override |
||||
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { |
||||
myPeer.fillArc(x, y, width, height, startAngle, arcAngle); |
||||
} |
||||
|
||||
@Override |
||||
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { |
||||
|
||||
myPeer.drawPolyline(xPoints, yPoints, nPoints); |
||||
} |
||||
|
||||
@Override |
||||
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { |
||||
|
||||
myPeer.drawPolygon(xPoints, yPoints, nPoints); |
||||
} |
||||
|
||||
@Override |
||||
public void drawPolygon(Polygon p) { |
||||
|
||||
myPeer.drawPolygon(p); |
||||
} |
||||
|
||||
@Override |
||||
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { |
||||
|
||||
myPeer.fillPolygon(xPoints, yPoints, nPoints); |
||||
} |
||||
|
||||
@Override |
||||
public void fillPolygon(Polygon p) { |
||||
|
||||
myPeer.fillPolygon(p); |
||||
} |
||||
|
||||
@Override |
||||
public void drawChars(char[] data, int offset, int length, int x, int y) { |
||||
myPeer.drawChars(data, offset, length, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public void drawBytes(byte[] data, int offset, int length, int x, int y) { |
||||
myPeer.drawBytes(data, offset, length, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, int x, int y, ImageObserver observer) { |
||||
return myPeer.drawImage(img, x, y, observer); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { |
||||
return myPeer.drawImage(img, x, y, width, height, observer); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { |
||||
return myPeer.drawImage(img, x, y, bgcolor, observer); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { |
||||
return myPeer.drawImage(img, x, y, width, height, bgcolor, observer); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { |
||||
return myPeer.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); |
||||
} |
||||
|
||||
@Override |
||||
public boolean drawImage(Image img, |
||||
int dx1, |
||||
int dy1, |
||||
int dx2, |
||||
int dy2, |
||||
int sx1, |
||||
int sy1, |
||||
int sx2, |
||||
int sy2, |
||||
Color bgcolor, |
||||
ImageObserver observer) { |
||||
return myPeer.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); |
||||
} |
||||
|
||||
@Override |
||||
public void dispose() { |
||||
myPeer.dispose(); |
||||
} |
||||
|
||||
@Override |
||||
public void finalize() { |
||||
myPeer.finalize(); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return myPeer.toString(); |
||||
} |
||||
|
||||
@Override |
||||
@Deprecated |
||||
public Rectangle getClipRect() { |
||||
return myPeer.getClipRect(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean hitClip(int x, int y, int width, int height) { |
||||
return myPeer.hitClip(x, y, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public Rectangle getClipBounds(Rectangle r) { |
||||
return myPeer.getClipBounds(r); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,557 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader; |
||||
|
||||
import com.bulenkov.iconloader.util.*; |
||||
import org.jetbrains.annotations.NonNls; |
||||
import org.jetbrains.annotations.NotNull; |
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.ImageFilter; |
||||
import java.lang.ref.Reference; |
||||
import java.lang.reflect.Field; |
||||
import java.net.URL; |
||||
import java.util.*; |
||||
import java.util.List; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
@SuppressWarnings("UnusedDeclaration") |
||||
public final class IconLoader { |
||||
public static boolean STRICT = false; |
||||
private static boolean USE_DARK_ICONS = UIUtil.isUnderDarcula(); |
||||
|
||||
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection") |
||||
private static final ConcurrentMap<URL, CachedImageIcon> ourIconsCache = new ConcurrentHashMap<URL, CachedImageIcon>(100, 0.9f, 2); |
||||
|
||||
/** |
||||
* This cache contains mapping between icons and disabled icons. |
||||
*/ |
||||
private static final Map<Icon, Icon> ourIcon2DisabledIcon = new WeakHashMap<Icon, Icon>(200); |
||||
|
||||
private static float SCALE = JBUI.scale(1f); |
||||
private static ImageFilter IMAGE_FILTER; |
||||
|
||||
private static final ImageIcon EMPTY_ICON = new ImageIcon(UIUtil.createImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)) { |
||||
@NonNls |
||||
public String toString() { |
||||
return "Empty icon " + super.toString(); |
||||
} |
||||
}; |
||||
|
||||
private static AtomicBoolean ourIsActivated = new AtomicBoolean(true); |
||||
private static AtomicBoolean ourIsSaveRealIconPath = new AtomicBoolean(false); |
||||
public static final Component ourComponent = new Component() {}; |
||||
|
||||
private IconLoader() { } |
||||
|
||||
@Deprecated |
||||
public static Icon getIcon(@NotNull final Image image) { |
||||
return new JBImageIcon(image); |
||||
} |
||||
|
||||
public static void setUseDarkIcons(boolean useDarkIcons) { |
||||
USE_DARK_ICONS = useDarkIcons; |
||||
clearCache(); |
||||
} |
||||
|
||||
public static void setScale(float scale) { |
||||
if (scale != SCALE) { |
||||
SCALE = scale; |
||||
clearCache(); |
||||
} |
||||
} |
||||
|
||||
public static void setFilter(ImageFilter filter) { |
||||
if (!Registry.is("color.blindness.icon.filter")) { |
||||
filter = null; |
||||
} |
||||
if (IMAGE_FILTER != filter) { |
||||
IMAGE_FILTER = filter; |
||||
clearCache(); |
||||
} |
||||
} |
||||
|
||||
private static void clearCache() { |
||||
ourIconsCache.clear(); |
||||
ourIcon2DisabledIcon.clear(); |
||||
} |
||||
|
||||
//TODO[kb] support iconsets
|
||||
//public static Icon getIcon(@NotNull final String path, @NotNull final String darkVariantPath) {
|
||||
// return new InvariantIcon(getIcon(path), getIcon(darkVariantPath));
|
||||
//}
|
||||
|
||||
@NotNull |
||||
public static Icon getIcon(@NonNls @NotNull final String path) { |
||||
Class callerClass = ReflectionUtil.getGrandCallerClass(); |
||||
|
||||
assert callerClass != null : path; |
||||
return getIcon(path, callerClass); |
||||
} |
||||
|
||||
@Nullable |
||||
private static Icon getReflectiveIcon(@NotNull String path, ClassLoader classLoader) { |
||||
try { |
||||
@NonNls String pckg = path.startsWith("AllIcons.") ? "com.intellij.icons." : "icons."; |
||||
Class cur = Class.forName(pckg + path.substring(0, path.lastIndexOf('.')).replace('.', '$'), true, classLoader); |
||||
Field field = cur.getField(path.substring(path.lastIndexOf('.') + 1)); |
||||
|
||||
return (Icon)field.get(null); |
||||
} |
||||
catch (Exception e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Might return null if icon was not found. |
||||
* Use only if you expected null return value, otherwise see {@link IconLoader#getIcon(String)} |
||||
*/ |
||||
@Nullable |
||||
public static Icon findIcon(@NonNls @NotNull String path) { |
||||
Class callerClass = ReflectionUtil.getGrandCallerClass(); |
||||
if (callerClass == null) return null; |
||||
return findIcon(path, callerClass); |
||||
} |
||||
|
||||
@NotNull |
||||
public static Icon getIcon(@NotNull String path, @NotNull final Class aClass) { |
||||
final Icon icon = findIcon(path, aClass); |
||||
if (icon == null) { |
||||
System.err.println("Icon cannot be found in '" + path + "', aClass='" + aClass + "'"); |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
public static void activate() { |
||||
ourIsActivated.set(true); |
||||
} |
||||
|
||||
public static void disable() { |
||||
ourIsActivated.set(false); |
||||
} |
||||
|
||||
public static boolean isLoaderDisabled() { |
||||
return !ourIsActivated.get(); |
||||
} |
||||
|
||||
/** |
||||
* This method is for test purposes only |
||||
*/ |
||||
static void enableSaveRealIconPath() { |
||||
ourIsSaveRealIconPath.set(true); |
||||
} |
||||
|
||||
/** |
||||
* Might return null if icon was not found. |
||||
* Use only if you expected null return value, otherwise see {@link IconLoader#getIcon(String, Class)} |
||||
*/ |
||||
@Nullable |
||||
public static Icon findIcon(@NotNull final String path, @NotNull final Class aClass) { |
||||
return findIcon(path, aClass, false); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Icon findIcon(@NotNull String path, @NotNull final Class aClass, boolean computeNow) { |
||||
return findIcon(path, aClass, computeNow, STRICT); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Icon findIcon(@NotNull String path, @NotNull final Class aClass, boolean computeNow, boolean strict) { |
||||
String originalPath = path; |
||||
path = patchPath(path); |
||||
if (isReflectivePath(path)) return getReflectiveIcon(path, aClass.getClassLoader()); |
||||
|
||||
URL myURL = aClass.getResource(path); |
||||
if (myURL == null) { |
||||
if (strict) throw new RuntimeException("Can't find icon in '" + path + "' near " + aClass); |
||||
return null; |
||||
} |
||||
final Icon icon = findIcon(myURL); |
||||
if (icon instanceof CachedImageIcon) { |
||||
((CachedImageIcon)icon).myOriginalPath = originalPath; |
||||
((CachedImageIcon)icon).myClassLoader = aClass.getClassLoader(); |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
private static String patchPath(@NotNull String path) { |
||||
// for (IconPathPatcher patcher : ourPatchers) {
|
||||
// String newPath = patcher.patchPath(path);
|
||||
// if (newPath != null) {
|
||||
// path = newPath;
|
||||
// }
|
||||
// }
|
||||
return path; |
||||
} |
||||
|
||||
private static boolean isReflectivePath(@NotNull String path) { |
||||
List<String> paths = StringUtil.split(path, "."); |
||||
return paths.size() > 1 && paths.get(0).endsWith("Icons"); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Icon findIcon(URL url) { |
||||
return findIcon(url, true); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Icon findIcon(URL url, boolean useCache) { |
||||
if (url == null) { |
||||
return null; |
||||
} |
||||
CachedImageIcon icon = ourIconsCache.get(url); |
||||
if (icon == null) { |
||||
icon = new CachedImageIcon(url); |
||||
if (useCache) { |
||||
icon = ConcurrencyUtil.cacheOrGet(ourIconsCache, url, icon); |
||||
} |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
@Nullable |
||||
public static Icon findIcon(@NotNull String path, @NotNull ClassLoader classLoader) { |
||||
String originalPath = path; |
||||
path = patchPath(path); |
||||
if (isReflectivePath(path)) return getReflectiveIcon(path, classLoader); |
||||
if (!StringUtil.startsWithChar(path, '/')) return null; |
||||
|
||||
final URL url = classLoader.getResource(path.substring(1)); |
||||
final Icon icon = findIcon(url); |
||||
if (icon instanceof CachedImageIcon) { |
||||
((CachedImageIcon)icon).myOriginalPath = originalPath; |
||||
((CachedImageIcon)icon).myClassLoader = classLoader; |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
@Nullable |
||||
private static ImageIcon checkIcon(final Image image, @NotNull URL url) { |
||||
if (image == null || image.getHeight(LabelHolder.ourFakeComponent) < 1) { // image wasn't loaded or broken
|
||||
return null; |
||||
} |
||||
|
||||
final Icon icon = getIcon(image); |
||||
if (icon != null && !isGoodSize(icon)) { |
||||
return EMPTY_ICON; |
||||
} |
||||
|
||||
return (ImageIcon)icon; |
||||
} |
||||
|
||||
public static boolean isGoodSize(@NotNull final Icon icon) { |
||||
return icon.getIconWidth() > 0 && icon.getIconHeight() > 0; |
||||
} |
||||
|
||||
/** |
||||
* Gets (creates if necessary) disabled icon based on the passed one. |
||||
* |
||||
* @return <code>ImageIcon</code> constructed from disabled image of passed icon. |
||||
*/ |
||||
@Nullable |
||||
public static Icon getDisabledIcon(Icon icon) { |
||||
if (icon instanceof LazyIcon) icon = ((LazyIcon)icon).getOrComputeIcon(); |
||||
if (icon == null) return null; |
||||
|
||||
Icon disabledIcon = ourIcon2DisabledIcon.get(icon); |
||||
if (disabledIcon == null) { |
||||
if (!isGoodSize(icon)) { |
||||
return EMPTY_ICON; |
||||
} |
||||
final int scale = UIUtil.isRetina() ? 2 : 1; |
||||
@SuppressWarnings("UndesirableClassUsage") |
||||
BufferedImage image = new BufferedImage(scale*icon.getIconWidth(), scale*icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB); |
||||
final Graphics2D graphics = image.createGraphics(); |
||||
|
||||
graphics.setColor(UIUtil.TRANSPARENT_COLOR); |
||||
graphics.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight()); |
||||
graphics.scale(scale, scale); |
||||
icon.paintIcon(LabelHolder.ourFakeComponent, graphics, 0, 0); |
||||
|
||||
graphics.dispose(); |
||||
|
||||
Image img = ImageUtil.filter(image, UIUtil.getGrayFilter()); |
||||
if (UIUtil.isRetina()) img = RetinaImage.createFrom(img); |
||||
|
||||
disabledIcon = new JBImageIcon(img); |
||||
ourIcon2DisabledIcon.put(icon, disabledIcon); |
||||
} |
||||
return disabledIcon; |
||||
} |
||||
|
||||
public static Icon getTransparentIcon(@NotNull final Icon icon) { |
||||
return getTransparentIcon(icon, 0.5f); |
||||
} |
||||
|
||||
public static Icon getTransparentIcon(@NotNull final Icon icon, final float alpha) { |
||||
return new RetrievableIcon() { |
||||
@Nullable |
||||
@Override |
||||
public Icon retrieveIcon() { |
||||
return icon; |
||||
} |
||||
|
||||
@Override |
||||
public int getIconHeight() { |
||||
return icon.getIconHeight(); |
||||
} |
||||
|
||||
@Override |
||||
public int getIconWidth() { |
||||
return icon.getIconWidth(); |
||||
} |
||||
|
||||
@Override |
||||
public void paintIcon(final Component c, final Graphics g, final int x, final int y) { |
||||
final Graphics2D g2 = (Graphics2D)g; |
||||
final Composite saveComposite = g2.getComposite(); |
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); |
||||
icon.paintIcon(c, g2, x, y); |
||||
g2.setComposite(saveComposite); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Gets a snapshot of the icon, immune to changes made by these calls: |
||||
* {@link IconLoader#setScale(float)}, {@link IconLoader#setFilter(ImageFilter)}, {@link IconLoader#setUseDarkIcons(boolean)} |
||||
* |
||||
* @param icon the source icon |
||||
* @return the icon snapshot |
||||
*/ |
||||
@NotNull |
||||
public static Icon getIconSnapshot(@NotNull Icon icon) { |
||||
if (icon instanceof CachedImageIcon) { |
||||
return ((CachedImageIcon)icon).getRealIcon(); |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
public static final class CachedImageIcon implements ScalableIcon { |
||||
private volatile Object myRealIcon; |
||||
public String myOriginalPath; |
||||
private ClassLoader myClassLoader; |
||||
@NotNull |
||||
private URL myUrl; |
||||
private volatile boolean dark; |
||||
private volatile float scale; |
||||
private volatile int numberOfPatchers = 0; |
||||
|
||||
private volatile ImageFilter filter; |
||||
private final MyScaledIconsCache myScaledIconsCache = new MyScaledIconsCache(); |
||||
|
||||
public CachedImageIcon(@NotNull URL url) { |
||||
myUrl = url; |
||||
dark = USE_DARK_ICONS; |
||||
scale = SCALE; |
||||
filter = IMAGE_FILTER; |
||||
} |
||||
|
||||
@NotNull |
||||
private synchronized ImageIcon getRealIcon() { |
||||
if (isLoaderDisabled() && (myRealIcon == null || dark != USE_DARK_ICONS || scale != SCALE || filter != IMAGE_FILTER)) return EMPTY_ICON; |
||||
|
||||
if (!isValid()) { |
||||
myRealIcon = null; |
||||
dark = USE_DARK_ICONS; |
||||
scale = SCALE; |
||||
filter = IMAGE_FILTER; |
||||
myScaledIconsCache.clear(); |
||||
} |
||||
Object realIcon = myRealIcon; |
||||
if (realIcon instanceof Icon) return (ImageIcon)realIcon; |
||||
|
||||
ImageIcon icon; |
||||
if (realIcon instanceof Reference) { |
||||
icon = ((Reference<ImageIcon>)realIcon).get(); |
||||
if (icon != null) return (ImageIcon)icon; |
||||
} |
||||
|
||||
Image image = ImageLoader.loadFromUrl(myUrl, true, filter); |
||||
icon = checkIcon(image, myUrl); |
||||
|
||||
if (icon != null) { |
||||
if (icon.getIconWidth() < 50 && icon.getIconHeight() < 50) { |
||||
realIcon = icon; |
||||
} |
||||
else { |
||||
realIcon = new SoftReference<ImageIcon>(icon); |
||||
} |
||||
myRealIcon = realIcon; |
||||
} |
||||
|
||||
return icon == null ? EMPTY_ICON : icon; |
||||
} |
||||
|
||||
private boolean isValid() { |
||||
return dark == USE_DARK_ICONS && scale == SCALE && filter == IMAGE_FILTER; |
||||
} |
||||
|
||||
@Override |
||||
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||
getRealIcon().paintIcon(c, g, x, y); |
||||
} |
||||
|
||||
@Override |
||||
public int getIconWidth() { |
||||
return getRealIcon().getIconWidth(); |
||||
} |
||||
|
||||
@Override |
||||
public int getIconHeight() { |
||||
return getRealIcon().getIconHeight(); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return myUrl.toString(); |
||||
} |
||||
|
||||
@Override |
||||
public Icon scale(float scaleFactor) { |
||||
if (scaleFactor == 1f) { |
||||
return this; |
||||
} |
||||
|
||||
if (!isValid()) getRealIcon(); // force state update & cache reset
|
||||
|
||||
Icon icon = myScaledIconsCache.getScaledIcon(scaleFactor); |
||||
if (icon != null) { |
||||
return icon; |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
private class MyScaledIconsCache { |
||||
// Map {false -> image}, {true -> image@2x}
|
||||
private Map<Boolean, SoftReference<Image>> origImagesCache = Collections.synchronizedMap(new HashMap<Boolean, SoftReference<Image>>(2)); |
||||
|
||||
private static final int SCALED_ICONS_CACHE_LIMIT = 5; |
||||
|
||||
// Map {effective scale -> icon}
|
||||
private Map<Float, SoftReference<Icon>> scaledIconsCache = Collections.synchronizedMap(new LinkedHashMap<Float, SoftReference<Icon>>(SCALED_ICONS_CACHE_LIMIT) { |
||||
@Override |
||||
public boolean removeEldestEntry(Map.Entry<Float, SoftReference<Icon>> entry) { |
||||
return size() > SCALED_ICONS_CACHE_LIMIT; |
||||
} |
||||
}); |
||||
|
||||
public Image getOrigImage(boolean retina) { |
||||
Image img = SoftReference.dereference(origImagesCache.get(retina)); |
||||
|
||||
if (img == null) { |
||||
img = ImageLoader.loadFromUrl(myUrl, UIUtil.isUnderDarcula(), retina, filter); |
||||
origImagesCache.put(retina, new SoftReference<Image>(img)); |
||||
} |
||||
return img; |
||||
} |
||||
|
||||
public Icon getScaledIcon(float scale) { |
||||
float effectiveScale = scale * JBUI.scale(1f); |
||||
Icon icon = SoftReference.dereference(scaledIconsCache.get(effectiveScale)); |
||||
|
||||
if (icon == null) { |
||||
boolean needRetinaImage = (effectiveScale >= 1.5f || UIUtil.isRetina()); |
||||
Image image = getOrigImage(needRetinaImage); |
||||
|
||||
if (image != null) { |
||||
Image iconImage = getRealIcon().getImage(); |
||||
int width = (int)(ImageUtil.getRealWidth(iconImage) * scale); |
||||
int height = (int)(ImageUtil.getRealHeight(iconImage) * scale); |
||||
|
||||
Image resizedImage = Scalr.resize(ImageUtil.toBufferedImage(image), Scalr.Method.ULTRA_QUALITY, width, height); |
||||
if (UIUtil.isRetina()) resizedImage = RetinaImage.createFrom(resizedImage); |
||||
|
||||
icon = getIcon(resizedImage); |
||||
scaledIconsCache.put(effectiveScale, new SoftReference<Icon>(icon)); |
||||
} |
||||
} |
||||
return icon; |
||||
} |
||||
|
||||
public void clear() { |
||||
scaledIconsCache.clear(); |
||||
origImagesCache.clear(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public abstract static class LazyIcon implements Icon { |
||||
private boolean myWasComputed; |
||||
private Icon myIcon; |
||||
private boolean isDarkVariant = USE_DARK_ICONS; |
||||
private float scale = SCALE; |
||||
// private int numberOfPatchers = 0;
|
||||
private ImageFilter filter = IMAGE_FILTER; |
||||
|
||||
@Override |
||||
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||
final Icon icon = getOrComputeIcon(); |
||||
if (icon != null) { |
||||
icon.paintIcon(c, g, x, y); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getIconWidth() { |
||||
final Icon icon = getOrComputeIcon(); |
||||
return icon != null ? icon.getIconWidth() : 0; |
||||
} |
||||
|
||||
@Override |
||||
public int getIconHeight() { |
||||
final Icon icon = getOrComputeIcon(); |
||||
return icon != null ? icon.getIconHeight() : 0; |
||||
} |
||||
|
||||
protected final synchronized Icon getOrComputeIcon() { |
||||
if (!myWasComputed || isDarkVariant != USE_DARK_ICONS || scale != SCALE || filter != IMAGE_FILTER /*|| numberOfPatchers != ourPatchers.size()*/) { |
||||
isDarkVariant = USE_DARK_ICONS; |
||||
scale = SCALE; |
||||
filter = IMAGE_FILTER; |
||||
myWasComputed = true; |
||||
// numberOfPatchers = ourPatchers.size();
|
||||
myIcon = compute(); |
||||
} |
||||
|
||||
return myIcon; |
||||
} |
||||
|
||||
public final void load() { |
||||
getIconWidth(); |
||||
} |
||||
|
||||
protected abstract Icon compute(); |
||||
} |
||||
|
||||
private static class LabelHolder { |
||||
/** |
||||
* To get disabled icon with paint it into the image. Some icons require |
||||
* not null component to paint. |
||||
*/ |
||||
private static final JComponent ourFakeComponent = new JLabel(); |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader; |
||||
|
||||
import apple.awt.CImage; |
||||
import com.bulenkov.iconloader.util.Ref; |
||||
|
||||
import java.awt.image.BufferedImage; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class IsRetina { |
||||
public static boolean isRetina() { |
||||
try { |
||||
final Ref<Boolean> isRetina = Ref.create(false); |
||||
|
||||
new CImage.HiDPIScaledImage(1, 1, BufferedImage.TYPE_INT_ARGB) { |
||||
@Override |
||||
public void drawIntoImage(BufferedImage image, float v) { |
||||
isRetina.set(v > 1); |
||||
} |
||||
}; |
||||
|
||||
return isRetina.get(); |
||||
} catch (Throwable ignore) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,51 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBHiDPIScaledImage extends BufferedImage { |
||||
private final Image myImage; |
||||
|
||||
public JBHiDPIScaledImage(int width, int height, int type) { |
||||
this(null, 2 * width, 2 * height, type); |
||||
} |
||||
|
||||
public JBHiDPIScaledImage(Image image, int width, int height, int type) { |
||||
super(width, height, type); |
||||
myImage = image; |
||||
} |
||||
|
||||
public Image getDelegate() { |
||||
return myImage; |
||||
} |
||||
|
||||
@Override |
||||
public Graphics2D createGraphics() { |
||||
final Graphics2D g = super.createGraphics(); |
||||
|
||||
if (myImage == null) { |
||||
return new HiDPIScaledGraphics(g, this); |
||||
} |
||||
|
||||
return g; |
||||
} |
||||
} |
@ -0,0 +1,88 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader; |
||||
|
||||
import com.bulenkov.iconloader.util.SystemInfo; |
||||
import com.bulenkov.iconloader.util.UIUtil; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.ImageObserver; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class RetinaImage { |
||||
|
||||
/** |
||||
* Creates a Retina-aware wrapper over a raw image. |
||||
* The raw image should be provided in scale of the Retina default scale factor (2x). |
||||
* The wrapper will represent the raw image in the user coordinate space. |
||||
* |
||||
* @param image the raw image |
||||
* @return the Retina-aware wrapper |
||||
*/ |
||||
public static Image createFrom(Image image) { |
||||
return createFrom(image, 2, IconLoader.ourComponent); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Retina-aware wrapper over a raw image. |
||||
* The raw image should be provided in the specified scale. |
||||
* The wrapper will represent the raw image in the user coordinate space. |
||||
* |
||||
* @param image the raw image |
||||
* @param scale the raw image scale |
||||
* @param observer the raw image observer |
||||
* @return the Retina-aware wrapper |
||||
*/ |
||||
public static Image createFrom(Image image, final int scale, ImageObserver observer) { |
||||
int w = image.getWidth(observer); |
||||
int h = image.getHeight(observer); |
||||
|
||||
Image hidpi = create(image, w / scale, h / scale, BufferedImage.TYPE_INT_ARGB); |
||||
if (SystemInfo.isAppleJvm) { |
||||
Graphics2D g = (Graphics2D)hidpi.getGraphics(); |
||||
g.scale(1f / scale, 1f / scale); |
||||
g.drawImage(image, 0, 0, null); |
||||
g.dispose(); |
||||
} |
||||
|
||||
return hidpi; |
||||
} |
||||
|
||||
public static BufferedImage create(final int width, int height, int type) { |
||||
return create(null, width, height, type); |
||||
} |
||||
|
||||
|
||||
private static BufferedImage create(Image image, final int width, int height, int type) { |
||||
if (SystemInfo.isAppleJvm) { |
||||
return AppleHiDPIScaledImage.create(width, height, type); |
||||
} else { |
||||
if (image == null) { |
||||
return new JBHiDPIScaledImage(width, height, type); |
||||
} else { |
||||
return new JBHiDPIScaledImage(image, width, height, type); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static boolean isAppleHiDPIScaledImage(Image image) { |
||||
return UIUtil.isAppleRetina() && AppleHiDPIScaledImage.is(image); |
||||
} |
||||
} |
@ -0,0 +1,77 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "SSBasedInspection"}) |
||||
public class ArrayUtilRt { |
||||
private static final int ARRAY_COPY_THRESHOLD = 20; |
||||
|
||||
public static final String[] EMPTY_STRING_ARRAY = new String[0]; |
||||
|
||||
|
||||
public static String[] toStringArray(Collection<String> collection) { |
||||
return collection == null || collection.isEmpty() |
||||
? EMPTY_STRING_ARRAY : toArray(collection, new String[collection.size()]); |
||||
} |
||||
|
||||
/** |
||||
* This is a replacement for {@link Collection#toArray(Object[])}. For small collections it is faster to stay at java level and refrain |
||||
* from calling JNI {@link System#arraycopy(Object, int, Object, int, int)} |
||||
*/ |
||||
|
||||
public static <T> T[] toArray(Collection<T> c, T[] sample) { |
||||
final int size = c.size(); |
||||
if (size == sample.length && size < ARRAY_COPY_THRESHOLD) { |
||||
int i = 0; |
||||
for (T t : c) { |
||||
sample[i++] = t; |
||||
} |
||||
return sample; |
||||
} |
||||
|
||||
return c.toArray(sample); |
||||
} |
||||
|
||||
/** |
||||
* @param src source array. |
||||
* @param obj object to be found. |
||||
* @return index of <code>obj</code> in the <code>src</code> array. |
||||
* Returns <code>-1</code> if passed object isn't found. This method uses |
||||
* <code>equals</code> of arrays elements to compare <code>obj</code> with |
||||
* these elements. |
||||
*/ |
||||
public static <T> int find(final T[] src, final T obj) { |
||||
for (int i = 0; i < src.length; i++) { |
||||
final T o = src[i]; |
||||
if (o == null) { |
||||
if (obj == null) { |
||||
return i; |
||||
} |
||||
} else { |
||||
if (o.equals(obj)) { |
||||
return i; |
||||
} |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
} |
@ -0,0 +1,88 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
import java.util.Arrays; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class AsyncByteArrayOutputStream extends OutputStream { |
||||
protected byte[] myBuffer; |
||||
protected int myCount; |
||||
|
||||
public AsyncByteArrayOutputStream() { |
||||
this(32); |
||||
} |
||||
|
||||
public AsyncByteArrayOutputStream(int size) { |
||||
myBuffer = new byte[size]; |
||||
} |
||||
|
||||
@Override |
||||
public void write(int b) { |
||||
int count = myCount + 1; |
||||
|
||||
if (count > myBuffer.length) { |
||||
myBuffer = Arrays.copyOf(myBuffer, Math.max(myBuffer.length << 1, count)); |
||||
} |
||||
|
||||
myBuffer[myCount] = (byte) b; |
||||
myCount = count; |
||||
} |
||||
|
||||
@Override |
||||
public void write(byte b[], int off, int len) { |
||||
if ((off < 0) || (off > b.length) || (len < 0) || |
||||
((off + len) > b.length) || ((off + len) < 0)) { |
||||
throw new IndexOutOfBoundsException(); |
||||
} else if (len == 0) { |
||||
return; |
||||
} |
||||
|
||||
int count = myCount + len; |
||||
|
||||
if (count > myBuffer.length) { |
||||
myBuffer = Arrays.copyOf(myBuffer, Math.max(myBuffer.length << 1, count)); |
||||
} |
||||
|
||||
System.arraycopy(b, off, myBuffer, myCount, len); |
||||
myCount = count; |
||||
} |
||||
|
||||
public void writeTo(OutputStream out) throws IOException { |
||||
out.write(myBuffer, 0, myCount); |
||||
} |
||||
|
||||
public void reset() { |
||||
myCount = 0; |
||||
} |
||||
|
||||
public byte[] toByteArray() { |
||||
return Arrays.copyOf(myBuffer, myCount); |
||||
} |
||||
|
||||
public int size() { |
||||
return myCount; |
||||
} |
||||
|
||||
public String toString() { |
||||
return new String(myBuffer, 0, myCount); |
||||
} |
||||
} |
@ -0,0 +1,180 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class Base64Converter { |
||||
private static final char[] alphabet = { |
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'}; // 56 to 63
|
||||
|
||||
private static final byte[] decodeTable = { |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, |
||||
58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, |
||||
-1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, |
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
-1, |
||||
}; |
||||
|
||||
public static String encode(String s) { |
||||
return encode(s.getBytes()); |
||||
} |
||||
|
||||
public static String encode(byte[] octetString) { |
||||
int bits24; |
||||
int bits6; |
||||
|
||||
char[] out = new char[((octetString.length - 1) / 3 + 1) * 4]; |
||||
|
||||
int outIndex = 0; |
||||
int i = 0; |
||||
|
||||
while ((i + 3) <= octetString.length) { |
||||
// store the octets
|
||||
bits24 = (octetString[i++] & 0xFF) << 16; |
||||
bits24 |= (octetString[i++] & 0xFF) << 8; |
||||
bits24 |= (octetString[i++] & 0xFF); |
||||
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
bits6 = (bits24 & 0x0003F000) >> 12; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
bits6 = (bits24 & 0x00000FC0) >> 6; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
bits6 = (bits24 & 0x0000003F); |
||||
out[outIndex++] = alphabet[bits6]; |
||||
} |
||||
|
||||
if (octetString.length - i == 2) { |
||||
// store the octets
|
||||
bits24 = (octetString[i] & 0xFF) << 16; |
||||
bits24 |= (octetString[i + 1] & 0xFF) << 8; |
||||
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
bits6 = (bits24 & 0x0003F000) >> 12; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
bits6 = (bits24 & 0x00000FC0) >> 6; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
|
||||
// padding
|
||||
out[outIndex] = '='; |
||||
} else if (octetString.length - i == 1) { |
||||
// store the octets
|
||||
bits24 = (octetString[i] & 0xFF) << 16; |
||||
|
||||
bits6 = (bits24 & 0x00FC0000) >> 18; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
bits6 = (bits24 & 0x0003F000) >> 12; |
||||
out[outIndex++] = alphabet[bits6]; |
||||
|
||||
// padding
|
||||
out[outIndex++] = '='; |
||||
out[outIndex] = '='; |
||||
} |
||||
|
||||
return StringFactory.createShared(out); |
||||
} |
||||
|
||||
public static String decode(String s) { |
||||
return new String(decode(s.getBytes())); |
||||
} |
||||
|
||||
public static byte[] decode(byte[] bytes) { |
||||
int paddingCount = 0; |
||||
int realLength = 0; |
||||
|
||||
for (int i = bytes.length - 1; i >= 0; i--) { |
||||
if (bytes[i] > ' ') { |
||||
realLength++; |
||||
} |
||||
|
||||
if (bytes[i] == '=') { |
||||
paddingCount++; |
||||
} |
||||
} |
||||
|
||||
if (realLength % 4 != 0) { |
||||
throw new IllegalArgumentException("Incorrect length " + realLength + ". Must be a multiple of 4"); |
||||
} |
||||
|
||||
final byte[] out = new byte[realLength / 4 * 3 - paddingCount]; |
||||
final byte[] t = new byte[4]; |
||||
int outIndex = 0; |
||||
int index = 0; |
||||
t[0] = t[1] = t[2] = t[3] = '='; |
||||
|
||||
for (byte c : bytes) { |
||||
if (c > ' ') { |
||||
t[index++] = c; |
||||
} |
||||
|
||||
if (index == 4) { |
||||
outIndex += decode(out, outIndex, t[0], t[1], t[2], t[3]); |
||||
index = 0; |
||||
t[0] = t[1] = t[2] = t[3] = '='; |
||||
} |
||||
} |
||||
|
||||
if (index > 0) { |
||||
decode(out, outIndex, t[0], t[1], t[2], t[3]); |
||||
} |
||||
return out; |
||||
} |
||||
|
||||
private static int decode(byte[] output, int outIndex, byte a, byte b, byte c, byte d) { |
||||
byte da = decodeTable[a]; |
||||
byte db = decodeTable[b]; |
||||
byte dc = decodeTable[c]; |
||||
byte dd = decodeTable[d]; |
||||
|
||||
if ((da == -1) || (db == -1) || ((dc == -1) && (c != '=')) || ((dd == -1) && (d != '='))) { |
||||
throw new IllegalArgumentException( |
||||
"Invalid character [" + (a & 0xFF) + ", " + (b & 0xFF) + ", " + (c & 0xFF) + ", " + (d & 0xFF) + "]"); |
||||
} |
||||
output[outIndex++] = (byte) ((da << 2) | db >>> 4); |
||||
|
||||
if (c == '=') { |
||||
return 1; |
||||
} |
||||
output[outIndex++] = (byte) ((db << 4) | dc >>> 2); |
||||
|
||||
if (d == '=') { |
||||
return 2; |
||||
} |
||||
output[outIndex] = (byte) ((dc << 6) | dd); |
||||
return 3; |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class BufferExposingByteArrayOutputStream extends AsyncByteArrayOutputStream { |
||||
public BufferExposingByteArrayOutputStream() { |
||||
} |
||||
|
||||
public BufferExposingByteArrayOutputStream(int size) { |
||||
super(size); |
||||
} |
||||
|
||||
public byte[] getInternalBuffer() { |
||||
return myBuffer; |
||||
} |
||||
|
||||
public int backOff(int size) { |
||||
assert size >= 0 : size; |
||||
myCount -= size; |
||||
assert myCount >= 0 : myCount; |
||||
return myCount; |
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class CenteredIcon implements Icon { |
||||
private final Icon myIcon; |
||||
|
||||
private final int myWidth; |
||||
private final int myHight; |
||||
|
||||
private final boolean myCenteredInComponent; |
||||
|
||||
public CenteredIcon(Icon icon) { |
||||
this(icon, icon.getIconWidth(), icon.getIconHeight(), true); |
||||
} |
||||
|
||||
public CenteredIcon(Icon icon, int width, int height) { |
||||
this(icon, width, height, true); |
||||
} |
||||
|
||||
public CenteredIcon(Icon icon, int width, int height, boolean centeredInComponent) { |
||||
myIcon = icon; |
||||
myWidth = width; |
||||
myHight = height; |
||||
myCenteredInComponent = centeredInComponent; |
||||
} |
||||
|
||||
@Override |
||||
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||
int offsetX; |
||||
int offsetY; |
||||
|
||||
if (myCenteredInComponent) { |
||||
final Dimension size = c.getSize(); |
||||
offsetX = size.width / 2 - myIcon.getIconWidth() / 2; |
||||
offsetY = size.height / 2 - myIcon.getIconHeight() / 2; |
||||
} else { |
||||
offsetX = (myWidth - myIcon.getIconWidth()) / 2; |
||||
offsetY = (myHight - myIcon.getIconHeight()) / 2; |
||||
} |
||||
|
||||
myIcon.paintIcon(c, g, x + offsetX, y + offsetY); |
||||
} |
||||
|
||||
@Override |
||||
public int getIconWidth() { |
||||
return myWidth; |
||||
} |
||||
|
||||
@Override |
||||
public int getIconHeight() { |
||||
return myHight; |
||||
} |
||||
} |
@ -0,0 +1,84 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class ColorUtil { |
||||
private static int shift(int colorComponent, double d) { |
||||
final int n = (int) (colorComponent * d); |
||||
return n > 255 ? 255 : n < 0 ? 0 : n; |
||||
} |
||||
|
||||
public static Color shift(Color c, double d) { |
||||
return new Color(shift(c.getRed(), d), shift(c.getGreen(), d), shift(c.getBlue(), d), c.getAlpha()); |
||||
} |
||||
|
||||
public static Color toAlpha(Color color, int a) { |
||||
Color c = color != null ? color : Color.black; |
||||
return new Color(c.getRed(), c.getGreen(), c.getBlue(), a); |
||||
} |
||||
|
||||
/** |
||||
* Return Color object from string. The following formats are allowed: |
||||
* <code>#abc123</code>, |
||||
* <code>ABC123</code>, |
||||
* <code>ab5</code>, |
||||
* <code>#FFF</code>. |
||||
* |
||||
* @param str hex string |
||||
* @return Color object |
||||
*/ |
||||
public static Color fromHex(String str) { |
||||
if (str.startsWith("#")) { |
||||
str = str.substring(1); |
||||
} |
||||
if (str.length() == 3) { |
||||
return new Color( |
||||
17 * Integer.valueOf(String.valueOf(str.charAt(0)), 16), |
||||
17 * Integer.valueOf(String.valueOf(str.charAt(1)), 16), |
||||
17 * Integer.valueOf(String.valueOf(str.charAt(2)), 16)); |
||||
} else if (str.length() == 6) { |
||||
return Color.decode("0x" + str); |
||||
} else { |
||||
throw new IllegalArgumentException("Should be String of 3 or 6 chars length."); |
||||
} |
||||
} |
||||
|
||||
public static Color fromHex(String str, Color defaultValue) { |
||||
try { |
||||
return fromHex(str); |
||||
} catch (Exception e) { |
||||
return defaultValue; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Checks whether color is dark or not based on perceptional luminosity |
||||
* http://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
|
||||
* |
||||
* @param c color to check |
||||
* @return dark or not |
||||
*/ |
||||
public static boolean isDark(final Color c) { |
||||
// based on perceptional luminosity, see
|
||||
return (1 - (0.299 * c.getRed() + 0.587 * c.getGreen() + 0.114 * c.getBlue()) / 255) >= 0.5; |
||||
} |
||||
} |
@ -0,0 +1,184 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.util.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class ComparingUtils { |
||||
private ComparingUtils() { |
||||
} |
||||
|
||||
public static <T> boolean equal(T arg1, T arg2) { |
||||
if (arg1 == null || arg2 == null) { |
||||
return arg1 == arg2; |
||||
} |
||||
if (arg1 instanceof Object[] && arg2 instanceof Object[]) { |
||||
Object[] arr1 = (Object[]) arg1; |
||||
Object[] arr2 = (Object[]) arg2; |
||||
return Arrays.equals(arr1, arr2); |
||||
} |
||||
if (arg1 instanceof CharSequence && arg2 instanceof CharSequence) { |
||||
return equal((CharSequence) arg1, (CharSequence) arg2, true); |
||||
} |
||||
return arg1.equals(arg2); |
||||
} |
||||
|
||||
public static <T> boolean equal(T[] arr1, T[] arr2) { |
||||
if (arr1 == null || arr2 == null) { |
||||
return arr1 == arr2; |
||||
} |
||||
return Arrays.equals(arr1, arr2); |
||||
} |
||||
|
||||
public static boolean equal(CharSequence s1, CharSequence s2) { |
||||
return equal(s1, s2, true); |
||||
} |
||||
|
||||
public static boolean equal(String arg1, String arg2) { |
||||
return arg1 == null ? arg2 == null : arg1.equals(arg2); |
||||
} |
||||
|
||||
public static boolean equal(CharSequence s1, CharSequence s2, boolean caseSensitive) { |
||||
if (s1 == s2) return true; |
||||
if (s1 == null || s2 == null) return false; |
||||
|
||||
// Algorithm from String.regionMatches()
|
||||
|
||||
if (s1.length() != s2.length()) return false; |
||||
int to = 0; |
||||
int po = 0; |
||||
int len = s1.length(); |
||||
|
||||
while (len-- > 0) { |
||||
char c1 = s1.charAt(to++); |
||||
char c2 = s2.charAt(po++); |
||||
if (c1 == c2) { |
||||
continue; |
||||
} |
||||
if (!caseSensitive && StringUtil.charsEqualIgnoreCase(c1, c2)) continue; |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public static boolean equal(String arg1, String arg2, boolean caseSensitive) { |
||||
if (arg1 == null || arg2 == null) { |
||||
return arg1 == null && arg2 == null; |
||||
} else { |
||||
return caseSensitive ? arg1.equals(arg2) : arg1.equalsIgnoreCase(arg2); |
||||
} |
||||
} |
||||
|
||||
public static boolean strEqual(String arg1, String arg2) { |
||||
return strEqual(arg1, arg2, true); |
||||
} |
||||
|
||||
public static boolean strEqual(String arg1, String arg2, boolean caseSensitive) { |
||||
return equal(arg1 == null ? "" : arg1, arg2 == null ? "" : arg2, caseSensitive); |
||||
} |
||||
|
||||
public static <T> boolean haveEqualElements(Collection<T> a, Collection<T> b) { |
||||
if (a.size() != b.size()) { |
||||
return false; |
||||
} |
||||
|
||||
Set<T> aSet = new HashSet<T>(a); |
||||
for (T t : b) { |
||||
if (!aSet.contains(t)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static <T> boolean haveEqualElements(T[] a, T[] b) { |
||||
if (a == null || b == null) { |
||||
return a == b; |
||||
} |
||||
|
||||
if (a.length != b.length) { |
||||
return false; |
||||
} |
||||
|
||||
Set<T> aSet = new HashSet<T>(Arrays.asList(a)); |
||||
for (T t : b) { |
||||
if (!aSet.contains(t)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static int hashcode(Object obj) { |
||||
return obj == null ? 0 : obj.hashCode(); |
||||
} |
||||
|
||||
public static int hashcode(Object obj1, Object obj2) { |
||||
return hashcode(obj1) ^ hashcode(obj2); |
||||
} |
||||
|
||||
public static int compare(byte o1, byte o2) { |
||||
return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; |
||||
} |
||||
|
||||
public static int compare(boolean o1, boolean o2) { |
||||
return o1 == o2 ? 0 : o1 ? 1 : -1; |
||||
} |
||||
|
||||
public static int compare(int o1, int o2) { |
||||
return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; |
||||
} |
||||
|
||||
public static int compare(long o1, long o2) { |
||||
return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; |
||||
} |
||||
|
||||
public static int compare(double o1, double o2) { |
||||
return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; |
||||
} |
||||
|
||||
public static int compare(byte[] o1, byte[] o2) { |
||||
if (o1 == o2) return 0; |
||||
if (o1 == null) return 1; |
||||
if (o2 == null) return -1; |
||||
|
||||
if (o1.length > o2.length) return 1; |
||||
if (o1.length < o2.length) return -1; |
||||
|
||||
for (int i = 0; i < o1.length; i++) { |
||||
if (o1[i] > o2[i]) return 1; |
||||
else if (o1[i] < o2[i]) return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
public static <T extends Comparable<T>> int compare(final T o1, final T o2) { |
||||
if (o1 == null) return o2 == null ? 0 : -1; |
||||
if (o2 == null) return 1; |
||||
return o1.compareTo(o2); |
||||
} |
||||
|
||||
public static <T> int compare(final T o1, final T o2, final Comparator<T> notNullComparator) { |
||||
if (o1 == null) return o2 == null ? 0 : -1; |
||||
if (o2 == null) return 1; |
||||
return notNullComparator.compare(o1, o2); |
||||
} |
||||
} |
@ -0,0 +1,133 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
import java.util.concurrent.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class ConcurrencyUtil { |
||||
/** |
||||
* Invokes and waits all tasks using threadPool, avoiding thread starvation on the way |
||||
* (see <a href="http://gafter.blogspot.com/2006/11/thread-pool-puzzler.html">"A Thread Pool Puzzler"</a>). |
||||
*/ |
||||
public static <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, ExecutorService executorService) throws Throwable { |
||||
if (executorService == null) { |
||||
for (Callable<T> task : tasks) { |
||||
task.call(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size()); |
||||
boolean done = false; |
||||
try { |
||||
for (Callable<T> t : tasks) { |
||||
Future<T> future = executorService.submit(t); |
||||
futures.add(future); |
||||
} |
||||
// force not started futures to execute using the current thread
|
||||
for (Future f : futures) { |
||||
((Runnable) f).run(); |
||||
} |
||||
for (Future f : futures) { |
||||
try { |
||||
f.get(); |
||||
} catch (CancellationException ignore) { |
||||
} catch (ExecutionException e) { |
||||
Throwable cause = e.getCause(); |
||||
if (cause != null) { |
||||
throw cause; |
||||
} |
||||
} |
||||
} |
||||
done = true; |
||||
} finally { |
||||
if (!done) { |
||||
for (Future f : futures) { |
||||
f.cancel(false); |
||||
} |
||||
} |
||||
} |
||||
return futures; |
||||
} |
||||
|
||||
/** |
||||
* @return defaultValue if there is no entry in the map (in that case defaultValue is placed into the map), |
||||
* or corresponding value if entry already exists. |
||||
*/ |
||||
|
||||
public static <K, V> V cacheOrGet(ConcurrentMap<K, V> map, final K key, final V defaultValue) { |
||||
V v = map.get(key); |
||||
if (v != null) return v; |
||||
V prev = map.putIfAbsent(key, defaultValue); |
||||
return prev == null ? defaultValue : prev; |
||||
} |
||||
|
||||
|
||||
public static ThreadPoolExecutor newSingleThreadExecutor(final String threadFactoryName) { |
||||
return newSingleThreadExecutor(threadFactoryName, Thread.NORM_PRIORITY); |
||||
} |
||||
|
||||
|
||||
public static ThreadPoolExecutor newSingleThreadExecutor(final String threadFactoryName, final int threadPriority) { |
||||
return new ThreadPoolExecutor(1, 1, |
||||
0L, TimeUnit.MILLISECONDS, |
||||
new LinkedBlockingQueue<Runnable>(), newNamedThreadFactory(threadFactoryName, true, threadPriority)); |
||||
} |
||||
|
||||
|
||||
public static ScheduledThreadPoolExecutor newSingleScheduledThreadExecutor(final String threadFactoryName) { |
||||
return newSingleScheduledThreadExecutor(threadFactoryName, Thread.NORM_PRIORITY); |
||||
} |
||||
|
||||
|
||||
public static ScheduledThreadPoolExecutor newSingleScheduledThreadExecutor(final String threadFactoryName, final int threadPriority) { |
||||
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, newNamedThreadFactory(threadFactoryName, true, threadPriority)); |
||||
executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); |
||||
executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); |
||||
return executor; |
||||
} |
||||
|
||||
|
||||
public static ThreadFactory newNamedThreadFactory(final String threadName, final boolean isDaemon, final int threadPriority) { |
||||
return new ThreadFactory() { |
||||
|
||||
@Override |
||||
public Thread newThread(final Runnable r) { |
||||
final Thread thread = new Thread(r, threadName); |
||||
thread.setDaemon(isDaemon); |
||||
thread.setPriority(threadPriority); |
||||
return thread; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public static ThreadFactory newNamedThreadFactory(final String threadName) { |
||||
return new ThreadFactory() { |
||||
|
||||
@Override |
||||
public Thread newThread(final Runnable r) { |
||||
return new Thread(r, threadName); |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,243 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.NotNull; |
||||
import org.jetbrains.annotations.TestOnly; |
||||
|
||||
import java.lang.ref.ReferenceQueue; |
||||
import java.util.*; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
|
||||
/** |
||||
* Base class for concurrent strong key:K -> (soft/weak) value:V map |
||||
* Null keys are NOT allowed |
||||
* Null values are NOT allowed |
||||
*/ |
||||
abstract class ConcurrentRefValueHashMap<K, V> implements ConcurrentMap<K, V> { |
||||
private final ConcurrentMap<K, ValueReference<K, V>> myMap; |
||||
protected final ReferenceQueue<V> myQueue = new ReferenceQueue<V>(); |
||||
|
||||
public ConcurrentRefValueHashMap(@NotNull Map<K, V> map) { |
||||
this(); |
||||
putAll(map); |
||||
} |
||||
|
||||
public ConcurrentRefValueHashMap() { |
||||
myMap = new ConcurrentHashMap<K, ValueReference<K, V>>(); |
||||
} |
||||
|
||||
public ConcurrentRefValueHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { |
||||
myMap = new ConcurrentHashMap<K, ValueReference<K, V>>(initialCapacity, loadFactor, concurrencyLevel); |
||||
} |
||||
|
||||
// public ConcurrentRefValueHashMap(int initialCapacity,
|
||||
// float loadFactor,
|
||||
// int concurrencyLevel,
|
||||
// @NotNull TObjectHashingStrategy<K> hashingStrategy) {
|
||||
// myMap = new ConcurrentHashMap<K, ValueReference<K, V>>(initialCapacity, loadFactor, concurrencyLevel, hashingStrategy);
|
||||
// }
|
||||
|
||||
protected interface ValueReference<K, V> { |
||||
@NotNull |
||||
K getKey(); |
||||
|
||||
V get(); |
||||
} |
||||
|
||||
// returns true if some refs were tossed
|
||||
boolean processQueue() { |
||||
boolean processed = false; |
||||
|
||||
while (true) { |
||||
@SuppressWarnings("unchecked") |
||||
ValueReference<K, V> ref = (ValueReference<K, V>)myQueue.poll(); |
||||
if (ref == null) break; |
||||
myMap.remove(ref.getKey(), ref); |
||||
processed = true; |
||||
} |
||||
return processed; |
||||
} |
||||
|
||||
@Override |
||||
public V get(@NotNull Object key) { |
||||
ValueReference<K, V> ref = myMap.get(key); |
||||
if (ref == null) return null; |
||||
return ref.get(); |
||||
} |
||||
|
||||
@Override |
||||
public V put(@NotNull K key, @NotNull V value) { |
||||
processQueue(); |
||||
ValueReference<K, V> oldRef = myMap.put(key, createValueReference(key, value)); |
||||
return oldRef != null ? oldRef.get() : null; |
||||
} |
||||
|
||||
@NotNull |
||||
protected abstract ValueReference<K, V> createValueReference(@NotNull K key, @NotNull V value); |
||||
|
||||
@Override |
||||
public V putIfAbsent(@NotNull K key, @NotNull V value) { |
||||
ValueReference<K, V> newRef = createValueReference(key, value); |
||||
while (true) { |
||||
processQueue(); |
||||
ValueReference<K, V> oldRef = myMap.putIfAbsent(key, newRef); |
||||
if (oldRef == null) return null; |
||||
final V oldVal = oldRef.get(); |
||||
if (oldVal == null) { |
||||
if (myMap.replace(key, oldRef, newRef)) return null; |
||||
} |
||||
else { |
||||
return oldVal; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(@NotNull final Object key, @NotNull Object value) { |
||||
processQueue(); |
||||
//noinspection unchecked
|
||||
return myMap.remove(key, createValueReference((K)key, (V)value)); |
||||
} |
||||
|
||||
@Override |
||||
public boolean replace(@NotNull final K key, @NotNull final V oldValue, @NotNull final V newValue) { |
||||
processQueue(); |
||||
return myMap.replace(key, createValueReference(key, oldValue), createValueReference(key, newValue)); |
||||
} |
||||
|
||||
@Override |
||||
public V replace(@NotNull final K key, @NotNull final V value) { |
||||
processQueue(); |
||||
ValueReference<K, V> ref = myMap.replace(key, createValueReference(key, value)); |
||||
return ref == null ? null : ref.get(); |
||||
} |
||||
|
||||
@Override |
||||
public V remove(@NotNull Object key) { |
||||
processQueue(); |
||||
ValueReference<K, V> ref = myMap.remove(key); |
||||
return ref == null ? null : ref.get(); |
||||
} |
||||
|
||||
@Override |
||||
public void putAll(@NotNull Map<? extends K, ? extends V> t) { |
||||
processQueue(); |
||||
for (Entry<? extends K, ? extends V> entry : t.entrySet()) { |
||||
V v = entry.getValue(); |
||||
if (v != null) { |
||||
K key = entry.getKey(); |
||||
put(key, v); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
myMap.clear(); |
||||
processQueue(); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
processQueue(); |
||||
return myMap.size(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
processQueue(); |
||||
return myMap.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsKey(@NotNull Object key) { |
||||
return get(key) != null; |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsValue(@NotNull Object value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@NotNull |
||||
@Override |
||||
public Set<K> keySet() { |
||||
return myMap.keySet(); |
||||
} |
||||
|
||||
@NotNull |
||||
@Override |
||||
public Collection<V> values() { |
||||
Collection<V> result = new ArrayList<V>(); |
||||
final Collection<ValueReference<K, V>> refs = myMap.values(); |
||||
for (ValueReference<K, V> ref : refs) { |
||||
final V value = ref.get(); |
||||
if (value != null) { |
||||
result.add(value); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
@NotNull |
||||
@Override |
||||
public Set<Entry<K, V>> entrySet() { |
||||
final Set<K> keys = keySet(); |
||||
Set<Entry<K, V>> entries = new HashSet<Entry<K, V>>(); |
||||
|
||||
for (final K key : keys) { |
||||
final V value = get(key); |
||||
if (value != null) { |
||||
entries.add(new Entry<K, V>() { |
||||
@Override |
||||
public K getKey() { |
||||
return key; |
||||
} |
||||
|
||||
@Override |
||||
public V getValue() { |
||||
return value; |
||||
} |
||||
|
||||
@Override |
||||
public V setValue(@NotNull V value) { |
||||
throw new UnsupportedOperationException("setValue is not implemented"); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "(" + getKey() + " : " + getValue() + ")"; |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
return entries; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "map size:" + size() + " [" + StringUtil.join(entrySet(), ",") + "]"; |
||||
} |
||||
|
||||
@TestOnly |
||||
int underlyingMapSize() { |
||||
return myMap.size(); |
||||
} |
||||
} |
@ -0,0 +1,79 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
import java.lang.ref.ReferenceQueue; |
||||
import java.lang.ref.SoftReference; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Concurrent strong key:K -> soft value:V map |
||||
* Null keys are NOT allowed |
||||
* Null values are NOT allowed |
||||
*/ |
||||
public final class ConcurrentSoftValueHashMap<K,V> extends ConcurrentRefValueHashMap<K,V> { |
||||
public ConcurrentSoftValueHashMap(@NotNull Map<K, V> map) { |
||||
super(map); |
||||
} |
||||
|
||||
public ConcurrentSoftValueHashMap() { |
||||
} |
||||
|
||||
public ConcurrentSoftValueHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { |
||||
super(initialCapacity, loadFactor, concurrencyLevel); |
||||
} |
||||
|
||||
// public ConcurrentSoftValueHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<K> hashingStrategy) {
|
||||
// super(initialCapacity, loadFactor, concurrencyLevel, hashingStrategy);
|
||||
// }
|
||||
|
||||
private static class MySoftReference<K, V> extends SoftReference<V> implements ValueReference<K, V> { |
||||
private final K key; |
||||
private MySoftReference(@NotNull K key, @NotNull V referent, @NotNull ReferenceQueue<V> q) { |
||||
super(referent, q); |
||||
this.key = key; |
||||
} |
||||
|
||||
@NotNull |
||||
@Override |
||||
public K getKey() { |
||||
return key; |
||||
} |
||||
|
||||
// When referent is collected, equality should be identity-based (for the processQueues() remove this very same SoftValue)
|
||||
// otherwise it's just canonical equals on referents for replace(K,V,V) to work
|
||||
public final boolean equals(final Object o) { |
||||
if (this == o) return true; |
||||
if (o == null || getClass() != o.getClass()) return false; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
ValueReference<K,V> that = (ValueReference)o; |
||||
|
||||
V v = get(); |
||||
V thatV = that.get(); |
||||
return key.equals(that.getKey()) && v != null && thatV != null && v.equals(thatV); |
||||
} |
||||
} |
||||
|
||||
@NotNull |
||||
@Override |
||||
protected ValueReference<K, V> createValueReference(@NotNull K key, @NotNull V value) { |
||||
return new MySoftReference<K,V>(key, value, myQueue); |
||||
} |
||||
} |
@ -0,0 +1,204 @@
|
||||
/* |
||||
* Copyright 2000-2013 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
|
||||
import java.awt.*; |
||||
import java.awt.color.ColorSpace; |
||||
import java.awt.geom.AffineTransform; |
||||
import java.awt.geom.Rectangle2D; |
||||
import java.awt.image.ColorModel; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class DoubleColor extends Color { |
||||
|
||||
private static volatile boolean DARK = UIUtil.isUnderDarcula(); |
||||
|
||||
private final Color darkColor; |
||||
|
||||
public DoubleColor(int rgb, int darkRGB) { |
||||
this(new Color(rgb), new Color(darkRGB)); |
||||
} |
||||
|
||||
public DoubleColor(Color regular, Color dark) { |
||||
super(regular.getRGB(), regular.getAlpha() != 255); |
||||
darkColor = dark; |
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
DARK = UIUtil.isUnderDarcula(); //Double check. Sometimes DARK != isDarcula() after dialogs appear on splash screen
|
||||
} |
||||
|
||||
public static void setDark(boolean dark) { |
||||
DARK = dark; |
||||
} |
||||
|
||||
Color getDarkVariant() { |
||||
return darkColor; |
||||
} |
||||
|
||||
@Override |
||||
public int getRed() { |
||||
return DARK ? getDarkVariant().getRed() : super.getRed(); |
||||
} |
||||
|
||||
@Override |
||||
public int getGreen() { |
||||
return DARK ? getDarkVariant().getGreen() : super.getGreen(); |
||||
} |
||||
|
||||
@Override |
||||
public int getBlue() { |
||||
return DARK ? getDarkVariant().getBlue() : super.getBlue(); |
||||
} |
||||
|
||||
@Override |
||||
public int getAlpha() { |
||||
return DARK ? getDarkVariant().getAlpha() : super.getAlpha(); |
||||
} |
||||
|
||||
@Override |
||||
public int getRGB() { |
||||
return DARK ? getDarkVariant().getRGB() : super.getRGB(); |
||||
} |
||||
|
||||
@Override |
||||
public Color brighter() { |
||||
return new DoubleColor(super.brighter(), getDarkVariant().brighter()); |
||||
} |
||||
|
||||
@Override |
||||
public Color darker() { |
||||
return new DoubleColor(super.darker(), getDarkVariant().darker()); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return DARK ? getDarkVariant().hashCode() : super.hashCode(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
return DARK ? getDarkVariant().equals(obj) : super.equals(obj); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return DARK ? getDarkVariant().toString() : super.toString(); |
||||
} |
||||
|
||||
@Override |
||||
public float[] getRGBComponents(float[] compArray) { |
||||
return DARK ? getDarkVariant().getRGBComponents(compArray) : super.getRGBComponents(compArray); |
||||
} |
||||
|
||||
@Override |
||||
public float[] getRGBColorComponents(float[] compArray) { |
||||
return DARK ? getDarkVariant().getRGBColorComponents(compArray) : super.getRGBComponents(compArray); |
||||
} |
||||
|
||||
@Override |
||||
public float[] getComponents(float[] compArray) { |
||||
return DARK ? getDarkVariant().getComponents(compArray) : super.getComponents(compArray); |
||||
} |
||||
|
||||
@Override |
||||
public float[] getColorComponents(float[] compArray) { |
||||
return DARK ? getDarkVariant().getColorComponents(compArray) : super.getColorComponents(compArray); |
||||
} |
||||
|
||||
@Override |
||||
public float[] getComponents(ColorSpace cspace, float[] compArray) { |
||||
return DARK ? getDarkVariant().getComponents(cspace, compArray) : super.getComponents(cspace, compArray); |
||||
} |
||||
|
||||
@Override |
||||
public float[] getColorComponents(ColorSpace cspace, float[] compArray) { |
||||
return DARK ? getDarkVariant().getColorComponents(cspace, compArray) : super.getColorComponents(cspace, compArray); |
||||
} |
||||
|
||||
@Override |
||||
public ColorSpace getColorSpace() { |
||||
return DARK ? getDarkVariant().getColorSpace() : super.getColorSpace(); |
||||
} |
||||
|
||||
@Override |
||||
public synchronized PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D r2d, AffineTransform xform, RenderingHints hints) { |
||||
return DARK ? getDarkVariant().createContext(cm, r, r2d, xform, hints) : super.createContext(cm, r, r2d, xform, hints); |
||||
} |
||||
|
||||
@Override |
||||
public int getTransparency() { |
||||
return DARK ? getDarkVariant().getTransparency() : super.getTransparency(); |
||||
} |
||||
|
||||
public static final DoubleColor red = new DoubleColor(Color.red, new Color(255, 100, 100)); |
||||
public static final DoubleColor RED = red; |
||||
|
||||
public static final DoubleColor blue = new DoubleColor(Color.blue, new Color(0x589df6)); |
||||
public static final DoubleColor BLUE = blue; |
||||
|
||||
public static final DoubleColor white = new DoubleColor(Color.white, UIUtil.getListBackground()) { |
||||
@Override |
||||
Color getDarkVariant() { |
||||
return UIUtil.getListBackground(); |
||||
} |
||||
}; |
||||
public static final DoubleColor WHITE = white; |
||||
|
||||
public static final DoubleColor black = new DoubleColor(Color.black, UIUtil.getListForeground()) { |
||||
@Override |
||||
Color getDarkVariant() { |
||||
return UIUtil.getListForeground(); |
||||
} |
||||
}; |
||||
public static final DoubleColor BLACK = black; |
||||
|
||||
public static final DoubleColor gray = new DoubleColor(Gray._128, Gray._128); |
||||
public static final DoubleColor GRAY = gray; |
||||
|
||||
public static final DoubleColor lightGray = new DoubleColor(Gray._192, Gray._64); |
||||
public static final DoubleColor LIGHT_GRAY = lightGray; |
||||
|
||||
public static final DoubleColor darkGray = new DoubleColor(Gray._64, Gray._192); |
||||
public static final DoubleColor DARK_GRAY = darkGray; |
||||
|
||||
public static final DoubleColor pink = new DoubleColor(Color.pink, Color.pink); |
||||
public static final DoubleColor PINK = pink; |
||||
|
||||
public static final DoubleColor orange = new DoubleColor(Color.orange, new Color(159, 107, 0)); |
||||
public static final DoubleColor ORANGE = orange; |
||||
|
||||
public static final DoubleColor yellow = new DoubleColor(Color.yellow, new Color(138, 138, 0)); |
||||
public static final DoubleColor YELLOW = yellow; |
||||
|
||||
public static final DoubleColor green = new DoubleColor(Color.green, new Color(98, 150, 85)); |
||||
public static final DoubleColor GREEN = green; |
||||
|
||||
public static final Color magenta = new DoubleColor(Color.magenta, new Color(151, 118, 169)); |
||||
public static final Color MAGENTA = magenta; |
||||
|
||||
public static final Color cyan = new DoubleColor(Color.cyan, new Color(0, 137, 137)); |
||||
public static final Color CYAN = cyan; |
||||
|
||||
public static Color foreground() { |
||||
return UIUtil.getLabelForeground(); |
||||
} |
||||
|
||||
public static Color background() { |
||||
return UIUtil.getListBackground(); |
||||
} |
||||
} |
@ -0,0 +1,92 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class EmptyIcon implements Icon { |
||||
private static final Map<Integer, Icon> cache = new HashMap<Integer, Icon>(); |
||||
private final int width; |
||||
private final int height; |
||||
|
||||
public static Icon create(int size) { |
||||
Icon icon = cache.get(size); |
||||
if (icon == null && size < 129) { |
||||
cache.put(size, icon = new EmptyIcon(size, size)); |
||||
} |
||||
return icon == null ? new EmptyIcon(size, size) : icon; |
||||
} |
||||
|
||||
public static Icon create(int width, int height) { |
||||
return width == height ? create(width) : new EmptyIcon(width, height); |
||||
} |
||||
|
||||
public static Icon create(Icon base) { |
||||
return create(base.getIconWidth(), base.getIconHeight()); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated use {@linkplain #create(int)} for caching. |
||||
*/ |
||||
public EmptyIcon(int size) { |
||||
this(size, size); |
||||
} |
||||
|
||||
public EmptyIcon(int width, int height) { |
||||
this.width = width; |
||||
this.height = height; |
||||
} |
||||
|
||||
/** |
||||
* @deprecated use {@linkplain #create(javax.swing.Icon)} for caching. |
||||
*/ |
||||
public EmptyIcon(Icon base) { |
||||
this(base.getIconWidth(), base.getIconHeight()); |
||||
} |
||||
|
||||
public int getIconWidth() { |
||||
return width; |
||||
} |
||||
|
||||
public int getIconHeight() { |
||||
return height; |
||||
} |
||||
|
||||
public void paintIcon(Component component, Graphics g, int i, int j) { |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof EmptyIcon)) return false; |
||||
|
||||
final EmptyIcon icon = (EmptyIcon) o; |
||||
|
||||
return height == icon.height && width == icon.width; |
||||
|
||||
} |
||||
|
||||
public int hashCode() { |
||||
int sum = width + height; |
||||
return sum * (sum + 1) / 2 + width; |
||||
} |
||||
} |
@ -0,0 +1,21 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
public interface Getter<A> { |
||||
A get(); |
||||
} |
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.awt.*; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class GraphicsConfig { |
||||
|
||||
private final Graphics2D myG; |
||||
private final Map myHints; |
||||
|
||||
public GraphicsConfig(Graphics g) { |
||||
myG = (Graphics2D) g; |
||||
myHints = (Map) myG.getRenderingHints().clone(); |
||||
} |
||||
|
||||
public GraphicsConfig setAntialiasing(boolean on) { |
||||
myG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, on ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); |
||||
return this; |
||||
} |
||||
|
||||
public Graphics2D getG() { |
||||
return myG; |
||||
} |
||||
|
||||
public void restore() { |
||||
myG.setRenderingHints(myHints); |
||||
} |
||||
} |
@ -0,0 +1,62 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.awt.*; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class GraphicsUtil { |
||||
public static void setupAntialiasing(Graphics g2) { |
||||
setupAntialiasing(g2, true, false); |
||||
} |
||||
|
||||
public static void setupAntialiasing(Graphics g2, boolean enableAA, boolean ignoreSystemSettings) { |
||||
if (g2 instanceof Graphics2D) { |
||||
Graphics2D g = (Graphics2D) g2; |
||||
Toolkit tk = Toolkit.getDefaultToolkit(); |
||||
//noinspection HardCodedStringLiteral
|
||||
Map map = (Map) tk.getDesktopProperty("awt.font.desktophints"); |
||||
|
||||
if (map != null && !ignoreSystemSettings) { |
||||
g.addRenderingHints(map); |
||||
} else { |
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, |
||||
enableAA ? RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static GraphicsConfig setupAAPainting(Graphics g) { |
||||
final GraphicsConfig config = new GraphicsConfig(g); |
||||
final Graphics2D g2 = (Graphics2D) g; |
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); |
||||
return config; |
||||
} |
||||
|
||||
public static GraphicsConfig paintWithAlpha(Graphics g, float alpha) { |
||||
assert 0.0f <= alpha && alpha <= 1.0f : "alpha should be in range 0.0f .. 1.0f"; |
||||
final GraphicsConfig config = new GraphicsConfig(g); |
||||
final Graphics2D g2 = (Graphics2D) g; |
||||
|
||||
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); |
||||
return config; |
||||
} |
||||
} |
@ -0,0 +1,605 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
@SuppressWarnings({"InspectionUsingGrayColors", "UnusedDeclaration"}) |
||||
public class Gray extends Color { |
||||
private Gray(int num) { |
||||
super(num, num, num); |
||||
} |
||||
|
||||
private Gray(int num, int alpha) { |
||||
super(num, num, num, alpha); |
||||
} |
||||
|
||||
public Color withAlpha(int alpha) { |
||||
assert 0 <= alpha && alpha <= 255 : "Alpha " + alpha + "is incorrect. Alpha should be in range 0..255"; |
||||
return new Gray(getRed(), alpha); |
||||
} |
||||
|
||||
public static Gray get(int gray) { |
||||
assert 0 <= gray && gray <= 255 : "Gray == " + gray + "Gray should be in range 0..255"; |
||||
return cache[gray]; |
||||
} |
||||
|
||||
public static Color get(int gray, int alpha) { |
||||
return get(gray).withAlpha(alpha); |
||||
} |
||||
|
||||
public static final Gray _0 = new Gray(0); |
||||
public static final Gray _1 = new Gray(1); |
||||
public static final Gray _2 = new Gray(2); |
||||
public static final Gray _3 = new Gray(3); |
||||
public static final Gray _4 = new Gray(4); |
||||
public static final Gray _5 = new Gray(5); |
||||
public static final Gray _6 = new Gray(6); |
||||
public static final Gray _7 = new Gray(7); |
||||
public static final Gray _8 = new Gray(8); |
||||
public static final Gray _9 = new Gray(9); |
||||
public static final Gray _10 = new Gray(10); |
||||
public static final Gray _11 = new Gray(11); |
||||
public static final Gray _12 = new Gray(12); |
||||
public static final Gray _13 = new Gray(13); |
||||
public static final Gray _14 = new Gray(14); |
||||
public static final Gray _15 = new Gray(15); |
||||
public static final Gray _16 = new Gray(16); |
||||
public static final Gray _17 = new Gray(17); |
||||
public static final Gray _18 = new Gray(18); |
||||
public static final Gray _19 = new Gray(19); |
||||
public static final Gray _20 = new Gray(20); |
||||
public static final Gray _21 = new Gray(21); |
||||
public static final Gray _22 = new Gray(22); |
||||
public static final Gray _23 = new Gray(23); |
||||
public static final Gray _24 = new Gray(24); |
||||
public static final Gray _25 = new Gray(25); |
||||
public static final Gray _26 = new Gray(26); |
||||
public static final Gray _27 = new Gray(27); |
||||
public static final Gray _28 = new Gray(28); |
||||
public static final Gray _29 = new Gray(29); |
||||
public static final Gray _30 = new Gray(30); |
||||
public static final Gray _31 = new Gray(31); |
||||
public static final Gray _32 = new Gray(32); |
||||
public static final Gray _33 = new Gray(33); |
||||
public static final Gray _34 = new Gray(34); |
||||
public static final Gray _36 = new Gray(36); |
||||
public static final Gray _35 = new Gray(35); |
||||
public static final Gray _37 = new Gray(37); |
||||
public static final Gray _38 = new Gray(38); |
||||
public static final Gray _39 = new Gray(39); |
||||
public static final Gray _40 = new Gray(40); |
||||
public static final Gray _41 = new Gray(41); |
||||
public static final Gray _42 = new Gray(42); |
||||
public static final Gray _43 = new Gray(43); |
||||
public static final Gray _44 = new Gray(44); |
||||
public static final Gray _45 = new Gray(45); |
||||
public static final Gray _46 = new Gray(46); |
||||
public static final Gray _47 = new Gray(47); |
||||
public static final Gray _48 = new Gray(48); |
||||
public static final Gray _49 = new Gray(49); |
||||
public static final Gray _50 = new Gray(50); |
||||
public static final Gray _51 = new Gray(51); |
||||
public static final Gray _52 = new Gray(52); |
||||
public static final Gray _53 = new Gray(53); |
||||
public static final Gray _54 = new Gray(54); |
||||
public static final Gray _55 = new Gray(55); |
||||
public static final Gray _56 = new Gray(56); |
||||
public static final Gray _57 = new Gray(57); |
||||
public static final Gray _58 = new Gray(58); |
||||
public static final Gray _59 = new Gray(59); |
||||
public static final Gray _60 = new Gray(60); |
||||
public static final Gray _61 = new Gray(61); |
||||
public static final Gray _62 = new Gray(62); |
||||
public static final Gray _63 = new Gray(63); |
||||
public static final Gray _64 = new Gray(64); |
||||
public static final Gray _65 = new Gray(65); |
||||
public static final Gray _66 = new Gray(66); |
||||
public static final Gray _67 = new Gray(67); |
||||
public static final Gray _68 = new Gray(68); |
||||
public static final Gray _69 = new Gray(69); |
||||
public static final Gray _70 = new Gray(70); |
||||
public static final Gray _71 = new Gray(71); |
||||
public static final Gray _72 = new Gray(72); |
||||
public static final Gray _73 = new Gray(73); |
||||
public static final Gray _74 = new Gray(74); |
||||
public static final Gray _75 = new Gray(75); |
||||
public static final Gray _76 = new Gray(76); |
||||
public static final Gray _77 = new Gray(77); |
||||
public static final Gray _78 = new Gray(78); |
||||
public static final Gray _79 = new Gray(79); |
||||
public static final Gray _80 = new Gray(80); |
||||
public static final Gray _81 = new Gray(81); |
||||
public static final Gray _82 = new Gray(82); |
||||
public static final Gray _83 = new Gray(83); |
||||
public static final Gray _84 = new Gray(84); |
||||
public static final Gray _85 = new Gray(85); |
||||
public static final Gray _86 = new Gray(86); |
||||
public static final Gray _87 = new Gray(87); |
||||
public static final Gray _88 = new Gray(88); |
||||
public static final Gray _89 = new Gray(89); |
||||
public static final Gray _90 = new Gray(90); |
||||
public static final Gray _91 = new Gray(91); |
||||
public static final Gray _92 = new Gray(92); |
||||
public static final Gray _93 = new Gray(93); |
||||
public static final Gray _94 = new Gray(94); |
||||
public static final Gray _95 = new Gray(95); |
||||
public static final Gray _96 = new Gray(96); |
||||
public static final Gray _97 = new Gray(97); |
||||
public static final Gray _98 = new Gray(98); |
||||
public static final Gray _99 = new Gray(99); |
||||
public static final Gray _100 = new Gray(100); |
||||
public static final Gray _101 = new Gray(101); |
||||
public static final Gray _102 = new Gray(102); |
||||
public static final Gray _103 = new Gray(103); |
||||
public static final Gray _104 = new Gray(104); |
||||
public static final Gray _105 = new Gray(105); |
||||
public static final Gray _106 = new Gray(106); |
||||
public static final Gray _107 = new Gray(107); |
||||
public static final Gray _108 = new Gray(108); |
||||
public static final Gray _109 = new Gray(109); |
||||
public static final Gray _110 = new Gray(110); |
||||
public static final Gray _111 = new Gray(111); |
||||
public static final Gray _112 = new Gray(112); |
||||
public static final Gray _113 = new Gray(113); |
||||
public static final Gray _114 = new Gray(114); |
||||
public static final Gray _115 = new Gray(115); |
||||
public static final Gray _116 = new Gray(116); |
||||
public static final Gray _117 = new Gray(117); |
||||
public static final Gray _118 = new Gray(118); |
||||
public static final Gray _119 = new Gray(119); |
||||
public static final Gray _120 = new Gray(120); |
||||
public static final Gray _121 = new Gray(121); |
||||
public static final Gray _122 = new Gray(122); |
||||
public static final Gray _123 = new Gray(123); |
||||
public static final Gray _124 = new Gray(124); |
||||
public static final Gray _125 = new Gray(125); |
||||
public static final Gray _126 = new Gray(126); |
||||
public static final Gray _127 = new Gray(127); |
||||
public static final Gray _128 = new Gray(128); |
||||
public static final Gray _129 = new Gray(129); |
||||
public static final Gray _130 = new Gray(130); |
||||
public static final Gray _131 = new Gray(131); |
||||
public static final Gray _132 = new Gray(132); |
||||
public static final Gray _133 = new Gray(133); |
||||
public static final Gray _134 = new Gray(134); |
||||
public static final Gray _135 = new Gray(135); |
||||
public static final Gray _136 = new Gray(136); |
||||
public static final Gray _137 = new Gray(137); |
||||
public static final Gray _138 = new Gray(138); |
||||
public static final Gray _139 = new Gray(139); |
||||
public static final Gray _140 = new Gray(140); |
||||
public static final Gray _141 = new Gray(141); |
||||
public static final Gray _142 = new Gray(142); |
||||
public static final Gray _143 = new Gray(143); |
||||
public static final Gray _144 = new Gray(144); |
||||
public static final Gray _145 = new Gray(145); |
||||
public static final Gray _146 = new Gray(146); |
||||
public static final Gray _147 = new Gray(147); |
||||
public static final Gray _148 = new Gray(148); |
||||
public static final Gray _149 = new Gray(149); |
||||
public static final Gray _150 = new Gray(150); |
||||
public static final Gray _151 = new Gray(151); |
||||
public static final Gray _152 = new Gray(152); |
||||
public static final Gray _153 = new Gray(153); |
||||
public static final Gray _154 = new Gray(154); |
||||
public static final Gray _155 = new Gray(155); |
||||
public static final Gray _156 = new Gray(156); |
||||
public static final Gray _157 = new Gray(157); |
||||
public static final Gray _158 = new Gray(158); |
||||
public static final Gray _159 = new Gray(159); |
||||
public static final Gray _160 = new Gray(160); |
||||
public static final Gray _161 = new Gray(161); |
||||
public static final Gray _162 = new Gray(162); |
||||
public static final Gray _163 = new Gray(163); |
||||
public static final Gray _164 = new Gray(164); |
||||
public static final Gray _165 = new Gray(165); |
||||
public static final Gray _166 = new Gray(166); |
||||
public static final Gray _167 = new Gray(167); |
||||
public static final Gray _168 = new Gray(168); |
||||
public static final Gray _169 = new Gray(169); |
||||
public static final Gray _170 = new Gray(170); |
||||
public static final Gray _171 = new Gray(171); |
||||
public static final Gray _172 = new Gray(172); |
||||
public static final Gray _173 = new Gray(173); |
||||
public static final Gray _174 = new Gray(174); |
||||
public static final Gray _175 = new Gray(175); |
||||
public static final Gray _176 = new Gray(176); |
||||
public static final Gray _177 = new Gray(177); |
||||
public static final Gray _178 = new Gray(178); |
||||
public static final Gray _179 = new Gray(179); |
||||
public static final Gray _180 = new Gray(180); |
||||
public static final Gray _181 = new Gray(181); |
||||
public static final Gray _182 = new Gray(182); |
||||
public static final Gray _183 = new Gray(183); |
||||
public static final Gray _184 = new Gray(184); |
||||
public static final Gray _185 = new Gray(185); |
||||
public static final Gray _186 = new Gray(186); |
||||
public static final Gray _187 = new Gray(187); |
||||
public static final Gray _188 = new Gray(188); |
||||
public static final Gray _189 = new Gray(189); |
||||
public static final Gray _190 = new Gray(190); |
||||
public static final Gray _191 = new Gray(191); |
||||
public static final Gray _192 = new Gray(192); |
||||
public static final Gray _193 = new Gray(193); |
||||
public static final Gray _194 = new Gray(194); |
||||
public static final Gray _195 = new Gray(195); |
||||
public static final Gray _196 = new Gray(196); |
||||
public static final Gray _197 = new Gray(197); |
||||
public static final Gray _198 = new Gray(198); |
||||
public static final Gray _199 = new Gray(199); |
||||
public static final Gray _200 = new Gray(200); |
||||
public static final Gray _201 = new Gray(201); |
||||
public static final Gray _202 = new Gray(202); |
||||
public static final Gray _203 = new Gray(203); |
||||
public static final Gray _204 = new Gray(204); |
||||
public static final Gray _205 = new Gray(205); |
||||
public static final Gray _206 = new Gray(206); |
||||
public static final Gray _207 = new Gray(207); |
||||
public static final Gray _208 = new Gray(208); |
||||
public static final Gray _209 = new Gray(209); |
||||
public static final Gray _210 = new Gray(210); |
||||
public static final Gray _211 = new Gray(211); |
||||
public static final Gray _212 = new Gray(212); |
||||
public static final Gray _213 = new Gray(213); |
||||
public static final Gray _214 = new Gray(214); |
||||
public static final Gray _215 = new Gray(215); |
||||
public static final Gray _216 = new Gray(216); |
||||
public static final Gray _217 = new Gray(217); |
||||
public static final Gray _218 = new Gray(218); |
||||
public static final Gray _219 = new Gray(219); |
||||
public static final Gray _220 = new Gray(220); |
||||
public static final Gray _221 = new Gray(221); |
||||
public static final Gray _222 = new Gray(222); |
||||
public static final Gray _223 = new Gray(223); |
||||
public static final Gray _224 = new Gray(224); |
||||
public static final Gray _225 = new Gray(225); |
||||
public static final Gray _226 = new Gray(226); |
||||
public static final Gray _227 = new Gray(227); |
||||
public static final Gray _228 = new Gray(228); |
||||
public static final Gray _229 = new Gray(229); |
||||
public static final Gray _230 = new Gray(230); |
||||
public static final Gray _231 = new Gray(231); |
||||
public static final Gray _232 = new Gray(232); |
||||
public static final Gray _233 = new Gray(233); |
||||
public static final Gray _234 = new Gray(234); |
||||
public static final Gray _235 = new Gray(235); |
||||
public static final Gray _236 = new Gray(236); |
||||
public static final Gray _237 = new Gray(237); |
||||
public static final Gray _238 = new Gray(238); |
||||
public static final Gray _239 = new Gray(239); |
||||
public static final Gray _240 = new Gray(240); |
||||
public static final Gray _241 = new Gray(241); |
||||
public static final Gray _242 = new Gray(242); |
||||
public static final Gray _243 = new Gray(243); |
||||
public static final Gray _244 = new Gray(244); |
||||
public static final Gray _245 = new Gray(245); |
||||
public static final Gray _246 = new Gray(246); |
||||
public static final Gray _247 = new Gray(247); |
||||
public static final Gray _248 = new Gray(248); |
||||
public static final Gray _249 = new Gray(249); |
||||
public static final Gray _250 = new Gray(250); |
||||
public static final Gray _251 = new Gray(251); |
||||
public static final Gray _252 = new Gray(252); |
||||
public static final Gray _253 = new Gray(253); |
||||
public static final Gray _254 = new Gray(254); |
||||
public static final Gray _255 = new Gray(255); |
||||
|
||||
public static final Gray x00 = _0; |
||||
public static final Gray x01 = _1; |
||||
public static final Gray x02 = _2; |
||||
public static final Gray x03 = _3; |
||||
public static final Gray x04 = _4; |
||||
public static final Gray x05 = _5; |
||||
public static final Gray x06 = _6; |
||||
public static final Gray x07 = _7; |
||||
public static final Gray x08 = _8; |
||||
public static final Gray x09 = _9; |
||||
public static final Gray x0A = _10; |
||||
public static final Gray x0B = _11; |
||||
public static final Gray x0C = _12; |
||||
public static final Gray x0D = _13; |
||||
public static final Gray x0E = _14; |
||||
public static final Gray x0F = _15; |
||||
public static final Gray x10 = _16; |
||||
public static final Gray x11 = _17; |
||||
public static final Gray x12 = _18; |
||||
public static final Gray x13 = _19; |
||||
public static final Gray x14 = _20; |
||||
public static final Gray x15 = _21; |
||||
public static final Gray x16 = _22; |
||||
public static final Gray x17 = _23; |
||||
public static final Gray x18 = _24; |
||||
public static final Gray x19 = _25; |
||||
public static final Gray x1A = _26; |
||||
public static final Gray x1B = _27; |
||||
public static final Gray x1C = _28; |
||||
public static final Gray x1D = _29; |
||||
public static final Gray x1E = _30; |
||||
public static final Gray x1F = _31; |
||||
public static final Gray x20 = _32; |
||||
public static final Gray x21 = _33; |
||||
public static final Gray x22 = _34; |
||||
public static final Gray x23 = _35; |
||||
public static final Gray x24 = _36; |
||||
public static final Gray x25 = _37; |
||||
public static final Gray x26 = _38; |
||||
public static final Gray x27 = _39; |
||||
public static final Gray x28 = _40; |
||||
public static final Gray x29 = _41; |
||||
public static final Gray x2A = _42; |
||||
public static final Gray x2B = _43; |
||||
public static final Gray x2C = _44; |
||||
public static final Gray x2D = _45; |
||||
public static final Gray x2E = _46; |
||||
public static final Gray x2F = _47; |
||||
public static final Gray x30 = _48; |
||||
public static final Gray x31 = _49; |
||||
public static final Gray x32 = _50; |
||||
public static final Gray x33 = _51; |
||||
public static final Gray x34 = _52; |
||||
public static final Gray x35 = _53; |
||||
public static final Gray x36 = _54; |
||||
public static final Gray x37 = _55; |
||||
public static final Gray x38 = _56; |
||||
public static final Gray x39 = _57; |
||||
public static final Gray x3A = _58; |
||||
public static final Gray x3B = _59; |
||||
public static final Gray x3C = _60; |
||||
public static final Gray x3D = _61; |
||||
public static final Gray x3E = _62; |
||||
public static final Gray x3F = _63; |
||||
public static final Gray x40 = _64; |
||||
public static final Gray x41 = _65; |
||||
public static final Gray x42 = _66; |
||||
public static final Gray x43 = _67; |
||||
public static final Gray x44 = _68; |
||||
public static final Gray x45 = _69; |
||||
public static final Gray x46 = _70; |
||||
public static final Gray x47 = _71; |
||||
public static final Gray x48 = _72; |
||||
public static final Gray x49 = _73; |
||||
public static final Gray x4A = _74; |
||||
public static final Gray x4B = _75; |
||||
public static final Gray x4C = _76; |
||||
public static final Gray x4D = _77; |
||||
public static final Gray x4E = _78; |
||||
public static final Gray x4F = _79; |
||||
public static final Gray x50 = _80; |
||||
public static final Gray x51 = _81; |
||||
public static final Gray x52 = _82; |
||||
public static final Gray x53 = _83; |
||||
public static final Gray x54 = _84; |
||||
public static final Gray x55 = _85; |
||||
public static final Gray x56 = _86; |
||||
public static final Gray x57 = _87; |
||||
public static final Gray x58 = _88; |
||||
public static final Gray x59 = _89; |
||||
public static final Gray x5A = _90; |
||||
public static final Gray x5B = _91; |
||||
public static final Gray x5C = _92; |
||||
public static final Gray x5D = _93; |
||||
public static final Gray x5E = _94; |
||||
public static final Gray x5F = _95; |
||||
public static final Gray x60 = _96; |
||||
public static final Gray x61 = _97; |
||||
public static final Gray x62 = _98; |
||||
public static final Gray x63 = _99; |
||||
public static final Gray x64 = _100; |
||||
public static final Gray x65 = _101; |
||||
public static final Gray x66 = _102; |
||||
public static final Gray x67 = _103; |
||||
public static final Gray x68 = _104; |
||||
public static final Gray x69 = _105; |
||||
public static final Gray x6A = _106; |
||||
public static final Gray x6B = _107; |
||||
public static final Gray x6C = _108; |
||||
public static final Gray x6D = _109; |
||||
public static final Gray x6E = _110; |
||||
public static final Gray x6F = _111; |
||||
public static final Gray x70 = _112; |
||||
public static final Gray x71 = _113; |
||||
public static final Gray x72 = _114; |
||||
public static final Gray x73 = _115; |
||||
public static final Gray x74 = _116; |
||||
public static final Gray x75 = _117; |
||||
public static final Gray x76 = _118; |
||||
public static final Gray x77 = _119; |
||||
public static final Gray x78 = _120; |
||||
public static final Gray x79 = _121; |
||||
public static final Gray x7A = _122; |
||||
public static final Gray x7B = _123; |
||||
public static final Gray x7C = _124; |
||||
public static final Gray x7D = _125; |
||||
public static final Gray x7E = _126; |
||||
public static final Gray x7F = _127; |
||||
public static final Gray x80 = _128; |
||||
public static final Gray x81 = _129; |
||||
public static final Gray x82 = _130; |
||||
public static final Gray x83 = _131; |
||||
public static final Gray x84 = _132; |
||||
public static final Gray x85 = _133; |
||||
public static final Gray x86 = _134; |
||||
public static final Gray x87 = _135; |
||||
public static final Gray x88 = _136; |
||||
public static final Gray x89 = _137; |
||||
public static final Gray x8A = _138; |
||||
public static final Gray x8B = _139; |
||||
public static final Gray x8C = _140; |
||||
public static final Gray x8D = _141; |
||||
public static final Gray x8E = _142; |
||||
public static final Gray x8F = _143; |
||||
public static final Gray x90 = _144; |
||||
public static final Gray x91 = _145; |
||||
public static final Gray x92 = _146; |
||||
public static final Gray x93 = _147; |
||||
public static final Gray x94 = _148; |
||||
public static final Gray x95 = _149; |
||||
public static final Gray x96 = _150; |
||||
public static final Gray x97 = _151; |
||||
public static final Gray x98 = _152; |
||||
public static final Gray x99 = _153; |
||||
public static final Gray x9A = _154; |
||||
public static final Gray x9B = _155; |
||||
public static final Gray x9C = _156; |
||||
public static final Gray x9D = _157; |
||||
public static final Gray x9E = _158; |
||||
public static final Gray x9F = _159; |
||||
public static final Gray xA0 = _160; |
||||
public static final Gray xA1 = _161; |
||||
public static final Gray xA2 = _162; |
||||
public static final Gray xA3 = _163; |
||||
public static final Gray xA4 = _164; |
||||
public static final Gray xA5 = _165; |
||||
public static final Gray xA6 = _166; |
||||
public static final Gray xA7 = _167; |
||||
public static final Gray xA8 = _168; |
||||
public static final Gray xA9 = _169; |
||||
public static final Gray xAA = _170; |
||||
public static final Gray xAB = _171; |
||||
public static final Gray xAC = _172; |
||||
public static final Gray xAD = _173; |
||||
public static final Gray xAE = _174; |
||||
public static final Gray xAF = _175; |
||||
public static final Gray xB0 = _176; |
||||
public static final Gray xB1 = _177; |
||||
public static final Gray xB2 = _178; |
||||
public static final Gray xB3 = _179; |
||||
public static final Gray xB4 = _180; |
||||
public static final Gray xB5 = _181; |
||||
public static final Gray xB6 = _182; |
||||
public static final Gray xB7 = _183; |
||||
public static final Gray xB8 = _184; |
||||
public static final Gray xB9 = _185; |
||||
public static final Gray xBA = _186; |
||||
public static final Gray xBB = _187; |
||||
public static final Gray xBC = _188; |
||||
public static final Gray xBD = _189; |
||||
public static final Gray xBE = _190; |
||||
public static final Gray xBF = _191; |
||||
public static final Gray xC0 = _192; |
||||
public static final Gray xC1 = _193; |
||||
public static final Gray xC2 = _194; |
||||
public static final Gray xC3 = _195; |
||||
public static final Gray xC4 = _196; |
||||
public static final Gray xC5 = _197; |
||||
public static final Gray xC6 = _198; |
||||
public static final Gray xC7 = _199; |
||||
public static final Gray xC8 = _200; |
||||
public static final Gray xC9 = _201; |
||||
public static final Gray xCA = _202; |
||||
public static final Gray xCB = _203; |
||||
public static final Gray xCC = _204; |
||||
public static final Gray xCD = _205; |
||||
public static final Gray xCE = _206; |
||||
public static final Gray xCF = _207; |
||||
public static final Gray xD0 = _208; |
||||
public static final Gray xD1 = _209; |
||||
public static final Gray xD2 = _210; |
||||
public static final Gray xD3 = _211; |
||||
public static final Gray xD4 = _212; |
||||
public static final Gray xD5 = _213; |
||||
public static final Gray xD6 = _214; |
||||
public static final Gray xD7 = _215; |
||||
public static final Gray xD8 = _216; |
||||
public static final Gray xD9 = _217; |
||||
public static final Gray xDA = _218; |
||||
public static final Gray xDB = _219; |
||||
public static final Gray xDC = _220; |
||||
public static final Gray xDD = _221; |
||||
public static final Gray xDE = _222; |
||||
public static final Gray xDF = _223; |
||||
public static final Gray xE0 = _224; |
||||
public static final Gray xE1 = _225; |
||||
public static final Gray xE2 = _226; |
||||
public static final Gray xE3 = _227; |
||||
public static final Gray xE4 = _228; |
||||
public static final Gray xE5 = _229; |
||||
public static final Gray xE6 = _230; |
||||
public static final Gray xE7 = _231; |
||||
public static final Gray xE8 = _232; |
||||
public static final Gray xE9 = _233; |
||||
public static final Gray xEA = _234; |
||||
public static final Gray xEB = _235; |
||||
public static final Gray xEC = _236; |
||||
public static final Gray xED = _237; |
||||
public static final Gray xEE = _238; |
||||
public static final Gray xEF = _239; |
||||
public static final Gray xF0 = _240; |
||||
public static final Gray xF1 = _241; |
||||
public static final Gray xF2 = _242; |
||||
public static final Gray xF3 = _243; |
||||
public static final Gray xF4 = _244; |
||||
public static final Gray xF5 = _245; |
||||
public static final Gray xF6 = _246; |
||||
public static final Gray xF7 = _247; |
||||
public static final Gray xF8 = _248; |
||||
public static final Gray xF9 = _249; |
||||
public static final Gray xFA = _250; |
||||
public static final Gray xFB = _251; |
||||
public static final Gray xFC = _252; |
||||
public static final Gray xFD = _253; |
||||
public static final Gray xFE = _254; |
||||
public static final Gray xFF = _255; |
||||
|
||||
private static final Gray[] cache = { |
||||
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, |
||||
_16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, |
||||
_32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, |
||||
_48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, |
||||
_64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, |
||||
_80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, |
||||
_96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, |
||||
_112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, |
||||
_128, _129, _130, _131, _132, _133, _134, _135, _136, _137, _138, _139, _140, _141, _142, _143, |
||||
_144, _145, _146, _147, _148, _149, _150, _151, _152, _153, _154, _155, _156, _157, _158, _159, |
||||
_160, _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, _171, _172, _173, _174, _175, |
||||
_176, _177, _178, _179, _180, _181, _182, _183, _184, _185, _186, _187, _188, _189, _190, _191, |
||||
_192, _193, _194, _195, _196, _197, _198, _199, _200, _201, _202, _203, _204, _205, _206, _207, |
||||
_208, _209, _210, _211, _212, _213, _214, _215, _216, _217, _218, _219, _220, _221, _222, _223, |
||||
_224, _225, _226, _227, _228, _229, _230, _231, _232, _233, _234, _235, _236, _237, _238, _239, |
||||
_240, _241, _242, _243, _244, _245, _246, _247, _248, _249, _250, _251, _252, _253, _254, _255}; |
||||
|
||||
//public static void main(String[] args) {
|
||||
// for (int i = 0; i < 256; i++) {
|
||||
// System.out.println("public static final Gray _" + i + " = new Gray("+ i + ");");
|
||||
// }
|
||||
// for (int i = 0; i < 256; i++) {
|
||||
// System.out.println("public static final Gray x" + (i < 16 ? "0" : "") + Integer.toHexString(i).toUpperCase() + " = _" + i + ";");
|
||||
// }
|
||||
//
|
||||
// System.out.println();
|
||||
// System.out.println("private static final Gray[] cache = {");
|
||||
// System.out.print(" ");
|
||||
// for (int i = 0; i < 256; i++) {
|
||||
// System.out.print(String.format("%4s", "_" + String.valueOf(i)));
|
||||
// if (i == 255) {
|
||||
// System.out.println("};");
|
||||
// } else {
|
||||
// if (i % 16 == 15) {
|
||||
// System.out.println(",");
|
||||
// System.out.print(" ");
|
||||
// } else {
|
||||
// System.out.print(", ");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
} |
@ -0,0 +1,404 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import com.bulenkov.iconloader.IconLoader; |
||||
import com.bulenkov.iconloader.RetinaImage; |
||||
import org.jetbrains.annotations.NonNls; |
||||
import org.jetbrains.annotations.NotNull; |
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.image.ImageFilter; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.Serializable; |
||||
import java.net.HttpURLConnection; |
||||
import java.net.URL; |
||||
import java.net.URLConnection; |
||||
import java.util.ArrayList; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class ImageLoader implements Serializable { |
||||
// private static final Log LOG = Logger.getLogger("#com.intellij.util.ImageLoader");
|
||||
|
||||
private static final ConcurrentMap<String, Image> ourCache = new ConcurrentSoftValueHashMap<String, Image>(); |
||||
|
||||
private static class ImageDesc { |
||||
public enum Type { |
||||
PNG, |
||||
|
||||
// SVG {
|
||||
// @Override
|
||||
// public Image load(URL url, InputStream is, float scale) throws IOException {
|
||||
// return SVGLoader.load(url, is, scale);
|
||||
// }
|
||||
// },
|
||||
|
||||
UNDEFINED; |
||||
|
||||
public Image load(URL url, InputStream stream, float scale) throws IOException { |
||||
return ImageLoader.load(stream, (int)scale); |
||||
} |
||||
} |
||||
|
||||
public final String path; |
||||
public final @Nullable Class cls; // resource class if present
|
||||
public final float scale; // initial scale factor
|
||||
public final Type type; |
||||
public final boolean original; // path is not altered
|
||||
|
||||
public ImageDesc(String path, Class cls, float scale, Type type) { |
||||
this(path, cls, scale, type, false); |
||||
} |
||||
|
||||
public ImageDesc(String path, Class cls, float scale, Type type, boolean original) { |
||||
this.path = path; |
||||
this.cls = cls; |
||||
this.scale = scale; |
||||
this.type = type; |
||||
this.original = original; |
||||
} |
||||
|
||||
@Nullable |
||||
public Image load() throws IOException { |
||||
String cacheKey = null; |
||||
InputStream stream = null; |
||||
URL url = null; |
||||
if (cls != null) { |
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
stream = cls.getResourceAsStream(path); |
||||
if (stream == null) return null; |
||||
} |
||||
if (stream == null) { |
||||
url = new URL(path); |
||||
URLConnection connection = url.openConnection(); |
||||
if (connection instanceof HttpURLConnection) { |
||||
if (!original) return null; |
||||
connection.addRequestProperty("User-Agent", "IntelliJ"); |
||||
|
||||
cacheKey = path; |
||||
Image image = ourCache.get(cacheKey); |
||||
if (image != null) return image; |
||||
} |
||||
stream = connection.getInputStream(); |
||||
} |
||||
Image image = type.load(url, stream, scale); |
||||
if (image != null && cacheKey != null) { |
||||
ourCache.put(cacheKey, image); |
||||
} |
||||
return image; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return path + ", scale: " + scale + ", type: " + type; |
||||
} |
||||
} |
||||
|
||||
private static class ImageDescList extends ArrayList<ImageDesc> { |
||||
private ImageDescList() {} |
||||
|
||||
@Nullable |
||||
public Image load() { |
||||
return load(ImageConverterChain.create()); |
||||
} |
||||
|
||||
@Nullable |
||||
public Image load(@NotNull ImageConverterChain converters) { |
||||
for (ImageDesc desc : this) { |
||||
try { |
||||
Image image = desc.load(); |
||||
if (image == null) continue; |
||||
// LOG.debug("Loaded image: " + desc);
|
||||
return converters.convert(image, desc); |
||||
} |
||||
catch (IOException ignore) { |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public static ImageDescList create(@NotNull String file, |
||||
@Nullable Class cls, |
||||
boolean dark, |
||||
boolean retina, |
||||
boolean allowFloatScaling) |
||||
{ |
||||
ImageDescList vars = new ImageDescList(); |
||||
if (retina || dark) { |
||||
final String name = getNameWithoutExtension(file); |
||||
final String ext = getExtension(file); |
||||
|
||||
float scale = calcScaleFactor(allowFloatScaling); |
||||
|
||||
// TODO: allow SVG images to freely scale on Retina
|
||||
|
||||
// if (Registry.is("ide.svg.icon") && dark) {
|
||||
// vars.add(new ImageDesc(name + "_dark.svg", cls, UIUtil.isRetina() ? 2f : scale, ImageDesc.Type.SVG));
|
||||
// }
|
||||
//
|
||||
// if (Registry.is("ide.svg.icon")) {
|
||||
// vars.add(new ImageDesc(name + ".svg", cls, UIUtil.isRetina() ? 2f : scale, ImageDesc.Type.SVG));
|
||||
// }
|
||||
|
||||
if (dark && retina) { |
||||
vars.add(new ImageDesc(name + "@2x_dark." + ext, cls, 2f, ImageDesc.Type.PNG)); |
||||
} |
||||
|
||||
if (dark) { |
||||
vars.add(new ImageDesc(name + "_dark." + ext, cls, 1f, ImageDesc.Type.PNG)); |
||||
} |
||||
|
||||
if (retina) { |
||||
vars.add(new ImageDesc(name + "@2x." + ext, cls, 2f, ImageDesc.Type.PNG)); |
||||
} |
||||
} |
||||
vars.add(new ImageDesc(file, cls, 1f, ImageDesc.Type.PNG, true)); |
||||
return vars; |
||||
} |
||||
} |
||||
|
||||
private interface ImageConverter { |
||||
Image convert(@Nullable Image source, ImageDesc desc); |
||||
} |
||||
|
||||
private static class ImageConverterChain extends ArrayList<ImageConverter> { |
||||
private ImageConverterChain() {} |
||||
|
||||
public static ImageConverterChain create() { |
||||
return new ImageConverterChain(); |
||||
} |
||||
|
||||
public ImageConverterChain withFilter(final ImageFilter filter) { |
||||
return with(new ImageConverter() { |
||||
@Override |
||||
public Image convert(Image source, ImageDesc desc) { |
||||
return ImageUtil.filter(source, filter); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public ImageConverterChain withRetina() { |
||||
return with(new ImageConverter() { |
||||
@Override |
||||
public Image convert(Image source, ImageDesc desc) { |
||||
if (source != null && UIUtil.isRetina() && desc.scale > 1) { |
||||
return RetinaImage.createFrom(source, (int)desc.scale, ourComponent); |
||||
} |
||||
return source; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public ImageConverterChain with(ImageConverter f) { |
||||
add(f); |
||||
return this; |
||||
} |
||||
|
||||
public Image convert(Image image, ImageDesc desc) { |
||||
for (ImageConverter f : this) { |
||||
image = f.convert(image, desc); |
||||
} |
||||
return image; |
||||
} |
||||
} |
||||
|
||||
public static final Component ourComponent = new Component() { |
||||
}; |
||||
|
||||
private static boolean waitForImage(Image image) { |
||||
if (image == null) return false; |
||||
if (image.getWidth(null) > 0) return true; |
||||
MediaTracker mediatracker = new MediaTracker(ourComponent); |
||||
mediatracker.addImage(image, 1); |
||||
try { |
||||
mediatracker.waitForID(1, 5000); |
||||
} |
||||
catch (InterruptedException ex) { |
||||
ex.printStackTrace(); |
||||
} |
||||
return !mediatracker.isErrorID(1); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromUrl(@NotNull URL url) { |
||||
return loadFromUrl(url, true); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromUrl(@NotNull URL url, boolean allowFloatScaling) { |
||||
return loadFromUrl(url, allowFloatScaling, null); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromUrl(@NotNull URL url, boolean allowFloatScaling, ImageFilter filter) { |
||||
final float scaleFactor = calcScaleFactor(allowFloatScaling); |
||||
|
||||
// We can't check all 3rd party plugins and convince the authors to add @2x icons.
|
||||
// (scaleFactor > 1.0) != isRetina() => we should scale images manually.
|
||||
// Note we never scale images on Retina displays because scaling is handled by the system.
|
||||
final boolean scaleImages = (scaleFactor > 1.0f) && !UIUtil.isRetina(); |
||||
|
||||
// For any scale factor > 1.0, always prefer retina images, because downscaling
|
||||
// retina images provides a better result than upscaling non-retina images.
|
||||
final boolean loadRetinaImages = UIUtil.isRetina() || scaleImages; |
||||
|
||||
return ImageDescList.create(url.toString(), null, UIUtil.isUnderDarcula(), loadRetinaImages, allowFloatScaling).load( |
||||
ImageConverterChain.create(). |
||||
withFilter(filter). |
||||
withRetina(). |
||||
with(new ImageConverter() { |
||||
public Image convert(Image source, ImageDesc desc) { |
||||
if (source != null && scaleImages /*&& desc.type != ImageDesc.Type.SVG*/) { |
||||
if (desc.path.contains("@2x")) |
||||
return scaleImage(source, scaleFactor / 2.0f); // divide by 2.0 as Retina images are 2x the resolution.
|
||||
else |
||||
return scaleImage(source, scaleFactor); |
||||
} |
||||
return source; |
||||
} |
||||
})); |
||||
} |
||||
|
||||
private static float calcScaleFactor(boolean allowFloatScaling) { |
||||
float scaleFactor = allowFloatScaling ? JBUI.scale(1f) : JBUI.scale(1f) > 1.5f ? 2f : 1f; |
||||
assert scaleFactor >= 1.0f : "By design, only scale factors >= 1.0 are supported"; |
||||
return scaleFactor; |
||||
} |
||||
|
||||
@NotNull |
||||
private static Image scaleImage(Image image, float scale) { |
||||
int w = image.getWidth(null); |
||||
int h = image.getHeight(null); |
||||
if (w <= 0 || h <= 0) { |
||||
return image; |
||||
} |
||||
int width = (int)(scale * w); |
||||
int height = (int)(scale * h); |
||||
// Using "QUALITY" instead of "ULTRA_QUALITY" results in images that are less blurry
|
||||
// because ultra quality performs a few more passes when scaling, which introduces blurriness
|
||||
// when the scaling factor is relatively small (i.e. <= 3.0f) -- which is the case here.
|
||||
return Scalr.resize(ImageUtil.toBufferedImage(image), Scalr.Method.QUALITY, width, height); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromUrl(URL url, boolean dark, boolean retina) { |
||||
return loadFromUrl(url, dark, retina, null); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromUrl(URL url, boolean dark, boolean retina, ImageFilter filter) { |
||||
return ImageDescList.create(url.toString(), null, dark, retina, true). |
||||
load(ImageConverterChain.create().withFilter(filter).withRetina()); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromResource(@NonNls @NotNull String s) { |
||||
Class callerClass = ReflectionUtil.getGrandCallerClass(); |
||||
if (callerClass == null) return null; |
||||
return loadFromResource(s, callerClass); |
||||
} |
||||
|
||||
@Nullable |
||||
public static Image loadFromResource(@NonNls @NotNull String path, @NotNull Class aClass) { |
||||
return ImageDescList.create(path, aClass, UIUtil.isUnderDarcula(), UIUtil.isRetina() || JBUI.scale(1.0f) >= 1.5f, true). |
||||
load(ImageConverterChain.create().withRetina()); |
||||
} |
||||
|
||||
public static Image loadFromStream(@NotNull final InputStream inputStream) { |
||||
return loadFromStream(inputStream, 1); |
||||
} |
||||
|
||||
public static Image loadFromStream(@NotNull final InputStream inputStream, final int scale) { |
||||
return loadFromStream(inputStream, scale, null); |
||||
} |
||||
|
||||
public static Image loadFromStream(@NotNull final InputStream inputStream, final int scale, ImageFilter filter) { |
||||
Image image = load(inputStream, scale); |
||||
ImageDesc desc = new ImageDesc("", null, scale, ImageDesc.Type.UNDEFINED); |
||||
return ImageConverterChain.create().withFilter(filter).withRetina().convert(image, desc); |
||||
} |
||||
|
||||
private static Image load(@NotNull final InputStream inputStream, final int scale) { |
||||
if (scale <= 0) throw new IllegalArgumentException("Scale must be 1 or greater"); |
||||
try { |
||||
BufferExposingByteArrayOutputStream outputStream = new BufferExposingByteArrayOutputStream(); |
||||
try { |
||||
byte[] buffer = new byte[1024]; |
||||
while (true) { |
||||
final int n = inputStream.read(buffer); |
||||
if (n < 0) break; |
||||
outputStream.write(buffer, 0, n); |
||||
} |
||||
} |
||||
finally { |
||||
inputStream.close(); |
||||
} |
||||
|
||||
Image image = Toolkit.getDefaultToolkit().createImage(outputStream.getInternalBuffer(), 0, outputStream.size()); |
||||
|
||||
waitForImage(image); |
||||
|
||||
return image; |
||||
} |
||||
catch (Exception ex) { |
||||
ex.printStackTrace(); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public static boolean isGoodSize(final Icon icon) { |
||||
return IconLoader.isGoodSize(icon); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated use {@link ImageDescList} |
||||
*/ |
||||
public static java.util.List<Pair<String, Integer>> getFileNames(@NotNull String file) { |
||||
return getFileNames(file, false, false); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated use {@link ImageDescList} |
||||
*/ |
||||
public static java.util.List<Pair<String, Integer>> getFileNames(@NotNull String file, boolean dark, boolean retina) { |
||||
new UnsupportedOperationException("unsupported method").printStackTrace(); |
||||
return new ArrayList<Pair<String, Integer>>(); |
||||
} |
||||
|
||||
@NotNull |
||||
public static String getNameWithoutExtension(@NotNull String name) { |
||||
int i = name.lastIndexOf('.'); |
||||
if (i != -1) { |
||||
name = name.substring(0, i); |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
@NotNull |
||||
public static String getExtension(@NotNull String fileName) { |
||||
int index = fileName.lastIndexOf('.'); |
||||
if (index < 0) return ""; |
||||
return fileName.substring(index + 1); |
||||
} |
||||
} |
@ -0,0 +1,71 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import com.bulenkov.iconloader.JBHiDPIScaledImage; |
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.FilteredImageSource; |
||||
import java.awt.image.ImageFilter; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class ImageUtil { |
||||
public static BufferedImage toBufferedImage(@NotNull Image image) { |
||||
if (image instanceof JBHiDPIScaledImage) { |
||||
Image img = ((JBHiDPIScaledImage)image).getDelegate(); |
||||
if (img != null) { |
||||
image = img; |
||||
} |
||||
} |
||||
if (image instanceof BufferedImage) { |
||||
return (BufferedImage)image; |
||||
} |
||||
|
||||
@SuppressWarnings("UndesirableClassUsage") |
||||
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); |
||||
Graphics2D g = bufferedImage.createGraphics(); |
||||
g.drawImage(image, 0, 0, null); |
||||
g.dispose(); |
||||
return bufferedImage; |
||||
} |
||||
|
||||
public static int getRealWidth(@NotNull Image image) { |
||||
if (image instanceof JBHiDPIScaledImage) { |
||||
Image img = ((JBHiDPIScaledImage)image).getDelegate(); |
||||
if (img != null) image = img; |
||||
} |
||||
return image.getWidth(null); |
||||
} |
||||
|
||||
public static int getRealHeight(@NotNull Image image) { |
||||
if (image instanceof JBHiDPIScaledImage) { |
||||
Image img = ((JBHiDPIScaledImage)image).getDelegate(); |
||||
if (img != null) image = img; |
||||
} |
||||
return image.getHeight(null); |
||||
} |
||||
|
||||
public static Image filter(Image image, ImageFilter filter) { |
||||
if (image == null || filter == null) return image; |
||||
return Toolkit.getDefaultToolkit().createImage( |
||||
new FilteredImageSource(toBufferedImage(image).getSource(), filter)); |
||||
} |
||||
} |
@ -0,0 +1,68 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.plaf.UIResource; |
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBDimension extends Dimension { |
||||
public final float originalScale = JBUI.scale(1f); |
||||
|
||||
public JBDimension(int width, int height) { |
||||
super(scale(width), scale(height)); |
||||
} |
||||
|
||||
private static int scale(int size) { |
||||
return size == -1 ? -1 : JBUI.scale(size); |
||||
} |
||||
|
||||
public static JBDimension create(Dimension from) { |
||||
if (from instanceof JBDimension) { |
||||
return ((JBDimension)from); |
||||
} |
||||
return new JBDimension(from.width, from.height); |
||||
} |
||||
|
||||
public JBDimensionUIResource asUIResource() { |
||||
return new JBDimensionUIResource(this); |
||||
} |
||||
|
||||
public static class JBDimensionUIResource extends JBDimension implements UIResource { |
||||
public JBDimensionUIResource(JBDimension size) { |
||||
super(0, 0); |
||||
width = size.width; |
||||
height = size.height; |
||||
} |
||||
} |
||||
|
||||
public JBDimension withWidth(int width) { |
||||
JBDimension size = new JBDimension(0, 0); |
||||
size.width = scale(width); |
||||
size.height = height; |
||||
return size; |
||||
} |
||||
|
||||
public JBDimension withHeight(int height) { |
||||
JBDimension size = new JBDimension(0, 0); |
||||
size.width = width; |
||||
size.height = scale(height); |
||||
return size; |
||||
} |
||||
} |
@ -0,0 +1,51 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.border.EmptyBorder; |
||||
import javax.swing.plaf.UIResource; |
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBEmptyBorder extends EmptyBorder { |
||||
public JBEmptyBorder(int top, int left, int bottom, int right) { |
||||
super(JBUI.insets(top, left, bottom, right)); |
||||
} |
||||
|
||||
public JBEmptyBorder(Insets insets) { |
||||
super(JBUI.insets(insets)); |
||||
} |
||||
|
||||
public JBEmptyBorder(int offset) { |
||||
this(offset, offset, offset, offset); |
||||
} |
||||
|
||||
public JBEmptyBorderUIResource asUIResource() { |
||||
return new JBEmptyBorderUIResource(this); |
||||
} |
||||
|
||||
public static class JBEmptyBorderUIResource extends JBEmptyBorder implements UIResource { |
||||
public JBEmptyBorderUIResource(JBEmptyBorder border) { |
||||
super(0,0,0,0); |
||||
top = border.top; |
||||
left = border.left; |
||||
bottom = border.bottom; |
||||
right = border.right; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,84 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.plaf.UIResource; |
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBFont extends Font { |
||||
private JBFont(Font font) { |
||||
super(font); |
||||
} |
||||
|
||||
public static JBFont create(Font font) { |
||||
return create(font, true); |
||||
} |
||||
|
||||
public static JBFont create(Font font, boolean tryToScale) { |
||||
if (font instanceof JBFont) { |
||||
return ((JBFont)font); |
||||
} |
||||
Font scaled = font; |
||||
if (tryToScale) { |
||||
scaled = font.deriveFont(font.getSize() * JBUI.scale(1f)); |
||||
} |
||||
|
||||
if (font instanceof UIResource) { |
||||
return new JBFontUIResource(scaled); |
||||
} |
||||
|
||||
return new JBFont(scaled); |
||||
} |
||||
|
||||
public JBFont asBold() { |
||||
return deriveFont(BOLD, getSize()); |
||||
} |
||||
|
||||
public JBFont asItalic() { |
||||
return deriveFont(ITALIC, getSize()); |
||||
} |
||||
|
||||
public JBFont asPlain() { |
||||
return deriveFont(PLAIN, getSize()); |
||||
} |
||||
|
||||
@Override |
||||
public JBFont deriveFont(int style, float size) { |
||||
return create(super.deriveFont(style, size), false); |
||||
} |
||||
|
||||
@Override |
||||
public JBFont deriveFont(float size) { |
||||
return create(super.deriveFont(size), false); |
||||
} |
||||
|
||||
public JBFont biggerOn(float size) { |
||||
return deriveFont(getSize() + JBUI.scale(size)); |
||||
} |
||||
|
||||
public JBFont lessOn(float size) { |
||||
return deriveFont(getSize() - JBUI.scale(size)); |
||||
} |
||||
|
||||
private static class JBFontUIResource extends JBFont implements UIResource { |
||||
private JBFontUIResource(Font font) { |
||||
super(font); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.image.ImageObserver; |
||||
|
||||
/** |
||||
* HiDPI-aware image icon |
||||
* |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBImageIcon extends ImageIcon { |
||||
public JBImageIcon(@NotNull Image image) { |
||||
super(image); |
||||
} |
||||
|
||||
@Override |
||||
public synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) { |
||||
final ImageObserver observer = getImageObserver(); |
||||
|
||||
UIUtil.drawImage(g, getImage(), x, y, observer == null ? c : observer); |
||||
} |
||||
} |
@ -0,0 +1,121 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.plaf.UIResource; |
||||
import java.awt.*; |
||||
|
||||
import static com.bulenkov.iconloader.util.JBUI.scale; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBInsets extends Insets { |
||||
/** |
||||
* Creates and initializes a new <code>Insets</code> object with the |
||||
* specified top, left, bottom, and right insets. |
||||
* |
||||
* @param top the inset from the top. |
||||
* @param left the inset from the left. |
||||
* @param bottom the inset from the bottom. |
||||
* @param right the inset from the right. |
||||
*/ |
||||
public JBInsets(int top, int left, int bottom, int right) { |
||||
super(scale(top), scale(left), scale(bottom), scale(right)); |
||||
} |
||||
|
||||
public int width() { |
||||
return left + right; |
||||
} |
||||
|
||||
public int height() { |
||||
return top + bottom; |
||||
} |
||||
|
||||
public static JBInsets create(Insets insets) { |
||||
if (insets instanceof JBInsets) { |
||||
JBInsets copy = new JBInsets(0, 0, 0, 0); |
||||
copy.top = insets.top; |
||||
copy.left = insets.left; |
||||
copy.bottom = insets.bottom; |
||||
copy.right = insets.right; |
||||
return copy; |
||||
} |
||||
return new JBInsets(insets.top, insets.left, insets.bottom, insets.right); |
||||
} |
||||
|
||||
public JBInsetsUIResource asUIResource() { |
||||
return new JBInsetsUIResource(this); |
||||
} |
||||
|
||||
public static class JBInsetsUIResource extends JBInsets implements UIResource { |
||||
public JBInsetsUIResource(JBInsets insets) { |
||||
super(0, 0, 0, 0); |
||||
top = insets.top; |
||||
left = insets.left; |
||||
bottom = insets.bottom; |
||||
right = insets.right; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param dimension the size to increase |
||||
* @param insets the insets to add |
||||
*/ |
||||
public static void addTo(Dimension dimension, Insets insets) { |
||||
if (insets != null) { |
||||
dimension.width += insets.left + insets.right; |
||||
dimension.height += insets.top + insets.bottom; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param dimension the size to decrease |
||||
* @param insets the insets to remove |
||||
*/ |
||||
public static void removeFrom(Dimension dimension, Insets insets) { |
||||
if (insets != null) { |
||||
dimension.width -= insets.left + insets.right; |
||||
dimension.height -= insets.top + insets.bottom; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param rectangle the size to increase and the location to move |
||||
* @param insets the insets to add |
||||
*/ |
||||
public static void addTo(Rectangle rectangle, Insets insets) { |
||||
if (insets != null) { |
||||
rectangle.x -= insets.left; |
||||
rectangle.y -= insets.top; |
||||
rectangle.width += insets.left + insets.right; |
||||
rectangle.height += insets.top + insets.bottom; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param rectangle the size to decrease and the location to move |
||||
* @param insets the insets to remove |
||||
*/ |
||||
public static void removeFrom(Rectangle rectangle, Insets insets) { |
||||
if (insets != null) { |
||||
rectangle.x += insets.left; |
||||
rectangle.y += insets.top; |
||||
rectangle.width -= insets.left + insets.right; |
||||
rectangle.height -= insets.top + insets.bottom; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,221 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import com.bulenkov.iconloader.IconLoader; |
||||
|
||||
import javax.swing.*; |
||||
import javax.swing.border.Border; |
||||
import javax.swing.plaf.UIResource; |
||||
import java.awt.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class JBUI { |
||||
private static float scaleFactor = 1.0f; |
||||
|
||||
static { |
||||
calculateScaleFactor(); |
||||
} |
||||
|
||||
private static void calculateScaleFactor() { |
||||
if (SystemInfo.isMac) { |
||||
scaleFactor = 1.0f; |
||||
return; |
||||
} |
||||
|
||||
if (System.getProperty("hidpi") != null && !"true".equalsIgnoreCase(System.getProperty("hidpi"))) { |
||||
scaleFactor = 1.0f; |
||||
return; |
||||
} |
||||
|
||||
UIUtil.initSystemFontData(); |
||||
Pair<String, Integer> fdata = UIUtil.getSystemFontData(); |
||||
|
||||
int size; |
||||
if (fdata != null) { |
||||
size = fdata.getSecond(); |
||||
} else { |
||||
size = Fonts.label().getSize(); |
||||
} |
||||
setScaleFactor(size / UIUtil.DEF_SYSTEM_FONT_SIZE); |
||||
} |
||||
|
||||
public static void setScaleFactor(float scale) { |
||||
final String value = System.getProperty("hidpi"); |
||||
if (value != null && "false".equalsIgnoreCase(value)) { |
||||
return; |
||||
} |
||||
|
||||
if (scale < 1.25f) scale = 1.0f; |
||||
else if (scale < 1.5f) scale = 1.25f; |
||||
else if (scale < 1.75f) scale = 1.5f; |
||||
else if (scale < 2f) scale = 1.75f; |
||||
else scale = 2.0f; |
||||
|
||||
if (SystemInfo.isLinux && scale == 1.25f) { |
||||
//Default UI font size for Unity and Gnome is 15. Scaling factor 1.25f works badly on Linux
|
||||
scale = 1f; |
||||
} |
||||
if (scaleFactor == scale) { |
||||
return; |
||||
} |
||||
|
||||
scaleFactor = scale; |
||||
IconLoader.setScale(scale); |
||||
} |
||||
|
||||
public static int scale(int i) { |
||||
return Math.round(scaleFactor * i); |
||||
} |
||||
|
||||
public static int scaleFontSize(int fontSize) { |
||||
if (scaleFactor == 1.25f) return (int)(fontSize * 1.34f); |
||||
if (scaleFactor == 1.75f) return (int)(fontSize * 1.67f); |
||||
return scale(fontSize); |
||||
} |
||||
|
||||
public static JBDimension size(int width, int height) { |
||||
return new JBDimension(width, height); |
||||
} |
||||
|
||||
public static JBDimension size(int widthAndHeight) { |
||||
return new JBDimension(widthAndHeight, widthAndHeight); |
||||
} |
||||
|
||||
public static JBDimension size(Dimension size) { |
||||
if (size instanceof JBDimension) { |
||||
final JBDimension jbSize = (JBDimension)size; |
||||
if (jbSize.originalScale == scale(1f)) { |
||||
return jbSize; |
||||
} |
||||
final JBDimension newSize = new JBDimension((int)(jbSize.width / jbSize.originalScale), (int)(jbSize.height / jbSize.originalScale)); |
||||
return size instanceof UIResource ? newSize.asUIResource() : newSize; |
||||
} |
||||
return new JBDimension(size.width, size.height); |
||||
} |
||||
|
||||
public static JBInsets insets(int top, int left, int bottom, int right) { |
||||
return new JBInsets(top, left, bottom, right); |
||||
} |
||||
|
||||
public static JBInsets insets(int all) { |
||||
return insets(all, all, all, all); |
||||
} |
||||
|
||||
public static JBInsets insets(int topBottom, int leftRight) { |
||||
return insets(topBottom, leftRight, topBottom, leftRight); |
||||
} |
||||
|
||||
public static JBInsets emptyInsets() { |
||||
return new JBInsets(0, 0, 0, 0); |
||||
} |
||||
|
||||
public static JBInsets insetsTop(int t) { |
||||
return insets(t, 0, 0, 0); |
||||
} |
||||
|
||||
public static JBInsets insetsLeft(int l) { |
||||
return insets(0, l, 0, 0); |
||||
} |
||||
|
||||
public static JBInsets insetsBottom(int b) { |
||||
return insets(0, 0, b, 0); |
||||
} |
||||
|
||||
public static JBInsets insetsRight(int r) { |
||||
return insets(0, 0, 0, r); |
||||
} |
||||
|
||||
public static EmptyIcon emptyIcon(int i) { |
||||
return (EmptyIcon)EmptyIcon.create(scale(i)); |
||||
} |
||||
|
||||
public static JBDimension emptySize() { |
||||
return new JBDimension(0, 0); |
||||
} |
||||
|
||||
public static float scale(float f) { |
||||
return f * scaleFactor; |
||||
} |
||||
|
||||
public static JBInsets insets(Insets insets) { |
||||
return JBInsets.create(insets); |
||||
} |
||||
|
||||
public static boolean isHiDPI() { |
||||
return scaleFactor > 1.0f; |
||||
} |
||||
|
||||
public static class Fonts { |
||||
public static JBFont label() { |
||||
return JBFont.create(UIManager.getFont("Label.font"), false); |
||||
} |
||||
|
||||
public static JBFont label(float size) { |
||||
return label().deriveFont(scale(size)); |
||||
} |
||||
|
||||
public static JBFont smallFont() { |
||||
return label().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL)); |
||||
} |
||||
|
||||
public static JBFont miniFont() { |
||||
return label().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.MINI)); |
||||
} |
||||
|
||||
public static JBFont create(String fontFamily, int size) { |
||||
return JBFont.create(new Font(fontFamily, Font.PLAIN, size)); |
||||
} |
||||
} |
||||
|
||||
public static class Borders { |
||||
public static JBEmptyBorder empty(int top, int left, int bottom, int right) { |
||||
return new JBEmptyBorder(top, left, bottom, right); |
||||
} |
||||
|
||||
public static JBEmptyBorder empty(int topAndBottom, int leftAndRight) { |
||||
return empty(topAndBottom, leftAndRight, topAndBottom, leftAndRight); |
||||
} |
||||
|
||||
public static JBEmptyBorder emptyTop(int offset) { |
||||
return empty(offset, 0, 0, 0); |
||||
} |
||||
|
||||
public static JBEmptyBorder emptyLeft(int offset) { |
||||
return empty(0, offset, 0, 0); |
||||
} |
||||
|
||||
public static JBEmptyBorder emptyBottom(int offset) { |
||||
return empty(0, 0, offset, 0); |
||||
} |
||||
|
||||
public static JBEmptyBorder emptyRight(int offset) { |
||||
return empty(0, 0, 0, offset); |
||||
} |
||||
|
||||
public static JBEmptyBorder empty() { |
||||
return empty(0, 0, 0, 0); |
||||
} |
||||
|
||||
public static Border empty(int offsets) { |
||||
return empty(offsets, offsets, offsets, offsets); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class Pair<FIRST, SECOND> { |
||||
public final FIRST first; |
||||
public final SECOND second; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private static final Pair EMPTY = create(null, null); |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public static <F, S> Pair<F, S> empty() { |
||||
return EMPTY; |
||||
} |
||||
|
||||
public Pair(FIRST first, SECOND second) { |
||||
this.first = first; |
||||
this.second = second; |
||||
} |
||||
|
||||
public final FIRST getFirst() { |
||||
return first; |
||||
} |
||||
|
||||
public final SECOND getSecond() { |
||||
return second; |
||||
} |
||||
|
||||
public final boolean equals(Object o) { |
||||
return o instanceof Pair |
||||
&& ComparingUtils.equal(first, ((Pair) o).first) |
||||
&& ComparingUtils.equal(second, ((Pair) o).second); |
||||
} |
||||
|
||||
public int hashCode() { |
||||
int result = first != null ? first.hashCode() : 0; |
||||
result = 31 * result + (second != null ? second.hashCode() : 0); |
||||
return result; |
||||
} |
||||
|
||||
public String toString() { |
||||
return "<" + first + ", " + second + ">"; |
||||
} |
||||
|
||||
public static <F, S> Pair<F, S> create(F first, S second) { |
||||
return new Pair<F, S>(first, second); |
||||
} |
||||
|
||||
public static <T> T getFirst(Pair<T, ?> pair) { |
||||
return pair != null ? pair.first : null; |
||||
} |
||||
|
||||
public static <T> T getSecond(Pair<?, T> pair) { |
||||
return pair != null ? pair.second : null; |
||||
} |
||||
} |
@ -0,0 +1,64 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class Ref<T> { |
||||
private T myValue; |
||||
|
||||
public Ref() { |
||||
} |
||||
|
||||
public Ref(T value) { |
||||
myValue = value; |
||||
} |
||||
|
||||
public boolean isNull() { |
||||
return myValue == null; |
||||
} |
||||
|
||||
public T get() { |
||||
return myValue; |
||||
} |
||||
|
||||
public void set(T value) { |
||||
myValue = value; |
||||
} |
||||
|
||||
public boolean setIfNull(T value) { |
||||
if (myValue == null) { |
||||
myValue = value; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public static <V> Ref<V> create() { |
||||
return new Ref<V>(); |
||||
} |
||||
|
||||
public static <V> Ref<V> create(V value) { |
||||
return new Ref<V>(value); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return String.valueOf(myValue); |
||||
} |
||||
} |
@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
public class ReflectionUtil { |
||||
@Nullable |
||||
public static Class getGrandCallerClass() { |
||||
int stackFrameCount = 3; |
||||
Class callerClass = findCallerClass(stackFrameCount); |
||||
while (callerClass != null && callerClass.getClassLoader() == null) { // looks like a system class
|
||||
callerClass = findCallerClass(++stackFrameCount); |
||||
} |
||||
if (callerClass == null) { |
||||
callerClass = findCallerClass(2); |
||||
} |
||||
return callerClass; |
||||
} |
||||
|
||||
/** |
||||
* Returns the class this method was called 'framesToSkip' frames up the caller hierarchy. |
||||
* |
||||
* NOTE: |
||||
* <b>Extremely expensive! |
||||
* Please consider not using it. |
||||
* These aren't the droids you're looking for!</b> |
||||
*/ |
||||
@Nullable |
||||
public static Class findCallerClass(int framesToSkip) { |
||||
try { |
||||
Class[] stack = MySecurityManager.INSTANCE.getStack(); |
||||
int indexFromTop = 1 + framesToSkip; |
||||
return stack.length > indexFromTop ? stack[indexFromTop] : null; |
||||
} |
||||
catch (Exception e) { |
||||
// LOG.warn(e);
|
||||
return null; |
||||
} |
||||
} |
||||
|
||||
private static class MySecurityManager extends SecurityManager { |
||||
private static final MySecurityManager INSTANCE = new MySecurityManager(); |
||||
public Class[] getStack() { |
||||
return getClassContext(); |
||||
} |
||||
|
||||
} |
||||
|
||||
private ReflectionUtil() { } |
||||
} |
@ -0,0 +1,35 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class Registry { |
||||
public static boolean is(String key) { |
||||
final String value = System.getProperty(key); |
||||
return "true".equalsIgnoreCase(value); |
||||
} |
||||
|
||||
public static Float getFloat(String key) { |
||||
try { |
||||
return Float.parseFloat(System.getProperty(key)); |
||||
} catch (Exception e) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import javax.swing.*; |
||||
|
||||
/** |
||||
* This class is mostly for testing purposes: in case an icon is hidden behind a private or a restricted interface, |
||||
* marking it as RetrievableIcon will help get the actual icon and perform checks. |
||||
*/ |
||||
public interface RetrievableIcon extends Icon { |
||||
@Nullable |
||||
Icon retrieveIcon(); |
||||
} |
@ -0,0 +1,30 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import javax.swing.*; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public interface ScalableIcon extends Icon { |
||||
/** |
||||
* @param scaleFactor scale |
||||
* @return scaled icon with width getIconWidth() * scaleFactor and height getIconHeight() * scaleFactor |
||||
*/ |
||||
Icon scale(float scaleFactor); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,58 @@
|
||||
/* |
||||
* Copyright 2000-2016 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import java.lang.ref.Reference; |
||||
import java.lang.ref.ReferenceQueue; |
||||
|
||||
/** |
||||
* The class is necessary to debug memory allocations via soft references. All IDEA classes should use this SoftReference |
||||
* instead of original from java.lang.ref. Whenever we suspect soft memory allocation overhead this easily becomes a hard |
||||
* reference so we can see allocations and memory consumption in memory profiler. |
||||
* |
||||
* @author max |
||||
*/ |
||||
@SuppressWarnings("ClassNameSameAsAncestorName") |
||||
public class SoftReference<T> extends java.lang.ref.SoftReference<T> implements Getter<T> { |
||||
//private final T myReferent;
|
||||
|
||||
public SoftReference(final T referent) { |
||||
super(referent); |
||||
//myReferent = referent;
|
||||
} |
||||
|
||||
public SoftReference(final T referent, final ReferenceQueue<? super T> q) { |
||||
super(referent, q); |
||||
//myReferent = referent;
|
||||
} |
||||
|
||||
//@Override
|
||||
//public T get() {
|
||||
// return myReferent;
|
||||
//}
|
||||
|
||||
@Nullable |
||||
public static <T> T dereference(@Nullable Reference<T> ref) { |
||||
return ref == null ? null : ref.get(); |
||||
} |
||||
@Nullable |
||||
public static <T> T deref(@Nullable Getter<T> ref) { |
||||
return ref == null ? null : ref.get(); |
||||
} |
||||
} |
@ -0,0 +1,63 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
//import sun.reflect.ConstructorAccessor;
|
||||
|
||||
import java.lang.reflect.Constructor; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class StringFactory { |
||||
// String(char[], boolean). Works since JDK1.7, earlier JDKs have too slow reflection anyway
|
||||
// private static final ConstructorAccessor ourConstructorAccessor;
|
||||
|
||||
// static {
|
||||
// ConstructorAccessor constructorAccessor = null;
|
||||
// try {
|
||||
// Constructor<String> newC = String.class.getDeclaredConstructor(char[].class, boolean.class);
|
||||
// newC.setAccessible(true);
|
||||
// it is faster to invoke constructor via sun.reflect.ConstructorAccessor; it avoids AccessibleObject.checkAccess()
|
||||
// Method accessor = Constructor.class.getDeclaredMethod("acquireConstructorAccessor");
|
||||
// accessor.setAccessible(true);
|
||||
// constructorAccessor = (ConstructorAccessor) accessor.invoke(newC);
|
||||
// } catch (Exception ignored) {
|
||||
// }
|
||||
// ourConstructorAccessor = constructorAccessor;
|
||||
// }
|
||||
|
||||
|
||||
/** |
||||
* @return new instance of String which backed by 'chars' array. |
||||
* <p/> |
||||
* CAUTION. EXTREMELY DANGEROUS. |
||||
* DO NOT USE THIS METHOD UNLESS YOU ARE TOO DESPERATE |
||||
*/ |
||||
public static String createShared(char[] chars) { |
||||
// if (ourConstructorAccessor != null) {
|
||||
// try {
|
||||
// return (String) ourConstructorAccessor.newInstance(new Object[]{chars, Boolean.TRUE});
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// }
|
||||
return new String(chars); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,304 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import org.jetbrains.annotations.Contract; |
||||
import org.jetbrains.annotations.NonNls; |
||||
import org.jetbrains.annotations.NotNull; |
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class StringUtil { |
||||
public static List<String> split(String s, String separator) { |
||||
return split(s, separator, true); |
||||
} |
||||
|
||||
public static List<String> split(String s, String separator, |
||||
boolean excludeSeparator) { |
||||
return split(s, separator, excludeSeparator, true); |
||||
} |
||||
|
||||
public static List<String> split(String s, String separator, |
||||
boolean excludeSeparator, boolean excludeEmptyStrings) { |
||||
if (separator.isEmpty()) { |
||||
return Collections.singletonList(s); |
||||
} |
||||
List<String> result = new ArrayList<String>(); |
||||
int pos = 0; |
||||
while (true) { |
||||
int index = s.indexOf(separator, pos); |
||||
if (index == -1) break; |
||||
final int nextPos = index + separator.length(); |
||||
String token = s.substring(pos, excludeSeparator ? index : nextPos); |
||||
if (!token.isEmpty() || !excludeEmptyStrings) { |
||||
result.add(token); |
||||
} |
||||
pos = nextPos; |
||||
} |
||||
if (pos < s.length() || (!excludeEmptyStrings && pos == s.length())) { |
||||
result.add(s.substring(pos, s.length())); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public static int indexOfIgnoreCase(String where, String what, int fromIndex) { |
||||
int targetCount = what.length(); |
||||
int sourceCount = where.length(); |
||||
|
||||
if (fromIndex >= sourceCount) { |
||||
return targetCount == 0 ? sourceCount : -1; |
||||
} |
||||
|
||||
if (fromIndex < 0) { |
||||
fromIndex = 0; |
||||
} |
||||
|
||||
if (targetCount == 0) { |
||||
return fromIndex; |
||||
} |
||||
|
||||
char first = what.charAt(0); |
||||
int max = sourceCount - targetCount; |
||||
|
||||
for (int i = fromIndex; i <= max; i++) { |
||||
/* Look for first character. */ |
||||
if (!charsEqualIgnoreCase(where.charAt(i), first)) { |
||||
while (++i <= max && !charsEqualIgnoreCase(where.charAt(i), first)) ; |
||||
} |
||||
|
||||
/* Found first character, now look at the rest of v2 */ |
||||
if (i <= max) { |
||||
int j = i + 1; |
||||
int end = j + targetCount - 1; |
||||
for (int k = 1; j < end && charsEqualIgnoreCase(where.charAt(j), what.charAt(k)); j++, k++) ; |
||||
|
||||
if (j == end) { |
||||
/* Found whole string. */ |
||||
return i; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
public static int indexOfIgnoreCase(String where, char what, int fromIndex) { |
||||
int sourceCount = where.length(); |
||||
|
||||
if (fromIndex >= sourceCount) { |
||||
return -1; |
||||
} |
||||
|
||||
if (fromIndex < 0) { |
||||
fromIndex = 0; |
||||
} |
||||
|
||||
for (int i = fromIndex; i < sourceCount; i++) { |
||||
if (charsEqualIgnoreCase(where.charAt(i), what)) { |
||||
return i; |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
public static boolean containsIgnoreCase(String where, String what) { |
||||
return indexOfIgnoreCase(where, what, 0) >= 0; |
||||
} |
||||
|
||||
public static boolean charsEqualIgnoreCase(char a, char b) { |
||||
return a == b || toUpperCase(a) == toUpperCase(b) || toLowerCase(a) == toLowerCase(b); |
||||
} |
||||
|
||||
public static char toUpperCase(char a) { |
||||
if (a < 'a') { |
||||
return a; |
||||
} |
||||
if (a <= 'z') { |
||||
return (char) (a + ('A' - 'a')); |
||||
} |
||||
return Character.toUpperCase(a); |
||||
} |
||||
|
||||
public static char toLowerCase(char a) { |
||||
if (a < 'A' || a >= 'a' && a <= 'z') { |
||||
return a; |
||||
} |
||||
|
||||
if (a <= 'Z') { |
||||
return (char) (a + ('a' - 'A')); |
||||
} |
||||
|
||||
return Character.toLowerCase(a); |
||||
} |
||||
|
||||
public static int compareVersionNumbers(String v1, String v2) { |
||||
if (v1 == null && v2 == null) { |
||||
return 0; |
||||
} |
||||
if (v1 == null) { |
||||
return -1; |
||||
} |
||||
if (v2 == null) { |
||||
return 1; |
||||
} |
||||
|
||||
String[] part1 = v1.split("[\\.\\_\\-]"); |
||||
String[] part2 = v2.split("[\\.\\_\\-]"); |
||||
|
||||
int idx = 0; |
||||
for (; idx < part1.length && idx < part2.length; idx++) { |
||||
String p1 = part1[idx]; |
||||
String p2 = part2[idx]; |
||||
|
||||
int cmp; |
||||
if (p1.matches("\\d+") && p2.matches("\\d+")) { |
||||
cmp = new Integer(p1).compareTo(new Integer(p2)); |
||||
} else { |
||||
cmp = part1[idx].compareTo(part2[idx]); |
||||
} |
||||
if (cmp != 0) return cmp; |
||||
} |
||||
|
||||
if (part1.length == part2.length) { |
||||
return 0; |
||||
} else { |
||||
boolean left = part1.length > idx; |
||||
String[] parts = left ? part1 : part2; |
||||
|
||||
for (; idx < parts.length; idx++) { |
||||
String p = parts[idx]; |
||||
int cmp; |
||||
if (p.matches("\\d+")) { |
||||
cmp = new Integer(p).compareTo(0); |
||||
} else { |
||||
cmp = 1; |
||||
} |
||||
if (cmp != 0) return left ? cmp : -cmp; |
||||
} |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public static boolean startsWithChar(CharSequence s, char prefix) { |
||||
return s != null && s.length() != 0 && s.charAt(0) == prefix; |
||||
} |
||||
|
||||
public static boolean endsWithChar(CharSequence s, char suffix) { |
||||
return s != null && s.length() != 0 && s.charAt(s.length() - 1) == suffix; |
||||
} |
||||
|
||||
|
||||
public static String stripQuotesAroundValue(String text) { |
||||
if (startsWithChar(text, '\"') || startsWithChar(text, '\'')) text = text.substring(1); |
||||
if (endsWithChar(text, '\"') || endsWithChar(text, '\'')) text = text.substring(0, text.length() - 1); |
||||
return text; |
||||
} |
||||
|
||||
/** |
||||
* Equivalent to string.startsWith(prefixes[0] + prefixes[1] + ...) but avoids creating an object for concatenation. |
||||
*/ |
||||
public static boolean startsWithConcatenation(String string, String... prefixes) { |
||||
int offset = 0; |
||||
for (String prefix : prefixes) { |
||||
int prefixLen = prefix.length(); |
||||
if (!string.regionMatches(offset, prefix, 0, prefixLen)) { |
||||
return false; |
||||
} |
||||
offset += prefixLen; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static String getFileExtension(String fileName) { |
||||
int index = fileName.lastIndexOf('.'); |
||||
if (index < 0) return ""; |
||||
return fileName.substring(index + 1); |
||||
} |
||||
|
||||
public static String getFileNameWithoutExtension(String name) { |
||||
int i = name.lastIndexOf('.'); |
||||
if (i != -1) { |
||||
name = name.substring(0, i); |
||||
} |
||||
return name; |
||||
|
||||
} |
||||
|
||||
@NotNull |
||||
@Contract(pure = true) |
||||
public static String join(@NotNull Collection<String> strings, @NotNull String separator) { |
||||
if (strings.size() <= 1) { |
||||
return notNullize(getFirstItem(strings)); |
||||
} |
||||
StringBuilder result = new StringBuilder(); |
||||
join(strings, separator, result); |
||||
return result.toString(); |
||||
} |
||||
|
||||
@Contract(pure = true) |
||||
public static String join(@NotNull Iterable<?> items, @NotNull @NonNls String separator) { |
||||
StringBuilder result = new StringBuilder(); |
||||
for (Object item : items) { |
||||
result.append(item).append(separator); |
||||
} |
||||
if (result.length() > 0) { |
||||
result.setLength(result.length() - separator.length()); |
||||
} |
||||
return result.toString(); |
||||
} |
||||
|
||||
|
||||
@NotNull |
||||
public static String notNullize(@Nullable final String s) { |
||||
return notNullize(s, ""); |
||||
} |
||||
|
||||
@NotNull |
||||
public static String notNullize(@Nullable final String s, @NotNull String defaultValue) { |
||||
return s == null ? defaultValue : s; |
||||
} |
||||
|
||||
public static void join(@NotNull Collection<String> strings, @NotNull String separator, @NotNull StringBuilder result) { |
||||
boolean isFirst = true; |
||||
for (String string : strings) { |
||||
if (string != null) { |
||||
if (isFirst) { |
||||
isFirst = false; |
||||
} |
||||
else { |
||||
result.append(separator); |
||||
} |
||||
result.append(string); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Nullable |
||||
public static <T> T getFirstItem(@Nullable Collection<T> items) { |
||||
return items == null || items.isEmpty() ? null : items.iterator().next(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,137 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
@SuppressWarnings({"HardCodedStringLiteral", "UtilityClassWithoutPrivateConstructor", "UnusedDeclaration"}) |
||||
public class SystemInfo { |
||||
public static final String OS_NAME = System.getProperty("os.name"); |
||||
public static final String OS_VERSION = System.getProperty("os.version").toLowerCase(); |
||||
public static final String JAVA_VERSION = System.getProperty("java.version"); |
||||
public static final String JAVA_RUNTIME_VERSION = System.getProperty("java.runtime.version"); |
||||
|
||||
protected static final String _OS_NAME = OS_NAME.toLowerCase(); |
||||
public static final boolean isWindows = _OS_NAME.startsWith("windows"); |
||||
public static final boolean isOS2 = _OS_NAME.startsWith("os/2") || _OS_NAME.startsWith("os2"); |
||||
public static final boolean isMac = _OS_NAME.startsWith("mac"); |
||||
public static final boolean isLinux = _OS_NAME.startsWith("linux"); |
||||
public static final boolean isUnix = !isWindows && !isOS2; |
||||
|
||||
public static final boolean isFileSystemCaseSensitive = isUnix && !isMac; |
||||
public static final boolean isMacOSLion = isLion(); |
||||
|
||||
public static final boolean isAppleJvm = isAppleJvm(); |
||||
public static final boolean isOracleJvm = isOracleJvm(); |
||||
public static final boolean isSunJvm = isSunJvm(); |
||||
public static final boolean isJetbrainsJvm = isJetbrainsJvm(); |
||||
|
||||
public static boolean isOsVersionAtLeast(String version) { |
||||
return compareVersionNumbers(OS_VERSION, version) >= 0; |
||||
} |
||||
|
||||
|
||||
private static boolean isTiger() { |
||||
return isMac && |
||||
!OS_VERSION.startsWith("10.0") && |
||||
!OS_VERSION.startsWith("10.1") && |
||||
!OS_VERSION.startsWith("10.2") && |
||||
!OS_VERSION.startsWith("10.3"); |
||||
} |
||||
|
||||
private static boolean isLeopard() { |
||||
return isMac && isTiger() && !OS_VERSION.startsWith("10.4"); |
||||
} |
||||
|
||||
private static boolean isSnowLeopard() { |
||||
return isMac && isLeopard() && !OS_VERSION.startsWith("10.5"); |
||||
} |
||||
|
||||
private static boolean isLion() { |
||||
return isMac && isSnowLeopard() && !OS_VERSION.startsWith("10.6"); |
||||
} |
||||
|
||||
private static boolean isMountainLion() { |
||||
return isMac && isLion() && !OS_VERSION.startsWith("10.7"); |
||||
} |
||||
|
||||
public static int compareVersionNumbers(String v1, String v2) { |
||||
if (v1 == null && v2 == null) { |
||||
return 0; |
||||
} |
||||
if (v1 == null) { |
||||
return -1; |
||||
} |
||||
if (v2 == null) { |
||||
return 1; |
||||
} |
||||
|
||||
String[] part1 = v1.split("[\\.\\_\\-]"); |
||||
String[] part2 = v2.split("[\\.\\_\\-]"); |
||||
|
||||
int idx = 0; |
||||
for (; idx < part1.length && idx < part2.length; idx++) { |
||||
String p1 = part1[idx]; |
||||
String p2 = part2[idx]; |
||||
|
||||
int cmp; |
||||
if (p1.matches("\\d+") && p2.matches("\\d+")) { |
||||
cmp = new Integer(p1).compareTo(new Integer(p2)); |
||||
} else { |
||||
cmp = part1[idx].compareTo(part2[idx]); |
||||
} |
||||
if (cmp != 0) return cmp; |
||||
} |
||||
|
||||
if (part1.length == part2.length) { |
||||
return 0; |
||||
} else if (part1.length > idx) { |
||||
return 1; |
||||
} else { |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
public static boolean isJavaVersionAtLeast(String v) { |
||||
return StringUtil.compareVersionNumbers(JAVA_RUNTIME_VERSION, v) >= 0; |
||||
} |
||||
|
||||
private static boolean isOracleJvm() { |
||||
final String vendor = getJavaVmVendor(); |
||||
return vendor != null && StringUtil.containsIgnoreCase(vendor, "Oracle"); |
||||
} |
||||
|
||||
private static boolean isSunJvm() { |
||||
final String vendor = getJavaVmVendor(); |
||||
return vendor != null && StringUtil.containsIgnoreCase(vendor, "Sun") && StringUtil.containsIgnoreCase(vendor, "Microsystems"); |
||||
} |
||||
|
||||
private static boolean isAppleJvm() { |
||||
final String vendor = getJavaVmVendor(); |
||||
return vendor != null && StringUtil.containsIgnoreCase(vendor, "Apple"); |
||||
} |
||||
|
||||
public static String getJavaVmVendor() { |
||||
return System.getProperty("java.vm.vendor"); |
||||
} |
||||
|
||||
private static boolean isJetbrainsJvm() { |
||||
final String vendor = System.getProperty("java.vendor"); |
||||
return vendor != null && StringUtil.containsIgnoreCase(vendor, "jetbrains"); |
||||
} |
||||
} |
@ -0,0 +1,272 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import com.bulenkov.iconloader.IsRetina; |
||||
import com.bulenkov.iconloader.JBHiDPIScaledImage; |
||||
import com.bulenkov.iconloader.RetinaImage; |
||||
import org.jetbrains.annotations.Nullable; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.ImageObserver; |
||||
import java.lang.reflect.Field; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class UIUtil { |
||||
public static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0); |
||||
private static volatile Pair<String, Integer> ourSystemFontData; |
||||
public static final float DEF_SYSTEM_FONT_SIZE = 12f; // TODO: consider 12 * 1.33 to compensate JDK's 72dpi font scale
|
||||
|
||||
public static <T extends JComponent> T findComponentOfType(JComponent parent, Class<T> cls) { |
||||
if (parent == null || cls.isAssignableFrom(parent.getClass())) { |
||||
@SuppressWarnings({"unchecked"}) final T t = (T) parent; |
||||
return t; |
||||
} |
||||
for (Component component : parent.getComponents()) { |
||||
if (component instanceof JComponent) { |
||||
T comp = findComponentOfType((JComponent) component, cls); |
||||
if (comp != null) return comp; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@Nullable |
||||
public static Pair<String, Integer> getSystemFontData() { |
||||
return ourSystemFontData; |
||||
} |
||||
|
||||
public static <T> T getParentOfType(Class<? extends T> cls, Component c) { |
||||
Component eachParent = c; |
||||
while (eachParent != null) { |
||||
if (cls.isAssignableFrom(eachParent.getClass())) { |
||||
@SuppressWarnings({"unchecked"}) final T t = (T) eachParent; |
||||
return t; |
||||
} |
||||
|
||||
eachParent = eachParent.getParent(); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public static boolean isAppleRetina() { |
||||
return isRetina() && SystemInfo.isAppleJvm; |
||||
} |
||||
|
||||
public static Color getControlColor() { |
||||
return UIManager.getColor("control"); |
||||
} |
||||
|
||||
public static Color getPanelBackground() { |
||||
return UIManager.getColor("Panel.background"); |
||||
} |
||||
|
||||
public static boolean isUnderDarcula() { |
||||
return UIManager.getLookAndFeel().getName().equals("Darcula"); |
||||
} |
||||
|
||||
public static Color getListBackground() { |
||||
return UIManager.getColor("List.background"); |
||||
} |
||||
|
||||
public static Color getListForeground() { |
||||
return UIManager.getColor("List.foreground"); |
||||
} |
||||
|
||||
public static Color getLabelForeground() { |
||||
return UIManager.getColor("Label.foreground"); |
||||
} |
||||
|
||||
public static Color getTextFieldBackground() { |
||||
return UIManager.getColor("TextField.background"); |
||||
} |
||||
|
||||
public static Color getTreeSelectionForeground() { |
||||
return UIManager.getColor("Tree.selectionForeground"); |
||||
} |
||||
|
||||
public static Color getTreeForeground() { |
||||
return UIManager.getColor("Tree.foreground"); |
||||
} |
||||
|
||||
private static final Color DECORATED_ROW_BG_COLOR = new DoubleColor(new Color(242, 245, 249), new Color(65, 69, 71)); |
||||
|
||||
public static Color getDecoratedRowColor() { |
||||
return DECORATED_ROW_BG_COLOR; |
||||
} |
||||
|
||||
public static Color getTreeSelectionBackground(boolean focused) { |
||||
return focused ? getTreeSelectionBackground() : getTreeUnfocusedSelectionBackground(); |
||||
} |
||||
|
||||
private static Color getTreeSelectionBackground() { |
||||
return UIManager.getColor("Tree.selectionBackground"); |
||||
} |
||||
|
||||
public static Color getTreeUnfocusedSelectionBackground() { |
||||
Color background = getTreeTextBackground(); |
||||
return ColorUtil.isDark(background) ? new DoubleColor(Gray._30, new Color(13, 41, 62)) : Gray._212; |
||||
} |
||||
|
||||
public static Color getTreeTextBackground() { |
||||
return UIManager.getColor("Tree.textBackground"); |
||||
} |
||||
|
||||
public static void drawImage(Graphics g, Image image, int x, int y, ImageObserver observer) { |
||||
if (image instanceof JBHiDPIScaledImage) { |
||||
final Graphics2D newG = (Graphics2D) g.create(x, y, image.getWidth(observer), image.getHeight(observer)); |
||||
newG.scale(0.5, 0.5); |
||||
Image img = ((JBHiDPIScaledImage) image).getDelegate(); |
||||
if (img == null) { |
||||
img = image; |
||||
} |
||||
newG.drawImage(img, 0, 0, observer); |
||||
newG.scale(1, 1); |
||||
newG.dispose(); |
||||
} else { |
||||
g.drawImage(image, x, y, observer); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static final Ref<Boolean> ourRetina = Ref.create(SystemInfo.isMac ? null : false); |
||||
|
||||
public static boolean isRetina() { |
||||
synchronized (ourRetina) { |
||||
if (ourRetina.isNull()) { |
||||
ourRetina.set(false); // in case HiDPIScaledImage.drawIntoImage is not called for some reason
|
||||
|
||||
if (SystemInfo.isJavaVersionAtLeast("1.6.0_33") && SystemInfo.isAppleJvm) { |
||||
if (!"false".equals(System.getProperty("ide.mac.retina"))) { |
||||
ourRetina.set(IsRetina.isRetina()); |
||||
return ourRetina.get(); |
||||
} |
||||
} else if (SystemInfo.isJavaVersionAtLeast("1.7.0_40") && (SystemInfo.isOracleJvm || SystemInfo.isJetbrainsJvm)) { |
||||
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); |
||||
final GraphicsDevice device = env.getDefaultScreenDevice(); |
||||
try { |
||||
Field field = device.getClass().getDeclaredField("scale"); |
||||
if (field != null) { |
||||
field.setAccessible(true); |
||||
Object scale = field.get(device); |
||||
if (scale instanceof Integer && (Integer) scale == 2) { |
||||
ourRetina.set(true); |
||||
return true; |
||||
} |
||||
} |
||||
} catch (Exception ignore) { |
||||
} |
||||
} |
||||
ourRetina.set(false); |
||||
} |
||||
|
||||
return ourRetina.get(); |
||||
} |
||||
} |
||||
|
||||
public static BufferedImage createImage(int width, int height, int type) { |
||||
if (isRetina()) { |
||||
return RetinaImage.create(width, height, type); |
||||
} |
||||
//noinspection UndesirableClassUsage
|
||||
return new BufferedImage(width, height, type); |
||||
} |
||||
|
||||
|
||||
private static final GrayFilter DEFAULT_GRAY_FILTER = new GrayFilter(true, 65); |
||||
private static final GrayFilter DARCULA_GRAY_FILTER = new GrayFilter(true, 30); |
||||
|
||||
public static GrayFilter getGrayFilter() { |
||||
return isUnderDarcula() ? DARCULA_GRAY_FILTER : DEFAULT_GRAY_FILTER; |
||||
} |
||||
|
||||
public static Font getLabelFont() { |
||||
return UIManager.getFont("Label.font"); |
||||
} |
||||
|
||||
public static float getFontSize(FontSize size) { |
||||
int defSize = getLabelFont().getSize(); |
||||
switch (size) { |
||||
case SMALL: |
||||
return Math.max(defSize - JBUI.scale(2f), JBUI.scale(11f)); |
||||
case MINI: |
||||
return Math.max(defSize - JBUI.scale(4f), JBUI.scale(9f)); |
||||
default: |
||||
return defSize; |
||||
} |
||||
} |
||||
|
||||
public enum FontSize {NORMAL, SMALL, MINI} |
||||
|
||||
public static void initSystemFontData() { |
||||
if (ourSystemFontData != null) return; |
||||
|
||||
// With JB Linux JDK the label font comes properly scaled based on Xft.dpi settings.
|
||||
Font font = getLabelFont(); |
||||
|
||||
Float forcedScale = null; |
||||
if (Registry.is("ide.ui.scale.override")) { |
||||
forcedScale = Registry.getFloat("ide.ui.scale"); |
||||
} |
||||
else if (SystemInfo.isLinux && !SystemInfo.isJetbrainsJvm) { |
||||
// With Oracle JDK: derive scale from X server DPI
|
||||
float scale = getScreenScale(); |
||||
if (scale > 1f) { |
||||
forcedScale = scale; |
||||
} |
||||
// Or otherwise leave the detected font. It's undetermined if it's scaled or not.
|
||||
// If it is (likely with GTK DE), then the UI scale will be derived from it,
|
||||
// if it's not, then IDEA will start unscaled. This lets the users of GTK DEs
|
||||
// not to bother about X server DPI settings. Users of other DEs (like KDE)
|
||||
// will have to set X server DPI to meet their display.
|
||||
} |
||||
else if (SystemInfo.isWindows) { |
||||
//noinspection HardCodedStringLiteral
|
||||
Font winFont = (Font)Toolkit.getDefaultToolkit().getDesktopProperty("win.messagebox.font"); |
||||
if (winFont != null) { |
||||
font = winFont; // comes scaled
|
||||
} |
||||
} |
||||
if (forcedScale != null) { |
||||
// With forced scale, we derive font from a hard-coded value as we cannot be sure
|
||||
// the system font comes unscaled.
|
||||
font = font.deriveFont(DEF_SYSTEM_FONT_SIZE * forcedScale.floatValue()); |
||||
} |
||||
ourSystemFontData = Pair.create(font.getName(), font.getSize()); |
||||
} |
||||
|
||||
private static float getScreenScale() { |
||||
int dpi = 96; |
||||
try { |
||||
dpi = Toolkit.getDefaultToolkit().getScreenResolution(); |
||||
} catch (HeadlessException e) { |
||||
} |
||||
float scale = 1f; |
||||
if (dpi < 120) scale = 1f; |
||||
else if (dpi < 144) scale = 1.25f; |
||||
else if (dpi < 168) scale = 1.5f; |
||||
else if (dpi < 192) scale = 1.75f; |
||||
else scale = 2f; |
||||
|
||||
return scale; |
||||
} |
||||
} |
@ -0,0 +1,199 @@
|
||||
/* |
||||
* Copyright 2000-2014 JetBrains s.r.o. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.bulenkov.iconloader.util; |
||||
|
||||
import java.io.*; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URL; |
||||
import java.nio.charset.Charset; |
||||
import java.util.ArrayList; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
import java.util.zip.ZipEntry; |
||||
import java.util.zip.ZipFile; |
||||
|
||||
/** |
||||
* @author Konstantin Bulenkov |
||||
*/ |
||||
public class URLUtil { |
||||
public static final String SCHEME_SEPARATOR = "://"; |
||||
public static final String FILE_PROTOCOL = "file"; |
||||
public static final String HTTP_PROTOCOL = "http"; |
||||
public static final String JAR_PROTOCOL = "jar"; |
||||
public static final String JAR_SEPARATOR = "!/"; |
||||
|
||||
public static final Pattern DATA_URI_PATTERN = Pattern.compile("data:([^,;]+/[^,;]+)(;charset=[^,;]+)?(;base64)?,(.+)"); |
||||
|
||||
private URLUtil() { |
||||
} |
||||
|
||||
/** |
||||
* Opens a url stream. The semantics is the sames as {@link java.net.URL#openStream()}. The |
||||
* separate method is needed, since jar URLs open jars via JarFactory and thus keep them |
||||
* mapped into memory. |
||||
*/ |
||||
|
||||
public static InputStream openStream(URL url) throws IOException { |
||||
String protocol = url.getProtocol(); |
||||
boolean isFile = protocol.equals(JAR_PROTOCOL) && !url.getFile().startsWith(HTTP_PROTOCOL); |
||||
return isFile ? openJarStream(url) : url.openStream(); |
||||
} |
||||
|
||||
|
||||
public static InputStream openResourceStream(final URL url) throws IOException { |
||||
try { |
||||
return openStream(url); |
||||
} catch (FileNotFoundException ex) { |
||||
final String protocol = url.getProtocol(); |
||||
String file = null; |
||||
if (protocol.equals(FILE_PROTOCOL)) { |
||||
file = url.getFile(); |
||||
} else if (protocol.equals(JAR_PROTOCOL)) { |
||||
int pos = url.getFile().indexOf("!"); |
||||
if (pos >= 0) { |
||||
file = url.getFile().substring(pos + 1); |
||||
} |
||||
} |
||||
if (file != null && file.startsWith("/")) { |
||||
InputStream resourceStream = URLUtil.class.getResourceAsStream(file); |
||||
if (resourceStream != null) return resourceStream; |
||||
} |
||||
throw ex; |
||||
} |
||||
} |
||||
|
||||
|
||||
private static InputStream openJarStream(URL url) throws IOException { |
||||
Pair<String, String> paths = splitJarUrl(url.getFile()); |
||||
if (paths == null) { |
||||
throw new MalformedURLException(url.getFile()); |
||||
} |
||||
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed") final ZipFile zipFile = new ZipFile(unquote(paths.first)); |
||||
ZipEntry zipEntry = zipFile.getEntry(paths.second); |
||||
if (zipEntry == null) { |
||||
throw new FileNotFoundException("Entry " + paths.second + " not found in " + paths.first); |
||||
} |
||||
|
||||
return new FilterInputStream(zipFile.getInputStream(zipEntry)) { |
||||
@Override |
||||
public void close() throws IOException { |
||||
super.close(); |
||||
zipFile.close(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public static String unquote(String urlString) { |
||||
urlString = urlString.replace('/', File.separatorChar); |
||||
return unescapePercentSequences(urlString); |
||||
} |
||||
|
||||
|
||||
public static Pair<String, String> splitJarUrl(String fullPath) { |
||||
int delimiter = fullPath.indexOf(JAR_SEPARATOR); |
||||
if (delimiter >= 0) { |
||||
String resourcePath = fullPath.substring(delimiter + 2); |
||||
String jarPath = fullPath.substring(0, delimiter); |
||||
if (StringUtil.startsWithConcatenation(jarPath, FILE_PROTOCOL, ":")) { |
||||
jarPath = jarPath.substring(FILE_PROTOCOL.length() + 1); |
||||
return Pair.create(jarPath, resourcePath); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
|
||||
public static String unescapePercentSequences(String s) { |
||||
if (s.indexOf('%') == -1) { |
||||
return s; |
||||
} |
||||
|
||||
StringBuilder decoded = new StringBuilder(); |
||||
final int len = s.length(); |
||||
int i = 0; |
||||
while (i < len) { |
||||
char c = s.charAt(i); |
||||
if (c == '%') { |
||||
ArrayList<Integer> bytes = new ArrayList<Integer>(); |
||||
while (i + 2 < len && s.charAt(i) == '%') { |
||||
final int d1 = decode(s.charAt(i + 1)); |
||||
final int d2 = decode(s.charAt(i + 2)); |
||||
if (d1 != -1 && d2 != -1) { |
||||
bytes.add(((d1 & 0xf) << 4 | d2 & 0xf)); |
||||
i += 3; |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
if (!bytes.isEmpty()) { |
||||
final byte[] bytesArray = new byte[bytes.size()]; |
||||
for (int j = 0; j < bytes.size(); j++) { |
||||
bytesArray[j] = bytes.get(j).byteValue(); |
||||
} |
||||
decoded.append(new String(bytesArray, Charset.forName("UTF-8"))); |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
decoded.append(c); |
||||
i++; |
||||
} |
||||
return decoded.toString(); |
||||
} |
||||
|
||||
private static int decode(char c) { |
||||
if ((c >= '0') && (c <= '9')) |
||||
return c - '0'; |
||||
if ((c >= 'a') && (c <= 'f')) |
||||
return c - 'a' + 10; |
||||
if ((c >= 'A') && (c <= 'F')) |
||||
return c - 'A' + 10; |
||||
return -1; |
||||
} |
||||
|
||||
public static boolean containsScheme(String url) { |
||||
return url.contains(SCHEME_SEPARATOR); |
||||
} |
||||
|
||||
public static boolean isDataUri(String value) { |
||||
return !value.isEmpty() && value.startsWith("data:", value.charAt(0) == '"' || value.charAt(0) == '\'' ? 1 : 0); |
||||
} |
||||
|
||||
/** |
||||
* Extracts byte array from given data:URL string. |
||||
* data:URL will be decoded from base64 if it contains the marker of base64 encoding. |
||||
* |
||||
* @param dataUrl data:URL-like string (may be quoted) |
||||
* @return extracted byte array or {@code null} if it cannot be extracted. |
||||
*/ |
||||
|
||||
public static byte[] getBytesFromDataUri(String dataUrl) { |
||||
Matcher matcher = DATA_URI_PATTERN.matcher(StringUtil.stripQuotesAroundValue(dataUrl)); |
||||
if (matcher.matches()) { |
||||
try { |
||||
String content = matcher.group(4); |
||||
final Charset charset = Charset.forName("UTF-8"); |
||||
final byte[] bytes = content.getBytes(charset); |
||||
return ";base64".equalsIgnoreCase(matcher.group(3)) ? Base64Converter.decode(bytes) : bytes; |
||||
} catch (IllegalArgumentException e) { |
||||
return null; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
Loading…
Reference in new issue