/******************************************************************************* * Copyright (c) Emil Crumhorn - Hexapixel.com - emil.crumhorn@gmail.com * 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: * emil.crumhorn@gmail.com - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.widgets.calendarcombo; import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Locale; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; 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.Layout; import org.eclipse.swt.widgets.Listener; class CalendarComposite extends Canvas implements MouseListener, MouseMoveListener { private final int ARROW_LEFT = 1; private final int ARROW_RIGHT = 2; private Button mButtonToday; private Button mButtonNone; private Rectangle mLeftArrowBounds; private Rectangle mRightArrowBounds; private Rectangle mMonthNameBounds; private Calendar mCalendar; private Calendar mToday; private int mDatesTopY = 0; private int mDayXs[] = new int[7]; private CalDay[] mDays = new CalDay[7 * 6]; private Calendar mSelectedDay; // used for date ranges private Calendar mMouseDownDay; private Calendar mMouseUpDay; private static DateFormatSymbols mDFS; private String mMonths[]; private static String[] mDayTitles = null; private boolean mMonthSelectorOpen; private ArrayList mListeners; private boolean mNoDayClicked; // this thread deals with holding down the mouse over the arrows to jump // months quickly // milliseconds private static final int ARROW_SLOW_TIME = 300; private static final int ARROW_FAST_TIME = 120; // after how many iterations do we switch speed? (after how many months // flipped-by) private static final int ARROW_SPEED_SWITCH_COUNT = 10; // default speed private int mArrowSleepTime = ARROW_SLOW_TIME; // various variables used to keep track private int mArrowIterations = 0; private Thread mArrowThread; private boolean mArrowRun; private boolean mArrowPause; private int mArrowThreadDirection = 0; private IColorManager mColorManager; private ISettings mSettings; private ICalendarListener mMainListener; private Calendar mDisallowBeforeDate; private Calendar mDisallowAfterDate; private boolean mDateRange; private boolean mMouseIsDown; public CalendarComposite(Composite parent, Calendar selectedDay, Calendar disallowBeforeDate, Calendar disallowAfterDate, IColorManager colorManager, ISettings settings, boolean dateRange, Calendar rangeStart, Calendar rangeEnd) { super(parent, SWT.NO_BACKGROUND | SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED); this.mSelectedDay = selectedDay; this.mCalendar = selectedDay; this.mColorManager = colorManager; this.mSettings = settings; this.mDisallowBeforeDate = disallowBeforeDate; this.mDisallowAfterDate = disallowAfterDate; this.mDateRange = dateRange; if (dateRange) { this.mMouseDownDay = rangeStart; this.mMouseUpDay = rangeEnd; } init(); build(); } private void init() { mDFS = new DateFormatSymbols(mSettings.getLocale()); mMonths = mDFS.getMonths(); if (mCalendar == null) mCalendar = Calendar.getInstance(mSettings.getLocale()); if (mToday == null) mToday = Calendar.getInstance(mSettings.getLocale()); String[] weekdays = mDFS.getWeekdays(); // hebrew needs short weekdays if (mSettings.getLocale().getDisplayLanguage().toLowerCase().equals("hebrew")) { weekdays = mDFS.getShortWeekdays(); } mDayTitles = new String[weekdays.length]; boolean isCNLocale = mSettings.getLocale().equals(Locale.CHINA) || mSettings.getLocale().equals(Locale.TAIWAN); for (int i = 0; i < weekdays.length; i++) { String weekday = weekdays[i]; if (weekday.length() > 0) { if (isCNLocale) { mDayTitles[i] = weekday.substring(2, 3).toUpperCase(); } else { mDayTitles[i] = weekday.substring(0, 1).toUpperCase(); } } } } private void build() { // button height & width and spacers int bheight = mSettings.getButtonHeight(); int bwidth = mSettings.getButtonWidth(); int buttonStyle = SWT.PUSH; mListeners = new ArrayList(); // Mac buttons need different flag to look normal if (CalendarCombo.OS_CARBON) { bheight = mSettings.getCarbonButtonHeight(); bwidth = mSettings.getButtonWidthCarbon(); buttonStyle = SWT.FLAT; } setLayout(new ButtonSectionLayout()); addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { paint(event); } }); addMouseListener(this); addMouseMoveListener(this); mButtonToday = new Button(this, buttonStyle); mButtonToday.setText(mSettings.getTodayText()); mButtonToday.setLayoutData(new GridData(bwidth, bheight)); mButtonToday.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { clickedTodayButton(); } }); mButtonNone = new Button(this, buttonStyle); mButtonNone.setText(mSettings.getNoneText()); mButtonNone.setLayoutData(new GridData(bwidth, bheight)); mButtonNone.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { clickedNoneButton(); } }); } private void clickedTodayButton() { setDate(Calendar.getInstance(mSettings.getLocale())); mSelectedDay = Calendar.getInstance(mSettings.getLocale()); mMouseDownDay = mSelectedDay; mMouseUpDay = mSelectedDay; notifyListeners(); } private void clickedNoneButton() { notifyListeners(null); notifyClose(); } private void paint(PaintEvent event) { GC gc = event.gc; drawChartOntoGC(gc); } private void drawChartOntoGC(GC gc) { Rectangle bounds = super.getBounds(); gc.setBackground(mColorManager.getCalendarBackgroundColor()); gc.fillRectangle(bounds); Font used = null; if (CalendarCombo.OS_CARBON) { used = mSettings.getCarbonDrawFont(); if (used != null) gc.setFont(used); } // header drawHeader(gc); // day titles drawTitleDays(gc); // days drawDays(gc); // 1 pixel border drawBorder(gc); gc.dispose(); if (used != null) used.dispose(); } public void setDate(Calendar date) { date.set(Calendar.DAY_OF_MONTH, 1); this.mCalendar = date; redraw(); } public void nextMonth() { mSelectedDay = null; this.mCalendar.set(Calendar.DAY_OF_MONTH, 1); this.mCalendar.add(Calendar.MONTH, 1); redraw(); } public void prevMonth() { mSelectedDay = null; this.mCalendar.add(Calendar.MONTH, -1); this.mCalendar.set(Calendar.DAY_OF_MONTH, 1); redraw(); } public void goToToday() { mSelectedDay = null; this.mCalendar = Calendar.getInstance(mSettings.getLocale()); redraw(); } // draws 1 pixel border around entire calendar private void drawBorder(GC gc) { Rectangle bounds = super.getBounds(); gc.setForeground(mColorManager.getCalendarBorderColor()); gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1); } private void drawHeader(GC gc) { Rectangle bounds = super.getBounds(); Rectangle bgRect = new Rectangle(bounds.x + mSettings.getHeaderLeftMargin(), bounds.y + mSettings.getHeaderTopMargin(), mSettings.getCalendarWidth() - 13, bounds.y + mSettings.getHeaderHeight()); gc.setBackground(mColorManager.getCalendarHeaderColor()); gc.fillRectangle(bgRect); drawArrow(gc, bounds.x + mSettings.getHeaderLeftMargin() + mSettings.getArrowLeftSpacing() + 1, bounds.y + mSettings.getHeaderTopMargin() + mSettings.getArrowTopSpacing() + 4, ARROW_LEFT); drawArrow(gc, bounds.x + mSettings.getCalendarWidth() - 13 - mSettings.getHeaderRightMargin(), bounds.y + mSettings.getHeaderTopMargin() + mSettings.getArrowTopSpacing() + 4, ARROW_RIGHT); String toDraw = mMonths[mCalendar.get(Calendar.MONTH)] + " " + mCalendar.get(Calendar.YEAR); Point strWidth = gc.stringExtent(toDraw); int avail = mSettings.getCalendarWidth() - 13 - strWidth.x; avail /= 2; mMonthNameBounds = new Rectangle(bounds.x + mSettings.getHeaderLeftMargin() + avail, bounds.y + mSettings.getHeaderTopMargin() + 1, strWidth.x, strWidth.y); gc.drawString(toDraw, bounds.x + mSettings.getHeaderLeftMargin() + avail, bounds.y + mSettings.getHeaderTopMargin() + 1, true); } private void drawTitleDays(GC gc) { Calendar temp = Calendar.getInstance(mSettings.getLocale()); // fetch the first day of the week, and draw starting on that day int fdow = temp.getFirstDayOfWeek(); Rectangle bounds = super.getBounds(); int xStart = mSettings.getDatesLeftMargin() + 5; int yStart = bounds.y + mSettings.getHeaderTopMargin() + mSettings.getHeaderHeight() + 1; int spacer = 0; int letterHeight = 0; for (int i = 0; i < 7; i++) { Point strWidth = gc.stringExtent(mDayTitles[fdow]); int x = xStart + mSettings.getOneDateBoxSize() + spacer - strWidth.x; // don't add the string width, as our string width later when // drawing days will differ mDayXs[i] = xStart + mSettings.getOneDateBoxSize() + spacer; gc.drawString(mDayTitles[fdow], x, yStart, true); letterHeight = strWidth.y; spacer += mSettings.getOneDateBoxSize() + mSettings.getBoxSpacer(); fdow++; if (fdow > 7) { fdow = 1; } } int lineStart = yStart + 1 + letterHeight; gc.setForeground(mColorManager.getLineColor()); gc.drawLine(mSettings.getDatesLeftMargin() + 1, lineStart, bounds.width - mSettings.getDatesRightMargin() - 3, lineStart); mDatesTopY = lineStart + 3; } private void drawDays(GC gc) { gc.setBackground(mColorManager.getCalendarBackgroundColor()); gc.setForeground(mColorManager.getTextColor()); Rectangle bounds = super.getBounds(); int spacer = 0; Calendar temp = (Calendar) mCalendar.clone(); temp.set(Calendar.DAY_OF_MONTH, 1); temp = clearTime(temp); int monthToShow = temp.get(Calendar.MONTH); int firstDayOfWeek = temp.getFirstDayOfWeek(); int firstDay = temp.get(Calendar.DAY_OF_WEEK) - firstDayOfWeek; if (firstDay < 0) firstDay += 7; temp.add(Calendar.DATE, -firstDay); int col = 0; int colCount = 0; String typicalLetter = "8"; int strHeight = gc.stringExtent(typicalLetter).y; gc.setForeground(mColorManager.getLineColor()); int lastY = 0; List betweenDays = null; if (mDateRange && mMouseDownDay != null) { Calendar end = mMouseUpDay == null ? mSelectedDay : mMouseUpDay; // end can be null when month is switching to next if (end != null) betweenDays = getCalendarsBetween(mMouseDownDay, end); } for (int y = 0; y < 42; y++) { // new row if (y % 7 == 0 && y != 0) { spacer += strHeight + 2; } if (colCount > 6) { colCount = 0; col = 0; } int curMonth = temp.get(Calendar.MONTH); if (curMonth == monthToShow) { gc.setForeground(mColorManager.getTextColor()); } else { gc.setForeground(mColorManager.getPreviousAndNextMonthForegroundColor()); } boolean disallowedDate = false; if (mDisallowBeforeDate != null) { if (temp.before(mDisallowBeforeDate)) { disallowedDate = true; gc.setForeground(mColorManager.getDisabledDayForegroundColor()); } } if (mDisallowAfterDate != null && !disallowedDate) { if (temp.after(mDisallowAfterDate)) { disallowedDate = true; gc.setForeground(mColorManager.getDisabledDayForegroundColor()); } } String dateStr = "" + temp.get(Calendar.DATE); Point width = gc.stringExtent(dateStr); if (mSelectedDay != null) { if (DateHelper.sameDate(mSelectedDay, temp) || (mDateRange && betweenDays != null && betweenDays.contains(temp))) { gc.setBackground(mColorManager.getSelectedDayColor()); gc.fillRectangle(mDayXs[col] - mSettings.getOneDateBoxSize() - 4, mDatesTopY + spacer - 1, mSettings.getOneDateBoxSize() + 5, 14); gc.setBackground(mColorManager.getCalendarBackgroundColor()); } } Rectangle dayBounds = new Rectangle(mDayXs[col] - mSettings.getOneDateBoxSize() - 4, mDatesTopY + spacer - 1, mSettings.getOneDateBoxSize() + 5, 14); mDays[y] = new CalDay(y, temp, dayBounds, disallowedDate); gc.drawString(dateStr, mDayXs[col] - width.x, mDatesTopY + spacer, true); if (DateHelper.sameDate(mToday, temp)) { Color old = gc.getForeground(); gc.setForeground(mColorManager.getSelectedDayBorderColor()); gc.drawRectangle(mDayXs[col] - mSettings.getOneDateBoxSize() - 4, mDatesTopY + spacer - 1, mSettings.getOneDateBoxSize() + 5, 14); gc.setForeground(old); } temp.add(Calendar.DATE, 1); col++; colCount++; lastY = mDatesTopY + spacer; } lastY += strHeight + 1; gc.setForeground(mColorManager.getLineColor()); gc.drawLine(mSettings.getDatesLeftMargin() + 1, lastY, bounds.width - mSettings.getDatesRightMargin() - 3, lastY); } private List getCalendarsBetween(Calendar start, Calendar end) { List ret = new ArrayList(); // we have to remember that the end can come before the start, so let's // figure that out first Calendar trueStart = end.before(start) ? end : start; Calendar trueEnd = end.after(start) ? end : start; // boolean flip = end.before(start); int days = (int) DateHelper.daysBetween(trueStart, trueEnd, mSettings.getLocale()); for (int i = 0; i <= days; i++) { // we need new objects for each day Calendar cal = Calendar.getInstance(mSettings.getLocale()); cal.setTime(trueStart.getTime()); cal.add(Calendar.DATE, i); ret.add(clearTime(cal)); } return ret; } private Calendar clearTime(Calendar cal) { cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); return cal; } private void drawArrow(GC gc, int x, int y, int style) { gc.setForeground(mColorManager.getArrowColor()); switch (style) { case ARROW_RIGHT: gc.drawLine(x, y - 4, x, y + 4); gc.drawLine(x + 1, y - 3, x + 1, y + 3); gc.drawLine(x + 2, y - 2, x + 2, y + 2); gc.drawLine(x + 3, y - 1, x + 3, y + 1); gc.drawLine(x + 4, y, x + 4, y); mRightArrowBounds = new Rectangle(x - 4, y - 4, x + 8, y); break; case ARROW_LEFT: gc.drawLine(x - 1, y, x - 1, y); gc.drawLine(x, y - 1, x, y + 1); gc.drawLine(x + 1, y - 2, x + 1, y + 2); gc.drawLine(x + 2, y - 3, x + 2, y + 3); gc.drawLine(x + 3, y - 4, x + 3, y + 4); mLeftArrowBounds = new Rectangle(x - 4, y - 4, x + 8, y); break; } } private boolean isInside(int x, int y, Rectangle rect) { if (rect == null) return false; if (x >= rect.x && y >= rect.y && x <= (rect.x + rect.width) && y <= (rect.y + rect.height)) return true; return false; } public void mouseMove(MouseEvent e) { if (mMonthSelectorOpen) return; // "dragging" the day, just paint it if (e.stateMask != 0) doDaySelection(e.x, e.y); if (mArrowRun && mArrowThread != null) { if (!isInside(e.x, e.y, mLeftArrowBounds) && !isInside(e.x, e.y, mRightArrowBounds)) { mArrowPause = true; // also pause the speed mArrowIterations = 0; mArrowSleepTime = ARROW_SLOW_TIME; } else { if (isInside(e.x, e.y, mLeftArrowBounds)) mArrowThreadDirection = ARROW_LEFT; else mArrowThreadDirection = ARROW_RIGHT; mArrowPause = false; } } } public void mouseDoubleClick(MouseEvent event) { } // draw the date selection on mouse down to give that flicker of "response" // to the user public void mouseDown(MouseEvent event) { mMouseIsDown = true; if (mDateRange) mMouseUpDay = null; if (isInside(event.x, event.y, mLeftArrowBounds)) { prevMonth(); runArrowThread(ARROW_LEFT); return; } if (isInside(event.x, event.y, mRightArrowBounds)) { nextMonth(); runArrowThread(ARROW_RIGHT); return; } if (mSettings.showMonthPickerOnMonthNameMousePress() && isInside(event.x, event.y, mMonthNameBounds)) { MonthPick mp = new MonthPick(this, SWT.NONE, mCalendar, this, mSettings, mSettings.getLocale()); mp.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { mMonthSelectorOpen = false; } }); // figure out where to put it Rectangle bounds = getBounds(); int xSpacer = (bounds.width - mp.getSize().x) / 2; int ySpacer = getLocation().y; mp.setLocation(xSpacer, ySpacer); mp.setVisible(true); mMonthSelectorOpen = true; return; } doDaySelection(event.x, event.y); if (mDateRange) mMouseDownDay = mSelectedDay; } private void killArrowThread() { if (mArrowThread != null) { mArrowPause = true; mArrowThreadDirection = 0; mArrowRun = false; mArrowThread = null; } } private void runArrowThread(int direction) { this.mArrowThreadDirection = direction; mArrowIterations = 0; mArrowSleepTime = ARROW_SLOW_TIME; mArrowRun = false; mArrowPause = false; mArrowThread = new Thread() { public void run() { while (mArrowRun) { try { sleep(mArrowSleepTime); if (!mArrowPause) mArrowIterations++; if (mArrowIterations > ARROW_SPEED_SWITCH_COUNT && mArrowSleepTime != ARROW_FAST_TIME) mArrowSleepTime = ARROW_FAST_TIME; } catch (InterruptedException e) { e.printStackTrace(); } if (!mArrowPause) { Display.getDefault().syncExec(new Runnable() { public void run() { if (isDisposed()) { mArrowRun = false; mArrowThread = null; } else { if (mArrowThreadDirection == ARROW_LEFT) prevMonth(); else if (mArrowThreadDirection == ARROW_RIGHT) nextMonth(); } } }); } } } }; mArrowPause = false; mArrowRun = true; mArrowThread.start(); } // selects a day at x, y if there is a day there to select private void doDaySelection(int x, int y) { int curYear = mCalendar.get(Calendar.YEAR); int curMonth = mCalendar.get(Calendar.MONTH); mNoDayClicked = false; for (int i = 0; i < mDays.length; i++) { if (isInside(x, y, mDays[i].getBounds())) { // disabled date? ignore click completely if (mDays[i].isDisabled()) return; int dayYear = mDays[i].getDate().get(Calendar.YEAR); int dayMonth = mDays[i].getDate().get(Calendar.MONTH); if (dayYear == curYear) { if (dayMonth < curMonth) { prevMonth(); return; } else if (dayMonth > curMonth) { nextMonth(); return; } } else { if (dayYear < curYear) { prevMonth(); return; } else if (dayYear > curYear) { nextMonth(); return; } } mSelectedDay = mDays[i].getDate(); redraw(); return; } } mNoDayClicked = true; } public void mouseUp(MouseEvent event) { mMouseIsDown = false; boolean bArrowThread = (mArrowThread!=null); killArrowThread(); if (mNoDayClicked) { mNoDayClicked = false; return; } //don't close the popup if they were pressing the arrow! if (mSelectedDay != null && !bArrowThread) { notifyListeners(); notifyClose(); } } private void notifyClose() { // notify ourselves first or dates will not be equal on the fired event // and the getDate() on the combo itself mMainListener.popupClosed(); for (int i = 0; i < mListeners.size(); i++) { ICalendarListener l = (ICalendarListener) mListeners.get(i); l.popupClosed(); } } private void notifyListeners(Calendar date) { // notify ourselves first if (mDateRange) { // this may seem odd but it's not. First we set the "up" date to the // current date // then we overwrite it by setting the selected date to when the // mouse click was "down". // that way the date set on the combo will be the date the user // clicked first, and not the date when the user // let go of the mouse button, this will be reflected in the // listeners as well mMouseUpDay = mSelectedDay; mSelectedDay = mMouseDownDay; } if (mDateRange) mMainListener.dateRangeChanged(mMouseDownDay, mMouseUpDay); else mMainListener.dateChanged(date); for (int i = 0; i < mListeners.size(); i++) { ICalendarListener l = (ICalendarListener) mListeners.get(i); if (mDateRange) l.dateRangeChanged(mMouseDownDay, mMouseUpDay); else l.dateChanged(date); } } private void notifyListeners() { notifyListeners(mSelectedDay); } void addMainCalendarListener(ICalendarListener listener) { mMainListener = listener; } public void addCalendarListener(ICalendarListener listener) { if (!mListeners.contains(listener)) { mListeners.add(listener); } } public void removeCalendarListener(ICalendarListener listener) { mListeners.remove(listener); } public boolean externalClick(Point p) { Point loc = mButtonToday.getLocation(); p = toControl(p); int width = mButtonToday.getSize().x; int height = mButtonToday.getSize().y; Rectangle area = new Rectangle(loc.x, loc.y, width, height); if (isInside(p.x, p.y, area)) { clickedTodayButton(); return true; } loc = mButtonNone.getLocation(); width = mButtonNone.getSize().x; height = mButtonNone.getSize().y; area = new Rectangle(loc.x, loc.y, width, height); if (isInside(p.x, p.y, area)) clickedNoneButton(); return true; } public boolean isMonthPopupActive() { return mMonthSelectorOpen; } boolean canJumpPrevMonth = false; void keyPressed(int keyCode, int stateMask) { if (mSelectedDay == null) { mSelectedDay = (Calendar) mCalendar.clone(); mSelectedDay.set(Calendar.DATE, 1); canJumpPrevMonth = true; redraw(); } else { if (keyCode == SWT.ARROW_RIGHT) { mSelectedDay.add(Calendar.DATE, 1); if (mSelectedDay.get(Calendar.DATE) == 1) { mCalendar.add(Calendar.MONTH, 1); canJumpPrevMonth = true; } redraw(); } else if (keyCode == SWT.ARROW_LEFT) { if (mSelectedDay.get(Calendar.DATE) == 1) mCalendar.add(Calendar.MONTH, -1); mSelectedDay.add(Calendar.DATE, -1); redraw(); } else if (keyCode == SWT.ARROW_UP) { //int monthNow = mSelectedDay.get(Calendar.MONTH); mSelectedDay.add(Calendar.DATE, -7); //int monthAfter = mSelectedDay.get(Calendar.MONTH); redraw(); } else if (keyCode == SWT.ARROW_DOWN) { //int monthNow = mSelectedDay.get(Calendar.MONTH); mSelectedDay.add(Calendar.DATE, 7); //int monthAfter = mSelectedDay.get(Calendar.MONTH); redraw(); } else if (keyCode == SWT.CR || keyCode == SWT.LF) { notifyListeners(); notifyClose(); return; } } } class ButtonSectionLayout extends Layout { protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { return new Point(SWT.DEFAULT, SWT.DEFAULT); } protected void layout(Composite composite, boolean flushCache) { int bheight = mSettings.getButtonHeight(); int bwidth = mSettings.getButtonWidth(); int vspacer = mSettings.getButtonVerticalSpace(); int bspacer = mSettings.getButtonsHorizontalSpace(); if (CalendarCombo.OS_CARBON) { bwidth = mSettings.getButtonWidthCarbon(); bheight = mSettings.getCarbonButtonHeight(); vspacer = mSettings.getCarbonButtonVerticalSpace(); bspacer = mSettings.getCarbonButtonsHorizontalSpace(); } // see how much space we put on the left and right sides of the // buttons int width = mSettings.getCalendarWidth() - (bwidth * 2) - bspacer; width /= 2; int button1Left = width; int button2Left = mSettings.getCalendarWidth() - width - bwidth; Control[] children = composite.getChildren(); for (int i = 0; i < children.length; i++) { switch (i) { case 0: children[i].setBounds(button1Left, vspacer, bwidth, bheight); break; case 1: children[i].setBounds(button2Left, vspacer, bwidth, bheight); break; } } } } class CalDay { private Calendar date; private int number; private Rectangle bounds; private boolean disabled; public CalDay(int number, Calendar date, Rectangle bounds, boolean disabled) { this.date = (Calendar) date.clone(); this.bounds = bounds; this.number = number; this.disabled = disabled; } public boolean isDisabled() { return disabled; } public Calendar getDate() { return date; } public int getNumber() { return number; } public Rectangle getBounds() { return bounds; } } }