/* * GeoSolutions - MapstoreMobile - GeoSpatial Framework on Android based devices * Copyright (C) 2013 GeoSolutions (www.geo-solutions.it) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.android.map.overlay.managers; import it.geosolutions.android.map.MapsActivity; import it.geosolutions.android.map.R; import it.geosolutions.android.map.listeners.LayerChangeListener; import it.geosolutions.android.map.mapstore.model.MapStoreConfiguration; import it.geosolutions.android.map.mapstore.utils.MapStoreUtils; import it.geosolutions.android.map.model.Layer; import it.geosolutions.android.map.model.MSMMap; import it.geosolutions.android.map.overlay.MarkerOverlay; import it.geosolutions.android.map.overlay.MultiSourceOverlay; import it.geosolutions.android.map.overlay.SpatialiteOverlay; import it.geosolutions.android.map.overlay.items.DescribedMarker; import it.geosolutions.android.map.renderer.RenderingException; import it.geosolutions.android.map.utils.MarkerUtils; import it.geosolutions.android.map.view.AdvancedMapView; import java.util.ArrayList; import org.mapsforge.android.maps.overlay.MyLocationOverlay; import org.mapsforge.android.maps.overlay.Overlay; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.widget.Toast; /** * Manages overlays of the AdvancedMapView * @author Lorenzo Natali (lorenzo.natali@geo-solutions.it) * */ public class MultiSourceOverlayManager implements OverlayManager { /** MARKERS_ENABLED_FLAG */ private static final String MARKERS_ENABLED_FLAG = "markers"; /** DATA_ENABLED_FLAG */ private static final String DATA_ENABLED_FLAG = "data"; /** MAPSTORE_ENABLED_FLAG */ private static final String MAPSTORE_ENABLED_FLAG = "mapstore"; public static final String MAPSTORE_CONFIG = "MAPSTORE_CONFIG"; private static final String LAYERS = "MAPSTORE_LAYERS"; //------------------------------------------------------ //PUBLIC VARIABLES //------------------------------------------------------ public MarkerOverlay markerOverlay; public SpatialiteOverlay spatialiteOverlay; public boolean markerActivated; public boolean spatialActivated; public boolean mapstoreActivated; public MultiSourceOverlay layerOverlay; private MapStoreConfiguration mapStoreConfig; private AdvancedMapView mapView; /** * returns the <MapStoreConfiguration> for the WMSLayer * @return */ public MapStoreConfiguration getMapStoreConfig() { return mapStoreConfig; } /** * set the * @param mapStoreConfig for the WMSLayer */ public void setMapStoreConfig(MapStoreConfiguration mapStoreConfig) { this.mapStoreConfig = mapStoreConfig; } /** * the <OverlayChangeListener> that notifies the changes in the overlay * visibility and events of add of a <MapStoreConfiguration> */ public LayerChangeListener overlayChangeListener; private LayerChangeListener listener; /** * Create the <OverlayManager> * it automatically binds to the mapView and initialize overlays * @param mapView */ public MultiSourceOverlayManager(AdvancedMapView mapView) { this.mapView =mapView; //add spatialite overlay mapView.setOverlayManger(this); this.spatialiteOverlay = new SpatialiteOverlay(); spatialiteOverlay.setProjection(mapView.getProjection()); layerOverlay = new MultiSourceOverlay(this); layerOverlay.setProjection(mapView.getProjection()); setMarkerOverlay(new MarkerOverlay()); } public void redrawLayer(Layer layer) { final Layer l = layer; //This does not causes problems //because the argument is used only to choose the //renderer to refresh new Thread(new Runnable() { public void run() { layerOverlay.refreshLayer(l); mapView.getOverlayController().redrawOverlays(); } }).start(); } /** * Add/Remove the Overlay from the mapView if the * * @param itemId * id of the menu item * @param enabled * true to set the layer visible, false to make it not visible */ public void toggleOverlayVisibility(int itemId, boolean enable) { boolean present = false; Overlay overlay = null; Log.v("LAYERS", mapView.getOverlays().size() + " overlays found"); for (Overlay o : mapView.getOverlays()) { if (o.equals(spatialiteOverlay) && itemId == R.id.data) { present = true; Log.v("LAYERS", "data layer is visible"); overlay = o; break; } if (o.equals(layerOverlay) && itemId == R.id.mapstore) { present = true; Log.v("LAYERS", "marker layer is visible"); overlay = o; break; } if (o.equals(markerOverlay) && itemId == R.id.markers) { present = true; Log.v("LAYERS", "marker layer is visible"); overlay = o; break; } } if (present && !enable) { mapView.getOverlays().remove(overlay); mapView.redraw(); Log.v("LAYERS", "removing layer"); } else if (!present && enable) { if (itemId == R.id.data) { //data layer is always at level 0 //mapView.getOverlays().add(0, spatialiteOverlay); Log.v("LAYERS", "add data layer"); }else if(itemId == R.id.mapstore){ if(mapView.getOverlays().size()>0){ mapView.getOverlays().add(1,layerOverlay ); }else{ mapView.getOverlays().add(0, layerOverlay); } } else if (itemId == R.id.markers) { //marker overlay goes always over the data and marker overlay int index = (mapView.getOverlays().contains(spatialiteOverlay) ? 1 :0 ) + (mapView.getOverlays().add(markerOverlay) ? 1 : 0 ); mapView.getOverlays().add(index, markerOverlay); Log.v("LAYERS", "add marker layer"); } mapView.getOverlayController().redrawOverlays(); } } /** * sets the data overlay visible */ public void setDataVisible() { spatialActivated = true; //mapView.getOverlays().add(spatialiteOverlay); } @Override public MarkerOverlay getMarkerOverlay() { return markerOverlay; } /** * Returns the data overlay (deprecated) * @return */ public SpatialiteOverlay getDataOverlay() { return spatialiteOverlay; } @Override public void setMarkerOverlay(MarkerOverlay markerOverlay) { this.markerOverlay= markerOverlay; } /** * Make the marker overlay visible */ public void setMarkerVisible() { //add the marker overlay to the mapView markerActivated =true; mapView.getOverlays().add(markerOverlay); } @Override public void addLocationOverlay(MyLocationOverlay overlay) { mapView.getOverlays().add(mapView.getOverlays().size(), overlay); } @Override public void removeOverlay(Overlay overlay) { mapView.getOverlays().remove(overlay); } public void setLayers(ArrayList<Layer> layers){ setLayers(layers,true); } /** * Set the layers and notify the listener if notify flag is true. * NOTE To Notify the process must be an UI thread!!! * @param layers set the layers in the <MultiSourceOverlay> * @param notify if true, notifies the layers */ public void setLayers(final ArrayList<Layer> layers,boolean notify){ if(layerOverlay == null){ layerOverlay=new MultiSourceOverlay(this); } toggleOverlayVisibility(R.id.mapstore, true); layerOverlay.setLayers(layers); if(notify){ onSetLayers(layers); } Log.v("LAYERS","TOTAL LAYERS:" + layerOverlay.getLayers().size()); } /** * launch the proper events to the layers list * @param layers */ private void onSetLayers(ArrayList<Layer> layers) { LayerChangeListener lcl = getLayerChangeListener(); if(lcl!= null){ lcl.onSetLayers(layers); }else{ Log.w("Overlay Manager","the change listener is not intialized yet"); } } public MultiSourceOverlay getOverlay() { return layerOverlay; } public ArrayList<Layer> getLayers(){ return layerOverlay.getLayers(); } /** * load a MapStore configuration into the WMSOverlay * @param the <MapStoreConfiguration> object to load */ public void loadMapStoreConfig(MapStoreConfiguration result){ if(result == null) { return ; } ArrayList<Layer> l = MapStoreUtils.buildWMSLayers(result); setLayers(l); setMapStoreConfig(result); } /** * save the current status of the layers in the provided bundle * @param savedInstanceState */ public void saveInstanceState(Bundle savedInstanceState) { ArrayList<DescribedMarker> markers = getMarkerOverlay().getMarkers(); savedInstanceState.putParcelableArrayList(MapsActivity.PARAMETERS.MARKERS,MarkerUtils.getMarkersDTO(markers)); savedInstanceState.putBoolean(MARKERS_ENABLED_FLAG, mapView.getOverlays().contains(getMarkerOverlay()));//TODO change for visibility!!! savedInstanceState.putBoolean(DATA_ENABLED_FLAG, mapView.getOverlays().contains(getDataOverlay())); //savedInstanceState.putBoolean(MAPSTORE_ENABLED_FLAG, mapView.getOverlays().contains(getViewOverlay())); savedInstanceState.putSerializable(MAPSTORE_CONFIG, getMapStoreConfig()); savedInstanceState.putSerializable(LAYERS, getLayers()); } /** * restore the state of the overlays from a bundle * @param savedInstanceState */ public void restoreInstanceState(Bundle savedInstanceState) { if(savedInstanceState.getBoolean(MARKERS_ENABLED_FLAG,true)){ setMarkerVisible(); if(savedInstanceState.getBoolean(DATA_ENABLED_FLAG,true)){ setDataVisible(); } } //loadMapStoreConfig((MapStoreConfiguration) savedInstanceState.getSerializable(MAPSTORE_CONFIG)); setLayers((ArrayList<Layer>)savedInstanceState.getSerializable(LAYERS)); toggleOverlayVisibility(R.id.mapstore,true); } /** * Does the default initialization of the Manager */ public void defaultInit() { setMarkerVisible(); } /** * Provides the listener attached to this Manager for Layer Changes * @return the listener */ public LayerChangeListener getLayerChangeListener() { return listener; } /** * Attach the listener to the Manager * @param l */ public void setLayerChangeListener(LayerChangeListener l){ listener = l; } /** * Load the layers containied ind the <MSMMap> provided as argument * @param m the MSMMap to load */ public void loadMap(MSMMap m){ setLayers(m.layers); } /* (non-Javadoc) * @see it.geosolutions.android.map.overlay.managers.OverlayManager#forceRedraw() */ @Override public void forceRedraw() { if(layerOverlay!=null){ layerOverlay.refresh(); } mapView.getOverlayController().redrawOverlays(); } /** * @param e */ public void notifyRenederingException(final RenderingException e) { // this is called from another thread to the UI Thread // so it needs to be posted to the view //TODO: move this in a more complex system for notification on UI final Context c = mapView.getContext(); mapView.post(new Runnable() { public void run() { Toast.makeText(c, e.getToastMessage(), Toast.LENGTH_SHORT).show(); //Toast.makeText(c, R.string.error_rendering, Toast.LENGTH_SHORT).show(); } }); } }