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 }