src.gov.nasa.worldwind.util.layertree.KMLLayerTreeNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwindx Show documentation
Show all versions of worldwindx Show documentation
World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util.layertree;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.layers.Layer;
import gov.nasa.worldwind.ogc.kml.*;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.util.tree.*;
import javax.swing.*;
import java.beans.*;
/**
* A LayerTreeNode
that represents a KML feature hierarchy defined by a {@link
* gov.nasa.worldwind.ogc.kml.KMLRoot}
.
*
* @author dcollins
* @version $Id: KMLLayerTreeNode.java 1171 2013-02-11 21:45:02Z dcollins $
* @see KMLFeatureTreeNode
*/
public class KMLLayerTreeNode extends LayerTreeNode
{
/** Indicates the KML feature hierarchy this node represents. Initialized during construction. */
protected KMLRoot kmlRoot;
/**
* Creates a new KMLLayerTreeNode
from the specified layer
and kmlRoot
. The
* node's name is set to the layer's name, and the node's hierarchy is populated from the feature hierarchy of the
* KMLRoot
.
*
* @param layer the Layer
the kmlRoot
corresponds to.
* @param kmlRoot the KML feature hierarchy this node represents.
*
* @throws IllegalArgumentException if the layer
is null
, or if kmlRoot
is
* null
.
*/
public KMLLayerTreeNode(Layer layer, KMLRoot kmlRoot)
{
super(layer);
if (kmlRoot == null)
{
String message = Logging.getMessage("nullValue.KMLRootIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.kmlRoot = kmlRoot;
this.addChildFeatures();
// Add a listener to refresh the tree model when the KML document is updated or a network link is retrieved.
this.kmlRoot.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(final PropertyChangeEvent event)
{
String name = (event != null) ? event.getPropertyName() : null;
Object newValue = (event != null) ? event.getNewValue() : null;
KMLAbstractFeature rootFeature = KMLLayerTreeNode.this.kmlRoot.getFeature();
// Update the document if an update is received, or if this node represents a network link that has been
// resolved.
if (AVKey.UPDATED.equals(name)
|| (AVKey.RETRIEVAL_STATE_SUCCESSFUL.equals(name) && rootFeature == newValue))
{
// Ensure that the node list is manipulated on the EDT
if (SwingUtilities.isEventDispatchThread())
{
KMLLayerTreeNode.this.refresh();
}
else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
KMLLayerTreeNode.this.refresh();
}
});
}
}
}
});
// Set the context of the KML document node to the root feature in the document.
this.setValue(AVKey.CONTEXT, kmlRoot.getFeature());
}
/**
* Specifies whether this node's layer is enabled for rendering. If the KMLRoot's feature is a container (Document
* or Folder), this method sets the visibility of that container as well as the node that represents the layer.
*
* @param selected true
to enable the layer, otherwise false
.
*/
@Override
public void setSelected(boolean selected)
{
super.setSelected(selected);
KMLAbstractFeature feature = this.kmlRoot.getFeature();
if (feature instanceof KMLAbstractContainer)
{
feature.setVisibility(selected);
}
}
/**
* Adds a new KMLFeatureTreeNode
to this node for each KML feature in the KMLRoot
.
*
* If the KMLRoot
's top level feature is a Document
or Folder
, this method
* ignores this container and adds its children directly to this node. Creating a node for the container adds an
* extra level to the tree node that doesn't provide any meaningful grouping.
*
* This does nothing if the KMLRoot
's top level feature is null
.
*/
protected void addChildFeatures()
{
KMLAbstractFeature rootFeature = this.kmlRoot.getFeature();
if (rootFeature == null)
return;
// Create a KMLFeatureTreeNode only to construct the description string for the root node and set it on this
// node. We do not add the root node to the tree because it would add a redundant.
KMLFeatureTreeNode featureNode = KMLFeatureTreeNode.fromKMLFeature(rootFeature);
this.setDescription(featureNode.getDescription());
// Initialize the selected state of this node to match the visibility of the root container.
Boolean visibility = rootFeature.getVisibility();
this.setSelected(visibility == null || visibility);
// If the root is a container, add its children
if (rootFeature instanceof KMLAbstractContainer)
{
KMLAbstractContainer container = (KMLAbstractContainer) rootFeature;
for (KMLAbstractFeature child : container.getFeatures())
{
if (child != null)
this.addFeatureNode(child);
}
}
// If the root is a network link, add the linked document
if (rootFeature instanceof KMLNetworkLink)
{
KMLRoot networkResource = ((KMLNetworkLink) rootFeature).getNetworkResource();
if (networkResource != null && networkResource.getFeature() != null)
{
rootFeature = networkResource.getFeature();
// Don't add Document nodes (they don't provide meaningful grouping).
if (rootFeature instanceof KMLDocument)
{
KMLAbstractContainer container = (KMLAbstractContainer) rootFeature;
for (KMLAbstractFeature child : container.getFeatures())
{
if (child != null)
this.addFeatureNode(child);
}
}
else if (rootFeature != null)
{
this.addFeatureNode(rootFeature);
}
}
}
}
/**
* Adds the a new KMLFeatureTreeNode
created with the specified feature
to this node.
*
* @param feature the KML feature to add.
*/
protected void addFeatureNode(KMLAbstractFeature feature)
{
TreeNode featureNode = KMLFeatureTreeNode.fromKMLFeature(feature);
if (featureNode != null)
this.addChild(featureNode);
}
/**
* Expands paths in the specified tree
corresponding to open KML container elements. This assumes that
* the tree
's model contains this node.
*
* This node's path is expanded if it's top level KML feature is an open KML container, an open KML network link, or
* is any other kind of KML feature.
*
* This calls expandOpenContainers
on all children which are instances of
* KMLFeatureTreeNode
.
*
* @param tree the Tree
who's paths should be expanded.
*
* @throws IllegalArgumentException if the tree
is null.
*/
public void expandOpenContainers(Tree tree)
{
if (tree == null)
{
String message = Logging.getMessage("nullValue.TreeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (this.mustExpandNode())
tree.expandPath(this.getPath());
for (TreeNode child : this.getChildren())
{
if (child instanceof KMLFeatureTreeNode)
((KMLFeatureTreeNode) child).expandOpenContainers(tree);
}
}
/**
* Indicates whether the tree path for this node must expanded. If the KMLRoot
's feature is a KML
* container or a KML network link, this returns whether that KML element's open
property is
* true
. Otherwise this returns true
*
* @return true
if the tree path for this node must be expanded, otherwise false
.
*/
protected boolean mustExpandNode()
{
if (this.kmlRoot.getFeature() instanceof KMLAbstractContainer)
{
return Boolean.TRUE.equals(this.kmlRoot.getFeature().getOpen());
}
return this.kmlRoot.getFeature() != null;
}
/** Refresh the tree model to match the contents of the KML document. */
protected void refresh()
{
this.removeAllChildren();
this.addChildFeatures();
}
}