package org.diretto.web.richwebclient.view.widgets.googlemap.client;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.diretto.web.richwebclient.view.base.client.MediaType;
import com.google.gwt.maps.client.base.InfoWindow;
import com.google.gwt.maps.client.base.InfoWindowOptions;
import com.google.gwt.maps.client.event.Event;
import com.google.gwt.maps.client.event.EventCallback;
import com.google.gwt.maps.client.event.HasMouseEvent;
import com.google.gwt.maps.client.event.MouseEventCallback;
import org.diretto.web.richwebclient.view.widgets.googlemap.client.base.AbstractVGoogleMap;
import org.diretto.web.richwebclient.view.widgets.googlemap.client.markers.Marker;
import org.diretto.web.richwebclient.view.widgets.googlemap.client.markers.RegularMarker;
import org.diretto.web.richwebclient.view.widgets.googlemap.client.markers.RegularMarker.RegularMarkerData;
import org.diretto.web.richwebclient.view.widgets.googlemap.server.ExploreGoogleMap;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.Timer;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.UIDL;
/**
* The client side component of the {@link ExploreGoogleMap}.
*
* @author Tobias Schlecht
*/
public final class VExploreGoogleMap extends AbstractVGoogleMap
{
private static final int THUMBNAIL_SIZE = 60;
private static final int POLLING_INTERVAL = 3000;
private boolean initialized = false;
private boolean polling = true;
private Timer timer = null;
private Map<String, RegularMarker> markers = new HashMap<String, RegularMarker>(1000);
private RegularMarker selectedMarker = null;
private InfoWindow openedInfoWindow = null;
private static String selectedMarkerDocumentID = null;
/**
* Constructs a {@link VExploreGoogleMap}.
*/
public VExploreGoogleMap()
{
super();
}
@Override
public void updateFromUIDL(UIDL uidl, final ApplicationConnection applicationConnection)
{
super.updateFromUIDL(uidl, applicationConnection);
if(!initialized)
{
timer = new Timer()
{
@Override
public void run()
{
applicationConnection.sendPendingVariableChanges();
}
};
timer.scheduleRepeating(POLLING_INTERVAL);
exportJavaScriptMethods();
addEventListeners();
initialized = true;
}
else
{
UIDL uidlPolling = uidl.getChildByTagName("polling");
boolean polling = uidlPolling.getBooleanAttribute("value");
if(polling)
{
if(!this.polling)
{
timer.scheduleRepeating(POLLING_INTERVAL);
this.polling = true;
}
}
else
{
if(this.polling)
{
timer.cancel();
this.polling = false;
}
}
UIDL uidlClearMap = uidl.getChildByTagName("clearMap");
boolean clearMap = uidlClearMap.getBooleanAttribute("value");
if(clearMap)
{
for(RegularMarker marker : markers.values())
{
marker.setMap(null);
}
markers.clear();
applicationConnection.updateVariable(paintableID, "cleared", true, true);
}
UIDL uidlDocuments = uidl.getChildByTagName("documents");
for(Iterator<Object> iterator = uidlDocuments.getChildIterator(); iterator.hasNext();)
{
UIDL uidlDocument = (UIDL) iterator.next();
String id = uidlDocument.getStringAttribute("id");
String title = uidlDocument.getStringAttribute("title");
String publisher = uidlDocument.getStringAttribute("publisher");
double positionLatitude = uidlDocument.getDoubleAttribute("position-latitude");
double positionLongitude = uidlDocument.getDoubleAttribute("position-longitude");
long averageTime = uidlDocument.getLongAttribute("average-time");
MediaType mediaType = MediaType.valueOf(uidlDocument.getStringAttribute("media-type"));
int votesUP = uidlDocument.getIntAttribute("votes-up");
int votesDOWN = uidlDocument.getIntAttribute("votes-down");
String thumbnailURL = uidlDocument.getStringAttribute("thumbnail-url");
RegularMarkerData regularMarkerData = new RegularMarkerData(id, title, publisher, averageTime, votesUP, votesDOWN, thumbnailURL);
RegularMarker marker = new RegularMarker(map, positionLatitude, positionLongitude, mediaType, regularMarkerData);
addMarkerEventListeners(marker);
markers.put(id, marker);
if(selectedMarker != null && id.equals(selectedMarkerDocumentID))
{
if(openedInfoWindow != null)
{
Event.trigger(marker, "mousedown");
}
else
{
selectedMarker = marker;
marker.select();
}
}
else
{
marker.setZIndex(-1);
}
}
}
}
/**
* Exports the necessary JavaScript methods.
*/
private native void exportJavaScriptMethods()
/*-{
$wnd.loadDocumentView = $entry(this.@org.diretto.web.richwebclient.view.widgets.googlemap.client.VExploreGoogleMap::loadDocumentView());
}-*/;
/**
* Sets the content of the given {@link InfoWindow}.
*
* @param infoWindow An {@code InfoWindow}
* @param regularMarkerData The corresponding {@code RegularMarkerData}
* @param positionLatitude The corresponding {@code Position} latitude in
* degrees
* @param positionLongitude The corresponding {@code Position} longitude in
* degrees
*/
private void setInfoWindowContent(InfoWindow infoWindow, RegularMarkerData regularMarkerData, double positionLatitude, double positionLongitude)
{
String content = "" +
"<div id=\"googleMapsInfoWindow\" style=\"height:220px; font-size:11px; line-height:15px;\">" +
"<div style=\"width:230px; height:1px;\" />" +
"<div style=\"width:205px; margin-bottom:10px; overflow:hidden;\">" +
"<a href=\"javascript:loadDocumentView()\" style=\"font-size:12px; font-weight:bold; color:#1B699F; text-decoration:none;\">" + SafeHtmlUtils.htmlEscape(regularMarkerData.getTitle()) + "</a>" +
"</div>" +
"<div style=\"margin-bottom:12px;\">" +
"<a href=\"javascript:loadDocumentView()\">" +
"<img src=\"" + regularMarkerData.getThumbnailURL() +"\" alt=\"\" style=\"width:" + THUMBNAIL_SIZE + "px; height:" + THUMBNAIL_SIZE + "px; border:1px solid #000000;\" />" +
"</a>" +
"</div>" +
"<div>" +
"<hr />" +
"</div>" +
"<div style=\"width:205px; overflow:hidden;\">" +
"<span style=\"font-weight:bold\">Publisher: </span>" +
"<span>" + SafeHtmlUtils.htmlEscape(regularMarkerData.getPublisher()) + "</span>" +
"</div>" +
"<div>" +
"<hr />" +
"</div>" +
"<div style=\"white-space:nowrap;\">" +
"<span style=\"font-weight:bold\">Position Latitude: </span>" +
"<span>" + positionLatitude + "</span>" +
"</div>" +
"<div style=\"white-space:nowrap;\">" +
"<span style=\"font-weight:bold\">Position Longitude: </span>" +
"<span>" + positionLongitude + "</span>" +
"</div>" +
"<div style=\"white-space:nowrap;\">" +
"<span style=\"font-weight:bold\">Time: </span>" +
"<span>" +
DateTimeFormat.getFormat("dd.MM.yyyy' '-' 'hh:mm:ss' 'aa").format(new Date(regularMarkerData.getAverageTime())) +
"</span>" +
"</div>" +
"<div>" +
"<hr />" +
"</div>" +
"<div style=\"white-space:nowrap;\">" +
"<span style=\"font-weight:bold\">UP Votes: </span>" +
"<span>" + regularMarkerData.getVotesUP() + "</span>" +
"<span> </span>" +
"<span style=\"font-weight:bold\">DOWN Votes: </span>" +
"<span>" + regularMarkerData.getVotesDOWN() + "</span>" +
"</div>" +
"</div>";
infoWindow.setContent(content);
}
/**
* Styles the opened {@link InfoWindow} and thereby resolves the problem
* with the unwanted scroll bars.
*/
private static native void styleInfoWindow()
/*-{
$wnd.document.getElementById('googleMapsInfoWindow').parentNode.style.overflow='';
$wnd.document.getElementById('googleMapsInfoWindow').parentNode.style.width=$wnd.document.getElementById('googleMapsInfoWindow').parentNode.width;
$wnd.document.getElementById('googleMapsInfoWindow').parentNode.parentNode.style.overflow='';
$wnd.document.getElementById('googleMapsInfoWindow').parentNode.parentNode.style.overflowX='hidden';
$wnd.document.getElementById('googleMapsInfoWindow').parentNode.parentNode.style.overflowY='auto';
$wnd.document.getElementById('googleMapsInfoWindow').style.width=($wnd.document.getElementById('googleMapsInfoWindow').parentNode.parentNode.width - 25);
}-*/;
/**
* Initializes the loading process of the {@code DocumentView} for the
* {@code Document} corresponding to the currently selected {@link Marker}.
*/
private void loadDocumentView()
{
if(selectedMarkerDocumentID != null)
{
applicationConnection.updateVariable(paintableID, "documentView", selectedMarkerDocumentID, true);
}
}
/**
* Adds {@code EventListener}s to the given {@link RegularMarker}.
*
* @param marker A {@code RegularMarker}
*/
private void addMarkerEventListeners(final RegularMarker marker)
{
Event.addListener(marker, "mousedown", new MouseEventCallback()
{
@Override
public void callback(HasMouseEvent event)
{
if(marker != selectedMarker)
{
if(openedInfoWindow != null)
{
openedInfoWindow.close();
}
if(selectedMarker != null)
{
selectedMarker.deselect();
}
InfoWindow infoWindow = new InfoWindow();
InfoWindowOptions infoWindowOptions = new InfoWindowOptions();
infoWindowOptions.setDisableAutoPan(true);
infoWindowOptions.setMaxWidth(300);
infoWindow.setOptions(infoWindowOptions);
addInfoWindowEventListeners(infoWindow);
setInfoWindowContent(infoWindow, marker.getRegularMarkerData(), marker.getPosition().getLatitude(), marker.getPosition().getLongitude());
infoWindow.open(map, marker);
openedInfoWindow = infoWindow;
selectedMarker = marker;
selectedMarkerDocumentID = marker.getRegularMarkerData().getDocumentID();
}
else if(openedInfoWindow == null)
{
InfoWindow infoWindow = new InfoWindow();
InfoWindowOptions infoWindowOptions = new InfoWindowOptions();
infoWindowOptions.setDisableAutoPan(true);
infoWindowOptions.setMaxWidth(300);
infoWindow.setOptions(infoWindowOptions);
addInfoWindowEventListeners(infoWindow);
setInfoWindowContent(infoWindow, marker.getRegularMarkerData(), marker.getPosition().getLatitude(), marker.getPosition().getLongitude());
infoWindow.open(map, marker);
openedInfoWindow = infoWindow;
}
}
});
}
/**
* Adds {@code EventListener}s to the given {@link InfoWindow}.
*
* @param infoWindow An {@code InfoWindow}
*/
private void addInfoWindowEventListeners(final InfoWindow infoWindow)
{
Event.addListener(infoWindow, "closeclick", new EventCallback()
{
@Override
public void callback()
{
openedInfoWindow = null;
}
});
Event.addListener(infoWindow, "domready", new EventCallback()
{
@Override
public void callback()
{
styleInfoWindow();
}
});
}
/**
* Adds {@code EventListener}s to the map.
*/
private void addEventListeners()
{
Event.addListener(map, "rightclick", new MouseEventCallback()
{
@Override
public void callback(HasMouseEvent event)
{
if(selectedMarker != null)
{
map.setCenter(selectedMarker.getPosition());
}
}
});
}
}