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