/*
* Copyright 2015 JBoss, by Red Hat, 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.uberfire.ext.widgets.common.client.common;
import java.util.Date;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.editor.client.IsEditor;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.HasName;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasVisibility;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
import org.gwtbootstrap3.client.shared.event.HideEvent;
import org.gwtbootstrap3.client.shared.event.HideHandler;
import org.gwtbootstrap3.client.shared.event.ShowHandler;
import org.gwtbootstrap3.client.ui.base.HasId;
import org.gwtbootstrap3.client.ui.base.HasPlaceholder;
import org.gwtbootstrap3.client.ui.base.HasResponsiveness;
import org.gwtbootstrap3.client.ui.constants.DeviceSize;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerDayOfWeek;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerLanguage;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerMinView;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.DatePickerPosition;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasAutoClose;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasDateTimePickerHandlers;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasDaysOfWeekDisabled;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasEndDate;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasForceParse;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasHighlightToday;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasKeyboardNavigation;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasLanguage;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasMinView;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasPosition;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasShowTodayButton;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasStartDate;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasStartView;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasViewSelect;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.constants.HasWeekStart;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeDateHandler;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeMonthHandler;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ChangeYearHandler;
import org.gwtbootstrap3.extras.datepicker.client.ui.base.events.ClearDateHandler;
/**
* A DatePicker wrapping BS3's DatePicker component adding additional functionality
* required by KIE Workbench.; such as prevention of empty values and support for
* setting the date format with GWT's DateTimeFormat patterns.
*/
public class DatePicker extends Composite
implements HasEnabled,
Focusable,
HasId,
HasResponsiveness,
HasVisibility,
HasPlaceholder,
HasAutoClose,
HasDaysOfWeekDisabled,
HasEndDate,
HasForceParse,
HasHighlightToday,
HasKeyboardNavigation,
HasMinView,
HasShowTodayButton,
HasStartDate,
HasStartView,
HasViewSelect,
HasWeekStart,
HasDateTimePickerHandlers,
HasLanguage,
HasName,
HasValue<Date>,
HasPosition,
IsEditor<LeafValueEditor<Date>> {
private final boolean allowEmptyValues;
private final org.gwtbootstrap3.extras.datepicker.client.ui.DatePicker datePicker;
//Default GWT date format
private String gwtDateFormat = "dd-MMM-yyyy";
private DateTimeFormat gwtDateTimeFormat = DateTimeFormat.getFormat(gwtDateFormat);
private String localeName;
public DatePicker() {
this(true);
}
/**
* Basic constuctor of uberfire datePicker without setting the datepicker container and without setting the hide
* handler to manage the interaction with org.gwtbootstrap3.extras.datepicker.client.ui.DatePicker popup
* @param datePicker
*/
public DatePicker(org.gwtbootstrap3.extras.datepicker.client.ui.DatePicker datePicker) {
this.datePicker = datePicker;
this.allowEmptyValues = true;
}
public DatePicker(final boolean allowEmptyValues) {
datePicker = GWT.create(org.gwtbootstrap3.extras.datepicker.client.ui.DatePicker.class);
this.allowEmptyValues = allowEmptyValues;
datePicker.setContainer(RootPanel.get());
datePicker.setAutoClose(true);
setLocaleName();
setFormat(gwtDateFormat);
//When the popup Date Picker component is hidden assert empty values
datePicker.addHideHandler(new HideHandler() {
@Override
public void onHide(HideEvent hideEvent) {
final Date value = getDataPickerDate();
if (!allowEmptyValues && value == null) {
doSetValue(new Date(),
true);
} else {
doSetValue(value,
true);
}
}
});
initWidget(datePicker);
}
private Date getDataPickerDate() {
DateTimeFormat dtf = DateTimeFormat.getFormat("dd/M/yyyy");
String dateStr = parseDate(datePicker.getTextBox().getElement(),
DatePickerFormatUtilities.convertToBS3DateFormat("dd/M/yyyy"));
Date dateRes = dtf.parse(dateStr);
return dateRes;
}
public void setContainer(final Widget container) {
datePicker.setContainer(container);
}
@Override
public void setAutoClose(final boolean autoClose) {
datePicker.setAutoClose(autoClose);
}
@Override
public void onShow(final Event e) {
datePicker.onShow(e);
}
@Override
public HandlerRegistration addShowHandler(final ShowHandler showHandler) {
return datePicker.addShowHandler(showHandler);
}
@Override
public void onHide(final Event e) {
datePicker.onHide(e);
}
@Override
public HandlerRegistration addHideHandler(final HideHandler hideHandler) {
return datePicker.addHideHandler(hideHandler);
}
@Override
public void onChangeDate(final Event e) {
datePicker.onChangeDate(e);
}
@Override
public HandlerRegistration addChangeDateHandler(final ChangeDateHandler changeDateHandler) {
return datePicker.addChangeDateHandler(changeDateHandler);
}
@Override
public void onChangeYear(final Event e) {
datePicker.onChangeYear(e);
}
@Override
public HandlerRegistration addChangeYearHandler(final ChangeYearHandler changeYearHandler) {
return datePicker.addChangeYearHandler(changeYearHandler);
}
@Override
public void onChangeMonth(final Event e) {
datePicker.onChangeMonth(e);
}
@Override
public HandlerRegistration addChangeMonthHandler(final ChangeMonthHandler changeMonthHandler) {
return datePicker.addChangeMonthHandler(changeMonthHandler);
}
@Override
public void onClearDate(final Event e) {
datePicker.onClearDate(e);
}
@Override
public HandlerRegistration addClearDateHandler(final ClearDateHandler outOfRangeHandler) {
return datePicker.addClearDateHandler(outOfRangeHandler);
}
@Override
public void setDaysOfWeekDisabled(final DatePickerDayOfWeek... daysOfWeekDisabled) {
datePicker.setDaysOfWeekDisabled(daysOfWeekDisabled);
}
@Override
public boolean isEnabled() {
return datePicker.isEnabled();
}
@Override
public void setEnabled(final boolean enabled) {
datePicker.setEnabled(enabled);
}
@Override
public void setEndDate(final Date endDate) {
datePicker.setEndDate(endDate);
}
@Override
public void setEndDate(final String endDate) {
datePicker.setEndDate(endDate);
}
@Override
public void clearEndDate() {
datePicker.clearEndDate();
}
@Override
public void setForceParse(final boolean forceParse) {
datePicker.setForceParse(forceParse);
}
/**
* Set the format of the Date shown in the TextBox component.
* This is converted to BS3's Date Format that the underlying jQuery-based BS3 DatePicker
* uses to convert values in the TextBox to selections in the popup date picker element.
* @param gwtDateFormat
*/
public void setFormat(final String gwtDateFormat) {
this.gwtDateFormat = gwtDateFormat;
this.gwtDateTimeFormat = DateTimeFormat.getFormat(this.gwtDateFormat);
if (getLocaleName().equals("")) {
datePicker.setLanguage(DatePickerLanguage.EN);
} else {
datePicker.setLanguage(DatePickerLanguage.valueOf(getLocaleName().toUpperCase()));
}
datePicker.setFormat(DatePickerFormatUtilities.convertToBS3DateFormat(gwtDateFormat));
}
public String getLocaleName() {
if (localeName != null && !localeName.isEmpty() && !localeName.equalsIgnoreCase("default")) {
return localeName;
}
return "";
}
public void setLocaleName(String localeName) {
if (localeName != null) {
this.localeName = localeName;
} else {
this.localeName = "";
}
}
public void setLocaleName() {
localeName = LocaleInfo.getCurrentLocale().getLocaleName();
}
@Override
public void setHighlightToday(final boolean highlightToday) {
datePicker.setHighlightToday(highlightToday);
}
@Override
public String getId() {
return datePicker.getId();
}
@Override
public void setId(final String id) {
datePicker.setId(id);
}
@Override
public void setHasKeyboardNavigation(final boolean hasKeyboardNavigation) {
datePicker.setHasKeyboardNavigation(hasKeyboardNavigation);
}
@Override
public DatePickerLanguage getLanguage() {
return datePicker.getLanguage();
}
@Override
public void setLanguage(final DatePickerLanguage language) {
datePicker.setLanguage(language);
}
@Override
public void setMinView(final DatePickerMinView datePickerMinView) {
datePicker.setMinView(datePickerMinView);
}
@Override
public String getName() {
return datePicker.getName();
}
@Override
public void setName(final String name) {
datePicker.setName(name);
}
@Override
public String getPlaceholder() {
return datePicker.getPlaceholder();
}
@Override
public void setPlaceholder(final String placeholder) {
datePicker.setPlaceholder(placeholder);
}
@Override
public DatePickerPosition getPosition() {
return datePicker.getPosition();
}
@Override
public void setPosition(final DatePickerPosition position) {
datePicker.setPosition(position);
}
@Override
public void setVisibleOn(final DeviceSize deviceSize) {
datePicker.setVisibleOn(deviceSize);
}
@Override
public void setHiddenOn(final DeviceSize deviceSize) {
datePicker.setHiddenOn(deviceSize);
}
@Override
public void setShowTodayButton(final boolean showTodayButton) {
datePicker.setShowTodayButton(showTodayButton);
}
@Override
public void setStartDate(final Date startDate) {
datePicker.setStartDate(startDate);
}
@Override
public void setStartDate(final String startDate) {
datePicker.setStartDate(startDate);
}
@Override
public void clearStartDate() {
datePicker.clearStartDate();
}
@Override
public void setStartView(final DatePickerMinView datePickerMinView) {
datePicker.setStartView(datePickerMinView);
}
@Override
//We don't delegate this to the wrapped DatePicker as that has some issues with the mismatch between GWT's DateFormat and BS3's DateFormat
public Date getValue() {
try {
return gwtDateTimeFormat != null && datePicker.getTextBox().getValue() != null ? gwtDateTimeFormat.parse(datePicker.getTextBox().getValue()) : null;
} catch (final Exception e) {
return null;
}
}
@Override
//We don't delegate this to the wrapped DatePicker as that has some issues with the mismatch between GWT's DateFormat and BS3's DateFormat
public void setValue(final Date value) {
if (!allowEmptyValues && value == null) {
doSetValue(new Date(),
true);
} else {
doSetValue(value,
false);
}
}
@Override
//We don't delegate this to the wrapped DatePicker as that has some issues with the mismatch between GWT's DateFormat and BS3's DateFormat
public void setValue(final Date value,
final boolean fireEvents) {
if (!allowEmptyValues && value == null) {
doSetValue(new Date(),
true);
} else {
doSetValue(value,
fireEvents);
}
}
//This is essentially an override of the wrapped DatePicker's setValue() method however
//we need to override it to use the "improved" GWT DateFormat<->BS3's DateFormat handling.
private void doSetValue(final Date value,
final boolean fireEvents) {
datePicker.getTextBox().setValue(value != null ? gwtDateTimeFormat.format(value) : null);
update(datePicker.getTextBox().getElement());
if (fireEvents) {
ValueChangeEvent.fire(datePicker,
value);
}
}
//Unfortunately the wrapped DatePicker hides the "update" method so we have to repeat it here
private native void update(Element e) /*-{
$wnd.jQuery(e).datepicker('update');
}-*/;
private final native String parseDate(Element e,
String format) /*-{
var dateStr = $wnd.jQuery(e).datepicker('getFormattedDate', format);
return dateStr
}-*/;
@Override
public com.google.gwt.event.shared.HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Date> handler) {
return datePicker.addValueChangeHandler(handler);
}
@Override
public void setViewSelect(final DatePickerMinView datePickerMinView) {
datePicker.setViewSelect(datePickerMinView);
}
@Override
public void setWeekStart(final DatePickerDayOfWeek weekStart) {
datePicker.setWeekStart(weekStart);
}
@Override
public LeafValueEditor<Date> asEditor() {
return datePicker;
}
@Override
public int getTabIndex() {
return datePicker.getTextBox().getTabIndex();
}
@Override
public void setTabIndex(final int index) {
datePicker.getTextBox().setTabIndex(index);
}
@Override
public void setAccessKey(final char key) {
datePicker.getTextBox().setAccessKey(key);
}
@Override
public void setFocus(final boolean focused) {
datePicker.getTextBox().setFocus(focused);
}
public HandlerRegistration addBlurHandler(final BlurHandler handler) {
return datePicker.getTextBox().addBlurHandler(handler);
}
}