/** * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onebusaway.webapp.gwt.stop_and_route_selection; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.onebusaway.geospatial.model.CoordinateBounds; import org.onebusaway.geospatial.services.SphericalGeometryLibrary; import org.onebusaway.presentation.client.RoutePresenter; import org.onebusaway.transit_data.model.RouteBean; import org.onebusaway.transit_data.model.StopBean; import org.onebusaway.webapp.gwt.common.context.Context; import org.onebusaway.webapp.gwt.common.context.ContextImpl; import org.onebusaway.webapp.gwt.where_library.rpc.WebappServiceAsync; import org.onebusaway.webapp.gwt.where_library.view.StopFinderCssResource; import org.onebusaway.webapp.gwt.where_library.view.StopFinderInterface; import org.onebusaway.webapp.gwt.where_library.view.StopFinderPresenter; import org.onebusaway.webapp.gwt.where_library.view.StopFinderWidget; import org.onebusaway.webapp.gwt.where_library.view.StopInfoWindowWidget; import org.onebusaway.webapp.gwt.where_library.view.constraints.OperationContext; import org.onebusaway.webapp.gwt.where_library.view.constraints.OperationHandler; import org.onebusaway.webapp.gwt.where_library.view.stops.TransitMapManager; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.ModalLayoutPanel; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.Widget; public class AbstractStopAndRouteSelectionWidget extends Composite { private static WebappServiceAsync _service = WebappServiceAsync.SERVICE; private StopRemovedHandler _stopRemovedHandler = new StopRemovedHandler(); private RouteHandler _routeHandler = new RouteHandler(); @UiField public MyStyle style; @UiField public Anchor _addStopAnchor; @UiField public FlowPanel _stopsPanel; @UiField public FlowPanel _routesPanel; protected Map<String, StopBean> _stopsById = new HashMap<String, StopBean>(); protected Map<String, Boolean> _routeSelectionById = new HashMap<String, Boolean>(); private boolean _routesSelectedByDefault = true; private StopBean _stop; private ModalLayoutPanel _dialog; public void addStop(StopBean stop) { _stopsById.put(stop.getId(), stop); refresh(); } public void removeStop(StopBean stop) { _stopsById.remove(stop.getId()); refresh(); } @UiHandler("_addStopAnchor") public void handleAddStopClick(ClickEvent e) { e.preventDefault(); _stop = null; _dialog = new ModalLayoutPanel(); StopFinderWidgetExtension widget = new StopFinderWidgetExtension(); final StopFinderPresenter stopFinder = new StopFinderPresenter(); stopFinder.setDefaultOperationHandler(new DefaultOperationHandler()); stopFinder.setWidget(widget); widget.setStopFinder(stopFinder); widget.addStyleName(style.StopFinderDialog()); _dialog.add(widget); _dialog.setWidgetLeftRight(widget, 5, Unit.PCT, 5, Unit.PCT); _dialog.setWidgetTopBottom(widget, 10, Unit.PCT, 10, Unit.PCT); _dialog.addCloseHandler(new CloseHandler<ModalLayoutPanel>() { @Override public void onClose(CloseEvent<ModalLayoutPanel> arg0) { if (_stop != null) addStop(_stop); } }); _dialog.show(); Context context = new ContextImpl(); if (!_stopsById.isEmpty()) { CoordinateBounds b = new CoordinateBounds(); for (StopBean stop : _stopsById.values()) b.addPoint(stop.getLat(), stop.getLon()); b = SphericalGeometryLibrary.bounds(b, 100); context = stopFinder.getCoordinateBoundsAsContext(b); System.out.println("context=" + context); } final Context c = context; DeferredCommand.addCommand(new Command() { @Override public void execute() { stopFinder.onContextChanged(c); } }); } /**** * ****/ protected void initialize() { _addStopAnchor.setHref("#addStop"); } protected void setStopsAndRoutes(Collection<String> stopIds, Collection<String> routeIds) { if (routeIds.isEmpty()) { _routesSelectedByDefault = true; } else { _routesSelectedByDefault = false; for (String routeId : routeIds) _routeSelectionById.put(routeId, Boolean.TRUE); } StopHandler stopHandler = new StopHandler(); for (String stopId : stopIds) { _service.getStop(stopId, stopHandler); } } protected void refresh() { Map<String, RouteBean> routesById = new HashMap<String, RouteBean>(); for (StopBean stop : _stopsById.values()) { for (RouteBean route : stop.getRoutes()) routesById.put(route.getId(), route); } List<StopBean> stops = new ArrayList<StopBean>(_stopsById.values()); List<RouteBean> routes = new ArrayList<RouteBean>(routesById.values()); Collections.sort(routes, new RouteNameComparator()); _stopsPanel.clear(); for (StopBean stop : stops) _stopsPanel.add(new StopWidget(stop, _stopRemovedHandler)); _routesPanel.clear(); for (RouteBean route : routes) { Boolean selected = _routeSelectionById.get(route.getId()); if (selected == null) { selected = _routesSelectedByDefault; _routeSelectionById.put(route.getId(), selected); } _routesPanel.add(new RouteWidget(route, selected, _routeHandler)); } } public class StopFinderWidgetExtension extends StopFinderWidget { public StopFinderWidgetExtension() { super(); setTitleWidget(new StopSelectionTitleWidget(_dialog)); hideLinksPanel(); } @Override protected Widget getStopInfoWindowWidget(StopBean stop, StopFinderCssResource css) { return new StopInfoWindowWidgetExtension(_stopFinder, _transitMapManager, stop, css); } } private class StopInfoWindowWidgetExtension extends StopInfoWindowWidget { public StopInfoWindowWidgetExtension(StopFinderInterface stopFinder, TransitMapManager transitMapManager, StopBean stop, StopFinderCssResource css) { super(stopFinder, transitMapManager, stop, css); } @Override protected void handleLinksForStopInfoWindow(final StopBean bean) { Anchor anchor = new Anchor("Add this stop to the list"); anchor.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { _stop = bean; _dialog.hide(); } }); getStopLinksPanel().clear(); getStopLinksPanel().add(anchor); } } private class DefaultOperationHandler implements OperationHandler { @Override public void handleOperation(OperationContext context) { Panel panel = context.getPanel(); HTMLPanel html = new HTMLPanel( "<p>Search for stops like you normally would.</p><p>Click and select a stop to add it to your custom stop view.</p>"); panel.add(html); context.getTransitMapManager().showStopsInCurrentView(); } } public interface MyStyle extends CssResource { String StopFinderDialog(); } private class StopRemovedHandler implements StopWidget.RemoveClickedHandler { @Override public void handleRemoveClicked(StopWidget widget, StopBean stop) { removeStop(stop); } } private class RouteHandler implements RouteWidget.RouteSelectionHandler { @Override public void handleSelectionChanged(RouteWidget widget, RouteBean route, boolean selected) { _routeSelectionById.put(route.getId(), selected); } } private class StopHandler implements AsyncCallback<StopBean> { @Override public void onSuccess(StopBean arg) { addStop(arg); } @Override public void onFailure(Throwable arg0) { } } private static class RouteNameComparator implements Comparator<RouteBean> { @Override public int compare(RouteBean o1, RouteBean o2) { String n1 = RoutePresenter.getNameForRoute(o1); String n2 = RoutePresenter.getNameForRoute(o2); return n1.compareTo(n2); } } }