source: josm/trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java@ 3826

Last change on this file since 3826 was 3826, checked in by framm, 13 years ago

Add a "blacklisted" property to imagery layers; set this property from a
compiled-in list of regular expressions; disable blacklisted entries in
the Imagery menu.

  • Property svn:eol-style set to native
File size: 29.7 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;
5
6import java.awt.Component;
7import java.awt.Graphics;
8import java.awt.Graphics2D;
9import java.awt.event.ActionEvent;
10import java.awt.image.BufferedImage;
11import java.io.File;
12import java.io.FileInputStream;
13import java.io.FileOutputStream;
14import java.io.ObjectInputStream;
15import java.io.ObjectOutputStream;
16import java.util.ArrayList;
17import java.util.Collections;
18import java.util.Iterator;
19import java.util.List;
20import java.util.concurrent.locks.Condition;
21import java.util.concurrent.locks.Lock;
22import java.util.concurrent.locks.ReentrantLock;
23
24import javax.swing.AbstractAction;
25import javax.swing.Action;
26import javax.swing.JCheckBoxMenuItem;
27import javax.swing.JFileChooser;
28import javax.swing.JOptionPane;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.actions.DiskAccessAction;
32import org.openstreetmap.josm.actions.SaveActionBase;
33import org.openstreetmap.josm.data.Bounds;
34import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
35import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
36import org.openstreetmap.josm.data.ProjectionBounds;
37import org.openstreetmap.josm.data.coor.EastNorth;
38import org.openstreetmap.josm.data.imagery.GeorefImage;
39import org.openstreetmap.josm.data.imagery.GeorefImage.State;
40import org.openstreetmap.josm.data.imagery.ImageryInfo;
41import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
42import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
43import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
44import org.openstreetmap.josm.data.preferences.BooleanProperty;
45import org.openstreetmap.josm.data.preferences.IntegerProperty;
46import org.openstreetmap.josm.gui.MapView;
47import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
48import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
49import org.openstreetmap.josm.io.CacheFiles;
50import org.openstreetmap.josm.io.imagery.Grabber;
51import org.openstreetmap.josm.io.imagery.HTMLGrabber;
52import org.openstreetmap.josm.io.imagery.WMSGrabber;
53import org.openstreetmap.josm.io.imagery.WMSRequest;
54import org.openstreetmap.josm.tools.ImageProvider;
55
56/**
57 * This is a layer that grabs the current screen from an WMS server. The data
58 * fetched this way is tiled and managed to the disc to reduce server load.
59 */
60public class WMSLayer extends ImageryLayer implements PreferenceChangedListener {
61 public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("imagery.wms.alpha_channel", true);
62 public static final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("imagery.wms.simultaneousConnections", 3);
63 public static final BooleanProperty PROP_OVERLAP = new BooleanProperty("imagery.wms.overlap", false);
64 public static final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("imagery.wms.overlapEast", 14);
65 public static final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("imagery.wms.overlapNorth", 4);
66
67 public int messageNum = 5; //limit for messages per layer
68 protected String resolution;
69 protected int imageSize = 500;
70 protected int dax = 10;
71 protected int day = 10;
72 protected int daStep = 5;
73 protected int minZoom = 3;
74
75 protected GeorefImage[][] images;
76 protected final int serializeFormatVersion = 5;
77 protected boolean autoDownloadEnabled = true;
78 protected boolean settingsChanged;
79 protected ImageryInfo info;
80 protected final MapView mv;
81
82 // Image index boundary for current view
83 private volatile int bminx;
84 private volatile int bminy;
85 private volatile int bmaxx;
86 private volatile int bmaxy;
87 private volatile int leftEdge;
88 private volatile int bottomEdge;
89
90 // Request queue
91 private final List<WMSRequest> requestQueue = new ArrayList<WMSRequest>();
92 private final List<WMSRequest> finishedRequests = new ArrayList<WMSRequest>();
93 /**
94 * List of request currently being processed by download threads
95 */
96 private final List<WMSRequest> processingRequests = new ArrayList<WMSRequest>();
97 private final Lock requestQueueLock = new ReentrantLock();
98 private final Condition queueEmpty = requestQueueLock.newCondition();
99 private final List<Grabber> grabbers = new ArrayList<Grabber>();
100 private final List<Thread> grabberThreads = new ArrayList<Thread>();
101 private int threadCount;
102 private int workingThreadCount;
103 private boolean canceled;
104
105
106 /** set to true if this layer uses an invalid base url */
107 private boolean usesInvalidUrl = false;
108 /** set to true if the user confirmed to use an potentially invalid WMS base url */
109 private boolean isInvalidUrlConfirmed = false;
110
111 public WMSLayer() {
112 this(new ImageryInfo(tr("Blank Layer")));
113 }
114
115 public WMSLayer(ImageryInfo info) {
116 super(info);
117 mv = Main.map.mapView;
118 setBackgroundLayer(true); /* set global background variable */
119 initializeImages();
120 this.info = new ImageryInfo(info);
121 if(this.info.getPixelPerDegree() == 0.0) {
122 this.info.setPixelPerDegree(getPPD());
123 }
124 resolution = mv.getDist100PixelText();
125
126 if(info.getUrl() != null) {
127 WMSGrabber.getProjection(info.getUrl(), true);
128 startGrabberThreads();
129 if(info.getImageryType() == ImageryType.WMS && !ImageryInfo.isUrlWithPatterns(info.getUrl())) {
130 if (!(info.getUrl().endsWith("&") || info.getUrl().endsWith("?"))) {
131 if (!confirmMalformedUrl(info.getUrl())) {
132 System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", info.getUrl()));
133 usesInvalidUrl = true;
134 setName(getName() + tr("(deactivated)"));
135 return;
136 } else {
137 isInvalidUrlConfirmed = true;
138 }
139 }
140 }
141 }
142
143 Main.pref.addPreferenceChangeListener(this);
144 }
145
146 public void doSetName(String name) {
147 setName(name);
148 info.setName(name);
149 }
150
151 public boolean hasAutoDownload(){
152 return autoDownloadEnabled;
153 }
154
155 @Override
156 public void destroy() {
157 cancelGrabberThreads(false);
158 Main.pref.removePreferenceChangeListener(this);
159 }
160
161 public void initializeImages() {
162 GeorefImage[][] old = images;
163 images = new GeorefImage[dax][day];
164 if (old != null) {
165 for (int i=0; i<old.length; i++) {
166 for (int k=0; k<old[i].length; k++) {
167 GeorefImage o = old[i][k];
168 images[modulo(o.getXIndex(),dax)][modulo(o.getYIndex(),day)] = old[i][k];
169 }
170 }
171 }
172 for(int x = 0; x<dax; ++x) {
173 for(int y = 0; y<day; ++y) {
174 if (images[x][y] == null) {
175 images[x][y]= new GeorefImage(this);
176 }
177 }
178 }
179 }
180
181 @Override public ImageryInfo getInfo() {
182 return info;
183 }
184
185 @Override public String getToolTipText() {
186 if(autoDownloadEnabled)
187 return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
188 else
189 return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
190 }
191
192 private int modulo (int a, int b) {
193 return a % b >= 0 ? a%b : a%b+b;
194 }
195
196 private boolean zoomIsTooBig() {
197 //don't download when it's too outzoomed
198 return info.getPixelPerDegree() / getPPD() > minZoom;
199 }
200
201 @Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
202 if(info.getUrl() == null || (usesInvalidUrl && !isInvalidUrlConfirmed)) return;
203
204 settingsChanged = false;
205
206 ProjectionBounds bounds = mv.getProjectionBounds();
207 bminx= getImageXIndex(bounds.min.east());
208 bminy= getImageYIndex(bounds.min.north());
209 bmaxx= getImageXIndex(bounds.max.east());
210 bmaxy= getImageYIndex(bounds.max.north());
211
212 leftEdge = (int)(bounds.min.east() * getPPD());
213 bottomEdge = (int)(bounds.min.north() * getPPD());
214
215 if (zoomIsTooBig()) {
216 for(int x = bminx; x<=bmaxx; ++x) {
217 for(int y = bminy; y<=bmaxy; ++y) {
218 images[modulo(x,dax)][modulo(y,day)].paint(g, mv, x, y, leftEdge, bottomEdge);
219 }
220 }
221 } else {
222 downloadAndPaintVisible(g, mv, false);
223 }
224 }
225
226 protected boolean confirmMalformedUrl(String url) {
227 if (isInvalidUrlConfirmed)
228 return true;
229 String msg = tr("<html>The base URL<br>"
230 + "''{0}''<br>"
231 + "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
232 + "This is likely to lead to invalid WMS request. You should check your<br>"
233 + "preference settings.<br>"
234 + "Do you want to fetch WMS tiles anyway?",
235 url);
236 String [] options = new String[] {
237 tr("Yes, fetch images"),
238 tr("No, abort")
239 };
240 int ret = JOptionPane.showOptionDialog(
241 Main.parent,
242 msg,
243 tr("Invalid URL?"),
244 JOptionPane.YES_NO_OPTION,
245 JOptionPane.WARNING_MESSAGE,
246 null,
247 options, options[1]
248 );
249 switch(ret) {
250 case JOptionPane.YES_OPTION: return true;
251 default: return false;
252 }
253 }
254
255 @Override
256 public void setOffset(double dx, double dy) {
257 super.setOffset(dx, dy);
258 settingsChanged = true;
259 }
260
261 public int getImageXIndex(double coord) {
262 return (int)Math.floor( ((coord - dx) * info.getPixelPerDegree()) / imageSize);
263 }
264
265 public int getImageYIndex(double coord) {
266 return (int)Math.floor( ((coord - dy) * info.getPixelPerDegree()) / imageSize);
267 }
268
269 public int getImageX(int imageIndex) {
270 return (int)(imageIndex * imageSize * (getPPD() / info.getPixelPerDegree()) + dx * getPPD());
271 }
272
273 public int getImageY(int imageIndex) {
274 return (int)(imageIndex * imageSize * (getPPD() / info.getPixelPerDegree()) + dy * getPPD());
275 }
276
277 public int getImageWidth(int xIndex) {
278 return getImageX(xIndex + 1) - getImageX(xIndex);
279 }
280
281 public int getImageHeight(int yIndex) {
282 return getImageY(yIndex + 1) - getImageY(yIndex);
283 }
284
285 /**
286 *
287 * @return Size of image in original zoom
288 */
289 public int getBaseImageWidth() {
290 int overlap = (PROP_OVERLAP.get()?PROP_OVERLAP_EAST.get() * imageSize / 100:0);
291 return imageSize + overlap;
292 }
293
294 /**
295 *
296 * @return Size of image in original zoom
297 */
298 public int getBaseImageHeight() {
299 int overlap = (PROP_OVERLAP.get()?PROP_OVERLAP_NORTH.get() * imageSize / 100:0);
300 return imageSize + overlap;
301 }
302
303 public int getImageSize() {
304 return imageSize;
305 }
306
307 /**
308 *
309 * @return When overlapping is enabled, return visible part of tile. Otherwise return original image
310 */
311 public BufferedImage normalizeImage(BufferedImage img) {
312 if (WMSLayer.PROP_OVERLAP.get() && (WMSLayer.PROP_OVERLAP_EAST.get() > 0 || WMSLayer.PROP_OVERLAP_NORTH.get() > 0)) {
313 BufferedImage copy = img;
314 img = new BufferedImage(imageSize, imageSize, copy.getType());
315 img.createGraphics().drawImage(copy, 0, 0, imageSize, imageSize,
316 0, copy.getHeight() - imageSize, imageSize, copy.getHeight(), null);
317 }
318 return img;
319 }
320
321
322 /**
323 *
324 * @param xIndex
325 * @param yIndex
326 * @return Real EastNorth of given tile. dx/dy is not counted in
327 */
328 public EastNorth getEastNorth(int xIndex, int yIndex) {
329 return new EastNorth((xIndex * imageSize) / info.getPixelPerDegree(), (yIndex * imageSize) / info.getPixelPerDegree());
330 }
331
332
333 protected void downloadAndPaintVisible(Graphics g, final MapView mv, boolean real){
334
335 int newDax = dax;
336 int newDay = day;
337
338 if (bmaxx - bminx >= dax || bmaxx - bminx < dax - 2 * daStep) {
339 newDax = ((bmaxx - bminx) / daStep + 1) * daStep;
340 }
341
342 if (bmaxy - bminy >= day || bmaxy - bminx < day - 2 * daStep) {
343 newDay = ((bmaxy - bminy) / daStep + 1) * daStep;
344 }
345
346 if (newDax != dax || newDay != day) {
347 dax = newDax;
348 day = newDay;
349 initializeImages();
350 }
351
352 for(int x = bminx; x<=bmaxx; ++x) {
353 for(int y = bminy; y<=bmaxy; ++y){
354 images[modulo(x,dax)][modulo(y,day)].changePosition(x, y);
355 }
356 }
357
358 gatherFinishedRequests();
359
360 for(int x = bminx; x<=bmaxx; ++x) {
361 for(int y = bminy; y<=bmaxy; ++y){
362 GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
363 if (!img.paint(g, mv, x, y, leftEdge, bottomEdge)) {
364 WMSRequest request = new WMSRequest(x, y, info.getPixelPerDegree(), real);
365 addRequest(request);
366 }
367 }
368 }
369 }
370
371 @Override public void visitBoundingBox(BoundingXYVisitor v) {
372 for(int x = 0; x<dax; ++x) {
373 for(int y = 0; y<day; ++y)
374 if(images[x][y].getImage() != null){
375 v.visit(images[x][y].getMin());
376 v.visit(images[x][y].getMax());
377 }
378 }
379 }
380
381 @Override public Action[] getMenuEntries() {
382 return new Action[]{
383 LayerListDialog.getInstance().createActivateLayerAction(this),
384 LayerListDialog.getInstance().createShowHideLayerAction(),
385 LayerListDialog.getInstance().createDeleteLayerAction(),
386 SeparatorLayerAction.INSTANCE,
387 new OffsetAction(),
388 new LoadWmsAction(),
389 new SaveWmsAction(),
390 new BookmarkWmsAction(),
391 SeparatorLayerAction.INSTANCE,
392 new StartStopAction(),
393 new ToggleAlphaAction(),
394 new ChangeResolutionAction(),
395 new ReloadErrorTilesAction(),
396 new DownloadAction(),
397 SeparatorLayerAction.INSTANCE,
398 new LayerListPopup.InfoAction(this)
399 };
400 }
401
402 public GeorefImage findImage(EastNorth eastNorth) {
403 int xIndex = getImageXIndex(eastNorth.east());
404 int yIndex = getImageYIndex(eastNorth.north());
405 GeorefImage result = images[modulo(xIndex, dax)][modulo(yIndex, day)];
406 if (result.getXIndex() == xIndex && result.getYIndex() == yIndex)
407 return result;
408 else
409 return null;
410 }
411
412 /**
413 *
414 * @param request
415 * @return -1 if request is no longer needed, otherwise priority of request (lower number <=> more important request)
416 */
417 private int getRequestPriority(WMSRequest request) {
418 if (request.getPixelPerDegree() != info.getPixelPerDegree())
419 return -1;
420 if (bminx > request.getXIndex()
421 || bmaxx < request.getXIndex()
422 || bminy > request.getYIndex()
423 || bmaxy < request.getYIndex())
424 return -1;
425
426 EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
427 int mouseX = getImageXIndex(cursorEastNorth.east());
428 int mouseY = getImageYIndex(cursorEastNorth.north());
429 int dx = request.getXIndex() - mouseX;
430 int dy = request.getYIndex() - mouseY;
431
432 return dx * dx + dy * dy;
433 }
434
435 public WMSRequest getRequest() {
436 requestQueueLock.lock();
437 try {
438 workingThreadCount--;
439 Iterator<WMSRequest> it = requestQueue.iterator();
440 while (it.hasNext()) {
441 WMSRequest item = it.next();
442 int priority = getRequestPriority(item);
443 if (priority == -1 || finishedRequests.contains(item) || processingRequests.contains(item)) {
444 it.remove();
445 } else {
446 item.setPriority(priority);
447 }
448 }
449 Collections.sort(requestQueue);
450
451 EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
452 int mouseX = getImageXIndex(cursorEastNorth.east());
453 int mouseY = getImageYIndex(cursorEastNorth.north());
454 boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY;
455
456 // If there is only one thread left then keep it in case we need to download other tile urgently
457 while (!canceled &&
458 (requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) {
459 try {
460 queueEmpty.await();
461 } catch (InterruptedException e) {
462 // Shouldn't happen
463 }
464 }
465
466 workingThreadCount++;
467 if (canceled)
468 return null;
469 else {
470 WMSRequest request = requestQueue.remove(0);
471 processingRequests.add(request);
472 return request;
473 }
474
475 } finally {
476 requestQueueLock.unlock();
477 }
478 }
479
480 public void finishRequest(WMSRequest request) {
481 requestQueueLock.lock();
482 try {
483 processingRequests.remove(request);
484 if (request.getState() != null) {
485 finishedRequests.add(request);
486 mv.repaint();
487 }
488 } finally {
489 requestQueueLock.unlock();
490 }
491 }
492
493 public void addRequest(WMSRequest request) {
494 requestQueueLock.lock();
495 try {
496 if (!requestQueue.contains(request) && !finishedRequests.contains(request) && !processingRequests.contains(request)) {
497 requestQueue.add(request);
498 queueEmpty.signalAll();
499 }
500 } finally {
501 requestQueueLock.unlock();
502 }
503 }
504
505 public boolean requestIsValid(WMSRequest request) {
506 return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex();
507 }
508
509 private void gatherFinishedRequests() {
510 requestQueueLock.lock();
511 try {
512 for (WMSRequest request: finishedRequests) {
513 GeorefImage img = images[modulo(request.getXIndex(),dax)][modulo(request.getYIndex(),day)];
514 if (img.equalPosition(request.getXIndex(), request.getYIndex())) {
515 img.changeImage(request.getState(), request.getImage());
516 }
517 }
518 } finally {
519 requestQueueLock.unlock();
520 finishedRequests.clear();
521 }
522 }
523
524 public class DownloadAction extends AbstractAction {
525 private static final long serialVersionUID = -7183852461015284020L;
526 public DownloadAction() {
527 super(tr("Download visible tiles"));
528 }
529 @Override
530 public void actionPerformed(ActionEvent ev) {
531 if (zoomIsTooBig()) {
532 JOptionPane.showMessageDialog(
533 Main.parent,
534 tr("The requested area is too big. Please zoom in a little, or change resolution"),
535 tr("Error"),
536 JOptionPane.ERROR_MESSAGE
537 );
538 } else {
539 downloadAndPaintVisible(mv.getGraphics(), mv, true);
540 }
541 }
542 }
543
544 public class ChangeResolutionAction extends AbstractAction {
545 public ChangeResolutionAction() {
546 super(tr("Change resolution"));
547 }
548 @Override
549 public void actionPerformed(ActionEvent ev) {
550 initializeImages();
551 resolution = mv.getDist100PixelText();
552 info.setPixelPerDegree(getPPD());
553 settingsChanged = true;
554 mv.repaint();
555 }
556 }
557
558 public class ReloadErrorTilesAction extends AbstractAction {
559 public ReloadErrorTilesAction() {
560 super(tr("Reload erroneous tiles"));
561 }
562 @Override
563 public void actionPerformed(ActionEvent ev) {
564 // Delete small files, because they're probably blank tiles.
565 // See https://josm.openstreetmap.de/ticket/2307
566 Grabber.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
567
568 for (int x = 0; x < dax; ++x) {
569 for (int y = 0; y < day; ++y) {
570 GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
571 if(img.getState() == State.FAILED){
572 addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), info.getPixelPerDegree(), true));
573 mv.repaint();
574 }
575 }
576 }
577 }
578 }
579
580 public class ToggleAlphaAction extends AbstractAction implements LayerAction {
581 public ToggleAlphaAction() {
582 super(tr("Alpha channel"));
583 }
584 @Override
585 public void actionPerformed(ActionEvent ev) {
586 JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
587 boolean alphaChannel = checkbox.isSelected();
588 PROP_ALPHA_CHANNEL.put(alphaChannel);
589
590 // clear all resized cached instances and repaint the layer
591 for (int x = 0; x < dax; ++x) {
592 for (int y = 0; y < day; ++y) {
593 GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
594 img.flushedResizedCachedInstance();
595 }
596 }
597 mv.repaint();
598 }
599 @Override
600 public Component createMenuComponent() {
601 JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
602 item.setSelected(PROP_ALPHA_CHANNEL.get());
603 return item;
604 }
605 @Override
606 public boolean supportLayers(List<Layer> layers) {
607 return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
608 }
609 }
610
611 public class SaveWmsAction extends AbstractAction {
612 public SaveWmsAction() {
613 super(tr("Save WMS layer to file"), ImageProvider.get("save"));
614 }
615 @Override
616 public void actionPerformed(ActionEvent ev) {
617 File f = SaveActionBase.createAndOpenSaveFileChooser(
618 tr("Save WMS layer"), ".wms");
619 try {
620 if (f != null) {
621 ObjectOutputStream oos = new ObjectOutputStream(
622 new FileOutputStream(f)
623 );
624 oos.writeInt(serializeFormatVersion);
625 oos.writeInt(dax);
626 oos.writeInt(day);
627 oos.writeInt(imageSize);
628 oos.writeDouble(info.getPixelPerDegree());
629 oos.writeObject(info.getName());
630 oos.writeObject(info.getFullUrl());
631 oos.writeObject(images);
632 oos.close();
633 }
634 } catch (Exception ex) {
635 ex.printStackTrace(System.out);
636 }
637 }
638 }
639
640 public class LoadWmsAction extends AbstractAction {
641 public LoadWmsAction() {
642 super(tr("Load WMS layer from file"), ImageProvider.get("open"));
643 }
644 @Override
645 public void actionPerformed(ActionEvent ev) {
646 JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
647 false, tr("Load WMS layer"), "wms");
648 if(fc == null) return;
649 File f = fc.getSelectedFile();
650 if (f == null) return;
651 try
652 {
653 FileInputStream fis = new FileInputStream(f);
654 ObjectInputStream ois = new ObjectInputStream(fis);
655 int sfv = ois.readInt();
656 if (sfv != serializeFormatVersion) {
657 JOptionPane.showMessageDialog(Main.parent,
658 tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
659 tr("File Format Error"),
660 JOptionPane.ERROR_MESSAGE);
661 return;
662 }
663 autoDownloadEnabled = false;
664 dax = ois.readInt();
665 day = ois.readInt();
666 imageSize = ois.readInt();
667 info.setPixelPerDegree(ois.readDouble());
668 doSetName((String)ois.readObject());
669 info.setUrl((String) ois.readObject());
670 images = (GeorefImage[][])ois.readObject();
671 ois.close();
672 fis.close();
673 for (GeorefImage[] imgs : images) {
674 for (GeorefImage img : imgs) {
675 if (img != null) {
676 img.setLayer(WMSLayer.this);
677 }
678 }
679 }
680 settingsChanged = true;
681 mv.repaint();
682 if(info.getUrl() != null)
683 {
684 startGrabberThreads();
685 }
686 }
687 catch (Exception ex) {
688 // FIXME be more specific
689 ex.printStackTrace(System.out);
690 JOptionPane.showMessageDialog(Main.parent,
691 tr("Error loading file"),
692 tr("Error"),
693 JOptionPane.ERROR_MESSAGE);
694 return;
695 }
696 }
697 }
698 /**
699 * This action will add a WMS layer menu entry with the current WMS layer
700 * URL and name extended by the current resolution.
701 * When using the menu entry again, the WMS cache will be used properly.
702 */
703 public class BookmarkWmsAction extends AbstractAction {
704 public BookmarkWmsAction() {
705 super(tr("Set WMS Bookmark"));
706 }
707 @Override
708 public void actionPerformed(ActionEvent ev) {
709 ImageryLayerInfo.addLayer(new ImageryInfo(info));
710 }
711 }
712
713 private class StartStopAction extends AbstractAction implements LayerAction {
714
715 public StartStopAction() {
716 super(tr("Automatic downloading"));
717 }
718
719 @Override
720 public Component createMenuComponent() {
721 JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
722 item.setSelected(autoDownloadEnabled);
723 return item;
724 }
725
726 @Override
727 public boolean supportLayers(List<Layer> layers) {
728 return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
729 }
730
731 @Override
732 public void actionPerformed(ActionEvent e) {
733 autoDownloadEnabled = !autoDownloadEnabled;
734 if (autoDownloadEnabled) {
735 for (int x = 0; x < dax; ++x) {
736 for (int y = 0; y < day; ++y) {
737 GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
738 if(img.getState() == State.NOT_IN_CACHE){
739 addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), info.getPixelPerDegree(), false));
740 }
741 }
742 }
743 mv.repaint();
744 }
745 }
746 }
747
748 private void cancelGrabberThreads(boolean wait) {
749 requestQueueLock.lock();
750 try {
751 canceled = true;
752 for (Grabber grabber: grabbers) {
753 grabber.cancel();
754 }
755 queueEmpty.signalAll();
756 } finally {
757 requestQueueLock.unlock();
758 }
759 if (wait) {
760 for (Thread t: grabberThreads) {
761 try {
762 t.join();
763 } catch (InterruptedException e) {
764 // Shouldn't happen
765 e.printStackTrace();
766 }
767 }
768 }
769 }
770
771 private void startGrabberThreads() {
772 int threadCount = PROP_SIMULTANEOUS_CONNECTIONS.get();
773 requestQueueLock.lock();
774 try {
775 canceled = false;
776 grabbers.clear();
777 grabberThreads.clear();
778 for (int i=0; i<threadCount; i++) {
779 Grabber grabber = getGrabber();
780 grabbers.add(grabber);
781 Thread t = new Thread(grabber, "WMS " + getName() + " " + i);
782 t.setDaemon(true);
783 t.start();
784 grabberThreads.add(t);
785 }
786 this.workingThreadCount = grabbers.size();
787 this.threadCount = grabbers.size();
788 } finally {
789 requestQueueLock.unlock();
790 }
791 }
792
793 @Override
794 public boolean isChanged() {
795 requestQueueLock.lock();
796 try {
797 return !finishedRequests.isEmpty() || settingsChanged;
798 } finally {
799 requestQueueLock.unlock();
800 }
801 }
802
803 @Override
804 public void preferenceChanged(PreferenceChangeEvent event) {
805 if (event.getKey().equals(PROP_SIMULTANEOUS_CONNECTIONS.getKey())) {
806 cancelGrabberThreads(true);
807 startGrabberThreads();
808 } else if (
809 event.getKey().equals(PROP_OVERLAP.getKey())
810 || event.getKey().equals(PROP_OVERLAP_EAST.getKey())
811 || event.getKey().equals(PROP_OVERLAP_NORTH.getKey())) {
812 for (int i=0; i<images.length; i++) {
813 for (int k=0; k<images[i].length; k++) {
814 images[i][k] = new GeorefImage(this);
815 }
816 }
817
818 settingsChanged = true;
819 }
820 }
821
822 protected Grabber getGrabber(){
823 if(getInfo().getImageryType() == ImageryType.HTML)
824 return new HTMLGrabber(mv, this);
825 else if(getInfo().getImageryType() == ImageryType.WMS)
826 return new WMSGrabber(mv, this);
827 else throw new IllegalStateException("getGrabber() called for non-WMS layer type");
828 }
829
830}
Note: See TracBrowser for help on using the repository browser.