0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * Created on 22 novembre 2003, 15.22
0017: */
0018: package org.geotools.map;
0019:
0020: import java.awt.geom.AffineTransform;
0021: import java.io.IOException;
0022: import java.util.ArrayList;
0023: import java.util.Collection;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.logging.Level;
0027: import java.util.logging.Logger;
0028:
0029: import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
0030: import org.geotools.data.DataUtilities;
0031: import org.geotools.data.FeatureSource;
0032: import org.geotools.data.memory.CollectionSource;
0033: import org.geotools.factory.FactoryConfigurationError;
0034: import org.geotools.feature.FeatureCollection;
0035: import org.geotools.feature.IllegalAttributeException;
0036: import org.geotools.feature.SchemaException;
0037: import org.geotools.geometry.jts.ReferencedEnvelope;
0038: import org.geotools.map.event.MapBoundsEvent;
0039: import org.geotools.map.event.MapLayerEvent;
0040: import org.geotools.map.event.MapLayerListEvent;
0041: import org.geotools.map.event.MapLayerListener;
0042: import org.geotools.referencing.CRS;
0043: import org.geotools.referencing.crs.DefaultGeographicCRS;
0044: import org.geotools.resources.image.CoverageUtilities;
0045: import org.geotools.styling.Style;
0046: import org.opengis.coverage.grid.GridCoverage;
0047: import org.opengis.referencing.FactoryException;
0048: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0049: import org.opengis.referencing.operation.TransformException;
0050:
0051: import com.vividsolutions.jts.geom.Envelope;
0052:
0053: /**
0054: * The default implementation of the {@linkplain org.geotools.map.MapContext}
0055: * interface
0056: *
0057: * @author Andrea Aime
0058: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/render/src/main/java/org/geotools/map/DefaultMapContext.java $
0059: */
0060: public class DefaultMapContext implements MapContext {
0061: /** The logger for the map module. */
0062: static public final Logger LOGGER = org.geotools.util.logging.Logging
0063: .getLogger("org.geotools.map");
0064:
0065: List layerList = new ArrayList();
0066:
0067: CoordinateReferenceSystem crs = null;
0068:
0069: ReferencedEnvelope areaOfInterest = null;
0070:
0071: /** Utility field used by event firing mechanism. */
0072: protected javax.swing.event.EventListenerList listenerList = null;
0073:
0074: protected MapLayerListener layerListener = new MapLayerListener() {
0075: public void layerChanged(MapLayerEvent event) {
0076: fireAsListEvent(event);
0077: }
0078:
0079: public void layerShown(MapLayerEvent event) {
0080: fireAsListEvent(event);
0081: }
0082:
0083: public void layerHidden(MapLayerEvent event) {
0084: fireAsListEvent(event);
0085: }
0086:
0087: private void fireAsListEvent(MapLayerEvent event) {
0088: MapLayer layer = (MapLayer) event.getSource();
0089: int position = layerList.indexOf(layer);
0090: fireMapLayerListListenerLayerChanged(new MapLayerListEvent(
0091: DefaultMapContext.this , layer, position, event));
0092: }
0093: };
0094:
0095: /** Holds value of property abstracts. */
0096: protected String abstracts;
0097:
0098: /** Utility field used by bound properties. */
0099: protected java.beans.PropertyChangeSupport propertyChangeSupport = new java.beans.PropertyChangeSupport(
0100: this );
0101:
0102: /** Holds value of property contactInformation. */
0103: protected String contactInformation;
0104:
0105: /** Holds value of property keywords. */
0106: protected String[] keywords;
0107:
0108: /** Holds value of property title. */
0109: protected String title;
0110:
0111: private ReferencedEnvelope bounds = null;
0112:
0113: /**
0114: * Creates a default empty map context
0115: *
0116: * @deprecated
0117: */
0118: public DefaultMapContext() {
0119: this .crs = DefaultGeographicCRS.WGS84;
0120: this .title = "";
0121: this .abstracts = "";
0122: this .contactInformation = "";
0123: this .keywords = new String[0];
0124: }
0125:
0126: /**
0127: * Creates a default empty map context
0128: *
0129: */
0130: public DefaultMapContext(final CoordinateReferenceSystem crs) {
0131: this .crs = crs;
0132: this .title = "";
0133: this .abstracts = "";
0134: this .contactInformation = "";
0135: this .keywords = new String[0];
0136: }
0137:
0138: /**
0139: * Creates a map context with the provided layers and title
0140: *
0141: * @param layers
0142: * DOCUMENT ME!
0143: * @deprecated
0144: */
0145: public DefaultMapContext(MapLayer[] layers) {
0146: this ();
0147: setTitle(title);
0148: addLayers(layers);
0149: }
0150:
0151: /**
0152: * Creates a map context with the provided layers and title
0153: *
0154: * @param layers
0155: * DOCUMENT ME!
0156: */
0157: public DefaultMapContext(MapLayer[] layers,
0158: final CoordinateReferenceSystem crs) {
0159: this ();
0160: this .crs = crs;
0161: setTitle(title);
0162: addLayers(layers);
0163: }
0164:
0165: /**
0166: * Creates a map context
0167: *
0168: * @param layers
0169: * DOCUMENT ME!
0170: * @param title
0171: * DOCUMENT ME!
0172: * @param contextAbstract
0173: * DOCUMENT ME!
0174: * @param contactInformation
0175: * DOCUMENT ME!
0176: * @param keywords
0177: * DOCUMENT ME!
0178: * @deprecated
0179: */
0180: public DefaultMapContext(MapLayer[] layers, String title,
0181: String contextAbstract, String contactInformation,
0182: String[] keywords) {
0183: this (layers);
0184: setTitle(title);
0185: setAbstract(contextAbstract);
0186: setContactInformation(contactInformation);
0187: setKeywords(keywords);
0188: }
0189:
0190: /**
0191: * Creates a map context
0192: *
0193: * @param layers
0194: * DOCUMENT ME!
0195: * @param title
0196: * DOCUMENT ME!
0197: * @param contextAbstract
0198: * DOCUMENT ME!
0199: * @param contactInformation
0200: * DOCUMENT ME!
0201: * @param keywords
0202: * DOCUMENT ME!
0203: */
0204: public DefaultMapContext(MapLayer[] layers, String title,
0205: String contextAbstract, String contactInformation,
0206: String[] keywords, final CoordinateReferenceSystem crs) {
0207:
0208: this (layers);
0209: this .crs = crs;
0210: setTitle(title);
0211: setAbstract(contextAbstract);
0212: setContactInformation(contactInformation);
0213: setKeywords(keywords);
0214: }
0215:
0216: /**
0217: * Add a new layer if not already present and trigger a {@link
0218: * LayerListEvent}.
0219: *
0220: * @param index
0221: * DOCUMENT ME!
0222: * @param layer
0223: * Then new layer that has been added.
0224: *
0225: * @return DOCUMENT ME!
0226: */
0227: public boolean addLayer(int index, MapLayer layer) {
0228: if (layerList.contains(layer)) {
0229: return false;
0230: }
0231:
0232: layerList.add(index, layer);
0233: // getLayerBounds();
0234: layer.addMapLayerListener(layerListener);
0235: bounds = null;
0236: fireMapLayerListListenerLayerAdded(new MapLayerListEvent(this ,
0237: layer, index));
0238:
0239: return true;
0240: }
0241:
0242: /**
0243: * Add a new layer and trigger a {@link LayerListEvent}.
0244: *
0245: * @param layer
0246: * Then new layer that has been added.
0247: *
0248: * @return DOCUMENT ME!
0249: */
0250: public boolean addLayer(MapLayer layer) {
0251: if (layerList.contains(layer)) {
0252: return false;
0253: }
0254:
0255: layerList.add(layer);
0256: // getLayerBounds();
0257: layer.addMapLayerListener(layerListener);
0258: bounds = null;
0259: fireMapLayerListListenerLayerAdded(new MapLayerListEvent(this ,
0260: layer, indexOf(layer)));
0261:
0262: return true;
0263: }
0264:
0265: /**
0266: * Add a new layer and trigger a {@link LayerListEvent}.
0267: *
0268: * @param featureSource
0269: * Then new layer that has been added.
0270: * @param style
0271: * DOCUMENT ME!
0272: */
0273: public void addLayer(FeatureSource featureSource, Style style) {
0274: this .addLayer(new DefaultMapLayer(featureSource, style, ""));
0275: }
0276:
0277: public void addLayer(CollectionSource source, Style style) {
0278: // JG: for later when feature source extends source
0279: // if( source instanceof FeatureSource){
0280: // addLayer( (FeatureSource) source, style);
0281: // }
0282: this .addLayer(new DefaultMapLayer(source, style, ""));
0283: }
0284:
0285: /**
0286: * Add a new layer and trigger a {@link LayerListEvent}.
0287: *
0288: * @param gc
0289: * Then new layer that has been added.
0290: * @param style
0291: * DOCUMENT ME!
0292: */
0293: public void addLayer(GridCoverage gc, Style style) {
0294: try {
0295: this .addLayer(CoverageUtilities.wrapGc(gc), style);
0296: } catch (TransformException e) {
0297: DefaultMapContext.LOGGER.log(Level.WARNING,
0298: "Could not use gc", e);
0299: } catch (FactoryConfigurationError e) {
0300: DefaultMapContext.LOGGER.log(Level.WARNING,
0301: "Could not use gc", e);
0302: } catch (SchemaException e) {
0303: DefaultMapContext.LOGGER.log(Level.WARNING,
0304: "Could not use gc", e);
0305: } catch (IllegalAttributeException e) {
0306: DefaultMapContext.LOGGER.log(Level.WARNING,
0307: "Could not use gc", e);
0308: ;
0309: }
0310: }
0311:
0312: /**
0313: * Add a new layer and trigger a {@link LayerListEvent}.
0314: *
0315: * @param reader
0316: * a reader with the new layer to be added.
0317: * @param style
0318: * DOCUMENT ME!
0319: */
0320: public void addLayer(AbstractGridCoverage2DReader reader,
0321: Style style) {
0322: try {
0323: this
0324: .addLayer(CoverageUtilities.wrapGcReader(reader),
0325: style);
0326: } catch (TransformException e) {
0327: DefaultMapContext.LOGGER.log(Level.WARNING,
0328: "Could not use gc", e);
0329: } catch (FactoryConfigurationError e) {
0330: DefaultMapContext.LOGGER.log(Level.WARNING,
0331: "Could not use gc", e);
0332: } catch (SchemaException e) {
0333: DefaultMapContext.LOGGER.log(Level.WARNING,
0334: "Could not use gc", e);
0335: } catch (IllegalAttributeException e) {
0336: DefaultMapContext.LOGGER.log(Level.WARNING,
0337: "Could not use gc", e);
0338:
0339: }
0340: }
0341:
0342: /**
0343: * Add a new layer and trigger a {@link LayerListEvent}.
0344: *
0345: * @param collection
0346: * Then new layer that has been added.
0347: * @param style
0348: * DOCUMENT ME!
0349: */
0350: public void addLayer(FeatureCollection collection, Style style) {
0351: this .addLayer(new DefaultMapLayer(collection, style, ""));
0352: }
0353:
0354: public void addLayer(Collection collection, Style style) {
0355: if (collection instanceof FeatureCollection) {
0356: this .addLayer(new DefaultMapLayer(
0357: (FeatureCollection) collection, style, ""));
0358: return;
0359: }
0360: this .addLayer(new DefaultMapLayer(collection, style, ""));
0361: }
0362:
0363: /**
0364: * Remove a layer and trigger a {@link LayerListEvent}.
0365: *
0366: * @param layer
0367: * Then new layer that has been removed.
0368: *
0369: * @return DOCUMENT ME!
0370: */
0371: public boolean removeLayer(MapLayer layer) {
0372: int index = indexOf(layer);
0373: // getLayerBounds();
0374: if (index == -1) {
0375: return false;
0376: } else {
0377: removeLayer(index);
0378:
0379: return true;
0380: }
0381: }
0382:
0383: /**
0384: * DOCUMENT ME!
0385: *
0386: * @param index
0387: * DOCUMENT ME!
0388: *
0389: * @return DOCUMENT ME!
0390: */
0391: public MapLayer removeLayer(int index) {
0392: MapLayer layer = (MapLayer) layerList.remove(index);
0393: // getLayerBounds();
0394: layer.removeMapLayerListener(layerListener);
0395: bounds = null;
0396: fireMapLayerListListenerLayerRemoved(new MapLayerListEvent(
0397: this , layer, index));
0398:
0399: return layer;
0400: }
0401:
0402: /**
0403: * Add an array of new layers and trigger a {@link LayerListEvent}.
0404: *
0405: * @param layers
0406: * The new layers that are to be added.
0407: *
0408: * @return DOCUMENT ME!
0409: */
0410: public int addLayers(MapLayer[] layers) {
0411: if ((layers == null) || (layers.length == 0)) {
0412: return 0;
0413: }
0414:
0415: int layerAdded = 0;
0416: MapLayer lastLayer = null;
0417: final int length = layers.length;
0418: for (int i = 0; i < length; i++) {
0419: if (!layerList.contains(layers[i])) {
0420: layerList.add(layers[i]);
0421: layerAdded++;
0422: lastLayer = layers[i];
0423: layers[i].addMapLayerListener(layerListener);
0424: }
0425: }
0426:
0427: if (layerAdded > 0) {
0428: bounds = null;
0429: int fromIndex = layerList.size() - layerAdded;
0430: int toIndex = layerList.size() - 1;
0431:
0432: if (layerAdded == 1) {
0433: fireMapLayerListListenerLayerAdded(new MapLayerListEvent(
0434: this , lastLayer, fromIndex, toIndex));
0435: } else {
0436: fireMapLayerListListenerLayerAdded(new MapLayerListEvent(
0437: this , null, fromIndex, toIndex));
0438: }
0439: }
0440:
0441: // getLayerBounds();
0442: return layerAdded;
0443: }
0444:
0445: /**
0446: * Remove an array of layers and trigger a {@link LayerListEvent}.
0447: *
0448: * @param layers
0449: * The layers that are to be removed.
0450: */
0451: public void removeLayers(MapLayer[] layers) {
0452: if ((layers == null) || (layers.length == 0)
0453: || (layerList.size() == 0)) {
0454: return;
0455: }
0456:
0457: // compute minimum and maximum index changed
0458: int fromIndex = layerList.size();
0459: int toIndex = 0;
0460: int layersRemoved = 0;
0461: int length = layers.length;
0462: for (int i = 0; i < length; i++) {
0463: int index = layerList.indexOf(layers[i]);
0464:
0465: if (index == -1) {
0466: continue;
0467: }
0468:
0469: layersRemoved++;
0470:
0471: if (index < fromIndex) {
0472: fromIndex = index;
0473: }
0474:
0475: if (index > toIndex) {
0476: toIndex = index;
0477: }
0478: }
0479: if (layersRemoved == 0)
0480: return;
0481:
0482: // remove layerslength=layers.length;
0483: for (int i = 0; i < layersRemoved; i++) {
0484: if (layerList.remove(layers[i])) {
0485: layers[i].removeMapLayerListener(layerListener);
0486: }
0487: }
0488: bounds = null;
0489: // getLayerBounds();
0490: // fire event
0491: fireMapLayerListListenerLayerRemoved(new MapLayerListEvent(
0492: this , null, fromIndex, toIndex));
0493: }
0494:
0495: /**
0496: * Return this model's list of layers. If no layers are present, then an
0497: * empty array is returned.
0498: *
0499: * @return This model's list of layers.
0500: */
0501: public MapLayer[] getLayers() {
0502: MapLayer[] layers = new MapLayer[layerList.size()];
0503:
0504: return (MapLayer[]) layerList.toArray(layers);
0505: }
0506:
0507: /**
0508: * Return the requested layer.
0509: *
0510: * @param index
0511: * index of layer to return.
0512: *
0513: * @return the layer at the specified position
0514: *
0515: * @throws IndexOutOfBoundsException
0516: * if the index is out of range
0517: */
0518: public MapLayer getLayer(int index)
0519: throws IndexOutOfBoundsException {
0520: return (MapLayer) layerList.get(index);
0521: }
0522:
0523: /**
0524: * @see org.geotools.map.MapContext#indexOf(org.geotools.map.MapLayer)
0525: */
0526: public int indexOf(MapLayer layer) {
0527: return layerList.indexOf(layer);
0528: }
0529:
0530: /**
0531: * Returns an iterator over the layers in this context in proper sequence.
0532: *
0533: * @return an iterator over the layers in this context in proper sequence.
0534: */
0535: public Iterator iterator() {
0536: return layerList.iterator();
0537: }
0538:
0539: /**
0540: * Get the bounding box of all the layers in this MapContext. If all the
0541: * layers cannot determine the bounding box in the speed required for each
0542: * layer, then null is returned. The bounds will be expressed in the
0543: * MapContext coordinate system.
0544: *
0545: * @return The bounding box of the features or null if unknown and too
0546: * expensive for the method to calculate. TODO: when coordinate
0547: * system information will be added reproject the bounds according
0548: * to the current coordinate system
0549: *
0550: * @throws IOException
0551: * DOCUMENT ME!
0552: *
0553: */
0554: public ReferencedEnvelope getLayerBounds() throws IOException {
0555: if (this .bounds != null)
0556: return this .bounds;
0557: if (this .crs == null)
0558: throw new IOException(
0559: "CRS of this map context is null. Unable to get bounds.");
0560: ReferencedEnvelope result = null;
0561:
0562: final int length = layerList.size();
0563: MapLayer layer;
0564: FeatureSource fs;
0565: ReferencedEnvelope env;
0566: CoordinateReferenceSystem sourceCrs;
0567: for (int i = 0; i < length; i++) {
0568: layer = (MapLayer) layerList.get(i);
0569: /*fs = layer.getFeatureSource();
0570: sourceCrs = fs.getSchema().getDefaultGeometry()
0571: .getCoordinateSystem();
0572: env = new ReferencedEnvelope(fs.getBounds(), sourceCrs);*/
0573:
0574: env = layer.getBounds();
0575: sourceCrs = env.getCoordinateReferenceSystem();
0576: if (env == null) {
0577: continue;
0578: } else {
0579: try {
0580:
0581: if ((sourceCrs != null)
0582: && (crs != null)
0583: && !CRS
0584: .equalsIgnoreMetadata(sourceCrs,
0585: crs)) {
0586:
0587: env = env.transform(crs, true);
0588: }
0589:
0590: } catch (FactoryException e) {
0591: LOGGER
0592: .log(
0593: Level.SEVERE,
0594: "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...",
0595: e);
0596: } catch (TransformException e) {
0597: LOGGER
0598: .log(
0599: Level.SEVERE,
0600: "Data source and map context coordinate system differ, yet it was not possible to get a projected bounds estimate...",
0601: e);
0602: }
0603:
0604: if (result == null) {
0605: result = env;
0606: } else {
0607: result.expandToInclude(env);
0608: }
0609: }
0610: }
0611:
0612: return result;
0613: }
0614:
0615: /**
0616: * Set a new area of interest and trigger a {@link BoundingBoxEvent}.
0617: *
0618: * @param areaOfInterest
0619: * The new areaOfInterest.
0620: * @param coordinateReferenceSystem
0621: * The coordinate system being using by this model.
0622: *
0623: * @throws IllegalArgumentException
0624: * if an argument is <code>null</code>.
0625: *
0626: *
0627: */
0628: public void setAreaOfInterest(Envelope areaOfInterest,
0629: CoordinateReferenceSystem coordinateReferenceSystem)
0630: throws IllegalArgumentException {
0631: if ((areaOfInterest == null)
0632: || (coordinateReferenceSystem == null)) {
0633: throw new IllegalArgumentException(
0634: "Input arguments cannot be null");
0635: }
0636:
0637: final Envelope oldAreaOfInterest = this .areaOfInterest;
0638: final CoordinateReferenceSystem oldCrs = this .crs;
0639:
0640: this .areaOfInterest = new ReferencedEnvelope(areaOfInterest,
0641: coordinateReferenceSystem);
0642: this .crs = coordinateReferenceSystem;
0643: // force computation of bounds next time someone asks them
0644: bounds = null;
0645:
0646: fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this ,
0647: MapBoundsEvent.AREA_OF_INTEREST_MASK
0648: | MapBoundsEvent.COORDINATE_SYSTEM_MASK,
0649: oldAreaOfInterest, oldCrs));
0650: }
0651:
0652: /**
0653: * Set a new area of interest and trigger an {@link BoundingBoxEvent}.
0654: *
0655: * @param areaOfInterest
0656: * The new area of interest.
0657: * @throws IllegalArgumentException
0658: * if an argument is <code>null</code>.
0659: *
0660: * @deprecated
0661: */
0662: public void setAreaOfInterest(Envelope areaOfInterest) {
0663: if (areaOfInterest == null) {
0664: throw new IllegalArgumentException(
0665: "Input argument cannot be null");
0666: }
0667:
0668: final Envelope oldAreaOfInterest = this .areaOfInterest;
0669: // this is a bad guess, I use the context crs, hopint that it is going
0670: // to be the right one
0671: this .areaOfInterest = new ReferencedEnvelope(areaOfInterest,
0672: this .crs);
0673: LOGGER.info("USing a deprecated method!");
0674:
0675: fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this ,
0676: MapBoundsEvent.AREA_OF_INTEREST_MASK,
0677: oldAreaOfInterest, this .crs));
0678: }
0679:
0680: /**
0681: * Gets the current area of interest. If no area of interest is the, the
0682: * default is to fall back on the layer bounds
0683: *
0684: * @return Current area of interest
0685: *
0686: */
0687: public ReferencedEnvelope getAreaOfInterest() {
0688: if (areaOfInterest == null) {
0689: try {
0690: final Envelope e = getLayerBounds();
0691: if (e != null)
0692: areaOfInterest = new ReferencedEnvelope(e, this .crs);
0693: else
0694: return null;
0695: } catch (IOException e) {
0696: LOGGER
0697: .log(
0698: Level.SEVERE,
0699: "Can't get layer bounds, and area of interest is not set",
0700: e);
0701:
0702: return null;
0703: }
0704: }
0705:
0706: if (areaOfInterest == null) {
0707: return null;
0708: } else {
0709: return this .areaOfInterest;
0710: }
0711: }
0712:
0713: /**
0714: * Get the current coordinate system.
0715: *
0716: * @return the coordinate system of this box.
0717: */
0718: public CoordinateReferenceSystem getCoordinateReferenceSystem() {
0719: return crs;
0720: }
0721:
0722: /**
0723: * Transform the coordinates according to the provided transform. Useful for
0724: * zooming and panning processes.
0725: *
0726: * @param transform
0727: * The transform to change area of interest.
0728: */
0729: public void transform(AffineTransform transform) {
0730: Envelope oldAreaOfInterest = this .areaOfInterest;
0731:
0732: double[] coords = new double[4];
0733: coords[0] = areaOfInterest.getMinX();
0734: coords[1] = areaOfInterest.getMinY();
0735: coords[2] = areaOfInterest.getMaxX();
0736: coords[3] = areaOfInterest.getMaxY();
0737: transform.transform(coords, 0, coords, 0, 2);
0738: this .areaOfInterest = new ReferencedEnvelope(coords[0],
0739: coords[2], coords[1], coords[3], this .crs);
0740:
0741: fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this ,
0742: MapBoundsEvent.AREA_OF_INTEREST_MASK,
0743: oldAreaOfInterest, this .crs));
0744: }
0745:
0746: /**
0747: * DOCUMENT ME!
0748: *
0749: * @param sourcePosition
0750: * DOCUMENT ME!
0751: * @param destPosition
0752: * DOCUMENT ME!
0753: *
0754: * @throws IndexOutOfBoundsException
0755: * DOCUMENT ME!
0756: */
0757: public void moveLayer(int sourcePosition, int destPosition) {
0758: if ((sourcePosition < 0)
0759: || (sourcePosition >= layerList.size())) {
0760: throw new IndexOutOfBoundsException("Source position "
0761: + sourcePosition + " out of bounds");
0762: }
0763:
0764: if ((destPosition < 0) || (destPosition >= layerList.size())) {
0765: throw new IndexOutOfBoundsException("Destination position "
0766: + destPosition + " out of bounds");
0767: }
0768:
0769: MapLayer layer = (MapLayer) layerList.remove(sourcePosition);
0770: layerList.add(destPosition, layer);
0771: fireMapLayerListListenerLayerMoved(new MapLayerListEvent(this ,
0772: layer, Math.min(sourcePosition, destPosition), Math
0773: .max(sourcePosition, destPosition)));
0774: }
0775:
0776: /**
0777: * DOCUMENT ME!
0778: */
0779: public void clearLayerList() {
0780: final int size = layerList.size();
0781: for (int i = 0; i < size; i++) {
0782: MapLayer layer = (MapLayer) layerList.get(i);
0783: layer.removeMapLayerListener(layerListener);
0784: }
0785:
0786: layerList.clear();
0787: bounds = null;
0788: fireMapLayerListListenerLayerRemoved(new MapLayerListEvent(
0789: this , null, 0, 1));
0790: }
0791:
0792: /**
0793: * Returns the number of layers in this map context
0794: *
0795: * @return the number of layers in this map context
0796: */
0797: public int getLayerCount() {
0798: return layerList.size();
0799: }
0800:
0801: /**
0802: * Getter for property abstracts.
0803: *
0804: * @return Value of property abstracts.
0805: */
0806: public String getAbstract() {
0807: return this .abstracts;
0808: }
0809:
0810: /**
0811: * Setter for property abstracts.
0812: *
0813: * @param abstractValue
0814: * New value of property abstracts.
0815: *
0816: * @throws NullPointerException
0817: * DOCUMENT ME!
0818: */
0819: public void setAbstract(String abstractValue) {
0820: if (abstractValue == null) {
0821: throw new NullPointerException();
0822: }
0823:
0824: String oldAbstracts = this .abstracts;
0825: this .abstracts = abstractValue;
0826: propertyChangeSupport.firePropertyChange("abstract",
0827: oldAbstracts, abstracts);
0828: }
0829:
0830: /**
0831: * Getter for property contactInformation.
0832: *
0833: * @return Value of property contactInformation.
0834: */
0835: public String getContactInformation() {
0836: return this .contactInformation;
0837: }
0838:
0839: /**
0840: * Setter for property contactInformation.
0841: *
0842: * @param contactInformation
0843: * New value of property contactInformation.
0844: *
0845: * @throws NullPointerException
0846: * DOCUMENT ME!
0847: */
0848: public void setContactInformation(String contactInformation) {
0849: if (contactInformation == null) {
0850: throw new NullPointerException();
0851: }
0852:
0853: String oldContactInformation = this .contactInformation;
0854: this .contactInformation = contactInformation;
0855: propertyChangeSupport.firePropertyChange("contactInformation",
0856: oldContactInformation, contactInformation);
0857: }
0858:
0859: /**
0860: * Getter for property keywords.
0861: *
0862: * @return Value of property keywords.
0863: */
0864: public String[] getKeywords() {
0865: if (this .keywords.length == 0) {
0866: return this .keywords;
0867: } else {
0868: String[] copy = new String[keywords.length];
0869: System.arraycopy(keywords, 0, copy, 0, keywords.length);
0870:
0871: return copy;
0872: }
0873: }
0874:
0875: /**
0876: * Setter for property keywords.
0877: *
0878: * @param keywords
0879: * New value of property keywords.
0880: *
0881: * @throws NullPointerException
0882: * DOCUMENT ME!
0883: */
0884: public void setKeywords(String[] keywords) {
0885: if (keywords == null) {
0886: throw new NullPointerException();
0887: }
0888:
0889: String[] oldKeywords = this .keywords;
0890: this .keywords = keywords;
0891: propertyChangeSupport.firePropertyChange("keywords",
0892: oldKeywords, keywords);
0893: }
0894:
0895: /**
0896: * Getter for property title.
0897: *
0898: * @return Value of property title.
0899: */
0900: public String getTitle() {
0901: return this .title;
0902: }
0903:
0904: /**
0905: * Setter for property title.
0906: *
0907: * @param title
0908: * New value of property title.
0909: *
0910: * @throws NullPointerException
0911: * DOCUMENT ME!
0912: */
0913: public void setTitle(String title) {
0914: if (title == null) {
0915: throw new NullPointerException();
0916: }
0917:
0918: String oldTitle = this .title;
0919: this .title = title;
0920: propertyChangeSupport.firePropertyChange("title", oldTitle,
0921: title);
0922: }
0923:
0924: // ------------------------------------------------------------------------
0925: // EVENT LISTENERS AND EVENT FIRING CODE
0926: // ------------------------------------------------------------------------
0927:
0928: /**
0929: * Registers MapLayerListListener to receive events.
0930: *
0931: * @param listener
0932: * The listener to register.
0933: */
0934: public synchronized void addMapLayerListListener(
0935: org.geotools.map.event.MapLayerListListener listener) {
0936: if (listenerList == null) {
0937: listenerList = new javax.swing.event.EventListenerList();
0938: }
0939:
0940: listenerList.add(
0941: org.geotools.map.event.MapLayerListListener.class,
0942: listener);
0943: }
0944:
0945: /**
0946: * Removes MapLayerListListener from the list of listeners.
0947: *
0948: * @param listener
0949: * The listener to remove.
0950: */
0951: public synchronized void removeMapLayerListListener(
0952: org.geotools.map.event.MapLayerListListener listener) {
0953: if (listenerList == null) {
0954: return;
0955: }
0956:
0957: listenerList.remove(
0958: org.geotools.map.event.MapLayerListListener.class,
0959: listener);
0960: }
0961:
0962: /**
0963: * Notifies all registered listeners about the event.
0964: *
0965: * @param event
0966: * The event to be fired
0967: */
0968: private void fireMapLayerListListenerLayerAdded(
0969: org.geotools.map.event.MapLayerListEvent event) {
0970: if (listenerList == null) {
0971: return;
0972: }
0973:
0974: Object[] listeners = listenerList.getListenerList();
0975: final int length = listeners.length;
0976: for (int i = length - 2; i >= 0; i -= 2) {
0977: if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) {
0978: ((org.geotools.map.event.MapLayerListListener) listeners[i + 1])
0979: .layerAdded(event);
0980: }
0981: }
0982: }
0983:
0984: /**
0985: * Notifies all registered listeners about the event.
0986: *
0987: * @param event
0988: * The event to be fired
0989: */
0990: private void fireMapLayerListListenerLayerRemoved(
0991: org.geotools.map.event.MapLayerListEvent event) {
0992: if (listenerList == null) {
0993: return;
0994: }
0995:
0996: Object[] listeners = listenerList.getListenerList();
0997: final int length = listeners.length;
0998: for (int i = length - 2; i >= 0; i -= 2) {
0999: if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) {
1000: ((org.geotools.map.event.MapLayerListListener) listeners[i + 1])
1001: .layerRemoved(event);
1002: }
1003: }
1004: }
1005:
1006: /**
1007: * Notifies all registered listeners about the event.
1008: *
1009: * @param event
1010: * The event to be fired
1011: */
1012: private void fireMapLayerListListenerLayerChanged(
1013: org.geotools.map.event.MapLayerListEvent event) {
1014: if (listenerList == null) {
1015: return;
1016: }
1017:
1018: Object[] listeners = listenerList.getListenerList();
1019: final int length = listeners.length;
1020: for (int i = length - 2; i >= 0; i -= 2) {
1021: if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) {
1022: ((org.geotools.map.event.MapLayerListListener) listeners[i + 1])
1023: .layerChanged(event);
1024: }
1025: }
1026: }
1027:
1028: /**
1029: * Notifies all registered listeners about the event.
1030: *
1031: * @param event
1032: * The event to be fired
1033: */
1034: private void fireMapLayerListListenerLayerMoved(
1035: org.geotools.map.event.MapLayerListEvent event) {
1036: if (listenerList == null) {
1037: return;
1038: }
1039:
1040: Object[] listeners = listenerList.getListenerList();
1041: final int length = listeners.length;
1042: for (int i = length - 2; i >= 0; i -= 2) {
1043: if (listeners[i] == org.geotools.map.event.MapLayerListListener.class) {
1044: ((org.geotools.map.event.MapLayerListListener) listeners[i + 1])
1045: .layerMoved(event);
1046: }
1047: }
1048: }
1049:
1050: /**
1051: * Registers PropertyChangeListener to receive events.
1052: *
1053: * @param listener
1054: * The listener to register.
1055: */
1056: public synchronized void addPropertyChangeListener(
1057: java.beans.PropertyChangeListener listener) {
1058: propertyChangeSupport.addPropertyChangeListener(listener);
1059: }
1060:
1061: /**
1062: * Removes PropertyChangeListener from the list of listeners.
1063: *
1064: * @param listener
1065: * The listener to remove.
1066: */
1067: public synchronized void removePropertyChangeListener(
1068: java.beans.PropertyChangeListener listener) {
1069: if (listenerList == null) {
1070: return;
1071: }
1072:
1073: propertyChangeSupport.removePropertyChangeListener(listener);
1074: }
1075:
1076: /**
1077: * Registers MapBoundsListener to receive events.
1078: *
1079: * @param listener
1080: * The listener to register.
1081: */
1082: public synchronized void addMapBoundsListener(
1083: org.geotools.map.event.MapBoundsListener listener) {
1084: if (listenerList == null) {
1085: listenerList = new javax.swing.event.EventListenerList();
1086: }
1087:
1088: listenerList.add(
1089: org.geotools.map.event.MapBoundsListener.class,
1090: listener);
1091: }
1092:
1093: /**
1094: * Removes MapBoundsListener from the list of listeners.
1095: *
1096: * @param listener
1097: * The listener to remove.
1098: */
1099: public synchronized void removeMapBoundsListener(
1100: org.geotools.map.event.MapBoundsListener listener) {
1101: if (listenerList == null) {
1102: return;
1103: }
1104:
1105: listenerList.remove(
1106: org.geotools.map.event.MapBoundsListener.class,
1107: listener);
1108: }
1109:
1110: /**
1111: * Notifies all registered listeners about the event.
1112: *
1113: * @param event
1114: * The event to be fired
1115: */
1116: private void fireMapBoundsListenerMapBoundsChanged(
1117: org.geotools.map.event.MapBoundsEvent event) {
1118: if (listenerList == null) {
1119: return;
1120: }
1121:
1122: Object[] listeners = listenerList.getListenerList();
1123: final int length = listeners.length;
1124: for (int i = length - 2; i >= 0; i -= 2) {
1125: if (listeners[i] == org.geotools.map.event.MapBoundsListener.class) {
1126: ((org.geotools.map.event.MapBoundsListener) listeners[i + 1])
1127: .mapBoundsChanged(event);
1128: }
1129: }
1130: }
1131:
1132: /**
1133: * Set a new area of interest and trigger an {@link BoundingBoxEvent}.
1134: *
1135: * @param areaOfInterest
1136: * The new area of interest.
1137: *
1138: * @throws NullPointerException
1139: * DOCUMENT ME!
1140: *
1141: *
1142: */
1143: public void setAreaOfInterest(ReferencedEnvelope areaOfInterest) {
1144: if (areaOfInterest == null) {
1145: throw new IllegalArgumentException(
1146: "Input argument cannot be null");
1147: }
1148:
1149: final Envelope oldAreaOfInterest = this .areaOfInterest;
1150: final CoordinateReferenceSystem tempCRS = areaOfInterest
1151: .getCoordinateReferenceSystem();
1152: if (tempCRS == null) {
1153: throw new IllegalArgumentException(
1154: "CRS of the provided AOI cannot be null");
1155: }
1156: final CoordinateReferenceSystem oldCRS = this .crs;
1157: this .crs = tempCRS;
1158: this .areaOfInterest = new ReferencedEnvelope(
1159: (Envelope) areaOfInterest, this .crs);
1160: // force computation of bounds next time someone asks them
1161: bounds = null;
1162:
1163: fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this ,
1164: MapBoundsEvent.AREA_OF_INTEREST_MASK
1165: | MapBoundsEvent.COORDINATE_SYSTEM_MASK,
1166: oldAreaOfInterest, oldCRS));
1167:
1168: }
1169:
1170: /**
1171: * @throws FactoryException
1172: * @throws TransformException
1173: *
1174: */
1175: public void setCoordinateReferenceSystem(
1176: CoordinateReferenceSystem crs) throws TransformException,
1177: FactoryException {
1178: if (crs == null) {
1179: throw new IllegalArgumentException(
1180: "Input argument cannot be null");
1181: }
1182:
1183: final Envelope oldBounds = this .areaOfInterest;
1184: final CoordinateReferenceSystem oldCRS = this .crs;
1185: this .bounds = null;
1186: if (!CRS.equalsIgnoreMetadata(crs, this .crs)
1187: && this .areaOfInterest != null)
1188: this .areaOfInterest = this .areaOfInterest.transform(crs,
1189: true);
1190: this .crs = crs;
1191: this .bounds = null;
1192:
1193: fireMapBoundsListenerMapBoundsChanged(new MapBoundsEvent(this,
1194: MapBoundsEvent.COORDINATE_SYSTEM_MASK, oldBounds,
1195: oldCRS));
1196:
1197: }
1198:
1199: }
|