001: /*
002: * uDig - User Friendly Desktop Internet GIS client http://udig.refractions.net (C) 2004,
003: * Refractions Research Inc. This library is free software; you can redistribute it and/or modify it
004: * under the terms of the GNU Lesser General Public License as published by the Free Software
005: * Foundation; version 2.1 of the License. This library is distributed in the hope that it will be
006: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
007: * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
008: */
009: package net.refractions.udig.catalog.internal.wms;
010:
011: import java.io.IOException;
012: import java.io.InputStream;
013: import java.net.MalformedURLException;
014: import java.net.URI;
015: import java.net.URL;
016: import java.util.ArrayList;
017: import java.util.Arrays;
018: import java.util.List;
019:
020: import net.refractions.udig.catalog.IGeoResource;
021: import net.refractions.udig.catalog.IGeoResourceInfo;
022: import net.refractions.udig.catalog.IService;
023: import net.refractions.udig.catalog.ui.CatalogUIPlugin;
024: import net.refractions.udig.catalog.ui.ISharedImages;
025: import net.refractions.udig.catalog.wms.internal.Messages;
026:
027: import org.eclipse.core.runtime.IProgressMonitor;
028: import org.eclipse.jface.resource.ImageDescriptor;
029: import org.eclipse.swt.SWT;
030: import org.eclipse.swt.SWTException;
031: import org.eclipse.swt.graphics.GC;
032: import org.eclipse.swt.graphics.Image;
033: import org.eclipse.swt.graphics.ImageData;
034: import org.eclipse.swt.graphics.Rectangle;
035: import org.geotools.data.ows.WMSCapabilities;
036: import org.geotools.data.wms.WebMapServer;
037: import org.geotools.data.wms.request.GetLegendGraphicRequest;
038: import org.geotools.data.wms.response.GetLegendGraphicResponse;
039: import org.geotools.data.wms.xml.WMSSchema;
040: import org.geotools.geometry.jts.ReferencedEnvelope;
041: import org.geotools.ows.ServiceException;
042: import org.geotools.referencing.CRS;
043: import org.opengis.referencing.NoSuchAuthorityCodeException;
044: import org.opengis.referencing.crs.CoordinateReferenceSystem;
045:
046: import com.vividsolutions.jts.geom.Envelope;
047:
048: /**
049: * FeatureType provided by WFS.
050: * </p>
051: *
052: * @author David Zwiers, Refractions Research
053: * @since 0.6
054: */
055: public class WMSGeoResourceImpl extends IGeoResource {
056:
057: WMSServiceImpl parent;
058: org.geotools.data.ows.Layer layer;
059: private IGeoResourceInfo info;
060: private ImageDescriptor icon;
061: private URL identifier;
062:
063: private WMSGeoResourceImpl() {
064: // should not be used
065: }
066:
067: /**
068: * Construct <code>WMSGeoResourceImpl</code>.
069: *
070: * @param parent
071: * @param layer
072: */
073: public WMSGeoResourceImpl(WMSServiceImpl parent,
074: org.geotools.data.ows.Layer layer) {
075: this .parent = parent;
076: this .layer = layer;
077: try {
078: identifier = new URL(parent.getIdentifier().toString()
079: + "#" + layer.getName()); //$NON-NLS-1$
080:
081: } catch (Throwable e) {
082: WmsPlugin.log(null, e);
083: identifier = parent.getIdentifier();
084: }
085: }
086:
087: @Override
088: public WMSServiceImpl parent(IProgressMonitor monitor)
089: throws IOException {
090: return parent;
091: }
092:
093: /*
094: * @see net.refractions.udig.catalog.IGeoResource#getStatus()
095: */
096: public Status getStatus() {
097: return parent.getStatus();
098: }
099:
100: public IGeoResourceInfo getInfo(IProgressMonitor monitor)
101: throws IOException {
102: if (info == null) {
103: parent.rLock.lock();
104: try {
105: if (info == null) {
106: info = new WMSResourceInfo(monitor);
107: }
108: } finally {
109: parent.rLock.unlock();
110: }
111: }
112: return info;
113: }
114:
115: public URL getIdentifier() {
116: return identifier;
117: }
118:
119: /*
120: * @see net.refractions.udig.catalog.IGeoResource#resolve(java.lang.Class,
121: * org.eclipse.core.runtime.IProgressMonitor)
122: */
123: public <T> T resolve(Class<T> adaptee, IProgressMonitor monitor)
124: throws IOException {
125: if (adaptee == null) {
126: throw new NullPointerException();
127: }
128:
129: // if (adaptee.isAssignableFrom(IService.class)) {
130: // return adaptee.cast( parent);
131: // }
132:
133: if (adaptee.isAssignableFrom(IGeoResource.class)) {
134: return adaptee.cast(this );
135: }
136:
137: if (adaptee.isAssignableFrom(IGeoResourceInfo.class)) {
138: return adaptee.cast(getInfo(monitor));
139: }
140:
141: if (adaptee.isAssignableFrom(WebMapServer.class)) {
142: return adaptee.cast(parent.getWMS(monitor));
143: }
144:
145: if (adaptee.isAssignableFrom(org.geotools.data.ows.Layer.class)) {
146: return adaptee.cast(layer);
147: }
148: if (adaptee.isAssignableFrom(ImageDescriptor.class)) {
149: return adaptee.cast(getIcon(monitor));
150: }
151: return super .resolve(adaptee, monitor);
152: }
153:
154: public IService service(IProgressMonitor monitor)
155: throws IOException {
156: return parent;
157: }
158:
159: /** Must be the same as resolve( ImageDescriptor.class ) */
160: public synchronized ImageDescriptor getIcon(IProgressMonitor monitor) {
161: if (icon == null) {
162: icon = fetchIcon(monitor);
163: if (icon == null) {
164: icon = CatalogUIPlugin.getDefault().getImages()
165: .getImageDescriptor(ISharedImages.GRID_OBJ);
166: }
167: }
168: return icon;
169: }
170:
171: /**
172: * This method will fetch the Icon associated with this url
173: * (if such is available).
174: *
175: * @param monitor
176: * @return Requested Icon or ISharedImages.GRID_OBJ
177: */
178: protected ImageDescriptor fetchIcon(IProgressMonitor monitor) {
179: try {
180: if (monitor != null)
181: monitor.beginTask(
182: Messages.WMSGeoResourceImpl_acquiring_task, 3);
183: if (monitor != null)
184: monitor.worked(1);
185:
186: if (layer.getChildren() != null
187: && layer.getChildren().length != 0) {
188: //Do not request "parent" layer graphics - this kills Mapserver
189: return CatalogUIPlugin.getDefault().getImages()
190: .getImageDescriptor(ISharedImages.GRID_OBJ);
191: }
192:
193: WebMapServer wms = parent.getWMS(monitor);
194:
195: if (wms.getCapabilities().getRequest()
196: .getGetLegendGraphic() == null) {
197: return CatalogUIPlugin.getDefault().getImages()
198: .getImageDescriptor(ISharedImages.GRID_OBJ);
199: }
200:
201: ImageDescriptor imageDescriptor = null;
202: try {
203: GetLegendGraphicRequest request = wms
204: .createGetLegendGraphicRequest();
205: request.setLayer(layer.getName());
206: request.setWidth("16"); //$NON-NLS-1$
207: request.setHeight("16"); //$NON-NLS-1$
208:
209: String desiredFormat = null;
210: List formats = Arrays.asList(wms.getCapabilities()
211: .getRequest().getGetLegendGraphic()
212: .getFormatStrings());
213: if (formats.contains("image/png")) { //$NON-NLS-1$
214: desiredFormat = "image/png"; //$NON-NLS-1$
215: }
216: if (desiredFormat == null
217: && formats.contains("image/gif")) { //$NON-NLS-1$
218: desiredFormat = "image/gif"; //$NON-NLS-1$
219: }
220: if (desiredFormat != null) {
221: request.setFormat(desiredFormat);
222:
223: request.setStyle(""); //$NON-NLS-1$
224:
225: System.out.println(request.getFinalURL()
226: .toExternalForm());
227:
228: GetLegendGraphicResponse response = wms
229: .issueRequest(request);
230:
231: imageDescriptor = ImageDescriptor
232: .createFromImageData(getImageData(response
233: .getInputStream()));
234: } else {
235: // cannot understand any of the provided formats
236: return CatalogUIPlugin.getDefault().getImages()
237: .getImageDescriptor(ISharedImages.GRID_OBJ);
238: }
239: } catch (UnsupportedOperationException notAvailable) {
240: WmsPlugin.trace("Icon is not available", notAvailable); //$NON-NLS-1$
241: return CatalogUIPlugin.getDefault().getImages()
242: .getImageDescriptor(ISharedImages.GRID_OBJ);
243: } catch (ServiceException e) {
244: WmsPlugin.trace("Icon is not available", e); //$NON-NLS-1$
245: return CatalogUIPlugin.getDefault().getImages()
246: .getImageDescriptor(ISharedImages.GRID_OBJ);
247: } catch (SWTException exc) {
248: WmsPlugin
249: .trace(
250: "Icon is not available or has unsupported format", exc); //$NON-NLS-1$
251: return CatalogUIPlugin.getDefault().getImages()
252: .getImageDescriptor(ISharedImages.GRID_OBJ);
253: }
254:
255: Image image = null;
256: Image swatch = null;
257: try {
258: if (monitor != null)
259: monitor.worked(2);
260: if (monitor != null)
261: monitor
262: .subTask(Messages.WMSGeoResourceImpl_downloading_icon);
263: image = imageDescriptor.createImage();
264: Rectangle bound = image.getBounds();
265: if (bound.width == 16 && bound.height == 16) {
266: final ImageData data = (ImageData) image
267: .getImageData().clone();
268: return new ImageDescriptor() {
269: public ImageData getImageData() {
270: return (ImageData) data.clone();
271: }
272: };
273: }
274: if (bound.height < 16 || bound.width < 16) {
275: if (WmsPlugin.getDefault().isDebugging())
276: System.out
277: .println("Icon scaled up to requested size"); //$NON-NLS-1$
278: final ImageData data = image.getImageData()
279: .scaledTo(16, 16);
280: return new ImageDescriptor() {
281: public ImageData getImageData() {
282: return (ImageData) data.clone();
283: }
284: };
285: }
286: swatch = new Image(null, 16, 16);
287: GC gc = new GC(swatch);
288: int sy = 0; //(bound.height / 2 ) - 8;
289: int sx = 0;
290: int sw = 0;
291: int sh = 0;
292: ImageData contents = image.getImageData();
293: if (contents == null) {
294: return CatalogUIPlugin.getDefault().getImages()
295: .getImageDescriptor(
296: ISharedImages.GRID_MISSING);
297: }
298: if (contents.maskData != null) {
299: // ((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad
300: int maskPad = contents.maskPad;
301: int scanLine = ((contents.width + 7) / 8 + (maskPad - 1))
302: / maskPad * maskPad;
303: // skip leading mask ...
304: SKIPY: for (int y = 0; y < contents.height / 2; y++) {
305: sy = y;
306: for (int x = 0; x < contents.width / 2; x++) {
307: int mask = contents.maskData[y * scanLine
308: + x];
309: if (mask != 0)
310: break SKIPY;
311: }
312: }
313: SKIPX: for (int x = 0; x < contents.width / 2; x++) {
314: sx = x;
315: for (int y = sy; y < contents.height / 2; y++) {
316: int mask = contents.maskData[y * scanLine
317: + x];
318: if (mask != 0)
319: break SKIPX;
320: }
321: }
322: sh = Math.min(contents.height - sy, 16);
323: sw = Math.min(contents.width - sx, 16);
324: if (WmsPlugin.getDefault().isDebugging())
325: System.out
326: .println("Mask offset to " + sx + "x" + sy); //$NON-NLS-1$ //$NON-NLS-2$
327: } else if (contents.alphaData != null) {
328: SKIPY: for (int y = 0; y < contents.height / 2; y++) {
329: sy = y;
330: for (int x = 0; x < contents.width / 2; x++) {
331: int alpha = contents.alphaData[y
332: * contents.width + x];
333: if (alpha != 0)
334: break SKIPY;
335: }
336: }
337: SKIPX: for (int x = 0; x < contents.width / 2; x++) {
338: sx = x;
339: for (int y = sy; y < contents.height / 2; y++) {
340: int alpha = contents.alphaData[y
341: * contents.width + x];
342: if (alpha != 0)
343: break SKIPX;
344: }
345: }
346: sh = Math.min(contents.height - sy, 16);
347: sw = Math.min(contents.width - sx, 16);
348: if (WmsPlugin.getDefault().isDebugging())
349: System.out
350: .println("Alpha offset to " + sx + "x" + sy); //$NON-NLS-1$ //$NON-NLS-2$
351: } else {
352: // try ignoring "white"
353: int depth = contents.depth;
354: int scanLine = contents.bytesPerLine;
355: SKIPY: for (int y = 0; y < contents.height / 2; y++) {
356: sy = y;
357: for (int x = 0; x < contents.width / 2; x++) {
358: int datum = contents.data[y * scanLine + x
359: * depth];
360: if (datum != 0)
361: break SKIPY;
362: }
363: }
364: SKIPX: for (int x = 0; x < contents.width / 2; x++) {
365: sx = x;
366: for (int y = sy; y < contents.height / 2; y++) {
367: int datum = contents.data[y * scanLine + x
368: * depth];
369: if (datum != 0)
370: break SKIPX;
371: }
372: }
373: sh = Math.min(contents.height - sy, 16);
374: sw = Math.min(contents.width - sx, 16);
375: if (WmsPlugin.getDefault().isDebugging())
376: System.out
377: .println("Alpha offset to " + sx + "x" + sy); //$NON-NLS-1$ //$NON-NLS-2$
378: }
379: // else {
380: // sh = Math.min( bound.height, bound.width );
381: // sw = Math.min( bound.height, bound.width );
382: // }
383: if (WmsPlugin.getDefault().isDebugging())
384: System.out
385: .println("Image resized to " + sh + "x" + sw); //$NON-NLS-1$ //$NON-NLS-2$
386:
387: gc.drawImage(image, sx, sy, sw, sh, 0, 0, 16, 16);
388: final ImageData data = (ImageData) swatch
389: .getImageData().clone();
390: return new ImageDescriptor() {
391: public ImageData getImageData() {
392: return (ImageData) data.clone();
393: }
394: };
395: //
396: } finally {
397: if (image != null) {
398: image.dispose();
399: }
400: if (swatch != null) {
401: swatch.dispose();
402: }
403: if (monitor != null)
404: monitor.worked(3);
405: }
406: } catch (IOException t) {
407: WmsPlugin.trace("Could not get icon", t); //$NON-NLS-1$
408: return CatalogUIPlugin.getDefault().getImages()
409: .getImageDescriptor(ISharedImages.GRID_MISSING);
410: }
411: }
412:
413: private ImageData getImageData(InputStream in) {
414: ImageData result = null;
415: if (in != null) {
416: try {
417: result = new ImageData(in);
418: } catch (SWTException e) {
419: if (e.code != SWT.ERROR_INVALID_IMAGE)
420: throw e;
421: // fall through otherwise
422: } finally {
423: try {
424: in.close();
425: } catch (IOException e) {
426: //System.err.println(getClass().getName()+".getImageData(): "+
427: // "Exception while closing InputStream : "+e);
428: }
429: }
430: }
431: return result;
432: }
433:
434: /*
435: * @see net.refractions.udig.catalog.IResolve#canResolve(java.lang.Class)
436: */
437: public <T> boolean canResolve(Class<T> adaptee) {
438: if (adaptee == null) {
439: return false;
440: }
441:
442: if (adaptee.isAssignableFrom(IGeoResource.class)
443: || adaptee.isAssignableFrom(WebMapServer.class)
444: || adaptee
445: .isAssignableFrom(org.geotools.data.ows.Layer.class)
446: || adaptee.isAssignableFrom(ImageDescriptor.class)
447: || adaptee.isAssignableFrom(IService.class)
448: || super .canResolve(adaptee)) {
449: return true;
450: }
451:
452: return false;
453: }
454:
455: /*
456: * @see net.refractions.udig.catalog.IResolve#getMessage()
457: */
458: public Throwable getMessage() {
459: return parent.getMessage();
460: }
461:
462: private class WMSResourceInfo extends IGeoResourceInfo {
463: WMSResourceInfo(IProgressMonitor monitor) throws IOException {
464: WebMapServer wms = parent.getWMS(monitor);
465: WMSCapabilities caps = wms.getCapabilities();
466:
467: org.opengis.spatialschema.geometry.Envelope env = null;
468: CoordinateReferenceSystem crs = null;
469: try {
470: crs = CRS.decode("EPSG:4326"); //$NON-NLS-1$
471: env = parent.getWMS(null).getEnvelope(layer, crs);
472: } catch (NoSuchAuthorityCodeException e) {
473: throw (IOException) new IOException(
474: Messages.WMSGeoResourceImpl_bounds_unavailable)
475: .initCause(e);
476: }
477: bounds = new ReferencedEnvelope(new Envelope(env
478: .getMinimum(0), env.getMaximum(0), env
479: .getMinimum(1), env.getMaximum(1)), crs);
480:
481: String parentid = parent != null
482: && parent.getIdentifier() != null ? getIdentifier()
483: .toString() : ""; //$NON-NLS-1$
484: name = layer.getName();
485: List<String> keywordsFromWMS = new ArrayList<String>();
486: if (caps.getService().getKeywordList() != null) {
487: keywordsFromWMS.addAll(Arrays.asList(caps.getService()
488: .getKeywordList()));
489: }
490:
491: if (layer.getKeywords() != null) {
492: keywordsFromWMS.addAll(Arrays.asList(layer
493: .getKeywords()));
494: }
495: keywordsFromWMS.add("WMS"); //$NON-NLS-1$
496: keywordsFromWMS.add(layer.getName());
497: keywordsFromWMS.add(caps.getService().getName());
498: keywordsFromWMS.add(parentid);
499: keywords = keywordsFromWMS
500: .toArray(new String[keywordsFromWMS.size()]);
501:
502: if (layer.get_abstract() != null
503: && layer.get_abstract().length() != 0) {
504: description = layer.get_abstract();
505: } else {
506: description = caps.getService().get_abstract();
507: }
508: description = caps.getService().get_abstract();
509:
510: if (layer.getTitle() != null
511: && layer.getTitle().length() != 0) {
512: title = layer.getTitle();
513: } else {
514: title = caps.getService().getTitle();
515: }
516: super .icon = CatalogUIPlugin.getDefault().getImages()
517: .getImageDescriptor(ISharedImages.GRID_OBJ);
518: // icon = fetchIcon( monitor );
519: }
520:
521: public String getName() {
522: return name;
523: }
524:
525: public URI getSchema() {
526: return WMSSchema.NAMESPACE;
527: }
528:
529: public String getTitle() {
530: return title;
531: }
532: }
533: }
|