/******************************************************************************* * Copyright (c) 2010 Stefan A. Tzeggai. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Stefan A. Tzeggai - initial API and implementation ******************************************************************************/ package org.geopublishing.atlasViewer.map; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; import org.apache.log4j.Logger; import org.geopublishing.atlasViewer.AtlasConfig; import org.geopublishing.atlasViewer.JNLPUtil; import org.geopublishing.atlasViewer.dp.DpEntry; import org.geopublishing.atlasViewer.dp.DpRef; import org.geopublishing.atlasViewer.dp.layer.DpLayer; import org.geopublishing.atlasViewer.dp.layer.LayerStyle; import org.geopublishing.atlasViewer.dp.media.DpMedia; import org.geopublishing.atlasViewer.http.AtlasProtocol; import org.geopublishing.atlasViewer.http.Webserver; import org.geopublishing.atlasViewer.swing.JNLPSwingUtil; import org.geopublishing.geopublisher.GpUtil; import org.geotools.map.MapContext; import org.geotools.referencing.CRS; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Envelope; import de.schmitzm.data.Copyable; import de.schmitzm.geotools.gui.GeotoolsGUIUtil; import de.schmitzm.geotools.gui.GridPanel; import de.schmitzm.geotools.gui.GridPanelFormatter; import de.schmitzm.geotools.gui.MapView; import de.schmitzm.geotools.gui.ScalePane; import de.schmitzm.geotools.gui.ScalePanel.ScaleUnits; import de.schmitzm.geotools.io.GeoImportUtil; import de.schmitzm.i18n.I18NUtil; import de.schmitzm.i18n.Translation; import de.schmitzm.jfree.chart.style.ChartStyle; import de.schmitzm.swing.swingworker.AtlasStatusDialogInterface; /** * A {@link Map} is a collection of references to {@link DpEntry} and HTML info * pages The {@link MapView} can present a {@link Map} * * @author Stefan Alfons Tzeggai * */ public class Map extends DefaultMutableTreeNode implements Comparable<Object>, Copyable<Map> { final static private Logger LOGGER = Logger.getLogger(Map.class); public static final String GRIDPANEL_CRS_FILENAME = "gridPanel.prj"; /** * A list that holds the {@link DpRef} s that are of type {@link DpLayer} */ private List<DpRef<DpLayer<?, ? extends ChartStyle>>> layers = new LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>>(); /** * Define a preferred ratio between the left and right components of the * MapView. If <code>null</code> or 0f it will use the automatic mode. */ private Double leftRightRatio = 0.; /** * A list that holds the {@link DpRef} s that are of type {@link DpMedia} */ List<DpRef<DpMedia<? extends ChartStyle>>> media = new LinkedList<DpRef<DpMedia<? extends ChartStyle>>>(); private Translation title = new Translation(), desc = new Translation(), keywords = new Translation(); final private java.util.Map<String, Boolean> minimizedInLegendMap = new HashMap<String, Boolean>(); final private java.util.Map<String, Boolean> hideInLegendMap = new HashMap<String, Boolean>(); final private java.util.Map<String, Boolean> hidden = new HashMap<String, Boolean>(); final private java.util.Map<String, Boolean> selectable = new HashMap<String, Boolean>(); /** A map has an unique ID {@link String} */ private String id; /** The default MapArea to show when the map opens * */ private Envelope defaultMapArea; /** A link to the {@link AtlasConfig} where this {@link Map} is configured. **/ private AtlasConfig ac = null; /** Shall the map scale be visible? **/ private boolean scaleVisible = true; /** Shall the horiz. and vertical {@link GridPanel}s be visible at all? **/ private boolean gridPanelVisible = true; /** * The {@link CoordinateReferenceSystem} used in the horiz. and vertical * {@link GridPanel}s **/ private CoordinateReferenceSystem gridPanelCRS = GeoImportUtil .getDefaultCRS(); /** * The {@link GridPanelFormatter} used in the horiz. and vertical * {@link GridPanel}s **/ private GridPanelFormatter gridPanelFormatter; /** * Creates a {@link Map}. The ID may not start with a number! */ public Map(final String id, final AtlasConfig ac) { if (!id.startsWith("map")) throw new IllegalArgumentException( "Map IDs have to start with 'map'"); this.id = id; this.ac = ac; } /** * Creates a {@link Map} and defines a random ID */ public Map(final AtlasConfig ac) { this(GpUtil.getRandomID("map"), ac); } /** * This {@link java.util.Map} holds a {@link List} of {@link ChartStyle}-IDs * for every {@link DpLayer} (referred to by its ID) * */ final private java.util.Map<String, ArrayList<String>> availableCharts = new HashMap<String, ArrayList<String>>(); /** * This {@link java.util.Map} holds a {@link List} of {@link LayerStyle}-IDs * for every {@link DpLayer} (referred to by its ID) * */ private final java.util.Map<String, ArrayList<String>> additionalStyles = new HashMap<String, ArrayList<String>>(); /** This {@link java.util.Map} links LayerIDs to {@link LayerStyle} - IDs * */ volatile private java.util.Map<String, String> selectedStyleID = new HashMap<String, String>(); volatile private ArrayList<String> missingHTMLLanguages; /** * The biggest visible extend for this map. If <code>null</code>, the user * may zoom out as much as he wants. **/ private Envelope maxExtend = null; /** The units to show the scale in **/ private ScaleUnits scaleUnits = ScaleUnits.METRIC; /** * If <code>true</code>, the max. map extend will be applied in the * MapComposer. Otherwise it will will only be applied in the exported Atlas **/ private boolean previewMapExtendInGeopublisher = false; private Double quality; long qualityLastCalced; /** * Caches a list of all CRS names used in this map */ private ArrayList<String> cacheUsedCrs; /** * Remebers when this list has been calculated the last time */ private long cacheUsedCrsLastCheckedTime; /** * Resets the cache that remembers for which languages the HTML info pages * exist. */ public void resetMissingHTMLinfos() { missingHTMLLanguages = null; } /** * Removes all Layers aka DpLayerReferences from the {@link Map} */ public void clearLayerList() { layers.clear(); } /** * Removes all memory-intensive cached objects that are not needed by the * {@link Map} newMap * * @param newMap * If <code>null</code>, then all referenced {@link DpEntry}s are * uncached.. * */ public void uncache(final Map newMap) { // LOGGER.debug("Uncaching map " + getId() + " aka " + getTitle()); List<DpRef<DpLayer<?, ? extends ChartStyle>>> newLayers; List<DpRef<DpMedia<? extends ChartStyle>>> newMedia; if (newMap != null) { newLayers = newMap.getLayers(); newMedia = newMap.getMedia(); } else { // Creates them empty so all DpEnties are uncached.. newLayers = new LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>>(); newMedia = new LinkedList<DpRef<DpMedia<? extends ChartStyle>>>(); } // Uncaching all DpMedia if not needed in next Map for (final DpRef<DpMedia<? extends ChartStyle>> dpr : getMedia()) { if (!newMedia.contains(dpr)) dpr.getTarget().uncache(); } // Uncaching all DpLayers if not needed in next Map for (final DpRef<DpLayer<?, ? extends ChartStyle>> dpr : getLayers()) { if (!newLayers.contains(dpr)) dpr.getTarget().uncache(); // Forget about the style changes. This may not be called from GP! dpr.getTarget().resetStyleChanges(); } cacheUsedCrs = null; quality = null; } /** * Ideally a {@link Map} only uses one CRS, as especially raster re-sampling * is very slow If first layer is always defining the CRS.. so moving the * layers can change the base CRS! * * @return null if no Layer is set yet */ public CoordinateReferenceSystem getLayer0Crs() { // TODO Add a forceCrs as a Map property! final int size = getLayers().size(); if (size > 0) { // The last layer's CRS equals the first layer in the MapContext return (getLayers().get(size - 1).getTarget()).getCrs(); } return null; } @Override /* * id and number of layers must equal */ public boolean equals(final Object obj) { if (obj instanceof Map) { final Map map = (Map) obj; return map.getId().equals(getId()) && map.getLayers().size() == getLayers().size() && map.getMedia().size() == getMedia().size(); } return super.equals(obj); } @Override public int hashCode() { return super.hashCode() * getId().hashCode() * getLayers().size() * 52 * getMedia().size() * 7; } /** * creates a new {@link Map} object with the same parameters and the same * id! change the id before adding it to the mapPool * * @return */ @Override public Map copy() { // final Map newMap = (Map) super.clone(); final Map newMap = new Map(id, getAc()); // newMap.setId(id); // newMap.setAtlasConfig(getAc()); copyTo(newMap); return newMap; } /** * Define the AtlasConfig this {@link Map} belongs to. Primarely written for * importing maps from other atlases. */ public void setAtlasConfig(final AtlasConfig newAtlasConfig) { ac = newAtlasConfig; } /** * Add a {@link DpRef} to the {@link Map} Used when loading or editing the * {@link Map} This method identifies the reference as either Layer or * Media.. The first Ref to a {@link DpLayer} sets the CRS for this * {@link Map} * * @param dpRef * {@link DpRef} to add. */ public void add(final DpRef<DpEntry<? extends ChartStyle>> dpRef) { add(dpRef, -1); } /** * Add a {@link DpRef} to the {@link Map} at the given position Used when * loading or editing the {@link Map} This method identifies the reference * as either Layer or Media.. The first Ref to a {@link DpLayer} sets the * CRS for this {@link Map} * * @param dpRef * {@link DpRef} to add. */ public void add(final DpRef dpRef, int whereIdx) { if ((whereIdx < 0) || (whereIdx > getLayers().size())) { whereIdx = getLayers().size(); } final DpEntry<?> dpe = dpRef.getTarget(); if (dpe.isLayer()) { layers.add(whereIdx, dpRef); } else { media.add(whereIdx, dpRef); } } final public Translation getTitle() { return title; } final public Translation getDesc() { return desc; } final public String getId() { return id; } final public void setId(final String id) { this.id = id; } final public void setTitle(final Translation title) { this.title = title; } final public void setDesc(final Translation desc) { this.desc = desc; } @Override final public String toString() { String returnStr = ""; if (!I18NUtil.isEmpty(title)) return returnStr += title.toString() + ", "; returnStr += ", ID=" + getId(); if (!I18NUtil.isEmpty(desc)) returnStr += ", Desc=" + getDesc(); return returnStr; } /* * (non-Javadoc) * * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override final public int compareTo(final Object o) { if (o instanceof Map) { final Map map = (Map) o; if (map.getTitle() != null) { // Internationalisierte Sortierung ;-) return (map.getTitle().toString().compareTo(title.toString())); } return (map.getId().compareTo(id)); } return 0; } final public Translation getKeywords() { return keywords; } final public void setKeywords(final Translation keywords) { this.keywords = keywords; } /** * Returns the {@link List} of {@link DpRef} to all {@link DpLayer}s * referenced by this {@link Map}. */ final public List<DpRef<DpLayer<?, ? extends ChartStyle>>> getLayers() { return layers; } final public void setLayers( final LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>> newLayers) { this.layers = newLayers; } /** * Returns the {@link List} of {@link DpRef} to {@link DpMedia} referenced * by this {@link Map}. */ final public List<DpRef<DpMedia<? extends ChartStyle>>> getMedia() { return media; } /** * Returns a {@link List} of {@link DpRef} to all Layers and Media (DpEntry) * referenced by this map. */ final public List<DpRef<?>> getDpes() { List<DpRef<?>> allEntries = new ArrayList<DpRef<?>>(); allEntries.addAll(getLayers()); allEntries.addAll(getMedia()); return allEntries; } /** * Set the List of {@link DpRef}s that are Media and are related to this * {@link Map} * * @param media */ final public void setMedia( final List<DpRef<DpMedia<? extends ChartStyle>>> media) { this.media = media; } /** * Returns true if the Ref is already in the map * * @param datapoolRef */ final public boolean has(final DpRef datapoolRef) { for (final DpRef dpr : layers) { if (dpr.equals(datapoolRef)) return true; } for (final DpRef dpr : media) { if (dpr.equals(datapoolRef)) return true; } return false; } /** * @return A {@link URL} to the HTML info for this {@link Map}. The * {@link URL} will point to a <code>index_LANGCODE.html</code> * file. <code>null</code> is returned, if no html file is found for * the active language. */ final public URL getInfoURL() { // LOGGER.debug("Map info URL = " // + getInfoURL(Translation.getActiveLang())); return getInfoURL(Translation.getActiveLang()); } /** * @return A {@link URL} to the HTML info for this {@link Map}. The * {@link URL} will point to a <code>index_LANGCODE.html</code> * file. <code>null</code> is returned, if no HTML file is found for * the active language. */ public URL getInfoURL(final String activeLang) { // That was too slow String: // urlString = Webserver.getDocumentBase() + "/" + // getId() + "/" + "index.html"; final String urlString = "http://127.0.0.1:" + Webserver.PORT + "/" + AtlasConfig.ATLASDATA_DIRNAME + "/" + AtlasConfig.HTML_DIRNAME + "/" + getId() + "/" + "index_" + activeLang + ".html"; // LOGGER.debug("URLstring fuer HTML mapinfo = " + urlString); try { final URL url = new URL(urlString); url.openStream().close(); return url; } catch (final IOException ee) { // LOGGER.debug("Not possible to access " + urlString, ee); // That is OK. They don't have to exist. return null; } } /** * Retunes the default MapArea (which will be shown when the Map starts...) */ public Envelope getDefaultMapArea() { return defaultMapArea; } /** * Define the default MapArea (to start the Map with...) */ public void setDefaultMapArea(final Envelope envelope) { this.defaultMapArea = envelope; } /** * This {@link java.util.Map} holds a {@link List} of {@link LayerStyle}-IDs * for every {@link DpLayer} (refered to by its ID). The list of IDs is a * subset of all IDs available for that layer. Only the available styles are * listed here. */ public java.util.Map<String, ArrayList<String>> getAdditionalStyles() { return additionalStyles; } /** * Tell the map, which user defined style to use * * @param styleID * #Filename of {@link LayerStyle} or <code>null</code> for * default. * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public void setSelectedStyleID(final String layerID, final String styleID) { LOGGER.debug("setSelectedStyleID for layerID " + layerID + " => " + styleID + " MAP=" + this); selectedStyleID.put(layerID, styleID); } /** * Which user defined style ID is selected at the moment (or which to use as * default). * * @return <code>null</code> if no layer is selected, or no additional * layers exist. * * @param styleID * #Filename of {@link LayerStyle} or <code>null</code> for * default. * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public String getSelectedStyleID(final String layerID) { // LOGGER.debug("getSelectedStyleID for layerID " + layerID + " =" // + selectedStyleID.get(layerID)); return selectedStyleID.get(layerID); } /** * Which user defined style is selected at the moment (or which to use as * default). * * @return <code>null</code> if no additional layers exist. * * @param styleID * #Filename of {@link LayerStyle} or <code>null</code> for * default. * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public LayerStyle getSelectedStyle(final String layerID) { final String lsID = getSelectedStyleID(layerID); if (lsID == null) return null; // for (final DpRef<DpLayer<?, ? extends ChartStyle>> dpr : getLayers()) // { // if (dpr.getTargetId().equals(layerID)) { // final DpLayer<?, ? extends ChartStyle> target = dpr.getTarget(); // // if (target instanceof DpLayer) { // final DpLayer<?, ? extends ChartStyle> dpl = target; final DpEntry<? extends ChartStyle> dpEntry = ac.getDataPool().get( layerID); return ((DpLayer) dpEntry).getLayerStyleByID(lsID); // } // // } // } // return null; } public java.util.Map<String, String> getSelectedStyleIDs() { return selectedStyleID; } /** * If we are in JWS mode, check if parts of the {@link Map} have to be * downloaded and download them all together * * @param owner * GUI element to refer to * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> * * @throws IOException * JWS is used and data is not cached and we can't download it! */ public void downloadMap(final AtlasStatusDialogInterface statusDialog) throws IOException { /** * Create a list of uncached parts */ final String[] partsToDownload = JNLPUtil.countPartsToDownload(this); if (partsToDownload.length == 0) { // All is cached LOGGER.debug(" all is cached."); return; } JNLPSwingUtil.loadPart(partsToDownload, statusDialog); } /** * @return A {@link Double} value (quality index) representing how much * metadata has been created for this {@link Map} */ public Double getQuality() { // long start = System.currentTimeMillis(); if (quality == null || (System.currentTimeMillis() - qualityLastCalced) > 1000) { qualityLastCalced = System.currentTimeMillis(); final List<String> languages = ac.getLanguages(); final double qmTitle = I18NUtil .qmTranslation(languages, getTitle()); final double qmDesc = I18NUtil.qmTranslation(languages, getDesc()); // final double qmKeywords = I18NUtil.qmTranslation(languages, // getKeywords()); double qmKeywords = 1; /** * Count HTML Infos */ final double countHTMLexist = (double) languages.size() - (double) getMissingHTMLLanguages().size(); final double qmHTML = countHTMLexist / ac.getLanguages().size(); final double qmMap = (qmTitle * 4. + qmDesc * 2. + qmKeywords * 1. + qmHTML * 4.) / 11.; Double averageLayerQuality = 0.; if (getLayers().size() > 0) { averageLayerQuality = getAverageLayerQuality(); } quality = (averageLayerQuality * 3. + qmMap * 1.) / 4.; // Subtract 20% if MaxExtend is not set. if (getMaxExtend() == null) { quality *= 0.8; } } // System.out.println(System.currentTimeMillis()-start); return quality; } /** * @return A {@link List<String>} of language codes that can't be found as * HTML info files. */ public List<String> getMissingHTMLLanguages() { // if (missingHTMLLanguages == null) { missingHTMLLanguages = new ArrayList<String>(); // synchronized (missingHTMLLanguages) { for (final String l : getAc().getLanguages()) { if (getInfoURL(l) == null) { missingHTMLLanguages.add(l); } } // } // } return missingHTMLLanguages; } /** * @return the {@link AtlasConfig} where this map is described. */ public AtlasConfig getAc() { return ac; } /** * @return the average quality index of the layers in this {@link Map} */ public Double getAverageLayerQuality() { if (getLayers().size() == 0) return null; Double averageLayerQM = 0.; for (final DpRef dpr : getLayers()) { averageLayerQM += dpr.getTarget().getQuality(); } return averageLayerQM / getLayers().size(); } /** * @return A {@link java.util.Map} which knows which Layers should start * minimized in the legend {@link MapContext} */ public java.util.Map<String, Boolean> getMinimizedInLegendMap() { return minimizedInLegendMap; } /** * @return A {@link java.util.Map} which knows which Layers should not * appear in the legend, even though they are part of the * {@link MapContext} */ public java.util.Map<String, Boolean> getHideInLegendMap() { return hideInLegendMap; } /** * @return Is this layer k in the legend for the given DpEntry-IDs. Never * returns <code>null</code>. */ public boolean getHideInLegendFor(final String id) { return hideInLegendMap.get(id) != null ? hideInLegendMap.get(id) : false; } /** * Define a preferred ratio between the left and right components of the * MapView. If <code>null</code> or 0f it will use the automatic mode. */ public void setLeftRightRatio(final Double leftRightRatio) { this.leftRightRatio = leftRightRatio; } /** * The preferred ratio between the left and right components of the MapView. * If <code>null</code> or 0f it will use the automatic mode. */ public Double getLeftRightRatio() { return leftRightRatio; } /** * Define if a layer of this {@link Map} shall start as a hidden layer in * AV, that means with the eye symbol closed. * * @param id * ID of the layer to be queried. * @return never <code>null</code>. <code>false</code> is default. */ public Boolean getHiddenFor(final String id) { return hidden.get(id) != null ? hidden.get(id) : false; } public void setHiddenFor(final String id, final Boolean isHidden) { hidden.put(id, isHidden); } /** * HashMap of DpLayerID <-> List of ChartStyle-IDs that are available for * viewing in this layer */ public java.util.Map<String, ArrayList<String>> getAvailableCharts() { return availableCharts; } /** * List of {@link ChartStyle}-IDs that are available in this {@link Map} for * the given {@link DpLayer}. * * @return never <code>null</code>, but rather an empty list. */ public ArrayList<String> getAvailableChartIDsFor(final String dpLayerID) { if (!availableCharts.containsKey(dpLayerID)) { // To avoid null checks, we create an empty ArrayList here and // insert it into the Map final ArrayList<String> arrayList = new ArrayList<String>(); availableCharts.put(dpLayerID, arrayList); } final ArrayList<String> availChartsForLayer = availableCharts .get(dpLayerID); /** * Now we double check, that all IDs are returned, that really still * exist. */ final ArrayList<String> clone = (ArrayList<String>) availChartsForLayer .clone(); availChartsForLayer.clear(); for (String id : clone) { final DpEntry<? extends ChartStyle> dpEntry = ac.getDataPool().get( dpLayerID); for (ChartStyle cs : dpEntry.getCharts()) { if (cs.getID().equals(id)) { if (!availChartsForLayer.contains(id)) availChartsForLayer.add(id); continue; } } } // System.out.println("avail:"+availChartsForLayer.size()+" "+availChartsForLayer); return availChartsForLayer; } /** * Returns true if the Map referenced this {@link DpEntry} as a layer oder * media. */ public boolean containsDpe(final String dpeId) { /* Scan the layers */ for (final DpRef<DpLayer<?, ? extends ChartStyle>> dpr : getLayers()) { if (dpr.getTargetId().equals(dpeId)) return true; } /* Scan the media */ for (final DpRef<DpMedia<? extends ChartStyle>> dpr : getMedia()) { if (dpr.getTargetId().equals(dpeId)) return true; } return false; } /** * Defines whether a given LayerID will be selectable in this map. * Selectablility/Clickablility concerns the ClickInfo tool. * * @param dpeId * The ID of the layer / dpe * @param isSelectable * If <code>true</code>, the layer is searched when clicking with * InfoClickTool */ public void setSelectableFor(final String dpeId, final Boolean isSelectable) { selectable.put(dpeId, isSelectable); } /** * Returns whether the layer identified by the id is selectable with the * InfoClickTool. Default is <code>true</code>. * * @param dpeId * The ID of the layer / dpe */ public Boolean isSelectableFor(final String dpeId) { return selectable.get(dpeId) == null ? Boolean.TRUE : selectable .get(dpeId); } /** * Defines the biggest visible envelope in the map. The user will not be * able to zoom out to see anything outside this area. */ public void setMaxExtend(Envelope envelope) { maxExtend = envelope; } /** * Returns the biggest visible envelope in the map. The user will not be * able to zoom out to see anything outside this area. If <code>null</code>, * the user may zoom out as much as she wants. */ public Envelope getMaxExtend() { return maxExtend; } public void setGridPanelVisible(boolean gridPanelVisible) { this.gridPanelVisible = gridPanelVisible; } public boolean isGridPanelVisible() { return gridPanelVisible; } public void setGridPanelCRS(CoordinateReferenceSystem gridPanelCRS) { this.gridPanelCRS = gridPanelCRS; } public CoordinateReferenceSystem getGridPanelCRS() { return gridPanelCRS; } public void setGridPanelFormatter(GridPanelFormatter gridPanelFormatter) { this.gridPanelFormatter = gridPanelFormatter; } /** * Returns an instance of the {@link GridPanelFormatter} that shall be used * for the map. */ public GridPanelFormatter getGridPanelFormatter() { // Usually the gridPanelFormatter is set while loading the atlas if (gridPanelFormatter == null) // this is just a fallback for new maps try { gridPanelFormatter = GridPanelFormatter.FORMATTERS[0] .newInstance(); } catch (Exception e) { throw new RuntimeException(e); } return gridPanelFormatter; } /** * Shall a scale be shown in the map window? */ public void setScaleVisible(boolean scaleVisible) { this.scaleVisible = scaleVisible; } /** * Shall a scale be shown in the map window? */ public boolean isScaleVisible() { return scaleVisible; } /** * Add/Overwrites all parameters to the given map, except the ID! * * @param map * copy source {@link Map} * @param newMap * copy destination {@link Map} * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ @Override public Map copyTo(final Map newMap) { newMap.setDefaultMapArea(getDefaultMapArea()); // newMap.setHTML(map.getHTML()); // Copy the Layer-Refs final LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>> newLayers = new LinkedList<DpRef<DpLayer<?, ? extends ChartStyle>>>(); for (final DpRef<DpLayer<?, ? extends ChartStyle>> dpr : getLayers()) { final DpRef<DpLayer<?, ? extends ChartStyle>> clone = dpr.clone(); newLayers.add(clone); } newMap.setLayers(newLayers); // Copy the media-Ref final LinkedList<DpRef<DpMedia<? extends ChartStyle>>> newMedia = new LinkedList<DpRef<DpMedia<? extends ChartStyle>>>(); for (final DpRef<DpMedia<? extends ChartStyle>> mr : getMedia()) { final DpRef<DpMedia<? extends ChartStyle>> clone = mr.clone(); newMap.add(clone); } newMap.setMedia(newMedia); // Copy the state of minimizeInLegend for (final String key : getMinimizedInLegendMap().keySet()) { newMap.getMinimizedInLegendMap().put(key, getMinimizedInLegendMap().get(key)); } // Copy the state of hideInLegend for (final String key : getHideInLegendMap().keySet()) { newMap.getHideInLegendMap().put(key, getHideInLegendMap().get(key)); } // Copy the state of hidden layers - layers with closed eyes closed for (final String key : hidden.keySet()) { newMap.setHiddenFor(key, getHiddenFor(key)); } // Copy the state of selectability of layers (click tool working or not) for (final String key : selectable.keySet()) { newMap.setSelectableFor(key, isSelectableFor(key)); } newMap.setMaxExtend(getMaxExtend()); // Copy the leftRight ratio of the legend/map divider newMap.setLeftRightRatio(getLeftRightRatio()); newMap.setTitle(title.copyTo(new Translation())); newMap.setDesc(desc.copyTo(new Translation())); newMap.setKeywords(keywords.copyTo(new Translation())); newMap.setScaleVisible(scaleVisible); newMap.setScaleUnits(scaleUnits); /*** Copy stuff related to the hor. and vert. GridPanel ***/ newMap.setGridPanelFormatter(gridPanelFormatter); newMap.setGridPanelCRS(gridPanelCRS); newMap.setGridPanelVisible(gridPanelVisible); /*** Copy the available additional Styles ***/ for (final DpRef dpRef : getLayers()) { String layerID = dpRef.getTargetId(); final List<String> availableStyles = getAdditionalStyles().get( layerID); if (availableStyles == null) continue; // copy the array final ArrayList<String> newAdditionalStyles = new ArrayList<String>(); newAdditionalStyles.addAll(availableStyles); // put the array to the newMap newMap.getAdditionalStyles().put(layerID, newAdditionalStyles); // LOGGER.debug("newMap.setSelectedStyleID("+layerID+", getSelectedStyleID("+layerID+"));"); newMap.setSelectedStyleID(layerID, getSelectedStyleID(layerID)); } /** Copy available Charts ** */ for (final String layerID : getAvailableCharts().keySet()) { final List<String> availableCharts = getAvailableCharts().get( layerID); if (availableCharts == null) continue; final ArrayList<String> newAvailableCharts = new ArrayList<String>(); for (final String styleID : availableCharts) { newAvailableCharts.add(styleID); // LOGGER.debug("Copying an available ChartStyle " + styleID); } newMap.getAvailableCharts().put(layerID, newAvailableCharts); } newMap.resetMissingHTMLinfos(); newMap.setPreviewMapExtendInGeopublisher(isPreviewMapExtendInGeopublisher()); return newMap; } /** * Removes all memory-intensive cached objects. */ public void uncache() { uncache(null); } /** * @return The units the {@link ScalePane} is shown in. */ public ScaleUnits getScaleUnits() { return scaleUnits; } /** * The units the {@link ScalePane} is shown in. */ public void setScaleUnits(ScaleUnits scaleUnits) { this.scaleUnits = scaleUnits; } /** * If <code>true</code>, the max. map extend will be applied in the * MapComposer. Otherwise it will will only be applied in the exported Atlas */ public boolean isPreviewMapExtendInGeopublisher() { return previewMapExtendInGeopublisher; } /** * If <code>true</code>, the max. map extend will be applied in the * MapComposer. Otherwise it will will only be applied in the exported Atlas */ public void setPreviewMapExtendInGeopublisher( boolean previewMapExtendInGeopublisher) { this.previewMapExtendInGeopublisher = previewMapExtendInGeopublisher; } /** * Is the entry visible in this map? */ public boolean isVisible(DpEntry<? extends ChartStyle> dpe) { Boolean b = hidden.get(dpe.getId()); if (b == null) return true; else return (!b); } public Object isVisibleInLegend(DpEntry<? extends ChartStyle> dpe) { Boolean b = hideInLegendMap.get(dpe.getId()); if (b == null) return true; else return (!b); } /** * @return A {@link List} of {@link String} with the names of all different * CRS used in the map. */ public List<String> getUsedCrs() { if (cacheUsedCrs != null || (System.currentTimeMillis() - cacheUsedCrsLastCheckedTime) > 1000) { cacheUsedCrsLastCheckedTime = System.currentTimeMillis(); CoordinateReferenceSystem mapCrs = getLayer0Crs(); // Returns a List of all DIFFERENT CRS used in the map if (mapCrs != null) { cacheUsedCrs = new ArrayList<String>(); // Name/Descriptor of the Map's CRS // The Map's CRS is always the first one in the list cacheUsedCrs.add(GeotoolsGUIUtil.getTitleForCRS(mapCrs)); /** * Now iterate over the layer's CRSs and check A) If they * semantically differ from the Map's one, and B) check that no * CRS-Name is in the list twice. */ for (DpRef dpr : getLayers()) { DpLayer dpl = (DpLayer) dpr.getTarget(); CoordinateReferenceSystem layerCrs = dpl.getCrs(); if (layerCrs != null) { if (!CRS.equalsIgnoreMetadata(mapCrs, layerCrs)) { String layerCrsName = GeotoolsGUIUtil .getTitleForCRS(layerCrs); if (layerCrsName != null && !cacheUsedCrs.contains(layerCrsName)) { cacheUsedCrs.add(layerCrsName); } } } } } else cacheUsedCrs = null; } return cacheUsedCrs; } /** * Liefert einen HTML a-Link in the requested langauge der innerhalb von * Atlas-HTML-Dokuemnten verwendet werden kann um auf ein DPE zu verlinken. */ public String getInternalLink(String lang) { return "<a href=\"" + AtlasProtocol.MAP.toString().toLowerCase() + "://" + getId() + "\">" + getTitle().get(lang) + "</a>"; } /** * Liefert einen HTML a-Link in the requested language der innerhalb von * Atlas-HTML-Dokuemnten verwendet werden kann um auf ein DPE zu verlinken. */ public String getInternalLink() { return "<a href=\"" + AtlasProtocol.MAP.toString().toLowerCase() + "://" + getId() + "\">" + getTitle().toString() + "</a>"; } /** * Returns <code>true</code> is any of the HTML documents for this map * contain a reference to the given {@link DpMedia}. */ public boolean referencesInHtml(DpMedia dpe) { for (String lang : getAc().getLanguages()) { URL infoURL = getInfoURL(lang); if (AtlasProtocol.findReferencesInHtml(infoURL, dpe)) { return true; } } return false; } }