/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.gwt.client.widget;
import java.util.ArrayList;
import java.util.List;
import org.geomajas.configuration.client.ClientVectorLayerInfo;
import org.geomajas.gwt.client.Geomajas;
import org.geomajas.gwt.client.map.MapModel;
import org.geomajas.gwt.client.map.event.LayerChangedHandler;
import org.geomajas.gwt.client.map.event.LayerFilteredEvent;
import org.geomajas.gwt.client.map.event.LayerFilteredHandler;
import org.geomajas.gwt.client.map.event.LayerLabeledEvent;
import org.geomajas.gwt.client.map.event.LayerShownEvent;
import org.geomajas.gwt.client.map.event.LayerStyleChangeEvent;
import org.geomajas.gwt.client.map.event.LayerStyleChangedHandler;
import org.geomajas.gwt.client.map.event.MapModelChangedEvent;
import org.geomajas.gwt.client.map.event.MapModelChangedHandler;
import org.geomajas.gwt.client.map.layer.Layer;
import org.geomajas.gwt.client.map.layer.RasterLayer;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.util.UrlBuilder;
import org.geomajas.gwt.client.util.WidgetLayout;
import org.geomajas.sld.FeatureTypeStyleInfo;
import org.geomajas.sld.RuleInfo;
import org.geomajas.sld.UserStyleInfo;
import com.google.gwt.event.shared.HandlerRegistration;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
/**
* <p>
* Widget that shows the styles of the currently visible layers. For vector layers, there can be many styles. Note that
* this widget will react automatically to the visibility status of the layers.
* </p>
*
* @author Frank Wynants
* @author Pieter De Graef
*/
public class Legend extends VLayout {
private List<HandlerRegistration> registrations = new ArrayList<HandlerRegistration>();
private HandlerRegistration loadedRegistration;
private MapModel mapModel;
private boolean staticLegend;
// -------------------------------------------------------------------------
// Constructor:
// -------------------------------------------------------------------------
/**
* A legend needs to be instantiated with the MapModel that contains (or will contain) the list of layers that this
* legend should listen to.
*
* @param mapModel
* map model
* @param staticLegend
* should this Legend be statically rendered?
* @since 1.10.0
*/
public Legend(MapModel mapModel, boolean staticLegend) {
this(mapModel);
setMargin(WidgetLayout.marginSmall);
this.staticLegend = staticLegend;
}
/**
* A legend needs to be instantiated with the MapModel that contains (or will contain) the list of layers that this
* legend should listen to.
*
* @param mapModel
* map model
*/
public Legend(MapModel mapModel) {
setMembersMargin(WidgetLayout.marginSmall);
this.mapModel = mapModel;
loadedRegistration = mapModel.addMapModelChangedHandler(new MapModelChangedHandler() {
public void onMapModelChanged(MapModelChangedEvent event) {
initialize();
}
});
}
// -------------------------------------------------------------------------
// Public methods:
// -------------------------------------------------------------------------
/**
* Render the legend. This triggers a complete redraw.
*/
public void render() {
removeMembers(getMembers());
// Then go over all layers, to draw styles:
for (Layer<?> layer : mapModel.getLayers()) {
if (staticLegend || layer.isShowing()) {
// Go over every truly visible layer:
if (layer instanceof VectorLayer) {
ClientVectorLayerInfo layerInfo = ((VectorLayer) layer).getLayerInfo();
// For vector layer; loop over the style definitions:
UserStyleInfo userStyle = layerInfo.getNamedStyleInfo().getUserStyle();
FeatureTypeStyleInfo info = userStyle.getFeatureTypeStyleList().get(0);
for (int i = 0; i < info.getRuleList().size(); i++) {
RuleInfo rule = info.getRuleList().get(i);
// use title if present, name if not
String title = (rule.getTitle() != null ? rule.getTitle() : rule.getName());
// fall back to style name
if (title == null) {
title = layerInfo.getNamedStyleInfo().getName();
}
addVector((VectorLayer) layer, i, title);
}
} else if (layer instanceof RasterLayer) {
addRaster((RasterLayer) layer);
}
}
}
}
// -------------------------------------------------------------------------
// Getters and setters:
// -------------------------------------------------------------------------
public MapModel getMapModel() {
return mapModel;
}
/**
* If staticLegend is true all layers will always be shown, not just when they are visible.
*
* @return if this is a static Legend
* @since 1.10.0
*/
public boolean isStaticLegend() {
return staticLegend;
}
/**
* Set if this legend should be static or dynamic.
*
* @param staticLegend should legend be static?
* @since 1.10.0
*/
public void setStaticLegend(boolean staticLegend) {
this.staticLegend = staticLegend;
}
// -------------------------------------------------------------------------
// Private methods:
// -------------------------------------------------------------------------
private void addVector(VectorLayer layer, int ruleIndex, String title) {
HLayout layout = new HLayout(WidgetLayout.marginSmall);
layout.setHeight(WidgetLayout.legendVectorRowHeight);
UrlBuilder urlBuilder = new UrlBuilder(Geomajas.getDispatcherUrl());
urlBuilder.addPath("legendgraphic");
urlBuilder.addPath(layer.getServerLayerId());
urlBuilder.addPath(layer.getLayerInfo().getNamedStyleInfo().getName());
urlBuilder.addPath(ruleIndex + ".png");
Img icon = new Img(urlBuilder.toString(), WidgetLayout.legendRasterIconWidth,
WidgetLayout.legendRasterIconHeight);
icon.setLayoutAlign(Alignment.LEFT);
layout.addMember(icon);
Label label = new Label(title);
label.setWrap(false);
label.setLayoutAlign(Alignment.LEFT);
layout.addMember(label);
addMember(layout);
}
private void addRaster(RasterLayer layer) {
HLayout layout = new HLayout(WidgetLayout.marginSmall);
layout.setHeight(WidgetLayout.legendRasterRowHeight);
UrlBuilder urlBuilder = new UrlBuilder(Geomajas.getDispatcherUrl());
urlBuilder.addPath("legendgraphic");
urlBuilder.addPath(layer.getServerLayerId() + ".png");
Img icon =
new Img(urlBuilder.toString(), WidgetLayout.legendRasterIconWidth, WidgetLayout.legendRasterIconHeight);
icon.setLayoutAlign(Alignment.LEFT);
layout.addMember(icon);
Label label = new Label(layer.getLabel());
label.setWrap(false);
label.setLayoutAlign(Alignment.LEFT);
layout.addMember(label);
addMember(layout);
}
/** Called when the MapModel configuration has been loaded. */
private void initialize() {
registrations.clear();
for (Layer<?> layer : mapModel.getLayers()) {
registrations.add(layer.addLayerChangedHandler(new LayerChangedHandler() {
public void onLabelChange(LayerLabeledEvent event) {
}
public void onVisibleChange(LayerShownEvent event) {
render();
}
}));
registrations.add(layer.addLayerStyleChangedHandler(new LayerStyleChangedHandler() {
public void onLayerStyleChange(LayerStyleChangeEvent event) {
render();
}
}));
}
for (final VectorLayer layer : mapModel.getVectorLayers()) {
layer.addLayerFilteredHandler(new LayerFilteredHandler() {
public void onFilterChange(LayerFilteredEvent event) {
render();
}
});
}
render();
}
/** Remove all handlers on unload. */
protected void onUnload() {
if (registrations != null) {
for (HandlerRegistration registration : registrations) {
registration.removeHandler();
}
}
loadedRegistration.removeHandler();
super.onUnload();
}
}