/******************************************************************************* * Copyright 2012 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.layer.tree; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.avlist.AVList; import gov.nasa.worldwind.event.Message; import gov.nasa.worldwind.globes.ElevationModel; import gov.nasa.worldwind.layers.Layer; import gov.nasa.worldwind.render.DrawContext; import java.awt.Point; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.net.URL; import java.util.Collection; import java.util.Map.Entry; import java.util.Set; import au.gov.ga.earthsci.common.persistence.Adapter; import au.gov.ga.earthsci.common.persistence.Persistent; import au.gov.ga.earthsci.common.util.IInformationed; import au.gov.ga.earthsci.common.util.ILoader; import au.gov.ga.earthsci.common.util.Util; import au.gov.ga.earthsci.core.model.IModelStatus; import au.gov.ga.earthsci.core.model.IStatused; import au.gov.ga.earthsci.layer.DrawOrder; import au.gov.ga.earthsci.layer.IPersistentLayer; import au.gov.ga.earthsci.layer.LayerPersistentAdapter; import au.gov.ga.earthsci.layer.Messages; import au.gov.ga.earthsci.layer.delegator.AbstractLayerDelegator; import au.gov.ga.earthsci.layer.delegator.ILayerDelegator; import au.gov.ga.earthsci.layer.delegator.PersistentLayerDelegator; import au.gov.ga.earthsci.layer.elevation.IElevationModelLayer; import au.gov.ga.earthsci.worldwind.common.layers.Bounded; import au.gov.ga.earthsci.worldwind.common.layers.Bounds; import au.gov.ga.earthsci.worldwind.common.util.AVKeyMore; /** * Layer tree node implementation for layers. Implements the {@link Layer} * interface, and delegates all layer methods to a * {@link AbstractLayerDelegator} object. * <p/> * Also fires a property change in all setter methods to comply with the Java * Bean specification. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class LayerNode extends AbstractLayerTreeNode implements ILayerNode { protected PersistentLayerDelegator delegator = new PersistentLayerDelegator(); private boolean loading = false; private Integer drawOrder = null; private Integer drawOrderCached = null; public LayerNode() { //propagate property changes from the delegate to the listeners of the node delegator.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { firePropertyChange(new PropertyChangeEvent(LayerNode.this, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue())); //new layer, update required information: if (evt.getPropertyName().equals("layer")) //$NON-NLS-1$ { //clear the cached draw order, as new layer may have a different default drawOrderCached = null; //get the legend url if it exists (set by the LayerFactory) URL legendURL = (URL) getValue(AVKeyMore.LEGEND_URL); if (legendURL == null) { AVList constructionParameters = (AVList) getValue(AVKey.CONSTRUCTION_PARAMETERS); if (constructionParameters != null) { legendURL = (URL) constructionParameters.getValue(AVKeyMore.LEGEND_URL); } } if (legendURL != null) { setLegendURL(legendURL); } //update layer list (draw order may have changed), and elevation models if required updateLayers(); if (getElevationModel() != null) { updateElevationModels(); } } } }); delegator.setPropertiesChangedTrackingEnabled(false); delegator.setName(Messages.LayerNode_Loading); delegator.setPropertiesChangedTrackingEnabled(true); } @Override public Class<IPersistentLayer> getLayerClass() { return delegator.getLayerClass(); } @Override public boolean isLayerSet() { return delegator.isLayerSet(); } @Override public boolean isGrandLayerSet() { return delegator.isGrandLayerSet(); } @Override public IPersistentLayer getLayer() { return delegator.getLayer(); } @Override public void setLayer(IPersistentLayer layer) { delegator.setLayer(layer); drawOrderCached = null; } @Persistent(name = "definition") @Adapter(LayerPersistentAdapter.class) private IPersistentLayer getPersistentLayer() { if (isLayerSet()) { return getLayer(); } return null; } //for unpersistence @SuppressWarnings("unused") private void setPersistentLayer(IPersistentLayer layer) { setLayer(layer); } @Override public Layer getGrandLayer() { return delegator.getGrandLayer(); } protected <T> T getDelegateImplementing(Class<T> c) { Layer layer = this.delegator; while (true) { if (c.isInstance(layer)) { return c.cast(layer); } if (!(layer instanceof ILayerDelegator)) { return null; } layer = ((ILayerDelegator<?>) layer).getLayer(); } } @Override public ElevationModel getElevationModel() { IElevationModelLayer elevationModelLayer = getDelegateImplementing(IElevationModelLayer.class); if (elevationModelLayer != null) { return elevationModelLayer.getElevationModel(); } return null; } @Override public URL getInformationURL() { //if the layer is IInformationed, use that instead IInformationed informationed = getDelegateImplementing(IInformationed.class); if (informationed != null) { URL url = informationed.getInformationURL(); if (url != null) { return url; } } return super.getInformationURL(); } @Override public String getInformationString() { //if the layer is IInformationed, use that instead IInformationed informationed = getDelegateImplementing(IInformationed.class); if (informationed != null) { String information = informationed.getInformationString(); if (!Util.isEmpty(information)) { return information; } } return super.getInformationString(); } @Override public IModelStatus getStatus() { IStatused statused = getDelegateImplementing(IStatused.class); if (statused != null) { return statused.getStatus(); } return super.getStatus(); } @Override public Bounds getBounds() { Bounded bounded = getDelegateImplementing(Bounded.class); if (bounded != null) { return bounded.getBounds(); } return null; } @Override public boolean isFollowTerrain() { Bounded bounded = getDelegateImplementing(Bounded.class); if (bounded != null) { return bounded.isFollowTerrain(); } return false; } @Override public void propertyChange(PropertyChangeEvent evt) { firePropertyChange(evt); } @Override public boolean isLoading() { if (loading) { return true; } ILoader loader = getDelegateImplementing(ILoader.class); if (loader != null) { return loader.isLoading(); } return false; } @Override public void setLoading(boolean loading) { firePropertyChange("loading", isLoading(), this.loading = loading); //$NON-NLS-1$ } @Override public int getDrawOrder() { if (drawOrder != null) { return drawOrder; } if (drawOrderCached != null) { return drawOrderCached; } Class<? extends Layer> layerClass = Layer.class; Layer l = getGrandLayer(); if (l != null) { layerClass = l.getClass(); } drawOrderCached = DrawOrder.getDefaultDrawOrder(layerClass); return drawOrderCached; } @Override public void setDrawOrder(int drawOrder) { firePropertyChange("drawOrder", getDrawOrder(), this.drawOrder = drawOrder); //$NON-NLS-1$ updateLayers(); //need to update the layer list, as it is sorted by draw order } @Persistent(name = "drawOrder", attribute = true) private Integer getPersistentDrawOrder() { return drawOrder; } @SuppressWarnings("unused") private void setPersistentDrawOrder(Integer drawOrder) { setDrawOrder(drawOrder); } ////////////////////// // Layer delegation // ////////////////////// @Override public void dispose() { delegator.dispose(); } @Override public void onMessage(Message msg) { delegator.onMessage(msg); } @Override public Object setValue(String key, Object value) { return delegator.setValue(key, value); } @Persistent(attribute = true) @Override public boolean isEnabled() { return delegator.isEnabled(); } @Override public void setEnabled(boolean enabled) { delegator.setEnabled(enabled); if (enabled && getOpacity() <= 0.0) { setOpacity(1.0); } } @Override public String getName() { return delegator.getName(); } @Override public void setName(String name) { delegator.setName(name); } @Override public AVList setValues(AVList avList) { return delegator.setValues(avList); } @Override public String getRestorableState() { return delegator.getRestorableState(); } @Persistent(attribute = true) @Override public double getOpacity() { return delegator.getOpacity(); } @Override public void restoreState(String stateInXml) { delegator.restoreState(stateInXml); } @Override public Object getValue(String key) { return delegator.getValue(key); } @Override public void setOpacity(double opacity) { delegator.setOpacity(opacity); } @Override public Collection<Object> getValues() { return delegator.getValues(); } @Override public String getStringValue(String key) { return delegator.getStringValue(key); } @Override public boolean isPickEnabled() { return delegator.isPickEnabled(); } @Override public Set<Entry<String, Object>> getEntries() { return delegator.getEntries(); } @Override public boolean hasKey(String key) { return delegator.hasKey(key); } @Override public Object removeKey(String key) { return delegator.removeKey(key); } @Override public void setPickEnabled(boolean isPickable) { delegator.setPickEnabled(isPickable); } @Override public void preRender(DrawContext dc) { delegator.preRender(dc); } @Override public void render(DrawContext dc) { delegator.render(dc); } @Override public void pick(DrawContext dc, Point pickPoint) { delegator.pick(dc, pickPoint); } @Override public boolean isAtMaxResolution() { return delegator.isAtMaxResolution(); } @Override public boolean isMultiResolution() { return delegator.isMultiResolution(); } @Override public double getScale() { return delegator.getScale(); } @Override public boolean isNetworkRetrievalEnabled() { return delegator.isNetworkRetrievalEnabled(); } @Override public void setNetworkRetrievalEnabled(boolean networkRetrievalEnabled) { delegator.setNetworkRetrievalEnabled(networkRetrievalEnabled); } @Override public AVList copy() { return delegator.copy(); } @Override public void setExpiryTime(long expiryTime) { delegator.setExpiryTime(expiryTime); } @Override public AVList clearList() { return delegator.clearList(); } @Override public long getExpiryTime() { return delegator.getExpiryTime(); } @Override public double getMinActiveAltitude() { return delegator.getMinActiveAltitude(); } @Override public void setMinActiveAltitude(double minActiveAltitude) { delegator.setMinActiveAltitude(minActiveAltitude); } @Override public double getMaxActiveAltitude() { return delegator.getMaxActiveAltitude(); } @Override public void setMaxActiveAltitude(double maxActiveAltitude) { delegator.setMaxActiveAltitude(maxActiveAltitude); } @Override public boolean isLayerInView(DrawContext dc) { return delegator.isLayerInView(dc); } @Override public boolean isLayerActive(DrawContext dc) { return delegator.isLayerActive(dc); } @Override public Double getMaxEffectiveAltitude(Double radius) { return delegator.getMaxEffectiveAltitude(radius); } @Override public Double getMinEffectiveAltitude(Double radius) { return delegator.getMinEffectiveAltitude(radius); } }