eu.geclipse.ui.widgets.DateTimeText.java Source code

Java tutorial

Introduction

Here is the source code for eu.geclipse.ui.widgets.DateTimeText.java

Source

/******************************************************************************
 * Copyright (c) 2007 g-Eclipse consortium 
 * 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
 *
 * Initial development of the original code was made for
 * project g-Eclipse founded by European Union
 * project number: FP6-IST-034327  http://www.geclipse.eu/
 *
 * Contributor(s):
 *     Mariusz Wojtysiak - initial API and implementation
 *     
 *****************************************************************************/
package eu.geclipse.ui.widgets;

import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Control;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import eu.geclipse.core.reporting.IProblem;
import eu.geclipse.core.reporting.ISolution;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.ui.internal.Activator;

/**
 * Widgets, which allow to edit date and time
 */
public class DateTimeText {

    /**
     * Widget style
     */
    public enum Style {
        /**
         * Edit only date
         */
        DATE,
        /**
         * Edit both date and time
         */
        DATETIME
    }

    private static Image image;
    protected Style style;
    protected Button calendarButton;
    private Text text;
    private Composite topComposite;
    private boolean allowEmpty;

    /**
     * @param parent
     * @param style
     * @param allowEmpty if false, then {@link DateTimeText#getDate()} throw an exception for empty date 
     */
    public DateTimeText(final Composite parent, final Style style, final boolean allowEmpty) {
        super();
        this.style = style;
        this.allowEmpty = allowEmpty;
        this.topComposite = new Composite(parent, SWT.NULL);
        GridLayout layout = new GridLayout(2, false);
        layout.horizontalSpacing = 0;
        layout.marginWidth = 0;
        layout.marginTop = 0;
        layout.marginBottom = 0;
        layout.verticalSpacing = 0;
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        this.topComposite.setLayout(layout);
        createText(this.topComposite);
        createButton(this.topComposite);
    }

    /**
     * @param date date which will be shown in widget
     */
    public void setDate(final Date date) {
        String valueString = ""; //$NON-NLS-1$
        if (date != null) {
            valueString = getFormatter(this.style).format(date);
        }
        this.text.setText(valueString);
    }

    /**
     * @return Date entered in control, or null if allowEmpty is true and entered date is empty
     * @throws ProblemException thrown when user entered date in wrong format
     * @see eu.geclipse.ui.dialogs.ProblemDialog#openProblem(Shell, String, String, Throwable)
     */
    public Date getDate() throws ProblemException {
        Date date = null;
        try {
            date = internalGetDate();
        } catch (ParseException exception) {
            ProblemException problemExc = new ProblemException(
                    "eu.geclipse.problem.widget.DateTimeText.WrongFormat", //$NON-NLS-1$
                    exception, Activator.PLUGIN_ID);
            IProblem problem = problemExc.getProblem();
            problem.addSolution(createUseCalendarSolution());
            problem.addSolution("eu.geclipse.solution.widget.DateTimeText.UseCorrectFormat", //$NON-NLS-1$
                    String.format(Messages.getString("DateTimeText.solutionEnterDateInCorrectFormat"), //$NON-NLS-1$
                            getValidDateFormat()));
            if (this.allowEmpty) {
                problem.addSolution("eu.geclipse.solution.widget.DateTimeText.DeleteValue", //$NON-NLS-1$
                        null);
            }
            throw problemExc;
        }
        return date;
    }

    /**
     * @return String containing format in which date should be entered.
     */
    public String getValidDateFormat() {

        String validFormat = null;
        try {
            validFormat = ((SimpleDateFormat) getFormatter(this.style)).toLocalizedPattern();
        } catch (ClassCastException exception) {
            // getFormatter() may return formatter other than SimpleDateFormat for rare localizations.
            // see java-doc for class DateFormat for details
        }
        return validFormat;
    }

    private DateFormat getFormatter(final Style forStyle) {
        DateFormat formatter = null;
        switch (forStyle) {
        case DATE:
            formatter = DateFormat.getDateInstance();
            break;
        case DATETIME:
        default:
            formatter = DateFormat.getDateTimeInstance();
            break;
        }

        formatter.setLenient(true);

        return formatter;
    }

    private void createText(final Composite parent) {
        this.text = new Text(parent, SWT.SINGLE | SWT.BORDER);
        GridData gridData = new GridData();
        gridData.widthHint = getWidthHint();
        this.text.setLayoutData(gridData);
    }

    private int getWidthHint() {
        int width = SWT.DEFAULT;
        switch (this.style) {
        case DATE:
            width = SWT.DEFAULT;
            break;

        case DATETIME:
        default:
            width = 110;
            break;
        }

        return width;
    }

    private Date internalGetDate() throws ParseException {
        Date date = null;
        DateFormat formatter = getFormatter(this.style);
        String dateString = this.text.getText();
        if (!this.allowEmpty || dateString.length() > 0) {
            try {
                date = formatter.parse(dateString);
            } catch (ParseException exception) {
                // if declared parser doesn't work for entered data, try to use other
                // parsers (maybe user omitted some date parts)?
                date = parseOtherFormats(dateString);

                if (date == null) {
                    throw exception;
                }
            }
        }
        return date;
    }

    private Date parseOtherFormats(final String dateString) {
        Date date = null;

        // formatters ordered since most detailed
        DateFormat[] formatters = new DateFormat[] {
                DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM),
                DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT), DateFormat.getDateInstance() };

        for (int index = 0; index < formatters.length && date == null; index++) {
            try {
                date = formatters[index].parse(dateString);
            } catch (ParseException exception) {
                // ignore exception
            }
        }

        return date;
    }

    private void createButton(final Composite parent) {
        this.calendarButton = new Button(parent, SWT.PUSH);
        this.calendarButton.setImage(getImage());
        this.calendarButton.addSelectionListener(new SelectionAdapter() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(final SelectionEvent e) {
                openCalendarDialog();
            }
        });
    }

    private Image getImage() {
        if (DateTimeText.image == null) {
            ImageDescriptor imageDescriptor = Activator.getDefault().getImageRegistry().getDescriptor("calendar"); //$NON-NLS-1$
            DateTimeText.image = imageDescriptor.createImage();
        }
        return DateTimeText.image;
    }

    /**
     * @return shell, on which control is placed 
     */
    public Shell getShell() {
        return this.topComposite.getShell();
    }

    /**
     * Opens popup dialog with calendar to easy selecting date and time
     */
    public void openCalendarDialog() {
        DateTimeDialog dialog = new DateTimeDialog(getShell());
        dialog.open();
    }

    private class DateTimeDialog extends PopupDialog {

        private DateTime dateControl;
        private DateTime timeControl;

        protected DateTimeDialog(final Shell parentShell) {
            super(parentShell, PopupDialog.INFOPOPUP_SHELLSTYLE, true, false, false, false, null, null);
        }

        private void setDate(final Date date) {
            if (date != null) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                this.dateControl.setYear(calendar.get(Calendar.YEAR));
                this.dateControl.setMonth(calendar.get(Calendar.MONTH));
                this.dateControl.setDay(calendar.get(Calendar.DAY_OF_MONTH));
                if (this.timeControl != null) {
                    this.timeControl.setHours(calendar.get(Calendar.HOUR_OF_DAY));
                    this.timeControl.setMinutes(calendar.get(Calendar.MINUTE));
                    this.timeControl.setSeconds(calendar.get(Calendar.SECOND));
                }
            }
        }

        private Date getDate() {
            Calendar calendar = Calendar.getInstance();
            calendar.set(this.dateControl.getYear(), this.dateControl.getMonth(), this.dateControl.getDay(),
                    this.timeControl == null ? 0 : this.timeControl.getHours(),
                    this.timeControl == null ? 0 : this.timeControl.getMinutes(),
                    this.timeControl == null ? 0 : this.timeControl.getSeconds());
            return calendar.getTime();
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
         */
        @Override
        protected Control createDialogArea(final Composite parent) {
            Composite composite = new Composite(parent, SWT.NONE);
            composite.setLayout(new GridLayout(2, true));

            createCalendar(composite);

            if (DateTimeText.this.style == Style.DATETIME) {
                createHour(composite);
            }

            createButtons(composite);

            try {
                setDate(DateTimeText.this.getDate());
            } catch (ProblemException exception) {
                // ignore exception
            }

            return composite;
        }

        private void createButtons(final Composite parent) {
            Composite composite = new Composite(parent, SWT.NONE);
            GridLayout layout = new GridLayout(2, false);
            layout.marginWidth = 0;
            layout.marginHeight = 0;
            composite.setLayout(layout);

            GridData gridData = new GridData();
            gridData.horizontalAlignment = SWT.RIGHT;
            gridData.horizontalSpan = 2;
            composite.setLayoutData(gridData);

            createOkButton(composite);
            createCancelButton(composite);
        }

        private void createCalendar(final Composite parent) {
            this.dateControl = new DateTime(parent, SWT.CALENDAR);
            GridData layoutData = new GridData();
            layoutData.horizontalSpan = 2;
            this.dateControl.setLayoutData(layoutData);
        }

        private void createHour(final Composite parent) {
            Label label = new Label(parent, SWT.NONE);
            label.setText(Messages.getString("DateTimeText.labelHour")); //$NON-NLS-1$
            GridData gridData = new GridData();
            gridData.horizontalAlignment = SWT.END;
            label.setLayoutData(gridData);

            this.timeControl = new DateTime(parent, SWT.TIME);
            gridData = new GridData();
            gridData.horizontalAlignment = SWT.RIGHT;
            this.timeControl.setLayoutData(gridData);
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.dialogs.Dialog#getInitialLocation(org.eclipse.swt.graphics.Point)
         */
        @Override
        protected Point getInitialLocation(final Point initialSize) {
            return Display.getCurrent().map(DateTimeText.this.calendarButton.getParent(), null,
                    DateTimeText.this.calendarButton.getLocation());
        }

        private void createOkButton(final Composite parent) {
            Button button = new Button(parent, SWT.PUSH | SWT.FLAT);
            button.setText(IDialogConstants.OK_LABEL);

            GridData gridData = new GridData();
            gridData.horizontalAlignment = SWT.RIGHT;
            gridData.widthHint = IDialogConstants.BUTTON_WIDTH;

            button.setLayoutData(gridData);
            getShell().setDefaultButton(button);

            button.addSelectionListener(new SelectionAdapter() {

                /* (non-Javadoc)
                 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
                 */
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    closeWithSave();
                }
            });
        }

        private void createCancelButton(final Composite parent) {
            Button button = new Button(parent, SWT.PUSH | SWT.FLAT);
            button.setText(IDialogConstants.CANCEL_LABEL);
            GridData gridData = new GridData();
            gridData.horizontalAlignment = SWT.RIGHT;
            gridData.widthHint = IDialogConstants.BUTTON_WIDTH;
            button.setLayoutData(gridData);

            button.addSelectionListener(new SelectionAdapter() {

                /* (non-Javadoc)
                 * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
                 */
                @Override
                public void widgetSelected(final SelectionEvent e) {
                    close();
                }
            });
        }

        protected void closeWithSave() {
            DateTimeText.this.setDate(getDate());
            close();
        }
    }

    /**
     * @param enabled true if widget should allow editing, false if should work in readonly mode  
     */
    public void setEnabled(final boolean enabled) {
        this.text.setEnabled(enabled);
        this.calendarButton.setEnabled(enabled);
    }

    /**
     * @return @see org.eclipse.swt.widgets.Text#setFocus()
     */
    public boolean setFocus() {
        return this.text.setFocus();
    }

    private ISolution createUseCalendarSolution() {
        return new ISolution() {

            public String getDescription() {
                return Messages.getString("DateTimeText.solutionUseButton"); //$NON-NLS-1$
            }

            public String getID() {
                return null;
            }

            public boolean isActive() {
                return true;
            }

            public void solve() throws InvocationTargetException {
                openCalendarDialog();
            }

        };
    }

}