0001: package com.xoetrope.swing.date;
0002:
0003: import com.xoetrope.event.XDateListener;
0004: import java.awt.BasicStroke;
0005: import java.awt.Color;
0006: import java.awt.Dimension;
0007: import java.awt.Font;
0008: import java.awt.FontMetrics;
0009: import java.awt.GradientPaint;
0010: import java.awt.Graphics;
0011: import java.awt.Graphics2D;
0012: import java.awt.Insets;
0013: import java.awt.Point;
0014: import java.awt.RenderingHints;
0015: import java.awt.Shape;
0016: import java.awt.Stroke;
0017: import java.awt.event.ActionEvent;
0018: import java.awt.event.ActionListener;
0019: import java.awt.event.MouseEvent;
0020: import java.awt.event.MouseListener;
0021: import java.awt.event.MouseMotionListener;
0022: import java.awt.geom.Rectangle2D;
0023: import java.awt.geom.RoundRectangle2D;
0024: import java.text.DateFormatSymbols;
0025: import java.text.ParsePosition;
0026: import java.text.SimpleDateFormat;
0027: import java.util.Calendar;
0028: import java.util.Date;
0029: import javax.swing.ImageIcon;
0030: import javax.swing.JComponent;
0031: import javax.swing.JButton;
0032:
0033: import net.xoetrope.xui.XAttributedComponent;
0034: import net.xoetrope.xui.XProjectManager;
0035: import net.xoetrope.xui.XTextHolder;
0036: import net.xoetrope.xui.helper.XuiUtilities;
0037: import net.xoetrope.xui.style.XStyle;
0038: import net.xoetrope.xui.style.XStyleManager;
0039:
0040: /**
0041: * A panel containing a representation of a month so that the user can select
0042: * a date visually. Events/Appointments can be added and rendered via the CalendatEvent
0043: * interface.
0044: *
0045: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
0046: * the GNU Public License (GPL), please see license.txt for more details. If
0047: * you make commercial use of this software you must purchase a commercial
0048: * license from Xoetrope.</p>
0049: * <p> $Revision: 1.2 $</p>
0050: */
0051: public class XCalendarPanel extends JComponent implements
0052: MouseListener, MouseMotionListener, XAttributedComponent,
0053: XTextHolder {
0054: public static final int MONTH_VIEW = 0;
0055: public static final int DAY_VIEW = 1;
0056:
0057: protected XStyleManager styleManager;
0058: private Calendar calendar;
0059:
0060: protected int selectedDay;
0061: protected int highlightedDay;
0062:
0063: private boolean mouseEventInvoked = false;
0064: private boolean showDayNames = true;
0065: private boolean showHeader = true;
0066: private double cellHeight = 10.0;
0067: private double cellWidth = 10.0;
0068: private int startDay = 1;
0069: private int oldX = 0;
0070: private int oldY = 0;
0071: private int top = 0;
0072: private int headerHeight;
0073: private SimpleDateFormat dateFormat;
0074:
0075: private Color foregroundColor, backgroundColor, highlightedColor,
0076: highlightedBkColor, selectedColor, selectedBkColor,
0077: weekendColor, weekendBkColor;
0078: private String styleWeekend, styleSelected, styleHighlighted,
0079: styleHeader, basicStyle;
0080: private XDateListener listener;
0081: private String[] dayNames;
0082: private int viewMode;
0083: private boolean drawBorder;
0084:
0085: private XAppointmentProvider appointmentProvider;
0086: private XAppointment appointments[];
0087: private XAppointment selectedAppointment;
0088:
0089: private JButton prevBtn, nextBtn, chooserBtn;
0090: protected String[] styles;
0091:
0092: AppointmentPainter appointmentPainter;
0093:
0094: public XCalendarPanel() {
0095: calendar = Calendar.getInstance();
0096: selectedDay = calendar.get(Calendar.DATE);
0097: viewMode = DAY_VIEW;
0098:
0099: addMouseListener(this );
0100: addMouseMotionListener(this );
0101:
0102: styleWeekend = "base";
0103: styleSelected = "base";
0104: styleHighlighted = "base";
0105: drawBorder = true;
0106:
0107: styleManager = XProjectManager.getStyleManager();
0108:
0109: XStyle weekendStyle = styleManager.getStyle(styleWeekend);
0110: XStyle selectedStyle = weekendStyle;
0111: XStyle highlightedStyle = weekendStyle;
0112: selectedColor = highlightedColor = weekendColor = selectedStyle
0113: .getStyleAsColor(XStyle.COLOR_FORE);
0114: selectedBkColor = highlightedBkColor = weekendBkColor = selectedStyle
0115: .getStyleAsColor(XStyle.COLOR_BACK);
0116:
0117: backgroundColor = getBackground();
0118: if (backgroundColor == null) {
0119: backgroundColor = new Color(255, 255, 225);
0120: weekendBkColor = new Color(255, 243, 198);
0121: }
0122: foregroundColor = getForeground();
0123: if (foregroundColor == null)
0124: foregroundColor = Color.darkGray;
0125:
0126: dateFormat = new SimpleDateFormat("d MMM yyyy");
0127: styles = new String[6];
0128: }
0129:
0130: /**
0131: * Set the AppointmentPainter which will receive month and day view paint
0132: * events.
0133: * @param painter the AppointmentPainter object
0134: */
0135: public void setAppointmentPainter(AppointmentPainter painter) {
0136: appointmentPainter = painter;
0137: }
0138:
0139: /**
0140: * Set the appointment provider that provides the dates for this calendar
0141: * @param provider the object that provides the appointment information
0142: */
0143: public void setAppointmentProvider(XAppointmentProvider provider) {
0144: appointmentProvider = provider;
0145: repaint();
0146: }
0147:
0148: /**
0149: * Show the navigation header items
0150: * @param bShow true to show the navigation items
0151: */
0152: public void showNavItems(boolean bShow) {
0153: showHeader = bShow;
0154:
0155: if (showHeader) {
0156: prevBtn = new JButton();
0157: prevBtn.setIcon(new ImageIcon(XCalendarPanel.class
0158: .getResource("/com/xoetrope/resources/back.gif")));
0159: prevBtn.setBounds(2, 2, 30,
0160: headerHeight > 0 ? headerHeight - 4 : 28);
0161: prevBtn.setMargin(new Insets(0, 0, 0, 0));
0162: add(prevBtn);
0163: prevBtn.addActionListener(new ActionListener() {
0164: public void actionPerformed(ActionEvent e) {
0165: if (viewMode == MONTH_VIEW)
0166: prev();
0167: else
0168: prevDay();
0169: }
0170: });
0171:
0172: nextBtn = new JButton();
0173: nextBtn
0174: .setIcon(new ImageIcon(
0175: XCalendarPanel.class
0176: .getResource("/com/xoetrope/resources/forward.gif")));
0177: nextBtn.setBounds(getWidth() - 32, 2, 30,
0178: headerHeight > 0 ? headerHeight - 4 : 28);
0179: nextBtn.setMargin(new Insets(0, 0, 0, 0));
0180: add(nextBtn);
0181: nextBtn.addActionListener(new ActionListener() {
0182: public void actionPerformed(ActionEvent e) {
0183: if (viewMode == MONTH_VIEW)
0184: next();
0185: else
0186: nextDay();
0187: }
0188: });
0189:
0190: chooserBtn = new JButton();
0191: chooserBtn
0192: .setIcon(new ImageIcon(
0193: XCalendarPanel.class
0194: .getResource("/com/xoetrope/resources/dateChooser.gif")));
0195: chooserBtn.setBounds(getWidth() - 64, 2, 30,
0196: headerHeight > 0 ? headerHeight - 4 : 28);
0197: chooserBtn.setMargin(new Insets(0, 0, 0, 0));
0198: add(chooserBtn);
0199: chooserBtn.addActionListener(new ActionListener() {
0200: public void actionPerformed(ActionEvent e) {
0201: Point pt = chooserBtn.getLocationOnScreen();
0202: XDateChooserDialog dpd = new XDateChooserDialog(pt);
0203: try {
0204: ParsePosition pp = new ParsePosition(0);
0205: dateFormat.setLenient(false);
0206: dpd.setDate(calendar.getTime());
0207: } catch (Exception ex) {
0208: }
0209: dpd.setStyles(styles);
0210: dpd.setShowDayNames(showDayNames);
0211: dpd.showDialog(chooserBtn.getParent(), null);
0212: calendar.setTime(dpd.getDate());
0213: repaint();
0214: }
0215: });
0216: }
0217: }
0218:
0219: /**
0220: * Moves and resizes this component. The new location of the top-left
0221: * corner is specified by <code>x</code> and <code>y</code>, and the
0222: * new size is specified by <code>width</code> and <code>height</code>.
0223: * @param x the new <i>x</i>-coordinate of this component
0224: * @param y the new <i>y</i>-coordinate of this component
0225: * @param width the new <code>width</code> of this component
0226: * @param height the new <code>height</code> of this
0227: * component
0228: * @see #getBounds
0229: * @see #setLocation(int, int)
0230: * @see #setLocation(Point)
0231: * @see #setSize(int, int)
0232: * @see #setSize(Dimension)
0233: * @since JDK1.1
0234: */
0235: public void setBounds(int x, int y, int w, int h) {
0236: super .setBounds(x, y, w, h);
0237:
0238: if (prevBtn != null)
0239: prevBtn.setBounds(2, 2, 30,
0240: headerHeight > 0 ? headerHeight - 4 : 28);
0241:
0242: if (nextBtn != null)
0243: nextBtn.setBounds(w - 32, 2, 30,
0244: headerHeight > 0 ? headerHeight - 4 : 28);
0245:
0246: if (chooserBtn != null)
0247: chooserBtn.setBounds(w - 64, 2, 30,
0248: headerHeight > 0 ? headerHeight - 4 : 28);
0249: }
0250:
0251: /**
0252: * Set one or more attributes of the component. Currently this handles the
0253: * attributes
0254: * <OL>
0255: * <LI>view (month|day) or</LI>
0256: s * <LI>format, value=the date format</LI>
0257: * <LI>style, value=the default style</LI>
0258: * <LI>selectedStyle, value=the selected date's style</LI>
0259: * <LI>weekendStyle, value=the weekend date style</LI>
0260: * <LI>highlightStyle, value=the rollover/highlighted date style</LI>
0261: * <LI>headerStyle, value=the header style</LI>
0262: * <LI>threeDStyle, value=the 3d element style</LI>
0263: * <LI>daynames, value=true to show the day names</LI>
0264: * <LI>header, value=true to show the date navigation headers</LI>
0265: * </OL>
0266: * @param attribName the attribute name
0267: * @param attribValue the attribute value
0268: * @return 0 for success, non zero otherwise
0269: */
0270: public int setAttribute(String attribName, Object attribValue) {
0271: String attribNameLwr = attribName.toLowerCase();
0272: String attribValueStr = (String) attribValue;
0273: String attribValueLwr = attribValueStr.toLowerCase();
0274: if (attribValueLwr == null)
0275: return 0;
0276:
0277: if (attribNameLwr.equals("view")) {
0278: if (attribValueLwr.equals("month"))
0279: viewMode = MONTH_VIEW;
0280: else
0281: viewMode = DAY_VIEW;
0282: }
0283:
0284: if (attribNameLwr.equals("header"))
0285: showNavItems(attribValueLwr.equals("true"));
0286: else if (attribNameLwr.equals("format"))
0287: dateFormat = new SimpleDateFormat(attribValueStr);
0288: else if (attribNameLwr.equals("style"))
0289: styles[0] = attribValueStr;
0290: else if (attribNameLwr.equals("selectedstyle"))
0291: styles[1] = attribValueStr;
0292: else if (attribNameLwr.equals("weekendstyle"))
0293: styles[2] = attribValueStr;
0294: else if (attribNameLwr.equals("highlightstyle"))
0295: styles[3] = attribValueStr;
0296: else if (attribNameLwr.equals("headerstyle"))
0297: styles[4] = attribValueStr;
0298: else if (attribNameLwr.equals("threedstyle"))
0299: styles[5] = attribValueStr;
0300: else if (attribNameLwr.equals("daynames"))
0301: showDayNames = (attribValue.equals("true") || attribValue
0302: .equals("1"));
0303: else if (attribNameLwr.equals("border"))
0304: drawBorder = (attribValueLwr.equals("true") || attribValueLwr
0305: .equals("1"));
0306:
0307: return 0;
0308: }
0309:
0310: /**
0311: * Gets the current date.
0312: * @return
0313: */
0314: public Date getDate() {
0315: return calendar.getTime();
0316: }
0317:
0318: /**
0319: * Sets the current date
0320: * @param newDate the new date
0321: */
0322: public void setDate(Date newDate) {
0323: calendar.setTime(newDate);
0324: selectedDay = calendar.get(Calendar.DATE);
0325: repaint();
0326: }
0327:
0328: /**
0329: * Move to the previous month
0330: */
0331: public void prev() {
0332: if (calendar.get(Calendar.MONTH) == 0)
0333: calendar.roll(Calendar.YEAR, false);
0334: calendar.roll(Calendar.MONTH, false);
0335: selectedDay = calendar.get(Calendar.DAY_OF_MONTH);
0336: highlightedDay = 0;
0337: repaint();
0338: }
0339:
0340: /**
0341: * Move to the next month
0342: */
0343: public void next() {
0344: if (calendar.get(Calendar.MONTH) == 11)
0345: calendar.roll(Calendar.YEAR, true);
0346: calendar.roll(Calendar.MONTH, true);
0347: if (calendar.get(Calendar.MONTH) == 12)
0348: selectedDay = 1;
0349: highlightedDay = 0;
0350: repaint();
0351: }
0352:
0353: /**
0354: * Move to the previous month
0355: */
0356: public void prevDay() {
0357: calendar.roll(Calendar.DAY_OF_YEAR, false);
0358: repaint();
0359: }
0360:
0361: /**
0362: * Move to the next month
0363: */
0364: public void nextDay() {
0365: calendar.roll(Calendar.DAY_OF_YEAR, true);
0366: repaint();
0367: }
0368:
0369: /**
0370: * Move to the previous year
0371: */
0372: public void prevYear() {
0373: calendar.roll(Calendar.YEAR, false);
0374: selectedDay = calendar.get(Calendar.DAY_OF_MONTH);
0375: highlightedDay = 0;
0376: repaint();
0377: }
0378:
0379: /**
0380: * Move to the next year
0381: */
0382: public void nextYear() {
0383: calendar.roll(Calendar.YEAR, true);
0384: selectedDay = calendar.get(Calendar.DAY_OF_MONTH);
0385: highlightedDay = 0;
0386: repaint();
0387: }
0388:
0389: /**
0390: * Get the selected appointment if any.
0391: * @return the appointment or null if none is selected
0392: */
0393: public XAppointment getSelectedAppointment() {
0394: return selectedAppointment;
0395: }
0396:
0397: /**
0398: * Renders the current month
0399: * @param g
0400: */
0401: public void paintComponent(Graphics g) {
0402: Graphics2D g2d = (Graphics2D) g;
0403: if (viewMode == DAY_VIEW)
0404: paintDayView(g2d);
0405: else
0406: paintMonthView(g2d);
0407: }
0408:
0409: /**
0410: * Paint the month view of the calendar
0411: */
0412: public void paintMonthView(Graphics2D g2d) {
0413: Color weekendShadow = new Color(240, 240, 240);
0414: Dimension d = getSize();
0415: int width = Math.max(d.width, 2);
0416: int height = Math.max(d.height, 2);
0417:
0418: FontMetrics fm = g2d.getFontMetrics();
0419: headerHeight = fm.getHeight() * 2;
0420:
0421: int month = calendar.get(Calendar.MONTH);
0422: int year = calendar.get(Calendar.YEAR);
0423: int day = calendar.get(Calendar.DATE);
0424: String dateStr = dateFormat.format(calendar.getTime());
0425: calendar.set(year, month, 1);
0426: int cellPos = startDay = calendar.get(calendar.DAY_OF_WEEK) - 1;
0427:
0428: DateFormatSymbols dfs = new DateFormatSymbols();
0429: String monthName = dfs.getShortMonths()[month];
0430:
0431: int numDays = calendar.getActualMaximum(calendar.DAY_OF_MONTH);
0432: int numWeeks = 1 + (int) (((double) numDays - (7.0 - (double) startDay)) / 7 + 0.9);
0433:
0434: int fontOffset = (headerHeight + fm.getAscent()) / 2;
0435: int pad = 4;
0436: int startY = 0;
0437: top = 0;
0438:
0439: Color headerColor = XuiUtilities.unsaturateColor(
0440: backgroundColor, 50);
0441: Color lineColor = headerColor.darker().darker();
0442: Color headerBkColorBright = headerColor.brighter();
0443: Color headerBkColorDarker = headerColor.darker();
0444: Color headerTextColor = XuiUtilities.unsaturateColor(
0445: foregroundColor, 50);
0446:
0447: // Paint the header with navigation controls and the current date
0448: if (showHeader) {
0449: top = headerHeight;
0450:
0451: GradientPaint gradient = new GradientPaint(0.0F, 0.0F,
0452: headerBkColorBright, (float) top / 4,
0453: (float) width / 2, headerBkColorDarker, true);
0454: g2d.setPaint(gradient);
0455: g2d.fillRect(0, 0, width, top);
0456:
0457: g2d.setColor(XuiUtilities.unsaturateColor(foregroundColor,
0458: 50));
0459:
0460: g2d.setColor(new Color(lineColor.getRed(), lineColor
0461: .getGreen(), lineColor.getBlue(), 128));
0462: g2d.drawLine(0, top - 1, width, headerHeight - 1);
0463:
0464: // Draw the date
0465: g2d.setColor(headerTextColor);
0466: g2d.drawString(dateStr, width - fm.stringWidth(dateStr)
0467: - 68, (headerHeight + fm.getAscent()) / 2);
0468: startY = top;
0469: }
0470:
0471: cellWidth = Math.max(1.0, width / 7.0);
0472: int iCellWidth = (int) cellWidth;
0473:
0474: if (showDayNames) {
0475: top += headerHeight;
0476: GradientPaint gradient = new GradientPaint(0.0F, 0.0F,
0477: headerBkColorBright, (float) top / 4,
0478: (float) width / 2, headerBkColorDarker, true);
0479: g2d.setPaint(gradient);
0480: g2d.fillRect(0, startY, width, headerHeight);
0481:
0482: dayNames = dfs.getWeekdays();
0483:
0484: // Check the width of the day names
0485: int maxNameLength = 0;
0486: for (int i = 0; i < 7; i++)
0487: maxNameLength = Math.max(fm.stringWidth(dayNames[i]),
0488: maxNameLength);
0489: // If they are too long use the short day names
0490: if (maxNameLength > (cellWidth - 8))
0491: dayNames = dfs.getShortWeekdays();
0492:
0493: for (int i = 1; i < 8; i++) {
0494: g2d.setColor(headerTextColor);
0495: g2d.drawString(dayNames[i],
0496: (i * iCellWidth)
0497: - (iCellWidth / 2 + fm
0498: .stringWidth(dayNames[i]) / 2),
0499: startY + fontOffset);
0500: if (i < 7) {
0501: g2d.setColor(headerBkColorDarker);
0502: g2d.drawLine(i * iCellWidth, startY + 3, i
0503: * iCellWidth, startY + headerHeight - 5);
0504: g2d.setColor(headerBkColorBright);
0505: g2d
0506: .drawLine(i * iCellWidth + 1, startY + 3, i
0507: * iCellWidth + 1, startY
0508: + headerHeight - 5);
0509: }
0510: }
0511:
0512: g2d.setColor(new Color(lineColor.getRed(), lineColor
0513: .getGreen(), lineColor.getBlue(), 128));
0514: g2d.drawLine(0, top - 1, width, top - 1);
0515: }
0516:
0517: // Paint the month
0518: cellHeight = Math.max(1.0, (height - top) / (double) numWeeks);
0519: int iCellHeight = (int) cellHeight;
0520:
0521: g2d.setColor(XuiUtilities.unsaturateColor(backgroundColor, 55));
0522: g2d.fillRect(0, top, width, height);
0523:
0524: fontOffset = (fm.getHeight() + fm.getAscent()) / 2;
0525:
0526: for (int i = 1; i <= numDays; i++) {
0527: // Calculate the position of the day in the months grid as the first day of
0528: // the month may not be the first day of the week.
0529: int cellX = cellPos % 7;
0530: int cellY = cellPos / 7;
0531:
0532: // Choose the highlight colour
0533: Object oldHint = g2d
0534: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
0535: g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
0536: RenderingHints.VALUE_ANTIALIAS_ON);
0537: Rectangle2D.Double cellRect = new Rectangle2D.Double(cellX
0538: * cellWidth, top + cellY * cellHeight, cellWidth,
0539: cellHeight);
0540: if ((i == highlightedDay) || (i == selectedDay)) {
0541: Color fillColor = ((i == selectedDay) ? ((i == highlightedDay) ? selectedBkColor
0542: .brighter()
0543: : selectedBkColor)
0544: : highlightedBkColor);
0545: GradientPaint gradient = new GradientPaint(0.0F, 0.0F,
0546: fillColor.brighter(), (float) top / 2,
0547: (float) width / 2, fillColor, true);
0548: g2d.setPaint(gradient);
0549: g2d.fill(cellRect);
0550: if (i == selectedDay) {
0551: g2d.setColor(fillColor.darker());
0552: g2d.draw(cellRect);
0553: g2d.setColor(selectedColor);
0554: } else
0555: g2d.setColor(highlightedColor);
0556: } else {
0557: // Shade weekend days
0558: if ((cellX == 0) || (cellX == 6)) {
0559: g2d.setColor(weekendBkColor);
0560: g2d.fill(cellRect);
0561: g2d.setColor(weekendColor);
0562: } else {
0563: g2d.setColor(backgroundColor);
0564: g2d.fill(cellRect);
0565: g2d.setColor(foregroundColor);
0566: }
0567: }
0568: g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
0569: oldHint);
0570:
0571: // Draw the day number
0572: g2d.drawString(new Integer(i).toString(), pad + cellX
0573: * iCellWidth,
0574: (int) (top + cellY * cellHeight + fontOffset));
0575:
0576: // Draw the month name
0577: if (i == 1)
0578: g2d.drawString(monthName, iCellWidth - pad
0579: - fm.stringWidth(monthName) + cellX
0580: * iCellWidth,
0581: (int) (top + cellY * cellHeight + fontOffset));
0582:
0583: // Draw the week number
0584: if (cellX == 0) {
0585: g2d.setColor(headerTextColor);
0586: calendar.set(year, month, i);
0587: String weekNumber = Integer.toString(calendar
0588: .get(calendar.WEEK_OF_YEAR));
0589: g2d.drawString(weekNumber, pad, top + cellY
0590: * iCellHeight + iCellHeight - pad);
0591: }
0592: g2d.setColor(Color.black);
0593: g2d.draw(cellRect);
0594:
0595: if (i == highlightedDay)
0596: appointments = null;
0597: if (appointmentProvider != null) {
0598: XAppointment[] events = appointmentProvider
0599: .getAppointments(calendar);
0600: if (events != null) {
0601: if (i == highlightedDay)
0602: appointments = events;
0603:
0604: int eventHeight = 25;
0605: Shape oldClip = g2d.getClip();
0606: for (int iEvent = 0; iEvent < events.length; iEvent++) {
0607: XAppointment evt = events[iEvent];
0608: double eventY = top + cellY * cellHeight
0609: + fontOffset + iEvent * eventHeight
0610: + pad;
0611: evt.location = new RoundRectangle2D.Double(pad
0612: - 1 + cellX * cellWidth, eventY,
0613: cellWidth - 8, eventHeight, 4, 4);
0614: g2d.setColor(evt.bkColor);
0615: g2d.fill(evt.location);
0616: g2d.setColor(evt.bkColor.darker());
0617: g2d.draw(evt.location);
0618: g2d.setColor(evt.fgColor);
0619: g2d.setClip(evt.location);
0620: g2d.drawString(evt.title, pad + 2 + cellX
0621: * iCellWidth,
0622: (int) (eventY + fontOffset));
0623: g2d.setClip(oldClip);
0624: if (appointmentPainter != null)
0625: appointmentPainter.paintMonthView(g2d, evt,
0626: pad - 1 + cellX * cellWidth,
0627: eventY, cellWidth - 8, eventHeight);
0628: }
0629: }
0630: }
0631:
0632: calendar.roll(Calendar.DATE, 1);
0633: cellPos++;
0634: if (calendar.get(Calendar.DATE) == 1)
0635: break;
0636: }
0637:
0638: g2d.setColor(backgroundColor);
0639: g2d.setColor(Color.black);
0640: g2d.drawRect(0, 0, width - 1, height - 1);
0641:
0642: calendar.set(year, month, day);
0643: }
0644:
0645: /**
0646: * Paint the day view of the calendar
0647: */
0648: public void paintDayView(Graphics2D g2d) {
0649: Object oldHint = g2d
0650: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
0651: g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
0652: RenderingHints.VALUE_ANTIALIAS_ON);
0653:
0654: Color weekendShadow = new Color(240, 240, 240);
0655: Dimension d = getSize();
0656: int width = Math.max(d.width, 2);
0657: int height = Math.max(d.height, 2);
0658:
0659: Font font = getFont();
0660: Font smallFont = font
0661: .deriveFont((float) font.getSize2D() / 1.3F);
0662: FontMetrics fm = g2d.getFontMetrics();
0663: FontMetrics fms = g2d.getFontMetrics(smallFont);
0664: headerHeight = fm.getHeight() * 2;
0665:
0666: int month = calendar.get(Calendar.MONTH);
0667: int year = calendar.get(Calendar.YEAR);
0668: int day = calendar.get(Calendar.DATE);
0669: String dateStr = dateFormat.format(calendar.getTime());
0670: startDay = calendar.get(calendar.DAY_OF_WEEK);
0671: int cellPos = startDay - 1;
0672:
0673: DateFormatSymbols dfs = new DateFormatSymbols();
0674: String monthName = dfs.getShortMonths()[month];
0675:
0676: cellHeight = Math.max(1, height
0677: - (showHeader ? headerHeight : 0));
0678: cellWidth = width;
0679: int iCellWidth = (int) cellWidth;
0680: int iCellHeight = (int) cellHeight;
0681:
0682: int startHour = 7;
0683: int numHoursShown = 12;
0684: double hourHeight = cellHeight / numHoursShown;
0685:
0686: double fontOffset = (headerHeight + fm.getAscent()) / 2;
0687: int pad = 4;
0688: top = 0;
0689: int startY = 0;
0690:
0691: Color headerColor = XuiUtilities.unsaturateColor(
0692: backgroundColor, 50);
0693: Color headerBkColorBright = headerColor.brighter();
0694: Color headerBkColorDarker = headerColor.darker();
0695: Color lineColor = headerColor.darker().darker();
0696: Color headerTextColor = XuiUtilities.unsaturateColor(
0697: foregroundColor, 50);
0698:
0699: // Paint the header with navigation controls and the current date
0700: if (showHeader) {
0701: top = headerHeight;
0702:
0703: GradientPaint gradient = new GradientPaint(0.0F, 0.0F,
0704: headerBkColorBright, (float) top / 4,
0705: (float) width / 2, headerBkColorDarker, true);
0706: g2d.setPaint(gradient);
0707: g2d.fillRect(0, 0, width, top);
0708:
0709: g2d.setColor(XuiUtilities.unsaturateColor(foregroundColor,
0710: 50));
0711:
0712: g2d.setColor(new Color(lineColor.getRed(), lineColor
0713: .getGreen(), lineColor.getBlue(), 128));
0714: g2d.drawLine(0, top - 1, width, headerHeight - 1);
0715:
0716: // Draw the date
0717: g2d.setColor(headerTextColor);
0718: dayNames = dfs.getWeekdays();
0719: g2d.drawString(dayNames[startDay] + ", " + dateStr, 40,
0720: (headerHeight + fm.getAscent()) / 2);
0721: startY = top;
0722: }
0723:
0724: double smallFontOffset = 3 + fm.getLeading() + fms.getAscent();
0725:
0726: int gutterWidth = pad + 2 + fm.stringWidth("00000");
0727: Stroke oldStroke = g2d.getStroke();
0728: BasicStroke fineLine = new BasicStroke(0.1F);
0729: for (int i = 0; i < numHoursShown; i++) {
0730: int hour = startHour + i;
0731:
0732: g2d.setColor(((hour < 8) || (hour > 17)) ? XuiUtilities
0733: .unsaturateColor(backgroundColor, 55)
0734: : backgroundColor);
0735: Rectangle2D.Double hourRect = new Rectangle2D.Double(0, top
0736: + i * hourHeight, width, hourHeight);
0737: g2d.fill(hourRect);
0738: g2d.setColor(backgroundColor.darker());
0739: int y = (int) (top + (1 + i) * hourHeight - 1);
0740: g2d.drawLine(0, y, width, y);
0741: y -= hourHeight / 2;
0742: g2d.setStroke(fineLine);
0743: g2d.drawLine(gutterWidth, y, width, y);
0744: g2d.setStroke(oldStroke);
0745: g2d.setColor(Color.darkGray);
0746:
0747: g2d.drawString(((hour < 10) ? "0" : "")
0748: + Integer.toString(hour), pad, (int) (top + i
0749: * hourHeight + fontOffset));
0750: g2d.setFont(smallFont);
0751: g2d.drawString("00", pad + 2 + fm.stringWidth("00"),
0752: (int) (top + i * hourHeight + smallFontOffset));
0753: g2d.setFont(font);
0754: }
0755:
0756: fontOffset = (fm.getHeight() + fm.getAscent()) / 2;
0757:
0758: // Calculate the position of the day in the months grid as the first day of
0759: // the month may not be the first day of the week.
0760: int cellX = cellPos % 7;
0761: int cellY = cellPos / 7;
0762:
0763: if (appointmentProvider != null) {
0764: appointments = appointmentProvider
0765: .getAppointments(calendar);
0766: int eventHeight = 25;
0767: Shape oldClip = g2d.getClip();
0768: double minuteHeight = hourHeight / 60.0;
0769: for (int iEvent = 0; iEvent < appointments.length; iEvent++) {
0770: XAppointment evt = appointments[iEvent];
0771: double topY = top
0772: + (evt.startTime.get(Calendar.HOUR_OF_DAY) - startHour)
0773: * hourHeight
0774: + evt.startTime.get(Calendar.MINUTE)
0775: * minuteHeight;
0776: double bottomY = top
0777: + (evt.endTime.get(Calendar.HOUR_OF_DAY) - startHour)
0778: * hourHeight + evt.endTime.get(Calendar.MINUTE)
0779: * minuteHeight;
0780: evt.location = new RoundRectangle2D.Double(gutterWidth
0781: + pad, topY, cellWidth - 2 * gutterWidth,
0782: bottomY - topY, 4, 4);
0783: g2d.setColor(evt.bkColor);
0784: g2d.fill(evt.location);
0785: g2d.setColor(evt.bkColor.darker());
0786: g2d.draw(evt.location);
0787: g2d.setColor(evt.fgColor);
0788: g2d.setClip(evt.location);
0789: g2d.drawString(evt.title, pad * 2 + gutterWidth,
0790: (int) (topY + fontOffset));
0791: g2d.setClip(oldClip);
0792: if (appointmentPainter != null)
0793: appointmentPainter.paintDayView(g2d, evt,
0794: gutterWidth + pad, topY, cellWidth - 2
0795: * gutterWidth, bottomY - topY);
0796: }
0797: }
0798:
0799: g2d.setColor(backgroundColor);
0800: if (drawBorder) {
0801: g2d.setColor(Color.black);
0802: g2d.drawRect(0, 0, width - 1, height - 1);
0803: }
0804:
0805: calendar.set(year, month, day);
0806: g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldHint);
0807: }
0808:
0809: /**
0810: * Selects the highlighted date
0811: */
0812: private void setSelection(MouseEvent e) {
0813: selectedDay = highlightedDay;
0814: if ((selectedDay <= 0)
0815: || (selectedDay > calendar
0816: .getActualMaximum(calendar.DAY_OF_MONTH)))
0817: return;
0818:
0819: int month = calendar.get(Calendar.MONTH);
0820: int year = calendar.get(Calendar.YEAR);
0821: int day = calendar.get(Calendar.DATE);
0822: calendar.set(year, month, selectedDay);
0823:
0824: repaint();
0825:
0826: if (listener != null)
0827: listener.setDate(calendar.getTime());
0828:
0829: selectedAppointment = null;
0830: if (appointments != null) {
0831: for (int i = 0; i < appointments.length; i++) {
0832: if (appointments[i].location.contains(e.getPoint())) {
0833: selectedAppointment = appointments[i];
0834: break;
0835: }
0836: }
0837: }
0838: }
0839:
0840: /**
0841: * Highlights the date under the cursor.
0842: * @param e
0843: */
0844: private void showSelection(MouseEvent e) {
0845: int x = e.getX();
0846: int y = e.getY() - top;
0847: highlightedDay = (x / (int) cellWidth + (y / (int) cellHeight) * 7)
0848: - startDay + 1;
0849: repaint(0, oldX, top + oldY, (int) cellWidth,
0850: (int) (cellHeight + 0.5));
0851: oldX = x - x % (int) cellWidth;
0852: oldY = y - y % (int) cellHeight;
0853: repaint(0, oldX, top + oldY, (int) cellWidth,
0854: (int) (cellHeight + 0.5));
0855: }
0856:
0857: /**
0858: * Clear the highlight data
0859: */
0860: private void clearSelection() {
0861: highlightedDay = -1;
0862: repaint(0, oldX, top + oldY, (int) cellWidth,
0863: (int) (cellHeight + 0.5));
0864: }
0865:
0866: public void mouseClicked(MouseEvent e) {
0867: if (!mouseEventInvoked)
0868: setSelection(e);
0869:
0870: mouseEventInvoked = true;
0871: }
0872:
0873: public void mouseEntered(MouseEvent e) {
0874: showSelection(e);
0875: }
0876:
0877: public void mouseExited(MouseEvent e) {
0878: clearSelection();
0879: }
0880:
0881: public void mousePressed(MouseEvent e) {
0882: mouseEventInvoked = false;
0883: }
0884:
0885: public void mouseReleased(MouseEvent e) {
0886: if (!mouseEventInvoked)
0887: setSelection(e);
0888:
0889: mouseEventInvoked = true;
0890: }
0891:
0892: public void mouseMoved(MouseEvent e) {
0893: showSelection(e);
0894: }
0895:
0896: public void mouseDragged(MouseEvent e) {
0897: showSelection(e);
0898: }
0899:
0900: void setDateListener(XDateListener dl) {
0901: listener = dl;
0902: }
0903:
0904: /**
0905: * Get the style asociated with the selected elements
0906: * @return the style name
0907: */
0908: public String getStyleSelected() {
0909: return styleSelected;
0910: }
0911:
0912: /**
0913: * Get the style asociated with the selected elements
0914: * @param newStyle the style name
0915: */
0916: public void setStyleSelected(String newStyle) {
0917: styleSelected = newStyle;
0918: XStyle selectedStyle = styleManager.getStyle(styleSelected);
0919: if (selectedStyle != null) {
0920: selectedColor = selectedStyle
0921: .getStyleAsColor(XStyle.COLOR_FORE);
0922: selectedBkColor = selectedStyle
0923: .getStyleAsColor(XStyle.COLOR_BACK);
0924: }
0925: }
0926:
0927: /**
0928: * Get the style asociated with the weekend element
0929: * @return the style name
0930: */
0931: public String getStyleWeekend() {
0932: return styleWeekend;
0933: }
0934:
0935: /**
0936: * set the style asociated with weekend element
0937: * @param newStyle the style name
0938: */
0939: public void setStyleWeekend(String newStyle) {
0940: styleWeekend = newStyle;
0941: XStyle weekendStyle = styleManager.getStyle(styleWeekend);
0942: if (weekendStyle != null) {
0943: weekendColor = weekendStyle
0944: .getStyleAsColor(XStyle.COLOR_FORE);
0945: weekendBkColor = weekendStyle
0946: .getStyleAsColor(XStyle.COLOR_BACK);
0947: }
0948: repaint();
0949: }
0950:
0951: /**
0952: * Get the style asociated with the highlighted element
0953: * @return the style name
0954: */
0955: public String getStyleHighlighted() {
0956: return styleHighlighted;
0957: }
0958:
0959: /**
0960: * set the style asociated with highlighted element
0961: * @param newStyle the style name
0962: */
0963: public void setStyleHighlighted(String newStyle) {
0964: styleHighlighted = newStyle;
0965: XStyle highlightedStyle = styleManager
0966: .getStyle(styleHighlighted);
0967: if (highlightedStyle != null) {
0968: highlightedColor = highlightedStyle
0969: .getStyleAsColor(XStyle.COLOR_FORE);
0970: highlightedBkColor = highlightedStyle
0971: .getStyleAsColor(XStyle.COLOR_BACK);
0972: }
0973: }
0974:
0975: /**
0976: * Get the style asociated with the normal elements
0977: * @return the style name
0978: */
0979: public String getStyle() {
0980: return basicStyle;
0981: }
0982:
0983: /**
0984: * set the style asociated with the normal elements
0985: * @param newStyle the style name
0986: */
0987: public void setStyle(String newStyle) {
0988: basicStyle = newStyle;
0989: XStyle style = styleManager.getStyle(basicStyle);
0990: if (style != null) {
0991: foregroundColor = style.getStyleAsColor(XStyle.COLOR_FORE);
0992: backgroundColor = style.getStyleAsColor(XStyle.COLOR_BACK);
0993: }
0994: }
0995:
0996: /**
0997: * Set the styles for the date panel
0998: * @param styles the styles in the following order: style, selectedStyle, weekendStyle, highlightStyle, headerStyle, threeDStyle
0999: */
1000: public void setStyles(String[] styles) {
1001: setStyle(styles[0]);
1002: setStyleSelected(styles[1]);
1003: setStyleWeekend(styles[2]);
1004: setStyleHighlighted(styles[3]);
1005: }
1006:
1007: /**
1008: * Show or hide the day names
1009: * @param state true to show the day names
1010: */
1011: public void setShowDayNames(boolean state) {
1012: showDayNames = state;
1013: }
1014:
1015: /**
1016: * Set the style of the weekend elements. The weekend elements are the dates
1017: * that fall on weekends (Saturday and Sunday). This style allowes those
1018: * dates to be shown in an alternative styles, typically with a grayed out
1019: * or less saturated/right background color.
1020: * @param styleName the style name for the weekend dates
1021: */
1022: public void setWeekendStyle(String styleName) {
1023: styles[2] = styleName;
1024: repaint();
1025: }
1026:
1027: /**
1028: * Set the style of the selected date. The selected date is chosen by clicking
1029: * on a date. It is shown in the specified style even if the curosr is moved.
1030: * @param styleName the style name for the selected date
1031: */
1032: public void setSelectedStyle(String styleName) {
1033: styles[1] = styleName;
1034: repaint();
1035: }
1036:
1037: /**
1038: * Set the style of the highlighted date. The highlighted date is is the date
1039: * shown below the curose. Setting this style provides user feedback when the
1040: * mouse moves.
1041: * @param styleName the style name for the highlighted date
1042: */
1043: public void setHighlightStyle(String styleName) {
1044: styles[3] = styleName;
1045: repaint();
1046: }
1047:
1048: /**
1049: * Set the style of the header. The header shows the month, year and the
1050: * navigation buttons. It is painted with a gradient
1051: * @param styleName the style name for the highlighted date
1052: */
1053: public void setHeaderStyle(String styleName) {
1054: styles[4] = styleName;
1055: repaint();
1056: }
1057:
1058: /**
1059: * Set the style of the 3D elements including the navigation buttons
1060: * @param styleName the style name for the highlighted date
1061: */
1062: public void setThreeDStyle(String styleName) {
1063: styles[5] = styleName;
1064: repaint();
1065: }
1066:
1067: /**
1068: * Set the format of the edit field. The format is used in the construction of
1069: * a java.text.SimpleDateFormat instance.
1070: * @param format the new date format
1071: */
1072: public void setFormat(String format) {
1073: dateFormat = new SimpleDateFormat(format);
1074: }
1075:
1076: /**
1077: * Set the style of the 3D elements including the navigation buttons
1078: * @param styleName the style name for the highlighted date
1079: */
1080: public void setDayNames(boolean show) {
1081: showDayNames = show;
1082: }
1083:
1084: /**
1085: * Get the style of the weekend elements. The weekend elements are the dates
1086: * that fall on weekends (Saturday and Sunday). This style allowes those
1087: * dates to be shown in an alternative styles, typically with a grayed out
1088: * or less saturated/right background color.
1089: * @return the style name for the weekend dates
1090: */
1091: public String getWeekendStyle() {
1092: return styles[2];
1093: }
1094:
1095: /**
1096: * Get the style of the selected date. The selected date is chosen by clicking
1097: * on a date. It is shown in the specified style even if the curosr is moved.
1098: * @return the style name for the selected date
1099: */
1100: public String getSelectedStyle() {
1101: return styles[1];
1102: }
1103:
1104: /**
1105: * Get the style of the highlighted date. The highlighted date is is the date
1106: * shown below the curose. Setting this style provides user feedback when the
1107: * mouse moves.
1108: * @return the style name for the highlighted date
1109: */
1110: public String getHighlightStyle() {
1111: return styles[3];
1112: }
1113:
1114: /**
1115: * Get the style of the header. The header shows the month, year and the
1116: * navigation buttons. It is painted with a gradient
1117: * @return the style name for the highlighted date
1118: */
1119: public String getHeaderStyle() {
1120: return styles[4];
1121: }
1122:
1123: /**
1124: * Get the style of the 3D elements including the navigation buttons
1125: * @return the style name for the highlighted date
1126: */
1127: public String getThreeDStyle() {
1128: return styles[5];
1129: }
1130:
1131: /**
1132: * Get the format of the edit field. The format is used in the construction of
1133: * a java.text.SimpleDateFormat instance.
1134: * @return the new date format
1135: */
1136: public String getFormat() {
1137: return ((SimpleDateFormat) dateFormat).toPattern();
1138: }
1139:
1140: /**
1141: * Get the style of the 3D elements including the navigation buttons
1142: * @return the style name for the highlighted date
1143: */
1144: public boolean getDayNames() {
1145: return showDayNames;
1146: }
1147:
1148: public void setText(String s) {
1149: if ((s != null) && (s.length() > 0)) {
1150: Date d = new Date(s);
1151: setDate(d);
1152: }
1153: }
1154:
1155: public String getText() {
1156: return calendar.getTime().toString();
1157: }
1158:
1159: /**
1160: * Get the drawBorder flag value
1161: * @return true if the border is drawn
1162: */
1163: public boolean getDrawBorder() {
1164: return drawBorder;
1165: }
1166:
1167: /**
1168: * Set the drawBorder flag value
1169: * @param b true if the border is drawn
1170: */
1171: public void setDrawBorder(boolean b) {
1172: drawBorder = b;
1173: }
1174: }
|