Revision 4356 trunk/extensions/extWCS/src/com/iver/cit/gvsig/fmap/layers/FLyrWCS.java

View differences:

FLyrWCS.java
41 41
package com.iver.cit.gvsig.fmap.layers;
42 42

  
43 43
import java.awt.Component;
44
import java.awt.Dimension;
44 45
import java.awt.Graphics2D;
45 46
import java.awt.Point;
47
import java.awt.Rectangle;
48
import java.awt.geom.AffineTransform;
49
import java.awt.geom.NoninvertibleTransformException;
46 50
import java.awt.geom.Point2D;
47 51
import java.awt.geom.Rectangle2D;
48 52
import java.awt.image.BufferedImage;
53
import java.awt.image.DataBuffer;
54
import java.io.File;
49 55
import java.io.IOException;
50 56
import java.lang.reflect.Constructor;
51 57
import java.lang.reflect.InvocationTargetException;
58
import java.net.MalformedURLException;
59
import java.net.URL;
52 60
import java.util.ArrayList;
53 61
import java.util.Hashtable;
54
import java.util.TreeMap;
55 62

  
56 63
import javax.swing.JOptionPane;
57 64

  
65
import org.cresques.geo.ViewPortData;
66
import org.cresques.io.GdalFile;
58 67
import org.cresques.io.GeoRasterFile;
59 68
import org.cresques.io.raster.RasterFilterStack;
69
import org.cresques.io.raster.RasterFilterStackManager;
70
import org.cresques.px.Extent;
71
import org.cresques.px.PxRaster;
72
import org.exolab.castor.xml.ValidationException;
73
import org.gvsig.remoteClient.wcs.WCSStatus;
60 74

  
61 75
import com.iver.andami.PluginServices;
62 76
import com.iver.cit.gvsig.fmap.DriverException;
63 77
import com.iver.cit.gvsig.fmap.ViewPort;
64 78
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
79
import com.iver.cit.gvsig.fmap.drivers.UnsupportedVersionException;
80
import com.iver.cit.gvsig.fmap.drivers.WCSException;
65 81
import com.iver.cit.gvsig.fmap.drivers.wcs.FMapWCSDriver;
82
import com.iver.cit.gvsig.fmap.layers.layerOperations.InfoByPoint;
66 83
import com.iver.cit.gvsig.fmap.operations.Cancellable;
67
import com.iver.cit.gvsig.fmap.services.OGCWCSService;
68 84
import com.iver.utiles.StringUtilities;
69 85
import com.iver.utiles.XMLEntity;
70 86

  
71
import es.uji.lsi.wcs.client.ServerErrorResponseException;
72

  
73 87
/**
74 88
 * Class for the WCS layer.
75 89
 * 
......
77 91
 * 
78 92
 * @author jaume - jaume.dominguez@iver.es
79 93
 */
80
public class FLyrWCS extends FLyrDefault implements RasterOperations{
81
	private FMapWCSAdapter wcs = null;
94
public class FLyrWCS extends FLyrDefault implements RasterOperations, InfoByPoint{
95
	private FMapWCSDriver wcs = null;
82 96

  
97
	private URL 						host;
83 98
	private String 						label;
99
	private String						coverageName;
100
	private Rectangle2D					fullExtent;
101
	private String						format;
102
	private String						srs;
103
	private String						time;
104
	private String						parameter;
105
	private Point2D						maxRes;
106
	private Hashtable 					onlineResources = new Hashtable();
107
	
108
	private WCSStatus					wcsStatus;
109
	
84 110
	private StatusRasterInterface		status = null;
85 111
	private int 						posX = 0, posY = 0;
86 112
	private double 						posXWC = 0, posYWC = 0;
87 113
	private int 						r = 0, g = 0, b = 0;
114
	private RasterFilterStackManager	stackManager = null;
115
	private PxRaster 					raster = null;
116
	private GeoRasterFile 				rasterFile = null;
117
	private RasterFilterStack 			filterStack;
118
	private boolean 					firstLoad = false;
119
	private int 						transparency = -1;
120
	private int							rband, gband, bband;
121
	private VisualStatus				visualStatus = new VisualStatus();
122

  
123
	private int 						maxTilePrintWidth  = 80000;
124
	private int							maxTilePrintHeight = 80000;
125

  
126
	private FMapWCSDriver driver;
127
	
128
	
129
	/**
130
	 * Clase que contiene los datos de visualizaci?n de WMS.
131
	 * @author Nacho Brodin (brodin_ign@gva.es)
132
	 */
133
	private class VisualStatus {
134
		/**
135
		 * Ancho y alto de la imagen o del conjunto de tiles si los tiene. Coincide con 
136
		 * el ancho y alto del viewPort
137
		 */
138
		private	int							width = 0, height = 0;
139
		private double						minX = 0D, minY = 0D, maxX = 0D, maxY = 0D;
140
		private int 						bandCount = 0;
141
		private int							dataType = DataBuffer.TYPE_UNDEFINED;
142
	}
143

  
144
	/*
145
	 *  (non-Javadoc)
146
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setRGB(int, int, int)
147
	 */
148
	public void setRGB(int r, int g, int b) {
149
		this.r = r;
150
		this.g = g;
151
		this.b = b;
152
	}
153
	
154
	/*
155
	 *  (non-Javadoc)
156
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getFilterStack()
157
	 */
158
	public RasterFilterStack getFilterStack() {
159
		if(raster!=null)
160
			return raster.filterStack;
161
		return null;
162
	}
163
	
164
	/*
165
	 *  (non-Javadoc)
166
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setFilterStack(org.cresques.io.raster.RasterFilterStack)
167
	 */
168
	public void setFilterStack(RasterFilterStack stack) {
169
		this.filterStack = stack;
170
	}
171
	
172
	/*
173
	 *  (non-Javadoc)
174
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getSource()
175
	 */
176
	public RasterAdapter getSource() {
177
		return null;
178
	}
179
	
180
	/*
181
	 *  (non-Javadoc)
182
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setSource(com.iver.cit.gvsig.fmap.layers.RasterAdapter)
183
	 */
184
	public void setSource(RasterAdapter ra) {
185
	}
186
	
187
	/*
188
	 *  (non-Javadoc)
189
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setPos(int, int)
190
	 */
191
	public void setPos(int x, int y) {
192
		this.posX = x;
193
		this.posY = y;
194
	}
195
	
196
	/*
197
	 *  (non-Javadoc)
198
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setPosWC(double, double)
199
	 */
200
	public void setPosWC(double x, double y) {
201
		this.posXWC = x;
202
		this.posYWC = y;
203
	}
204
	
205
	/*
206
	 *  (non-Javadoc)
207
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getPixel(double, double)
208
	 */
209
	public int[] getPixel(double wcx, double wcy) {
210
		if(getPxRaster() != null)
211
			return getPxRaster().getPixel(wcx, wcy);
212
        return null;
213
	}
214
	
215
	/*
216
	 *  (non-Javadoc)
217
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setBand(int, int)
218
	 */
219
	public void setBand(int flag, int nBand) {
220
		switch(flag){
221
		case GeoRasterFile.RED_BAND:setBandR(nBand);break;
222
		case GeoRasterFile.GREEN_BAND:setBandG(nBand);break;
223
		case GeoRasterFile.BLUE_BAND:setBandB(nBand);break;
224
		}
225
	}
226
	
227
	/**
228
	 * Sets the R-band.
229
	 * 
230
	 * Asigna la banda R.
231
	 * @param r
232
	 */
233
	public void setBandR(int r){
234
		this.rband = r;
235
	}
236
	
237
	/**
238
	 * Sets the G-band.
239
	 * 
240
	 * Asigna la banda G
241
	 * @param g
242
	 */
243
	public void setBandG(int g){
244
		this.gband = g;
245
	}
246
	
247
	/**
248
	 * Sets the B-band.
249
	 * 
250
	 * Asigna la banda B
251
	 * @param b
252
	 */
253
	public void setBandB(int b){
254
		this.bband = b;
255
	}
256
	
257
	/*
258
	 *  (non-Javadoc)
259
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getAttributes()
260
	 */
261
	public ArrayList getAttributes() {
262
		if (rasterFile != null){
263
			ArrayList attr = new ArrayList();
264
			String dataType = "Byte";
265
			if (rasterFile.getDataType() == DataBuffer.TYPE_BYTE) dataType = "Byte";
266
			else if (visualStatus.dataType == DataBuffer.TYPE_SHORT)
267
				dataType = "Short";
268
			else if (visualStatus.dataType == DataBuffer.TYPE_USHORT)
269
				dataType = "Unsigned Short";
270
			else if (visualStatus.dataType == DataBuffer.TYPE_INT)
271
				dataType = "Integer";
272
			else if (visualStatus.dataType == DataBuffer.TYPE_FLOAT)
273
				dataType = "Float";
274
			else if (visualStatus.dataType == DataBuffer.TYPE_DOUBLE)
275
				dataType = "Double";
276
			else
277
				dataType = "Unknown";
278

  
279
			Object [][] a = {
280
				{"Filename",rasterFile.getName().substring(rasterFile.getName().lastIndexOf("/")+1, rasterFile.getName().length())},
281
				{"Filesize",new Long(0)},
282
				{"Width",new Integer((int)this.getWidth())},
283
				{"Height", new Integer((int)this.getHeight())},
284
				{"Bands", new Integer(visualStatus.bandCount)},
285
				{"BandDataType", dataType}
286
			};
287
			for (int i=0; i<a.length; i++)
288
				attr.add(a[i]);
289

  
290
			return attr;
291
		}
292
		return  null;
293
	}
294
	
295
	/*
296
	 *  (non-Javadoc)
297
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMaxX()
298
	 */
299
	public double getMaxX() {
300
		return visualStatus.maxX;
301
	}
302
	
303
	/*
304
	 *  (non-Javadoc)
305
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMaxY()
306
	 */
307
	public double getMaxY() {
308
		return visualStatus.maxY;
309
	}
310
	
311
	/*
312
	 *  (non-Javadoc)
313
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMinX()
314
	 */
315
	public double getMinX() {
316
		return visualStatus.minX;
317
	}
318
	
319
	/*
320
	 *  (non-Javadoc)
321
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMinY()
322
	 */
323
	public double getMinY() {
324
		return visualStatus.minY;
325
	}
326
	
327
	/*
328
	 *  (non-Javadoc)
329
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getWidth()
330
	 */
331
	public double getWidth() {
332
		return visualStatus.width;
333
	}
334
	
335
	/*
336
	 *  (non-Javadoc)
337
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getHeight()
338
	 */
339
	public double getHeight() {
340
		return visualStatus.height;
341
	}
342
	
343
	/*
344
	 *  (non-Javadoc)
345
	 * @see com.iver.cit.gvsig.fmap.layers.layerOperations.InfoByPoint#queryByPoint(java.awt.Point)
346
	 */
347
	public String queryByPoint(Point p) throws DriverException {
348
		String data = "<file:"+getName().replaceAll("[^a-zA-Z0-9]","")+">\n";
349
		ArrayList attr = this.getAttributes();
350
		data += "  <raster\n";
351
		data += "    File=\""+getName()+"\"\n";
352
		for (int i=0; i<attr.size(); i++) {
353
			Object [] a = (Object []) attr.get(i);
354

  
355
			data += "    "+a[0].toString()+"=";
356
			if (a[1].toString() instanceof String)
357
				data += "\""+a[1].toString()+"\"\n";
358
			else
359
				data += a[1].toString()+"\n";
360
		}
361
		data += "    Point=\""+posX+" , "+posY+"\"\n";
362
		data += "    Point_WC=\""+posXWC+" , "+posYWC+"\"\n";
363
		data += "    RGB=\""+r+", "+g+", "+b+"\"\n";
364
		data += "  />\n";
365

  
366
		data += "</file:"+getName().replaceAll("[^a-zA-Z0-9]","")+">\n";
367
		System.out.println(data);
368
		return data;
369
	}
370
	
371
	/*
372
	 *  (non-Javadoc)
373
	 * @see com.iver.cit.gvsig.fmap.layers.FLayer#getFullExtent()
374
	 */
375
	public Rectangle2D getFullExtent() {
376
		return fullExtent;
377
	}
378
	
379
	/*
380
	 *  (non-Javadoc)
381
	 * @see com.iver.cit.gvsig.fmap.layers.FLayer#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, com.iver.cit.gvsig.fmap.ViewPort, com.iver.cit.gvsig.fmap.operations.Cancellable, double)
382
	 */
383
	public void draw(BufferedImage image, Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale) throws DriverException {
384
		if (isWithinScale(scale)){
385
			Point2D p = viewPort.getOffset();
386
			// p will be (0, 0) when drawing a view or other when painting onto
387
			// the Layout.
388
			visualStatus.width =  viewPort.getImageWidth();
389
			visualStatus.height =  viewPort.getImageHeight();
390
			visualStatus.minX = viewPort.getAdjustedExtent().getMinX();
391
			visualStatus.minY = viewPort.getAdjustedExtent().getMinY();
392
			visualStatus.maxX = viewPort.getAdjustedExtent().getMaxX();
393
			visualStatus.maxY = viewPort.getAdjustedExtent().getMaxY();
394
			
395
				Rectangle r = new Rectangle((int) p.getX(), (int) p.getY(), viewPort.getImageWidth() - 1, viewPort.getImageHeight() - 1);
396
				Tiling tiles = new Tiling(maxTilePrintWidth, maxTilePrintHeight, r);
397
				tiles.setAffineTransform((AffineTransform) viewPort.getAffineTransform().clone());
398
				for (int tileNr=0; tileNr < tiles.getNumTiles(); tileNr++) {
399
					// drawing part
400
					try {
401
						ViewPort vp = tiles.getTileViewPort(viewPort, tileNr);
402
						drawTile(g, vp, cancel);
403
					} catch (NoninvertibleTransformException e) {
404
						e.printStackTrace();
405
					}
406
				}
407
		}
408
		Runtime r = Runtime.getRuntime();
409
		long mem = r.totalMemory() - r.freeMemory();
410
		System.err.println("Memoria total: " + (mem / 1024) +"KB");
411
	}
88 412
		
413
	/**
414
	 * This is the method used to draw a tile in a WMS mosaic layer.
415
	 */
416
	private void drawTile(Graphics2D g, ViewPort vp, Cancellable cancel) throws DriverException {
89 417

  
418
		// Compute the query geometry 
419
		// 1. Check if it is within borders
420
		Rectangle2D extent = getFullExtent();
421
        if ((vp.getExtent().getMinX() > extent.getMaxX()) ||
422
                (vp.getExtent().getMinY() > extent.getMaxY()) ||
423
                (vp.getExtent().getMaxX() < extent.getMinX()) ||
424
                (vp.getExtent().getMaxY() < extent.getMinY())) {
425
            return;
426
        }
427
        
428
        // 2. Compute extent to be requested.
429
        Rectangle2D bBox = new Rectangle2D.Double();
430
        Rectangle2D.intersect(vp.getExtent(), extent, bBox);
431
        
432
        // 3. Compute size in pixels
433
        double scalex = vp.getAffineTransform().getScaleX(); 
434
        double scaley = vp.getAffineTransform().getScaleY(); 
435
        int wImg = (int) Math.ceil(Math.abs(bBox.getWidth() * scalex) + 1);
436
        int hImg = (int) Math.ceil(Math.abs(bBox.getHeight() * scaley) + 1);
437
        Dimension sz = new Dimension(wImg, hImg);
438

  
439
        if ((wImg <= 0) || (hImg <= 0)) {
440
            return;
441
        }
442
		
443
		try {	
444
			wcsStatus.setCoveraName( coverageName );
445
			wcsStatus.setExtent( bBox );
446
			wcsStatus.setFormat( format );
447
			wcsStatus.setHeight( hImg );
448
			wcsStatus.setWidth( wImg );
449
			wcsStatus.setSrs(srs);
450
			wcsStatus.setParameters( parameter );
451
			wcsStatus.setOnlineResource((String) onlineResources.get("GetMap"));
452
			
453
			File f = getDriver().getCoverage(wcsStatus);
454
			String nameWordFile = f.getPath() + getExtensionWorldFile();
455
			com.iver.andami.Utilities.createTemp(nameWordFile, this.getDataWorldFile(bBox, sz));
456
			
457
			if(status!=null && firstLoad){
458
				status.applyStatus(this);
459
				firstLoad = false;
460
			}
461
			ViewPortData vpData = new ViewPortData(
462
				vp.getProjection(), new Extent(bBox), sz );
463
			vpData.setMat(vp.getAffineTransform());
464

  
465
			rasterProcess(g, vpData, f);
466
			
467
		} catch (ValidationException e) {
468
			throw new DriverException(PluginServices.getText(this, "unknown_response_format"), e);
469
		} catch (UnsupportedVersionException e) {
470
			throw new DriverException(PluginServices.getText(this, "version_conflict"), e);
471
		} catch (IOException e) {
472
			throw new DriverException(PluginServices.getText(this, "connect_error"), e);
473
		} catch (WCSException e) {
474
            JOptionPane.showMessageDialog((Component)PluginServices.getMainFrame(), e.getMessage());
475
			this.setVisible(false);
476
		}
477
	}
478
	
90 479
	/**
480
	 * Devuelve el FMapWMSDriver.
481
	 *
482
	 * @return FMapWMSDriver
483
	 *
484
	 * @throws IllegalStateException
485
	 * @throws ValidationException
486
	 * @throws UnsupportedVersionException
487
	 * @throws IOException
488
	 */
489
	private FMapWCSDriver getDriver() throws IllegalStateException, ValidationException, UnsupportedVersionException, IOException {
490
		if (wcs == null) {
491
			wcs = new FMapWCSDriver();
492
            wcs.createClient(host);
493
        }
494
		return wcs;
495
	}
496

  
497
	/**
498
	 * Calcula el contenido del fichero de georreferenciaci?n de una imagen.
499
	 * @param bBox Tama?o y posici?n de la imagen (en coordenadas de usuario)
500
	 * @param sz Tama?o de la imagen en pixeles.
501
	 * @return el 'WorldFile', como String.
502
	 * @throws IOException
503
	 */
504
	public String getDataWorldFile(Rectangle2D bBox, Dimension sz) throws IOException {
505
		StringBuffer data = new StringBuffer();
506
    	data.append((bBox.getMaxX() - bBox.getMinX())/(sz.getWidth() - 1)+"\n");
507
    	data.append("0.0\n");
508
    	data.append("0.0\n");
509
    	data.append((bBox.getMaxY() - bBox.getMinY())/(sz.getHeight() - 1)+"\n");
510
    	data.append(""+bBox.getMinX()+"\n");
511
    	data.append(""+bBox.getMinY()+"\n");
512
    	return data.toString();
513
	}
514
	
515
	/**
516
	 * Dibuja una imagen usando PxRaster
517
	 * @param g	Graphics2D en el que hay que dibujar.
518
	 * @param vpData Par?metros de visualizaci?n
519
	 * @param file La imagen en cuesti?n.
520
	 */
521
	private void rasterProcess(Graphics2D g, ViewPortData vpData, File file) {
522
		
523
		//Creamos el PxRaster	
524
		rasterFile = new GdalFile(vpData.getProjection(), file.getAbsolutePath());
525
		raster = new PxRaster(rasterFile, null, rasterFile.getExtent());
526
		
527
		//Recuperamos la pila de filtros si ya hubiese sido cargado antes
528
		if (this.filterStack!=null)
529
			raster.filterStack = this.filterStack;
530
		
531
		raster.setTransparency(false);
532
						
533
		//Asignamos transparencia y orden de bandas
534
		if (this.transparency==-1 && !firstLoad);
535
		else
536
			raster.setTransparency(this.transparency);
537
		
538
		raster.setBand(GeoRasterFile.RED_BAND,rband);
539
		raster.setBand(GeoRasterFile.GREEN_BAND, gband);
540
		raster.setBand(GeoRasterFile.BLUE_BAND, bband);
541
	
542
		//Despues del primer pxRaster asignamos el stackManager guardado para los siguientes.
543
		//Con esto conseguimos asignar los cambios que se hayan producido desde el cuadro de 
544
		//propiedades cuando creamos un nuevo pxRaster
545
		if (this.stackManager != null)
546
			raster.setStackManager(this.stackManager); 
547

  
548
		if (visualStatus != null){
549
			visualStatus.bandCount = raster.getBandCount();
550
			visualStatus.dataType = raster.getDataType();
551
		}
552
		
553
		raster.draw(g, vpData);
554
		
555
		//En el primer pxRaster de una imagen obtenemos el Stack Manager para poder modificarlo
556
		//si queremos desde las propiedades
557
		
558
		if (this.stackManager == null)
559
			this.stackManager = raster.getStackManager(); 
560
		
561
		if (this.filterStack == null)
562
			this.filterStack = raster.filterStack;
563
		
564
		rasterFile.close();
565
	}
566
	
567
	public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale) throws DriverException {
568
		// TODO Auto-generated method stub
569
		
570
	}
571
		
572
	/**
573
	 * @return Returns the raster.
574
	 */
575
	public PxRaster getPxRaster() {
576
		return raster;
577
	}
578

  
579
	/**
91 580
	 * Returns the XMLEntity containing the necessary info for reproduce
92 581
	 * the layer.
93 582
	 * 
......
101 590
		XMLEntity xml = super.getXMLEntity();
102 591

  
103 592
		xml.putProperty("wcs.host", getHost());
104
		try {
105
            xml.putProperty("wcs.fullExtent",
106
            	StringUtilities.rect2String(wcs.getFullExtent()));
107
        } catch (IOException e) {
108
        } catch (DriverException e) {
109
        }
110
		xml.putProperty("wcs.layerQuery", wcs.getCoverageQuery());
111
		xml.putProperty("wcs.format", getFormat());
112
		xml.putProperty("wcs.srs", getSRS());
113
		xml.putProperty("wcs.time", getTime());
114
		xml.putProperty("wcs.parameter", getParameter());
593
		xml.putProperty("wcs.fullExtent", StringUtilities.rect2String( fullExtent ));
594
		xml.putProperty("wcs.layerQuery", coverageName );
595
		xml.putProperty("wcs.format", format );
596
		xml.putProperty("wcs.srs", srs );
597
		xml.putProperty("wcs.time", time );
598
		xml.putProperty("wcs.parameter", parameter );
115 599
		xml.putProperty("wcs.label", label);
116
		xml.putProperty("wcs.coverageName", getCoverageName());
117
		xml.putProperty("wcs.maxResX", getMaxResolution().getX());
118
		xml.putProperty("wcs.maxResY", getMaxResolution().getY());
600
		xml.putProperty("wcs.coverageName", coverageName );
601
		xml.putProperty("wcs.maxResX", maxRes.getX());
602
		xml.putProperty("wcs.maxResY", maxRes.getY());
119 603
		if (status!=null)
120 604
			status.getXMLEntity(xml, true, this);
121 605
		else{
......
138 622
	 */
139 623
	public void setXMLEntity(XMLEntity xml) throws XMLException {
140 624
		super.setXMLEntity(xml);
141
		//System.out.println(" Cargo la capa WCS. ... o no ;-)");
142
		setHost(xml.getStringProperty("wcs.host"));
143
		setFullExtent(StringUtilities.string2Rect(
144
			xml.getStringProperty("wcs.fullExtent")));
145
		wcs.setCoverageQuery(xml.getStringProperty("wcs.layerQuery"));
146
		setFormat(xml.getStringProperty("wcs.format"));
147
		setSRS(xml.getStringProperty("wcs.srs"));
148
		setTime(xml.getStringProperty("wcs.time"));
149
		setParameter(xml.getStringProperty("wcs.parameter"));
625
		
626
		// host
627
		try {
628
			host = new URL(xml.getStringProperty("wcs.host"));
629
		} catch (MalformedURLException e) {
630
			throw new XMLException(e);
631
		}
632
		
633
		// full extent
634
		fullExtent = StringUtilities.string2Rect(xml.getStringProperty("wcs.fullExtent"));
635
		
636
		// coverageQuery
637
		coverageName = xml.getStringProperty("wcs.layerQuery");
638
		
639
		// format
640
		format = xml.getStringProperty("wcs.format");
641
		
642
		// srs
643
		srs = xml.getStringProperty("wcs.srs");
644
		
645
		// time
646
		time = xml.getStringProperty("wcs.time");
647
		
648
		// parameter
649
		parameter = xml.getStringProperty("wcs.parameter");
650
		
651
		// label
150 652
		label = xml.getStringProperty("wcs.label");
151
		setCoverageName(xml.getStringProperty("wcs.coverageName"));
653
		
654
		// coverage name
655
		coverageName = xml.getStringProperty("wcs.coverageName");
656
		
657
		// max resolution
152 658
		if (xml.contains("wcs.maxRes"))
153
			setMaxResolution(new Point2D.Double(xml.getDoubleProperty("wcs.maxRes"), xml.getDoubleProperty("wcs.maxRes")));
154
		else if (xml.contains("wcs.maxResX") && xml.contains("wcs.maxResY")) 
155
			setMaxResolution(new Point2D.Double(xml.getDoubleProperty("wcs.maxResX"), xml.getDoubleProperty("wcs.maxResY")));
156

  
659
			maxRes = new Point2D.Double(xml.getDoubleProperty("wcs.maxRes"), xml.getDoubleProperty("wcs.maxRes"));
660
		else if (xml.contains("wcs.maxResX") && xml.contains("wcs.maxResY"))
661
			maxRes = new Point2D.Double(xml.getDoubleProperty("wcs.maxResX"), xml.getDoubleProperty("wcs.maxResY"));
157 662
		
663
		// OnlineResources
664
        if (xml.contains("onlineResources")) {
665
        	String[] operations = xml.getStringProperty("onlineResources").split("~##SEP1##~");
666
        	for (int i = 0; i < operations.length; i++) {
667
				String[] resources = operations[i].split("~##SEP2##~");
668
				if (resources.length==2 && resources[1]!="")
669
					onlineResources.put(resources[0], resources[1]);
670
			}
671
        }
158 672
		String claseStr = null;
159 673
		if (xml.contains("raster.class")) {
160 674
			claseStr = xml.getStringProperty("raster.class");
161 675
		}
162
		if(status!=null)
676
		if (status!=null)
163 677
			status.setXMLEntity(xml, this);
164
		else{
678
		else {
165 679
			
166 680
			//Cuando cargamos un proyecto 
167 681
			
......
172 686
					status = (StatusRasterInterface)constr.newInstance(null);
173 687
					if(status!=null)
174 688
						status.setXMLEntity(xml, this);
175
				}catch(ClassNotFoundException exc){
689
				} catch(ClassNotFoundException exc) {
176 690
					exc.printStackTrace();
177
				}catch(InstantiationException exc){
691
				} catch(InstantiationException exc) {
178 692
					exc.printStackTrace();
179
				}catch(IllegalAccessException exc){
693
				} catch(IllegalAccessException exc) {
180 694
					exc.printStackTrace();
181
				}catch(NoSuchMethodException exc){
695
				} catch(NoSuchMethodException exc) {
182 696
					exc.printStackTrace();
183
				}catch(InvocationTargetException exc){
697
				} catch(InvocationTargetException exc) {
184 698
					exc.printStackTrace();
185 699
				}					
186 700
			}
187 701
		}
188
		wcs.firstLoad = true;
702
		firstLoad = true;
189 703
	}
704

  
705
	public void setLabel(String label) {
706
		this.label = label;
707
	}
708

  
709
	public void setCoverageName(String coverageName) {
710
		this.coverageName = coverageName;
711
	}
712

  
713
	public void setParameter(String parametersString) {
714
		this.parameter = parametersString;
715
	}
716

  
717
	public void setTime(String time) {
718
		this.time = time;
719
	}
720

  
721
	public void setSRS(String srs) {
722
		this.srs = srs;
723
	}
724

  
725
	public void setFormat(String format) {
726
		this.format = format;
727
	}
728

  
729

  
730
	/**
731
	 * Inserta el URL.
732
	 *
733
	 * @param host String.
734
	 * @throws MalformedURLException 
735
	 */
736
	public void setHost(String host) {
737
		try {
738
			setHost(new URL(host));
739
		} catch (MalformedURLException e) {
740
			
741
		}
742
	}
190 743
	
191 744
	/**
745
	 * Inserta el URL.
746
	 *
747
	 * @param host URL.
748
	 */
749
	public void setHost(URL host) {
750
		this.host = host;
751
	}
752

  
753
	/**
754
	 * Sets the layer's full extent.
755
	 * 
756
	 * Establece la extensi?n m?xima de la capa.
757
	 * 
758
	 * @param rect
759
	 */
760
	public void setFullExtent(Rectangle2D rect) {
761
		this.fullExtent = rect;
762
	}
763
	
764
	/**
765
	 * Devuelve el URL.
766
	 *
767
	 * @return URL.
768
	 */
769
	public URL getHost() {
770
		return host;
771
	}
772

  
773
	/**
774
	 * Remote source layers have a bunch of properties that are required for get them from
775
	 * the servers. This method supplies a hash table containing any needed field. This hash
776
	 * table may be used to let the client to connect to a server and restore a previously saved
777
	 * layer. So, the layer itself may not be saved to the disk since the actual saved
778
	 * info is just its properties.
779
	 * 
780
	 * @return Returns a hash table containing all the required information for
781
	 * set up a wms layer
782
	 */
783
	public Hashtable getProperties(){
784
		Hashtable info = new Hashtable();
785
		info.put(   "name", coverageName);
786
		info.put(   "host", getHost());
787
		info.put(    "crs", srs);
788
		info.put( "format", format);
789
		String str = time;
790
		if (str==null) 
791
			str = "";
792
		info.put(   "time", str);
793
		str = parameter;
794
		if (str==null)
795
			str = "";
796
		info.put("parameter", str);	
797
		
798
		return info;
799
	}
800

  
801
	/**
802
	 * Obtiene la extensi?n del fichero de georreferenciaci?n
803
	 * @return String con la extensi�n del fichero de georreferenciaci�n dependiendo
804
	 * del valor del formato obtenido del servidor. Por defecto asignaremos un .wld 
805
	 */
806
	private String getExtensionWorldFile(){
807
		String extWorldFile = ".wld";
808
    	if (format.equals("image/tif") || format.equals("image/tiff"))
809
    		extWorldFile = ".tfw";
810
    	if (format.equals("image/jpeg"))
811
    		extWorldFile = ".jpgw";
812
    	return extWorldFile;
813
	}
814
	
815
	public void setMaxResolution(Point2D maxResolution) {
816
		this.maxRes = maxResolution;
817
	}
818

  
819
	/**
820
	 * Gets the last open GeoRasterFile against the temp file received
821
	 * 
822
	 * Obtiene el ?ltimo GeoRasterFile abierto sobre el temporal recibido
823
	 * @return
824
	 */
825
	public GeoRasterFile getGeoRasterFile(){
826
		return rasterFile;
827
	}
828
	
829
	
830
	/**
831
	 * Asignar el estado del raster
832
	 * @param status
833
	 */
834
	public void setStatus(StatusRasterInterface status){
835
		this.status = status;
836
	}
837
	
838
	/**
839
	 * Obtiene el estado del raster
840
	 * @return
841
	 */
842
	public StatusRasterInterface getStatus(){
843
		return this.status;
844
	}
845
	
846
	/**
847
	 * Gets the max resolution allowed by the coverage. Requesting a higher resolution
848
	 * than this value does not cause any error, but the info responsed is just an
849
	 * interpolation.
850
	 * 
851
	 * In exchange for obtaining a greater file and without additional information,
852
	 * we can easily connect it at the View.
853
	 * 
854
	 * 
855
	 * Obtiene la resoluci?n m?xima soportada por la cobertura. La petici?n
856
	 * de una resoluci?n superior a la soportada no provoca ning?n error, aunque
857
	 * la informaci?n obtenida s?lo es una mera interpolaci?n de informaci?n. 
858
	 * 
859
	 * A cambio de obtener un archivo mayor y sin informaci?n adicional, podemos
860
	 * f?cilmente acoplarlo a la vista.
861
	 * 
862
	 * @return double
863
	 */
864
	public Point2D getMaxResolution() {
865
		if (maxRes==null)
866
			maxRes = wcs.getMaxResolution(coverageName);
867
		return maxRes;
868
	}
869
	
870

  
871
	public void setDriver(FMapWCSDriver driver) {
872
		this.driver = driver;
873
	}
874

  
875
	/**
192 876
	 * The full extent of the layer.
193 877
	 * 
194 878
	 * La extensi?n completa de la layer.
195 879
	 * 
196 880
	 * @return Rectangle2D
197
	 */
881
	 * /
198 882
	public Rectangle2D getFullExtent(){// throws DriverException {
199 883
		try {
200 884
            return getWCSAdaptor().getFullExtent();
......
212 896
	 * Draws the layer on the ViewPort using PxRaster.
213 897
	 * 
214 898
	 * Dibuja la capa en el ViewPort con PxRaster.
215
	 */
899
	 * /
216 900
	public void draw(BufferedImage image, Graphics2D g,
217 901
			ViewPort viewPort, Cancellable cancel, double scale) throws DriverException {
218 902
		/* This try loop I've moved here is for show an alert window when it is not
219 903
		 * possible to download the coverage. 
220
		 */
904
		 * /
221 905
			try {
222 906
				if (!isWithinScale(scale))
223 907
					return;
......
242 926
	 * Prints the layer.
243 927
	 * 
244 928
	 * Imprime la cobertura.
245
	 */	
929
	 * /	
246 930
	public void print(Graphics2D g, ViewPort viewPort, Cancellable cancel, double scale)
247 931
			throws DriverException {
248 932
		draw(null, g, viewPort, cancel, scale);
......
254 938
	 * Establece la etiqueta de la cobertura. La que se usar? en el TOC.
255 939
	 * 
256 940
	 * @param lbl
257
	 */
941
	 * /
258 942
	public void setLabel(String lbl) {
259 943
		label = lbl;
260 944
	}
......
265 949
	 * Establece la extensi?n m?xima de la capa.
266 950
	 * 
267 951
	 * @param rect
268
	 */
952
	 * /
269 953
	public void setFullExtent(Rectangle2D rect) {
270 954
		wcs.setFullExtent(rect);
271 955
	}
......
283 967
	 * dessitge.
284 968
	 * 
285 969
	 * @return String
286
	 */
970
	 * /
287 971
	public String getLabel() {
288 972
		return this.label;
289 973
	}
......
297 981
	 * 
298 982
	 * @return Returns a hash table containing all the required information for
299 983
	 * set up a wms layer
300
	 */
984
	 * /
301 985
	public Hashtable getProperties(){
302 986
		Hashtable info = new Hashtable();
303 987
		info.put(   "name", getCoverageName());
......
322 1006
	 * 
323 1007
	 * Obtiene el nombre de la cobertura.
324 1008
	 * @return String
325
	 */
1009
	 * /
326 1010
	public String getCoverageName() {
327 1011
		return wcs.getCoverageName();
328 1012
	}
......
332 1016
	 * 
333 1017
	 * Obtiene el formato en que la cobertura est? codificado.
334 1018
	 * @return String
335
	 */
1019
	 * /
336 1020
	public String getFormat() {
337 1021
		return wcs.getFormat();
338 1022
	}
......
343 1027
	 * Obtiene la direcci?n URL del servidor WCS
344 1028
	 * 
345 1029
	 * @return String
346
	 */
1030
	 * /
347 1031
	public String getHost() {
348 1032
		return wcs.getHost();
349 1033
	}
......
353 1037
	 * 
354 1038
	 * Obtiene el valor del par?metro.
355 1039
	 * @return String
356
	 */
1040
	 * /
357 1041
	public String getParameter() {
358 1042
		return wcs.getParameter();
359 1043
	}
......
363 1047
	 * 
364 1048
	 * Obtiene el SRS actual de la cobertura.
365 1049
	 * @return String
366
	 */
1050
	 * /
367 1051
	public String getSRS() {
368 1052
		return wcs.getSRS();
369 1053
	}
......
373 1057
	 * 
374 1058
	 * Obtiene el valor para TIME en la consulta WCS.
375 1059
	 * @return String
376
	 */
1060
	 * /
377 1061
	public String getTime() {
378 1062
		return wcs.getTime();
379 1063
	}
......
383 1067
	 * 
384 1068
	 * Establece el par?metro FORMAT en que se pide la cobertura WCS
385 1069
	 * @param format
386
	 */
1070
	 * /
387 1071
	public void setFormat(String format) {
388 1072
		wcs.setFormat(format);
389 1073
	}
......
393 1077
	 * 
394 1078
	 * Establece la direcci?n URL del servidor WCS
395 1079
	 * @param host
396
	 */
1080
	 * /
397 1081
	public void setHost(String host) {
398 1082
		if (wcs == null) {
399 1083
			wcs = new FMapWCSAdapter();
......
409 1093
	 * Establece el nombre y el valor (lista de valores separados por comas)
410 1094
	 * del par?metro de la consulta WCS
411 1095
	 * @param parameter
412
	 */
1096
	 * /
413 1097
	public void setParameter(String parameter) {
414 1098
		wcs.setParameter(parameter);
415 1099
	}
......
419 1103
	 * 
420 1104
	 * Establece el SRS de la consulta WCS.
421 1105
	 * @param srs
422
	 */
1106
	 * /
423 1107
	public void setSRS(String srs) {
424 1108
		wcs.setSRS(srs);
425 1109
	}
......
429 1113
	 * 
430 1114
	 * Establece el par?metro TIME de la consulta WCS.
431 1115
	 * @param time
432
	 */
1116
	 * /
433 1117
	public void setTime(String time) {
434 1118
		 wcs.setTime(time);
435 1119
	}
......
439 1123
	 * 
440 1124
	 * Establece el par?metro COVERAGE de la consulta WCS.
441 1125
	 * @param coverageName
442
	 */
1126
	 * /
443 1127
	public void setCoverageName(String coverageName) {
444 1128
		wcs.setCoverageName(coverageName);
445 1129
	}
......
461 1145
	 * f?cilmente acoplarlo a la vista.
462 1146
	 * 
463 1147
	 * @return double
464
	 */
1148
	 * /
465 1149
	public Point2D getMaxResolution() {
466 1150
		return wcs.getMaxResolution();
467 1151
	}
......
489 1173
	 * un "zoom a la resoluci?n del r?ster".
490 1174
	 * 
491 1175
	 * @param res
492
	 */
1176
	 * /
493 1177
	//public void setMaxResolution(double res){
494 1178
	public void setMaxResolution(Point2D res){
495 1179
		wcs.setMaxResolution(res);
......
499 1183
	 * Returns the adaptor.
500 1184
	 * 
501 1185
	 * Obtiene el adaptor.
502
	 */
1186
	 * /
503 1187
	public FMapWCSAdapter getWCSAdaptor(){
504 1188
	    return wcs;
505 1189
	}
......
511 1195
	 * 
512 1196
	 * @deprecated
513 1197
	 * @param wcs
514
	 */
1198
	 * /
515 1199
	public void setWCSAdaptor(FMapWCSAdapter wcs){
516 1200
		this.wcs = wcs;
517 1201
	}
......
521 1205
	 * 
522 1206
	 * Obtiene la Bounding Box sobre la que se est? operando
523 1207
	 * @return Rectangle2D
524
	 */
1208
	 * /
525 1209
	private Rectangle2D getBbox() {
526 1210
		return wcs.getBbox();
527 1211
	}
......
531 1215
	 * 
532 1216
	 * Obtiene la resoluci?n actual para la cobertura de la vista.
533 1217
	 * @return
534
	 */
1218
	 * /
535 1219
	private Point2D getRes() {
536 1220
		return wcs.getRes();
537 1221
	}
......
546 1230
	 * ser usado ?nicamente para recuperar este valor de un proyecto
547 1231
	 * anteriormente guardado. 
548 1232
	 * @param res
549
	 */
1233
	 * /
550 1234
	//private void setRes(double res) {
551 1235
	private void setRes(Point2D res) {
552 1236
		wcs.setRes(res);
......
563 1247
	 * guardado.
564 1248
	 * 
565 1249
	 * @param rect
566
	 */
1250
	 * /
567 1251
	private void setBBox(Rectangle2D rect) {
568 1252
		wcs.setBBox(rect);
569 1253
	}
......
575 1259
	 * Inicializa una cobertura a partir de una URL GetCoverage completa.
576 1260
	 * (To use this method supposes to skip all the regular operation)
577 1261
	 * 
578
	 */
1262
	 * /
579 1263
	public void initFromQueryString(String queryString){
580 1264
		System.out.println("Query = "+queryString);
581 1265
		TreeMap map = new TreeMap(); 
......
612 1296
		}
613 1297
	}
614 1298
	
615
	/**
616
	 * Asignar el estado del raster
617
	 * @param status
618
	 */
619
	public void setStatus(StatusRasterInterface status){
620
		this.status = status;
621
	}
622 1299
	
623
	/**
624
	 * Obtiene el estado del raster
625
	 * @return
626
	 */
627
	public StatusRasterInterface getStatus(){
628
		return this.status;
629
	}
630 1300
	
631 1301
	/**
632 1302
	 * Builds a coverage starting from a full GetCoverage URL.
......
637 1307
	 * 
638 1308
	 * TODO Por completar y probar
639 1309
	 * @param queryString
640
	 */
1310
	 * /
641 1311
	public void initFromQueryString2(String queryString){
642 1312

  
643 1313
		String host = queryString.substring(0, queryString.indexOf('?'));
......
682 1352
	 * Devuelve la pila de filtros aplicada sobre  la capa raster.
683 1353
	 *
684 1354
	 * @return RasterFilterStack.
685
	 */
1355
	 * /
686 1356
	public RasterFilterStack getFilterStack() {
687 1357
		return wcs.getFilterStack();
688 1358
	}
......
690 1360
	/**
691 1361
	 * Asigna la pila de filtros aplicada al raster
692 1362
	 * @return
693
	 */
1363
	 * /
694 1364
	public void setFilterStack(RasterFilterStack stack){
695 1365
		wcs.setFilterStack(stack);		
696 1366
	}
697 1367
	
698 1368
	/* (non-Javadoc)
699 1369
	 * @see com.iver.cit.gvsig.fmap.layers.FLyrDefault#setTransparency(int)
700
	 */
1370
	 * /
701 1371
	public void setTransparency(int trans) {
702 1372
		wcs.setTransparency(trans);
703 1373
	}
704 1374
	
705 1375
	/* (non-Javadoc)
706 1376
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setBand(int, int)
707
	 */
1377
	 * /
708 1378
	public void setBand(int flag, int nBand) {
709 1379
		switch(flag){
710 1380
		case GeoRasterFile.RED_BAND:wcs.setBandR(nBand);break;
......
715 1385
	
716 1386
	/* (non-Javadoc)
717 1387
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getAttributes()
718
	 */
1388
	 * /
719 1389
	public ArrayList getAttributes() {
720 1390
		return wcs.getAttributes();
721 1391
	}
722 1392
	/* (non-Javadoc)
723 1393
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getHeight()
724
	 */
1394
	 * /
725 1395
	public double getHeight() {
726 1396
		if(wcs.getGeoRasterFile() != null)
727 1397
			return wcs.getGeoRasterFile().getHeight();
......
730 1400
	}
731 1401
	/* (non-Javadoc)
732 1402
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMaxX()
733
	 */
1403
	 * /
734 1404
	public double getMaxX() {
735 1405
		if(wcs.getPxRaster() != null)
736 1406
			return wcs.getPxRaster().getExtent().getMax().getX();
......
739 1409
	}
740 1410
	/* (non-Javadoc)
741 1411
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMaxY()
742
	 */
1412
	 * /
743 1413
	public double getMaxY() {
744 1414
		if(wcs.getPxRaster() != null)
745 1415
			return wcs.getPxRaster().getExtent().getMax().getY();
......
748 1418
	}
749 1419
	/* (non-Javadoc)
750 1420
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMinX()
751
	 */
1421
	 * /
752 1422
	public double getMinX() {
753 1423
		if(wcs.getPxRaster() != null)
754 1424
			return wcs.getPxRaster().getExtent().getMin().getX();
......
757 1427
	}
758 1428
	/* (non-Javadoc)
759 1429
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getMinY()
760
	 */
1430
	 * /
761 1431
	public double getMinY() {
762 1432
		if(wcs.getPxRaster() != null)
763 1433
			return wcs.getPxRaster().getExtent().getMin().getY();
......
766 1436
	}
767 1437
	/* (non-Javadoc)
768 1438
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getPixel(double, double)
769
	 */
1439
	 * /
770 1440
	public int[] getPixel(double wcx, double wcy) {
771 1441
		if(wcs.getPxRaster() != null)
772 1442
			return wcs.getPxRaster().getPixel(wcx, wcy);
......
775 1445
	}
776 1446
	/* (non-Javadoc)
777 1447
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getSource()
778
	 */
1448
	 * /
779 1449
	public RasterAdapter getSource() {
780 1450
		// TODO Auto-generated method stub
781 1451
		return null;
782 1452
	}
783 1453
	/* (non-Javadoc)
784 1454
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#getWidth()
785
	 */
1455
	 * /
786 1456
	public double getWidth() {
787 1457
		if(wcs.getGeoRasterFile() != null)
788 1458
			return wcs.getGeoRasterFile().getWidth();
......
791 1461
	}
792 1462
	/* (non-Javadoc)
793 1463
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setPos(int, int)
794
	 */
1464
	 * /
795 1465
	public void setPos(int x, int y) {
796 1466
		this.posX = x;
797 1467
		this.posY = y;
798 1468
	}
799 1469
	/* (non-Javadoc)
800 1470
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setPosWC(double, double)
801
	 */
1471
	 * /
802 1472
	public void setPosWC(double x, double y) {
803 1473
		this.posXWC = x;
804 1474
		this.posYWC = y;
805 1475
	}
806 1476
	/* (non-Javadoc)
807 1477
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setRGB(int, int, int)
808
	 */
1478
	 * /
809 1479
	public void setRGB(int r, int g, int b) {
810 1480
		this.r = r;
811 1481
		this.g = g;
......
813 1483
	}
814 1484
	/* (non-Javadoc)
815 1485
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setSource(com.iver.cit.gvsig.fmap.layers.RasterAdapter)
816
	 */
1486
	 * /
817 1487
	public void setSource(RasterAdapter ra) {
818 1488
		// TODO Auto-generated method stub
819 1489

  
820 1490
	}
821 1491
	/* (non-Javadoc)
822 1492
	 * @see com.iver.cit.gvsig.fmap.layers.layerOperations.InfoByPoint#queryByPoint(java.awt.Point)
823
	 */
1493
	 * /
824 1494
	public String queryByPoint(Point p) throws DriverException {
825 1495
		String data = "<file:"+getName().replaceAll("[^a-zA-Z0-9]","")+">\n";
826 1496
		ArrayList attr = this.getAttributes();
......
848 1518

  
849 1519
	/* (non-Javadoc)
850 1520
	 * @see com.iver.cit.gvsig.fmap.layers.RasterOperations#setTempExtent(com.iver.cit.gvsig.fmap.ViewPort)
851
	 */
1521
	 * /
852 1522
	public void setTempExtent(ViewPort vp){
853 1523
		
854 1524
	}
855
}
1525
	/**/
1526

  
1527
	
1528
	
1529
}

Also available in: Unified diff