org.onebusaway.webapp.gwt.oba_application.view.SearchWidget.java Source code

Java tutorial

Introduction

Here is the source code for org.onebusaway.webapp.gwt.oba_application.view.SearchWidget.java

Source

/**
 * 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.oba_application.view;

import java.util.Date;

import org.onebusaway.transit_data.model.tripplanning.ConstraintsBean;
import org.onebusaway.transit_data.model.tripplanning.TransitShedConstraintsBean;
import org.onebusaway.webapp.gwt.common.control.FlexibleDateParser;
import org.onebusaway.webapp.gwt.common.model.ModelListener;
import org.onebusaway.webapp.gwt.common.resources.CommonResources;
import org.onebusaway.webapp.gwt.common.widgets.DivPanel;
import org.onebusaway.webapp.gwt.common.widgets.DivWidget;
import org.onebusaway.webapp.gwt.common.widgets.SpanWidget;
import org.onebusaway.webapp.gwt.oba_application.control.ConstraintsParameterMapping;
import org.onebusaway.webapp.gwt.oba_application.control.OneBusAwayStandardControl;
import org.onebusaway.webapp.gwt.oba_application.model.QueryModel;
import org.onebusaway.webapp.gwt.oba_application.resources.OneBusAwayCssResource;
import org.onebusaway.webapp.gwt.oba_application.resources.OneBusAwayStandardResources;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.event.MapClickHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ResizableDockLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;

public class SearchWidget extends FlowPanel {

    private static OneBusAwayCssResource _css = OneBusAwayStandardResources.INSTANCE.getCss();

    private static final String USING_LOCATION_TEXTBOX_STYLE = _css.SearchWidgetTextBoxUsingLocation();

    private static final int DEFAULT_SEARCH_WINDOW = 60;

    private static final int DEFAULT_TRIP_DURATION = 20;

    private static final int DEFAULT_WALKING_DISTANCE = 5280 / 2;

    private static final int DEFAULT_TRANSFERS = 1;

    private static DateTimeFormat _dateFormat = DateTimeFormat.getShortDateFormat();

    private static DateTimeFormat _timeFormat = DateTimeFormat.getShortTimeFormat();

    private QueryModelListener _modelListener = new QueryModelListener();

    private OneBusAwayStandardControl _control;

    private long _time = System.currentTimeMillis();

    private TransitShedConstraintsBean _constraints = new TransitShedConstraintsBean();

    /*****************************************************************************
     * 
     ****************************************************************************/

    private TextBox _queryTextBox;

    private TextBox _addressTextBox;

    private DivPanel _optionsPanel;

    private TextBox _dateTextBox;

    private TextBox _timeTextBox;

    private ListBox _maxTripLengthBox;

    private ListBox _maxTransfersListBox;

    private ListBox _maxWalkDistance;

    /****
     * Location Selection
     ****/

    private MapWidget _map;

    private boolean _usingLocation = false;

    private LatLng _location = null;

    private Marker _locationMarker = null;

    /****
     * Options Panel
     ****/

    private boolean _optionsExpanded = false;

    private Anchor _optionsButton;

    private ResizableDockLayoutPanel _dockLayoutPanelParent;

    public SearchWidget() {
        setDefaultConstraints();
        initializeWidget();
        refreshWidgets();
    }

    public void setControl(OneBusAwayStandardControl control) {
        _control = control;
    }

    public void setMapWidget(MapWidget map) {
        _map = map;
    }

    public ModelListener<QueryModel> getQueryModelHandler() {
        return _modelListener;
    }

    public void setDockLayoutPanelParent(ResizableDockLayoutPanel dockLayoutPanel) {
        _dockLayoutPanelParent = dockLayoutPanel;
    }

    private void setDefaultConstraints() {

        _time = System.currentTimeMillis();

        _constraints.setMaxInitialWaitTime(DEFAULT_SEARCH_WINDOW * 60);

        ConstraintsBean c = _constraints.getConstraints();
        c.setMaxTransfers(DEFAULT_TRANSFERS);
        c.setMaxTripDuration(DEFAULT_TRIP_DURATION * 60);
        c.setMaxWalkingDistance(DEFAULT_WALKING_DISTANCE);
    }

    private void initializeWidget() {

        addStyleName(_css.SearchWidget());

        FormPanel form = new FormPanel();
        form.setAction("index.html");

        add(form);

        form.addSubmitHandler(new SubmitHandler() {
            public void onSubmit(SubmitEvent event) {
                event.cancel();
            }
        });

        FlowPanel panel = new FlowPanel();
        form.add(panel);

        DivPanel searchPanel = new DivPanel();
        searchPanel.addStyleName(_css.SearchWidgetSearchPanel());
        panel.add(searchPanel);

        DivPanel searchForPanel = new DivPanel();
        searchForPanel.addStyleName(_css.SearchWidgetSearchForPanel());
        searchPanel.add(searchForPanel);

        DivWidget queryLabel = new DivWidget("Search for:");
        queryLabel.addStyleName(_css.SearchWidgetLabel());
        searchForPanel.add(queryLabel);

        DivPanel queryTextBoxPanel = new DivPanel();
        queryTextBoxPanel.addStyleName(_css.SearchWidgetTextBoxPanel());
        searchForPanel.add(queryTextBoxPanel);

        _queryTextBox = new TextBox();
        _queryTextBox.addStyleName(_css.SearchWidgetTextBox());
        _queryTextBox.setName(ConstraintsParameterMapping.PARAM_QUERY);
        _queryTextBox.addKeyPressHandler(new QueryTextBoxHandler());
        queryTextBoxPanel.add(_queryTextBox);

        DivPanel searchForExamplePanel = new DivPanel();
        searchForExamplePanel.addStyleName(_css.SearchWidgetExamplePanel());
        searchForPanel.add(searchForExamplePanel);

        DivWidget searchForExampleLabel = new DivWidget("(ex. \"restaurants\", \"parks\", \"grocery stores\")");
        searchForExampleLabel.addStyleName(_css.SearchWidgetExampleLabel());
        searchForExamplePanel.add(searchForExampleLabel);

        DivPanel addressPanel = new DivPanel();
        searchPanel.add(addressPanel);

        DivPanel addressPanel1 = new DivPanel();
        addressPanel.add(addressPanel1);

        DivWidget addressLabel = new DivWidget("Start Address:");
        addressLabel.addStyleName(_css.SearchWidgetLabel());
        addressPanel1.add(addressLabel);

        DivPanel addressTextBoxPanel = new DivPanel();
        addressTextBoxPanel.addStyleName(_css.SearchWidgetTextBoxPanel());
        addressPanel1.add(addressTextBoxPanel);

        _addressTextBox = new TextBox();
        _addressTextBox.addStyleName(_css.SearchWidgetTextBox());
        _addressTextBox.setName(ConstraintsParameterMapping.PARAM_LOCATION);
        addressTextBoxPanel.add(_addressTextBox);

        DivPanel addressPanel2 = new DivPanel();
        addressPanel2.addStyleName(_css.SearchWidgetExamplePanel());
        addressPanel.add(addressPanel2);

        SpanWidget addressExampleLabel1 = new SpanWidget("(ex. \"3rd and pike\" or ");
        addressExampleLabel1.addStyleName(_css.SearchWidgetExampleLabel());
        addressPanel2.add(addressExampleLabel1);

        Anchor addressExampleLabel2 = new Anchor("use the map");
        addressExampleLabel2.addStyleName(_css.SearchWidgetExampleLabel());
        addressExampleLabel2.addClickHandler(new UseTheMapHandler());
        addressPanel2.add(addressExampleLabel2);

        SpanWidget addressExampleLabel3 = new SpanWidget(")");
        addressExampleLabel3.addStyleName(_css.SearchWidgetExampleLabel());
        addressPanel2.add(addressExampleLabel3);

        DivPanel buttonPanel = new DivPanel();
        buttonPanel.addStyleName(_css.SearchWidgetButtonPanel());
        searchPanel.add(buttonPanel);

        Button button = new Button("Go");
        buttonPanel.add(button);
        button.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent widget) {
                handleQuery();
            }
        });

        AddressTextBoxHandler handler = new AddressTextBoxHandler();
        _addressTextBox.addKeyPressHandler(handler);
        _addressTextBox.addFocusHandler(handler);
        _addressTextBox.addBlurHandler(handler);

        _optionsButton = new Anchor("Show More Options");
        _optionsButton.addStyleName(_css.SearchWidgetShowOptionsButton());
        _optionsButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent arg0) {
                toggleExpansion();
                // TODO : Refresh layout
            }
        });
        buttonPanel.add(_optionsButton);

        DivPanel clearPanel = new DivPanel();
        clearPanel.addStyleName(_css.ClearPanel());
        panel.add(clearPanel);
        Image hiddenPixel = new Image(CommonResources.INSTANCE.getHiddenPixel().getUrl());
        clearPanel.add(hiddenPixel);

        _optionsPanel = new DivPanel();
        _optionsPanel.addStyleName(_css.SearchWidgetOptionsPanel());
        _optionsPanel.setVisible(false);
        panel.add(_optionsPanel);

        Grid optionsGrid = new Grid(2, 4);
        optionsGrid.addStyleName(_css.SearchWidgetOptionsGrid());
        for (int i = 0; i < 4; i++) {
            optionsGrid.getCellFormatter().addStyleName(0, i, "SearchWidget-OptionsGrid-Column" + i);
            optionsGrid.getCellFormatter().addStyleName(1, i, "SearchWidget-OptionsGrid-Column" + i);
        }
        _optionsPanel.add(optionsGrid);

        SpanWidget timeLabel = new SpanWidget("Start Time:");
        optionsGrid.setWidget(0, 0, timeLabel);

        DivPanel dateAndTimePanel = new DivPanel();
        optionsGrid.setWidget(0, 1, dateAndTimePanel);
        _dateTextBox = new TextBox();
        _dateTextBox.addStyleName(_css.SearchWidgetStartDateTextBox());
        dateAndTimePanel.add(_dateTextBox);
        _timeTextBox = new TextBox();
        _timeTextBox.addStyleName(_css.SearchWidgetStartTimeTextBox());
        dateAndTimePanel.add(_timeTextBox);

        SpanWidget maxLengthLabel = new SpanWidget("Trip Time:");
        optionsGrid.setWidget(1, 0, maxLengthLabel);

        _maxTripLengthBox = new ListBox();
        _maxTripLengthBox.addItem("10 mins", "10");
        _maxTripLengthBox.addItem("15 mins", "15");
        _maxTripLengthBox.addItem("20 mins", "20");
        _maxTripLengthBox.addItem("30 mins", "30");
        _maxTripLengthBox.addItem("45 mins", "45");
        _maxTripLengthBox.addItem("1 hour", "60");
        _maxTripLengthBox.addStyleName(_css.SearchWidgetTripLengthList());
        optionsGrid.setWidget(1, 1, _maxTripLengthBox);

        SpanWidget maxTransfersLabel = new SpanWidget("Transfers:");
        optionsGrid.setWidget(0, 2, maxTransfersLabel);

        _maxTransfersListBox = new ListBox();
        _maxTransfersListBox.addItem("Don't Care", "-1");
        _maxTransfersListBox.addItem("0", "0");
        _maxTransfersListBox.addItem("1", "1");
        _maxTransfersListBox.addItem("2", "2");
        optionsGrid.setWidget(0, 3, _maxTransfersListBox);

        SpanWidget maxWalkLabel = new SpanWidget("Walk at most:");
        optionsGrid.setWidget(1, 2, maxWalkLabel);

        _maxWalkDistance = new ListBox();
        _maxWalkDistance.addItem("1/4 mile", "1320");
        _maxWalkDistance.addItem("1/2 mile", "2640");
        _maxWalkDistance.addItem("3/4 mile", "3960");
        _maxWalkDistance.addItem("1 mile", "5280");
        optionsGrid.setWidget(1, 3, _maxWalkDistance);

        DivPanel optionsPanelRowB = new DivPanel();
        _optionsPanel.add(optionsPanelRowB);
    }

    private void refreshWidgets() {

        Date time = new Date(_time);
        _dateTextBox.setText(_dateFormat.format(time));
        _timeTextBox.setText(_timeFormat.format(time));

        ConstraintsBean c = _constraints.getConstraints();
        setClosestIndex(_maxTransfersListBox, c.getMaxTransfers());
        setClosestIndex(_maxTripLengthBox, c.getMaxTripDuration() / 60);
        setClosestIndex(_maxWalkDistance, (int) c.getMaxWalkingDistance());
    }

    private void setClosestIndex(ListBox listBox, int value) {
        int minIndex = -1;
        double minDiff = 0;
        for (int i = 0; i < listBox.getItemCount(); i++) {
            Integer itemValue = Integer.parseInt(listBox.getValue(i));
            double diff = Math.abs(value - itemValue);
            if (minIndex == -1 || diff < minDiff) {
                minIndex = i;
                minDiff = diff;
            }
        }

        if (minIndex != -1)
            listBox.setSelectedIndex(minIndex);
    }

    private void refreshConstraints() {

        Date date = new Date();

        String dateValue = _dateTextBox.getText();
        String timeValue = _timeTextBox.getText();
        if (dateValue.length() > 0 && timeValue.length() > 0) {
            try {
                Date parsedDate = _dateFormat.parse(dateValue);
                FlexibleDateParser parser = new FlexibleDateParser();
                int minutes = parser.getMintuesSinceMidnight(timeValue);
                date = new Date(parsedDate.getTime() + minutes * 60 * 1000);
            } catch (FlexibleDateParser.DateParseException ex) {
                System.err.println("bad time=" + dateValue + " " + timeValue);
            }
        }

        System.out.println("date=" + date);

        _time = date.getTime();

        ConstraintsBean c = _constraints.getConstraints();

        int maxTransfersIndex = _maxTransfersListBox.getSelectedIndex();
        if (maxTransfersIndex != -1)
            c.setMaxTransfers(Integer.parseInt(_maxTransfersListBox.getValue(maxTransfersIndex)));

        int maxTripDurationIndex = _maxTripLengthBox.getSelectedIndex();
        if (maxTripDurationIndex != -1)
            c.setMaxTripDuration(Integer.parseInt(_maxTripLengthBox.getValue(maxTripDurationIndex)) * 60);

        int maxWalkDistanceindex = _maxWalkDistance.getSelectedIndex();
        if (maxWalkDistanceindex != -1)
            c.setMaxWalkingDistance(Integer.parseInt(_maxWalkDistance.getValue(maxWalkDistanceindex)));
    }

    private void toggleExpansion() {
        _optionsExpanded = !_optionsExpanded;
        _optionsPanel.setVisible(_optionsExpanded);
        _optionsButton.setText(_optionsExpanded ? "Hide Options" : "Show More Options");
        double size = _optionsExpanded ? 8 : 4;
        _dockLayoutPanelParent.setWidgetSize(this, size);
        _dockLayoutPanelParent.forceLayout();
    }

    private void handleQuery() {

        String queryText = _queryTextBox.getText();
        String addressText = _addressTextBox.getText();

        if (queryText == null || queryText.length() == 0)
            return;

        if (!_usingLocation && (addressText == null || addressText.length() == 0))
            return;

        refreshConstraints();

        if (_usingLocation)
            addressText = "";

        _control.query(queryText, addressText, _location, _time, _constraints);
    }

    private void setLocation(LatLng location) {
        _addressTextBox.setText("See the marker on the map...");
        _addressTextBox.addStyleName(USING_LOCATION_TEXTBOX_STYLE);

        _location = location;

        if (_locationMarker != null) {
            _map.removeOverlay(_locationMarker);
            _locationMarker = null;
        }

        _locationMarker = new Marker(_location);
        _map.addOverlay(_locationMarker);

        _map.setCenter(_location);
        _usingLocation = true;
    }

    /*****************************************************************************
     * Inner Classes
     ****************************************************************************/

    private class QueryTextBoxHandler implements KeyPressHandler {
        public void onKeyPress(KeyPressEvent event) {
            if (event.getCharCode() == '\n' && !event.isAnyModifierKeyDown()) {
                handleQuery();
            }
        }

    }

    private class AddressTextBoxHandler implements KeyPressHandler, FocusHandler, BlurHandler {

        public void onKeyPress(KeyPressEvent event) {
            if (event.getCharCode() == '\n' && !event.isAnyModifierKeyDown()) {
                handleQuery();
            } else {
                _usingLocation = false;
                _location = null;
                if (_locationMarker != null)
                    _map.removeOverlay(_locationMarker);
            }
        }

        public void onFocus(FocusEvent event) {
            if (_usingLocation) {
                _addressTextBox.removeStyleName(USING_LOCATION_TEXTBOX_STYLE);
                _addressTextBox.setText("");
            }
        }

        public void onBlur(BlurEvent arg0) {
            if (_usingLocation) {
                _addressTextBox.setText("See the marker on the map...");
                _addressTextBox.addStyleName(USING_LOCATION_TEXTBOX_STYLE);
            }
        }
    }

    private class QueryModelListener implements ModelListener<QueryModel> {

        public void handleUpdate(QueryModel model) {

            _queryTextBox.setText(model.getQuery());

            _constraints = new TransitShedConstraintsBean(model.getConstraints());

            String locationValue = model.getLocationQuery();
            if ((locationValue == null || locationValue.length() == 0) && model.getLocation() != null) {
                setLocation(model.getLocation());
            } else {
                _addressTextBox.setText(locationValue);
            }

            refreshWidgets();
        }
    }

    private class UseTheMapHandler implements ClickHandler, MapClickHandler {

        public void onClick(ClickEvent widget) {

            _addressTextBox.setText("Click on the map to pick a location...");
            _addressTextBox.addStyleName(USING_LOCATION_TEXTBOX_STYLE);

            _map.addMapClickHandler(this);
        }

        public void onClick(MapClickEvent event) {
            _map.removeMapClickHandler(this);
            setLocation(event.getLatLng());
        }
    }

}