org.cruxframework.crux.widgets.client.datebox.GWTOverriddenDateBox.java Source code

Java tutorial

Introduction

Here is the source code for org.cruxframework.crux.widgets.client.datebox.GWTOverriddenDateBox.java

Source

/*
 * Copyright 2008 Google Inc.
 * 
 * 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.cruxframework.crux.widgets.client.datebox;

import java.util.Date;

import org.cruxframework.crux.widgets.client.datebox.DateBox.CruxFormat;
import org.cruxframework.crux.widgets.client.datepicker.DatePicker;
import org.cruxframework.crux.widgets.client.datepicker.GWTOverriddenDateChangeEvent;
import org.cruxframework.crux.widgets.client.maskedtextbox.MaskedTextBox;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.editor.client.IsEditor;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.editor.client.adapters.TakesValueEditor;
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.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.PopupPanel;

/**
 * CruxDateBox
 * This is a GWT Class and had to be fully overridden because method visibility that
 * didn't allowed me to override the method itself.   
 * @author Samuel Almeida Cardoso (samuel@cruxframework.org)
 */
class GWTOverriddenDateBox extends Composite
        implements HasEnabled, HasValue<Date>, IsEditor<LeafValueEditor<Date>> {

    private IFormatToFormatterConverter formatter = null;

    /**
     * Default {@link GWTOverriddenDateBox.Format} class. The date is first parsed using the
     * {@link DateTimeFormat} supplied by the user, or
     * {@link DateTimeFormat#getMediumDateFormat()} by default.
     * <p>
     * If that fails, we then try to parse again using the default browser date
     * parsing.
     * </p>
     * If that fails, the <code>dateBoxFormatError</code> css style is applied to
     * the {@link GWTOverriddenDateBox}. The style will be removed when either a successful
     * {@link #parse(GWTOverriddenDateBox,String, boolean)} is called or
     * {@link #format(GWTOverriddenDateBox,Date)} is called.
     * <p>
     * Use a different {@link GWTOverriddenDateBox.Format} instance to change that behavior.
     * </p>
     */
    public static class DefaultFormat implements CruxFormat {
        private final DateTimeFormat dateTimeFormat;

        /**
         * Creates a new default format instance.
         */
        @SuppressWarnings("deprecation")
        public DefaultFormat() {
            dateTimeFormat = DateTimeFormat.getMediumDateTimeFormat();
        }

        /**
         * Creates a new default format instance.
         *
         * @param dateTimeFormat the {@link DateTimeFormat} to use with this
         *          {@link Format}.
         */
        public DefaultFormat(DateTimeFormat dateTimeFormat) {
            this.dateTimeFormat = dateTimeFormat;
        }

        public String format(GWTOverriddenDateBox box, Date date) {
            if (date == null) {
                return "";
            } else {
                return dateTimeFormat.format(date);
            }
        }

        /**
         * Gets the date time format.
         *
         * @return the date time format
         */
        public DateTimeFormat getDateTimeFormat() {
            return dateTimeFormat;
        }

        public Date parse(GWTOverriddenDateBox dateBox, String dateText, boolean reportError) {
            Date date = null;
            try {
                if (dateText.length() > 0) {
                    date = dateTimeFormat.parseStrict(dateText);
                }
            } catch (IllegalArgumentException exception) {
                return null;
            }
            return date;
        }

        public void reset(GWTOverriddenDateBox dateBox, boolean abandon) {
            dateBox.removeStyleName(DATE_BOX_FORMAT_ERROR);
        }

        @Override
        public String getPattern() {
            return dateTimeFormat.getPattern();
        }
    }

    /**
       * Implemented by a delegate to handle the parsing and formating of date
       * values. The default {@link Format} uses a new {@link DefaultFormat}
       * instance.
       */
    public interface Format {

        /**
         * Formats the provided date. Note, a null date is a possible input.
         *
         * @param dateBox the date box you are formatting
         * @param date the date to format
         * @return the formatted date as a string
         */
        String format(GWTOverriddenDateBox dateBox, Date date);

        /**
         * Parses the provided string as a date.
         *
         * @param dateBox the date box
         * @param text the string representing a date
         * @param reportError should the formatter indicate a parse error to the
         *          user?
         * @return the date created, or null if there was a parse error
         */
        Date parse(GWTOverriddenDateBox dateBox, String text, boolean reportError);

        /**
         * If the format did any modifications to the date box's styling, reset them
         * now.
         *
         * @param abandon true when the current format is being replaced by another
         * @param dateBox the date box
         */
        void reset(GWTOverriddenDateBox dateBox, boolean abandon);
    }

    private class DateBoxHandler implements ValueChangeHandler<Date>, FocusHandler, BlurHandler, ClickHandler,
            KeyDownHandler, CloseHandler<PopupPanel> {

        public void onBlur(BlurEvent event) {
            if (isDatePickerShowing() == false) {
                updateDateFromTextBox();
            }
        }

        public void onClick(ClickEvent event) {
            showDatePicker();
        }

        public void onClose(CloseEvent<PopupPanel> event) {
            // If we are not closing because we have picked a new value, make sure the
            // current value is updated.
            if (allowDPShow) {
                updateDateFromTextBox();
            }
        }

        public void onFocus(FocusEvent event) {
            if (allowDPShow && isDatePickerShowing() == false) {
                showDatePicker();
            }
        }

        public void onKeyDown(KeyDownEvent event) {
            switch (event.getNativeKeyCode()) {
            case KeyCodes.KEY_ENTER:
            case KeyCodes.KEY_TAB:
                updateDateFromTextBox();
                // Deliberate fall through
            case KeyCodes.KEY_ESCAPE:
            case KeyCodes.KEY_UP:
                hideDatePicker();
                break;
            case KeyCodes.KEY_DOWN:
                showDatePicker();
                break;
            }
        }

        public void onValueChange(ValueChangeEvent<Date> event) {
            setValue(parseDate(false), event.getValue(), true, true);
            hideDatePicker();
            preventDatePickerPopup();
            box.setFocus(true);
        }
    }

    /**
     * Default style name added when the date box has a format error.
     */
    private static final String DATE_BOX_FORMAT_ERROR = "dateBoxFormatError";

    /**
     * Default style name.
     */
    public static final String DEFAULT_STYLENAME = "gwt-Date";
    private static final DefaultFormat DEFAULT_FORMAT = GWT.create(DefaultFormat.class);
    private final PopupPanel popup;
    private final MaskedTextBox box = new MaskedTextBox();
    private final DatePicker picker;
    private LeafValueEditor<Date> editor;
    private CruxFormat format;
    private boolean allowDPShow = true;
    private boolean fireNullValues = false;

    /**
     * Create a date box with a new {@link DatePicker}.
     */
    public GWTOverriddenDateBox() {
        this(new DatePicker(), null, DEFAULT_FORMAT);
    }

    /**
     * Create a new date box.
     *
     * @param date the default date.
     * @param picker the picker to drop down from the date box
     * @param format to use to parse and format dates
     */
    public GWTOverriddenDateBox(DatePicker picker, Date date, final CruxFormat format) {
        this.picker = picker;
        this.popup = new PopupPanel(true);
        assert format != null : "You may not construct a date box with a null format";
        this.format = format;

        popup.addAutoHidePartner(box.getElement());
        popup.setWidget(picker);
        popup.setStyleName("dateBoxPopup");

        initWidget(box);
        setStyleName(DEFAULT_STYLENAME);

        DateBoxHandler handler = new DateBoxHandler();
        picker.addValueChangeHandler(handler);
        box.addFocusHandler(handler);
        box.addBlurHandler(handler);
        box.addClickHandler(handler);
        box.addKeyDownHandler(handler);
        box.setClearIfNotValid(true);

        popup.addCloseHandler(handler);

        setValue(date);
    }

    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Date> handler) {
        return addHandler(handler, ValueChangeEvent.getType());
    }

    /**
     * Returns a {@link TakesValueEditor} backed by the DateBoxGWTOverridden.
     */
    public LeafValueEditor<Date> asEditor() {
        if (editor == null) {
            editor = TakesValueEditor.of(this);
        }
        return editor;
    }

    //   /**
    //    * Gets the current cursor position in the date box.
    //    *
    //    * @return the cursor position
    //    *
    //    */
    //   public int getCursorPos() {
    //      return box.getCursorPos();
    //   }

    /**
     * Gets the date picker.
     *
     * @return the date picker
     */
    public DatePicker getDatePicker() {
        return picker;
    }

    /**
     * Returns true iff the date box will fire {@code ValueChangeEvents} with a
     * date value of {@code null} for invalid or empty string values.
     */
    public boolean getFireNullValues() {
        return fireNullValues;
    }

    /**
     * Gets the format instance used to control formatting and parsing of this
     * {@link GWTOverriddenDateBox}.
     *
     * @return the format
     */
    public CruxFormat getFormat() {
        return format;
    }

    /**
     * Gets the date box's position in the tab index.
     *
     * @return the date box's tab index
     */
    public int getTabIndex() {
        return box.getTabIndex();
    }

    /**
     * Get text box.
     *
     * @return the text box used to enter the formatted date
     */
    public MaskedTextBox getTextBox() {
        return box;
    }

    /**
     * Get the date displayed, or null if the text box is empty, or cannot be
     * interpreted.
     *
     * @return the current date value
     */
    public Date getValue() {
        return parseDate(true);
    }

    /**
     * Hide the date picker.
     */
    public void hideDatePicker() {
        popup.hide();
    }

    /**
     * Returns true if date picker is currently showing, false if not.
     */
    public boolean isDatePickerShowing() {
        return popup != null && popup.isAttached() && popup.isShowing();
    }

    /**
     * Returns true if the date box is enabled, false if not.
     */
    public boolean isEnabled() {
        return box.isEnabled();
    }

    /**
     * Sets the date box's 'access key'. This key is used (in conjunction with a
     * browser-specific modifier key) to automatically focus the widget.
     *
     * @param key the date box's access key
     */
    public void setAccessKey(char key) {
        box.setAccessKey(key);
    }

    /**
     * Sets whether the date box is enabled.
     *
     * @param enabled is the box enabled
     */
    public void setEnabled(boolean enabled) {
        box.setEnabled(enabled);
    }

    /**
     * Sets whether or not the date box will fire {@code ValueChangeEvents} with a
     * date value of {@code null} for invalid or empty string values.
     */
    public void setFireNullValues(boolean fireNullValues) {
        this.fireNullValues = fireNullValues;
    }

    /**
     * Explicitly focus/unfocus this widget. Only one widget can have focus at a
     * time, and the widget that does will receive all keyboard events.
     *
     * @param focused whether this widget should take focus or release it
     */
    public void setFocus(boolean focused) {
        box.setFocus(focused);
    }

    /**
     * Sets the format used to control formatting and parsing of dates in this
     * {@link GWTOverriddenDateBox}. If this {@link GWTOverriddenDateBox} is not empty, the contents of date
     * box will be replaced with current contents in the new format.
     *
     * @param format the new date format
     */
    public void setFormat(final CruxFormat format) {
        assert format != null : "A Date box may not have a null format";
        if (this.format != format) {
            Date date = getValue();

            // This call lets the formatter do whatever other clean up is required to
            // switch formatters.
            //
            this.format.reset(this, true);

            // Now update the format and show the current date using the new format.
            this.format = format;
            setValue(date);
        }
        this.formatter = GWT.create(FormatToFormatterConverter.class);
        formatter.setFormat(format);
        box.setFormatter(formatter);
    }

    /**
     * Sets the date box's position in the tab index. If more than one widget has
     * the same tab index, each such widget will receive focus in an arbitrary
     * order. Setting the tab index to <code>-1</code> will cause this widget to
     * be removed from the tab order.
     *
     * @param index the date box's tab index
     */
    public void setTabIndex(int index) {
        box.setTabIndex(index);
    }

    /**
     * Set the date.
     */
    @Override
    public void setValue(Date date) {
        setValue(date, false);
    }

    public void setValue(Date date, boolean fireEvents) {
        setValue(picker.getValue(), date, fireEvents, true);
    }

    /**
     * Parses the current date box's value and shows that date.
     */
    public void showDatePicker() {
        Date currentMonth = null;
        if (getDatePicker().getMonthToOpen() == null) {
            currentMonth = parseDate(false);
            if (currentMonth == null) {
                currentMonth = new Date();
            }
        } else {
            currentMonth = getDatePicker().getMonthToOpen();
        }

        picker.setCurrentMonth(currentMonth);
        popup.showRelativeTo(this);
    }

    private Date parseDate(boolean reportError) {
        if (reportError) {
            getFormat().reset(this, false);
        }
        String text = box.getValue().trim();
        return getFormat().parse(this, text, reportError);
    }

    private void preventDatePickerPopup() {
        allowDPShow = false;
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
            public void execute() {
                allowDPShow = true;
            }
        });
    }

    private void setValue(Date oldDate, Date date, boolean fireEvents, boolean updateText) {
        if (date != null) {
            picker.setCurrentMonth(date);
        }
        picker.setValue(date, false);

        if (updateText) {
            format.reset(this, false);
            box.setUnformattedValue(date);
        }

        if (fireEvents) {
            GWTOverriddenDateChangeEvent.fireIfNotEqualDates(this, oldDate, date);
        }
    }

    private void updateDateFromTextBox() {
        Date parsedDate = parseDate(true);
        if (fireNullValues || (parsedDate != null)) {
            setValue(picker.getValue(), parsedDate, true, false);
        }

        if (parsedDate == null) {
            box.setUnformattedValue(null);
        }
    }

    public PopupPanel getPopup() {
        return popup;
    }

}