package org.celllife.idart.gui.widget;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.celllife.function.DateRule;
import org.celllife.idart.gui.utils.ResourceUtils;
import org.celllife.idart.gui.utils.iDartFont;
import org.celllife.idart.misc.iDARTUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MessageBox;
import org.vafada.swtcalendar.SWTCalendarDialog;
import org.vafada.swtcalendar.SWTCalendarEvent;
import org.vafada.swtcalendar.SWTCalendarListener;
/**
* DateButton is an extension of {@link Button} that displays a date as the text
* on the button and pops up a calendar dialog when the button is pressed
* allowing the user to select a date.
*
* The class also supports restricting valid dates by adding a combination of
* {@link DateRule} instances. Each <code>DateRule</code> must return true when
* evaluated for the selected date in order for the date to be valid.
*
* Example Usage:
*
* <pre>
* DateButton b = new DateButton(shell, SWT.PUSH);
* b.setDate(initialDate);
* </pre>
*/
public class DateButton extends Button {
public static int NONE = 0;
public static int ZERO_TIMESTAMP = 1;
private static final String DATE = " Date ";
private final Set<DateChangedListener> listeners;
private String errorMessage;
private String errorMessageTitle = "Date Error";
private IObjectInputValidator validator;
private final int style;
private boolean snap = true;
/**
* @param parent
* @param style
* DateButton.NONE or DateButton.ZERO_TIMESTAMP
* @param validator
*/
public DateButton(Composite parent, int style,
IObjectInputValidator validator) {
super(parent, SWT.PUSH);
this.style = style;
this.validator = validator;
listeners = new HashSet<DateChangedListener>();
this.setText(DATE);
this.setFont(ResourceUtils.getFont(iDartFont.VERASANS_8));
final DateButton thisButton = this;
this.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
super.widgetSelected(event);
final SWTCalendarDialog cal = new SWTCalendarDialog(getShell(),
snap ? DateButton.this : null);
if (getDate() != null) {
cal.setDate(getDate());
} else {
cal.setDate(new Date());
}
cal.addDateChangedListener(new SWTCalendarListener() {
@Override
public void dateChanged(SWTCalendarEvent calendarEvent) {
if (calendarEvent.type == SWTCalendarEvent.DAY) {
cal.close();
try {
Date selectedDate = calendarEvent.getCalendar()
.getTime();
thisButton.setDate(selectedDate);
} catch (RuntimeException e) {
displayFailureMessage();
}
}
}
});
cal.open();
}
});
}
/**
* If set to true the calendar dialog will appear below the button (if the control
* is not null) otherwise it will be centered.
*
* Default = true
*
* @param snap
*/
public void snapToControl(boolean snap){
this.snap = snap;
}
/**
* Clear Get the current date represented by the button.
*
*/
public void clearDate() {
this.setText(DATE);
super.setData(null);
}
/**
* Get the current date represented by the button.
*
* @return the Date if it has been set or null.
*/
public Date getDate() {
Object data = super.getData();
if (data != null && data instanceof Date)
if (style == ZERO_TIMESTAMP)
return iDARTUtil.zeroTimeStamp((Date) data);
else
return (Date) data;
else
return null;
}
/**
* Use setDate() instead.
*/
@Override
@Deprecated
public void setData(Object o) {
if (o instanceof Date) {
Date date = (Date) o;
setDate(date);
}
}
/**
* Use getDate() instead.
*/
@Override
@Deprecated
public Object getData() {
return getDate();
}
/**
* Set the date for the button.
*
* @param date
* @throws DateException
* if the date is not valid according to the restrictions.
*/
public void setDate(Date date) throws RuntimeException {
Date previousDate = getDate();
if (date == null) {
clearDate();
} else if (validate(date)) {
this.setText(iDARTUtil.format(date));
super.setData(date);
fireDateChangedEvent(date, previousDate);
} else
throw new RuntimeException(getValidationMessage());
}
@Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
/**
* Validates the input.
* <p>
* The default implementation of this method delegates the request to the
* supplied input validator object; if it finds the input invalid, the error
* message is displayed in a message box. This hook method is called
* whenever the date changes.
* </p>
*
* @param newDate
* the date to be validated
* @return true if the date is valid
*/
private boolean validate(Date selectedDate) {
errorMessage = null;
if (validator != null) {
errorMessage = validator.isValid(selectedDate);
}
return errorMessage == null;
}
private void displayFailureMessage() {
MessageBox mb = new MessageBox(getShell(), SWT.OK | SWT.ICON_ERROR);
mb.setText(getErrorMessageTitle());
mb.setMessage(errorMessage);
mb.open();
}
private String getValidationMessage() {
return errorMessage;
}
public void setValidator(IObjectInputValidator validator) {
this.validator = validator;
}
public void addDateChangedListener(DateChangedListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeDateChangedListener(DateChangedListener listener) {
if (listeners.contains(listener)) {
listeners.remove(listener);
}
}
private void fireDateChangedEvent(Date newDate, Date previousDate) {
DateChangedEvent event = new DateChangedEvent(newDate, previousDate);
for (DateChangedListener listener : listeners) {
listener.dateChanged(event);
}
}
/**
* Sets the value of the error message that will be displayed in the message box
* @param errorMessageTitle
*/
public void setErrorMessageTitle(String errorMessageTitle) {
this.errorMessageTitle = errorMessageTitle;
}
public String getErrorMessageTitle() {
return errorMessageTitle;
}
}