/*******************************************************************************
* 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.worldwind.common.layers.point.types;
import gov.nasa.worldwind.avlist.AVList;
import gov.nasa.worldwind.event.SelectEvent;
import gov.nasa.worldwind.event.SelectListener;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.MarkerLayer;
import gov.nasa.worldwind.pick.PickedObject;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.GlobeAnnotation;
import gov.nasa.worldwind.render.Material;
import gov.nasa.worldwind.render.markers.BasicMarkerAttributes;
import gov.nasa.worldwind.render.markers.BasicMarkerShape;
import gov.nasa.worldwind.render.markers.Marker;
import gov.nasa.worldwind.render.markers.MarkerAttributes;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import au.gov.ga.earthsci.worldwind.common.WorldWindowRegistry;
import au.gov.ga.earthsci.worldwind.common.layers.Bounds;
import au.gov.ga.earthsci.worldwind.common.layers.point.PointLayer;
import au.gov.ga.earthsci.worldwind.common.layers.point.PointLayerHelper;
import au.gov.ga.earthsci.worldwind.common.layers.styled.StyleAndText;
import au.gov.ga.earthsci.worldwind.common.render.DiskMarkerShape;
import au.gov.ga.earthsci.worldwind.common.util.DefaultLauncher;
/**
* {@link PointLayer} implementation which extends {@link MarkerLayer} and uses
* Markers to represent points.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class MarkerPointLayer extends MarkerLayer implements PointLayer, SelectListener
{
private final PointLayerHelper helper;
private List<Marker> markers = new ArrayList<Marker>();
private UrlMarker pickedMarker;
private Material highlightMaterial = new Material(Color.white);
private GlobeAnnotation tooltipAnnotation;
public MarkerPointLayer(PointLayerHelper helper)
{
this.helper = helper;
getMarkerRenderer().setOverrideMarkerElevation(true);
getMarkerRenderer().setElevation(0);
// Init tooltip annotation
this.tooltipAnnotation = new GlobeAnnotation("", Position.fromDegrees(0, 0, 0));
Font font = Font.decode("Arial-Plain-16");
this.tooltipAnnotation.getAttributes().setFont(font);
this.tooltipAnnotation.getAttributes().setSize(new Dimension(270, 0));
this.tooltipAnnotation.getAttributes().setDistanceMinScale(1);
this.tooltipAnnotation.getAttributes().setDistanceMaxScale(1);
this.tooltipAnnotation.getAttributes().setVisible(false);
this.tooltipAnnotation.setPickEnabled(false);
this.tooltipAnnotation.setAlwaysOnTop(true);
WorldWindowRegistry.INSTANCE.addSelectListener(this);
}
@Override
public void render(DrawContext dc)
{
if (isEnabled())
{
helper.requestPoints(this);
}
this.tooltipAnnotation.render(dc);
super.render(dc);
}
@Override
public Bounds getBounds()
{
return helper.getBounds();
}
@Override
public boolean isFollowTerrain()
{
return helper.isFollowTerrain();
}
@Override
public void addPoint(Position position, AVList attributeValues)
{
MarkerAttributes attributes = new BasicMarkerAttributes();
StyleAndText properties = helper.getStyle(attributeValues);
properties.style.setPropertiesFromAttributes(helper.getContext(), attributeValues, attributes);
fixShapeType(attributes);
UrlMarker marker = new UrlMarker(position, attributes);
marker.setUrl(properties.link);
marker.setTooltipText(properties.text);
markers.add(marker);
}
/**
* In the {@link BasicMarkerShape#createShapeInstance(String)} function, the
* shape type string is checked for equality instead of using the equals()
* function. This function will replace a shape type with the actual
* constant, so that the == check works.
*
* @param attributes
*/
public static void fixShapeType(MarkerAttributes attributes)
{
//someone decided to use string equality instead of the equals function when testing the
//shape type; so fix it here instead (see BasicMarkerShape.createShapeInstance()).
String shapetype = attributes.getShapeType();
if (shapetype != null)
{
if (BasicMarkerShape.SPHERE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.SPHERE);
}
else if (BasicMarkerShape.CUBE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.CUBE);
}
else if (BasicMarkerShape.CONE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.CONE);
}
else if (BasicMarkerShape.CYLINDER.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.CYLINDER);
}
else if (BasicMarkerShape.HEADING_ARROW.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.HEADING_ARROW);
}
else if (BasicMarkerShape.HEADING_LINE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.HEADING_LINE);
}
else if (BasicMarkerShape.ORIENTED_SPHERE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_SPHERE);
}
else if (BasicMarkerShape.ORIENTED_CUBE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_CUBE);
}
else if (BasicMarkerShape.ORIENTED_CONE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_CONE);
}
else if (BasicMarkerShape.ORIENTED_CYLINDER.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_CYLINDER);
}
else if (BasicMarkerShape.ORIENTED_SPHERE_LINE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_SPHERE_LINE);
}
else if (BasicMarkerShape.ORIENTED_CONE_LINE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_CONE_LINE);
}
else if (BasicMarkerShape.ORIENTED_CYLINDER_LINE.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(BasicMarkerShape.ORIENTED_CYLINDER_LINE);
}
else if (DiskMarkerShape.DISK.equalsIgnoreCase(shapetype))
{
attributes.setShapeType(DiskMarkerShape.DISK);
}
}
}
@Override
public void loadComplete()
{
setMarkers(markers);
}
@Override
public URL getUrl() throws MalformedURLException
{
return helper.getUrl();
}
@Override
public String getDataCacheName()
{
return helper.getDataCacheName();
}
@Override
public void selected(SelectEvent e)
{
if (e == null)
{
return;
}
PickedObject topPickedObject = e.getTopPickedObject();
if (topPickedObject != null && topPickedObject.getObject() instanceof UrlMarker)
{
if (pickedMarker != null)
{
highlight(pickedMarker, false);
}
pickedMarker = (UrlMarker) topPickedObject.getObject();
highlight(pickedMarker, true);
if (e.getEventAction() == SelectEvent.LEFT_CLICK)
{
String link = pickedMarker.getUrl();
if (link != null)
{
try
{
URL url = new URL(link);
DefaultLauncher.openURL(url);
}
catch (MalformedURLException m)
{
}
}
}
}
else if (pickedMarker != null)
{
highlight(pickedMarker, false);
pickedMarker = null;
}
}
protected void highlight(UrlMarker marker, boolean highlight)
{
if (highlight)
{
marker.backupMaterial();
marker.getAttributes().setMaterial(highlightMaterial);
this.tooltipAnnotation.setText(marker.getTooltipText());
this.tooltipAnnotation.setPosition(marker.getPosition());
this.tooltipAnnotation.getAttributes().setVisible(true);
}
else
{
marker.restoreMaterial();
this.tooltipAnnotation.getAttributes().setVisible(false);
}
}
@Override
public boolean isLoading()
{
return helper.getPointProvider().isLoading();
}
@Override
public void addLoadingListener(LoadingListener listener)
{
helper.getPointProvider().addLoadingListener(listener);
}
@Override
public void removeLoadingListener(LoadingListener listener)
{
helper.getPointProvider().removeLoadingListener(listener);
}
}