/******************************************************************************* * Copyright (c) 2008 Dennis Schenk, Peter Siska. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Dennis Schenk - initial implementation * Peter Siska - initial implementation *******************************************************************************/ package ch.unibe.iam.scg.archie.ui.widgets; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DateTime; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import ch.unibe.iam.scg.archie.ArchieActivator; import ch.unibe.iam.scg.archie.i18n.Messages; import ch.unibe.iam.scg.archie.model.RegexValidation; /** * Implements <code>AbstractWidget</code> with a SmartDateField. * * $Id: DateWidget.java 747 2009-07-23 09:14:53Z peschehimself $ * * @author Peter Siska * @author Dennis Schenk * @version $Rev: 747 $ */ public class DateWidget extends TextWidget { /** * Valid DateFormat pattern for DateTextFieldComposites. */ public final static String VALID_DATE_FORMAT = "dd.MM.yyyy"; /** * A simple date format used in this class. */ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(DateWidget.VALID_DATE_FORMAT); private DateTime datePicker; private Shell datePickerShell; /** * @param parent * @param style * @param labelText * @param regex */ public DateWidget(Composite parent, int style, final String labelText, RegexValidation regex) { super(parent, style, labelText, regex); // Add datePicker Popup Button (as Label) Label datePickerPopupButton = new Label(this, SWT.FLAT); Image image = ArchieActivator.getInstance().getImageRegistry().get(ArchieActivator.IMG_BUTTON_CALENDAR); datePickerPopupButton.setImage(image); datePickerPopupButton.addMouseListener(new MouseListener() { public void mouseDown(MouseEvent event) { DateWidget.this.popUpCalendar(); } public void mouseDoubleClick(MouseEvent e) { // Nothing here. Move along. } public void mouseUp(MouseEvent e) { // Nothing here. Move along. } }); // Init Datepicker Popup Shell this.datePickerShell = new Shell(this.getDisplay(), SWT.APPLICATION_MODAL); // Layout GridLayout shellLayout = new GridLayout(); shellLayout.numColumns = 1; this.datePickerShell.setLayout(shellLayout); // Add Datepicker this.datePicker = new DateTime(this.datePickerShell, SWT.CALENDAR); // Add Select Date Button Button button = new Button(this.datePickerShell, SWT.NONE); button.setText(Messages.BUTTON_DATE_SELECT); button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); button.addMouseListener(new MouseListener() { public void mouseDoubleClick(MouseEvent e) { // Nothing here. Move along... } public void mouseDown(MouseEvent e) { Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, DateWidget.this.datePicker.getYear()); cal.set(Calendar.MONTH, DateWidget.this.datePicker.getMonth()); cal.set(Calendar.DAY_OF_MONTH, DateWidget.this.datePicker.getDay()); DateWidget.this.smartField.setContents(DateWidget.DATE_FORMAT.format(cal.getTime())); DateWidget.this.popDownCalendar(); } public void mouseUp(MouseEvent e) { // Nothing here. Move along... } }); // Pack Datepicker Popup Shell this.datePickerShell.pack(); // Allow to close datePicker shell with ESC or ENTER this.datePickerShell.addListener(SWT.Traverse, new Listener() { public void handleEvent(Event event) { switch (event.detail) { case SWT.TRAVERSE_ESCAPE: case SWT.TRAVERSE_RETURN: DateWidget.this.popDownCalendar(); event.detail = SWT.TRAVERSE_NONE; event.doit = false; break; } } }); this.datePicker.addMouseListener(new MouseListener() { public void mouseDoubleClick(MouseEvent e) { // Nothing here. Move along... } public void mouseDown(MouseEvent e) { Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, DateWidget.this.datePicker.getYear()); cal.set(Calendar.MONTH, DateWidget.this.datePicker.getMonth()); cal.set(Calendar.DAY_OF_MONTH, DateWidget.this.datePicker.getDay()); DateWidget.this.smartField.setContents(DateWidget.DATE_FORMAT.format(cal.getTime())); } public void mouseUp(MouseEvent e) { // Nothing here. Move along... } }); // Create quickFix menu listener this.controlDecoration.addMenuDetectListener(new MenuDetectListener() { public void menuDetected(MenuDetectEvent event) { // no quick fix if we aren't in error state. if (DateWidget.this.smartField.isValid()) { return; } if (DateWidget.this.smartField.quickFixMenu == null) { DateWidget.this.smartField.quickFixMenu = DateWidget.this .createQuickFixMenu((SmartDateField) DateWidget.this.smartField); } DateWidget.this.smartField.quickFixMenu.setLocation(event.x, event.y); DateWidget.this.smartField.quickFixMenu.setVisible(true); } }); } /** * Custom layout creation as the date picker has three columns. */ @Override protected void createLayout() { // Create layout. this.layout = new GridLayout(); this.layout.numColumns = 3; this.layout.marginWidth = 2; this.setLayout(this.layout); } /** * Create a <code>SmartNumericField</code> */ @Override protected void createSmartField() { this.smartField = new SmartDateField(); } protected void popUpCalendar() { // TODO: make sure the shell never gets displayed outside of the screen. this.updateCalendarPopup(); Point pt = this.getDisplay().getCursorLocation(); this.datePickerShell.setLocation(pt.x - this.datePicker.getSize().x, pt.y); this.datePickerShell.setVisible(true); this.datePickerShell.setFocus(); } protected void popDownCalendar() { this.datePickerShell.setVisible(false); } /** * Sets the date of the calendar popup to the current contents of the date * smartfield. */ private void updateCalendarPopup() { // add current date from the smartfield if (this.smartField.isValid()) { Date date; try { date = DateWidget.DATE_FORMAT.parse(this.smartField.getContents()); Calendar cal = Calendar.getInstance(); cal.setTime(date); this.datePicker .setDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); } catch (ParseException e) { e.printStackTrace(); } } } protected Menu createQuickFixMenu(final SmartDateField field) { Menu newMenu = new Menu(this.control); MenuItem item = new MenuItem(newMenu, SWT.PUSH); item.setText("You can set this field to the value of today's date."); item.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent event) { field.quickFix(); } public void widgetDefaultSelected(SelectionEvent event) { // do nothing } }); return newMenu; } /** * Smart Date Field: knows if its date is formated right. */ private class SmartDateField extends SmartField { public SmartDateField() { super(); } @Override protected String getErrorMessage() { String format = DateWidget.VALID_DATE_FORMAT; String error = NLS.bind(Messages.ERROR_DATE_FORMAT, format.toUpperCase()); if (DateWidget.this.hasRegexValidation()) { error += " " + DateWidget.this.regexValidation.getMessage(); } return error; } @Override public boolean isValid() { // An empty field is never valid. if (this.getContents().equals("")) { return false; } Date testDate = null; // If the format of the string provided doesn't match the format we // declared in SimpleDateFormat() we will get an exception try { testDate = DateWidget.DATE_FORMAT.parse(this.getContents()); } catch (ParseException e) { return false; } // Dateformat.parse will accept any date as long as it's in the // format we defined, it simply rolls dates over, for example, // december 32 becomes jan 1 and december 0 becomes november 30. // This statement will make sure that once the string has been // checked for proper formatting the date is still the date // that was entered, if it's not, we assume that the date is invalid if (!DateWidget.DATE_FORMAT.format(testDate).equals(this.getContents())) { return false; } // Check for possible regex validation for dates if (DateWidget.this.hasRegexValidation() && !this.getContents().matches(DateWidget.this.regexValidation.getPattern())) { return false; } return true; } /** * @see ch.unibe.iam.scg.archie.ui.widgets.TextWidget.SmartField#hasQuickFix() */ @Override public boolean hasQuickFix() { return true; } /** * @see ch.unibe.iam.scg.archie.ui.widgets.TextWidget.SmartField#getQuickfixMessage() */ @Override protected String getQuickfixMessage() { return this.getErrorMessage(); } /** * Sets the date field contents to the value of today's date. */ protected void quickFix() { Calendar cal = Calendar.getInstance(); this.setContents(DateWidget.DATE_FORMAT.format(cal.getTime())); } } }