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

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

see #15182 - deprecate Main.main.menu. Replacement: gui.MainApplication.getMenu()

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