/******************************************************************************
* 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();
}
};
}
}