package semorg.gui.util;

import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.SWTEventListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;

import semorg.sql.util.Utility;

/**
 * This class provides a CalendarControl which enables the user to select a date
 * in very comfortable manner.
 */
public class CalendarControl extends Composite {

    /**
     * The Class SWTCalendarPopup.
     */
    private class SWTCalendarPopup {

	/** The popup shell. */
	final Shell popupShell;

	/** The calendar. */
	private SWTCalendar swtcal;

	/** Instantiates a new SWT calendar popup. */
	SWTCalendarPopup() {
	    popupShell = new Shell(parent.getShell(), SWT.NO_TRIM | SWT.BORDER);
	    popupShell.setBackground(popupShell.getDisplay().getSystemColor(
		    SWT.COLOR_DARK_BLUE));
	    popupShell.addShellListener(new ShellListener() {
		public void shellActivated(ShellEvent arg0) {
		}

		public void shellClosed(ShellEvent arg0) {
		}

		public void shellDeactivated(ShellEvent arg0) {
		    popupShell.close();
		    fireSWTCalendarPopupClosed();
		}

		public void shellDeiconified(ShellEvent arg0) {
		}

		public void shellIconified(ShellEvent arg0) {
		}
	    });

	    Composite comp = backgroundHack.getParent();
	    int x = 2;
	    int y = titleBarHeight + backgroundHack.getSize().y;

	    while (!(comp instanceof Shell)) {
		x += comp.getLocation().x;
		y += comp.getLocation().y;
		comp = comp.getParent();
	    }
	    x += comp.getLocation().x;
	    y += comp.getLocation().y;

	    popupShell.setLayout(new RowLayout());

	    swtcal = new SWTCalendar(popupShell, SWTCalendar.RED_SUNDAY);

	    swtcal.addSWTCalendarListener(new SWTCalendarListener() {

		public void dateChanged(SWTCalendarEvent calendarEvent) {
		    Calendar calendar = calendarEvent.getCalendar();
		    calendar.set(Calendar.HOUR_OF_DAY, 0);
		    calendar.set(Calendar.MINUTE, 0);
		    calendar.set(Calendar.SECOND, 0);
		    calendar.set(Calendar.MILLISECOND, 0);
		    date = calendar.getTime();
		    t.setText(Utility.dateOnlyFormatter.format(date));
		}

	    });

	    swtcal.addMouseListener(new MouseListener() {

		public void mouseDoubleClick(MouseEvent arg0) {
		}

		public void mouseDown(MouseEvent arg0) {
		    popupShell.close();
		    fireSWTCalendarDateChanged();
		}

		public void mouseUp(MouseEvent arg0) {
		}
	    });

	    if (t.getText() != null && t.getText().length() > 0) {
		try {
		    Date d = Utility.dateOnlyFormatter.parse(t.getText());
		    setDate(d);
		} catch (ParseException pe) {
		}
	    }

	    popupShell.pack();
	    popupShell.setLocation(new Point(x, y));
	    popupShell.open();
	}

	/**
	 * Sets the date into calendar control.
	 * 
	 * @param date
	 *                the new date
	 */
	public void setDate(Date date) {

	    Calendar calendar = Calendar.getInstance();

	    calendar.setTime(date);

	    swtcal.setCalendar(calendar);

	}

	/** Closes the popup shell. */
	public void close() {
	    if (isOpen())
		popupShell.close();
	}

	/**
	 * Checks if the popup shell is open.
	 * 
	 * @return <tt>true</tt> if the shell is open, <tt>false</tt>
	 *         otherwise.
	 */
	public boolean isOpen() {
	    return popupShell != null && !popupShell.isDisposed();
	}

    }

    /**
     * This class provides the calendar of the control.
     */
    private class SWTCalendar extends Composite {

	/** Style constant for making Sundays red. */
	public static final int RED_SUNDAY = SWTDayChooser.RED_SUNDAY;

	/** Style constant for making weekends red. */
	public static final int RED_WEEKEND = SWTDayChooser.RED_WEEKEND;

	/**
	 * <tt>true</tt> if the date gets actual set, <tt>false</tt>
	 * otherwise.
	 */
	private boolean settingDate;

	/** The year chooser. */
	private Spinner yearChooser;

	/** The month chooser. */
	private SWTMonthChooser monthChooser;

	/** The day chooser. */
	private SWTDayChooser dayChooser;

	/** The setting year month. */
	private boolean settingYearMonth;

	/**
	 * Constructs a calendar control.
	 * 
	 * @param parent
	 *                a parent container.
	 * @param style
	 *                FLAT to make the buttons flat, or NONE.
	 */
	public SWTCalendar(Composite parent, int style) {
	    super(parent, (style & ~(SWT.FLAT | RED_WEEKEND)));

	    Calendar calendar = Calendar.getInstance();

	    {
		final GridLayout gridLayout = new GridLayout();
		gridLayout.marginHeight = 0;
		gridLayout.marginWidth = 0;
		gridLayout.horizontalSpacing = 2;
		gridLayout.verticalSpacing = 2;
		setLayout(gridLayout);
	    }

	    final Composite header = new Composite(this, SWT.NONE);

	    {
		{
		    final GridData gridData = new GridData(
			    GridData.FILL_HORIZONTAL);
		    header.setLayoutData(gridData);
		    final GridLayout gridLayout = new GridLayout();
		    gridLayout.numColumns = 3;
		    gridLayout.marginWidth = 0;
		    gridLayout.marginHeight = 0;
		    header.setLayout(gridLayout);
		}

		final Button prevMonthButton = new Button(header, SWT.ARROW
			| SWT.LEFT | SWT.CENTER | (style & SWT.FLAT));
		prevMonthButton.setLayoutData(new GridData(
			GridData.VERTICAL_ALIGN_FILL));
		prevMonthButton.addSelectionListener(new SelectionAdapter() {
		    public void widgetSelected(SelectionEvent e) {
			previousMonth();
		    }
		});

		final Composite composite = new Composite(header, SWT.NONE);
		composite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
			| GridData.HORIZONTAL_ALIGN_CENTER));
		{
		    final GridLayout gridLayout = new GridLayout();
		    gridLayout.numColumns = 2;
		    gridLayout.marginWidth = 0;
		    gridLayout.marginHeight = 0;
		    composite.setLayout(gridLayout);
		}
		header.setTabList(new Control[] { composite });

		monthChooser = new SWTMonthChooser(composite);
		monthChooser
			.setLayoutData(new GridData(GridData.FILL_VERTICAL));
		monthChooser.addSelectionListener(new SelectionAdapter() {
		    public void widgetSelected(SelectionEvent e) {
			if (!settingYearMonth) {
			    dayChooser.setMonth(monthChooser.getMonth());
			}
		    }
		});

		yearChooser = new Spinner(composite, SWT.BORDER);
		yearChooser.setLayoutData(new GridData(
			GridData.VERTICAL_ALIGN_FILL));
		yearChooser.setMinimum(1);
		yearChooser.setMaximum(9999);
		yearChooser.setSelection(calendar.get(Calendar.YEAR));
		yearChooser.addModifyListener(new ModifyListener() {
		    public void modifyText(ModifyEvent e) {
			if (!settingYearMonth) {
			    dayChooser.setYear(yearChooser.getSelection());
			}
		    }
		});

		final Button nextMonthButton = new Button(header, SWT.ARROW
			| SWT.RIGHT | SWT.CENTER | (style & SWT.FLAT));
		nextMonthButton.setLayoutData(new GridData(
			GridData.VERTICAL_ALIGN_FILL));
		nextMonthButton.addSelectionListener(new SelectionAdapter() {
		    public void widgetSelected(SelectionEvent e) {
			nextMonth();
		    }
		});
	    }

	    {
		dayChooser = new SWTDayChooser(this, SWT.BORDER
			| (style & RED_WEEKEND));
		GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 3;
		dayChooser.setLayoutData(gridData);
		dayChooser.addSWTCalendarListener(new SWTCalendarListener() {
		    public void dateChanged(SWTCalendarEvent event) {
			refreshYearMonth(event.getCalendar());
		    }

		});
	    }

	    setTabList(new Control[] { header, dayChooser });

	    setFont(parent.getFont());
	}

	/**
	 * Instantiates a new SWT calendar.
	 * 
	 * @param parent
	 *                the parent
	 */
	public SWTCalendar(Composite parent) {
	    this(parent, SWT.FLAT);
	}

	/**
	 * Sets the calendar.
	 * 
	 * @param cal
	 *                the new calendar
	 */
	public void setCalendar(Calendar cal) {
	    settingDate = true;
	    try {
		refreshYearMonth(cal);
		dayChooser.setCalendar(cal);
	    } finally {
		settingDate = false;
	    }
	}

	/**
	 * Refresh year month.
	 * 
	 * @param cal
	 *                the cal
	 */
	private void refreshYearMonth(Calendar cal) {
	    settingYearMonth = true;
	    yearChooser.setSelection(cal.get(Calendar.YEAR));
	    monthChooser.setMonth(cal.get(Calendar.MONTH));
	    settingYearMonth = false;
	}

	/**
	 * Next month.
	 */
	public void nextMonth() {
	    Calendar cal = dayChooser.getCalendar();
	    cal.add(Calendar.MONTH, 1);
	    refreshYearMonth(cal);
	    dayChooser.setCalendar(cal);
	}

	/**
	 * Previous month.
	 */
	public void previousMonth() {
	    Calendar cal = dayChooser.getCalendar();
	    cal.add(Calendar.MONTH, -1);
	    refreshYearMonth(cal);
	    dayChooser.setCalendar(cal);
	}

	/**
	 * Gets the calendar.
	 * 
	 * @return the calendar
	 */
	public Calendar getCalendar() {
	    return dayChooser.getCalendar();
	}

	/**
	 * Adds the SWT calendar listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void addSWTCalendarListener(SWTCalendarListener listener) {
	    dayChooser.addSWTCalendarListener(listener);
	}

	/**
	 * Removes the SWT calendar listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void removeSWTCalendarListener(SWTCalendarListener listener) {
	    dayChooser.removeSWTCalendarListener(listener);
	}

	/**
	 * Sets the locale.
	 * 
	 * @param locale
	 *                the new locale
	 */
	public void setLocale(Locale locale) {
	    monthChooser.setLocale(locale);
	    dayChooser.setLocale(locale);
	    yearChooser.setSelection(getCalendar().get(Calendar.YEAR));
	}

	/**
	 * Sets the font that the receiver will use to paint textual information
	 * to the font specified by the argument, or to the default font for
	 * that kind of control if the argument is null.
	 * 
	 * @param font
	 *                the new font (or null)
	 * 
	 * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
	 */
	public void setFont(Font font) {
	    super.setFont(font);
	    monthChooser.setFont(font);
	    yearChooser.setFont(font);
	    dayChooser.setFont(font);
	}

	/**
	 * Checks if the control is setting the date.
	 * 
	 * @return <tt>true</tt>, if is setting date, <tt>false</tt>
	 *         otherwise.
	 */
	public boolean isSettingDate() {
	    return settingDate;
	}

	/**
	 * Adds the listener to the collection of listeners who will be notified
	 * when mouse buttons are pressed and released, by sending it one of the
	 * messages defined in the <code>MouseListener</code> interface.
	 * 
	 * @param listener
	 *                the listener which should be notified
	 * 
	 * @see org.eclipse.swt.widgets.Control#addMouseListener(org.eclipse.swt.events.MouseListener)
	 */
	public void addMouseListener(MouseListener listener) {
	    dayChooser.addRealMouseListener(listener);
	}

	/**
	 * Removes the listener from the collection of listeners who will be
	 * notified when mouse buttons are pressed and released.
	 * 
	 * @param listener
	 *                the listener which should no longer be notified
	 * 
	 * @see org.eclipse.swt.widgets.Control#removeMouseListener(org.eclipse.swt.events.MouseListener)
	 */
	public void removeMouseListener(MouseListener listener) {
	    dayChooser.removeRealMouseListener(listener);
	}

    }

    /**
     * The Class SWTMonthChooser.
     */
    private class SWTMonthChooser extends Composite {

	/** The combo box. */
	private Combo comboBox;

	/** The locale. */
	private Locale locale;

	/**
	 * Instantiates a new SWT month chooser.
	 * 
	 * @param parent
	 *                the parent
	 */
	public SWTMonthChooser(Composite parent) {

	    super(parent, SWT.NONE);

	    locale = Locale.getDefault();

	    setLayout(new FillLayout());

	    comboBox = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);

	    initNames();

	    setMonth(Calendar.getInstance().get(Calendar.MONTH));

	    setFont(parent.getFont());

	}

	/**
	 * Inits the names.
	 */
	private void initNames() {

	    DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);

	    String[] monthNames = dateFormatSymbols.getMonths();

	    int month = comboBox.getSelectionIndex();

	    if (comboBox.getItemCount() > 0) {

		comboBox.removeAll();

	    }

	    for (int i = 0; i < monthNames.length; i++) {

		String name = monthNames[i];

		if (name.length() > 0) {

		    comboBox.add(name);

		}

	    }

	    if (month < 0) {

		month = 0;

	    } else if (month >= comboBox.getItemCount()) {

		month = comboBox.getItemCount() - 1;

	    }

	    comboBox.select(month);

	}

	/**
	 * Adds the selection listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void addSelectionListener(SelectionListener listener) {

	    comboBox.addSelectionListener(listener);

	}

	/**
	 * Removes the selection listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void removeSelectionListener(SelectionListener listener) {

	    comboBox.removeSelectionListener(listener);

	}

	/**
	 * Sets the month.
	 * 
	 * @param newMonth
	 *                the new month
	 */
	public void setMonth(int newMonth) {

	    comboBox.select(newMonth);

	}

	/**
	 * Gets the month.
	 * 
	 * @return the month
	 */
	public int getMonth() {

	    return comboBox.getSelectionIndex();

	}

	/**
	 * Sets the locale.
	 * 
	 * @param locale
	 *                the new locale
	 */
	public void setLocale(Locale locale) {

	    this.locale = locale;

	    initNames();

	}

	/**
	 * Sets the font that the receiver will use to paint textual information
	 * to the font specified by the argument, or to the default font for
	 * that kind of control if the argument is null.
	 * 
	 * @param font
	 *                the new font (or null)
	 * 
	 * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
	 * 
	 */
	public void setFont(Font font) {
	    super.setFont(font);
	    comboBox.setFont(getFont());
	}

    }

    /**
     * The Class SWTDayChooser.
     */
    public class SWTDayChooser extends Composite implements MouseListener,
	    FocusListener, TraverseListener, KeyListener {

	/** Style constant for making Sundays red. */
	public static final int RED_SUNDAY = 1 << 24; // == SWT.EMBEDDED

	/** Style constant for making Saturdays red. */
	public static final int RED_SATURDAY = 1 << 28; // == SWT.VIRTUAL

	/** Style constant for making weekends red. */
	public static final int RED_WEEKEND = RED_SATURDAY | RED_SUNDAY;

	/** The day titles. */
	private Label[] dayTitles;

	/** The days. */
	private DayControl[] days;

	/** The day offset. */
	private int dayOffset;

	/** The active selection background. */
	private Color activeSelectionBackground;

	/** The inactive selection background. */
	private Color inactiveSelectionBackground;

	/** The active selection foreground. */
	private Color activeSelectionForeground;

	/** The inactive selection foreground. */
	private Color inactiveSelectionForeground;

	/** The other month color. */
	private Color otherMonthColor;

	/** The calendar. */
	private Calendar calendar;

	/** The today. */
	private Calendar today;

	/** The locale. */
	private Locale locale;

	/** The listeners. */
	private List<SWTCalendarListener> listeners;

	/** The style. */
	private int style;

	/**
	 * Instantiates a new SWT day chooser.
	 * 
	 * @param parent
	 *                the parent
	 * @param style
	 *                the style
	 */
	public SWTDayChooser(Composite parent, int style) {
	    super(parent, style & ~RED_WEEKEND);
	    this.style = style;
	    listeners = new ArrayList<SWTCalendarListener>(3);

	    setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));

	    otherMonthColor = new Color(getDisplay(), 128, 128, 128);
	    activeSelectionBackground = getDisplay().getSystemColor(
		    SWT.COLOR_LIST_SELECTION);
	    inactiveSelectionBackground = getDisplay().getSystemColor(
		    SWT.COLOR_GRAY);
	    activeSelectionForeground = getDisplay().getSystemColor(
		    SWT.COLOR_LIST_SELECTION_TEXT);
	    inactiveSelectionForeground = getForeground();

	    locale = Locale.getDefault();

	    GridLayout gridLayout = new GridLayout();
	    gridLayout.makeColumnsEqualWidth = true;
	    gridLayout.numColumns = 7;
	    gridLayout.marginHeight = 0;
	    gridLayout.marginWidth = 0;
	    gridLayout.horizontalSpacing = 0;
	    gridLayout.verticalSpacing = 0;
	    setLayout(gridLayout);

	    dayTitles = new Label[7];
	    for (int i = 0; i < dayTitles.length; i++) {
		Label label = new Label(this, SWT.CENTER);
		dayTitles[i] = label;
		label
			.setLayoutData(new GridData(
				GridData.HORIZONTAL_ALIGN_FILL));
		label.addMouseListener(this);
	    }
	    {
		final Composite spacer = new Composite(this, SWT.NO_FOCUS);
		spacer.setBackground(getBackground());
		final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.heightHint = 2;
		gridData.horizontalSpan = 7;
		spacer.setLayoutData(gridData);
		spacer.setLayout(new GridLayout());
		spacer.addMouseListener(this);
	    }

	    {
		final Label label = new Label(this, SWT.HORIZONTAL
			| SWT.SEPARATOR);
		final GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 7;
		label.setLayoutData(gridData);
	    }

	    days = new DayControl[42];
	    for (int i = 0; i < days.length; i++) {
		DayControl day = new DayControl(this);
		days[i] = day;
		day.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
			| GridData.VERTICAL_ALIGN_FILL));
		day.addMouseListener(this);
	    }

	    setTabList(new Control[0]);

	    setFont(parent.getFont());

	    init();

	    addMouseListener(this);
	    addFocusListener(this);
	    addTraverseListener(this);
	    addKeyListener(this);

	    addDisposeListener(new DisposeListener() {
		public void widgetDisposed(DisposeEvent event) {
		    otherMonthColor.dispose();
		}
	    });
	}

	/**
	 * Init.
	 */
	protected void init() {
	    calendar = Calendar.getInstance(locale);
	    calendar.setLenient(true);
	    today = (Calendar) calendar.clone();
	    int firstDayOfWeek = calendar.getFirstDayOfWeek();
	    DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
	    String[] dayNames = dateFormatSymbols.getShortWeekdays();
	    int minLength = Integer.MAX_VALUE;
	    for (int i = 0; i < dayNames.length; i++) {
		int len = dayNames[i].length();
		if (len > 0 && len < minLength) {
		    minLength = len;
		}
	    }
	    if (minLength > 2) {
		for (int i = 0; i < dayNames.length; i++) {
		    if (dayNames[i].length() > 0) {
			dayNames[i] = dayNames[i].substring(0, 1);
		    }
		}
	    }

	    int d = firstDayOfWeek;
	    for (int i = 0; i < dayTitles.length; i++) {
		Label label = dayTitles[i];
		label.setText(dayNames[d]);
		label.setBackground(getBackground());
		if (d == Calendar.SUNDAY && (style & RED_SUNDAY) != 0
			|| d == Calendar.SATURDAY
			&& (style & RED_SATURDAY) != 0) {
		    label.setForeground(getDisplay().getSystemColor(
			    SWT.COLOR_DARK_RED));
		} else {
		    label.setForeground(getForeground());
		}

		d++;
		if (d > dayTitles.length) {
		    d -= dayTitles.length;
		}
	    }

	    drawDays();
	}

	/**
	 * Draw days.
	 */
	protected void drawDays() {
	    calendar.get(Calendar.DAY_OF_YEAR); // Force calendar update
	    Calendar cal = (Calendar) calendar.clone();
	    int firstDayOfWeek = cal.getFirstDayOfWeek();
	    cal.set(Calendar.DAY_OF_MONTH, 1);

	    dayOffset = firstDayOfWeek - cal.get(Calendar.DAY_OF_WEEK);
	    if (dayOffset >= 0) {
		dayOffset -= 7;
	    }
	    cal.add(Calendar.DAY_OF_MONTH, dayOffset);

	    Color foregroundColor = getForeground();
	    for (int i = 0; i < days.length; cal.add(Calendar.DAY_OF_MONTH, 1)) {
		DayControl dayControl = days[i++];
		dayControl.setText(Integer.toString(cal
			.get(Calendar.DAY_OF_MONTH)));
		if (isSameDay(cal, today)) {
		    dayControl.setBorderColor(getDisplay().getSystemColor(
			    SWT.COLOR_BLACK));
		} else {
		    dayControl.setBorderColor(getBackground());
		}

		if (isSameMonth(cal, calendar)) {
		    int d = cal.get(Calendar.DAY_OF_WEEK);
		    if (d == Calendar.SUNDAY && (style & RED_SUNDAY) != 0
			    || d == Calendar.SATURDAY
			    && (style & RED_SATURDAY) != 0) {
			dayControl.setForeground(getDisplay().getSystemColor(
				SWT.COLOR_DARK_RED));
		    } else {
			dayControl.setForeground(foregroundColor);
		    }
		} else {
		    dayControl.setForeground(otherMonthColor);
		}

		if (isSameDay(cal, calendar)) {
		    dayControl.setBackground(getSelectionBackgroundColor());
		    dayControl.setForeground(getSelectionForegroundColor());
		} else {
		    dayControl.setBackground(getBackground());
		}
	    }
	}

	/**
	 * Checks if is same day.
	 * 
	 * @param cal1
	 *                the cal1
	 * @param cal2
	 *                the cal2
	 * 
	 * @return true, if is same day
	 */
	private boolean isSameDay(Calendar cal1, Calendar cal2) {
	    return cal1.get(Calendar.DAY_OF_YEAR) == cal2
		    .get(Calendar.DAY_OF_YEAR)
		    && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
	}

	/**
	 * Checks if is same month.
	 * 
	 * @param cal1
	 *                the cal1
	 * @param cal2
	 *                the cal2
	 * 
	 * @return true, if is same month
	 */
	private boolean isSameMonth(Calendar cal1, Calendar cal2) {
	    return cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH)
		    && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
	}

	/**
	 * Sets the month.
	 * 
	 * @param month
	 *                the new month
	 */
	public void setMonth(int month) {
	    calendar.set(Calendar.MONTH, month);
	    drawDays();
	    dateChanged();
	}

	/**
	 * Sets the year.
	 * 
	 * @param year
	 *                the new year
	 */
	public void setYear(int year) {
	    calendar.set(Calendar.YEAR, year);
	    drawDays();
	    dateChanged();
	}

	/**
	 * Sets the calendar.
	 * 
	 * @param cal
	 *                the new calendar
	 */
	public void setCalendar(Calendar cal) {
	    calendar = (Calendar) cal.clone();
	    calendar.setLenient(true);
	    drawDays();
	    dateChanged();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
	 */
	public void mouseDown(MouseEvent event) {
	    if (event.button == 1) { // Left click
		setFocus();

		if (event.widget instanceof DayControl) {
		    int index = findDay(event.widget);
		    selectDay(index + 1 + dayOffset);
		}
	    }
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
	 */
	public void mouseDoubleClick(MouseEvent event) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
	 */
	public void mouseUp(MouseEvent event) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent)
	 */
	public void focusGained(FocusEvent event) {
	    DayControl selectedDay = getSelectedDayControl();
	    selectedDay.setBackground(getSelectionBackgroundColor());
	    selectedDay.setForeground(getSelectionForegroundColor());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
	 */
	public void focusLost(FocusEvent event) {
	    DayControl selectedDay = getSelectedDayControl();
	    selectedDay.setBackground(getSelectionBackgroundColor());
	    selectedDay.setForeground(getSelectionForegroundColor());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.TraverseListener#keyTraversed(org.eclipse.swt.events.TraverseEvent)
	 */
	public void keyTraversed(TraverseEvent event) {
	    switch (event.detail) {
	    case SWT.TRAVERSE_ARROW_PREVIOUS:
	    case SWT.TRAVERSE_ARROW_NEXT:
	    case SWT.TRAVERSE_PAGE_PREVIOUS:
	    case SWT.TRAVERSE_PAGE_NEXT:
		event.doit = false;
		break;

	    case SWT.TRAVERSE_TAB_NEXT:
	    case SWT.TRAVERSE_TAB_PREVIOUS:
		event.doit = true;
	    }
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent)
	 */
	public void keyPressed(KeyEvent event) {
	    switch (event.keyCode) {
	    case SWT.ARROW_LEFT:
		selectDay(calendar.get(Calendar.DAY_OF_MONTH) - 1);
		break;

	    case SWT.ARROW_RIGHT:
		selectDay(calendar.get(Calendar.DAY_OF_MONTH) + 1);
		break;

	    case SWT.ARROW_UP:
		selectDay(calendar.get(Calendar.DAY_OF_MONTH) - 7);
		break;

	    case SWT.ARROW_DOWN:
		selectDay(calendar.get(Calendar.DAY_OF_MONTH) + 7);
		break;

	    case SWT.PAGE_UP:
		setMonth(calendar.get(Calendar.MONTH) - 1);
		break;

	    case SWT.PAGE_DOWN:
		setMonth(calendar.get(Calendar.MONTH) + 1);
		break;
	    }
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent)
	 */
	public void keyReleased(KeyEvent event) {
	}

	/**
	 * Finds position of a control in <code>days</code> array.
	 * 
	 * @param dayControl
	 *                a control to find.
	 * 
	 * @return an index of <code>dayControl</code> in <code>days</code>
	 *         array, or -1 if not found.
	 */
	private int findDay(Widget dayControl) {
	    for (int i = 0; i < days.length; i++) {
		if (days[i] == dayControl) {
		    return i;
		}
	    }

	    return -1;
	}

	/**
	 * Select day.
	 * 
	 * @param day
	 *                the day
	 */
	private void selectDay(int day) {
	    calendar.get(Calendar.DAY_OF_YEAR); // Force calendar update
	    if (day >= calendar.getActualMinimum(Calendar.DAY_OF_MONTH)
		    && day <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) {
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		// Stay on the same month.
		DayControl selectedDay = getSelectedDayControl();
		selectedDay.setBackground(getBackground());
		if (dayOfWeek == Calendar.SUNDAY) {
		    selectedDay.setForeground(getDisplay().getSystemColor(
			    SWT.COLOR_DARK_RED));
		} else {
		    selectedDay.setForeground(getForeground());
		}

		calendar.set(Calendar.DAY_OF_MONTH, day);

		selectedDay = getSelectedDayControl();
		selectedDay.setBackground(getSelectionBackgroundColor());
		selectedDay.setForeground(getSelectionForegroundColor());

	    } else {
		// Move to a different month.
		calendar.set(Calendar.DAY_OF_MONTH, day);
		drawDays();
	    }

	    dateChanged();
	}

	/**
	 * Gets the selected day control.
	 * 
	 * @return the selected day control
	 */
	private DayControl getSelectedDayControl() {
	    return days[calendar.get(Calendar.DAY_OF_MONTH) - 1 - dayOffset];
	}

	/**
	 * Gets the selection background color.
	 * 
	 * @return the selection background color
	 */
	private Color getSelectionBackgroundColor() {
	    return isFocusControl() ? activeSelectionBackground
		    : inactiveSelectionBackground;
	}

	/**
	 * Gets the selection foreground color.
	 * 
	 * @return the selection foreground color
	 */
	private Color getSelectionForegroundColor() {
	    return isFocusControl() ? activeSelectionForeground
		    : inactiveSelectionForeground;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.widgets.Control#isFocusControl()
	 */
	public boolean isFocusControl() {
	    for (Control control = getDisplay().getFocusControl(); control != null; control = control
		    .getParent()) {
		if (control == this) {
		    return true;
		}
	    }

	    return false;
	}

	/**
	 * Adds the SWT calendar listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void addSWTCalendarListener(SWTCalendarListener listener) {
	    this.listeners.add(listener);
	}

	/**
	 * Removes the SWT calendar listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void removeSWTCalendarListener(SWTCalendarListener listener) {
	    this.listeners.remove(listener);
	}

	/**
	 * Date changed.
	 */
	private void dateChanged() {
	    if (!listeners.isEmpty()) {
		SWTCalendarListener[] listenersArray = new SWTCalendarListener[listeners
			.size()];
		listeners.toArray(listenersArray);
		for (int i = 0; i < listenersArray.length; i++) {
		    Event event = new Event();
		    event.widget = this;
		    event.display = getDisplay();
		    event.time = (int) System.currentTimeMillis();
		    event.data = calendar.clone();
		    listenersArray[i].dateChanged(new SWTCalendarEvent(event));
		}
	    }
	}

	/**
	 * Gets the calendar.
	 * 
	 * @return the calendar
	 */
	public Calendar getCalendar() {
	    return (Calendar) calendar.clone();
	}

	/**
	 * Sets the locale.
	 * 
	 * @param locale
	 *                the new locale
	 */
	public void setLocale(Locale locale) {
	    this.locale = locale;
	    init();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
	 */
	public void setFont(Font font) {
	    super.setFont(font);

	    for (int i = 0; i < dayTitles.length; i++) {
		dayTitles[i].setFont(font);
	    }

	    for (int i = 0; i < days.length; i++) {
		days[i].setFont(font);
	    }
	}

	/**
	 * The Class DayControl.
	 */
	public class DayControl extends Composite implements Listener {

	    /** The filler. */
	    private Composite filler;

	    /** The label. */
	    private Label label;

	    /**
	     * Instantiates a new day control.
	     * 
	     * @param parent
	     *                the parent
	     */
	    public DayControl(Composite parent) {
		super(parent, SWT.NO_FOCUS);
		{
		    final GridLayout gridLayout = new GridLayout();
		    gridLayout.marginWidth = 1;
		    gridLayout.marginHeight = 1;
		    setLayout(gridLayout);
		}

		filler = new Composite(this, SWT.NO_FOCUS);
		filler.setLayoutData(new GridData(GridData.FILL_BOTH));
		{
		    final GridLayout gridLayout = new GridLayout();
		    gridLayout.marginWidth = 2;
		    gridLayout.marginHeight = 0;
		    filler.setLayout(gridLayout);
		}
		filler.addListener(SWT.MouseDown, this);
		filler.addListener(SWT.MouseUp, this);
		filler.addListener(SWT.MouseDoubleClick, this);

		label = new DayLabel(filler, SWT.RIGHT | SWT.NO_FOCUS);
		label.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
			| GridData.HORIZONTAL_ALIGN_CENTER));
		label.addListener(SWT.MouseDown, this);
		label.addListener(SWT.MouseUp, this);
		label.addListener(SWT.MouseDoubleClick, this);

		setBorderColor(parent.getBackground());
		setBackground(parent.getBackground());
		setFont(parent.getFont());
	    }

	    /**
	     * Sets the text.
	     * 
	     * @param text
	     *                the new text
	     */
	    public void setText(String text) {
		label.setText(text);
	    }

	    /**
	     * Gets the text.
	     * 
	     * @return the text
	     */
	    public String getText() {
		return label.getText();
	    }

	    /*
	     * (non-Javadoc)
	     * 
	     * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
	     */
	    public void setFont(Font font) {
		super.setFont(font);
		filler.setFont(font);
		label.setFont(font);
	    }

	    /*
	     * (non-Javadoc)
	     * 
	     * @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
	     */
	    public void setBackground(Color color) {
		filler.setBackground(color);
		label.setBackground(color);
	    }

	    /*
	     * (non-Javadoc)
	     * 
	     * @see org.eclipse.swt.widgets.Control#setForeground(org.eclipse.swt.graphics.Color)
	     */
	    public void setForeground(Color color) {
		label.setForeground(color);
	    }

	    /**
	     * Sets the border color.
	     * 
	     * @param color
	     *                the new border color
	     */
	    public void setBorderColor(Color color) {
		super.setBackground(color);
	    }

	    /*
	     * (non-Javadoc)
	     * 
	     * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
	     */
	    public void handleEvent(Event event) {
		notifyListeners(event.type, event);
	    }
	}

	/**
	 * The Class DayLabel.
	 */
	public class DayLabel extends Label {

	    /**
	     * Instantiates a new day label.
	     * 
	     * @param parent
	     *                the parent
	     * @param style
	     *                the style
	     */
	    public DayLabel(Composite parent, int style) {
		super(parent, style);
	    }

	    /*
	     * (non-Javadoc)
	     * 
	     * @see org.eclipse.swt.widgets.Control#computeSize(int, int,
	     *      boolean)
	     */
	    public Point computeSize(int wHint, int hHint, boolean changed) {
		if (wHint == SWT.DEFAULT) {
		    GC gc = new GC(this);
		    wHint = gc.textExtent("22").x; //$NON-NLS-1$
		    gc.dispose();
		}

		return super.computeSize(wHint, hHint, changed);
	    }

	    /*
	     * (non-Javadoc)
	     * 
	     * @see org.eclipse.swt.widgets.Widget#checkSubclass()
	     */
	    protected void checkSubclass() {
	    }
	}

	/**
	 * Adds the real mouse listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void addRealMouseListener(MouseListener listener) {
	    for (int i = 0; i < days.length; i++) {
		days[i].addMouseListener(listener);
	    }
	}

	/**
	 * Removes the real mouse listener.
	 * 
	 * @param listener
	 *                the listener
	 */
	public void removeRealMouseListener(MouseListener listener) {
	    for (int i = 0; i < days.length; i++) {
		days[i].removeMouseListener(listener);
	    }
	}

    }

    /**
     * The listener interface for receiving SWTCalendar events. The class that
     * is interested in processing a SWTCalendar event implements this
     * interface, and the object created with that class is registered with a
     * component using the component's
     * <code>addSWTCalendarListener<code> method. When
     * the SWTCalendar event occurs, that object's appropriate
     * method is invoked.
     * 
     * @see SWTCalendarEvent
     */
    public interface SWTCalendarListener extends SWTEventListener {

	/**
	 * Date changed.
	 * 
	 * @param event
	 *                the event
	 */
	public void dateChanged(SWTCalendarEvent event);
    }

    /**
     * The listener interface for receiving SWTCalendarPopup events. The class
     * that is interested in processing a SWTCalendarPopup event implements this
     * interface, and the object created with that class is registered with a
     * component using the component's
     * <code>addSWTCalendarPopupListener<code> method. When
     * the SWTCalendarPopup event occurs, that object's appropriate
     * method is invoked.
     *
     */
    public interface SWTCalendarPopupListener extends SWTEventListener {

	/**
	 * Is called when the Popup is opened.
	 * 
	 * @param event
	 *                the event
	 */
	public void popupOpened(SWTCalendarEvent event);

	/**
	 * Is called when the Popup is closed.
	 * 
	 * @param event
	 *                the event
	 */
	public void popupClosed(SWTCalendarEvent event);
    }

    /**
     * The Class SWTCalendarEvent.
     */
    public class SWTCalendarEvent extends TypedEvent {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = -5120399610511453497L;

	/**
	 * Instantiates a new SWT calendar event.
	 * 
	 * @param event
	 *                the event
	 */
	public SWTCalendarEvent(Event event) {
	    super(event);
	}

	/**
	 * Returns the calendar.
	 * 
	 * @return the calendar
	 */
	public Calendar getCalendar() {
	    return (Calendar) this.data;

	}

    }

    /** The parent composite. */
    final private Composite parent;

    /** The text field to display the date. */
    final private Text t;

    /** The button to open th popup. */
    final private Button openPopupButton;

    /** The button to activate the control. */
    final private Button checker;

    /** The date displayed in the control. */
    private Date date;

    /** The title bar height. */
    private int titleBarHeight;

    /** The background hack. */
    private Text backgroundHack;

    /** <tt>true</tt> if the popup window is open, <tt>false</tt> otherwise. */
    private boolean activated;

    /** The date change listeners. */
    private List<SWTCalendarListener> dateChangeListeners = new ArrayList<SWTCalendarListener>();

    /** The popup listeners. */
    private List<SWTCalendarPopupListener> popupListeners = new ArrayList<SWTCalendarPopupListener>();

    /** The popup. */
    private SWTCalendarPopup popup;

    /**
     * Instantiates a new calendar control.
     * 
     * @param par
     *                the parent composite
     * @param tbh
     *                the tbh
     */
    public CalendarControl(Composite par, int tbh) {

	super(par, SWT.NULL);
	this.setLayout(new FormLayout());

	parent = par;

	checker = new Button(this, SWT.CHECK);
	checker.setLayoutData(Utility.getFormData(0, 4, 0, 16, 0, 6, 0, 18));
	checker.addSelectionListener(new SelectionListener() {

	    public void widgetSelected(SelectionEvent event) {
		boolean selected = checker.getSelection();
		setActivated(selected);
		if (selected)
		    try {
			date = Utility.dateOnlyFormatter.parse(t.getText());
			date = Utility.dateOnlyFormatter.parse(t.getText());
		    } catch (ParseException e) {/* kann eigentlich nie passieren */
		    }
		fireSWTCalendarDateChanged();
	    }

	    public void widgetDefaultSelected(SelectionEvent event) {
		widgetSelected(event);
	    }
	});

	date = new Date();

	t = new Text(this, SWT.READ_ONLY);
	t.setBackground(par.getDisplay().getSystemColor(SWT.COLOR_WHITE));
	t.setLayoutData(Utility.getFormData(0, 4, 0, 17, 0, 21, 0, 81));
	t.setText(Utility.dateOnlyFormatter.format(date));

	openPopupButton = new Button(this, SWT.ARROW | SWT.DOWN);
	openPopupButton.setLayoutData(Utility.getFormData(0, 2, 0, 18, 0, 81,
		0, 97));

	backgroundHack = new Text(this, SWT.BORDER | SWT.READ_ONLY);
	backgroundHack.setEnabled(false);
	backgroundHack.setBackground(par.getDisplay().getSystemColor(
		SWT.COLOR_WHITE));
	backgroundHack.setLayoutData(Utility.getFormData(0, 0, 0, 20, 0, 0, 0,
		99));

	titleBarHeight = tbh;

	openPopupButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event event) {
		onOpen();
	    }
	});

	setActivated(false);
    }

    /**
     * This method is invoked on clicking the {@link #openPopupButton}. It
     * activates the calendar control, i.e. it opens the popup.
     */
    private void onOpen() {
	if (!activated) {
	    setActivated(true);
	}
	fireSWTCalendarPopupOpened();
	try {
	    popup = new SWTCalendarPopup();
	} catch (Throwable t) {
	    t.printStackTrace();
	}
    }

    /**
     * Fires all {@link SWTCalendarListener} in the vector
     * {@link #popupListeners}.
     */
    private void fireSWTCalendarPopupClosed() {
	Iterator<SWTCalendarPopupListener> it = popupListeners.iterator();
	while (it.hasNext()) {
	    SWTCalendarPopupListener listener = it.next();

	    Event event = new Event();
	    event.widget = this;
	    event.display = getDisplay();
	    event.time = (int) System.currentTimeMillis();
	    listener.popupClosed(new SWTCalendarEvent(event));
	}
    }

    /**
     * Fires all {@link SWTCalendarListener} instances in the vector
     * {@link #popupListeners}.
     */
    private void fireSWTCalendarPopupOpened() {
	Iterator<SWTCalendarPopupListener> it = popupListeners.iterator();
	while (it.hasNext()) {
	    SWTCalendarPopupListener listener = it.next();

	    Event event = new Event();
	    event.widget = this;
	    event.display = getDisplay();
	    event.time = (int) System.currentTimeMillis();
	    listener.popupOpened(new SWTCalendarEvent(event));
	}
    }

    /**
     * Sets {@link #activated} to the give value, i.e. activates / deactivates
     * the calendar control. If deactivated the controls appears "grayed".
     * 
     * @param activ
     *                the new activated state.
     */
    public void setActivated(boolean activ) {
	activated = activ;
	checker.setSelection(activated);

	if (activated) {
	    t.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
	} else {
	    t.setForeground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
	}
    }

    /**
     * Returns the date.
     * 
     * @return the date if {@link #activated} is <tt>true</tt>, <tt>null</tt>
     *         otherwise.
     */
    public Date getDate() {
	if (activated) {
	    return date;
	} else {
	    return null;
	}
    }

    /**
     * Sets the font that the receiver will use to paint textual information to
     * the font specified by the argument, or to the default font for that kind
     * of control if the argument is null.
     * 
     * @param font
     *                the new font (or null)
     * 
     * @see org.eclipse.swt.widgets.Control#setFont(org.eclipse.swt.graphics.Font)
     */
    public void setFont(Font font) {
	t.setFont(font);
    }

    /**
     * Sets the date displayed in the text field to the given value..
     * 
     * @param d
     *                the new date to display.
     */
    public void setDate(Date d) {
	/* if the popup is open, close it by revoking the focus */
	if (activated) {
	    getShell().forceActive();
	}

	date = d;
	setActivated(d != null);
	if (d != null) {
	    t.setText(Utility.dateOnlyFormatter.format(date));
	} else {
	    t.setText(Utility.dateOnlyFormatter.format(new Date()));
	}
    }

    /**
     * Adds the given SWT calendar popup listener to {@link #popupListeners}.
     * 
     * @param listener
     *                the listener to add.
     */
    public void addSWTCalendarPopuplistener(SWTCalendarPopupListener listener) {
	this.popupListeners.add(listener);
    }

    /**
     * Removes the given SWT calendar popup listener from
     * {@link #popupListeners}.
     * 
     * @param listener
     *                the listener to remove.
     */
    public void removeSWTCalendarPopuplistener(SWTCalendarPopupListener listener) {
	this.popupListeners.remove(listener);
    }

    /**
     * Adds the given SWT calendar listener from the
     * {@link #dateChangeListeners} vector.
     * 
     * @param listener
     *                the listener
     */
    public void addSWTCalendarlistener(SWTCalendarListener listener) {
	this.dateChangeListeners.add(listener);
    }

    /**
     * Removes the given SWT calendar listener from the
     * {@link #dateChangeListeners} vector.
     * 
     * @param listener
     *                the listener to remove.
     */
    public void removeSWTCalendarlistener(SWTCalendarListener listener) {
	this.dateChangeListeners.remove(listener);
    }

    /**
     * Fires all {@link SWTCalendarListener} instances in the
     * {@link #dateChangeListeners} Vector.
     */
    private void fireSWTCalendarDateChanged() {
	Iterator<SWTCalendarListener> it = dateChangeListeners.iterator();
	while (it.hasNext()) {
	    SWTCalendarListener listener = it.next();

	    Event event = new Event();
	    event.widget = this;
	    event.display = getDisplay();
	    event.time = (int) System.currentTimeMillis();
	    event.data = getDate();
	    listener.dateChanged(new SWTCalendarEvent(event));
	}
    }

    /**
     * Enables the receiver if the argument is <code>true</code>, and
     * disables it otherwise.<br>
     * <br>
     * 
     * A disabled control is typically not selectable from the user interface
     * and draws with an inactive or "grayed" look.
     */
    public void setEnabled(boolean enabled) {
	super.setEnabled(enabled);
	openPopupButton.setEnabled(enabled);
	t.setEnabled(enabled);
	checker.setEnabled(enabled);
    }

    /**
     * Return button to open the popup.
     * 
     * @return {@link Button} instance to open the popup.
     */
    public Button getOpenPopupButton() {
	return openPopupButton;
    }

    /**
     * Checks if the popup window is open.
     * 
     * @return <tt>true</tt>, if the popup is open, otherwise <tt>false</tt>.
     */
    public boolean isPopupOpen() {
	return (popup != null && popup.isOpen());
    }

    /** Closes popup window. */
    public void closePopup() {
	if (popup != null) {
	    popup.close();
	}
    }

    /**
     * Sets the tooltip the {@link CalendarControl} to the given string.
     * 
     * @param toolTipText
     *                the new tooltip text.
     */
    public void setToolTipText(String toolTipText) {
	t.setToolTipText(toolTipText);
	openPopupButton.setToolTipText(toolTipText);
	checker.setToolTipText(toolTipText);
    }
}
