/******************************************************************************* * Copyright 2014 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.ui; import gov.nasa.worldwind.layers.Layer; import gov.nasa.worldwind.layers.LayerList; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import au.gov.ga.earthsci.common.util.AbstractPropertyChangeBean; import au.gov.ga.earthsci.common.util.IPropertyChangeBean; import au.gov.ga.earthsci.layer.DrawOrder; import au.gov.ga.earthsci.layer.tree.ILayerNode; import au.gov.ga.earthsci.layer.tree.ILayerTreeNode; /** * Model that represents the draw order of the layers. Automatically updates * when the layers change, using {@link PropertyChangeListener}s. * * @author Michael de Hoog (michael.dehoog@ga.gov.au) */ public class DrawOrderModel { private ILayerTreeNode input; private final RootDrawOrderModelElement root = new RootDrawOrderModelElement(); private final Map<Integer, DrawOrderDrawOrderModelElement> drawOrderElements = new HashMap<Integer, DrawOrderDrawOrderModelElement>(); private final DrawOrderDrawOrderModelElement nullDrawOrderElement = new DrawOrderDrawOrderModelElement(root, null); private PropertyChangeListener listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { rebuildTree(); } }; public RootDrawOrderModelElement getRoot() { return root; } public synchronized void setInput(ILayerTreeNode input) { if (this.input != null) { this.input.removePropertyChangeListener("layers", listener); //$NON-NLS-1$ } this.input = input; if (input != null) { input.addPropertyChangeListener("layers", listener); //$NON-NLS-1$ } rebuildTree(); } public void dispose() { setInput(null); } protected synchronized void rebuildTree() { //first clear out the child lists root.getChildren().clear(); for (DrawOrderDrawOrderModelElement drawOrderElement : drawOrderElements.values()) { drawOrderElement.getChildren().clear(); } //if no input, then don't add anything if (input == null) { return; } //sorted set of draw orders SortedSet<DrawOrderDrawOrderModelElement> drawOrders = new TreeSet<DrawOrderDrawOrderModelElement>(); //ensure all pre-defined draw orders are added as elements for (DrawOrder drawOrderValue : DrawOrder.values()) { DrawOrderDrawOrderModelElement element = getDrawOrderElement(drawOrderValue.value); drawOrders.add(element); } //add the layers to their draw order element LayerList layers = input.getLayers(); for (Layer layer : layers) { if (layer instanceof ILayerTreeNode) { Integer value = null; if (layer instanceof ILayerNode) { value = ((ILayerNode) layer).getDrawOrder(); } DrawOrderDrawOrderModelElement parent = getDrawOrderElement(value); parent.getChildren().add(new LayerDrawOrderModelElement(parent, (ILayerTreeNode) layer)); } } //add all used draw orders to the root for (DrawOrderDrawOrderModelElement element : drawOrders) { root.getChildren().add(element); } if (!nullDrawOrderElement.getChildren().isEmpty()) { root.getChildren().add(nullDrawOrderElement); } //fire property changes root.fireChildrenPropertyChange(); for (IDrawOrderModelElement child : root.getChildren()) { child.fireChildrenPropertyChange(); } } protected DrawOrderDrawOrderModelElement getDrawOrderElement(Integer value) { if (value == null) { return nullDrawOrderElement; } DrawOrderDrawOrderModelElement element = drawOrderElements.get(value); if (element == null) { element = new DrawOrderDrawOrderModelElement(root, value); drawOrderElements.put(value, element); } return element; } /** * Node in the draw order model tree hierarchy. */ public interface IDrawOrderModelElement extends IPropertyChangeBean { /** * @return Parent of this node, <code>null</code> if root */ IDrawOrderModelElement getParent(); /** * @return List of this node's children */ List<IDrawOrderModelElement> getChildren(); /** * Call {@link #firePropertyChange(String, Object, Object)} with the * "children" property */ void fireChildrenPropertyChange(); } /** * Abstract implementation of {@link IDrawOrderModelElement}. */ public abstract class AbstractDrawOrderModelElement extends AbstractPropertyChangeBean implements IDrawOrderModelElement { public final IDrawOrderModelElement parent; public final List<IDrawOrderModelElement> children = new ArrayList<IDrawOrderModelElement>(); public AbstractDrawOrderModelElement(IDrawOrderModelElement parent) { this.parent = parent; } @Override public IDrawOrderModelElement getParent() { return parent; } @Override public List<IDrawOrderModelElement> getChildren() { return children; } @Override public void fireChildrenPropertyChange() { firePropertyChange("children", null, getChildren()); //$NON-NLS-1$ } } /** * {@link IDrawOrderModelElement} for the root node. */ public class RootDrawOrderModelElement extends AbstractDrawOrderModelElement { public RootDrawOrderModelElement() { super(null); } } /** * {@link IDrawOrderModelElement} for the draw order nodes. */ public class DrawOrderDrawOrderModelElement extends AbstractDrawOrderModelElement implements Comparable<DrawOrderDrawOrderModelElement> { public final Integer drawOrder; public DrawOrderDrawOrderModelElement(RootDrawOrderModelElement root, Integer drawOrder) { super(root); this.drawOrder = drawOrder; } @Override public int compareTo(DrawOrderDrawOrderModelElement o) { if (drawOrder == null || o.drawOrder == null) { return 0; } return drawOrder.compareTo(o.drawOrder); } } /** * {@link IDrawOrderModelElement} for the layer leaf nodes. */ public class LayerDrawOrderModelElement extends AbstractDrawOrderModelElement { public final ILayerTreeNode node; public LayerDrawOrderModelElement(DrawOrderDrawOrderModelElement parent, ILayerTreeNode node) { super(parent); this.node = node; } @Override public DrawOrderDrawOrderModelElement getParent() { return (DrawOrderDrawOrderModelElement) super.getParent(); } } }