de.swm.commons.mobile.client.widgets.date.DatePopup Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swm-mobile Show documentation
Show all versions of swm-mobile Show documentation
GWT Bibliothek fuer Mobile Plattformen der SWM
/*
* Copyright 2011 SWM Services GmbH.
*
* 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 de.swm.commons.mobile.client.widgets.date;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import de.swm.commons.mobile.client.SWMMobile;
import de.swm.commons.mobile.client.widgets.*;
import java.util.Date;
/**
* Popup to select date and time.
*/
public class DatePopup extends PopupPanel {
/**
* Additional style: margin.
*/
private static final double MARGIN_YEAR = 12.0;
/**
* Additional style: margin.
*/
private static final double MARGIN_PIXEL_SIZE_4_0 = 4.0;
/**
* Number Formatter for two-digit number strings.
*/
private final NumberFormat numFormat = NumberFormat.getFormat("00");
/**
* Date selection handler.
*/
public interface DateSelectionHandler {
/**
* Sets the selected date.
*
* @param selectedDate the selected date
*/
void dateSelected(Date selectedDate);
/**
* Called, if date selection was canceled.
*/
void dateSelectionCancelled();
}
/**
* Defines the different fields in the popup.
*/
private enum DateField {
DAY, MONTH, YEAR, HOUR, MINUTE
}
/**
* The underlying selection handler.
*/
private DateSelectionHandler selectionHandler;
/**
* Label displaying the day.
*/
private TextBox dayLabel;
/**
* Label displaying the month.
*/
private TextBox monthLabel;
/**
* Label displaying the year.
*/
private TextBox yearLabel;
/**
* Label displaying the hour.
*/
private TextBox hourLabel;
/**
* Label displaying the minute.
*/
private TextBox minuteLabel;
/**
* Delegate for date calculations.
*/
private DateCalculation dateCalc;
private final VerticalPanel mainPanel;
private final DateStyle dateStyle;
private TextBox dateTextBox;
private final Label dateTimeSelectionCaption;
private DropDownList dropDown;
/**
* Default constructor.
*
* @param givenDate date to start with
* @param dateStyle der date style
* @param handler date selection handler
*/
public DatePopup(Date givenDate, final DateStyle dateStyle, DateSelectionHandler handler) {
setStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().datePopup());
setGlassStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateGlassPanel());
selectionHandler = handler;
if (givenDate == null) {
givenDate = new Date();
}
this.dateStyle = dateStyle;
dateCalc = new DateCalculation(givenDate);
mainPanel = new VerticalPanel();
dateTimeSelectionCaption = new Label(SWMMobile.getI18N().dateTimeSelectionCaption());
mainPanel.add(dateTimeSelectionCaption);
dateTimeSelectionCaption.setVisible(false);
if (SWMMobile.getOsDetection().isIOs()) {
renderIOS5DateBox(givenDate, dateStyle);
} else {
renderDateBox(dateStyle);
}
setWidget(mainPanel);
}
/**
* Adds another user-defined widget to the date popup, e.g. for additional options when choosing the date.
*
* @param widget additional widget
* @param position of the widget in the main vertical panel (0=first widget)
*/
public void addWidget(Widget widget, int position) {
mainPanel.insert(widget, position);
}
/**
* Adds a drop down list to choose times relative to the current time (e.g., "in 10 Minutes").
*
* @param choiceTitles titles of the available choices
* @param choiceRelativeMinutes for each choice, difference to the current time in minutes
* @param initialChoice initially selected choice - must be one of choiceRelativeMinutes, or null if no selection
* @param includeNowButton whether a "now" button should be included to choose the current time
* @param closeOnChoice whether the date popup should be immediately closed when a relative choice is made
*/
public void addRelativeTimeChooser(String[] choiceTitles, int[] choiceRelativeMinutes,
Integer initialChoice, final boolean includeNowButton, final boolean closeOnChoice) {
if (choiceTitles.length != choiceRelativeMinutes.length) {
throw new IllegalArgumentException("Must supply same number of choiceTitles and choiceRelativeMilliseconds!");
}
HorizontalPanel relativeTimeChooserPanel = new HorizontalPanel();
relativeTimeChooserPanel.addStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateRelativeTimeChooserPanel());
if (includeNowButton) {
Button nowButton = new Button(SWMMobile.getI18N().nowButton(), new ClickHandler() {
/**
* {@inheritDoc}
*/
@Override
public void onClick(ClickEvent event) {
Date currentDate = new Date();
if (closeOnChoice) {
hide();
selectionHandler.dateSelected(currentDate);
} else {
updateDate(currentDate);
}
}
});
relativeTimeChooserPanel.add(nowButton);
}
Label label = new Label(SWMMobile.getI18N().relativeTimeChooserLabel());
relativeTimeChooserPanel.add(label);
dropDown = new DropDownList();
dropDown.add(new DropDownItem(null, ""));
for (int i = 0; i < choiceTitles.length; i++) {
dropDown.add(new DropDownItem(new Integer(choiceRelativeMinutes[i]).toString(), choiceTitles[i]));
}
if (initialChoice != null) {
// TODO: possibly update date selector time for initial choice?
dropDown.setValue(initialChoice.toString());
}
dropDown.addValueChangeHandler(new ValueChangeHandler() {
@Override
public void onValueChange(ValueChangeEvent event) {
if ((event.getValue() == null) || event.getValue().equals("") || event.getValue().equals("null")) {
return;
}
int relativeMinutes = Integer.parseInt(event.getValue().toString());
Date newDate = new Date(new Date().getTime() + relativeMinutes * 60000);
if (closeOnChoice) {
hide();
selectionHandler.dateSelected(newDate);
} else {
updateDate(newDate);
}
}
});
relativeTimeChooserPanel.add(dropDown);
mainPanel.insert(relativeTimeChooserPanel, 0);
}
/**
* Clears the relative time displayed in the relative time chooser.
*/
private void clearRelativeTime() {
if (dropDown != null) {
dropDown.setValue(null);
}
}
/**
* Sets the visibility of the caption for the date/time selection (default: caption is not visible).
*
* @param visible visibility of caption for date/time selection
*/
public void setDateTimeSelectionCaptionVisible(boolean visible) {
dateTimeSelectionCaption.setVisible(visible);
}
/**
* Renders the date box for devices where native date input field is not avalilable.
*
* @param givenDate
* @param dateStyle
*/
private void renderIOS5DateBox(final Date givenDate, final DateStyle dateStyle) {
final InputElement dateInput = createNumberInputElement(dateStyle.getHtmlInputType());
dateInput.focus();
dateTextBox = TextBox.wrap(dateInput);
dateTextBox.setSize("95%", "40px");
dateTextBox.setValue(dateCalc.formatToRfc3339(givenDate, dateStyle, true));
// TODO: on value change, call clearRelativeTime() (special handling necessary)
HorizontalPanel dateInputPanel = new HorizontalPanel();
dateInputPanel.addStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateInputPanel());
dateInputPanel.add(dateTextBox);
mainPanel.add(dateInputPanel);
Widget commandPanel = createCommandPanel(new ClickHandler() {
/**
* {@inheritDoc}
*/
@Override
public void onClick(ClickEvent event) {
hide();
selectionHandler.dateSelected(dateCalc.parseRfc3339(dateTextBox.getText().trim(), dateStyle, true));
}
});
mainPanel.add(commandPanel);
dateTextBox.setFocus(true);
}
/**
* Renders the date box for devices where native date input field is not avalilable.
*/
private void renderDateBox(DateStyle dateStyle) {
HorizontalPanel spinnerPanel = new HorizontalPanel();
spinnerPanel.addStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateSpinnerPanel());
VerticalPanel dayPanel = createSpinner(DateField.DAY);
dayPanel.getElement().getStyle().setMarginRight(MARGIN_PIXEL_SIZE_4_0, Unit.PX);
spinnerPanel.add(dayPanel);
VerticalPanel monthPanel = createSpinner(DateField.MONTH);
monthPanel.getElement().getStyle().setMarginRight(MARGIN_PIXEL_SIZE_4_0, Unit.PX);
spinnerPanel.add(monthPanel);
VerticalPanel yearPanel = createSpinner(DateField.YEAR);
yearPanel.getElement().getStyle().setMarginRight(MARGIN_YEAR, Unit.PX);
spinnerPanel.add(yearPanel);
VerticalPanel hourPanel = createSpinner(DateField.HOUR);
spinnerPanel.add(hourPanel);
Label separatorLabel = new Label(":");
separatorLabel.setVisible(false);
separatorLabel.getElement().getStyle().setFontWeight(FontWeight.BOLD);
spinnerPanel.add(separatorLabel);
VerticalPanel minutePanel = createSpinner(DateField.MINUTE);
spinnerPanel.add(minutePanel);
if (DateStyle.DATE.equals(dateStyle) || DateStyle.DATETIME.equals(dateStyle)) {
dayPanel.setVisible(true);
monthPanel.setVisible(true);
yearPanel.setVisible(true);
}
if (DateStyle.TIME.equals(dateStyle) || DateStyle.DATETIME.equals(dateStyle)) {
hourPanel.setVisible(true);
separatorLabel.setVisible(true);
minutePanel.setVisible(true);
}
mainPanel.add(spinnerPanel);
Widget commandPanel = createCommandPanel(new ClickHandler() {
/**
* {@inheritDoc}
*/
@Override
public void onClick(ClickEvent event) {
hide();
Date selectedDate = dateCalc.getDate();
selectionHandler.dateSelected(selectedDate);
}
});
mainPanel.add(commandPanel);
}
/**
* Creates the command panel (with the buttons to confirm or cancel the date choice).
* Can be overridden if command panel should contain different widgets.
*
* @param okClickHandler ClickHandler that is called when the confirm button is pressed and which parses the date.
* @return Widget for Command Panel
*/
protected Widget createCommandPanel(final ClickHandler okClickHandler) {
HorizontalPanel commandPanel = new HorizontalPanel();
commandPanel.addStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateCommandPanel());
Button okButton = new Button(SWMMobile.getI18N().confirmButton(), okClickHandler);
okButton.addStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateOkButton());
commandPanel.add(okButton);
Button cancelButton = new Button(SWMMobile.getI18N().cancelButton(), new ClickHandler() {
/**
* {@inheritDoc}
*/
@Override
public void onClick(ClickEvent event) {
hide();
selectionHandler.dateSelectionCancelled();
}
});
cancelButton.addStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateCancelButton());
commandPanel.add(cancelButton);
return commandPanel;
}
/**
* Will display the popup centered.
*
* @param glassEffect true if glass efect
*/
public void showCentered(boolean glassEffect) {
setGlassEnabled(glassEffect);
setPopupPositionAndShow(new PositionCallback() {
/**
* {@inheritDoc}
*/
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
int left = (Window.getClientWidth() - offsetWidth) / 2;
int top = (Window.getClientHeight() - offsetHeight) / 2;
setPopupPosition(left, top);
}
});
}
public DateSelectionHandler getSelectionHandler() {
return selectionHandler;
}
public void setSelectionHandler(DateSelectionHandler selectionHandler) {
this.selectionHandler = selectionHandler;
}
/**
* Will create the spinner buttons.
*
* @param df the date field
* @return spinner button panel
*/
private VerticalPanel createSpinner(final DateField df) {
VerticalPanel vPanel = new VerticalPanel();
vPanel.setVisible(false);
ImageButton upButton = new ImageButton(SWMMobile.getTheme().getMGWTImageBundle().arrowup(), new ClickHandler() {
/**
* {@inheritDoc}
*/
@Override
public void onClick(ClickEvent event) {
switch (df) {
case DAY:
dateCalc.incrementDay();
break;
case MONTH:
dateCalc.incrementMonth();
break;
case YEAR:
dateCalc.incrementYear();
break;
case HOUR:
dateCalc.incrementHour();
break;
case MINUTE:
dateCalc.incrementMinute();
break;
default:
break;
}
updateLabels();
clearRelativeTime();
}
});
vPanel.add(upButton);
final TextBox label;
switch (df) {
case DAY:
dayLabel = new TextBox();
dayLabel.setWidth("2rem");
dayLabel.setText(dateCalc.getDay() + ".");
label = dayLabel;
break;
case MONTH:
monthLabel = new TextBox();
monthLabel.setWidth("2rem");
monthLabel.setText(dateCalc.getMonth() + ".");
label = monthLabel;
break;
case YEAR:
yearLabel = new TextBox();
yearLabel.setWidth("4rem");
yearLabel.setText(dateCalc.getYear());
label = yearLabel;
break;
case HOUR:
hourLabel = new TextBox();
hourLabel.setWidth("2rem");
hourLabel.setText(numFormat.format(dateCalc.getHour()));
label = hourLabel;
break;
case MINUTE:
minuteLabel = new TextBox();
minuteLabel.setWidth("2rem");
label = minuteLabel;
minuteLabel.setText(numFormat.format(dateCalc.getMinute()));
break;
default:
label = new TextBox();
break;
}
label.addFocusHandler(new FocusHandler() {
@Override
public void onFocus(FocusEvent event) {
label.setText("");
}
});
label.addBlurHandler(new BlurHandler() {
@Override
public void onBlur(BlurEvent event) {
switch (df) {
case DAY:
dateCalc.setDay(label.getText());
updateLabels();
clearRelativeTime();
break;
case MONTH:
dateCalc.setMonth(label.getText());
updateLabels();
clearRelativeTime();
break;
case YEAR:
dateCalc.setYear(label.getText());
updateLabels();
clearRelativeTime();
break;
case HOUR:
dateCalc.setHour(label.getText());
updateLabels();
clearRelativeTime();
break;
case MINUTE:
dateCalc.setMinute(label.getText());
updateLabels();
clearRelativeTime();
break;
default:
break;
}
}
});
label.setStyleName(SWMMobile.getTheme().getMGWTCssBundle().getPopupsCss().dateValueLabel());
vPanel.add(label);
ImageButton downButton = new ImageButton(SWMMobile.getTheme().getMGWTImageBundle().arrowdown(),
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
switch (df) {
case DAY:
dateCalc.decrementDay();
break;
case MONTH:
dateCalc.decrementMonth();
break;
case YEAR:
dateCalc.decrementYear();
break;
case HOUR:
dateCalc.decrementHour();
break;
case MINUTE:
dateCalc.decrementMinute();
break;
default:
break;
}
updateLabels();
clearRelativeTime();
}
});
vPanel.add(downButton);
return vPanel;
}
/**
* Update the date displayed in the date popup.
*
* @param newDate date to be displayed
*/
private void updateDate(Date newDate) {
dateCalc = new DateCalculation(newDate);
if (dateTextBox != null) {
dateTextBox.setValue(dateCalc.formatToRfc3339(newDate, dateStyle, true));
} else {
updateLabels();
}
}
/**
* Update the labels with internal state.
*/
private void updateLabels() {
yearLabel.setText(dateCalc.getYear());
monthLabel.setText(dateCalc.getMonth() + ".");
dayLabel.setText(dateCalc.getDay() + ".");
hourLabel.setText(numFormat.format(dateCalc.getHour()));
minuteLabel.setText(numFormat.format(dateCalc.getMinute()));
}
/**
* Create the HTML input element.
*
* @param type the type
* @return the input element.
*/
private static native InputElement createNumberInputElement(String type) /*-{
var e = $doc.createElement("INPUT");
e.type = type;
return e;
}-*/;
}