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

Last change on this file since 12603 was 12460, checked in by bastiK, 7 years ago

see #14794 - javadoc

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