001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.mappaint; 003 004 import static org.openstreetmap.josm.tools.Utils.equal; 005 006 import java.awt.Image; 007 import java.awt.Rectangle; 008 import java.awt.image.BufferedImage; 009 010 import javax.swing.ImageIcon; 011 012 import org.openstreetmap.josm.Main; 013 import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.BoxProvider; 014 import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.BoxProviderResult; 015 import org.openstreetmap.josm.gui.util.GuiHelper; 016 import org.openstreetmap.josm.tools.ImageProvider; 017 import org.openstreetmap.josm.tools.ImageProvider.ImageCallback; 018 import org.openstreetmap.josm.tools.Utils; 019 020 public class MapImage { 021 /** 022 * ImageIcon can change while the image is loading. 023 */ 024 private BufferedImage img; 025 026 /** 027 * The 5 following fields are only used to check for equality. 028 */ 029 public int alpha = 255; 030 public String name; 031 public StyleSource source; 032 public int width = -1; 033 public int height = -1; 034 035 private boolean temporary; 036 private Image disabledImg; 037 038 public MapImage(String name, StyleSource source) { 039 this.name = name; 040 this.source = source; 041 } 042 043 public Image getDisabled() { 044 if (disabledImg != null) 045 return disabledImg; 046 if (img == null) 047 getImage(); // fix #7498 ? 048 disabledImg = GuiHelper.getDisabledImage(img); 049 return disabledImg; 050 } 051 052 public BufferedImage getImage() { 053 if (img != null) 054 return img; 055 temporary = false; 056 new ImageProvider(name) 057 .setDirs(MapPaintStyles.getIconSourceDirs(source)) 058 .setId("mappaint."+source.getPrefName()) 059 .setArchive(source.zipIcons) 060 .setWidth(width) 061 .setHeight(height) 062 .setOptional(true) 063 .getInBackground(new ImageCallback() { 064 @Override 065 public void finished(ImageIcon result) { 066 synchronized (MapImage.this) { 067 if (result == null) { 068 ImageIcon noIcon = MapPaintStyles.getNoIcon_Icon(source); 069 img = noIcon == null ? null : (BufferedImage) noIcon.getImage(); 070 } else { 071 img = (BufferedImage) result.getImage(); 072 } 073 if (temporary) { 074 Main.map.mapView.preferenceChanged(null); // otherwise repaint is ignored, because layer hasn't changed 075 Main.map.mapView.repaint(); 076 } 077 temporary = false; 078 } 079 } 080 } 081 ); 082 synchronized (this) { 083 if (img == null) { 084 img = (BufferedImage) ImageProvider.get("clock").getImage(); 085 temporary = true; 086 } 087 } 088 return img; 089 } 090 091 public int getWidth() { 092 return getImage().getWidth(null); 093 } 094 095 public int getHeight() { 096 return getImage().getHeight(null); 097 } 098 099 public float getAlphaFloat() { 100 return Utils.color_int2float(alpha); 101 } 102 103 /** 104 * Returns true, if image is not completely loaded and getImage() returns a temporary image. 105 */ 106 public boolean isTemporary() { 107 return temporary; 108 } 109 110 protected class MapImageBoxProvider implements BoxProvider { 111 @Override 112 public BoxProviderResult get() { 113 return new BoxProviderResult(box(), temporary); 114 } 115 116 private Rectangle box() { 117 int w = getWidth(), h = getHeight(); 118 return new Rectangle(-w/2, -h/2, w, h); 119 } 120 121 private MapImage getParent() { 122 return MapImage.this; 123 } 124 125 @Override 126 public int hashCode() { 127 return MapImage.this.hashCode(); 128 } 129 130 @Override 131 public boolean equals(Object obj) { 132 if (obj == null || !(obj instanceof BoxProvider)) 133 return false; 134 if (obj instanceof MapImageBoxProvider) { 135 MapImageBoxProvider other = (MapImageBoxProvider) obj; 136 return MapImage.this.equals(other.getParent()); 137 } else if (temporary) { 138 return false; 139 } else { 140 final BoxProvider other = (BoxProvider) obj; 141 BoxProviderResult resultOther = other.get(); 142 if (resultOther.isTemporary()) return false; 143 return box().equals(resultOther.getBox()); 144 } 145 } 146 } 147 148 public BoxProvider getBoxProvider() { 149 return new MapImageBoxProvider(); 150 } 151 152 @Override 153 public boolean equals(Object obj) { 154 if (obj == null || getClass() != obj.getClass()) 155 return false; 156 final MapImage other = (MapImage) obj; 157 // img changes when image is fully loaded and can't be used for equality check. 158 return alpha == other.alpha && 159 equal(name, other.name) && 160 equal(source, other.source) && 161 width == other.width && 162 height == other.height; 163 } 164 165 @Override 166 public int hashCode() { 167 int hash = 7; 168 hash = 67 * hash + alpha; 169 hash = 67 * hash + name.hashCode(); 170 hash = 67 * hash + source.hashCode(); 171 hash = 67 * hash + width; 172 hash = 67 * hash + height; 173 return hash; 174 } 175 176 @Override 177 public String toString() { 178 return name; 179 } 180 }