package org.osmdroid.views.overlay.infowindow;
import java.util.ArrayList;
import org.osmdroid.api.IMapView;
import org.osmdroid.config.Configuration;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/** {@link org.osmdroid.views.overlay.infowindow.InfoWindow} is a (pop-up-) View that can
* be displayed on an {@link org.osmdroid.views.MapView}, associated to a
* {@link org.osmdroid.api.IGeoPoint}.
*
* Typical usage: cartoon-like bubbles displayed when clicking an overlay item (i.e. a
* {@link org.osmdroid.views.overlay.Marker}).
* It mimics the InfoWindow class of Google Maps JavaScript API V3.
* Main differences are:
* <ul>
* <li>Structure and content of the view is let to the responsibility of the caller. </li>
* <li>The same InfoWindow can be associated to many items. </li>
* </ul>
*
* This is an abstract class.
*
* <img alt="Class diagram around Marker class" width="686" height="413" src='./doc-files/marker-infowindow-classes.png' />
*
* @see MarkerInfoWindow
* @author M.Kergall
*/
public abstract class InfoWindow {
protected View mView;
protected boolean mIsVisible;
protected MapView mMapView;
/**
* @param layoutResId the id of the view resource.
* @param mapView the mapview on which is hooked the view
*/
public InfoWindow(int layoutResId, MapView mapView) {
mMapView = mapView;
mIsVisible = false;
ViewGroup parent=(ViewGroup)mapView.getParent();
Context context = mapView.getContext();
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(layoutResId, parent, false);
mView.setTag(this);
}
/**
* may return null if the info window hasn't been attached yet
* @return
*/
public MapView getMapView(){
return mMapView;
}
/**
* Returns the Android view. This allows to set its content.
* @return the Android view
*/
public View getView() {
return(mView);
}
/**
* open the InfoWindow at the specified GeoPosition + offset.
* If it was already opened, close it before reopening.
* @param object the graphical object on which is hooked the view
* @param position to place the window on the map
* @param offsetX (&offsetY) the offset of the view to the position, in pixels.
* This allows to offset the view from the object position.
*/
public void open(Object object, GeoPoint position, int offsetX, int offsetY) {
close(); //if it was already opened
onOpen(object);
MapView.LayoutParams lp = new MapView.LayoutParams(
MapView.LayoutParams.WRAP_CONTENT,
MapView.LayoutParams.WRAP_CONTENT,
position, MapView.LayoutParams.BOTTOM_CENTER,
offsetX, offsetY);
if (mMapView!=null && mView!=null) {
mMapView.addView(mView, lp);
mIsVisible = true;
} else {
Log.w(IMapView.LOGTAG, "Error trapped, InfoWindow.open mMapView: " + (mMapView==null ? "null" : "ok") + " mView: " + (mView==null ? "null" : "ok"));
}
}
public void close() {
if (mIsVisible) {
mIsVisible = false;
((ViewGroup)mView.getParent()).removeView(mView);
onClose();
}
}
/**
* this destroys the window and all references to views
*/
public void onDetach(){
close();
if (mView!=null)
mView.setTag(null);
mView=null;
mMapView=null;
if (Configuration.getInstance().isDebugMode())
Log.d(IMapView.LOGTAG, "Marked detached");
}
public boolean isOpen(){
return mIsVisible;
}
/** close all InfoWindows currently opened on this MapView */
static public void closeAllInfoWindowsOn(MapView mapView){
ArrayList<InfoWindow> opened = getOpenedInfoWindowsOn(mapView);
for (InfoWindow infoWindow:opened){
infoWindow.close();
}
}
/** return all InfoWindows currently opened on this MapView */
static public ArrayList<InfoWindow> getOpenedInfoWindowsOn(MapView mapView){
int count = mapView.getChildCount();
ArrayList<InfoWindow> opened = new ArrayList<InfoWindow>(count);
for (int i = 0; i < count; i++) {
final View child = mapView.getChildAt(i);
Object tag = child.getTag();
if (tag != null && tag instanceof InfoWindow){
InfoWindow infoWindow = (InfoWindow)tag;
opened.add(infoWindow);
}
}
return opened;
}
//Abstract methods to implement in sub-classes:
public abstract void onOpen(Object item);
public abstract void onClose();
}