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

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

fix #7575 - Non-scrollable menu for Imagery offset

  • Property svn:eol-style set to native
File size: 10.2 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.Graphics;
12import java.awt.Toolkit;
13import java.awt.event.ActionEvent;
14import java.awt.image.BufferedImage;
15import java.awt.image.BufferedImageOp;
16import java.awt.image.ConvolveOp;
17import java.awt.image.Kernel;
18import java.util.List;
19
20import javax.swing.AbstractAction;
21import javax.swing.Icon;
22import javax.swing.JCheckBoxMenuItem;
23import javax.swing.JComponent;
24import javax.swing.JMenu;
25import javax.swing.JMenuItem;
26import javax.swing.JPopupMenu;
27import javax.swing.JSeparator;
28import javax.swing.SwingUtilities;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.actions.ImageryAdjustAction;
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.ImageryInfo.ImageryType;
36import org.openstreetmap.josm.data.imagery.OffsetBookmark;
37import org.openstreetmap.josm.data.preferences.IntegerProperty;
38import org.openstreetmap.josm.gui.MenuScroller;
39import org.openstreetmap.josm.io.imagery.OffsetServer;
40import org.openstreetmap.josm.io.imagery.OsmosnimkiOffsetServer;
41import org.openstreetmap.josm.tools.ImageProvider;
42
43public abstract class ImageryLayer extends Layer {
44 protected static final Icon icon = ImageProvider.get("imagery_small");
45
46 public static final IntegerProperty PROP_FADE_AMOUNT = new IntegerProperty("imagery.fade_amount", 0);
47 public static final IntegerProperty PROP_SHARPEN_LEVEL = new IntegerProperty("imagery.sharpen_level", 0);
48
49 public static Color getFadeColor() {
50 return Main.pref.getColor(marktr("Imagery fade"), Color.white);
51 }
52
53 public static Color getFadeColorWithAlpha() {
54 Color c = getFadeColor();
55 return new Color(c.getRed(),c.getGreen(),c.getBlue(),PROP_FADE_AMOUNT.get()*255/100);
56 }
57
58 public static void setFadeColor(Color color) {
59 Main.pref.putColor(marktr("Imagery fade"), color);
60 }
61
62 protected final ImageryInfo info;
63
64 protected double dx = 0.0;
65 protected double dy = 0.0;
66
67 protected int sharpenLevel;
68
69 protected boolean offsetServerSupported;
70 protected boolean offsetServerUsed;
71 protected OffsetServerThread offsetServerThread;
72
73 protected OffsetServerThread createoffsetServerThread() {
74 return new OffsetServerThread(new OsmosnimkiOffsetServer(
75 OsmosnimkiOffsetServer.PROP_SERVER_URL.get()));
76 }
77
78 public ImageryLayer(ImageryInfo info) {
79 super(info.getName());
80 this.info = info;
81 this.sharpenLevel = PROP_SHARPEN_LEVEL.get();
82 if (OffsetServer.PROP_SERVER_ENABLED.get()) {
83 offsetServerThread = createoffsetServerThread();
84 offsetServerThread.start();
85 }
86 }
87
88 public double getPPD(){
89 if (Main.map == null || Main.map.mapView == null) return Main.getProjection().getDefaultZoomInPPD();
90 ProjectionBounds bounds = Main.map.mapView.getProjectionBounds();
91 return Main.map.mapView.getWidth() / (bounds.maxEast - bounds.minEast);
92 }
93
94 public double getDx() {
95 return dx;
96 }
97
98 public double getDy() {
99 return dy;
100 }
101
102 public void setOffset(double dx, double dy) {
103 this.dx = dx;
104 this.dy = dy;
105 }
106
107 public void displace(double dx, double dy) {
108 setOffset(this.dx += dx, this.dy += dy);
109 }
110
111 public ImageryInfo getInfo() {
112 return info;
113 }
114
115 @Override
116 public Icon getIcon() {
117 return icon;
118 }
119
120 @Override
121 public boolean isMergable(Layer other) {
122 return false;
123 }
124
125 @Override
126 public void mergeFrom(Layer from) {
127 }
128
129 @Override
130 public Object getInfoComponent() {
131 return getToolTipText();
132 }
133
134 public static ImageryLayer create(ImageryInfo info) {
135 if (info.getImageryType() == ImageryType.WMS || info.getImageryType() == ImageryType.HTML)
136 return new WMSLayer(info);
137 else if (info.getImageryType() == ImageryType.TMS || info.getImageryType() == ImageryType.BING || info.getImageryType() == ImageryType.SCANEX)
138 return new TMSLayer(info);
139 else throw new AssertionError();
140 }
141
142 class ApplyOffsetAction extends AbstractAction {
143 private OffsetBookmark b;
144 ApplyOffsetAction(OffsetBookmark b) {
145 super(b.name);
146 this.b = b;
147 }
148
149 @Override
150 public void actionPerformed(ActionEvent ev) {
151 setOffset(b.dx, b.dy);
152 enableOffsetServer(false);
153 Main.main.menu.imageryMenu.refreshOffsetMenu();
154 Main.map.repaint();
155 }
156 }
157
158 public class OffsetAction extends AbstractAction implements LayerAction {
159 @Override
160 public void actionPerformed(ActionEvent e) {
161 }
162
163 @Override
164 public Component createMenuComponent() {
165 return getOffsetMenuItem();
166 }
167
168 @Override
169 public boolean supportLayers(List<Layer> layers) {
170 return false;
171 }
172 }
173
174 ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
175 AbstractAction useServerOffsetAction = new AbstractAction(tr("(use server offset)")) {
176 @Override
177 public void actionPerformed(ActionEvent e) {
178 enableOffsetServer(true);
179 }
180 };
181
182 public void enableOffsetServer(boolean enable) {
183 offsetServerUsed = enable;
184 if (offsetServerUsed && !offsetServerThread.isAlive()) {
185 offsetServerThread = createoffsetServerThread();
186 offsetServerThread.start();
187 }
188 }
189
190 public JMenuItem getOffsetMenuItem() {
191 JMenu subMenu = new JMenu(trc("layer", "Offset"));
192 subMenu.setIcon(ImageProvider.get("mapmode", "adjustimg"));
193 return (JMenuItem)getOffsetMenuItem(subMenu);
194 }
195
196 public JComponent getOffsetMenuItem(JComponent subMenu) {
197 JMenuItem adjustMenuItem = new JMenuItem(adjustAction);
198 if (OffsetBookmark.allBookmarks.isEmpty() && !offsetServerSupported) return adjustMenuItem;
199
200 subMenu.add(adjustMenuItem);
201 if (offsetServerSupported) {
202 JCheckBoxMenuItem item = new JCheckBoxMenuItem(useServerOffsetAction);
203 if (offsetServerUsed) {
204 item.setSelected(true);
205 }
206 subMenu.add(item);
207 }
208 subMenu.add(new JSeparator());
209 boolean hasBookmarks = false;
210 int menuItemHeight = 0;
211 for (OffsetBookmark b : OffsetBookmark.allBookmarks) {
212 if (!b.isUsable(this)) {
213 continue;
214 }
215 JCheckBoxMenuItem item = new JCheckBoxMenuItem(new ApplyOffsetAction(b));
216 if (b.dx == dx && b.dy == dy && !offsetServerUsed) {
217 item.setSelected(true);
218 }
219 subMenu.add(item);
220 menuItemHeight = item.getPreferredSize().height;
221 hasBookmarks = true;
222 }
223 if (menuItemHeight > 0) {
224 int scrollcount = (Toolkit.getDefaultToolkit().getScreenSize().height / menuItemHeight) - 1;
225 if (subMenu instanceof JMenu) {
226 MenuScroller.setScrollerFor((JMenu) subMenu, scrollcount);
227 } else if (subMenu instanceof JPopupMenu) {
228 MenuScroller.setScrollerFor((JPopupMenu)subMenu, scrollcount);
229 }
230 }
231 return (hasBookmarks || offsetServerSupported) ? subMenu : adjustMenuItem;
232 }
233
234 public BufferedImage sharpenImage(BufferedImage img) {
235 if (sharpenLevel <= 0) return img;
236 int width = img.getWidth(null);
237 int height = img.getHeight(null);
238 BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
239 tmp.getGraphics().drawImage(img, 0, 0, null);
240 Kernel kernel;
241 if (sharpenLevel == 1) {
242 kernel = new Kernel(3, 3, new float[] { -0.25f, -0.5f, -0.25f, -0.5f, 4, -0.5f, -0.25f, -0.5f, -0.25f});
243 } else {
244 kernel = new Kernel(3, 3, new float[] { -0.5f, -1, -0.5f, -1, 7, -1, -0.5f, -1, -0.5f});
245 }
246 BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
247 return op.filter(tmp, null);
248 }
249
250 public void drawErrorTile(BufferedImage img) {
251 Graphics g = img.getGraphics();
252 g.setColor(Color.RED);
253 g.fillRect(0, 0, img.getWidth(), img.getHeight());
254 g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
255 g.setColor(Color.BLACK);
256
257 String text = tr("ERROR");
258 g.drawString(text, (img.getWidth() + g.getFontMetrics().stringWidth(text)) / 2, img.getHeight()/2);
259 }
260
261 protected class OffsetServerThread extends Thread {
262 OffsetServer offsetServer;
263 EastNorth oldCenter = new EastNorth(Double.NaN, Double.NaN);
264
265 public OffsetServerThread(OffsetServer offsetServer) {
266 this.offsetServer = offsetServer;
267 setDaemon(true);
268 }
269
270 private void updateOffset() {
271 if (Main.map == null || Main.map.mapView == null) return;
272 EastNorth center = Main.map.mapView.getCenter();
273 if (center.equals(oldCenter)) return;
274 oldCenter = center;
275
276 EastNorth offset = offsetServer.getOffset(getInfo(), center);
277 if (offset != null) {
278 setOffset(offset.east(),offset.north());
279 }
280 }
281
282 @Override
283 public void run() {
284 if (!offsetServerSupported) {
285 if (!offsetServer.isLayerSupported(info)) return;
286 offsetServerSupported = true;
287 }
288 offsetServerUsed = true;
289 SwingUtilities.invokeLater(new Runnable() {
290 @Override
291 public void run() {
292 Main.main.menu.imageryMenu.refreshOffsetMenu();
293 }
294 });
295 try {
296 while (offsetServerUsed) {
297 updateOffset();
298 Thread.sleep(1000);
299 }
300 } catch (InterruptedException e) {
301 }
302 offsetServerUsed = false;
303 }
304 }
305}
Note: See TracBrowser for help on using the repository browser.