/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.cismap.commons.raster.wms; import edu.umd.cs.piccolo.PNode; import org.apache.log4j.Logger; import org.jdom.DataConversionException; import org.jdom.Element; import java.awt.EventQueue; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.tree.TreePath; import de.cismet.cismap.commons.BoundingBox; import de.cismet.cismap.commons.Crs; import de.cismet.cismap.commons.LayerInfoProvider; import de.cismet.cismap.commons.RetrievalServiceLayer; import de.cismet.cismap.commons.XBoundingBox; import de.cismet.cismap.commons.gui.MappingComponent; import de.cismet.cismap.commons.gui.piccolo.XPImage; import de.cismet.cismap.commons.interaction.ActiveLayerListener; import de.cismet.cismap.commons.interaction.CismapBroker; import de.cismet.cismap.commons.interaction.events.ActiveLayerEvent; import de.cismet.cismap.commons.preferences.CapabilityLink; import de.cismet.cismap.commons.rasterservice.MapService; import de.cismet.cismap.commons.rasterservice.RasterMapService; import de.cismet.cismap.commons.retrieval.AbstractRetrievalService; import de.cismet.cismap.commons.retrieval.RetrievalEvent; import de.cismet.cismap.commons.retrieval.RetrievalListener; import de.cismet.cismap.commons.wms.capabilities.Envelope; import de.cismet.cismap.commons.wms.capabilities.Layer; import de.cismet.cismap.commons.wms.capabilities.LayerBoundingBox; import de.cismet.cismap.commons.wms.capabilities.Position; import de.cismet.cismap.commons.wms.capabilities.WMSCapabilities; /** * DOCUMENT ME! * * @author thorsten * @version $Revision$, $Date$ */ public final class SlidableWMSServiceLayerGroup extends AbstractRetrievalService implements RetrievalServiceLayer, RasterMapService, ChangeListener, MapService, LayerInfoProvider, ActiveLayerListener { //~ Static fields/initializers --------------------------------------------- private static final transient Logger LOG = Logger.getLogger(SlidableWMSServiceLayerGroup.class); public static final String XML_ELEMENT_NAME = "SlidableWMSServiceLayerGroup"; // NOI18N /** A suffix which makes it clear, if a layer name was loaded from the config file. */ public static final String LAYERNAME_FROM_CONFIG_SUFFIX = "$fromConfig$"; private static final String SLIDER_PREFIX = "Slider"; // NOI18N private static List<Integer> uniqueNumbers = new ArrayList<Integer>(); private static String addedInternalWidget = null; private static boolean BOTTOM_UP; private static boolean RESOURCE_CONSERVING; private static int TIME_TILL_LOCKED; private static int INACTIVE_TIME_TILL_LOCKED; private static double VERTICAL_LABEL_WIDTH_THRESHOLD; static { final Properties prop = new Properties(); try { prop.load(SlidableWMSServiceLayerGroup.class.getResourceAsStream( "SlidableWMSServiceLayerGroup.properties")); BOTTOM_UP = prop.getProperty("bottomUp", "true").trim().equalsIgnoreCase("true"); RESOURCE_CONSERVING = prop.getProperty("resourceConserving", "false").trim().equalsIgnoreCase("true"); TIME_TILL_LOCKED = Math.abs(Integer.parseInt(prop.getProperty("timeTillLocked", "60"))); INACTIVE_TIME_TILL_LOCKED = Math.abs(Integer.parseInt(prop.getProperty("inactiveTimeTillLocked", "10"))); VERTICAL_LABEL_WIDTH_THRESHOLD = Math.abs(Double.parseDouble( prop.getProperty("verticalLabelWidthThreshold", "0.5"))); } catch (Exception ex) { LOG.error("Could not load the properties for the SlidableWMSServiceLayerGroup", ex); BOTTOM_UP = true; RESOURCE_CONSERVING = false; TIME_TILL_LOCKED = 60; INACTIVE_TIME_TILL_LOCKED = 10; VERTICAL_LABEL_WIDTH_THRESHOLD = 0.5; } } //~ Enums ------------------------------------------------------------------ /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ public enum LabelDirection { //~ Enum constants ----------------------------------------------------- HORIZONTAL, VERTICAL; } //~ Instance fields -------------------------------------------------------- SlidableWMSServiceLayerGroupInternalFrame internalFrame; private boolean printMode = false; private boolean resourceConserving; private final List<WMSServiceLayer> layers = new ArrayList<WMSServiceLayer>(); private boolean layerQuerySelected = false; private final String sliderName; private PNode pnode = new XPImage(); private int layerPosition; private String name; private String completePath = null; private Map<WMSServiceLayer, Integer> progressTable = new ConcurrentHashMap<WMSServiceLayer, Integer>(); private AtomicInteger layerComplete = new AtomicInteger(0); private String preferredRasterFormat; private String preferredBGColor; private String preferredExceptionsFormat; private String capabilitiesUrl = null; private WMSCapabilities wmsCapabilities; private XBoundingBox boundingBox; private String customSLD; private boolean selected = false; private boolean locked; private boolean doNotDisableSlider; private Timer lockTimer; private boolean crossfadeEnabled; private boolean bottomUp; private boolean enableAllChildren; private int timeTillLocked; private int inactiveTimeTillLocked; private double verticalLabelWidthThreshold; private ActionListener btnLockListener = new java.awt.event.ActionListener() { @Override public void actionPerformed(final java.awt.event.ActionEvent evt) { btnLockResultsActionPerformed(evt); } }; private ActionListener lockTimerListener = new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { doNotDisableSlider = !lockTimer.isRunning(); SlidableWMSServiceLayerGroup.this.setLocked(!lockTimer.isRunning()); } }; private HashMap<WMSServiceLayer, RetrievalListener> layerRetrievalListeners = new HashMap<WMSServiceLayer, RetrievalListener>(); private boolean enabled = true; private List originalTreePaths; private Element originalElement; private HashMap<String, WMSCapabilities> orginalCapabilities; private float translucency = 1.0f; private boolean reverseAxisOrder = false; //~ Constructors ----------------------------------------------------------- /** * Creates a new SlidableWMSServiceLayerGroup object. * * @param treePaths DOCUMENT ME! */ public SlidableWMSServiceLayerGroup(final List treePaths) { originalTreePaths = treePaths; sliderName = SLIDER_PREFIX + getUniqueRandomNumber(); final TreePath tp = ((TreePath)treePaths.get(0)); final Layer selectedLayer = (de.cismet.cismap.commons.wms.capabilities.Layer)tp.getLastPathComponent(); evaluateLayerKeywords(selectedLayer); final List<Layer> children = Arrays.asList(selectedLayer.getChildren()); lockTimer = new Timer(timeTillLocked * 1000, lockTimerListener); lockTimer.setRepeats(false); setName(selectedLayer.getTitle()); for (final Object path : tp.getPath()) { if (path instanceof Layer) { if (completePath == null) { completePath = ((Layer)path).getName(); } else { completePath += "/" + ((Layer)path).getName(); } } } double maxx = Double.NaN; double minx = Double.NaN; double maxy = Double.NaN; double miny = Double.NaN; String srsCode = null; boolean usesMultipleSrs = false; if (bottomUp) { Collections.reverse(children); } for (final Layer l : children) { boolean addLayer = false; if (enableAllChildren) { addLayer = true; } else { for (final String keyword : l.getKeywords()) { if (keyword.equalsIgnoreCase("cismapSlidingLayerGroupMember")) { addLayer = true; } } } if (addLayer) { final WMSServiceLayer wsl = new WMSServiceLayer(l); layers.add(wsl); final Position min; final Position max; final LayerBoundingBox[] boundingBoxes = l.getBoundingBoxes(); if (boundingBoxes.length > 0) { min = boundingBoxes[0].getMin(); max = boundingBoxes[0].getMax(); if (srsCode == null) { srsCode = boundingBoxes[0].getSRS(); } else if (!srsCode.equalsIgnoreCase(boundingBoxes[0].getSRS())) { usesMultipleSrs = true; } } else { final Envelope envelope = l.getLatLonBoundingBoxes(); min = envelope.getMin(); max = envelope.getMax(); if (srsCode == null) { srsCode = "EPSG:4326"; } else if (!srsCode.equalsIgnoreCase("EPSG:4326")) { usesMultipleSrs = true; } } if ((Double.isNaN(maxx)) || (maxx < max.getX())) { maxx = max.getX(); } if ((Double.isNaN(minx)) || (minx > min.getX())) { minx = min.getX(); } if ((Double.isNaN(maxy)) || (maxy < max.getY())) { maxy = max.getY(); } if ((Double.isNaN(miny)) || (miny > min.getY())) { miny = min.getY(); } } } if (!usesMultipleSrs && (maxx != Double.NaN) && (minx != Double.NaN) && (maxy != Double.NaN) && (miny != Double.NaN)) { final Crs srs = CismapBroker.getInstance().crsFromCode(srsCode); if (srs != null) { this.boundingBox = new XBoundingBox(minx, miny, maxx, maxy, srs.getCode(), srs.isMetric()); } else { if (LOG.isDebugEnabled()) { LOG.debug("Layer's SRS code '" + srsCode + "' isn't available in cismap."); } } } else { if (LOG.isDebugEnabled()) { LOG.debug("The children of '" + getName() + "' whether use multiple srs or don't have valid bounding boxes."); } } init(0); } /** * Creates a new SlidableWMSServiceLayerGroup object. * * @param element treePaths DOCUMENT ME! * @param capabilities DOCUMENT ME! */ public SlidableWMSServiceLayerGroup(final Element element, final HashMap<String, WMSCapabilities> capabilities) { orginalCapabilities = capabilities; originalElement = element; sliderName = SLIDER_PREFIX + getUniqueRandomNumber(); setName(element.getAttributeValue("name")); lockTimer = new Timer(timeTillLocked * 1000, lockTimerListener); lockTimer.setRepeats(false); try { this.setEnabled(element.getAttribute("enabled").getBooleanValue()); } catch (DataConversionException ex) { LOG.warn("Attribute enabled has wrong data type.", ex); } catch (final NullPointerException ex) { LOG.warn("Attribute enabled not found.", ex); } try { final boolean visible = element.getAttribute("visible").getBooleanValue(); pnode.setVisible(visible); } catch (final DataConversionException e) { LOG.warn("Attribute visible has wrong data type.", e); } catch (final NullPointerException e) { LOG.warn("Attribute visible not found.", e); } try { this.reverseAxisOrder = element.getAttribute("reverseAxisOrder").getBooleanValue(); } catch (final DataConversionException e) { LOG.warn("Attribute reverseAxisOrder has wrong data type.", e); } catch (final NullPointerException e) { LOG.info("Attribute reverseAxisOrder not found.", e); } try { pnode.setTransparency(element.getAttribute("translucency").getFloatValue()); } catch (final DataConversionException e) { LOG.warn("Attribute translucency has wrong data type.", e); } catch (final NullPointerException e) { LOG.warn("Attribute translucency not found.", e); } try { completePath = element.getAttribute("completePath").getValue(); } catch (final NullPointerException e) { LOG.warn("Attribute translucency not found.", e); } try { preferredBGColor = element.getAttribute("bgColor").getValue(); preferredRasterFormat = element.getAttribute("imageFormat").getValue(); preferredExceptionsFormat = element.getAttribute("exceptionFormat").getValue(); } catch (final NullPointerException e) { LOG.warn("Attribute not found.", e); } try { boundingBox = new XBoundingBox(element); } catch (final Exception ex) { LOG.warn("Child element BoundingBox not found.", ex); } final Element layersElement = element.getChild("layers"); final List layersList = layersElement.getChildren(); evaluateElementKeywords(element); if (bottomUp) { Collections.reverse(layersList); } for (final Object o : layersList) { final WMSServiceLayer l = new WMSServiceLayer((Element)o, capabilities); layers.add(l); } try { final Element capElement = element.getChild("capabilities"); final CapabilityLink cp = new CapabilityLink(capElement); setWmsCapabilities(capabilities.get(cp.getLink())); capabilitiesUrl = cp.getLink(); } catch (final NullPointerException e) { LOG.warn("Child element capabilities not found.", e); } int sliderValue = 0; try { sliderValue = element.getAttribute("sliderValue").getIntValue(); } catch (DataConversionException ex) { LOG.warn("Could not load attribute sliderValue.", ex); } init(sliderValue); } /** * Creates a new SlidableWMSServiceLayerGroup object. * * <p>Note: Deprecated - please test before using this constructor. If everything works as expected, the deprecated * tag can be removed.</p> * * @param name DOCUMENT ME! * @param completePath DOCUMENT ME! * @param layers DOCUMENT ME! * @param wmsCapabilities DOCUMENT ME! * @param capabilitiesUrl DOCUMENT ME! * @param srs DOCUMENT ME! * * @deprecated DOCUMENT ME! */ public SlidableWMSServiceLayerGroup(final String name, final String completePath, final Collection<Layer> layers, final WMSCapabilities wmsCapabilities, final String capabilitiesUrl, final Crs srs) { sliderName = SLIDER_PREFIX + getUniqueRandomNumber(); setName(name); this.completePath = completePath; setWmsCapabilities(wmsCapabilities); double maxx = Double.NaN; double minx = Double.NaN; double maxy = Double.NaN; double miny = Double.NaN; evaluateLayerKeywords(null); for (final Layer l : layers) { this.layers.add(new WMSServiceLayer(l)); final Position min; final Position max; final LayerBoundingBox[] boundingBoxes = l.getBoundingBoxes(); if (boundingBoxes.length > 0) { min = boundingBoxes[0].getMin(); max = boundingBoxes[0].getMax(); } else { final Envelope envelope = l.getLatLonBoundingBoxes(); min = envelope.getMin(); max = envelope.getMax(); } if ((Double.isNaN(maxx)) || (maxx < max.getX())) { maxx = max.getX(); } if ((Double.isNaN(minx)) || (minx > min.getX())) { minx = min.getX(); } if ((Double.isNaN(maxy)) || (maxy < max.getY())) { maxy = max.getY(); } if ((Double.isNaN(miny)) || (miny > min.getY())) { miny = min.getY(); } } if ((maxx != Double.NaN) && (minx != Double.NaN) && (maxy != Double.NaN) && (miny != Double.NaN)) { this.boundingBox = new XBoundingBox(minx, miny, maxx, maxy, srs.getCode(), srs.isMetric()); } setWmsCapabilities(wmsCapabilities); setCapabilitiesUrl(capabilitiesUrl); init(0); } //~ Methods ---------------------------------------------------------------- /** * Print Mode has to be set true, if this class is used with the headlessMapProvider. If it is not set, the needed * retrievalCompleteEvent will not be fired. On the other side if the retrievalCompleteEvent is fired, the sliding * functionality will be destroyed, for some reason. Therefore the print mode has to be considered as a hack. * * @param printMode DOCUMENT ME! */ public void setPrintMode(final boolean printMode) { this.printMode = printMode; } /** * See setPrintMode(). * * @return DOCUMENT ME! */ public boolean isPrintMode() { return printMode; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ private static int getUniqueRandomNumber() { int number = 0; do { number = (new Random(System.currentTimeMillis())).nextInt(); } while (uniqueNumbers.contains(number)); uniqueNumbers.add(number); return number; } /** * initializes a new SlidableWMSServiceLayerGroup object. * * @param sliderValue the initial position of the slider */ private void init(final int sliderValue) { setDefaults(); for (final WMSServiceLayer wsl : layers) { if (capabilitiesUrl == null) { capabilitiesUrl = wsl.getCapabilitiesUrl(); } wsl.setPNode(new XPImage()); pnode.addChild(wsl.getPNode()); final RetrievalListener retrievalListener = new RetrievalListener() { @Override public void retrievalStarted(final RetrievalEvent e) { fireRetrievalStarted(e); } @Override public void retrievalProgress(final RetrievalEvent e) { final RetrievalEvent event = new RetrievalEvent(); progressTable.put(wsl, e.getPercentageDone()); int progress = 0; for (final int i : progressTable.values()) { progress += i; } if (!isLocked()) { progress /= layers.size(); } SlidableWMSServiceLayerGroup.this.progress = progress; event.setPercentageDone(progress); fireRetrievalProgress(event); } @Override public void retrievalComplete(final RetrievalEvent e) { final Image i = (Image)e.getRetrievedObject(); ((XPImage)wsl.getPNode()).setImage(i); new Thread("SlidableWMSServiceLayerGroup retrievalComplete()") { @Override public void run() { final Point2D localOrigin = CismapBroker.getInstance() .getMappingComponent() .getCamera() .getViewBounds() .getOrigin(); final double localScale = CismapBroker.getInstance() .getMappingComponent() .getCamera() .getViewScale(); wsl.getPNode().setScale(1 / localScale); wsl.getPNode().setOffset(localOrigin); layerComplete.incrementAndGet(); if (layerComplete.get() == layers.size()) { CismapBroker.getInstance().getMappingComponent().repaint(); final RetrievalEvent re = new RetrievalEvent(); re.setIsComplete(true); re.setRetrievalService(SlidableWMSServiceLayerGroup.this); re.setHasErrors(false); re.setRetrievedObject(null); fireRetrievalComplete(re); stateChanged(new ChangeEvent(this)); enableSliderAndRestartTimer(); progressTable.clear(); } else if (wsl == getSelectedLayer()) { CismapBroker.getInstance().getMappingComponent().repaint(); } if (isPrintMode()) { fireRetrievalComplete(e); } } }.start(); } @Override public void retrievalAborted(final RetrievalEvent e) { fireRetrievalAborted(e); } @Override public void retrievalError(final RetrievalEvent e) { fireRetrievalError(e); } }; layerRetrievalListeners.put(wsl, retrievalListener); wsl.addRetrievalListener(retrievalListener); if (wsl.getBackgroundColor() == null) { wsl.setBackgroundColor(preferredBGColor); } if (wsl.getExceptionsFormat() == null) { wsl.setExceptionsFormat(preferredExceptionsFormat); } if (wsl.getImageFormat() == null) { wsl.setImageFormat(preferredRasterFormat); } } layers.get(0).setVisible(true); initDialog(sliderValue); CismapBroker.getInstance().addActiveLayerListener(this); } /** * DOCUMENT ME! * * @param slidableLayerElement DOCUMENT ME! */ private void evaluateElementKeywords(final Element slidableLayerElement) { try { resourceConserving = slidableLayerElement.getAttribute("resourceConserving").getBooleanValue(); timeTillLocked = slidableLayerElement.getAttribute("timeTillLocked").getIntValue(); inactiveTimeTillLocked = slidableLayerElement.getAttribute("inactiveTimeTillLocked").getIntValue(); bottomUp = slidableLayerElement.getAttribute("bottomUp").getBooleanValue(); verticalLabelWidthThreshold = slidableLayerElement.getAttribute("verticalLabelWidthThreshold") .getDoubleValue(); crossfadeEnabled = slidableLayerElement.getAttribute("crossfadeEnabled").getBooleanValue(); } catch (final NullPointerException e) { LOG.warn("Attribute not found.", e); } catch (DataConversionException ex) { LOG.warn("Attribute could not be converted.", ex); } } /** * DOCUMENT ME! * * @param selectedLayer DOCUMENT ME! */ private void evaluateLayerKeywords(final Layer selectedLayer) { if (selectedLayer != null) { Boolean resourceConserving = null; Integer timeTillLocked = null; Integer inactiveTimeTillLocked = null; Boolean bottomUp = null; Double verticalLabelWidthThreshold = null; this.enableAllChildren = false; this.crossfadeEnabled = false; for (final String keyword : selectedLayer.getKeywords()) { if (keyword.equalsIgnoreCase("cismapSlidingLayerGroup.config.resourceConserving.enabled")) { resourceConserving = true; } else if (keyword.equalsIgnoreCase("cismapSlidingLayerGroup.config.resourceConserving.disabled")) { resourceConserving = false; } if (keyword.startsWith("cismapSlidingLayerGroup.config.resourceConserving.timeTillLocked")) { try { final String value = keyword.split(":")[1]; timeTillLocked = Integer.parseInt(value); } catch (Exception ex) { LOG.error("An error occured while parsing timeTillLocked. Use default value.", ex); } } if (keyword.startsWith("cismapSlidingLayerGroup.config.resourceConserving.inactiveTimeTillLocked")) { try { final String value = keyword.split(":")[1]; inactiveTimeTillLocked = Integer.parseInt(value); } catch (Exception ex) { LOG.error("An error occured while parsing inactiveTimeTillLocked. Use default value.", ex); } } if (keyword.equalsIgnoreCase("cismapSlidingLayerGroup.config.bottomUp")) { bottomUp = true; } else if (keyword.equalsIgnoreCase("cismapSlidingLayerGroup.config.topDown")) { bottomUp = false; } if (keyword.startsWith("cismapSlidingLayerGroup.config.verticalLabelWidthThreshold")) { try { final String value = keyword.split(":")[1]; verticalLabelWidthThreshold = Double.parseDouble(value); } catch (Exception ex) { LOG.error("An error occured while parsing inactiveTimeTillLocked. Use default value.", ex); } } if (keyword.equalsIgnoreCase("cismapSlidingLayerGroup.config.enableAllChildren")) { this.enableAllChildren = true; } if (keyword.equalsIgnoreCase("cismapSlidingLayerGroup.config.crossfadeEnabled")) { this.crossfadeEnabled = true; } } if (resourceConserving == null) { this.resourceConserving = RESOURCE_CONSERVING; } else { this.resourceConserving = resourceConserving; } if (timeTillLocked == null) { this.timeTillLocked = TIME_TILL_LOCKED; } else { this.timeTillLocked = timeTillLocked; } if (inactiveTimeTillLocked == null) { this.inactiveTimeTillLocked = INACTIVE_TIME_TILL_LOCKED; } else { this.inactiveTimeTillLocked = inactiveTimeTillLocked; } if (bottomUp == null) { this.bottomUp = BOTTOM_UP; } else { this.bottomUp = bottomUp; } if (verticalLabelWidthThreshold == null) { this.verticalLabelWidthThreshold = VERTICAL_LABEL_WIDTH_THRESHOLD; } else { this.verticalLabelWidthThreshold = verticalLabelWidthThreshold; } } else { resourceConserving = RESOURCE_CONSERVING; timeTillLocked = TIME_TILL_LOCKED; inactiveTimeTillLocked = INACTIVE_TIME_TILL_LOCKED; bottomUp = BOTTOM_UP; verticalLabelWidthThreshold = VERTICAL_LABEL_WIDTH_THRESHOLD; enableAllChildren = false; } } /** * DOCUMENT ME! */ private void setDefaults() { preferredRasterFormat = "image/png"; // NOI18N preferredBGColor = "0xF0F0F0"; // NOI18N preferredExceptionsFormat = "application/vnd.ogc.se_xml"; // NOI18N } /** * DOCUMENT ME! * * @param wmsCapabilities DOCUMENT ME! */ public void setWmsCapabilities(final WMSCapabilities wmsCapabilities) { this.wmsCapabilities = wmsCapabilities; for (final WMSServiceLayer layer : layers) { layer.setWmsCapabilities(wmsCapabilities); } } /** * DOCUMENT ME! * * @param capabilitiesUrl DOCUMENT ME! */ public void setCapabilitiesUrl(final String capabilitiesUrl) { this.capabilitiesUrl = capabilitiesUrl; for (final WMSServiceLayer layer : layers) { layer.setCapabilitiesUrl(capabilitiesUrl); } } /** * DOCUMENT ME! * * @param srs DOCUMENT ME! */ public void setSrs(final String srs) { for (final WMSServiceLayer layer : layers) { layer.setSrs(srs); } } /** * Initializes the internal frame, which contains the slider. * * @param sliderValue the initial position of the slider */ private void initDialog(final int sliderValue) { internalFrame = new SlidableWMSServiceLayerGroupInternalFrame(this, sliderValue); setLocked(resourceConserving); } /** * DOCUMENT ME! * * @param evt DOCUMENT ME! */ private void btnLockResultsActionPerformed(final ActionEvent evt) { setLocked(!isLocked()); } @Override public void stateChanged(final ChangeEvent e) { if (getPNode() == null) { return; } final int i = (internalFrame.getSliderValue() / 100); final int rest = internalFrame.getSliderValue() % 100; for (int j = 0; j < getPNode().getChildrenCount(); ++j) { if (i == j) { getPNode().getChild(i).setTransparency(1f); } else { getPNode().getChild(j).setTransparency(0f); } } if (internalFrame.isAllowCrossfade() && ((i + 1) < getPNode().getChildrenCount())) { getPNode().getChild(i + 1).setTransparency(((float)rest) / 100f); } if (lockTimer.isRunning()) { lockTimer.restart(); } } @Override public PNode getPNode() { return pnode; } @Override public void setPNode(final PNode imageObject) { pnode = imageObject; } @Override public void retrieve(final boolean forced) { if (enabled || forced) { // these fields are needed to determine the progress of the retrieval progress = -1; layerComplete.set(0); progressTable.clear(); // the slider is always disabled during the retrieval of the layers and might be enabled later on when all // the layers are completely loaded internalFrame.enableSlider(false); // stop the timer, otherwise it can happen that SlidableWMSServiceLayerGroup gets locked during the // retrieval. lockTimer.stop(); if (isLocked()) { getSelectedLayer().retrieve(forced); } else { for (final WMSServiceLayer layer : layers) { layer.retrieve(forced); } } setRefreshNeeded(false); } } @Override public boolean canBeDisabled() { return true; } @Override public int getLayerPosition() { return layerPosition; } @Override public String getName() { return name; } /** * Provides the bounding box of this layer. The bounding box represents the extent of the children's bounding boxes. * * @return Extent of this layer. */ public XBoundingBox getBoundingBox() { return boundingBox; } /** * Returns the path of this layer. It's formatted by concatenating the names of parent layers with '/' as delimiter. * /[<...>/]<Name of grand parent>/<Name of parent>/<Name of this layer> * * @return Extent of this layer. */ public String getPath() { return completePath; } /** * DOCUMENT ME! * * @param customSLD DOCUMENT ME! */ public void setCustomSLD(final String customSLD) { this.customSLD = customSLD; for (final WMSServiceLayer layer : layers) { layer.setCustomSLD(this.customSLD); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public String getCustomSLD() { return customSLD; } @Override public boolean isEnabled() { return enabled; } @Override public void setEnabled(final boolean enabled) { this.enabled = enabled; for (final WMSServiceLayer layer : layers) { layer.setEnabled(enabled); } } @Override public void setLayerPosition(final int layerPosition) { this.layerPosition = layerPosition; } @Override public void setName(final String name) { this.name = name; } @Override public float getTranslucency() { return translucency; } @Override public void setTranslucency(final float t) { translucency = t; } @Override public Object clone() { SlidableWMSServiceLayerGroup clonedLayer; if (originalTreePaths != null) { clonedLayer = new SlidableWMSServiceLayerGroup(originalTreePaths); clonedLayer.setWmsCapabilities(wmsCapabilities); } else if (originalElement != null) { clonedLayer = new SlidableWMSServiceLayerGroup(originalElement, orginalCapabilities); } else { LOG.error("Could not clone SlidableWMSServiceLayerGroup.", new Exception()); return null; } clonedLayer.setBoundingBox(boundingBox); clonedLayer.setCapabilitiesUrl(capabilitiesUrl); clonedLayer.setCustomSLD(customSLD); clonedLayer.setEnabled(enabled); clonedLayer.setLayerPosition(layerPosition); clonedLayer.setLayerQuerySelected(layerQuerySelected); clonedLayer.setLocked(true); clonedLayer.setName(name); // The cloned service layer and the origin service layer should not use the same pnode, // because this would lead to problems, if the cloned layer and the origin layer are // used in 2 different MappingComponents // This has to be set afterwards. clonedLayer.setPNode(null); clonedLayer.setTranslucency(this.getTranslucency()); clonedLayer.setSliderValue(internalFrame.getSliderValue()); clonedLayer.reverseAxisOrder = reverseAxisOrder; return clonedLayer; } @Override public boolean isVisible() { return pnode.getVisible(); } @Override public void setBoundingBox(final BoundingBox bb) { for (final WMSServiceLayer layer : layers) { layer.setBoundingBox(bb); } } @Override public void setSize(final int height, final int width) { for (final WMSServiceLayer layer : layers) { layer.setSize(height, width); } } @Override public String toString() { return name; } @Override public String getLayerURI() { return getName(); } @Override public String getServerURI() { return capabilitiesUrl; } @Override public boolean isLayerQuerySelected() { return layerQuerySelected; } @Override public void setLayerQuerySelected(final boolean selected) { layerQuerySelected = selected; } @Override public boolean isQueryable() { return true; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public double getVerticalLabelWidthThreshold() { return verticalLabelWidthThreshold; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean isCrossfadeEnabled() { return crossfadeEnabled; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean isResourceConserving() { return resourceConserving; } /** * DOCUMENT ME! * * @return the layer capabilities object of the current layer */ @Override public Layer getLayerInformation() { if (wmsCapabilities != null) { return getLayerInformation(null, wmsCapabilities.getLayer().getChildren()); } return null; } /** * DOCUMENT ME! * * @param path DOCUMENT ME! * @param layerArray DOCUMENT ME! * * @return the layer capabilities object of the current layer */ private Layer getLayerInformation(final String path, final Layer[] layerArray) { if (layerArray != null) { for (final Layer l : layerArray) { final String currentPath = ((path == null) ? l.getName() : (path + "/" + l.getName())); if (currentPath.equals(completePath)) { return l; } else { final Layer res = getLayerInformation(currentPath, l.getChildren()); if (res != null) { return res; } } } } return null; } @Override public boolean equals(final Object obj) { if (obj instanceof SlidableWMSServiceLayerGroup) { final SlidableWMSServiceLayerGroup other = (SlidableWMSServiceLayerGroup)obj; final Iterator<WMSServiceLayer> otherLayerIt = other.layers.iterator(); for (final WMSServiceLayer l : layers) { if (otherLayerIt.hasNext()) { final WMSServiceLayer lOther = otherLayerIt.next(); if (!lOther.propertyEquals(l)) { return false; } } } return other.layers.size() == layers.size(); } return false; } @Override public int hashCode() { int hash = 0; for (final WMSServiceLayer l : layers) { hash += l.hashCode() % 71; } return hash; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean isLocked() { return locked; } /** * Locks the SlidableWMSServiceLayerGroup, this is not possible if RESOURCE_CONSERVING is false. Locked means that * the slider is disabled (generally) and that only the currently selected layer gets loaded. Otherwise all the * layers get loaded every time. * * @param locked DOCUMENT ME! */ public void setLocked(final boolean locked) { if (resourceConserving) { this.locked = locked; if (locked) { internalFrame.setLockIcon(); internalFrame.enableSlider(false || doNotDisableSlider); } else { internalFrame.setUnlocIcon(); doNotDisableSlider = false; // refresh the other layers this.retrieve(false); } } else { this.locked = false; } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public ActionListener getLockListener() { return btnLockListener; } /** * DOCUMENT ME! */ private void enableSliderAndRestartTimer() { final Runnable r = new Runnable() { @Override public void run() { internalFrame.enableSlider(true); lockTimer.restart(); } }; if (!isLocked()) { if (SwingUtilities.isEventDispatchThread()) { r.run(); } else { SwingUtilities.invokeLater(r); } } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public List<WMSServiceLayer> getLayers() { return layers; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public Element toElement() { final Element element = new Element(XML_ELEMENT_NAME); element.setAttribute("name", getName()); element.setAttribute("visible", (getPNode().getVisible() ? "true" : "false")); element.setAttribute("enabled", Boolean.toString(isEnabled())); element.setAttribute("translucency", "" + getPNode().getTransparency()); element.setAttribute("bgColor", preferredBGColor); element.setAttribute("imageFormat", preferredRasterFormat); element.setAttribute("exceptionFormat", preferredExceptionsFormat); element.setAttribute("completePath", String.valueOf(completePath)); // set the slidable layer keywords element.setAttribute("resourceConserving", Boolean.toString(resourceConserving)); element.setAttribute("timeTillLocked", Integer.toString(timeTillLocked)); element.setAttribute("inactiveTimeTillLocked", Integer.toString(inactiveTimeTillLocked)); element.setAttribute("bottomUp", Boolean.toString(bottomUp)); element.setAttribute("verticalLabelWidthThreshold", Double.toString(verticalLabelWidthThreshold)); element.setAttribute("crossfadeEnabled", Boolean.toString(crossfadeEnabled)); element.setAttribute("sliderValue", Integer.toString(internalFrame.getSliderValue())); if (boundingBox != null) { element.addContent(boundingBox.getJDOMElement()); } final Element capElement = new Element("capabilities"); // NOI18N final CapabilityLink capLink = new CapabilityLink(CapabilityLink.OGC, capabilitiesUrl, reverseAxisOrder, false); capElement.addContent(capLink.getElement()); element.addContent(capElement); final Element layersElement = new Element("layers"); // NOI18N for (final WMSServiceLayer l : layers) { final Element layerElement = l.getElement(); layerElement.setAttribute("name", internalFrame.getTickTitle(l) + LAYERNAME_FROM_CONFIG_SUFFIX); layersElement.addContent(layerElement); } element.addContent(layersElement); return element; } @Override public void layerAdded(final ActiveLayerEvent e) { } @Override public void layerRemoved(final ActiveLayerEvent e) { if (e.getLayer() == this) { if ((addedInternalWidget != null) && addedInternalWidget.equals(sliderName)) { CismapBroker.getInstance().getMappingComponent().removeInternalWidget(sliderName); internalFrame.removeModel(); // internalFrame.dispose(); internalFrame = null; addedInternalWidget = null; } // use invoke later to avoid a java.util.ConcurrentModificationException EventQueue.invokeLater(new Runnable() { @Override public void run() { CismapBroker.getInstance().removeActiveLayerListener(SlidableWMSServiceLayerGroup.this); } }); try { uniqueNumbers.remove(Integer.valueOf(sliderName.substring(SLIDER_PREFIX.length()))); } catch (final NumberFormatException ex) { LOG.error("The name of the internal slider widget is not valid.", ex); } lockTimer.removeActionListener(lockTimerListener); lockTimer.stop(); for (final WMSServiceLayer wsl : layers) { wsl.removeRetrievalListener(layerRetrievalListeners.get(wsl)); } } } @Override public void layerPositionChanged(final ActiveLayerEvent e) { } @Override public void layerVisibilityChanged(final ActiveLayerEvent e) { if ((e.getLayer() == this) && (getPNode() != null)) { boolean fadeOutOldWidget = false; boolean fadeInThisWidget = false; if (!getPNode().getVisible()) { fadeOutOldWidget = (addedInternalWidget != null) && addedInternalWidget.equals(sliderName); } else { fadeInThisWidget = selected; } if (fadeOutOldWidget) { CismapBroker.getInstance().getMappingComponent().removeInternalWidget(addedInternalWidget); addedInternalWidget = null; } if (fadeInThisWidget) { CismapBroker.getInstance() .getMappingComponent() .addInternalWidget(sliderName, MappingComponent.POSITION_NORTHEAST, internalFrame); addedInternalWidget = sliderName; CismapBroker.getInstance().getMappingComponent().showInternalWidget(sliderName, true, 800); } } } @Override public void layerAvailabilityChanged(final ActiveLayerEvent e) { } @Override public void layerInformationStatusChanged(final ActiveLayerEvent e) { } @Override public synchronized void layerSelectionChanged(final ActiveLayerEvent e) { selected = e.getLayer() == this; if (e.getLayer() == this) { if (addedInternalWidget != null) { CismapBroker.getInstance().getMappingComponent().removeInternalWidget(addedInternalWidget); CismapBroker.getInstance().getMappingComponent().repaint(); } if ((getPNode() != null) && getPNode().getVisible()) { CismapBroker.getInstance() .getMappingComponent() .addInternalWidget(sliderName, MappingComponent.POSITION_NORTHEAST, internalFrame); addedInternalWidget = sliderName; CismapBroker.getInstance().getMappingComponent().showInternalWidget(sliderName, true, 800); } } else { if ((addedInternalWidget != null) && !(e.getLayer() instanceof SlidableWMSServiceLayerGroup)) { CismapBroker.getInstance().getMappingComponent().showInternalWidget(addedInternalWidget, false, 800); } } updateTimerDelay(); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ private WMSServiceLayer getSelectedLayer() { final int i = (internalFrame.getSliderValue() / 100); if (i < layers.size()) { return layers.get(i); } else { return layers.get(layers.size() - 1); } } /** * DOCUMENT ME! * * @param value DOCUMENT ME! */ private void setSliderValue(final int value) { internalFrame.setSliderValue(value); } /** * DOCUMENT ME! */ private void updateTimerDelay() { if (selected) { lockTimer.setDelay(timeTillLocked * 1000); lockTimer.setInitialDelay(timeTillLocked * 1000); } else { lockTimer.setDelay(inactiveTimeTillLocked * 1000); lockTimer.setInitialDelay(inactiveTimeTillLocked * 1000); } if (lockTimer.isRunning()) { lockTimer.restart(); } } }