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

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

see #7427 - sonar - squid:S1449 - Locale should be used in String operations

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trc;
6
7import java.awt.Component;
8import java.awt.GridBagLayout;
9import java.awt.event.ActionEvent;
10import java.awt.image.BufferedImage;
11import java.awt.image.BufferedImageOp;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.List;
16import java.util.Locale;
17
18import javax.swing.AbstractAction;
19import javax.swing.Action;
20import javax.swing.BorderFactory;
21import javax.swing.Icon;
22import javax.swing.JCheckBoxMenuItem;
23import javax.swing.JComponent;
24import javax.swing.JLabel;
25import javax.swing.JMenu;
26import javax.swing.JMenuItem;
27import javax.swing.JPanel;
28import javax.swing.JPopupMenu;
29import javax.swing.JSeparator;
30import javax.swing.JTextField;
31
32import org.openstreetmap.josm.Main;
33import org.openstreetmap.josm.data.ProjectionBounds;
34import org.openstreetmap.josm.data.imagery.ImageryInfo;
35import org.openstreetmap.josm.data.imagery.OffsetBookmark;
36import org.openstreetmap.josm.data.preferences.IntegerProperty;
37import org.openstreetmap.josm.gui.MenuScroller;
38import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
39import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
40import org.openstreetmap.josm.tools.GBC;
41import org.openstreetmap.josm.tools.ImageProvider;
42import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
43import org.openstreetmap.josm.tools.Utils;
44
45public abstract class ImageryLayer extends Layer {
46
47 public static final IntegerProperty PROP_SHARPEN_LEVEL = new IntegerProperty("imagery.sharpen_level", 0);
48
49 private final List<ImageProcessor> imageProcessors = new ArrayList<>();
50
51 protected final ImageryInfo info;
52
53 protected Icon icon;
54
55 private final ImageryFilterSettings filterSettings = new ImageryFilterSettings();
56
57 /**
58 * Constructs a new {@code ImageryLayer}.
59 * @param info imagery info
60 */
61 public ImageryLayer(ImageryInfo info) {
62 super(info.getName());
63 this.info = info;
64 if (info.getIcon() != null) {
65 icon = new ImageProvider(info.getIcon()).setOptional(true).
66 setMaxSize(ImageSizes.LAYER).get();
67 }
68 if (icon == null) {
69 icon = ImageProvider.get("imagery_small");
70 }
71 for (ImageProcessor processor : filterSettings.getProcessors()) {
72 addImageProcessor(processor);
73 }
74 filterSettings.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f);
75 }
76
77 public double getPPD() {
78 if (!Main.isDisplayingMapView())
79 return Main.getProjection().getDefaultZoomInPPD();
80 ProjectionBounds bounds = Main.map.mapView.getProjectionBounds();
81 return Main.map.mapView.getWidth() / (bounds.maxEast - bounds.minEast);
82 }
83
84 /**
85 * Gets the x displacement of this layer.
86 * To be removed end of 2016
87 * @return The x displacement.
88 * @deprecated Use {@link TileSourceDisplaySettings#getDx()}
89 */
90 @Deprecated
91 public double getDx() {
92 // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
93 return 0;
94 }
95
96 /**
97 * Gets the y displacement of this layer.
98 * To be removed end of 2016
99 * @return The y displacement.
100 * @deprecated Use {@link TileSourceDisplaySettings#getDy()}
101 */
102 @Deprecated
103 public double getDy() {
104 // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
105 return 0;
106 }
107
108 /**
109 * Sets the displacement offset of this layer. The layer is automatically invalidated.
110 * To be removed end of 2016
111 * @param dx The x offset
112 * @param dy The y offset
113 * @deprecated Use {@link TileSourceDisplaySettings}
114 */
115 @Deprecated
116 public void setOffset(double dx, double dy) {
117 // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
118 }
119
120 /**
121 * To be removed end of 2016
122 * @param dx deprecated
123 * @param dy deprecated
124 * @deprecated Use {@link TileSourceDisplaySettings}
125 */
126 @Deprecated
127 public void displace(double dx, double dy) {
128 // moved to AbstractTileSourceLayer/TileSourceDisplaySettings. Remains until all actions migrate.
129 }
130
131 /**
132 * Returns imagery info.
133 * @return imagery info
134 */
135 public ImageryInfo getInfo() {
136 return info;
137 }
138
139 @Override
140 public Icon getIcon() {
141 return icon;
142 }
143
144 @Override
145 public boolean isMergable(Layer other) {
146 return false;
147 }
148
149 @Override
150 public void mergeFrom(Layer from) {
151 }
152
153 public abstract Collection<String> getNativeProjections();
154
155 @Override
156 public Object getInfoComponent() {
157 JPanel panel = new JPanel(new GridBagLayout());
158 panel.add(new JLabel(getToolTipText()), GBC.eol());
159 if (info != null) {
160 List<List<String>> content = new ArrayList<>();
161 content.add(Arrays.asList(tr("Name"), info.getName()));
162 content.add(Arrays.asList(tr("Type"), info.getImageryType().getTypeString().toUpperCase(Locale.ENGLISH)));
163 content.add(Arrays.asList(tr("URL"), info.getUrl()));
164 content.add(Arrays.asList(tr("Id"), info.getId() == null ? "-" : info.getId()));
165 if (info.getMinZoom() != 0) {
166 content.add(Arrays.asList(tr("Min. zoom"), Integer.toString(info.getMinZoom())));
167 }
168 if (info.getMaxZoom() != 0) {
169 content.add(Arrays.asList(tr("Max. zoom"), Integer.toString(info.getMaxZoom())));
170 }
171 if (info.getDescription() != null) {
172 content.add(Arrays.asList(tr("Description"), info.getDescription()));
173 }
174 content.add(Arrays.asList(tr("Native projections"), Utils.join(", ", getNativeProjections())));
175 for (List<String> entry: content) {
176 panel.add(new JLabel(entry.get(0) + ':'), GBC.std());
177 panel.add(GBC.glue(5, 0), GBC.std());
178 panel.add(createTextField(entry.get(1)), GBC.eol().fill(GBC.HORIZONTAL));
179 }
180 }
181 return panel;
182 }
183
184 protected JTextField createTextField(String text) {
185 JTextField ret = new JTextField(text);
186 ret.setEditable(false);
187 ret.setBorder(BorderFactory.createEmptyBorder());
188 return ret;
189 }
190
191 public static ImageryLayer create(ImageryInfo info) {
192 switch(info.getImageryType()) {
193 case WMS:
194 return new WMSLayer(info);
195 case WMTS:
196 return new WMTSLayer(info);
197 case TMS:
198 case BING:
199 case SCANEX:
200 return new TMSLayer(info);
201 default:
202 throw new AssertionError(tr("Unsupported imagery type: {0}", info.getImageryType()));
203 }
204 }
205
206 class ApplyOffsetAction extends AbstractAction {
207 private final transient OffsetBookmark b;
208
209 ApplyOffsetAction(OffsetBookmark b) {
210 super(b.name);
211 this.b = b;
212 }
213
214 @Override
215 public void actionPerformed(ActionEvent ev) {
216 setOffset(b.dx, b.dy);
217 Main.main.menu.imageryMenu.refreshOffsetMenu();
218 Main.map.repaint();
219 }
220 }
221
222 public class OffsetAction extends AbstractAction implements LayerAction {
223 @Override
224 public void actionPerformed(ActionEvent e) {
225 // Do nothing
226 }
227
228 @Override
229 public Component createMenuComponent() {
230 return getOffsetMenuItem();
231 }
232
233 @Override
234 public boolean supportLayers(List<Layer> layers) {
235 return false;
236 }
237 }
238
239 public JMenuItem getOffsetMenuItem() {
240 JMenu subMenu = new JMenu(trc("layer", "Offset"));
241 subMenu.setIcon(ImageProvider.get("mapmode", "adjustimg"));
242 return (JMenuItem) getOffsetMenuItem(subMenu);
243 }
244
245 public JComponent getOffsetMenuItem(JComponent subMenu) {
246 JMenuItem adjustMenuItem = new JMenuItem(getAdjustAction());
247 List<OffsetBookmark> allBookmarks = OffsetBookmark.getBookmarks();
248 if (allBookmarks.isEmpty()) return adjustMenuItem;
249
250 subMenu.add(adjustMenuItem);
251 subMenu.add(new JSeparator());
252 boolean hasBookmarks = false;
253 int menuItemHeight = 0;
254 for (OffsetBookmark b : allBookmarks) {
255 if (!b.isUsable(this)) {
256 continue;
257 }
258 JCheckBoxMenuItem item = new JCheckBoxMenuItem(new ApplyOffsetAction(b));
259 if (Utils.equalsEpsilon(b.dx, getDx()) && Utils.equalsEpsilon(b.dy, getDy())) {
260 item.setSelected(true);
261 }
262 subMenu.add(item);
263 menuItemHeight = item.getPreferredSize().height;
264 hasBookmarks = true;
265 }
266 if (menuItemHeight > 0) {
267 if (subMenu instanceof JMenu) {
268 MenuScroller.setScrollerFor((JMenu) subMenu);
269 } else if (subMenu instanceof JPopupMenu) {
270 MenuScroller.setScrollerFor((JPopupMenu) subMenu);
271 }
272 }
273 return hasBookmarks ? subMenu : adjustMenuItem;
274 }
275
276 protected abstract Action getAdjustAction();
277
278 /**
279 * Gets the settings for the filter that is applied to this layer.
280 * @return The filter settings.
281 * @since 10547
282 */
283 public ImageryFilterSettings getFilterSettings() {
284 return filterSettings;
285 }
286
287 /**
288 * This method adds the {@link ImageProcessor} to this Layer if it is not {@code null}.
289 *
290 * @param processor that processes the image
291 *
292 * @return true if processor was added, false otherwise
293 */
294 public boolean addImageProcessor(ImageProcessor processor) {
295 return processor != null && imageProcessors.add(processor);
296 }
297
298 /**
299 * This method removes given {@link ImageProcessor} from this layer
300 *
301 * @param processor which is needed to be removed
302 *
303 * @return true if processor was removed
304 */
305 public boolean removeImageProcessor(ImageProcessor processor) {
306 return imageProcessors.remove(processor);
307 }
308
309 /**
310 * Wraps a {@link BufferedImageOp} to be used as {@link ImageProcessor}.
311 * @param op the {@link BufferedImageOp}
312 * @param inPlace true to apply filter in place, i.e., not create a new {@link BufferedImage} for the result
313 * (the {@code op} needs to support this!)
314 * @return the {@link ImageProcessor} wrapper
315 */
316 public static ImageProcessor createImageProcessor(final BufferedImageOp op, final boolean inPlace) {
317 return image -> op.filter(image, inPlace ? image : null);
318 }
319
320 /**
321 * This method gets all {@link ImageProcessor}s of the layer
322 *
323 * @return list of image processors without removed one
324 */
325 public List<ImageProcessor> getImageProcessors() {
326 return imageProcessors;
327 }
328
329 /**
330 * Applies all the chosen {@link ImageProcessor}s to the image
331 *
332 * @param img - image which should be changed
333 *
334 * @return the new changed image
335 */
336 public BufferedImage applyImageProcessors(BufferedImage img) {
337 for (ImageProcessor processor : imageProcessors) {
338 img = processor.process(img);
339 }
340 return img;
341 }
342
343 @Override
344 public String toString() {
345 return getClass().getSimpleName() + " [info=" + info + ']';
346 }
347}
Note: See TracBrowser for help on using the repository browser.