Browse Source

Merge pull request #371 in CORE/base-third from ~ZHOUPING/base-third:research/10.0 to research/10.0

* commit '94c85f7d3405a94db058f75fc53727902a501465':
  REPORT-27037 alphafine快捷键不生效,无法使用
research/10.0
zhouping 5 years ago
parent
commit
1ddec90177
  1. 3
      build.third_step1-jdk11.gradle
  2. 2
      build.third_step1.gradle
  3. 2
      fine-iconloader/README.md
  4. BIN
      fine-iconloader/lib/annotations.jar
  5. BIN
      fine-iconloader/lib/eawtstub.jar
  6. 39
      fine-iconloader/src/main/java/com/bulenkov/iconloader/AppleHiDPIScaledImage.java
  7. 484
      fine-iconloader/src/main/java/com/bulenkov/iconloader/HiDPIScaledGraphics.java
  8. 557
      fine-iconloader/src/main/java/com/bulenkov/iconloader/IconLoader.java
  9. 45
      fine-iconloader/src/main/java/com/bulenkov/iconloader/IsRetina.java
  10. 51
      fine-iconloader/src/main/java/com/bulenkov/iconloader/JBHiDPIScaledImage.java
  11. 88
      fine-iconloader/src/main/java/com/bulenkov/iconloader/RetinaImage.java
  12. 77
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ArrayUtilRt.java
  13. 88
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/AsyncByteArrayOutputStream.java
  14. 180
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Base64Converter.java
  15. 40
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/BufferExposingByteArrayOutputStream.java
  16. 74
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/CenteredIcon.java
  17. 84
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ColorUtil.java
  18. 184
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ComparingUtils.java
  19. 133
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ConcurrencyUtil.java
  20. 243
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ConcurrentRefValueHashMap.java
  21. 79
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ConcurrentSoftValueHashMap.java
  22. 204
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/DoubleColor.java
  23. 92
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/EmptyIcon.java
  24. 21
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Getter.java
  25. 47
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/GraphicsConfig.java
  26. 62
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/GraphicsUtil.java
  27. 605
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Gray.java
  28. 404
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ImageLoader.java
  29. 71
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ImageUtil.java
  30. 68
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBDimension.java
  31. 51
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBEmptyBorder.java
  32. 84
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBFont.java
  33. 41
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBImageIcon.java
  34. 121
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBInsets.java
  35. 221
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBUI.java
  36. 74
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Pair.java
  37. 64
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Ref.java
  38. 65
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ReflectionUtil.java
  39. 35
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Registry.java
  40. 30
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/RetrievableIcon.java
  41. 30
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ScalableIcon.java
  42. 2303
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Scalr.java
  43. 58
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/SoftReference.java
  44. 63
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/StringFactory.java
  45. 304
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/StringUtil.java
  46. 137
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/SystemInfo.java
  47. 272
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/UIUtil.java
  48. 199
      fine-iconloader/src/main/java/com/bulenkov/iconloader/util/URLUtil.java

3
build.third_step1-jdk11.gradle

@ -48,6 +48,7 @@ sourceSets{
"${srcDir}/fine-freehep/src/main/java", "${srcDir}/fine-freehep/src/main/java",
"${srcDir}/fine-guava/src", "${srcDir}/fine-guava/src",
"${srcDir}/fine-hsqldb/src/main/java", "${srcDir}/fine-hsqldb/src/main/java",
"${srcDir}/fine-iconloader/src/main/java",
"${srcDir}/fine-icu4j/src", "${srcDir}/fine-icu4j/src",
"${srcDir}/fine-imageJ/src/main/java", "${srcDir}/fine-imageJ/src/main/java",
"${srcDir}/fine-j2v8/src", "${srcDir}/fine-j2v8/src",
@ -111,6 +112,7 @@ def resourceDirs = [
"${srcDir}/fine-freehep/src/main/java", "${srcDir}/fine-freehep/src/main/java",
"${srcDir}/fine-guava/src", "${srcDir}/fine-guava/src",
"${srcDir}/fine-hsqldb/src/main/java", "${srcDir}/fine-hsqldb/src/main/java",
"${srcDir}/fine-iconloader/src/main/java",
"${srcDir}/fine-icu4j/src", "${srcDir}/fine-icu4j/src",
"${srcDir}/fine-imageJ/src/main/java", "${srcDir}/fine-imageJ/src/main/java",
"${srcDir}/fine-j2v8/src", "${srcDir}/fine-j2v8/src",
@ -177,6 +179,7 @@ dependencies{
compile fileTree(dir:"${srcDir}/fine-cssparser/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-cssparser/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-freehep/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-freehep/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-hsqldb/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-hsqldb/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-iconloader/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-jgit/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-jgit/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-org-dom4j/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-org-dom4j/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-sense4/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-sense4/lib",include:'**/*.jar')

2
build.third_step1.gradle

@ -49,6 +49,7 @@ sourceSets{
"${srcDir}/fine-freehep/src/main/java", "${srcDir}/fine-freehep/src/main/java",
"${srcDir}/fine-guava/src", "${srcDir}/fine-guava/src",
"${srcDir}/fine-hsqldb/src/main/java", "${srcDir}/fine-hsqldb/src/main/java",
"${srcDir}/fine-iconloader/src/main/java",
"${srcDir}/fine-icu4j/src", "${srcDir}/fine-icu4j/src",
"${srcDir}/fine-imageJ/src/main/java", "${srcDir}/fine-imageJ/src/main/java",
"${srcDir}/fine-j2v8/src", "${srcDir}/fine-j2v8/src",
@ -108,6 +109,7 @@ dependencies{
compile fileTree(dir:"${srcDir}/fine-cssparser/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-cssparser/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-freehep/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-freehep/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-hsqldb/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-hsqldb/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-iconloader/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-jgit/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-jgit/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-org-dom4j/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-org-dom4j/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-sense4/lib",include:'**/*.jar') compile fileTree(dir:"${srcDir}/fine-sense4/lib",include:'**/*.jar')

2
fine-iconloader/README.md

@ -0,0 +1,2 @@
源码地址:https://github.com/bulenkov/iconloader <br>
版本:1.0

BIN
fine-iconloader/lib/annotations.jar

Binary file not shown.

BIN
fine-iconloader/lib/eawtstub.jar

Binary file not shown.

39
fine-iconloader/src/main/java/com/bulenkov/iconloader/AppleHiDPIScaledImage.java

@ -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;
}
}

484
fine-iconloader/src/main/java/com/bulenkov/iconloader/HiDPIScaledGraphics.java

@ -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);
}
}

557
fine-iconloader/src/main/java/com/bulenkov/iconloader/IconLoader.java

@ -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();
}
}

45
fine-iconloader/src/main/java/com/bulenkov/iconloader/IsRetina.java

@ -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;
}
}
}

51
fine-iconloader/src/main/java/com/bulenkov/iconloader/JBHiDPIScaledImage.java

@ -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;
}
}

88
fine-iconloader/src/main/java/com/bulenkov/iconloader/RetinaImage.java

@ -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);
}
}

77
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ArrayUtilRt.java

@ -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;
}
}

88
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/AsyncByteArrayOutputStream.java

@ -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);
}
}

180
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Base64Converter.java

@ -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;
}
}

40
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/BufferExposingByteArrayOutputStream.java

@ -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;
}
}

74
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/CenteredIcon.java

@ -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;
}
}

84
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ColorUtil.java

@ -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;
}
}

184
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ComparingUtils.java

@ -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);
}
}

133
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ConcurrencyUtil.java

@ -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);
}
};
}
}

243
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ConcurrentRefValueHashMap.java

@ -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();
}
}

79
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ConcurrentSoftValueHashMap.java

@ -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);
}
}

204
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/DoubleColor.java

@ -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();
}
}

92
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/EmptyIcon.java

@ -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;
}
}

21
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Getter.java

@ -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();
}

47
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/GraphicsConfig.java

@ -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);
}
}

62
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/GraphicsUtil.java

@ -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;
}
}

605
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Gray.java

@ -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(", ");
// }
// }
// }
//}
}

404
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ImageLoader.java

@ -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);
}
}

71
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ImageUtil.java

@ -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));
}
}

68
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBDimension.java

@ -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;
}
}

51
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBEmptyBorder.java

@ -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;
}
}
}

84
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBFont.java

@ -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);
}
}
}

41
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBImageIcon.java

@ -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);
}
}

121
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBInsets.java

@ -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;
}
}
}

221
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/JBUI.java

@ -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);
}
}
}

74
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Pair.java

@ -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;
}
}

64
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Ref.java

@ -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);
}
}

65
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ReflectionUtil.java

@ -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() { }
}

35
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Registry.java

@ -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;
}
}
}

30
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/RetrievableIcon.java

@ -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();
}

30
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/ScalableIcon.java

@ -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);
}

2303
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/Scalr.java

File diff suppressed because it is too large Load Diff

58
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/SoftReference.java

@ -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();
}
}

63
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/StringFactory.java

@ -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);
}
}

304
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/StringUtil.java

@ -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();
}
}

137
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/SystemInfo.java

@ -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");
}
}

272
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/UIUtil.java

@ -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;
}
}

199
fine-iconloader/src/main/java/com/bulenkov/iconloader/util/URLUtil.java

@ -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…
Cancel
Save