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

Last change on this file since 11841 was 11785, checked in by bastiK, 9 years ago

Imagery: remove fade setting (superseded by layer opacity), see #7427

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