/****************************************************************************
* Copyright (c) 2004-2008 Jeremy Dowdall
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Jeremy Dowdall <jeremyd@aspencloud.com> - initial API and implementation
*****************************************************************************/
package org.eclipse.nebula.widgets.cdatetime;
import java.awt.ComponentOrientation;
import java.text.BreakIterator;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import org.eclipse.nebula.cwt.v.VButton;
import org.eclipse.nebula.cwt.v.VControl;
import org.eclipse.nebula.cwt.v.VGridLayout;
import org.eclipse.nebula.cwt.v.VLabel;
import org.eclipse.nebula.cwt.v.VPanel;
import org.eclipse.nebula.cwt.v.VStackLayout;
import org.eclipse.nebula.cwt.v.VTracker;
import org.eclipse.nebula.widgets.cdatetime.CDT.Key;
import org.eclipse.nebula.widgets.cdatetime.CDT.PickerPart;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
class DatePicker extends VPanel {
private static final int DAYS_IN_WEEK = 7;
private static final int NUM_ROWS = 6;
private Listener dayListener;
private VPanel header;
private VPanel body;
private VPanel[] bodyPanels;
private VPanel footer;
private VPanel dayPanel;
VButton monthButton;
VButton monthPrev;
VButton dateNow;
VButton monthNext;
VButton yearButton;
VButton yearPrev;
VButton yearNext;
VButton timeButton;
VLabel dayLabels[];
VButton dayButtons[];
VButton today;
VButton clear;
MenuItem todayMenuItem;
MenuItem showSelMenuItem;
MenuItem[] monthItems;
MenuItem[] yearItems;
// private int focusDayButton;
boolean editYear = false;
private boolean scrollable = true;
// private Comparator<Date> dayComparator = new Comparator<Date>() {
// public int compare(Date d1, Date d2) {
// return d1.compareTo(d2);
// }
// };
VPanel monthPanel;
VButton[] monthButtons;
VPanel yearPanel;
VButton[] yearButtons;
AnalogTimePicker timePanel;
private CDateTime cdt;
private int fields = 0;
private SimpleDateFormat sdf;
private String lastPattern;
/**
* Constructs a new instance of this class given its parent, a style value
* describing its behavior and appearance, a date to which the initial
* selection will be set, and the locale to use.
*
* @param parent
* a widget which will be the parent of the new instance (cannot
* be null)
*/
public DatePicker(CDateTime parent) {
super(parent.pickerPanel, parent.style);
cdt = parent;
init(parent.style);
}
private void addBodyPanel() {
if (bodyPanels == null) {
bodyPanels = new VPanel[1];
} else {
VPanel[] pa = new VPanel[bodyPanels.length + 1];
System.arraycopy(bodyPanels, 0, pa, 0, bodyPanels.length);
bodyPanels = pa;
body.getLayout(VGridLayout.class).numColumns++;
}
VPanel picker = new VPanel(body, SWT.NONE);
picker.setData(CDT.PickerPart, PickerPart.BodyPanel);
picker.setPainter(cdt.getPainter());
cdt.getPainter().update(picker);
picker.setLayout(new VStackLayout());
picker.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
bodyPanels[bodyPanels.length - 1] = picker;
}
/**
* Modifies the given Calendar field by the given amount for every
* dayButton.<br/>
* calendar.add(CalendarField, amount)
*
* @param field
* Calendar Field
* @param amount
* adjustment to be added
*/
private void adjustDays(int field, int amount) {
Calendar tmpcal = cdt.getCalendarInstance();
for (int day = 0; day < dayButtons.length; day++) {
tmpcal.setTime(dayButtons[day].getData(CDT.Key.Date, Date.class));
tmpcal.add(field, amount);
dayButtons[day].setData(CDT.Key.Date, tmpcal.getTime());
}
}
/**
* create the Calendar's body, which contains the dayLabels and dayButtons
*/
private void createBody() {
body = new VPanel(this, SWT.NONE);
body.setData(CDT.PickerPart, PickerPart.BodyPanel);
body.setPainter(cdt.getPainter());
cdt.getPainter().update(body);
VGridLayout layout = new VGridLayout(1, false);
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.horizontalSpacing = 0;
body.setLayout(layout);
body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
addBodyPanel();
for (Iterator<Body> iter = cdt.builder.getBodies().iterator(); iter
.hasNext();) {
Body b = iter.next();
if (b.newColumn) {
VLabel sep = new VLabel(body, SWT.SEPARATOR | SWT.VERTICAL);
sep.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
body.getLayout(VGridLayout.class).numColumns++;
addBodyPanel();
}
switch (b.type) {
case Body.DAYS:
createDays(b);
break;
case Body.MONTHS:
createMonths(b);
break;
case Body.TIME:
createTime(b);
break;
case Body.YEARS:
createYears(b);
break;
}
}
for (VPanel bodyPanel : bodyPanels) {
bodyPanel.getLayout(VStackLayout.class).setTopControl(null);
}
}
protected void createContents() {
VGridLayout layout = new VGridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
setLayout(layout);
if (cdt.builder.hasHeader()) {
createHeader();
// if (cdt.field.length > 1
// || (cdt.getCalendarField(cdt.field[0]) != Calendar.MONTH
// && cdt.getCalendarField(cdt.field[0]) != Calendar.YEAR)) {
// createHeader();
// }
}
if (cdt.builder.hasHeader()
&& (cdt.builder.hasBody() || cdt.builder.hasFooter())) {
VLabel separator = new VLabel(this, SWT.HORIZONTAL | SWT.SEPARATOR);
separator.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
false));
}
if (cdt.builder.hasBody()) {
createBody();
}
if ((cdt.builder.hasHeader() || cdt.builder.hasBody())
&& cdt.builder.hasFooter()) {
VLabel sep = new VLabel(this, SWT.HORIZONTAL | SWT.SEPARATOR);
sep.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
}
if (cdt.builder.hasFooter()) {
createFooter();
}
}
private void createDays(Body b) {
VPanel bodyPanel = bodyPanels[bodyPanels.length - 1];
dayPanel = new VPanel(bodyPanel, SWT.NO_FOCUS);
dayPanel.setData(CDT.PickerPart, PickerPart.DayPanel);
dayPanel.setPainter(cdt.getPainter());
cdt.getPainter().update(dayPanel);
VGridLayout layout = new VGridLayout(7, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = b.spacing;
layout.verticalSpacing = b.spacing;
dayPanel.setLayout(layout);
bodyPanel.getLayout(VStackLayout.class).setDefault(dayPanel, false);
addListener(SWT.MouseWheel, new Listener() {
public void handleEvent(Event event) {
scrollCalendar((event.count > 0) ? SWT.ARROW_UP
: SWT.ARROW_DOWN);
}
});
Menu bodyMenu = dayPanel.createMenu();
todayMenuItem = new MenuItem(bodyMenu, SWT.NONE);
todayMenuItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
setCDTSelection(new Date());
}
});
showSelMenuItem = new MenuItem(bodyMenu, SWT.NONE);
showSelMenuItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
cdt.showSelection();
}
});
dayListener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.KeyDown:
if (event.stateMask == 0) {
if (event.keyCode == SWT.KEYPAD_CR
|| event.character == SWT.CR
|| event.character == ' ') {
setSelectionFromFocusButton(event);
} else if (event.keyCode == SWT.HOME
|| event.keyCode == SWT.END
|| event.keyCode == SWT.PAGE_DOWN
|| event.keyCode == SWT.PAGE_UP) {
scrollCalendar(event.keyCode);
setSelectionFromFocusButton(event);
}
}
break;
case SWT.MouseDown:
if (event.button == 3) {
dayPanel.getMenu().setVisible(true);
}
break;
case SWT.MouseWheel:
scrollCalendar((event.count > 0) ? SWT.ARROW_UP
: SWT.ARROW_DOWN);
break;
case SWT.Selection:
if (event.widget == null) {
VButton button = (VButton) event.data;
int stateMask = event.stateMask;
setSelectionFromButton(button, stateMask);
// Bug 388813
// when the date field is the most "precise"
// information according to the pattern
if (cdt.isClosingField(Calendar.DATE)) {
cdt.fireSelectionChanged(true);
} else {
cdt.fireSelectionChanged();
}
}
break;
case SWT.Traverse:
if (event.detail == SWT.TRAVERSE_RETURN) {
setSelectionFromFocusButton(event);
} else {
traverseSelection(event.keyCode);
setSelectionFromFocusButton(event);
}
break;
}
}
};
dayLabels = new VLabel[DAYS_IN_WEEK];
for (int day = 0; day < dayLabels.length; day++) {
dayLabels[day] = new VLabel(dayPanel, SWT.CENTER);
dayLabels[day].setData(CDT.PickerPart, PickerPart.DayOfWeekLabel);
dayLabels[day].setData(CDT.Key.Compact, b.compact);
dayLabels[day].setData(CDT.Key.Index, day);
dayLabels[day].setPainter(cdt.getPainter());
cdt.getPainter().update(dayLabels[day]);
dayLabels[day].setMargins(1, 1);
dayLabels[day].setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
true, false));
}
VLabel sep = new VLabel(dayPanel, SWT.HORIZONTAL | SWT.SEPARATOR);
sep.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 7, 1));
dayButtons = new VButton[DAYS_IN_WEEK * NUM_ROWS];
for (int day = 0; day < dayButtons.length; day++) {
dayButtons[day] = new VButton(dayPanel, SWT.TOGGLE);
dayButtons[day].setData(CDT.PickerPart, PickerPart.DayButton);
dayButtons[day].setData(CDT.Key.Index, day);
dayButtons[day].setPainter(cdt.getPainter());
cdt.getPainter().update(dayButtons[day]);
dayButtons[day].setSquare(true);
dayButtons[day].setMargins(4, 4);
dayButtons[day].setLayoutData(new GridData(SWT.FILL, SWT.FILL,
true, true));
dayButtons[day].addListener(SWT.KeyDown, dayListener);
dayButtons[day].addListener(SWT.MouseDown, dayListener);
dayButtons[day].addListener(SWT.MouseWheel, dayListener);
dayButtons[day].addListener(SWT.Selection, dayListener);
dayButtons[day].addListener(SWT.Traverse, dayListener);
}
}
/**
* create the footer (footerButton) for the Calendar part of this CDateTime<br/>
* there is currently no footer for the Clock part - should there be? or
* should this footer span both parts?
*/
private void createFooter() {
footer = new VPanel(this, SWT.NONE);
footer.setData(CDT.PickerPart, PickerPart.FooterPanel);
footer.setPainter(cdt.getPainter());
cdt.getPainter().update(footer);
VGridLayout layout = new VGridLayout();
layout.makeColumnsEqualWidth = cdt.builder.getFooterEqualColumns();
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
layout.marginHeight = 1;
layout.marginWidth = 1;
footer.setLayout(layout);
footer.setLayoutData(new GridData(cdt.builder.getFooterAlignment(),
SWT.FILL, true, false));
for (Iterator<Footer> iter = cdt.builder.getFooters().iterator(); iter
.hasNext();) {
((VGridLayout) footer.getLayout()).numColumns++;
Footer f = iter.next();
switch (f.type) {
case Footer.CLEAR:
clear = new VButton(footer, SWT.PUSH | SWT.NO_FOCUS);
clear.setData(CDT.PickerPart, PickerPart.ClearButton);
clear.setPainter(cdt.getPainter());
cdt.getPainter().update(clear);
clear.setLayoutData(new GridData(f.alignment, SWT.FILL, f.grab,
false));
clear.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
setCDTSelection(null);
}
});
break;
case Footer.TODAY:
case Footer.VERBOSE_TODAY:
today = new VButton(footer, SWT.PUSH | SWT.NO_FOCUS);
today.setData(CDT.PickerPart, PickerPart.TodayButton);
today.setPainter(cdt.getPainter());
cdt.getPainter().update(today);
today.setLayoutData(new GridData(f.alignment, SWT.FILL, f.grab,
false));
today.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
setCDTSelection(new Date());
}
});
break;
}
}
}
/**
* create the header for the Calendar part of this CDateTime<br/>
* there is no equivalent for the Clock part
*/
private void createHeader() {
header = new VPanel(this, SWT.NONE);
header.setData(CDT.PickerPart, PickerPart.HeaderPanel);
header.setPainter(cdt.getPainter());
cdt.getPainter().update(header);
VGridLayout layout = new VGridLayout();
layout.makeColumnsEqualWidth = cdt.builder.getHeaderEqualColumns();
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
layout.marginHeight = 2;
layout.marginWidth = 2;
header.setLayout(layout);
header.setLayoutData(new GridData(cdt.builder.getHeaderAlignment(),
SWT.FILL, true, false));
GridData data;
for (Iterator<Header> iter = cdt.builder.getHeaders().iterator(); iter
.hasNext();) {
((VGridLayout) header.getLayout()).numColumns++;
Header h = iter.next();
data = new GridData(h.alignment, SWT.FILL, h.grab, false);
switch (h.type) {
case Header.DATE_NOW:
dateNow = new VButton(header, SWT.PUSH | SWT.NO_FOCUS);
dateNow.setData(CDT.PickerPart, PickerPart.DateNow);
dateNow.setPainter(cdt.getPainter());
cdt.getPainter().update(dateNow);
dateNow.setMargins(4, 0);
dateNow.setPolygon(new int[] { 7, 7 });
dateNow.setLayoutData(data);
dateNow.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
setCDTSelection(new Date());
}
});
break;
case Header.MONTH:
monthButton = new VButton(header, SWT.TOGGLE | SWT.NO_FOCUS);
monthButton.setData(CDT.PickerPart, PickerPart.MonthLabel);
monthButton.setPainter(cdt.getPainter());
cdt.getPainter().update(monthButton);
monthButton.setAlignment(h.textAlignment, SWT.CENTER);
monthButton.setLayoutData(data);
if (h.readOnly) {
monthButton.setPaintNative(false);
} else {
if (CDT.gtk) {
monthButton.addListener(SWT.MouseWheel, new Listener() {
public void handleEvent(Event event) {
if (SWT.MouseWheel == event.type) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.add(Calendar.MONTH,
(event.count > 0) ? 1 : -1);
setCDTSelection(tmpcal.getTime());
}
}
});
}
monthButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
handleHeaderSelection((VButton) event.data);
}
});
Menu monthMenu = monthButton.createMenu();
monthItems = new MenuItem[12];
for (int i = 0; i < 12; i++) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.set(Calendar.MONTH, i);
monthItems[i] = new MenuItem(monthMenu, SWT.NONE);
monthItems[i]
.setData(
"Month", new Integer(tmpcal.get(Calendar.MONTH))); //$NON-NLS-1$
monthItems[i]
.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
MenuItem item = (MenuItem) e.widget;
Calendar tmpcal = cdt
.getCalendarInstance();
tmpcal.set(
Calendar.MONTH,
((Integer) item
.getData("Month")).intValue()); //$NON-NLS-1$
setCDTSelection(tmpcal.getTime());
}
});
}
}
break;
case Header.MONTH_NEXT:
monthNext = new VButton(header, SWT.ARROW | SWT.RIGHT
| SWT.NO_FOCUS);
monthNext.setData(CDT.PickerPart, PickerPart.MonthNext);
monthNext.setPainter(cdt.getPainter());
cdt.getPainter().update(monthNext);
monthNext.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
false));
monthNext.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
Calendar tmpcal = cdt.getCalendarInstance();
if (yearNext == null && yearButton != null
&& yearButton.getSelection()) {
tmpcal.add(Calendar.YEAR, 10);
} else {
tmpcal.add(Calendar.MONTH, 1);
}
setCDTSelection(tmpcal.getTime());
}
});
break;
case Header.MONTH_PREV:
monthPrev = new VButton(header, SWT.ARROW | SWT.LEFT
| SWT.NO_FOCUS);
monthPrev.setData(CDT.PickerPart, PickerPart.MonthPrev);
monthPrev.setPainter(cdt.getPainter());
cdt.getPainter().update(monthPrev);
monthPrev.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
false));
monthPrev.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
Calendar tmpcal = cdt.getCalendarInstance();
if (yearPrev == null && yearButton != null
&& yearButton.getSelection()) {
tmpcal.add(Calendar.YEAR, -10);
} else {
tmpcal.add(Calendar.MONTH, -1);
}
setCDTSelection(tmpcal.getTime());
}
});
break;
case Header.TIME:
timeButton = new VButton(header, SWT.TOGGLE | SWT.NO_FOCUS);
timeButton.setMargins(3, 5);
timeButton.setImage(Resources.getIconClock());
timeButton.setData(CDT.PickerPart, PickerPart.MonthPrev);
timeButton.setPainter(cdt.getPainter());
cdt.getPainter().update(timeButton);
timeButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
false, false));
timeButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
handleHeaderSelection((VButton) event.data);
}
});
break;
case Header.YEAR:
yearButton = new VButton(header, SWT.TOGGLE | SWT.NO_FOCUS);
yearButton.setData(CDT.PickerPart, PickerPart.YearLabel);
yearButton.setPainter(cdt.getPainter());
cdt.getPainter().update(yearButton);
yearButton.setAlignment(h.textAlignment, SWT.CENTER);
yearButton.setLayoutData(data);
if (h.readOnly) {
yearButton.setPaintNative(false);
} else {
if (CDT.gtk) {
yearButton.addListener(SWT.MouseWheel, new Listener() {
public void handleEvent(Event event) {
if (SWT.MouseWheel == event.type) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.add(Calendar.YEAR,
(event.count > 0) ? 1 : -1);
setCDTSelection(tmpcal.getTime());
}
}
});
}
yearButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
handleHeaderSelection((VButton) event.data);
}
});
Menu yearMenu = yearButton.createMenu();
yearItems = new MenuItem[11];
for (int i = 0; i < 11; i++) {
yearItems[i] = new MenuItem(yearMenu, SWT.NONE);
yearItems[i].setData("Year", new Integer(i)); //$NON-NLS-1$
yearItems[i]
.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
MenuItem item = (MenuItem) e.widget;
Calendar tmpcal = cdt
.getCalendarInstance();
tmpcal.add(
Calendar.YEAR,
((Integer) item.getData("Year")).intValue() - 5); //$NON-NLS-1$
setCDTSelection(tmpcal.getTime());
}
});
}
}
break;
case Header.YEAR_NEXT:
yearNext = new VButton(header, SWT.ARROW | SWT.RIGHT
| SWT.NO_FOCUS);
yearNext.setData(CDT.PickerPart, PickerPart.YearNext);
yearNext.setPainter(cdt.getPainter());
cdt.getPainter().update(yearNext);
yearNext.setLayoutData(data);
yearNext.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
Calendar tmpcal = cdt.getCalendarInstance();
if (yearButton != null && yearButton.getSelection()) {
tmpcal.add(Calendar.YEAR, 10);
} else if (cdt.isClosingField(Calendar.YEAR)) {
tmpcal.add(Calendar.YEAR, 10);
} else {
tmpcal.add(Calendar.YEAR, 1);
}
setCDTSelection(tmpcal.getTime());
}
});
break;
case Header.YEAR_PREV:
yearPrev = new VButton(header, SWT.ARROW | SWT.LEFT
| SWT.NO_FOCUS);
yearPrev.setData(CDT.PickerPart, PickerPart.YearPrev);
yearPrev.setPainter(cdt.getPainter());
cdt.getPainter().update(yearPrev);
yearPrev.setLayoutData(data);
yearPrev.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
Calendar tmpcal = cdt.getCalendarInstance();
if (yearButton != null && yearButton.getSelection()) {
tmpcal.add(Calendar.YEAR, -10);
} else if (cdt.isClosingField(Calendar.YEAR)) {
tmpcal.add(Calendar.YEAR, -10);
} else {
tmpcal.add(Calendar.YEAR, -1);
}
setCDTSelection(tmpcal.getTime());
}
});
break;
}
}
}
private void createMonths(Body b) {
VPanel bodyPanel = bodyPanels[bodyPanels.length - 1];
monthPanel = new VPanel(bodyPanel, SWT.NONE);
monthPanel.setData(CDT.PickerPart, PickerPart.DayOfWeekPanel);
monthPanel.setPainter(cdt.getPainter());
cdt.getPainter().update(monthPanel);
VGridLayout layout = new VGridLayout(3, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = b.spacing;
layout.verticalSpacing = b.spacing;
monthPanel.setLayout(layout);
bodyPanel.getLayout(VStackLayout.class).setDefault(monthPanel, false);
monthButtons = new VButton[12];
for (int month = 0; month < monthButtons.length; month++) {
monthButtons[month] = new VButton(monthPanel,
(cdt.field.length > 1) ? (SWT.PUSH | SWT.NO_FOCUS)
: SWT.TOGGLE);
monthButtons[month].setSquare(true);
monthButtons[month].setData("month", month); //$NON-NLS-1$
monthButtons[month].setData(CDT.PickerPart,
PickerPart.DayOfWeekLabel);
monthButtons[month].setData(CDT.Key.Index, month);
monthButtons[month].setPainter(cdt.getPainter());
cdt.getPainter().update(monthButtons[month]);
monthButtons[month].setLayoutData(new GridData(SWT.FILL, SWT.FILL,
true, true));
// monthButtons[month].addListener(SWT.Selection, dayListener);
monthButtons[month].addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
if (event.widget == null) {
VButton button = (VButton) event.data;
if (button.hasStyle(SWT.TOGGLE)) {
for (VButton b : monthButtons) {
if (b != button) {
b.setSelection(false);
}
}
}
Calendar tmpcal = cdt.getCalendarInstance();
int tmpday = tmpcal.get(Calendar.DAY_OF_MONTH);
Integer tmpmonth = (Integer) button.getData("Month"); //$NON-NLS-1$
/*
* : Bug 288164 keep the selected month by setting the day of month
* to the minimum of actual maximum and the selected date
*/
tmpcal.set(tmpcal.get(Calendar.YEAR), tmpmonth, 1);
if (tmpcal.getActualMaximum(Calendar.DAY_OF_MONTH)<tmpday)
tmpday = tmpcal.getActualMaximum(Calendar.DAY_OF_MONTH);
tmpcal.set(Calendar.DAY_OF_MONTH, tmpday);
tmpcal.set(Calendar.MONTH, tmpmonth);
cdt.setSelection(tmpcal.getTime());
/*
* : Bug 388813 the method cdt.isClosingField checks the
* "most concrete" portion of the date pattern and
* returns true if the requested field *is* the one
* closing the picker panel and false otherwise
*/
if (cdt.isClosingField(Calendar.MONTH)) {
cdt.fireSelectionChanged(true);
} else {
cdt.fireSelectionChanged();
handleHeaderSelection(null);
}
}
}
});
}
updateMonths();
if (monthButton != null) {
monthButton.setData(Key.Panel, monthPanel);
}
}
private void createTime(Body b) {
VPanel bodyPanel = bodyPanels[bodyPanels.length - 1];
timePanel = new AnalogTimePicker(cdt, this);
timePanel.setParent(bodyPanel);
bodyPanel.getLayout(VStackLayout.class).setDefault(timePanel, false);
if (timeButton != null) {
timeButton.setData(Key.Panel, timePanel);
}
}
private void createYears(Body b) {
VPanel bodyPanel = bodyPanels[bodyPanels.length - 1];
yearPanel = new VPanel(bodyPanel, SWT.NONE);
yearPanel.setData(CDT.PickerPart, PickerPart.DayOfWeekPanel);
yearPanel.setPainter(cdt.getPainter());
cdt.getPainter().update(yearPanel);
VGridLayout layout = new VGridLayout(3, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.horizontalSpacing = b.spacing;
layout.verticalSpacing = b.spacing;
yearPanel.setLayout(layout);
bodyPanel.getLayout(VStackLayout.class).setDefault(yearPanel, false);
yearButtons = new VButton[15];
for (int year = 0; year < yearButtons.length; year++) {
yearButtons[year] = new VButton(yearPanel,
(cdt.field.length > 1) ? (SWT.PUSH | SWT.NO_FOCUS)
: SWT.TOGGLE);
yearButtons[year].setSquare(true);
yearButtons[year]
.setData(CDT.PickerPart, PickerPart.DayOfWeekLabel);
yearButtons[year].setData(CDT.Key.Index, year);
yearButtons[year].setPainter(cdt.getPainter());
cdt.getPainter().update(yearButtons[year]);
yearButtons[year].setLayoutData(new GridData(SWT.FILL, SWT.FILL,
true, true));
yearButtons[year].addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
if (event.widget == null) {
VButton button = (VButton) event.data;
if (button.hasStyle(SWT.TOGGLE)) {
for (VButton b : yearButtons) {
if (b != button) {
b.setSelection(false);
}
}
}
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.set(Calendar.YEAR,
Integer.parseInt(button.getText()));
cdt.setSelection(tmpcal.getTime());
// Bug 388813
// when the year field is the most precise field
if (cdt.isClosingField(Calendar.YEAR)) {
cdt.fireSelectionChanged(true);
} else {
cdt.fireSelectionChanged();
handleHeaderSelection(null);
}
}
}
});
}
if (yearButton != null) {
yearButton.setData(Key.Panel, yearPanel);
}
}
public int[] getFields() {
return new int[] { Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH };
}
private int getFocusDayButton() {
VControl focusControl = VTracker.getFocusControl();
if (focusControl != null) {
for (int i = 0; i < dayButtons.length; i++) {
if (focusControl == dayButtons[i]) {
return i;
}
}
}
return -1;
}
private String getFormattedDate(String pattern, Date date) {
if (pattern != null) {
if (sdf == null) {
sdf = new SimpleDateFormat(pattern, cdt.locale);
sdf.setTimeZone(cdt.timezone);
} else if (!pattern.equals(lastPattern)) {
sdf.applyPattern(pattern);
}
lastPattern = pattern;
return sdf.format(date);
}
return ""; //$NON-NLS-1$
}
private void handleHeaderSelection(VButton button) {
if (monthButton != null && monthButton != button) {
monthButton.setSelection(false);
}
if (yearButton != null && yearButton != button) {
yearButton.setSelection(false);
}
if (timeButton != null && timeButton != button) {
timeButton.setSelection(false);
}
if (button != null && button.getSelection()) {
VPanel panel = button.getData(Key.Panel, VPanel.class);
panel.getParent().getLayout(VStackLayout.class)
.setTopControl(panel, 500);
} else {
for (VPanel panel : bodyPanels) {
panel.getLayout(VStackLayout.class).setTopControl(null, 500);
}
}
}
private void init(int style) {
if (cdt.builder == null) {
if (cdt.field.length > 1 && (style & (CDT.COMPACT)) != 0) {
cdt.builder = CDateTimeBuilder.getCompact();
} else {
cdt.builder = CDateTimeBuilder.getStandard();
}
}
}
/**
* perform the scroll by making a call to {@link #adjustDays(int, int)} with
* the <code>field</code> set to Calendar.DATE and the <code>amount</code>
* corresponding to the keycode.
*/
private void scrollCalendar(int keycode) {
if (scrollable) {
switch (keycode) {
case SWT.ARROW_DOWN:
adjustDays(Calendar.DATE, 7);
break;
case SWT.ARROW_UP:
adjustDays(Calendar.DATE, -7);
break;
case SWT.END:
adjustDays(Calendar.YEAR, 1);
break;
case SWT.HOME:
adjustDays(Calendar.YEAR, -1);
break;
case SWT.PAGE_DOWN:
adjustDays(Calendar.MONTH, 1);
break;
case SWT.PAGE_UP:
adjustDays(Calendar.MONTH, -1);
break;
}
}
}
private void setButtonFocus(int index) {
if (index >= 0 && index < dayButtons.length) {
VButton button = dayButtons[index];
button.setFocus();
}
}
/**
* Set the date for each dayButton by starting with the given
* <code>firstDate</code> and iterating over all the dayButtons, adding 1
* day to the date with each iteration.<br>
* The date is stored in the dayButton with: setData(CDT.Key.Date, date).<br>
* If <code>alignMonth</code> is true, then the actual first date used will
* be modified to be the first date of the visible calendar which includes
* the given <code>firstDate</code>
*
* @param firstDate
* the first date of the dayButtons
* @param alignMonth
* whether or not to align the month
*/
private void setDays(Date firstDate, boolean alignMonth) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.setTime(firstDate);
if (alignMonth) {
tmpcal.set(Calendar.DATE, 1);
int firstDay = tmpcal.get(Calendar.DAY_OF_WEEK)
- tmpcal.getFirstDayOfWeek();
if (firstDay < 0) {
firstDay += 7;
}
tmpcal.add(Calendar.DATE, -firstDay);
}
for (int day = 0; day < dayButtons.length; day++) {
dayButtons[day].setData(CDT.Key.Date, tmpcal.getTime());
tmpcal.add(Calendar.DATE, 1);
}
}
public void setEditable(boolean editable) {
setStyle(SWT.READ_ONLY, !editable);
if (dayPanel != null) {
dayPanel.setActivatable(false);
}
if (timePanel != null) {
timePanel.setActivatable(false);
}
}
public void setFields(int[] calendarFields) {
cdt.builder.setFields(calendarFields);
fields = 0;
int[] fa = getFields();
for (int i = 0; i < calendarFields.length; i++) {
for (int j = 0; j < fa.length; j++) {
if (calendarFields[i] == fa[j])
fields |= (1 << j);
}
}
createContents();
updateLabels();
if (monthButton != null) {
monthButton.addListener(SWT.Resize, new Listener() {
public void handleEvent(Event event) {
if (SWT.Resize == event.type) {
setMonthLabelText();
}
}
});
}
if (timePanel != null) {
timePanel.setFields(calendarFields);
}
}
public boolean setFocus() {
return setFocusToSelection();
}
@Override
protected boolean setFocus(boolean focus) {
if (!focus) {
return super.setFocus(focus);
} else if (dayPanel != null) {
return setFocusToSelection();
} else {
return false;
}
}
private boolean setFocusToSelection() {
if (dayPanel != null) {
if (cdt.hasSelection()) {
Calendar first = cdt.getCalendarInstance((Date) dayButtons[0]
.getData(CDT.Key.Date));
first.set(Calendar.MILLISECOND, 0);
first.set(Calendar.SECOND, 0);
first.set(Calendar.MINUTE, 0);
first.set(Calendar.HOUR_OF_DAY, 0);
Calendar last = cdt
.getCalendarInstance((Date) dayButtons[dayButtons.length - 1]
.getData(CDT.Key.Date));
last.set(Calendar.MILLISECOND, 0);
last.set(Calendar.SECOND, 0);
last.set(Calendar.MINUTE, 0);
last.set(Calendar.HOUR_OF_DAY, 0);
last.add(Calendar.DATE, 1);
last.add(Calendar.MILLISECOND, -1);
Date selection = cdt.getSelection();
Calendar scal = cdt.getCalendarInstance(selection);
for (int j = 0; j < dayButtons.length; j++) {
Calendar tmpcal = cdt
.getCalendarInstance((Date) dayButtons[j]
.getData(CDT.Key.Date));
if ((scal.get(Calendar.DATE) == tmpcal.get(Calendar.DATE))
&& (scal.get(Calendar.MONTH) == tmpcal
.get(Calendar.MONTH))
&& (scal.get(Calendar.YEAR) == tmpcal
.get(Calendar.YEAR))) {
return dayButtons[j].setFocus();
}
}
} else {
dayButtons[0].setFocus();
}
}
return true;
}
void setMonthLabelText() {
String str = getFormattedDate("MMMM", cdt.getCalendarTime()); //$NON-NLS-1$
GC gc = new GC(getDisplay());
int width = monthButton.getClientArea().width;
if (width > 0 && gc.stringExtent(str).x >= width) {
str = getFormattedDate("MMM", cdt.getCalendarTime()); //$NON-NLS-1$
}
gc.dispose();
monthButton.setText(str);
}
public void setScrollable(boolean scrollable) {
this.scrollable = scrollable;
}
private void setSelectionFromButton(VButton button, int stateMask) {
Date date = (Date) button.getData(CDT.Key.Date.name());
if (cdt.isSingleSelection()) {
if ((stateMask & SWT.CTRL) != 0 && cdt.isSelected(date)) {
cdt.setSelection(null);
} else {
cdt.setSelection(date);
}
} else {
// if((stateMask & SWT.CTRL) != 0) {
// if(cdt.isSelected(date)) {
// cdt.deselect(date);
// } else {
// cdt.select(date);
// }
// } else if((stateMask & SWT.SHIFT) != 0 && cdt.hasSelection()) {
// cdt.select(cdt.getSelection(), date, Calendar.DATE, 1);
// } else {
cdt.setSelection(date);
// }
}
setFocus(true);
}
private void setSelectionFromFocusButton(Event event) {
int fb = getFocusDayButton();
if (fb >= 0 && fb < dayButtons.length) {
VButton button = dayButtons[fb];
int stateMask = event.stateMask;
setSelectionFromButton(button, stateMask);
boolean defaultSelection = false;
if (event.type == SWT.KeyDown && event.stateMask == 0) {
if (event.keyCode == SWT.KEYPAD_CR || event.character == SWT.CR) {
defaultSelection = true;
}
} else if (event.type == SWT.Traverse && event.stateMask == 0) {
if (event.keyCode == SWT.TRAVERSE_RETURN) {
defaultSelection = true;
}
}
cdt.fireSelectionChanged(defaultSelection);
}
}
/**
* Traverse the selection programmatically just as a user would with the
* keyboard. <dt><b>Valid Keys:</b></dt> <dd>SWT.ARROW_UP, SWT.ARROW_DOWN,
* SWT.ARROW_LEFT, SWT.ARROW_RIGHT</dd>
*
* @param keyCode
* a SWT traversal keycode
* @see #scrollCalendar(int)
*/
void traverseSelection(int keyCode) {
int focusDayButton = getFocusDayButton();
switch (keyCode) {
case SWT.ARROW_UP:
if (focusDayButton > DAYS_IN_WEEK) {
setButtonFocus(focusDayButton - DAYS_IN_WEEK);
} else {
scrollCalendar(SWT.ARROW_UP);
setButtonFocus(focusDayButton);
}
break;
case SWT.ARROW_DOWN:
if (focusDayButton < DAYS_IN_WEEK * (NUM_ROWS - 1)) {
setButtonFocus(focusDayButton + DAYS_IN_WEEK);
} else {
scrollCalendar(SWT.ARROW_DOWN);
}
break;
case SWT.ARROW_LEFT:
if (focusDayButton > 0) {
setButtonFocus(focusDayButton - 1);
} else {
scrollCalendar(SWT.ARROW_UP);
setButtonFocus(focusDayButton + (DAYS_IN_WEEK - 1));
}
break;
case SWT.ARROW_RIGHT:
if (focusDayButton < (DAYS_IN_WEEK * NUM_ROWS - 1)) {
setButtonFocus(focusDayButton + 1);
} else {
scrollCalendar(SWT.ARROW_DOWN);
setButtonFocus(focusDayButton - (DAYS_IN_WEEK - 1));
}
}
}
/**
* set / update the text and font color of the <code>dayButton</code>s.
*/
private void updateDays() {
if (dayPanel != null) {
Calendar date = cdt.getCalendarInstance();
Calendar active = cdt.getCalendarInstance();
Calendar today = cdt
.getCalendarInstance(System.currentTimeMillis());
for (int day = 0; day < dayButtons.length; day++) {
if ((dayButtons[day] != null)) {
date.setTime((Date) dayButtons[day].getData(CDT.Key.Date));
boolean isToday = (date.get(Calendar.YEAR) == today
.get(Calendar.YEAR))
&& (date.get(Calendar.DAY_OF_YEAR) == today
.get(Calendar.DAY_OF_YEAR));
boolean isActive = (date.get(Calendar.YEAR) == active
.get(Calendar.YEAR))
&& (date.get(Calendar.MONTH) == active
.get(Calendar.MONTH));
dayButtons[day].setText(getFormattedDate(
"d", date.getTime())); //$NON-NLS-1$
dayButtons[day].setData(CDT.Key.Today, isToday);
dayButtons[day].setData(CDT.Key.Active, isActive);
cdt.getPainter().update(dayButtons[day]);
}
}
int focusButton = -1;
for (int i = 0; i < dayButtons.length; i++) {
dayButtons[i].setSelection(false);
}
if (cdt.hasSelection()) {
Calendar first = cdt.getCalendarInstance((Date) dayButtons[0]
.getData(CDT.Key.Date));
first.set(Calendar.MILLISECOND, 0);
first.set(Calendar.SECOND, 0);
first.set(Calendar.MINUTE, 0);
first.set(Calendar.HOUR_OF_DAY, 0);
Calendar last = cdt
.getCalendarInstance((Date) dayButtons[dayButtons.length - 1]
.getData(CDT.Key.Date));
last.set(Calendar.MILLISECOND, 0);
last.set(Calendar.SECOND, 0);
last.set(Calendar.MINUTE, 0);
last.set(Calendar.HOUR_OF_DAY, 0);
last.add(Calendar.DATE, 1);
last.add(Calendar.MILLISECOND, -1);
Date selection = cdt.getSelection();
Calendar scal = cdt.getCalendarInstance(selection);
for (int j = 0; j < dayButtons.length; j++) {
Calendar tmpcal = cdt
.getCalendarInstance((Date) dayButtons[j]
.getData(CDT.Key.Date));
if ((scal.get(Calendar.DATE) == tmpcal.get(Calendar.DATE))
&& (scal.get(Calendar.MONTH) == tmpcal
.get(Calendar.MONTH))
&& (scal.get(Calendar.YEAR) == tmpcal
.get(Calendar.YEAR))) {
dayButtons[j].setSelection(true);
// Bug 388813:
// don't catch the focus
// focusButton = j;
break;
}
}
if (focusButton >= 0) {
dayButtons[focusButton].setFocus();
}
}
dayPanel.redraw();
}
}
/**
* set / update the text of the displayLabels. these are the Week column
* headers above the days on the Calendar part of the <code>CDateTime</code>
* .
*/
private void updateDaysOfWeek() {
if (dayPanel != null) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.set(Calendar.DAY_OF_WEEK, tmpcal.getFirstDayOfWeek());
Locale locale = cdt.getLocale();
boolean ltr = (ComponentOrientation.getOrientation(locale)
.isLeftToRight() && !locale.getLanguage().equals("zh")); //$NON-NLS-1$
BreakIterator iterator = BreakIterator.getCharacterInstance(locale);
for (int x = 0; x < dayLabels.length; x++) {
String str = getFormattedDate("E", tmpcal.getTime()); //$NON-NLS-1$
if (dayLabels[x].getData(CDT.Key.Compact, Boolean.class)) {
iterator.setText(str);
int start, end;
if (ltr) {
start = iterator.first();
end = iterator.next();
} else {
end = iterator.last();
start = iterator.previous();
}
dayLabels[x].setText(str.substring(start, end));
} else {
dayLabels[x].setText(str);
}
tmpcal.add(Calendar.DAY_OF_WEEK, 1);
}
}
}
/**
* set / update the text of the <code>footerButton</code>.
*/
private void updateFooter() {
if (footer != null) {
Locale locale = cdt.getLocale();
if (today != null) {
if (cdt.builder.hasFooter(Footer.VERBOSE_TODAY)) {
Calendar cal = cdt.getCalendarInstance(System
.currentTimeMillis());
Object[] margs = {
cal.getTime(),
Resources
.getString(
"date_ordinal_" + cal.get(Calendar.DATE), locale) //$NON-NLS-1$
};
MessageFormat formatter = new MessageFormat(
Resources.getString("today_verbose.text", locale), locale); //$NON-NLS-1$
today.setText(formatter.format(margs));
} else {
today.setText(Resources.getString("today.text", locale)); //$NON-NLS-1$
}
}
if (clear != null) {
clear.setText(Resources.getString("clear.text", locale)); //$NON-NLS-1$
}
footer.layout();
}
}
/**
* set / update the text of the header - <code>monthLabel</code>,
* <code>yearLabel</code>, and the <code>monthLabel</code> context menu.
*/
private void updateHeader() {
if (header != null) {
Calendar selected = cdt.getCalendarInstance();
if (monthButton != null) {
setMonthLabelText();
}
if (monthItems != null) {
Calendar tmpcal = cdt.getCalendarInstance();
for (int i = 0; i < 12; i++) {
tmpcal.set(Calendar.MONTH, i);
monthItems[i].setText(getFormattedDate(
"MMMM", tmpcal.getTime())); //$NON-NLS-1$
monthItems[i].setData(
"Month", new Integer(tmpcal.get(Calendar.MONTH)));//$NON-NLS-1$
if (selected.get(Calendar.MONDAY) == tmpcal
.get(Calendar.MONTH)) {
monthItems[i].setImage(Resources.getIconBullet());
} else {
monthItems[i].setImage(null);
}
}
}
if (yearButton != null) {
yearButton.setText(getFormattedDate(
"yyyy", cdt.getCalendarTime())); //$NON-NLS-1$
}
if (yearItems != null) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.add(Calendar.YEAR, -5);
for (int i = 0; i < 11; i++) {
yearItems[i].setText(getFormattedDate(
"yyyy", tmpcal.getTime())); //$NON-NLS-1$
if (selected.get(Calendar.YEAR) == tmpcal
.get(Calendar.YEAR)) {
yearItems[i].setImage(Resources.getIconBullet());
} else {
yearItems[i].setImage(null);
}
tmpcal.add(Calendar.YEAR, 1);
}
}
header.layout();
}
}
protected void updateLabels() {
updateLocale();
if (dayButtons != null) {
setDays(new Date(cdt.getCalendarTimeInMillis()), true);
updateDays();
}
updateHeader();
updateMonths();
updateYears();
if (dayLabels != null) {
updateDaysOfWeek();
}
updateFooter();
}
/**
* set / update, or calls methods to set / update, all components affected
* by the <code>locale</code>
*
* @see #updateHeader
* @see #updateDayLabels
* @see #updateDays
* @see #updateFooter
*/
private void updateLocale() {
Locale locale = cdt.getLocale();
if (monthPrev != null)
monthPrev.setToolTipText(Resources.getString(
"nav_prev_month", locale)); //$NON-NLS-1$
if (monthNext != null)
monthNext.setToolTipText(Resources.getString(
"nav_next_month", locale)); //$NON-NLS-1$
if (dateNow != null)
dateNow.setToolTipText(Resources.getString(
"nav_current_day", locale)); //$NON-NLS-1$
if (yearPrev != null)
yearPrev.setToolTipText(Resources
.getString("nav_prev_year", locale)); //$NON-NLS-1$
if (yearNext != null)
yearNext.setToolTipText(Resources
.getString("nav_next_year", locale)); //$NON-NLS-1$
if (today != null)
today.setToolTipText(Resources.getString("nav_current_day", locale)); //$NON-NLS-1$
if (todayMenuItem != null)
todayMenuItem.setText(Resources
.getString("nav_current_day", locale)); //$NON-NLS-1$
if (showSelMenuItem != null)
showSelMenuItem.setText(Resources.getString(
"show_selection", locale)); //$NON-NLS-1$
}
private void updateMonths() {
if (monthPanel != null) {
Calendar tmpcal = cdt.getCalendarInstance();
/*
* : Bug 288164 use first day of month to get February if currently selected date is higher than 29th
*/
tmpcal.set(Calendar.DAY_OF_MONTH, 1);
for (int i = 0; i < 12; i++) {
tmpcal.set(Calendar.MONTH, i);
monthButtons[i].setText(getFormattedDate(
"MMM", tmpcal.getTime())); //$NON-NLS-1$
monthButtons[i].setData(
"Month", new Integer(tmpcal.get(Calendar.MONTH)));//$NON-NLS-1$
}
}
}
void updateView() {
updateHeader();
if (dayPanel != null) {
setDays(cdt.getCalendarTime(), true);
updateDays();
}
updateMonths();
updateYears();
if (timePanel != null) {
timePanel.updateView();
}
updateFooter();
}
private void updateYears() {
if (yearPanel != null) {
Calendar tmpcal = cdt.getCalendarInstance();
tmpcal.add(Calendar.YEAR, -7);
for (int i = 0; i < yearButtons.length; i++) {
yearButtons[i].setText(getFormattedDate(
"yyyy", tmpcal.getTime())); //$NON-NLS-1$
tmpcal.add(Calendar.YEAR, 1);
}
}
}
private void setCDTSelection(Date selection) {
cdt.setSelection(selection);
cdt.fireSelectionChanged();
}
}