source: josm/trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java@ 8540

Last change on this file since 8540 was 8540, checked in by Don-vip, 10 years ago

fix remaining checkstyle issues

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trc;
7
8import java.awt.Color;
9import java.awt.Component;
10import java.awt.Font;
11import java.awt.Graphics2D;
12import java.awt.GridBagLayout;
13import java.awt.event.ActionEvent;
14import java.awt.font.FontRenderContext;
15import java.awt.font.LineBreakMeasurer;
16import java.awt.font.TextAttribute;
17import java.awt.font.TextLayout;
18import java.awt.image.BufferedImage;
19import java.awt.image.BufferedImageOp;
20import java.awt.image.ConvolveOp;
21import java.awt.image.Kernel;
22import java.text.AttributedCharacterIterator;
23import java.text.AttributedString;
24import java.util.Hashtable;
25import java.util.List;
26import java.util.Map;
27
28import javax.swing.AbstractAction;
29import javax.swing.Icon;
30import javax.swing.JCheckBoxMenuItem;
31import javax.swing.JComponent;
32import javax.swing.JLabel;
33import javax.swing.JMenu;
34import javax.swing.JMenuItem;
35import javax.swing.JPanel;
36import javax.swing.JPopupMenu;
37import javax.swing.JSeparator;
38
39import org.openstreetmap.josm.Main;
40import org.openstreetmap.josm.actions.ImageryAdjustAction;
41import org.openstreetmap.josm.data.ProjectionBounds;
42import org.openstreetmap.josm.data.imagery.ImageryInfo;
43import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
44import org.openstreetmap.josm.data.imagery.OffsetBookmark;
45import org.openstreetmap.josm.data.preferences.ColorProperty;
46import org.openstreetmap.josm.data.preferences.IntegerProperty;
47import org.openstreetmap.josm.gui.MenuScroller;
48import org.openstreetmap.josm.gui.widgets.UrlLabel;
49import org.openstreetmap.josm.tools.GBC;
50import org.openstreetmap.josm.tools.ImageProvider;
51import org.openstreetmap.josm.tools.Utils;
52
53public abstract class ImageryLayer extends Layer {
54
55 public static final ColorProperty PROP_FADE_COLOR = new ColorProperty(marktr("Imagery fade"), Color.white);
56 public static final IntegerProperty PROP_FADE_AMOUNT = new IntegerProperty("imagery.fade_amount", 0);
57 public static final IntegerProperty PROP_SHARPEN_LEVEL = new IntegerProperty("imagery.sharpen_level", 0);
58
59 public static Color getFadeColor() {
60 return PROP_FADE_COLOR.get();
61 }
62
63 public static Color getFadeColorWithAlpha() {
64 Color c = PROP_FADE_COLOR.get();
65 return new Color(c.getRed(), c.getGreen(), c.getBlue(), PROP_FADE_AMOUNT.get()*255/100);
66 }
67
68 protected final ImageryInfo info;
69
70 protected Icon icon;
71
72 protected double dx = 0.0;
73 protected double dy = 0.0;
74
75 protected int sharpenLevel;
76
77 private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
78
79 /**
80 * Constructs a new {@code ImageryLayer}.
81 * @param info imagery info
82 */
83 public ImageryLayer(ImageryInfo info) {
84 super(info.getName());
85 this.info = info;
86 if (info.getIcon() != null) {
87 icon = new ImageProvider(info.getIcon()).setOptional(true).
88 setMaxHeight(ICON_SIZE).setMaxWidth(ICON_SIZE).get();
89 }
90 if (icon == null) {
91 icon = ImageProvider.get("imagery_small");
92 }
93 this.sharpenLevel = PROP_SHARPEN_LEVEL.get();
94 }
95
96 public double getPPD() {
97 if (!Main.isDisplayingMapView()) return Main.getProjection().getDefaultZoomInPPD();
98 ProjectionBounds bounds = Main.map.mapView.getProjectionBounds();
99 return Main.map.mapView.getWidth() / (bounds.maxEast - bounds.minEast);
100 }
101
102 public double getDx() {
103 return dx;
104 }
105
106 public double getDy() {
107 return dy;
108 }
109
110 public void setOffset(double dx, double dy) {
111 this.dx = dx;
112 this.dy = dy;
113 }
114
115 public void displace(double dx, double dy) {
116 setOffset(this.dx += dx, this.dy += dy);
117 }
118
119 public ImageryInfo getInfo() {
120 return info;
121 }
122
123 @Override
124 public Icon getIcon() {
125 return icon;
126 }
127
128 @Override
129 public boolean isMergable(Layer other) {
130 return false;
131 }
132
133 @Override
134 public void mergeFrom(Layer from) {
135 }
136
137 @Override
138 public Object getInfoComponent() {
139 JPanel panel = new JPanel(new GridBagLayout());
140 panel.add(new JLabel(getToolTipText()), GBC.eol());
141 if (info != null) {
142 String url = info.getUrl();
143 if (url != null) {
144 panel.add(new JLabel(tr("URL: ")), GBC.std().insets(0, 5, 2, 0));
145 panel.add(new UrlLabel(url), GBC.eol().insets(2, 5, 10, 0));
146 }
147 if (dx != 0 || dy != 0) {
148 panel.add(new JLabel(tr("Offset: ") + dx + ";" + dy), GBC.eol().insets(0, 5, 10, 0));
149 }
150 }
151 return panel;
152 }
153
154 public static ImageryLayer create(ImageryInfo info) {
155 ImageryType type = info.getImageryType();
156 if (type == ImageryType.WMS || type == ImageryType.HTML)
157 return new WMSLayer(info);
158 else if (type == ImageryType.TMS || type == ImageryType.BING || type == ImageryType.SCANEX)
159 return new TMSLayer(info);
160 else throw new AssertionError();
161 }
162
163 class ApplyOffsetAction extends AbstractAction {
164 private transient OffsetBookmark b;
165
166 ApplyOffsetAction(OffsetBookmark b) {
167 super(b.name);
168 this.b = b;
169 }
170
171 @Override
172 public void actionPerformed(ActionEvent ev) {
173 setOffset(b.dx, b.dy);
174 Main.main.menu.imageryMenu.refreshOffsetMenu();
175 Main.map.repaint();
176 }
177 }
178
179 public class OffsetAction extends AbstractAction implements LayerAction {
180 @Override
181 public void actionPerformed(ActionEvent e) {
182 }
183
184 @Override
185 public Component createMenuComponent() {
186 return getOffsetMenuItem();
187 }
188
189 @Override
190 public boolean supportLayers(List<Layer> layers) {
191 return false;
192 }
193 }
194
195 public JMenuItem getOffsetMenuItem() {
196 JMenu subMenu = new JMenu(trc("layer", "Offset"));
197 subMenu.setIcon(ImageProvider.get("mapmode", "adjustimg"));
198 return (JMenuItem) getOffsetMenuItem(subMenu);
199 }
200
201 public JComponent getOffsetMenuItem(JComponent subMenu) {
202 JMenuItem adjustMenuItem = new JMenuItem(adjustAction);
203 if (OffsetBookmark.allBookmarks.isEmpty()) return adjustMenuItem;
204
205 subMenu.add(adjustMenuItem);
206 subMenu.add(new JSeparator());
207 boolean hasBookmarks = false;
208 int menuItemHeight = 0;
209 for (OffsetBookmark b : OffsetBookmark.allBookmarks) {
210 if (!b.isUsable(this)) {
211 continue;
212 }
213 JCheckBoxMenuItem item = new JCheckBoxMenuItem(new ApplyOffsetAction(b));
214 if (Utils.equalsEpsilon(b.dx, dx) && Utils.equalsEpsilon(b.dy, dy)) {
215 item.setSelected(true);
216 }
217 subMenu.add(item);
218 menuItemHeight = item.getPreferredSize().height;
219 hasBookmarks = true;
220 }
221 if (menuItemHeight > 0) {
222 if (subMenu instanceof JMenu) {
223 MenuScroller.setScrollerFor((JMenu) subMenu);
224 } else if (subMenu instanceof JPopupMenu) {
225 MenuScroller.setScrollerFor((JPopupMenu) subMenu);
226 }
227 }
228 return hasBookmarks ? subMenu : adjustMenuItem;
229 }
230
231 public BufferedImage sharpenImage(BufferedImage img) {
232 if (sharpenLevel <= 0) return img;
233 int width = img.getWidth(null);
234 int height = img.getHeight(null);
235 BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
236 tmp.getGraphics().drawImage(img, 0, 0, null);
237 Kernel kernel;
238 if (sharpenLevel == 1) {
239 kernel = new Kernel(3, 3, new float[] {-0.25f, -0.5f, -0.25f, -0.5f, 4, -0.5f, -0.25f, -0.5f, -0.25f});
240 } else {
241 kernel = new Kernel(3, 3, new float[] {-0.5f, -1, -0.5f, -1, 7, -1, -0.5f, -1, -0.5f});
242 }
243 BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
244 return op.filter(tmp, null);
245 }
246
247 /**
248 * Draws a red error tile when imagery tile cannot be fetched.
249 * @param img The buffered image
250 * @param message Additional error message to display
251 */
252 public void drawErrorTile(BufferedImage img, String message) {
253 Graphics2D g = (Graphics2D) img.getGraphics();
254 g.setColor(Color.RED);
255 g.fillRect(0, 0, img.getWidth(), img.getHeight());
256 g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(24.0f));
257 g.setColor(Color.BLACK);
258
259 String text = tr("ERROR");
260 g.drawString(text, (img.getWidth() - g.getFontMetrics().stringWidth(text)) / 2, g.getFontMetrics().getHeight()+5);
261 if (message != null) {
262 float drawPosY = 2.5f*g.getFontMetrics().getHeight()+10;
263 if (!message.contains(" ")) {
264 g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(18.0f));
265 g.drawString(message, 5, (int) drawPosY);
266 } else {
267 // Draw message on several lines
268 Map<TextAttribute, Object> map = new Hashtable<TextAttribute, Object>();
269 map.put(TextAttribute.FAMILY, "Serif");
270 map.put(TextAttribute.SIZE, new Float(18.0));
271 AttributedString vanGogh = new AttributedString(message, map);
272 // Create a new LineBreakMeasurer from the text
273 AttributedCharacterIterator paragraph = vanGogh.getIterator();
274 int paragraphStart = paragraph.getBeginIndex();
275 int paragraphEnd = paragraph.getEndIndex();
276 FontRenderContext frc = g.getFontRenderContext();
277 LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
278 // Set break width to width of image with some margin
279 float breakWidth = img.getWidth()-10;
280 // Set position to the index of the first character in the text
281 lineMeasurer.setPosition(paragraphStart);
282 // Get lines until the entire paragraph has been displayed
283 while (lineMeasurer.getPosition() < paragraphEnd) {
284 // Retrieve next layout
285 TextLayout layout = lineMeasurer.nextLayout(breakWidth);
286
287 // Compute pen x position
288 float drawPosX = layout.isLeftToRight() ? 0 : breakWidth - layout.getAdvance();
289
290 // Move y-coordinate by the ascent of the layout
291 drawPosY += layout.getAscent();
292
293 // Draw the TextLayout at (drawPosX, drawPosY)
294 layout.draw(g, drawPosX, drawPosY);
295
296 // Move y-coordinate in preparation for next layout
297 drawPosY += layout.getDescent() + layout.getLeading();
298 }
299 }
300 }
301 }
302
303 @Override
304 public void destroy() {
305 super.destroy();
306 adjustAction.destroy();
307 }
308}
Note: See TracBrowser for help on using the repository browser.