/******************************************************************************* * 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.dp; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.Set; import java.util.Stack; import java.util.TreeMap; import java.util.Vector; import org.apache.log4j.Logger; import org.geopublishing.atlasStyler.RuleChangedEvent; import org.geopublishing.atlasViewer.dp.layer.DpLayer; import org.geopublishing.atlasViewer.dp.layer.DpLayerRaster; import org.geopublishing.atlasViewer.dp.layer.DpLayerVector; import org.geopublishing.atlasViewer.map.Map; import org.geopublishing.atlasViewer.map.MapPool; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.util.WeakHashSet; import org.opengis.referencing.crs.CoordinateReferenceSystem; import de.schmitzm.geotools.io.GeoImportUtil; import de.schmitzm.jfree.chart.style.ChartStyle; /** * Stores {@link DpEntry}s by their IDs. Offers to add * {@link PropertyChangeListener}s that listen to changes in the * {@link DataPool}. * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> * */ public class DataPool extends TreeMap<String, DpEntry<? extends ChartStyle>> { static final Logger LOGGER = Logger.getLogger(DataPool.class); private WeakHashSet<PropertyChangeListener> listeners = new WeakHashSet<PropertyChangeListener>( PropertyChangeListener.class); public enum EventTypes { addDpe, removeDpe, changeDpe, unknown }; /** * Convenience method to add a {@link DpEntry} * * @param entry */ public void add(DpEntry<? extends ChartStyle> entry) { if (entry == null) { LOGGER.warn("A null has been added to the datapool!"); return; } put(entry.getId(), entry); fireChangeEvents(EventTypes.addDpe); } /** * You can ask for the String ID or for an Integer, which is then is * interpreted as the position in the ordered list. */ @Override public DpEntry<? extends ChartStyle> get(Object key) { if (key instanceof Integer) { String[] orderedKeys = keySet().toArray(new String[size()]); return get(orderedKeys[(Integer) key]); } return super.get(key); } /** * Overridden from {@link Map} to inform our {@link PropertyChangeListener} */ @Override public DpEntry<? extends ChartStyle> put(String key, DpEntry<? extends ChartStyle> value) { DpEntry<? extends ChartStyle> result = super.put(key, value); if (result == null) fireChangeEvents(EventTypes.addDpe); return result; } /** * Overridden from {@link Map} to inform our {@link PropertyChangeListener} */ @Override public DpEntry<? extends ChartStyle> remove(Object key) { DpEntry<? extends ChartStyle> result = super.remove(key); if (result != null) fireChangeEvents(EventTypes.removeDpe); return result; } /** * {@link PropertyChangeListener} can be registered to be informed when the * {@link MapPool} changes. * * @param propertyChangeListener */ public void addChangeListener(PropertyChangeListener propertyChangeListener) { listeners.add(propertyChangeListener); } /** * {@link PropertyChangeListener} can be unregistered. * * @param propertyChangeListener */ public void removeChangeListener( PropertyChangeListener propertyChangeListener) { if (listeners.contains(propertyChangeListener)) { listeners.remove(propertyChangeListener); } else { LOGGER .warn("Removing a PropertyChangeListener that is not registered."); } } /** * If {@link #quite} == <code>true</code> no {@link RuleChangedEvent} will * be fired. */ private boolean quite = false; EventTypes lastOpressedEvent = null; Stack<Boolean> stackQuites = new Stack<Boolean>(); /** * Add a QUITE-State to the event firing state stack */ public void pushQuite() { stackQuites.push(quite); setQuite(true); } /** * Remove a QUITE-State from the event firing state stack */ public void popQuite() { setQuite(stackQuites.pop()); if (quite == false) { if (lastOpressedEvent != null) fireChangeEvents(lastOpressedEvent); // Not anymore.. if lastOpressedEvent == null, there is no reason to // send an event now // else // fireEvents(new RuleChangedEvent("Not quite anymore", this)); } else { LOGGER.debug("not firing event because there are " + stackQuites.size() + " 'quites' still on the stack"); } } public void popQuite(EventTypes fireThis) { setQuite(stackQuites.pop()); if (quite == false && fireThis != null) fireChangeEvents(fireThis); else { lastOpressedEvent = fireThis; LOGGER.debug("not firing event " + fireThis + " because there are " + stackQuites.size() + " 'quites' still on the stack"); } } /** * If quite, the RuleList will not fire {@link RuleChangedEvent}s. */ private void setQuite(boolean b) { quite = b; } /** * If quite, the RuleList will not fire {@link RuleChangedEvent}s */ public boolean isQuite() { return quite; } /** * Informs all registered {@link PropertyChangeListener}s about a change in * the {@link MapPool}. The events are fired on the EDT. */ public void fireChangeEvents(final EventTypes type) { if (quite) { lastOpressedEvent = type; return; } else { lastOpressedEvent = null; } PropertyChangeEvent pce = new PropertyChangeEvent(this, type.toString(), false, true); for (PropertyChangeListener pcl : listeners) { if (pcl != null) pcl.propertyChange(pce); } } public void dispose() { listeners.clear(); } /** * @return a list of all CRS used in the DataPool */ public Vector<CoordinateReferenceSystem> getCRSList() { Vector<CoordinateReferenceSystem> crss = new Vector<CoordinateReferenceSystem>(); crss.add(DefaultGeographicCRS.WGS84); if (!crss.contains(GeoImportUtil.getDefaultCRS())) crss.add(GeoImportUtil.getDefaultCRS()); for (DpEntry dpe : values()) { if (dpe instanceof DpLayer) { DpLayer dpl = (DpLayer) dpe; if (!crss.contains(dpl.getCrs())) crss.add(dpl.getCrs()); } } return crss; } /** * Return an unsorted list of only the vector layer data pool entries */ public Set<DpLayerVector> getVectorLayers() { HashSet<DpLayerVector> vectorLayers = new HashSet<DpLayerVector>(); for (DpEntry dpe : values()) { if (dpe instanceof DpLayerVector) vectorLayers.add((DpLayerVector) dpe); } return vectorLayers; } /** * Return an unsorted list of only the layer data pool entries */ public Set<DpLayer> getLayers() { HashSet<DpLayer> layers = new HashSet<DpLayer>(); for (DpEntry dpe : values()) { if (dpe instanceof DpLayer) layers.add((DpLayer) dpe); } return layers; } /** * Return an unsorted list of only the raster layer data pool entries */ public Set<DpLayerRaster> getRasterLayers() { HashSet<DpLayerRaster> rasterLayers = new HashSet<DpLayerRaster>(); for (DpEntry dpe : values()) { if (dpe instanceof DpLayerRaster) rasterLayers.add((DpLayerRaster) dpe); } return rasterLayers; } }