package org.xmind.ui.datepicker;
import static java.util.Calendar.DATE;
import static java.util.Calendar.DAY_OF_WEEK;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.SATURDAY;
import static java.util.Calendar.SUNDAY;
import static java.util.Calendar.YEAR;
import static org.eclipse.jface.resource.JFaceResources.DEFAULT_FONT;
import java.util.Calendar;
import java.util.List;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.GridData;
import org.eclipse.draw2d.GridLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Layer;
import org.eclipse.draw2d.LineBorder;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener2;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.xmind.ui.dialogs.PopupDialog;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.resources.FontUtils;
import org.xmind.ui.viewers.MButton;
import org.xmind.ui.viewers.SWTUtils;
/**
* A viewer to pick a date on the calendar.
*
* @author Frank Shaka
*/
public class DatePicker extends Viewer {
public static final String[] MONTHS = new String[] { Messages.January,
Messages.Feburary, Messages.March, Messages.April, Messages.May,
Messages.June, Messages.July, Messages.August, Messages.September,
Messages.October, Messages.November, Messages.December };
public static final String[] WEEK_SYMBOLS = new String[] { Messages.Sunday,
Messages.Monday, Messages.Tuesday, Messages.Wednesday,
Messages.Thursday, Messages.Friday, Messages.Saturday };
public static final int TIME_12 = 12;
public static final int TIME_24 = 24;
public static final int CORNER = 8;
public static final int LOAD_TIMEPICKER = 1 << 3;
private static final int FUTURE_YEARS = 7;
private static final int PASSED_YEARS = 3;
private static final String TEXT = "#000000"; //$NON-NLS-1$
private static final String WEEKEND = "#EE0000"; //$NON-NLS-1$
private static final String SEPARATOR = "#C0C0C0"; //$NON-NLS-1$
private static final String TODAY = "#ff9900"; //$NON-NLS-1$
private static final String WEEK_SYMBOL = "#808080"; //$NON-NLS-1$
private static final String ARROW_BORDER = "#808080"; //$NON-NLS-1$
private static final String ARROW_FILL = "#C0C0C0"; //$NON-NLS-1$
private static final String CANCEL = "#D80000"; //$NON-NLS-1$
private static final String TIME = "#5D5D5D"; //$NON-NLS-1$
protected static final int NORMAL_ALPHA = 0xff;
protected static final int SIBLING_MONTH_ALPHA = 0x20;
private static final int DURATION = 200;
protected static final int TOTAL_DAYS = 42;
protected class EventHandler
implements MouseListener, MouseMotionListener, Listener {
private boolean dayPressed = false;
private BaseFigure pretarget = null;
private FigureCanvas canvas;
private BaseFigure target = null;
public void attach(IFigure figure) {
figure.addMouseListener(this);
figure.addMouseMotionListener(this);
}
public void detach(IFigure figure) {
figure.removeMouseListener(this);
figure.removeMouseMotionListener(this);
}
public void install(Control control) {
control.addListener(SWT.MouseUp, this);
control.addListener(SWT.MouseWheel, this);
control.addListener(SWT.KeyDown, this);
}
public void uninstall(Control control) {
control.removeListener(SWT.MouseUp, this);
control.removeListener(SWT.MouseWheel, this);
control.removeListener(SWT.KeyDown, this);
}
public void handleEvent(Event event) {
if (event.type == SWT.MouseUp) {
dayPressed = false;
if (target != null) {
final BaseFigure eventTarget = target;
final BaseFigure eventPreTarget = pretarget;
target.setPressed(false);
target = null;
selected(eventTarget, eventPreTarget);
}
} else if (event.type == SWT.MouseWheel) {
if (event.count == 0)
return;
// wheel upwards, count > 0, month should decrease
// wheel downwards, count < 0, month should increase
rollMonth(event.count > 0 ? -1 : 1);
} else if (event.type == SWT.KeyDown) {
handleKeyPress(event.keyCode, event.stateMask);
}
}
private void handleKeyPress(int key, int mask) {
if (SWTUtils.matchKey(mask, key, 0, SWT.ARROW_UP)) {
lastMonthSelected(true);
} else if (SWTUtils.matchKey(mask, key, 0, SWT.ARROW_DOWN)) {
nextMonthSelected(true);
} else if (SWTUtils.matchKey(mask, key, 0, SWT.ARROW_LEFT)) {
lastYearSelected(true);
} else if (SWTUtils.matchKey(mask, key, 0, SWT.ARROW_RIGHT)) {
nextYearSelected(true);
}
}
public void mouseDoubleClicked(MouseEvent me) {
// do nothing
BaseFigure source = (BaseFigure) me.getSource();
if (source instanceof HourFigure
|| source instanceof MinutesFigure) {
startEditing(source);
}
}
private void startEditing(final BaseFigure source) {
canvas = getDatePicker();
final Text editor = new Text(getDatePicker(),
SWT.SINGLE | SWT.BORDER);
editor.setFont(source.getFont());
editor.setText(source.getText());
//set location of editor
Rectangle bounds = source.getBounds();
Viewport viewport = canvas.getViewport();
int x = bounds.x - viewport.getClientArea().x;
int y = bounds.y - viewport.getClientArea().y;
Point size = editor.computeSize(SWT.DEFAULT, SWT.DEFAULT);
editor.setBounds(x, y + (bounds.height - size.y) / 2, bounds.width,
size.y);
canvas.layout();
editor.selectAll();
editor.setFocus();
//focus out
final Listener mouseDownFilter = new Listener() {
public void handleEvent(Event event) {
if (event.widget != editor) {
finishEditingTime(editor, source);
}
}
};
editor.getDisplay().addFilter(SWT.MouseDown, mouseDownFilter);
editor.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
editor.getDisplay().removeFilter(SWT.MouseDown,
mouseDownFilter);
}
});
editor.addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.keyCode == SWT.CR) {
finishEditingTime(editor, source);
}
}
});
editor.addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_ESCAPE) {
e.doit = false;
cancelEditingTime(editor);
}
}
});
}
private void cancelEditingTime(Text editor) {
editor.dispose();
canvas.layout();
}
private void finishEditingTime(Text editor, BaseFigure source) {
String newValue = editor.getText().trim();
String oldValue = source.getText().trim();
if ("".equals(newValue) || null == newValue //$NON-NLS-1$
|| newValue.equals(oldValue)) {
disposeEditor(editor, source);
if (!"12".equals(newValue)) //$NON-NLS-1$
return;
}
int value = -1;
try {
value = Integer.parseInt(newValue);
if (source instanceof HourFigure)
changeHourOrMinutes(false, value, currentMinutes);
if (source instanceof MinutesFigure)
changeHourOrMinutes(false, currentHour, value);
} catch (NumberFormatException e) {
// e.printStackTrace();
}
disposeEditor(editor, source);
}
private void disposeEditor(Text editor, BaseFigure source) {
updateSelection();
source.setBorder(null);
editor.dispose();
canvas.layout();
}
public void mouseDragged(MouseEvent me) {
// do nothing
}
public void mouseEntered(MouseEvent me) {
if (target == null) {
BaseFigure source = (BaseFigure) me.getSource();
if (source instanceof DayFigure && dayPressed) {
source.setPressed(true);
source.setPreselected(false);
} else {
if (source == monthFigure || source == lastMonth
|| source == nextMonth) {
monthFigure.setPreselected(true);
lastMonth.getContent().setVisible(true);
nextMonth.getContent().setVisible(true);
} else if (source == yearFigure || source == lastYear
|| source == nextYear) {
yearFigure.setPreselected(true);
lastYear.getContent().setVisible(true);
nextYear.getContent().setVisible(true);
} else if (source == todayFigure) {
todayFigure.setFont(
FontUtils.getRelativeHeight(DEFAULT_FONT, 0));
todayFigure.setForegroundColor(
ColorUtils.getColor(CANCEL));
return;
}
source.setPreselected(true);
}
}
}
public void mouseExited(MouseEvent me) {
if (target == null) {
BaseFigure source = (BaseFigure) me.getSource();
if (source instanceof DayFigure) {
source.setPreselected(false);
if (dayPressed) {
source.setPressed(false);
}
} else {
if (source == monthFigure || source == lastMonth
|| source == nextMonth) {
monthFigure.setPreselected(false);
lastMonth.getContent().setVisible(false);
nextMonth.getContent().setVisible(false);
} else if (source == yearFigure || source == lastYear
|| source == nextYear) {
yearFigure.setPreselected(false);
lastYear.getContent().setVisible(false);
nextYear.getContent().setVisible(false);
} else if (source == todayFigure) {
todayFigure.setFont(
FontUtils.getRelativeHeight(DEFAULT_FONT, 0));
todayFigure
.setForegroundColor(ColorUtils.getColor(TEXT));
return;
}
source.setPreselected(false);
}
}
}
public void mouseHover(MouseEvent me) {
// do nothing
}
public void mouseMoved(MouseEvent me) {
// do nothing
}
public void mousePressed(MouseEvent me) {
BaseFigure source = (BaseFigure) me.getSource();
if (source != todayFigure) {
source.setPressed(true);
source.setPreselected(false);
}
if (source instanceof DayFigure) {
dayPressed = true;
} else {
target = source;
}
if (source instanceof HourFigure
|| source instanceof MinutesFigure) {
startEditing(source);
}
}
public void mouseReleased(MouseEvent me) {
BaseFigure source = (BaseFigure) me.getSource();
source.setPressed(false);
if (source instanceof DayFigure) {
if (dayPressed) {
daySelected((DayFigure) me.getSource());
}
source.setPreselected(true);
} else if (source instanceof HourFigure
|| source instanceof MinutesFigure) {
pretarget = source;
} else {
if (!source.isSelected()) {
if (source != todayFigure)
source.setPreselected(true);
}
}
}
}
private class DropdownDatePicker extends PopupDialog {
public DropdownDatePicker(Shell parent) {
super(parent, SWT.NO_TRIM, true, false, false, false, false, null,
null);
}
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
createDatePicker(composite);
datePicker.setLayoutData(new org.eclipse.swt.layout.GridData(
SWT.FILL, SWT.FILL, true, true));
initDatePicker();
update();
return composite;
}
@Override
public int open() {
isPopupEditing = true;
return super.open();
}
@Override
public boolean close() {
isPopupEditing = false;
boolean closed = super.close();
if (closed) {
datePicker = null;
}
return closed;
}
@Override
protected Point getInitialLocation(Point initialSize) {
Control c = DatePicker.this.getControl();
org.eclipse.swt.graphics.Rectangle r = c.getBounds();
return c.toDisplay(0, r.height + 1);
}
}
private class MonthAction extends Action {
private int month;
public MonthAction(int month) {
super(MONTHS[month]);
this.month = month;
}
public void run() {
monthSelected(month);
}
}
private class YearAction extends Action {
private int year;
public void setYear(int year) {
this.year = year;
setText("" + year); //$NON-NLS-1$
}
public int getYear() {
return year;
}
public void run() {
yearSelected(year);
}
}
private class AnimationAdvisor implements IAnimationAdvisor {
private int monthsToRoll = 0;
private int yearsToRoll = 0;
private int duration = -1;
private int oldYear;
private int oldMonth;
private int newYear;
private int newMonth;
public void addMonthsToRoll(int count) {
monthsToRoll += count;
duration = -1;
}
public void addYearsToRoll(int count) {
yearsToRoll += count;
duration = -1;
}
public int getDuration() {
if (duration < 0) {
int steps = Math.abs(monthsToRoll) + Math.abs(yearsToRoll);
duration = steps == 0 ? 0 : DURATION / steps;
}
return duration;
}
public IFigure getLayer() {
return DatePicker.this.dateLayer;
}
public int getMonthsToRoll() {
return monthsToRoll;
}
public int getNewMonth() {
return newMonth;
}
public int getNewYear() {
return newYear;
}
public int getOldMonth() {
return oldMonth;
}
public int getOldYear() {
return oldYear;
}
public IFigure getPanel() {
return DatePicker.this.datePanel;
}
public int getYearsToRoll() {
return yearsToRoll;
}
public void initNewDay(DayFigure figure) {
updateDayFigure(figure, oldYear, oldMonth);
}
public void initOldDay(DayFigure figure) {
figure.setPreselected(false);
figure.setSelected(isSameDay(figure.getDate(), getSelectedDate()));
eventHandler.detach(figure);
}
public boolean isDone() {
return monthsToRoll == 0 && yearsToRoll == 0;
}
public void setEndMonth(int newYear, int newMonth) {
this.newYear = newYear;
this.newMonth = newMonth;
}
public void setStartMonth(int oldYear, int oldMonth) {
this.oldYear = oldYear;
this.oldMonth = oldMonth;
}
public void updateNewDay(DayFigure figure) {
figure.setPreselected(false);
figure.setSelected(isSameDay(figure.getDate(), getSelectedDate()));
eventHandler.attach(figure);
updateDayFigure(figure, newYear, newMonth);
}
}
private int style; //mark the style of datepicker
private int type = TIME_12; // TIME_12 or TIME_24 mark the type of time 12 Hour or 24 Hour.
private Control control;
private FigureCanvas datePicker;
private BaseFigure timePicker;
private HourFigure hourFigure;
private MinutesFigure minutesFigure;
// private BaseFigure okButton;
//
// private BaseFigure cancelButton;
// private BaseFigure figure;
private BaseFigure timeLabel;
private ArrowFigure beforeTime;
private ArrowFigure afterTime;
private MButton placeholder;
private ILabelProvider dateLabelProvider;
private DropdownDatePicker dropdownDatePicker;
private Calendar today;
private int currentMonth;
private int currentYear;
private int currentHour;
private int currentMinutes;
private Calendar selection;
private IFigure dateLayer;
private IFigure datePanel;
private MonthFigure monthFigure;
private YearFigure yearFigure;
private BaseFigure todayFigure;
private BaseFigure cancelFigure;
private EventHandler eventHandler;
private MenuManager monthMenu;
private MonthAction[] monthActions;
private MenuManager yearMenu;
private YearAction[] yearActions;
private ArrowFigure lastYear;
private ArrowFigure nextYear;
private ArrowFigure lastMonth;
private ArrowFigure nextMonth;
private boolean firingSelectionChange = false;
private boolean animating = false;
private IAnimationAdvisor animationAdvisor = new AnimationAdvisor();
private boolean isPopupEditing = false;
/**
* Constructs a new instance of this class given its parent and a style
* value describing its behavior and appearance.
*
* @param parent
* a composite control which will be the parent of the new
* instance (cannot be null)
* @param style
* the style of control to construct
* @see SWT#SIMPLE
* @see SWT#DROP_DOWN
* @see SWT#CANCEL
*/
public DatePicker(Composite parent, int style) {
this(parent, style, Calendar.getInstance());
}
public DatePicker(Composite parent, int style, Calendar today) {
this.today = today;
this.currentMonth = today.get(MONTH);
this.currentYear = today.get(YEAR);
this.currentHour = today.get(HOUR_OF_DAY);
this.currentMinutes = today.get(MINUTE);
this.style = style;
if ((style & SWT.DROP_DOWN) != 0) {
createPlaceholder(parent);
this.control = placeholder.getControl();
initPlaceholder();
} else {
createDatePicker(parent);
this.control = datePicker;
initDatePicker();
}
update();
}
private void createPlaceholder(Composite parent) {
this.placeholder = new MButton(parent, MButton.NORMAL);
}
private void createDatePicker(Composite parent) {
this.datePicker = new FigureCanvas(parent);
}
public void setLabelProvider(ILabelProvider labelProvider) {
this.dateLabelProvider = labelProvider;
update();
}
public ILabelProvider getLabelProvider() {
if (this.dateLabelProvider == null) {
this.dateLabelProvider = new DateLabelProvider();
}
return this.dateLabelProvider;
}
public Control getControl() {
return control;
}
public FigureCanvas getDatePicker() {
return datePicker;
}
public boolean isPopupEditing() {
return isPopupEditing;
}
public void setBackground(Color color) {
if (control != null && !control.isDisposed()) {
control.setBackground(color);
}
}
public void setEnabled(boolean enabled) {
if (placeholder != null) {
placeholder.setEnabled(enabled);
}
}
public MButton getPlaceholder() {
return placeholder;
}
public ISelection getSelection() {
return new DateSelection(selection);
}
@Override
public void setSelection(ISelection selection) {
setSelection(selection, true);
}
@Override
public void setSelection(ISelection selection, boolean reveal) {
if (selection instanceof DateSelection) {
setDateSelection(((DateSelection) selection).getDate(), reveal);
} else if (selection instanceof IStructuredSelection) {
Object sel = ((IStructuredSelection) selection).getFirstElement();
if (sel instanceof Calendar) {
setDateSelection((Calendar) sel, reveal);
}
}
}
public void setDateSelection(Calendar date, boolean reveal) {
changeDate(date);
if (reveal && date != null) {
changeCalendar(date.get(YEAR), date.get(MONTH),
date.get(HOUR_OF_DAY), date.get(MINUTE));
}
update();
}
private void initPlaceholder() {
placeholder.addOpenListener(new IOpenListener() {
public void open(OpenEvent event) {
if (dropdownDatePicker == null
|| dropdownDatePicker.getShell() == null
|| dropdownDatePicker.getShell().isDisposed()
|| !dropdownDatePicker.isClosing())
showDropdown();
}
});
}
/**
* Shows the drop-down date picker ,and compute the size by the control.
*/
private void showDropdown() {
placeholder.setForceFocus(true);
createDropdownDatePicker();
dropdownDatePicker.open();
Shell shell = dropdownDatePicker.getShell();
int x = placeholder.getControl().getBounds().width;
x = x < 230 ? 230 : x; //set the datepicker min width is 250px
x = x > 250 ? 250 : x; //set the datepicker max width is 280px
shell.setSize(x, x + 30);
if (shell != null && !shell.isDisposed()) {
shell.addListener(SWT.Dispose, new Listener() {
public void handleEvent(Event event) {
if (placeholder != null
&& !placeholder.getControl().isDisposed()) {
placeholder.setForceFocus(false);
updateSelection();
closeDatePicker();
}
}
});
} else {
placeholder.setForceFocus(false);
}
}
private void closeDatePicker() {
if (firingSelectionChange)
return;
firingSelectionChange = true;
if (dropdownDatePicker != null) {
control.getDisplay().asyncExec(new Runnable() {
public void run() {
dropdownDatePicker.close();
}
});
}
fireSelectionChanged(
new SelectionChangedEvent(DatePicker.this, getSelection()));
firingSelectionChange = false;
}
/**
* Shows the drop-down menu if this date picker is created with
* <code>SWT.DROP_DOWN</code> style bit.
*/
public void open() {
showDropdown();
}
public void close() {
if (dropdownDatePicker != null) {
control.getDisplay().asyncExec(new Runnable() {
public void run() {
dropdownDatePicker.close();
}
});
}
}
private void createDropdownDatePicker() {
if (dropdownDatePicker != null)
return;
dropdownDatePicker = new DropdownDatePicker(control.getShell());
}
private void initDatePicker() {
datePicker.setScrollBarVisibility(FigureCanvas.NEVER);
// if (Util.isWindows()) {
//datePicker.setBackground(datePicker.getParent().getBackground());
// } else {
// datePicker.getLightweightSystem().getRootFigure().setOpaque(false);
// }
eventHandler = new EventHandler();
eventHandler.install(datePicker);
datePicker.addListener(SWT.Dispose, new Listener() {
public void handleEvent(Event event) {
eventHandler.uninstall(datePicker);
}
});
Viewport viewport = new Viewport(true);
viewport.setContentsTracksHeight(true);
viewport.setContentsTracksWidth(true);
datePicker.setViewport(viewport);
IFigure container = new Layer();
datePicker.setContents(container);
GridLayout containerLayout = new GridLayout(1, true);
containerLayout.horizontalSpacing = 3;
containerLayout.verticalSpacing = 3;
containerLayout.marginHeight = 3;
containerLayout.marginWidth = 3;
container.setLayoutManager(containerLayout);
createTopPanel(container);
createSeparator(container);
createWeekPanel(container);
createDaysPanel(container);
createSeparator(container);
createBottomPanel(container);
// createSeparator(container);
// createOkAndCancel(container);
}
private void createTopPanel(IFigure parent) {
IFigure panel = new Layer();
GridData panelConstraint = new GridData(SWT.FILL, SWT.FILL, true,
false);
parent.add(panel, panelConstraint);
GridLayout panelLayout = new GridLayout(12, true);
panelLayout.horizontalSpacing = 0;
panelLayout.verticalSpacing = 0;
panelLayout.marginHeight = 0;
panelLayout.marginWidth = 0;
panel.setLayoutManager(panelLayout);
lastMonth = createArrowFigure(panel, ArrowFigure.UP);
monthFigure = createMonthFigure(panel);
nextMonth = createArrowFigure(panel, ArrowFigure.DOWN);
lastYear = createArrowFigure(panel, ArrowFigure.LEFT);
yearFigure = createYearFigure(panel);
nextYear = createArrowFigure(panel, ArrowFigure.RIGHT);
}
private MonthFigure createMonthFigure(IFigure parent) {
MonthFigure figure = new MonthFigure();
figure.setTextCandidates(MONTHS);
GridData constraint = new GridData(SWT.FILL, SWT.FILL, true, true);
constraint.horizontalSpan = 5;
parent.add(figure, constraint);
eventHandler.attach(figure);
return figure;
}
private YearFigure createYearFigure(IFigure parent) {
YearFigure figure = new YearFigure();
figure.setTextCandidates(new String[] { "0000" }); //$NON-NLS-1$
GridData constraint = new GridData(SWT.FILL, SWT.FILL, true, true);
constraint.horizontalSpan = 3;
parent.add(figure, constraint);
eventHandler.attach(figure);
return figure;
}
@SuppressWarnings("deprecation")
private ArrowFigure createArrowFigure(IFigure parent, int orientation) {
ArrowFigure arrow = new ArrowFigure();
arrow.setOrientation(orientation);
arrow.setForegroundColor(ColorUtils.getColor(ARROW_BORDER));
arrow.setBackgroundColor(ColorUtils.getColor(ARROW_FILL));
arrow.getContent().setVisible(false);
GridData constraint = new GridData(SWT.FILL, SWT.FILL, true, true);
parent.add(arrow, constraint);
eventHandler.attach(arrow);
return arrow;
}
@SuppressWarnings("deprecation")
private void createSeparator(IFigure parent) {
HorizontalLine line = new HorizontalLine();
line.setMargin(3);
line.setForegroundColor(ColorUtils.getColor(SEPARATOR));
GridData constraint = new GridData(SWT.FILL, SWT.FILL, true, false);
constraint.heightHint = 3;
parent.add(line, constraint);
}
@SuppressWarnings("deprecation")
private void createWeekPanel(IFigure parent) {
IFigure panel = new Layer();
GridData panelConstraint = new GridData(SWT.FILL, SWT.FILL, true,
false);
parent.add(panel, panelConstraint);
GridLayout panelLayout = new GridLayout(7, true);
panelLayout.horizontalSpacing = 0;
panelLayout.verticalSpacing = 0;
panelLayout.marginHeight = 0;
panelLayout.marginWidth = 0;
panel.setLayoutManager(panelLayout);
@SuppressWarnings("deprecation")
Font symbolFont = FontUtils.getRelativeHeight(DEFAULT_FONT, -2);
for (int i = 0; i < 7; i++) {
TextLayer symbol = new TextLayer();
symbol.setFont(symbolFont);
symbol.setText(WEEK_SYMBOLS[i]);
if (i == 0 || i == 6) {
symbol.setForegroundColor(ColorUtils.getColor(WEEKEND));
} else {
symbol.setForegroundColor(ColorUtils.getColor(WEEK_SYMBOL));
}
GridData symbolConstraint = new GridData(SWT.FILL, SWT.FILL, true,
true);
panel.add(symbol, symbolConstraint);
}
}
private void createDaysPanel(IFigure parent) {
dateLayer = new Layer();
GridData layerConstraint = new GridData(SWT.FILL, SWT.FILL, true, true);
parent.add(dateLayer, layerConstraint);
dateLayer.setLayoutManager(new ConstraintStackLayout());
datePanel = new Layer();
dateLayer.add(datePanel, null);
datePanel.setLayoutManager(new DatePanelLayout());
for (int i = 0; i < TOTAL_DAYS; i++) {
DayFigure dayFigure = new DayFigure();
eventHandler.attach(dayFigure);
datePanel.add(dayFigure);
}
}
private void createBottomPanel(IFigure parent) {
boolean hasCancel = (style & SWT.CANCEL) != 0;
boolean hasTimePicker = (style & LOAD_TIMEPICKER) != 0;
IFigure panel = new Layer();
GridData panelConstraint = new GridData(SWT.FILL, SWT.FILL, true,
false);
parent.add(panel, panelConstraint);
int cols = 0;
cols = hasCancel ? 2 : 1;
cols = hasTimePicker ? cols + 2 : cols;
GridLayout panelLayout = new GridLayout(cols, false);
panelLayout.horizontalSpacing = 0;
panelLayout.verticalSpacing = 0;
panelLayout.marginHeight = 10;
panelLayout.marginWidth = 5;
panel.setLayoutManager(panelLayout);
todayFigure = createTodayFigure(panel);
if (hasTimePicker) {
timePicker = createTimeFigure(panel);
// createUpAndDown(panel);
timeLabel = createLabelOfTime(panel);
}
if (hasCancel) {
cancelFigure = createCancelFigure(panel);
}
}
@SuppressWarnings("deprecation")
private BaseFigure createTodayFigure(IFigure parent) {
BaseFigure figure = new BaseFigure();
figure.setFont(FontUtils.getRelativeHeight(DEFAULT_FONT, 0));
figure.setForegroundColor(ColorUtils.getColor(TEXT));
GridData constraint = new GridData(SWT.CENTER, SWT.CENTER, true, true);
parent.add(figure, constraint);
eventHandler.attach(figure);
return figure;
}
@SuppressWarnings("deprecation")
private BaseFigure createCancelFigure(IFigure parent) {
BaseFigure figure = new BaseFigure();
figure.setText(" X "); //$NON-NLS-1$
figure.setFont(FontUtils.getRelativeHeight(DEFAULT_FONT, -2));
figure.setForegroundColor(ColorUtils.getColor(CANCEL));
GridData constraint = new GridData(SWT.FILL, SWT.FILL, false, true);
parent.add(figure, constraint);
eventHandler.attach(figure);
return figure;
}
@SuppressWarnings("deprecation")
private BaseFigure createTimeFigure(IFigure parent) {
BaseFigure figure = new BaseFigure();
figure.setFont(FontUtils.getRelativeHeight(DEFAULT_FONT, -1));
figure.setForegroundColor(ColorConstants.white);
figure.setBackgroundColor(ColorConstants.white);
figure.setOpaque(true);
GridData constraint = new GridData(SWT.FILL, SWT.FILL, false, false);
figure.setLayoutManager(new XYLayout());
parent.add(figure, constraint);
IFigure panel = new Layer();
figure.add(panel, new Rectangle(0, 2, 60, 20));
panel.setBorder(new LineBorder(ColorConstants.lightGray, 1));
panel.setForegroundColor(ColorConstants.white);
XYLayout layout = new XYLayout();
panel.setLayoutManager(layout);
hourFigure = createHourFigure(panel);
BaseFigure point = createPointFigure(panel);
minutesFigure = createMinutesFigure(panel);
panel.add(hourFigure, new Rectangle(0, 0, 25, 18));
panel.add(point, new Rectangle(26, 0, 3, 18));
panel.add(minutesFigure, new Rectangle(31, 0, 25, 18));
return figure;
}
@SuppressWarnings("deprecation")
private BaseFigure createPointFigure(IFigure parent) {
BaseFigure figure = new BaseFigure();
figure.setSize(3, 18);
figure.setText(" : "); //$NON-NLS-1$
figure.setForegroundColor(ColorUtils.getColor(TIME));
parent.add(figure);
return figure;
}
// private IFigure createHourAndMinutesPanel(IFigure parent) {
// IFigure panel = new Layer();
// panel.setSize(32, 16);
// GridData constraint = new GridData(SWT.FILL, SWT.FILL, true, false);
// constraint.horizontalSpan = 3;
// parent.add(panel, constraint);
// ToolbarLayout layout = new ToolbarLayout();
// layout.setSpacing(0);
// panel.setLayoutManager(layout);
// return panel;
// }
@SuppressWarnings("deprecation")
private HourFigure createHourFigure(IFigure parent) {
HourFigure figure = new HourFigure();
figure.setHour(currentHour, type);
figure.setTextCandidates(new String[] { " 00 " }); //$NON-NLS-1$
figure.setForegroundColor(ColorUtils.getColor(TIME));
eventHandler.attach(figure);
return figure;
}
@SuppressWarnings("deprecation")
private MinutesFigure createMinutesFigure(IFigure parent) {
MinutesFigure figure = new MinutesFigure();
figure.setMinutes(currentMinutes);
figure.setTextCandidates(new String[] { " 00 " }); //$NON-NLS-1$
figure.setForegroundColor(ColorUtils.getColor(TIME));
eventHandler.attach(figure);
return figure;
}
@SuppressWarnings("deprecation")
private BaseFigure createLabelOfTime(IFigure parent) {
BaseFigure figure = new BaseFigure();
figure.setText(getTimeLabel());
figure.setFont(FontUtils.getRelativeHeight(DEFAULT_FONT, -1));
figure.setForegroundColor(ColorUtils.getColor(TEXT));
figure.setCursor(Cursors.ARROW);
GridData constraint = new GridData(SWT.FILL, SWT.FILL, false, true);
parent.add(figure, constraint);
return figure;
}
// private void createOkAndCancel(IFigure parent) {
// IFigure panel = new Layer();
// GridData panelConstraint = new GridData(SWT.CENTER, SWT.FILL, true,
// false);
// parent.add(panel, panelConstraint);
// GridLayout panelLayout = new GridLayout(4, true);
// panelLayout.horizontalSpacing = 10;
// panelLayout.verticalSpacing = 0;
// panelLayout.marginHeight = 5;
// panelLayout.marginWidth = 5;
// panelLayout.verticalSpacing = 5;
// panel.setLayoutManager(panelLayout);
// cancelButton = createCancel(panel);
// createLabel(panel);
// createLabel(panel);
// okButton = createOk(panel);
// }
// private void createLabel(IFigure parent) {
// BaseFigure figure = new BaseFigure();
// GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
// parent.add(figure, data);
// }
//
// private BaseFigure createOk(IFigure parent) {
// BaseFigure figure = new BaseFigure();
// figure.setText("OK");
// figure.setOpaque(true);
// figure.setBackgroundColor(ColorConstants.white);
// figure.setBorder(new LineBorder(ColorConstants.lightGray));
// figure.setFont(FontUtils.getRelativeHeight(DEFAULT_FONT, -2));
// parent.add(figure, new GridData(SWT.FILL, SWT.FILL, false, false));
// eventHandler.attach(figure);
// return figure;
// }
// private BaseFigure createCancel(IFigure parent) {
// BaseFigure figure = new BaseFigure();
// figure.setText("CANCEL");
// figure.setBackgroundColor(ColorConstants.white);
// figure.setOpaque(true);
// figure.setFont(FontUtils.getRelativeHeight(DEFAULT_FONT, -2));
// figure.setBorder(new LineBorder(ColorConstants.lightGray));
// parent.add(figure, new GridData(SWT.FILL, SWT.FILL, false, false));
// eventHandler.attach(figure);
// return figure;
// }
private String getTimeLabel() {
if (currentHour >= 0 && currentHour < 12)
return Messages.DatePicker_Time_AM_text;
else if (currentHour >= 12 && currentHour < 24)
return Messages.DatePicker_Time_PM_text;
return ""; //$NON-NLS-1$
}
private Calendar getSelectedDate() {
return selection;
}
private static boolean isSameDay(Calendar date1, Calendar date2) {
if (date1 == null)
return date2 == null;
if (date2 == null)
return false;
return date1.get(DATE) == date2.get(DATE)
&& date1.get(MONTH) == date2.get(MONTH)
&& date1.get(YEAR) == date2.get(YEAR);
}
protected void changeCalendar(int newYear, int newMonth, int newHour,
int newMinutes) {
changeCalendar(newYear, newMonth, newHour, newMinutes, false);
}
//change the ui of canlendar
protected void changeCalendar(int newYear, int newMonth, int hours,
int minutes, boolean smooth) {
boolean calendarChanged = newMonth != currentMonth
|| newYear != currentYear || currentHour != hours
|| currentMinutes != minutes;
if (!calendarChanged)
return;
if (smooth) {
if (datePicker != null) {
int months = (newYear - currentYear) * 12 + newMonth
- currentMonth;
animationAdvisor.addYearsToRoll(months / 12);
animationAdvisor.addMonthsToRoll(months % 12);
performRollCalendarAnimation(currentYear, currentMonth);
}
currentYear = newYear;
currentMonth = newMonth;
currentHour = hours;
currentMinutes = minutes;
} else {
currentYear = newYear;
currentMonth = newMonth;
currentHour = hours;
currentMinutes = minutes;
if (datePicker != null) {
updateCalendar();
}
updateSelection();
}
}
private void updateCalendar() {
today = Calendar.getInstance();
updateDayFigures(datePanel.getChildren(), currentYear, currentMonth);
monthFigure.setMonth(currentMonth);
yearFigure.setYear(currentYear);
hourFigure.setHour(currentHour, type);
minutesFigure.setMinutes(currentMinutes);
// todayFigure.setText(NLS.bind(Messages.TodayPattern,
// String.format("%1$tb %1$te, %1$tY", today))); //$NON-NLS-1$
todayFigure.setText(Messages.TodayPattern);
}
private void updateDayFigures(List dayFigures, int year, int month) {
Calendar date = getCalendarStart(today, year, month);
for (int i = 0; i < dayFigures.size(); i++) {
DayFigure dayFigure = (DayFigure) dayFigures.get(i);
date = (Calendar) date.clone();
if (i > 0)
date.add(DATE, 1);
dayFigure.setDate(date);
updateDayFigure(dayFigure, year, month);
}
}
@SuppressWarnings("deprecation")
void updateDayFigure(DayFigure figure, int year, int month) {
figure.setFont(FontUtils.getBold(DEFAULT_FONT));
Calendar date = figure.getDate();
if (isSameDay(date, today)) {
figure.setForegroundColor(ColorUtils.getColor(TODAY));
} else if (isWeekend(date)) {
figure.setForegroundColor(ColorUtils.getColor(WEEKEND));
} else {
figure.setForegroundColor(ColorUtils.getColor(TEXT));
}
if (date.get(MONTH) == month && date.get(YEAR) == year) {
figure.setTextAlpha(NORMAL_ALPHA);
} else {
figure.setTextAlpha(SIBLING_MONTH_ALPHA);
}
}
private void updateSelection() {
if (datePicker != null) {
for (Object figure : datePanel.getChildren()) {
DayFigure dayFigure = (DayFigure) figure;
dayFigure.setSelected(
isSameDay(dayFigure.getDate(), getSelectedDate()));
}
}
// if (null != hourFigure && null != selection)
// selection.set(HOUR_OF_DAY, hourFigure.getHour());
// if (null != minutesFigure && null != selection)
// selection.set(MINUTE, minutesFigure.getMinutes());
if (placeholder != null) {
String text = getLabelProvider().getText(selection);
placeholder.setText(text);
}
}
protected void update() {
if (datePicker != null) {
updateCalendar();
}
updateSelection();
}
private void performRollCalendarAnimation(int oldYear, int oldMonth) {
if (animating)
return;
animating = true;
final int newYear, newMonth;
final CalendarAnimation animation;
if (animationAdvisor.getYearsToRoll() != 0) {
if (animationAdvisor.getYearsToRoll() < 0) {
newYear = oldYear - 1;
newMonth = oldMonth;
animation = new LastYearAnimation(animationAdvisor);
} else {
newYear = oldYear + 1;
newMonth = oldMonth;
animation = new NextYearAnimation(animationAdvisor);
}
} else if (animationAdvisor.getMonthsToRoll() != 0) {
if (animationAdvisor.getMonthsToRoll() < 0) {
newYear = oldMonth <= 0 ? oldYear - 1 : oldYear;
newMonth = oldMonth <= 0 ? 11 : oldMonth - 1;
animation = new LastMonthAnimation(animationAdvisor);
} else {
newYear = oldMonth >= 11 ? oldYear + 1 : oldYear;
newMonth = oldMonth >= 11 ? 0 : oldMonth + 1;
animation = new NextMonthAnimation(animationAdvisor);
}
} else {
newYear = oldYear;
newMonth = oldMonth;
animation = null;
}
monthFigure.setMonth(newMonth);
yearFigure.setYear(newYear);
if (animation != null) {
animationAdvisor.setStartMonth(oldYear, oldMonth);
animationAdvisor.setEndMonth(newYear, newMonth);
animation.callback(new Runnable() {
public void run() {
datePanel = animation.getNewPanel();
if (animationAdvisor.isDone()) {
animating = false;
} else {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
animating = false;
performRollCalendarAnimation(newYear, newMonth);
}
});
}
}
}).start();
}
}
static int calc(int start, int end, int current, int total) {
return start + (end - start) * current / total;
}
protected void selected(final BaseFigure target,
final BaseFigure pretarget) {
if (target instanceof MonthFigure) {
target.setSelected(true);
showMonthPopup();
} else if (target instanceof YearFigure) {
target.setSelected(true);
showYearPopup();
} else if (target == todayFigure) {
todaySelected();
} else if (target == lastMonth) {
lastMonthSelected(true);
} else if (target == nextMonth) {
nextMonthSelected(true);
} else if (target == lastYear) {
lastYearSelected(true);
} else if (target == nextYear) {
nextYearSelected(true);
} else if (target == cancelFigure) {
cancelSelected();
} else if (target == beforeTime) {
// beforeTimeSelected(true, pretarget);
} else if (target == afterTime) {
// afterTimeSelected(true, pretarget);
} else if (target instanceof HourFigure) {
if (null != minutesFigure)
minutesFigure.setSelected(false);
hourSelected((HourFigure) target);
} else if (target instanceof MinutesFigure) {
if (null != hourFigure)
hourFigure.setSelected(false);
minuteSelected((MinutesFigure) target);
}
}
protected void showMonthPopup() {
createMonthMenu();
for (int month = 0; month < monthActions.length; month++) {
MonthAction action = monthActions[month];
action.setChecked(month == currentMonth);
}
Rectangle b = monthFigure.getBounds();
Point loc = control.toDisplay(b.x, b.y + b.height);
final Menu menu = monthMenu.createContextMenu(control);
menu.setLocation(loc.x + 10, loc.y + 1);
menu.setVisible(true);
}
protected void createMonthMenu() {
if (monthMenu != null)
return;
monthMenu = new MenuManager();
monthMenu.addMenuListener(new IMenuListener2() {
public void menuAboutToShow(IMenuManager manager) {
// do nothing
}
public void menuAboutToHide(IMenuManager manager) {
monthFigure.setSelected(false);
}
});
monthActions = new MonthAction[12];
for (int month = 0; month < 12; month++) {
MonthAction action = new MonthAction(month);
monthMenu.add(action);
monthActions[month] = action;
}
}
protected void showYearPopup() {
createYearMenu();
int start = currentYear - PASSED_YEARS;
for (int year = 0; year < yearActions.length; year++) {
YearAction action = yearActions[year];
action.setYear(start + year);
action.setChecked(action.getYear() == currentYear);
}
Rectangle b = yearFigure.getBounds();
Point loc = control.toDisplay(b.x, b.y + b.height);
Menu menu = yearMenu.createContextMenu(control);
menu.setLocation(loc.x, loc.y + 1);
menu.setVisible(true);
}
protected void createYearMenu() {
if (yearMenu != null)
return;
yearMenu = new MenuManager();
yearMenu.addMenuListener(new IMenuListener2() {
public void menuAboutToShow(IMenuManager manager) {
// do nothing
}
public void menuAboutToHide(IMenuManager manager) {
yearFigure.setSelected(false);
}
});
yearActions = new YearAction[FUTURE_YEARS + PASSED_YEARS + 1];
for (int year = 0; year < yearActions.length; year++) {
YearAction action = new YearAction();
yearMenu.add(action);
yearActions[year] = action;
}
}
protected void monthSelected(int month) {
changeCalendar(currentYear, month, currentHour, currentMinutes);
}
protected void yearSelected(int year) {
changeCalendar(year, currentMonth, currentHour, currentMinutes);
}
protected void daySelected(DayFigure day) {
Calendar date = day.getDate();
if (date != null && date.get(MONTH) != currentMonth) {
changeCalendar(date.get(YEAR), date.get(MONTH),
date.get(HOUR_OF_DAY), date.get(MINUTE), true);
}
if (null != date && date.get(HOUR_OF_DAY) != currentHour) {
changeHourOrMinutes(true, date.get(HOUR_OF_DAY), date.get(MINUTE));
}
selection = date;
changeDate(date);
}
protected void hourSelected(HourFigure hour) {
hour.setSelected(true);
}
protected void minuteSelected(MinutesFigure minute) {
minute.setSelected(true);
}
protected void todaySelected() {
changeDate(today);
changeCalendar(today.get(YEAR), today.get(MONTH),
today.get(HOUR_OF_DAY), today.get(MINUTE));
}
protected void lastMonthSelected(boolean smooth) {
if (currentMonth <= 0) {
changeCalendar(currentYear - 1, 11, currentHour, currentMinutes,
smooth);
} else {
changeCalendar(currentYear, currentMonth - 1, currentHour,
currentMinutes, smooth);
}
}
protected void nextMonthSelected(boolean smooth) {
if (currentMonth >= 11) {
changeCalendar(currentYear + 1, 0, currentHour, currentMinutes,
smooth);
} else {
changeCalendar(currentYear, currentMonth + 1, currentHour,
currentMinutes, smooth);
}
}
protected void lastYearSelected(boolean smooth) {
changeCalendar(currentYear - 1, currentMonth, currentHour,
currentMinutes, smooth);
}
protected void nextYearSelected(boolean smooth) {
changeCalendar(currentYear + 1, currentMonth, currentHour,
currentMinutes, smooth);
}
protected void cancelSelected() {
changeDate(null);
}
// protected void beforeTimeSelected(boolean smooth, BaseFigure target) {
// if (target instanceof HourFigure) {
// changeHourOrMinutes(smooth, currentHour - 1, currentMinutes);
// } else if (target instanceof MinutesFigure)
// changeHourOrMinutes(smooth, currentHour, currentMinutes - 1);
// }
//
// protected void afterTimeSelected(boolean smooth, BaseFigure target) {
// if (target instanceof HourFigure)
// changeHourOrMinutes(smooth, currentHour + 1, currentMinutes);
// else if (target instanceof MinutesFigure)
// changeHourOrMinutes(smooth, currentHour, currentMinutes + 1);
// }
protected void changeHourOrMinutes(boolean smooth, int newHour,
int newMinutes) {
freshTimePicker(newHour, newMinutes);
if (selection != null) {
selection.set(HOUR_OF_DAY, newHour);
selection.set(MINUTE, newMinutes);
changeDate(selection);
}
update();
}
private void freshTimePicker(int newHour, int newMinutes) {
boolean hourChanged = newHour != currentHour;
boolean minuteChanged = newMinutes != currentMinutes;
if (!hourChanged && !minuteChanged)
return;
newHour = resetHour(newHour);
newMinutes = resetMinutes(newMinutes);
if (null != timePicker) {
if (null != hourFigure && hourChanged) {
if (!validateHour(newHour))
return;
if (newHour >= 12)
timeLabel.setText(Messages.DatePicker_Time_AM_text);
else if (newHour < 12)
timeLabel.setText(Messages.DatePicker_Time_PM_text);
currentHour = newHour;
hourFigure.setHour(newHour, type); //default type = 12 hours every day.
}
if (null != minutesFigure && minuteChanged) {
if (!validateMinutes(newMinutes))
return;
currentMinutes = newMinutes;
minutesFigure.setMinutes(newMinutes);
}
}
}
private int resetHour(int hour) {
if (hour > 23) {
return 0;
}
if (hour < 0 && type == TIME_24) {
hour = 23;
} else if (hour < 0 && type == TIME_12) {
hour = 11;
}
return hour;
}
private int resetMinutes(int minutes) {
if (minutes > 59) {
minutes = 0;
} else if (minutes < 0) {
minutes = 59;
}
return minutes;
}
private boolean validateHour(int hour) {
if (hour >= 0 && hour <= 23)
return true;
return false;
}
private boolean validateMinutes(int minutes) {
if (minutes >= 0 && minutes < 60)
return true;
return false;
}
protected void rollMonth(int count) {
Calendar temp = (Calendar) today.clone();
temp.set(YEAR, currentYear);
temp.set(MONTH, currentMonth);
temp.add(MONTH, count);
changeCalendar(temp.get(YEAR), temp.get(MONTH), temp.get(HOUR_OF_DAY),
temp.get(MINUTE), true);
}
//send the selectionChanged event ,inform all listeners.
protected void changeDate(Calendar date) {
this.selection = date;
updateSelection();
if (firingSelectionChange)
return;
firingSelectionChange = true;
fireSelectionChanged(
new SelectionChangedEvent(DatePicker.this, getSelection()));
firingSelectionChange = false;
}
@Override
public Object getInput() {
return today;
}
@Override
public void refresh() {
update();
}
@Override
public void setInput(Object input) {
if (input instanceof Calendar) {
Calendar oldInput = this.today;
this.today = (Calendar) input;
inputChanged(input, oldInput);
}
}
@Override
protected void inputChanged(Object input, Object oldInput) {
update();
}
private static boolean isWeekend(Calendar date) {
int dow = date.get(DAY_OF_WEEK);
return dow == SUNDAY || dow == SATURDAY;
}
static Calendar getCalendarStart(Calendar date, int year, int month) {
date = (Calendar) date.clone();
date.set(year, month, 1);
while (date.get(DAY_OF_WEEK) != SUNDAY) {
date.add(DATE, -1);
}
return date;
}
}