/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.common.widget;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TypedListener;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.ui.common.InternalUiConstants;
/**
* CalendarWidget
*
* @since 8.0
*/
public class CalendarWidget extends Composite implements InternalUiConstants {
private static final String PREFIX = I18nUtil.getPropertyPrefix(CalendarWidget.class);
int m_Day;
int m_Month;
int m_Year;
boolean m_showCalendar;
boolean m_showTime;
private Button nextMonth;
private Button nextYear;
private Button prevMonth;
private Button prevYear;
private Label m_CalendarLabel;
private TDatePanel m_DatePanel;
private Spinner m_hourSpinner;
private Spinner m_minuteSpinner;
Composite pnlCalendar;
private Composite pnlTime;
/**
* Construct an instance of <code>CalendarWidget</code>. The calendar will always be shown.
*
* @param theParent
* @param theStyle
* @param theShowTime indicates if time should be shown
*/
public CalendarWidget( Composite theParent,
int theStyle,
boolean theShowTime ) {
this(theParent, theStyle, theShowTime, true);
}
/**
* Construct an instance of <code>CalendarWidget</code>.
*
* @param theParent
* @param theStyle
* @param theShowTime indicates if time should be shown
* @param theShowCalendar indicates if the calendar should be shown
*/
public CalendarWidget( Composite theParent,
int theStyle,
boolean theShowTime,
boolean theShowCalendar ) {
super(theParent, theStyle);
GridLayout gridLayout = new GridLayout();
gridLayout.marginHeight = 1;
gridLayout.marginWidth = 1;
gridLayout.verticalSpacing = 0;
gridLayout.horizontalSpacing = 0;
setLayout(gridLayout);
setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
m_showTime = theShowTime;
m_showCalendar = theShowCalendar;
construct(this);
// initialize state
Calendar currentDate = Calendar.getInstance();
m_Day = currentDate.get(Calendar.DATE);
m_Month = currentDate.get(Calendar.MONTH);
m_Year = currentDate.get(Calendar.YEAR);
m_hourSpinner.setSelection(currentDate.get(Calendar.HOUR_OF_DAY));
m_minuteSpinner.setSelection(currentDate.get(Calendar.MINUTE));
}
private void construct( Composite theParent ) {
//
// calendar container
//
pnlCalendar = new Composite(theParent, SWT.NONE) {
// need to override since computeSize does not consider if visible or not
@Override
public Point computeSize( int wHint,
int hHint,
boolean changed ) {
if (!m_showCalendar) {
return new Point(0, 0);
}
return super.computeSize(wHint, hHint, changed);
}
};
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 5;
gridLayout.verticalSpacing = 0;
gridLayout.horizontalSpacing = 0;
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
pnlCalendar.setLayout(gridLayout);
pnlCalendar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
//
// previous year button
//
prevYear = new Button(pnlCalendar, SWT.NONE);
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gridData.heightHint = 20;
gridData.widthHint = 20;
prevYear.setLayoutData(gridData);
prevYear.setText("<<"); //$NON-NLS-1$
prevYear.setToolTipText(Util.getString(PREFIX + "previousYear")); //$NON-NLS-1$
prevYear.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent theEvent ) {
--m_Year;
updateDate();
}
});
//
// previous month button
//
prevMonth = new Button(pnlCalendar, SWT.NONE);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gridData.heightHint = gridData.widthHint = 20;
prevMonth.setLayoutData(gridData);
prevMonth.setText("<"); //$NON-NLS-1$
prevMonth.setToolTipText(Util.getString(PREFIX + "previousMonth")); //$NON-NLS-1$
prevMonth.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent theEvent ) {
--m_Month;
updateDate();
}
});
//
// calendar label
//
m_CalendarLabel = new Label(pnlCalendar, SWT.CENTER);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.heightHint = prevYear.computeSize(20, 20).y;
int minLabelChars = 20;
gridData.minimumWidth = getMinCalWidth(m_CalendarLabel, minLabelChars);
m_CalendarLabel.setLayoutData(gridData);
//
// next month button
//
nextMonth = new Button(pnlCalendar, SWT.NONE);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
gridData.heightHint = gridData.widthHint = 20;
nextMonth.setLayoutData(gridData);
nextMonth.setText(">"); //$NON-NLS-1$
nextMonth.setToolTipText(Util.getString(PREFIX + "nextMonth")); //$NON-NLS-1$
nextMonth.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent theEvent ) {
++m_Month;
updateDate();
}
});
//
// next year button
//
nextYear = new Button(pnlCalendar, SWT.NONE);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
gridData.heightHint = gridData.widthHint = 20;
nextYear.setLayoutData(gridData);
nextYear.setText(">>"); //$NON-NLS-1$
nextYear.setToolTipText(Util.getString(PREFIX + "nextYear")); //$NON-NLS-1$
nextYear.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected( SelectionEvent theEvent ) {
++m_Year;
updateDate();
}
});
//
// calendar date panel
//
m_DatePanel = new TDatePanel(pnlCalendar, SWT.NONE);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 5;
m_DatePanel.setLayoutData(gridData);
//
// time container
//
pnlTime = new Composite(theParent, SWT.NONE) {
@Override
public Point computeSize( int wHint,
int hHint,
boolean changed ) {
// need to override since computeSize does not consider if visible or not
if (!m_showTime) {
return new Point(0, 0);
}
return super.computeSize(wHint, hHint, changed);
}
};
GridLayout gridLayout2 = new GridLayout();
gridLayout2.numColumns = 4;
gridLayout2.marginHeight = 1;
gridLayout2.marginWidth = 1;
pnlTime.setLayout(gridLayout2);
//
// hour label
//
Label lblHour = new Label(pnlTime, SWT.NONE);
lblHour.setText(Util.getString(PREFIX + "lblHour")); //$NON-NLS-1$
//
// hour spinner
//
m_hourSpinner = new Spinner(pnlTime, SWT.NONE);
m_hourSpinner.setMinimum(0);
m_hourSpinner.setMaximum(23);
m_hourSpinner.setToolTipText(Util.getString(PREFIX + "hourSpinner.toolTip", //$NON-NLS-1$
m_hourSpinner.getMinimum(),
m_hourSpinner.getMaximum()));
//
// minute label
//
Label lblMinute = new Label(pnlTime, SWT.NONE);
lblMinute.setText(Util.getString(PREFIX + "lblMinute")); //$NON-NLS-1$
//
// minute spinner
//
m_minuteSpinner = new Spinner(pnlTime, SWT.NONE);
m_minuteSpinner.setMinimum(0);
m_minuteSpinner.setMaximum(59);
m_minuteSpinner.setToolTipText(Util.getString(PREFIX + "minuteSpinner.toolTip", //$NON-NLS-1$
m_minuteSpinner.getMinimum(),
m_minuteSpinner.getMaximum()));
//
// set initial state
//
if (!m_showCalendar) {
showCalendar(false);
}
if (!m_showTime) {
showTime(false);
}
panelChanged();
}
/**
* Gets the avg width in pixels for the desired number of characters using the supplied label's font
*
* @param label the supplied label
* @param nChars number of chars to calculate avg width
*/
private int getMinCalWidth( Label label,
int nChars ) {
int widthPixels = 0;
// Get font metric for labels font
GC gc = new GC(label);
gc.setFont(label.getFont());
FontMetrics fontMetrics = gc.getFontMetrics();
// calculate avg width for the supplied number of chars
widthPixels = fontMetrics.getAverageCharWidth() * nChars;
gc.dispose();
return widthPixels;
}
public void addSelectionListener( SelectionListener theListener ) {
checkWidget();
if (theListener == null) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
if (m_showCalendar) {
TypedListener typedListener = new TypedListener(theListener);
addListener(SWT.Selection, typedListener);
addListener(SWT.DefaultSelection, typedListener);
prevMonth.addSelectionListener(theListener);
prevYear.addSelectionListener(theListener);
nextMonth.addSelectionListener(theListener);
nextYear.addSelectionListener(theListener);
}
if (m_showTime) {
m_hourSpinner.addSelectionListener(theListener);
m_minuteSpinner.addSelectionListener(theListener);
}
}
void dateSelected( boolean good ) {
Event event = new Event();
event.doit = good;
m_DatePanel.redraw();
notifyListeners(SWT.Selection, event);
}
public Date getDate() {
Calendar date = Calendar.getInstance();
date.set(Calendar.MONTH, getMonth());
date.set(Calendar.DATE, getDay());
date.set(Calendar.YEAR, getYear());
return new Date(date.getTime().getTime());
}
public int getDay() {
return m_Day;
}
public int getHour() {
return m_hourSpinner.getSelection();
}
public int getMinute() {
return m_minuteSpinner.getSelection();
}
public int getMonth() {
return m_Month;
}
private String getMonthName( int theMonth ) {
return m_DatePanel.getMonthName(theMonth - 1);
}
public Time getTime() {
Calendar date = Calendar.getInstance();
date.set(Calendar.HOUR_OF_DAY, m_hourSpinner.getSelection());
date.set(Calendar.MINUTE, m_minuteSpinner.getSelection());
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
return new Time(date.getTime().getTime());
}
public Timestamp getTimestamp() {
Calendar date = Calendar.getInstance();
date.set(Calendar.MONTH, getMonth());
date.set(Calendar.DATE, getDay());
date.set(Calendar.YEAR, getYear());
date.set(Calendar.HOUR_OF_DAY, m_hourSpinner.getSelection());
date.set(Calendar.MINUTE, m_minuteSpinner.getSelection());
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
return new Timestamp(date.getTime().getTime());
}
public int getYear() {
return m_Year;
}
public boolean isDateWidget() {
return (m_showCalendar && !m_showTime);
}
public boolean isTimeWidget() {
return (!m_showCalendar && m_showTime);
}
public boolean isTimestampWidget() {
return (m_showCalendar && m_showTime);
}
void normalizeDay() {
// used in case an invalid day or month is set by the onKeyDown method (ex. day < 0 or > 31)
Calendar calendar = Calendar.getInstance();
if (m_showCalendar) {
calendar.set(Calendar.YEAR, m_Year);
calendar.set(Calendar.MONTH, m_Month);
calendar.set(Calendar.DAY_OF_MONTH, m_Day);
m_Year = calendar.get(Calendar.YEAR);
m_Month = calendar.get(Calendar.MONTH);
m_Day = calendar.get(Calendar.DAY_OF_MONTH);
}
if (m_showTime) {
calendar.set(Calendar.HOUR_OF_DAY, m_hourSpinner.getSelection());
calendar.set(Calendar.MINUTE, m_minuteSpinner.getSelection());
m_hourSpinner.setSelection(calendar.get(Calendar.HOUR_OF_DAY));
m_minuteSpinner.setSelection(calendar.get(Calendar.MINUTE));
}
}
void panelChanged() {
if (m_showCalendar) {
m_CalendarLabel.setText(getMonthName(m_Month + 1) + ", " + m_Year); //$NON-NLS-1$
}
}
public void removeSelectionListener( SelectionListener theListener ) { // NO_UCD (Indicates this is ignored by unused code detection tool)
checkWidget();
if (theListener == null) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
removeListener(SWT.Selection, theListener);
removeListener(SWT.DefaultSelection, theListener);
}
// public void setDay(int theDay) {
// m_Day = theDay;
// panelChanged();
// redraw();
// }
//
public void setValue( Date theDate ) {
Calendar date = Calendar.getInstance();
date.setTime(theDate);
m_Day = date.get(Calendar.DATE);
m_Month = date.get(Calendar.MONTH);
m_Year = date.get(Calendar.YEAR);
panelChanged();
}
public void setValue( Time theTime ) {
Calendar date = Calendar.getInstance();
date.setTime(theTime);
m_hourSpinner.setSelection(date.get(Calendar.HOUR_OF_DAY));
m_minuteSpinner.setSelection(date.get(Calendar.MINUTE));
panelChanged();
}
public void setValue( Timestamp theTimestamp ) {
Calendar date = Calendar.getInstance();
date.setTime(theTimestamp);
m_Day = date.get(Calendar.DATE);
m_Month = date.get(Calendar.MONTH);
m_Year = date.get(Calendar.YEAR);
m_hourSpinner.setSelection(date.get(Calendar.HOUR_OF_DAY));
m_minuteSpinner.setSelection(date.get(Calendar.MINUTE));
panelChanged();
}
public void showCalendar( boolean theShowFlag ) {
m_showCalendar = theShowFlag;
pnlCalendar.setVisible(theShowFlag);
}
public void showTime( boolean theShowFlag ) {
m_showTime = theShowFlag;
pnlTime.setVisible(theShowFlag);
}
void updateDate() {
normalizeDay();
m_DatePanel.redraw();
panelChanged();
}
private class TDatePanel extends Canvas {
private Display m_Display = Display.getCurrent();
private Calendar m_Calendar = Calendar.getInstance();
private int m_ColSize;
private int m_RowSize;
private String[] m_Days = new String[7];
private String[] m_Months = new String[12];
public TDatePanel( Composite parent,
int style ) {
super(parent, style | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE);
Calendar cal = Calendar.getInstance();
m_Year = cal.get(Calendar.YEAR);
m_Month = cal.get(Calendar.MONTH);
m_Day = cal.get(Calendar.DATE);
DateFormat format = new SimpleDateFormat("EE"); //$NON-NLS-1$
for (int i = 1; i <= 7; ++i) {
cal.set(Calendar.DAY_OF_WEEK, i);
m_Days[i - 1] = format.format(cal.getTime()).substring(0, 2);
}
format = new SimpleDateFormat("MMMM"); //$NON-NLS-1$
for (int i = 0; i < 12; ++i) {
cal.set(Calendar.MONTH, i);
m_Months[i] = format.format(cal.getTime());
}
GC gc = new GC(this);
Point p = gc.stringExtent("Q"); //$NON-NLS-1$
gc.dispose();
m_ColSize = p.x * 3;
m_RowSize = (int)(p.y * 1.2);
addPaintListener(new PaintListener() {
@Override
public void paintControl( PaintEvent event ) {
onPaint(event);
}
});
addControlListener(new ControlAdapter() {
@Override
public void controlResized( ControlEvent e ) {
redraw();
}
});
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed( KeyEvent e ) {
onKeyDown(e);
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mouseDown( MouseEvent e ) {
onMouseDown(e);
}
});
}
private int calendarDayToNormal( int theDay ) {
switch (theDay) {
case Calendar.SUNDAY:
return 0;
case Calendar.MONDAY:
return 1;
case Calendar.TUESDAY:
return 2;
case Calendar.WEDNESDAY:
return 3;
case Calendar.THURSDAY:
return 4;
case Calendar.FRIDAY:
return 5;
case Calendar.SATURDAY:
return 6;
}
return -1;
}
@Override
public Point computeSize( int wHint,
int hHint,
boolean changed ) {
Point size = pnlCalendar.getSize();
m_ColSize = (int)(size.x / 7D);
return new Point((int)(size.x / 7D * 7), m_RowSize * 7);
}
private int getDayFromPoint( int x,
int y ) {
for (int i = 1; i <= 31; i++) {
Point p = getDayPoint(i);
Rectangle r = new Rectangle(p.x, p.y, m_ColSize, m_RowSize);
if (r.contains(x, y)) return i;
}
return -1;
}
private String getDayName( int day ) {
return m_Days[day];
}
private Point getDayPoint( int day ) {
m_Calendar.set(Calendar.YEAR, m_Year);
m_Calendar.set(Calendar.MONTH, m_Month);
m_Calendar.set(Calendar.DAY_OF_MONTH, 1);
int first_day_of_week = calendarDayToNormal(m_Calendar.get(Calendar.DAY_OF_WEEK)) - 1;
m_Calendar.set(Calendar.DAY_OF_MONTH, day);
int day_of_week = calendarDayToNormal(m_Calendar.get(Calendar.DAY_OF_WEEK));
int x = (day_of_week) * m_ColSize;
int y = (1 + (first_day_of_week + day) / 7) * m_RowSize;
return new Point(x, y);
}
private int getMaxDay() {
m_Calendar.set(Calendar.YEAR, m_Year);
m_Calendar.set(Calendar.MONTH, m_Month);
int day = 28;
for (int i = 0; i < 10; i++) {
m_Calendar.set(Calendar.DAY_OF_MONTH, day);
if (m_Calendar.get(Calendar.MONTH) != m_Month) return day - 1;
day++;
}
return -1;
}
String getMonthName( int month ) {
return m_Months[month];
}
void onKeyDown( KeyEvent theEvent ) {
if (theEvent.character == SWT.ESC) {
dateSelected(false);
return;
}
if ((theEvent.character == ' ') || (theEvent.character == '\r')) {
dateSelected(true);
return;
}
int oldDay = m_Day;
int oldMonth = m_Month;
if (theEvent.keyCode == SWT.ARROW_LEFT) {
m_Day--;
} else if (theEvent.keyCode == SWT.ARROW_RIGHT) {
m_Day++;
} else if (theEvent.keyCode == SWT.ARROW_UP) {
m_Day -= 7;
if (m_Day < 1) {
m_Day = oldDay;
}
} else if (theEvent.keyCode == SWT.ARROW_DOWN) {
m_Day += 7;
if (m_Day > getMaxDay()) {
m_Day = oldDay;
}
} else if (theEvent.keyCode == SWT.PAGE_UP) {
m_Month--;
} else if (theEvent.keyCode == SWT.PAGE_DOWN) {
m_Month++;
}
normalizeDay();
if ((m_Day != oldDay) || (m_Month != oldMonth)) {
redraw();
if (m_Month != oldMonth) {
panelChanged();
}
}
}
void onMouseDown( MouseEvent theEvent ) {
int day = getDayFromPoint(theEvent.x, theEvent.y);
if (day > 0) {
m_Day = day;
dateSelected(true);
}
}
void onPaint( PaintEvent event ) {
Rectangle rect = getClientArea();
GC gc0 = event.gc;
Image image = new Image(m_Display, rect.width, rect.height);
GC gc = new GC(image);
gc.setBackground(m_Display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
gc.fillRectangle(rect);
int x = 0;
int y = 0;
for (int i = 0; i < 7; i++) {
if (i == 0) {
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_RED));
} else {
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_BLACK));
}
String text = getDayName(i);
Point size = gc.stringExtent(text);
gc.drawText(text, x + (m_ColSize - size.x) / 2, (m_RowSize - size.y) / 2, true);
x += m_ColSize;
}
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_BLACK));
y += m_RowSize;
gc.drawLine(0, 0, rect.width, 0);
gc.drawLine(0, y - 1, rect.width, y - 1);
m_Calendar.set(Calendar.YEAR, m_Year);
m_Calendar.set(Calendar.MONTH, m_Month);
int day = 1;
Font stdFont = gc.getFont();
FontData fontData = stdFont.getFontData()[0];
Font boldFont = new Font(null, fontData.getName(), fontData.getHeight(), SWT.BOLD);
while (true) {
m_Calendar.set(Calendar.DAY_OF_MONTH, day);
if (m_Calendar.get(Calendar.MONTH) != m_Month) {
break;
}
int day_of_week = calendarDayToNormal(m_Calendar.get(Calendar.DAY_OF_WEEK));
Point p = getDayPoint(day);
if (day == m_Day) {
gc.setFont(boldFont);
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_BLACK));
gc.setBackground(m_Display.getSystemColor(SWT.COLOR_LIST_SELECTION));
} else {
gc.setFont(stdFont);
gc.setBackground(m_Display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
if (day_of_week == 0) {
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_RED));
} else {
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_BLACK));
}
}
String text = "" + day; //$NON-NLS-1$
Point size = gc.stringExtent(text);
gc.drawText(text, p.x + ((m_ColSize - size.x) / 2), p.y + ((m_RowSize - size.y) / 2), true);
day++;
}
gc0.drawImage(image, 0, 0);
gc.dispose();
image.dispose();
}
}
}