/*
* 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.gwt2.client.map.render.dom;
import org.geomajas.gwt2.client.event.LayerAddedEvent;
import org.geomajas.gwt2.client.event.LayerOrderChangedEvent;
import org.geomajas.gwt2.client.event.LayerOrderChangedHandler;
import org.geomajas.gwt2.client.event.LayerRemovedEvent;
import org.geomajas.gwt2.client.event.MapCompositionHandler;
import org.geomajas.gwt2.client.event.NavigationStartEvent;
import org.geomajas.gwt2.client.event.NavigationStartHandler;
import org.geomajas.gwt2.client.event.NavigationStopEvent;
import org.geomajas.gwt2.client.event.NavigationStopHandler;
import org.geomajas.gwt2.client.map.MapConfiguration;
import org.geomajas.gwt2.client.map.MapEventBus;
import org.geomajas.gwt2.client.map.ViewPort;
import org.geomajas.gwt2.client.map.layer.Layer;
import org.geomajas.gwt2.client.map.layer.LayersModel;
import org.geomajas.gwt2.client.map.render.LayerRenderer;
import org.geomajas.gwt2.client.map.render.LayersModelRenderer;
import org.geomajas.gwt2.client.map.render.RenderingInfo;
import org.geomajas.gwt2.client.map.render.dom.container.HtmlContainer;
import org.geomajas.gwt2.client.map.render.dom.container.HtmlGroup;
import org.geomajas.gwt2.client.map.render.dom.container.HtmlObject;
import org.geomajas.gwt2.client.service.DomService;
import java.util.HashMap;
import java.util.Map;
/**
* Default implementation of the {@link org.geomajas.gwt2.client.map.render.LayersModelRenderer}. Delegates the
* rendering to specific {@link org.geomajas.gwt2.client.map.render.LayerRenderer}s. Also checks the {@link
* org.geomajas.gwt2.client.map.MapConfiguration} to see if layer should be animated or not before delegating.
*
* @author Pieter De Graef
*/
public class DomLayersModelRenderer implements LayersModelRenderer {
private final LayersModel layersModel;
private final ViewPort viewPort;
private final Map<Layer, LayerRenderer> layerRenderers;
private final Map<Layer, HtmlContainer> layerContainers;
private final Map<Layer, Boolean> layerAnimation;
private MapConfiguration configuration;
private HtmlContainer layersModelContainer;
private boolean navigating;
// ------------------------------------------------------------------------
// Constructor:
// ------------------------------------------------------------------------
public DomLayersModelRenderer(LayersModel layersModel, ViewPort viewPort, MapEventBus eventBus) {
this.layersModel = layersModel;
this.viewPort = viewPort;
this.layerRenderers = new HashMap<Layer, LayerRenderer>();
this.layerContainers = new HashMap<Layer, HtmlContainer>();
this.layerAnimation = new HashMap<Layer, Boolean>();
// register all layers
for (int i = 0; i < layersModel.getLayerCount(); i++) {
LayerRenderer layerRenderer = layersModel.getLayer(i).getRenderer();
if (layerRenderer != null) {
registerLayerRenderer(layersModel.getLayer(i), layerRenderer);
}
}
// Keep the list of LayerRenderers synchronized with the list of layers:
eventBus.addMapCompositionHandler(new MapCompositionHandler() {
@Override
public void onLayerRemoved(LayerRemovedEvent event) {
layersModelContainer.remove(getOrCreateLayerContainer(event.getLayer()));
layerRenderers.remove(event.getLayer());
layerContainers.remove(event.getLayer());
}
@Override
public void onLayerAdded(LayerAddedEvent event) {
LayerRenderer layerRenderer = event.getLayer().getRenderer();
if (layerRenderer != null) {
registerLayerRenderer(event.getLayer(), layerRenderer);
layerRenderer.render(new RenderingInfo(getOrCreateLayerContainer(event.getLayer()),
DomLayersModelRenderer.this.viewPort.getView(), null));
}
}
});
// Keep the layer order synchronized with the LayersModel:
eventBus.addLayerOrderChangedHandler(new LayerOrderChangedHandler() {
@Override
public void onLayerOrderChanged(LayerOrderChangedEvent event) {
if (event.getFromIndex() < layersModelContainer.getChildCount()) {
int toIndex = event.getToIndex() > layersModelContainer.getChildCount() ? layersModelContainer
.getChildCount() : event.getToIndex();
HtmlObject layerContainer = layersModelContainer.getChild(event.getFromIndex());
if (layerContainer != null) {
layersModelContainer.remove(layerContainer);
layersModelContainer.insert(layerContainer, toIndex);
}
}
}
});
eventBus.addNavigationStartHandler(new NavigationStartHandler() {
@Override
public void onNavigationStarted(NavigationStartEvent event) {
navigating = true;
// Go over all layer to see if they should be animated or not:
for (Layer layer : layerRenderers.keySet()) {
if (!isAnimated(layer)) {
// This layer is not animated, hide it before the navigation starts:
HtmlContainer layerContainer = getOrCreateLayerContainer(layer);
LayerRenderer layerRenderer = layerRenderers.get(layer);
layerRenderer.render(new RenderingInfo(layerContainer, event.getTrajectory().getView(0.0),
event.getTrajectory()));
DomService.applyTransition(layerContainer.asWidget().getElement(), new String[] { "opacity" },
new Integer[] { 0 });
layerContainer.asWidget().getElement().getStyle().setOpacity(0.0f);
}
}
}
});
eventBus.addNavigationStopHandler(new NavigationStopHandler() {
@Override
public void onNavigationStopped(NavigationStopEvent event) {
navigating = false;
// Go over all layer to see if they should be animated or not:
for (Layer layer : layerRenderers.keySet()) {
if (!isAnimated(layer)) {
// This layer is not animated, hide it before the navigation starts:
HtmlContainer layerContainer = getOrCreateLayerContainer(layer);
LayerRenderer layerRenderer = layerRenderers.get(layer);
layerRenderer.render(new RenderingInfo(layerContainer, event.getView(), null));
if (DomLayersModelRenderer.this.configuration != null) {
DomService.applyTransition(layerContainer.asWidget().getElement(),
new String[] { "opacity" },
new Integer[] { DomLayersModelRenderer.this.configuration
.getHintValue(MapConfiguration.FADE_IN_TIME) });
}
layerContainer.asWidget().getElement().getStyle().setOpacity(layer.getOpacity());
}
}
}
});
}
public void setMapConfiguration(MapConfiguration configuration) {
this.configuration = configuration;
}
// ------------------------------------------------------------------------
// LayerRenderer registration:
// ------------------------------------------------------------------------
@Override
public void registerLayerRenderer(Layer layer, LayerRenderer layerRenderer) {
if (layerRenderers.containsKey(layer)) {
layerRenderers.remove(layer);
}
layerRenderers.put(layer, layerRenderer);
}
@Override
public LayerRenderer getLayerRenderer(Layer layer) {
return layerRenderers.get(layer);
}
// ------------------------------------------------------------------------
// BasicRenderer implementation:
// ------------------------------------------------------------------------
@Override
public void render(RenderingInfo renderingInfo) {
if (renderingInfo == null) {
throw new NullPointerException("RenderingInfo cannot be null.");
}
if (!(renderingInfo.getWidget() instanceof HtmlContainer)) {
throw new IllegalArgumentException("This renderer requires a HtmlContainer to render in.");
}
layersModelContainer = (HtmlContainer) renderingInfo.getWidget();
// Delegate to the layers in layer order:
for (int i = 0; i < layersModel.getLayerCount(); i++) {
Layer layer = layersModel.getLayer(i);
// If we're in the middle of an animation and the layer does not support it, skip this layer:
if (navigating && !isAnimated(layer)) {
continue;
}
// Adjust the rendering info, to use a layer specific container widget:
RenderingInfo layerInfo = new RenderingInfo(getOrCreateLayerContainer(layer), renderingInfo.getView(),
renderingInfo.getTrajectory());
LayerRenderer layerRenderer = layerRenderers.get(layer);
layerRenderer.render(layerInfo);
}
}
public DomTileLevelLayerRenderer getCurrentRenderer() {
return (DomTileLevelLayerRenderer) layersModel.getLayer(0).getRenderer();
}
@Override
public boolean isAnimated(Layer layer) {
if (!layerAnimation.containsKey(layer)) {
return false;
}
return layerAnimation.get(layer);
}
@Override
public void setAnimated(Layer layer, boolean animated) {
if (layerAnimation.containsKey(layer)) {
layerAnimation.remove(layer);
}
layerAnimation.put(layer, animated);
}
// ------------------------------------------------------------------------
// Private methods:
// ------------------------------------------------------------------------
private HtmlContainer getOrCreateLayerContainer(Layer layer) {
if (layerContainers.containsKey(layer)) {
return layerContainers.get(layer);
}
HtmlContainer layerContainer = new HtmlGroup();
layerContainer.asWidget().getElement().setId(layer.getId());
layersModelContainer.add(layerContainer);
layerContainers.put(layer, layerContainer);
return layerContainer;
}
}