Source Code Cross Referenced for JXMonthView.java in  » Project-Management » OpenProj » org » jdesktop » swing » calendar » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Project Management » OpenProj » org.jdesktop.swing.calendar 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: JXMonthView.java,v 1.1 2007/08/15 23:28:24 suricate Exp $
0003:         * 
0004:         * This code comes from the dormant jdnc project at https://jdnc.dev.java.net/. It is licensed with the LGPL
0005:         * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 
0006:         * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
0007:         */
0008:        package org.jdesktop.swing.calendar;
0009:
0010:        import java.awt.AWTEvent;
0011:        import java.awt.Color;
0012:        import java.awt.ComponentOrientation;
0013:        import java.awt.Dimension;
0014:        import java.awt.Font;
0015:        import java.awt.FontMetrics;
0016:        import java.awt.Graphics;
0017:        import java.awt.Graphics2D;
0018:        import java.awt.Insets;
0019:        import java.awt.Rectangle;
0020:        import java.awt.RenderingHints;
0021:        import java.awt.event.ActionEvent;
0022:        import java.awt.event.ActionListener;
0023:        import java.awt.event.MouseEvent;
0024:        import java.text.SimpleDateFormat;
0025:        import java.util.Calendar;
0026:        import java.util.Date;
0027:        import java.util.TimeZone;
0028:
0029:        import javax.swing.JComponent;
0030:        import javax.swing.Timer;
0031:        import javax.swing.UIManager;
0032:        import javax.swing.border.Border;
0033:
0034:        /**
0035:         * Component that displays a month calendar which can be used to select a day
0036:         * or range of days.  By default the <code>JXMonthView</code> will display a
0037:         * single calendar using the current month and year, using
0038:         * <code>Calendar.SUNDAY</code> as the first day of the week.
0039:         * <p> 
0040:         * The <code>JXMonthView</code> can be configured to display more than one
0041:         * calendar at a time by calling
0042:         * <code>setPreferredCalCols</code>/<code>setPreferredCalRows</code>.  These
0043:         * methods will set the preferred number of calendars to use in each
0044:         * column/row.  As these values change, the <code>Dimension</code> returned
0045:         * from <code>getMinimumSize</code> and <code>getPreferredSize</code> will
0046:         * be updated.  The following example shows how to create a 2x2 view which is
0047:         * contained within a <code>JFrame</code>:
0048:         * <pre>
0049:         *     JXMonthView monthView = new JXMonthView();
0050:         *     monthView.setPreferredCols(2);
0051:         *     monthView.setPreferredRows(2);
0052:         *
0053:         *     JFrame frame = new JFrame();
0054:         *     frame.getContentPane().add(monthView);
0055:         *     frame.pack();
0056:         *     frame.setVisible(true);
0057:         * </pre>
0058:         * <p>
0059:         * <code>JXMonthView</code> can be further configured to allow any day of the
0060:         * week to be considered the first day of the week.  Character
0061:         * representation of those days may also be set by providing an array of
0062:         * strings.
0063:         * <pre>
0064:         *    monthView.setFirstDayOfWeek(Calendar.MONDAY);
0065:         *    monthView.setDaysOfTheWeek(
0066:         *            new String[]{"S", "M", "T", "W", "R", "F", "S"});
0067:         * </pre>
0068:         * <p>
0069:         * This component supports flagging days.  These flagged days, which must be
0070:         * provided in sorted order, are displayed in a bold font.  This can be used to
0071:         * inform the user of such things as scheduled appointment.
0072:         * <pre>
0073:         *    // Create some dates that we want to flag as being important.
0074:         *    Calendar cal1 = Calendar.getInstance();
0075:         *    cal1.set(2004, 1, 1);
0076:         *    Calendar cal2 = Calendar.getInstance();
0077:         *    cal2.set(2004, 1, 5);
0078:         *
0079:         *    long[] flaggedDates = new long[] {
0080:         *        cal1.getTimeInMillis(),
0081:         *        cal2.getTimeInMillis(),
0082:         *        System.currentTimeMillis()
0083:         *    };
0084:         *
0085:         *    // Sort them in ascending order.
0086:         *    java.util.Arrays.sort(flaggedDates);
0087:         *    monthView.setFlaggedDates(flaggedDates);
0088:         * </pre>
0089:         * Applications may have the need to allow users to select different ranges of
0090:         * dates.  There are four modes of selection that are supported, single,
0091:         * multiple, week and no selection.  Once a selection is made an action is
0092:         * fired, with exception of the no selection mode, to inform listeners that
0093:         * selection has changed.
0094:         * <pre>
0095:         *    // Change the selection mode to select full weeks.
0096:         *    monthView.setSelectionMode(JXMonthView.WEEK_SELECTION);
0097:         *
0098:         *    // Add an action listener that will be notified when the user
0099:         *    // changes selection via the mouse.
0100:         *    monthView.addActionListener(new ActionListener() {
0101:         *        public void actionPerformed(ActionEvent e) {
0102:         *            System.out.println(
0103:         *                ((JXMonthView)e.getSource()).getSelectedDateSpan());
0104:         *        }
0105:         *    });
0106:         * </pre>
0107:         *
0108:         * @author Joshua Outwater
0109:         * @version  $Revision: 1.1 $
0110:         */
0111:        public class JXMonthView extends JComponent {
0112:            /** Mode that disallows selection of days from the calendar. */
0113:            public static final int NO_SELECTION = 0;
0114:            /** Mode that allows for selection of a single day. */
0115:            public static final int SINGLE_SELECTION = 1;
0116:            /** Mode that allows for selecting of multiple consecutive days. */
0117:            public static final int MULTIPLE_SELECTION = 2;
0118:            /**
0119:             * Mode where selections consisting of more than 7 days will
0120:             * snap to a full week.
0121:             */
0122:            public static final int WEEK_SELECTION = 3;
0123:
0124:            /**
0125:             * Insets used in determining the rectangle for the month string
0126:             * background.
0127:             */
0128:            protected Insets _monthStringInsets = new Insets(0, 8, 0, 8);
0129:
0130:            private static final int MONTH_DROP_SHADOW = 1;
0131:            private static final int MONTH_LINE_DROP_SHADOW = 2;
0132:            private static final int WEEK_DROP_SHADOW = 4;
0133:
0134:            private int _boxPaddingX = 3;
0135:            private int _boxPaddingY = 3;
0136:            private static final int CALENDAR_SPACING = 10;
0137:            private static final int DAYS_IN_WEEK = 7;
0138:            private static final int MONTHS_IN_YEAR = 12;
0139:
0140:            /**
0141:             * Keeps track of the first date we are displaying.  We use this as a
0142:             * restore point for the calendar.
0143:             */
0144:            private long _firstDisplayedDate;
0145:            private int _firstDisplayedMonth;
0146:            private int _firstDisplayedYear;
0147:
0148:            private long _lastDisplayedDate;
0149:            private Font _derivedFont;
0150:
0151:            /** Beginning date of selection.  -1 if no date is selected. */
0152:            private long _startSelectedDate = -1;
0153:
0154:            /** End date of selection.  -1 if no date is selected. */
0155:            private long _endSelectedDate = -1;
0156:
0157:            /** For multiple selection we need to record the date we pivot around. */
0158:            private long _pivotDate = -1;
0159:
0160:            /** Bounds of the selected date including its visual border. */
0161:            private Rectangle _selectedDateRect = new Rectangle();
0162:
0163:            /** The number of calendars able to be displayed horizontally. */
0164:            private int _numCalCols = 1;
0165:
0166:            /** The number of calendars able to be displayed vertically. */
0167:            private int _numCalRows = 1;
0168:
0169:            private int _minCalCols = 1;
0170:            private int _minCalRows = 1;
0171:            private long _today;
0172:            private long[] _flaggedDates;
0173:            private int _selectionMode = SINGLE_SELECTION;
0174:            private int _boxHeight;
0175:            private int _boxWidth;
0176:            private int _calendarWidth;
0177:            private int _calendarHeight;
0178:            private int _firstDayOfWeek = Calendar.SUNDAY;
0179:            private int _startX;
0180:            private int _startY;
0181:            private int _dropShadowMask = MONTH_DROP_SHADOW;
0182:            private boolean _dirty = false;
0183:            private boolean _antiAlias = false;
0184:            private boolean _ltr;
0185:            private boolean _asKirkWouldSay_FIRE = false;
0186:            private Calendar _cal;
0187:            private String[] _daysOfTheWeek;
0188:            private static String[] _monthsOfTheYear;
0189:            private Dimension _dim = new Dimension();
0190:            private Rectangle _bounds = new Rectangle();
0191:            private Rectangle _dirtyRect = new Rectangle();
0192:            private Color _todayBackgroundColor;
0193:            private Color _monthStringBackground = Color.LIGHT_GRAY;
0194:            private Color _selectedBackground = Color.LIGHT_GRAY;
0195:            private SimpleDateFormat _dayOfMonthFormatter = new SimpleDateFormat(
0196:                    "d");
0197:            private String _actionCommand = "selectionChanged";
0198:            private Timer _todayTimer = null;
0199:
0200:            /**
0201:             * Create a new instance of the <code>JXMonthView</code> class using the
0202:             * month and year of the current day as the first date to display.
0203:             */
0204:            public JXMonthView() {
0205:                this (new Date().getTime());
0206:            }
0207:
0208:            /**
0209:             * Create a new instance of the <code>JXMonthView</code> class using the
0210:             * month and year from <code>initialTime</code> as the first date to
0211:             * display.
0212:             *
0213:             * @param initialTime The first month to display.
0214:             */
0215:            public JXMonthView(long initialTime) {
0216:                super ();
0217:
0218:                _ltr = getComponentOrientation().isLeftToRight();
0219:
0220:                // Set up calendar instance.
0221:                _cal = Calendar.getInstance(getLocale());
0222:                _cal.setFirstDayOfWeek(_firstDayOfWeek);
0223:
0224:                // Keep track of today.
0225:                _cal.set(Calendar.HOUR_OF_DAY, 0);
0226:                _cal.set(Calendar.MINUTE, 0);
0227:                _cal.set(Calendar.SECOND, 0);
0228:                _cal.set(Calendar.MILLISECOND, 0);
0229:                _today = _cal.getTimeInMillis();
0230:
0231:                _cal.setTimeInMillis(initialTime);
0232:                setFirstDisplayedDate(_cal.getTimeInMillis());
0233:
0234:                // Get string representation of the months of the year.
0235:                _cal.set(Calendar.MONTH, _cal.getMinimum(Calendar.MONTH));
0236:                _cal.set(Calendar.DAY_OF_MONTH, _cal
0237:                        .getActualMinimum(Calendar.DAY_OF_MONTH));
0238:                _monthsOfTheYear = new String[MONTHS_IN_YEAR];
0239:                SimpleDateFormat fullMonthNameFormatter = new SimpleDateFormat(
0240:                        "MMMM");
0241:                for (int i = 0; i < MONTHS_IN_YEAR; i++) {
0242:                    _monthsOfTheYear[i] = fullMonthNameFormatter.format(_cal
0243:                            .getTime());
0244:                    _cal.add(Calendar.MONTH, 1);
0245:                }
0246:
0247:                setOpaque(true);
0248:                setBackground(Color.WHITE);
0249:                setFont(new Font("Dialog", Font.PLAIN, 12));
0250:                _todayBackgroundColor = getForeground();
0251:
0252:                // Restore original time value.
0253:                _cal.setTimeInMillis(_firstDisplayedDate);
0254:
0255:                enableEvents(AWTEvent.MOUSE_EVENT_MASK);
0256:                enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
0257:
0258:                updateUI();
0259:            }
0260:
0261:            /**
0262:             * Resets the UI property to a value from the current look and feel.
0263:             */
0264:            public void updateUI() {
0265:                super .updateUI();
0266:
0267:                String[] daysOfTheWeek = (String[]) UIManager
0268:                        .get("JXMonthView.daysOfTheWeek");
0269:                // Use some meaningful default if the UIManager doesn't have anything
0270:                // for us.
0271:                if (daysOfTheWeek == null) {
0272:                    daysOfTheWeek = new String[] { "S", "M", "T", "W", "T",
0273:                            "F", "S" };
0274:                }
0275:                setDaysOfTheWeek(daysOfTheWeek);
0276:
0277:                Color color = UIManager
0278:                        .getColor("JXMonthView.monthStringBackground");
0279:                // Use some meaningful default if the UIManager doesn't have anything
0280:                // for us.
0281:                if (color == null) {
0282:                    color = Color.LIGHT_GRAY;
0283:                }
0284:                setMonthStringBackground(color);
0285:
0286:                color = UIManager.getColor("JXMonthView.selectedBackground");
0287:                // Use some meaningful default if the UIManager doesn't have anything
0288:                // for us.
0289:                if (color == null) {
0290:                    color = Color.LIGHT_GRAY;
0291:                }
0292:                setSelectedBackground(color);
0293:            }
0294:
0295:            /**
0296:             * Returns the first displayed date.
0297:             *
0298:             * @return long The first displayed date.
0299:             */
0300:            public long getFirstDisplayedDate() {
0301:                return _firstDisplayedDate;
0302:            }
0303:
0304:            /**
0305:             * Set the first displayed date.  We only use the month and year of
0306:             * this date.  The <code>Calendar.DAY_OF_MONTH</code> field is reset to
0307:             * 1 and all other fields, with exception of the year and month ,
0308:             * are reset to 0.
0309:             *
0310:             * @param date The first displayed date.
0311:             */
0312:            public void setFirstDisplayedDate(long date) {
0313:                long old = _firstDisplayedDate;
0314:
0315:                _cal.setTimeInMillis(date);
0316:                _cal.set(Calendar.DAY_OF_MONTH, 1);
0317:                _cal.set(Calendar.HOUR_OF_DAY, 0);
0318:                _cal.set(Calendar.MINUTE, 0);
0319:                _cal.set(Calendar.SECOND, 0);
0320:                _cal.set(Calendar.MILLISECOND, 0);
0321:
0322:                _firstDisplayedDate = _cal.getTimeInMillis();
0323:                _firstDisplayedMonth = _cal.get(Calendar.MONTH);
0324:                _firstDisplayedYear = _cal.get(Calendar.YEAR);
0325:
0326:                calculateLastDisplayedDate();
0327:                firePropertyChange("firstDisplayedDate", old,
0328:                        _firstDisplayedDate);
0329:
0330:                repaint();
0331:            }
0332:
0333:            /**
0334:             * Returns the last date able to be displayed.  For example, if the last
0335:             * visible month was April the time returned would be April 30, 23:59:59.
0336:             *
0337:             * @return long The last displayed date.
0338:             */
0339:            public long getLastDisplayedDate() {
0340:                return _lastDisplayedDate;
0341:            }
0342:
0343:            private void calculateLastDisplayedDate() {
0344:                long old = _lastDisplayedDate;
0345:
0346:                _cal.setTimeInMillis(_firstDisplayedDate);
0347:
0348:                // Figure out the last displayed date.
0349:                _cal.add(Calendar.MONTH, ((_numCalCols * _numCalRows) - 1));
0350:                _cal.set(Calendar.DAY_OF_MONTH, _cal
0351:                        .getActualMaximum(Calendar.DAY_OF_MONTH));
0352:                _cal.set(Calendar.HOUR_OF_DAY, 23);
0353:                _cal.set(Calendar.MINUTE, 59);
0354:                _cal.set(Calendar.SECOND, 59);
0355:
0356:                _lastDisplayedDate = _cal.getTimeInMillis();
0357:
0358:                firePropertyChange("lastDisplayedDate", old, _lastDisplayedDate);
0359:            }
0360:
0361:            /**
0362:             * Moves the <code>date</code> into the visible region of the calendar.
0363:             * If the date is greater than the last visible date it will become the
0364:             * last visible date.  While if it is less than the first visible date
0365:             * it will become the first visible date.
0366:             *
0367:             * @param date Date to make visible.
0368:             */
0369:            public void ensureDateVisible(long date) {
0370:                if (date < _firstDisplayedDate) {
0371:                    setFirstDisplayedDate(date);
0372:                } else if (date > _lastDisplayedDate) {
0373:                    _cal.setTimeInMillis(date);
0374:                    int month = _cal.get(Calendar.MONTH);
0375:                    int year = _cal.get(Calendar.YEAR);
0376:
0377:                    _cal.setTimeInMillis(_lastDisplayedDate);
0378:                    int lastMonth = _cal.get(Calendar.MONTH);
0379:                    int lastYear = _cal.get(Calendar.YEAR);
0380:
0381:                    int diffMonths = month - lastMonth
0382:                            + ((year - lastYear) * 12);
0383:
0384:                    _cal.setTimeInMillis(_firstDisplayedDate);
0385:                    _cal.add(Calendar.MONTH, diffMonths);
0386:                    setFirstDisplayedDate(_cal.getTimeInMillis());
0387:                }
0388:
0389:                if (_startSelectedDate != -1 || _endSelectedDate != -1) {
0390:                    calculateDirtyRectForSelection();
0391:                }
0392:            }
0393:
0394:            /**
0395:             * Returns a date span of the selected dates.  The result will be null if
0396:             * no dates are selected.
0397:             */
0398:            public DateSpan getSelectedDateSpan() {
0399:                DateSpan result = null;
0400:                if (_startSelectedDate != -1) {
0401:                    result = new DateSpan(new Date(_startSelectedDate),
0402:                            new Date(_endSelectedDate));
0403:                }
0404:                return result;
0405:            }
0406:
0407:            /**
0408:             * Selects the dates in the DateSpan.  This method will not change the
0409:             * initial date displayed so the caller must update this if necessary.
0410:             * If we are in SINGLE_SELECTION mode only the start time from the DateSpan
0411:             * will be used.  If we are in WEEK_SELECTION mode the span will be
0412:             * modified to be valid if necessary.
0413:             *
0414:             * @param dateSpan DateSpan defining the selected dates.  Passing 
0415:             * <code>null</code> will clear the selection.
0416:             */
0417:            public void setSelectedDateSpan(DateSpan dateSpan) {
0418:                DateSpan oldSpan = null;
0419:                if (_startSelectedDate != -1 && _endSelectedDate != -1) {
0420:                    oldSpan = new DateSpan(_startSelectedDate, _endSelectedDate);
0421:                }
0422:
0423:                if (dateSpan == null) {
0424:                    _startSelectedDate = -1;
0425:                    _endSelectedDate = -1;
0426:                } else {
0427:                    _cal.setTimeInMillis(dateSpan.getStart());
0428:                    _cal.set(Calendar.HOUR_OF_DAY, 0);
0429:                    _cal.set(Calendar.MINUTE, 0);
0430:                    _cal.set(Calendar.SECOND, 0);
0431:                    _cal.set(Calendar.MILLISECOND, 0);
0432:                    _startSelectedDate = _cal.getTimeInMillis();
0433:
0434:                    if (_selectionMode == SINGLE_SELECTION) {
0435:                        _endSelectedDate = _startSelectedDate;
0436:                    } else {
0437:                        _cal.setTimeInMillis(dateSpan.getEnd());
0438:                        _cal.set(Calendar.HOUR_OF_DAY, 0);
0439:                        _cal.set(Calendar.MINUTE, 0);
0440:                        _cal.set(Calendar.SECOND, 0);
0441:                        _cal.set(Calendar.MILLISECOND, 0);
0442:                        _endSelectedDate = _cal.getTimeInMillis();
0443:
0444:                        if (_selectionMode == WEEK_SELECTION) {
0445:                            // Make sure if we are over 7 days we span full weeks.
0446:                            _cal.setTimeInMillis(_startSelectedDate);
0447:                            int count = 1;
0448:                            while (_cal.getTimeInMillis() < _endSelectedDate) {
0449:                                _cal.add(Calendar.DAY_OF_MONTH, 1);
0450:                                count++;
0451:                            }
0452:                            if (count > 7) {
0453:                                // Make sure start date is on the beginning of the
0454:                                // week.
0455:                                _cal.setTimeInMillis(_startSelectedDate);
0456:                                int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
0457:                                if (dayOfWeek != _firstDayOfWeek) {
0458:                                    // Move the start date back to the first day of the
0459:                                    // week.
0460:                                    int daysFromStart = dayOfWeek
0461:                                            - _firstDayOfWeek;
0462:                                    if (daysFromStart < 0) {
0463:                                        daysFromStart += DAYS_IN_WEEK;
0464:                                    }
0465:                                    _cal.add(Calendar.DAY_OF_MONTH,
0466:                                            -daysFromStart);
0467:                                    count += daysFromStart;
0468:                                    _startSelectedDate = _cal.getTimeInMillis();
0469:                                }
0470:
0471:                                // Make sure we have full weeks.  Otherwise modify the
0472:                                // end date.
0473:                                int remainder = count % 7;
0474:                                if (remainder != 0) {
0475:                                    _cal.setTimeInMillis(_endSelectedDate);
0476:                                    _cal.add(Calendar.DAY_OF_MONTH,
0477:                                            (7 - remainder));
0478:                                    _endSelectedDate = _cal.getTimeInMillis();
0479:                                }
0480:                            }
0481:                        }
0482:                    }
0483:                    // Restore original time value.
0484:                    _cal.setTimeInMillis(_firstDisplayedDate);
0485:                }
0486:
0487:                repaint(_dirtyRect);
0488:                calculateDirtyRectForSelection();
0489:                repaint(_dirtyRect);
0490:
0491:                // Fire property change.
0492:                firePropertyChange("selectedDates", oldSpan, dateSpan);
0493:            }
0494:
0495:            /**
0496:             * Returns the current selection mode for this JXMonthView.
0497:             *
0498:             * @return int Selection mode.
0499:             */
0500:            public int getSelectionMode() {
0501:                return _selectionMode;
0502:            }
0503:
0504:            /**
0505:             * Set the selection mode for this JXMonthView.
0506:             *
0507:             * @throws IllegalArgumentException
0508:             */
0509:            public void setSelectionMode(int mode)
0510:                    throws IllegalArgumentException {
0511:                if (mode != SINGLE_SELECTION && mode != MULTIPLE_SELECTION
0512:                        && mode != WEEK_SELECTION && mode != NO_SELECTION) {
0513:                    throw new IllegalArgumentException(mode
0514:                            + " is not a valid selection mode");
0515:                }
0516:                _selectionMode = mode;
0517:            }
0518:
0519:            /**
0520:             * An array of longs defining days that should be flagged.  This array is
0521:             * assumed to be in sorted order from least to greatest.
0522:             */
0523:            public void setFlaggedDates(long[] flaggedDates) {
0524:                _flaggedDates = flaggedDates;
0525:
0526:                if (_flaggedDates == null) {
0527:                    repaint();
0528:                    return;
0529:                }
0530:
0531:                // Loop through the flaggedDates and set the hour, minute, seconds and
0532:                // milliseconds to 0 so we can compare times later.
0533:                for (int i = 0; i < _flaggedDates.length; i++) {
0534:                    _cal.setTimeInMillis(_flaggedDates[i]);
0535:
0536:                    // We only want to compare the day, month and year
0537:                    // so reset all other values to 0.
0538:                    _cal.set(Calendar.HOUR_OF_DAY, 0);
0539:                    _cal.set(Calendar.MINUTE, 0);
0540:                    _cal.set(Calendar.SECOND, 0);
0541:                    _cal.set(Calendar.MILLISECOND, 0);
0542:
0543:                    _flaggedDates[i] = _cal.getTimeInMillis();
0544:                }
0545:
0546:                // Restore the time.
0547:                _cal.setTimeInMillis(_firstDisplayedDate);
0548:
0549:                repaint();
0550:            }
0551:
0552:            /**
0553:             * Returns the padding used between days in the calendar.
0554:             */
0555:            public int getBoxPaddingX() {
0556:                return _boxPaddingX;
0557:            }
0558:
0559:            /**
0560:             * Sets the number of pixels used to pad the left and right side of a day.
0561:             * The padding is applied to both sides of the days.  Therefore, if you
0562:             * used the padding value of 3, the number of pixels between any two days
0563:             * would be 6.
0564:             */
0565:            public void setBoxPaddingX(int _boxPaddingX) {
0566:                this ._boxPaddingX = _boxPaddingX;
0567:                _dirty = true;
0568:            }
0569:
0570:            /**
0571:             * Returns the padding used above and below days in the calendar.
0572:             */
0573:            public int getBoxPaddingY() {
0574:                return _boxPaddingY;
0575:            }
0576:
0577:            /**
0578:             * Sets the number of pixels used to pad the top and bottom of a day.
0579:             * The padding is applied to both the top and bottom of a day.  Therefore,
0580:             * if you used the padding value of 3, the number of pixels between any
0581:             * two days would be 6.
0582:             */
0583:            public void setBoxPaddingY(int _boxPaddingY) {
0584:                this ._boxPaddingY = _boxPaddingY;
0585:                _dirty = true;
0586:            }
0587:
0588:            /**
0589:             * Sets the single character representation for each day of the
0590:             * week.  For this method the first days of the week days[0] is assumed to
0591:             * be <code>Calendar.SUNDAY</code>.
0592:             *
0593:             * @throws IllegalArgumentException if <code>days.length</code> != 7
0594:             * @throws NullPointerException if <code>days</code> == null
0595:             */
0596:            public void setDaysOfTheWeek(String[] days)
0597:                    throws IllegalArgumentException, NullPointerException {
0598:                if (days == null) {
0599:                    throw new NullPointerException("Array of days is null.");
0600:                } else if (days.length != 7) {
0601:                    throw new IllegalArgumentException(
0602:                            "Array of days is not of length 7 as expected.");
0603:                }
0604:                _daysOfTheWeek = days;
0605:            }
0606:
0607:            /**
0608:             * Returns the single character representation for each day of the
0609:             * week.
0610:             *
0611:             * @return Single character representation for the days of the week
0612:             */
0613:            public String[] getDaysOfTheWeek() {
0614:                String[] days = new String[7];
0615:                System.arraycopy(_daysOfTheWeek, 0, days, 0, 7);
0616:                return days;
0617:            }
0618:
0619:            /**
0620:             * Gets what the first day of the week is; e.g.,
0621:             * <code>Calendar.SUNDAY</code> in the U.S., <code>Calendar.MONDAY</code>
0622:             * in France.
0623:             *
0624:             * @return int The first day of the week.
0625:             */
0626:            public int getFirstDayOfWeek() {
0627:                return _firstDayOfWeek;
0628:            }
0629:
0630:            /**
0631:             * Sets what the first day of the week is; e.g.,
0632:             * <code>Calendar.SUNDAY</code> in US, <code>Calendar.MONDAY</code>
0633:             * in France.
0634:             *
0635:             * @param firstDayOfWeek The first day of the week.
0636:             *
0637:             * @see java.util.Calendar
0638:             */
0639:            public void setFirstDayOfWeek(int firstDayOfWeek) {
0640:                if (firstDayOfWeek == _firstDayOfWeek) {
0641:                    return;
0642:                }
0643:
0644:                _firstDayOfWeek = firstDayOfWeek;
0645:                _cal.setFirstDayOfWeek(_firstDayOfWeek);
0646:
0647:                repaint();
0648:            }
0649:
0650:            /**
0651:             * Gets the time zone.
0652:             *
0653:             * @return The <code>TimeZone</code> used by the <code>JXMonthView</code>.
0654:             */
0655:            public TimeZone getTimeZone() {
0656:                return _cal.getTimeZone();
0657:            }
0658:
0659:            /**
0660:             * Sets the time zone with the given time zone value.
0661:             *
0662:             * @param tz The <code>TimeZone</code>.
0663:             */
0664:            public void setTimeZone(TimeZone tz) {
0665:                _cal.setTimeZone(tz);
0666:            }
0667:
0668:            /**
0669:             * Returns true if anti-aliased text is enabled for this component, false
0670:             * otherwise.
0671:             *
0672:             * @return boolean <code>true</code> if anti-aliased text is enabled,
0673:             * <code>false</code> otherwise.
0674:             */
0675:            public boolean getAntialiased() {
0676:                return _antiAlias;
0677:            }
0678:
0679:            /**
0680:             * Turns on/off anti-aliased text for this component.
0681:             *
0682:             * @param antiAlias <code>true</code> for anti-aliased text,
0683:             * <code>false</code> to turn it off.
0684:             */
0685:            public void setAntialiased(boolean antiAlias) {
0686:                if (_antiAlias == antiAlias) {
0687:                    return;
0688:                }
0689:                _antiAlias = antiAlias;
0690:                repaint();
0691:            }
0692:
0693:            /**
0694:            public void setDropShadowMask(int mask) {
0695:                _dropShadowMask = mask;
0696:                repaint();
0697:            }
0698:             */
0699:
0700:            /**
0701:             * Returns the selected background color.
0702:             *
0703:             * @return the selected background color.
0704:             */
0705:            public Color getSelectedBackground() {
0706:                return _selectedBackground;
0707:            }
0708:
0709:            /**
0710:             * Sets the selected background color to <code>c</code>.  The default color
0711:             * is <code>Color.LIGHT_GRAY</code>.
0712:             *
0713:             * @param c Selected background.
0714:             */
0715:            public void setSelectedBackground(Color c) {
0716:                _selectedBackground = c;
0717:            }
0718:
0719:            /**
0720:             * Returns the color used when painting the today background.
0721:             *
0722:             * @return Color Color
0723:             */
0724:            public Color getTodayBackground() {
0725:                return _todayBackgroundColor;
0726:            }
0727:
0728:            /**
0729:             * Sets the color used to draw the bounding box around today.  The default
0730:             * is the background of the <code>JXMonthView</code> component.
0731:             */
0732:            public void setTodayBackground(Color c) {
0733:                _todayBackgroundColor = c;
0734:                repaint();
0735:            }
0736:
0737:            /**
0738:             * Returns the color used to paint the month string background.
0739:             *
0740:             * @return Color Color.
0741:             */
0742:            public Color getMonthStringBackground() {
0743:                return _monthStringBackground;
0744:            }
0745:
0746:            /**
0747:             * Sets the color used to draw the background of the month string.  The
0748:             * default is <code>Color.LIGHT_GRAY</code>.
0749:             */
0750:            public void setMonthStringBackground(Color c) {
0751:                _monthStringBackground = c;
0752:                repaint();
0753:            }
0754:
0755:            /**
0756:             * Returns a copy of the insets used to paint the month string background.
0757:             *
0758:             * @return Insets Month string insets.
0759:             */
0760:            public Insets getMonthStringInsets() {
0761:                return (Insets) _monthStringInsets.clone();
0762:            }
0763:
0764:            /**
0765:             * Insets used to modify the width/height when painting the background
0766:             * of the month string area.
0767:             *
0768:             * @param insets Insets
0769:             */
0770:            public void setMonthStringInsets(Insets insets) {
0771:                if (insets == null) {
0772:                    _monthStringInsets.top = 0;
0773:                    _monthStringInsets.left = 0;
0774:                    _monthStringInsets.bottom = 0;
0775:                    _monthStringInsets.right = 0;
0776:                } else {
0777:                    _monthStringInsets.top = insets.top;
0778:                    _monthStringInsets.left = insets.left;
0779:                    _monthStringInsets.bottom = insets.bottom;
0780:                    _monthStringInsets.right = insets.right;
0781:                }
0782:                repaint();
0783:            }
0784:
0785:            /**
0786:             * Returns the preferred number of columns to paint calendars in.
0787:             *
0788:             * @return int Columns of calendars.
0789:             */
0790:            public int getPreferredCols() {
0791:                return _minCalCols;
0792:            }
0793:
0794:            /**
0795:             * The preferred number of columns to paint calendars.
0796:             *
0797:             * @param cols The number of columns of calendars.
0798:             */
0799:            public void setPreferredCols(int cols) {
0800:                if (cols <= 0) {
0801:                    return;
0802:                }
0803:                _minCalCols = cols;
0804:                _dirty = true;
0805:                revalidate();
0806:                repaint();
0807:            }
0808:
0809:            /**
0810:             * Returns the preferred number of rows to paint calendars in.
0811:             *
0812:             * @return int Rows of calendars.
0813:             */
0814:            public int getPreferredRows() {
0815:                return _minCalRows;
0816:            }
0817:
0818:            /**
0819:             * Sets the preferred number of rows to paint calendars.
0820:             *
0821:             * @param rows The number of rows of calendars.
0822:             */
0823:            public void setPreferredRows(int rows) {
0824:                if (rows <= 0) {
0825:                    return;
0826:                }
0827:                _minCalRows = rows;
0828:                _dirty = true;
0829:                revalidate();
0830:                repaint();
0831:            }
0832:
0833:            private void updateIfNecessary() {
0834:                if (_dirty) {
0835:                    update();
0836:                    _dirty = false;
0837:                }
0838:            }
0839:
0840:            /**
0841:             * Calculates size information necessary for laying out the month view.
0842:             */
0843:            private void update() {
0844:                // Loop through year and get largest representation of the month.
0845:                // Keep track of the longest month so we can loop through it to
0846:                // determine the width of a date box.
0847:                int currDays;
0848:                int longestMonth = 0;
0849:                int daysInLongestMonth = 0;
0850:
0851:                int currWidth;
0852:                int longestMonthWidth = 0;
0853:
0854:                // We use a bold font for figuring out size constraints since
0855:                // it's larger and flaggedDates will be noted in this style.
0856:                _derivedFont = getFont().deriveFont(Font.BOLD);
0857:                FontMetrics fm = getFontMetrics(_derivedFont);
0858:
0859:                _cal.set(Calendar.MONTH, _cal.getMinimum(Calendar.MONTH));
0860:                _cal.set(Calendar.DAY_OF_MONTH, _cal
0861:                        .getActualMinimum(Calendar.DAY_OF_MONTH));
0862:                for (int i = 0; i < _cal.getMaximum(Calendar.MONTH); i++) {
0863:                    currWidth = fm.stringWidth(_monthsOfTheYear[i]);
0864:                    if (currWidth > longestMonthWidth) {
0865:                        longestMonthWidth = currWidth;
0866:                    }
0867:                    currDays = _cal.getActualMaximum(Calendar.DAY_OF_MONTH);
0868:                    if (currDays > daysInLongestMonth) {
0869:                        longestMonth = _cal.get(Calendar.MONTH);
0870:                        daysInLongestMonth = currDays;
0871:                    }
0872:                    _cal.add(Calendar.MONTH, 1);
0873:                }
0874:
0875:                // Loop through longest month and get largest representation of the day
0876:                // of the month.
0877:                _cal.set(Calendar.MONTH, longestMonth);
0878:                _cal.set(Calendar.DAY_OF_MONTH, _cal
0879:                        .getActualMinimum(Calendar.DAY_OF_MONTH));
0880:                _boxHeight = fm.getHeight();
0881:                for (int i = 0; i < daysInLongestMonth; i++) {
0882:                    currWidth = fm.stringWidth(_dayOfMonthFormatter.format(_cal
0883:                            .getTime()));
0884:                    if (currWidth > _boxWidth) {
0885:                        _boxWidth = currWidth;
0886:                    }
0887:                    _cal.add(Calendar.DAY_OF_MONTH, 1);
0888:                }
0889:
0890:                // Modify _boxWidth if month string is longer
0891:                _dim.width = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK;
0892:                if (_dim.width < longestMonthWidth) {
0893:                    double diff = longestMonthWidth - _dim.width;
0894:                    _boxWidth += Math.ceil(diff / (double) DAYS_IN_WEEK);
0895:                    _dim.width = (_boxWidth + (2 * _boxPaddingX))
0896:                            * DAYS_IN_WEEK;
0897:                }
0898:
0899:                // Keep track of calendar width and height for use later.
0900:                _calendarWidth = (_boxWidth + (2 * _boxPaddingX))
0901:                        * DAYS_IN_WEEK;
0902:                _calendarHeight = (_boxPaddingY + _boxHeight + _boxPaddingY) * 8;
0903:
0904:                // Calculate minimum width/height for the component.
0905:                _dim.height = (_calendarHeight * _minCalRows)
0906:                        + (CALENDAR_SPACING * (_minCalRows - 1));
0907:
0908:                _dim.width = (_calendarWidth * _minCalCols)
0909:                        + (CALENDAR_SPACING * (_minCalCols - 1));
0910:
0911:                // Add insets to the dimensions.
0912:                Insets insets = getInsets();
0913:                _dim.width += insets.left + insets.right;
0914:                _dim.height += insets.top + insets.bottom;
0915:
0916:                // Restore calendar.
0917:                _cal.setTimeInMillis(_firstDisplayedDate);
0918:            }
0919:
0920:            private void updateToday() {
0921:                // Update _today.
0922:                _cal.setTimeInMillis(_today);
0923:                _cal.add(Calendar.DAY_OF_MONTH, 1);
0924:                _today = _cal.getTimeInMillis();
0925:
0926:                // Restore calendar.
0927:                _cal.setTimeInMillis(_firstDisplayedDate);
0928:                repaint();
0929:            }
0930:
0931:            /**
0932:             * Returns the minimum size needed to display this component.
0933:             *
0934:             * @return Dimension Minimum size.
0935:             */
0936:            public Dimension getMinimumSize() {
0937:                return getPreferredSize();
0938:            }
0939:
0940:            /**
0941:             * Returns the preferred size of this component.
0942:             *
0943:             * @return Dimension Preferred size.
0944:             */
0945:            public Dimension getPreferredSize() {
0946:                updateIfNecessary();
0947:                return new Dimension(_dim);
0948:            }
0949:
0950:            /**
0951:             * Returns the maximum size of this component.
0952:             *
0953:             * @return Dimension Maximum size.
0954:             */
0955:            public Dimension getMaximumSize() {
0956:                return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
0957:            }
0958:
0959:            /**
0960:             * Sets the border of this component. The Border object is responsible
0961:             * for defining the insets for the component (overriding any insets set
0962:             * directly on the component) and for optionally rendering any border
0963:             * decorations within the bounds of those insets. Borders should be used
0964:             * (rather than insets) for creating both decorative and non-decorative
0965:             * (such as margins and padding) regions for a swing component. Compound
0966:             * borders can be used to nest multiple borders within a single component.
0967:             * <p>
0968:             * As the border may modify the bounds of the component, setting the border
0969:             * may result in a reduced number of displayed calendars.
0970:             *
0971:             * @param border Border.
0972:             */
0973:            public void setBorder(Border border) {
0974:                super .setBorder(border);
0975:                calculateNumDisplayedCals();
0976:                calculateStartPosition();
0977:                _dirty = true;
0978:            }
0979:
0980:            /**
0981:             * Moves and resizes this component. The new location of the top-left
0982:             * corner is specified by x and y, and the new size is specified by
0983:             * width and height.
0984:             *
0985:             * @param x The new x-coordinate of this component
0986:             * @param y The new y-coordinate of this component
0987:             * @param width The new width of this component
0988:             * @param height The new height of this component
0989:             */
0990:            public void setBounds(int x, int y, int width, int height) {
0991:                super .setBounds(x, y, width, height);
0992:
0993:                calculateNumDisplayedCals();
0994:                calculateStartPosition();
0995:
0996:                if (_startSelectedDate != -1 || _endSelectedDate != -1) {
0997:                    if (_startSelectedDate > _lastDisplayedDate
0998:                            || _startSelectedDate < _firstDisplayedDate) {
0999:                        // Already does the recalculation for the dirty rect.
1000:                        ensureDateVisible(_startSelectedDate);
1001:                    } else {
1002:                        calculateDirtyRectForSelection();
1003:                    }
1004:                }
1005:            }
1006:
1007:            /**
1008:             * Moves and resizes this component to conform to the new bounding
1009:             * rectangle r. This component's new position is specified by r.x and
1010:             * r.y, and its new size is specified by r.width and r.height
1011:             *
1012:             * @param r The new bounding rectangle for this component
1013:             */
1014:            public void setBounds(Rectangle r) {
1015:                setBounds(r.x, r.y, r.width, r.height);
1016:            }
1017:
1018:            /**
1019:             * Sets the language-sensitive orientation that is to be used to order
1020:             * the elements or text within this component. Language-sensitive
1021:             * LayoutManager and Component  subclasses will use this property to
1022:             * determine how to lay out and draw components.
1023:             * <p>
1024:             * At construction time, a component's orientation is set to
1025:             * ComponentOrientation.UNKNOWN, indicating that it has not been
1026:             * specified explicitly. The UNKNOWN orientation behaves the same as
1027:             * ComponentOrientation.LEFT_TO_RIGHT.
1028:             *
1029:             * @param o The component orientation.
1030:             */
1031:            public void setComponentOrientation(ComponentOrientation o) {
1032:                super .setComponentOrientation(o);
1033:                _ltr = o.isLeftToRight();
1034:                calculateStartPosition();
1035:            }
1036:
1037:            /**
1038:             * Sets the font of this component.
1039:             *
1040:             * @param font The font to become this component's font; if this parameter
1041:             * is null then this component will inherit the font of its parent.
1042:             */
1043:            public void setFont(Font font) {
1044:                super .setFont(font);
1045:                _dirty = true;
1046:            }
1047:
1048:            /**
1049:             * {@inheritDoc}
1050:             */
1051:            public void removeNotify() {
1052:                _todayTimer.stop();
1053:                super .removeNotify();
1054:            }
1055:
1056:            /**
1057:             * {@inheritDoc}
1058:             */
1059:            public void addNotify() {
1060:                super .addNotify();
1061:
1062:                // Setup timer to update the value of _today.
1063:                int secondsTillTomorrow = 86400;
1064:
1065:                if (_todayTimer == null) {
1066:                    _todayTimer = new Timer(secondsTillTomorrow * 1000,
1067:                            new ActionListener() {
1068:                                public void actionPerformed(ActionEvent e) {
1069:                                    updateToday();
1070:                                }
1071:                            });
1072:                }
1073:
1074:                // Modify the initial delay be the current time.
1075:                secondsTillTomorrow = secondsTillTomorrow
1076:                        - (_cal.get(Calendar.HOUR_OF_DAY) * 3600)
1077:                        - (_cal.get(Calendar.MINUTE) * 60)
1078:                        - _cal.get(Calendar.SECOND);
1079:                _todayTimer.setInitialDelay(secondsTillTomorrow * 1000);
1080:                _todayTimer.start();
1081:            }
1082:
1083:            /**
1084:             * {@inheritDoc}
1085:             */
1086:            protected void paintComponent(Graphics g) {
1087:                Object oldAAValue = null;
1088:                Graphics2D g2 = (g instanceof  Graphics2D) ? (Graphics2D) g
1089:                        : null;
1090:                if (g2 != null && _antiAlias) {
1091:                    oldAAValue = g2
1092:                            .getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
1093:                    g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
1094:                            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
1095:                }
1096:
1097:                Rectangle clip = g.getClipBounds();
1098:
1099:                updateIfNecessary();
1100:
1101:                if (isOpaque()) {
1102:                    g.setColor(getBackground());
1103:                    g.fillRect(clip.x, clip.y, clip.width, clip.height);
1104:                }
1105:                g.setColor(getForeground());
1106:                Color shadowColor = g.getColor();
1107:                shadowColor = new Color(shadowColor.getRed(), shadowColor
1108:                        .getGreen(), shadowColor.getBlue(), (int) (.20 * 255));
1109:
1110:                FontMetrics fm = g.getFontMetrics();
1111:
1112:                // Reset the calendar.
1113:                _cal.setTimeInMillis(_firstDisplayedDate);
1114:
1115:                // Center the calendars vertically in the available space.
1116:                int y = _startY;
1117:                for (int row = 0; row < _numCalRows; row++) {
1118:                    // Center the calendars horizontally in the available space.
1119:                    int x = _startX;
1120:                    int tmpX, tmpY;
1121:
1122:                    // Check if this row falls in the clip region.
1123:                    _bounds.x = 0;
1124:                    _bounds.y = _startY + row
1125:                            * (_calendarHeight + CALENDAR_SPACING);
1126:                    _bounds.width = getWidth();
1127:                    _bounds.height = _calendarHeight;
1128:
1129:                    if (!_bounds.intersects(clip)) {
1130:                        _cal.add(Calendar.MONTH, _numCalCols);
1131:                        y += _calendarHeight + CALENDAR_SPACING;
1132:                        continue;
1133:                    }
1134:
1135:                    for (int column = 0; column < _numCalCols; column++) {
1136:                        String monthName = _monthsOfTheYear[_cal
1137:                                .get(Calendar.MONTH)];
1138:                        monthName = monthName + " " + _cal.get(Calendar.YEAR);
1139:
1140:                        _bounds.x = _ltr ? x : x - _calendarWidth;
1141:                        _bounds.y = y + _boxPaddingY;
1142:                        _bounds.width = _calendarWidth;
1143:                        _bounds.height = _boxHeight;
1144:
1145:                        if (_bounds.intersects(clip)) {
1146:                            // Paint month name background.
1147:                            paintMonthStringBackground(g, _bounds.x, _bounds.y,
1148:                                    _bounds.width, _bounds.height);
1149:
1150:                            // Paint month name.
1151:                            g.setColor(getForeground());
1152:                            tmpX = _ltr ? x + (_calendarWidth / 2)
1153:                                    - (fm.stringWidth(monthName) / 2) : x
1154:                                    - (_calendarWidth / 2)
1155:                                    - (fm.stringWidth(monthName) / 2) - 1;
1156:                            tmpY = y + _boxPaddingY + _boxHeight
1157:                                    - fm.getDescent();
1158:
1159:                            g.drawString(monthName, tmpX, tmpY);
1160:
1161:                            if ((_dropShadowMask & MONTH_DROP_SHADOW) != 0) {
1162:                                g.setColor(shadowColor);
1163:                                g.drawString(monthName, tmpX + 1, tmpY + 1);
1164:                                g.setColor(getForeground());
1165:                            }
1166:                        }
1167:
1168:                        _bounds.x = _ltr ? x : x - _calendarWidth;
1169:                        _bounds.y = y + _boxPaddingY + _boxHeight
1170:                                + _boxPaddingY + _boxPaddingY;
1171:                        _bounds.width = _calendarWidth;
1172:                        _bounds.height = _boxHeight;
1173:
1174:                        if (_bounds.intersects(clip)) {
1175:                            _cal.set(Calendar.DAY_OF_MONTH, _cal
1176:                                    .getActualMinimum(Calendar.DAY_OF_MONTH));
1177:
1178:                            // Paint short representation of day of the week.
1179:                            int dayIndex = _firstDayOfWeek - 1;
1180:                            for (int i = 0; i < DAYS_IN_WEEK; i++) {
1181:                                tmpX = _ltr ? x
1182:                                        + (i * (_boxPaddingX + _boxWidth + _boxPaddingX))
1183:                                        + _boxPaddingX
1184:                                        + (_boxWidth / 2)
1185:                                        - (fm
1186:                                                .stringWidth(_daysOfTheWeek[dayIndex]) / 2)
1187:                                        : x
1188:                                                - (i * (_boxPaddingX
1189:                                                        + _boxWidth + _boxPaddingX))
1190:                                                - _boxPaddingX
1191:                                                - (_boxWidth / 2)
1192:                                                - (fm
1193:                                                        .stringWidth(_daysOfTheWeek[dayIndex]) / 2);
1194:                                tmpY = y + _boxPaddingY + _boxHeight
1195:                                        + _boxPaddingY + _boxPaddingY
1196:                                        + fm.getAscent();
1197:                                g.drawString(_daysOfTheWeek[dayIndex], tmpX,
1198:                                        tmpY);
1199:                                if ((_dropShadowMask & WEEK_DROP_SHADOW) != 0) {
1200:                                    g.setColor(shadowColor);
1201:                                    g.drawString(_daysOfTheWeek[dayIndex],
1202:                                            tmpX + 1, tmpY + 1);
1203:                                    g.setColor(getForeground());
1204:                                }
1205:                                dayIndex++;
1206:                                if (dayIndex == 7) {
1207:                                    dayIndex = 0;
1208:                                }
1209:                            }
1210:
1211:                            // Paint a line across bottom of days of the week.
1212:                            g.drawLine(_ltr ? x + 2 : x - 3, y
1213:                                    + (_boxPaddingY * 3) + (_boxHeight * 2),
1214:                                    _ltr ? x + _calendarWidth - 3 : x
1215:                                            - _calendarWidth + 2, y
1216:                                            + (_boxPaddingY * 3)
1217:                                            + (_boxHeight * 2));
1218:                            if ((_dropShadowMask & MONTH_LINE_DROP_SHADOW) != 0) {
1219:                                g.setColor(shadowColor);
1220:                                g.drawLine(_ltr ? x + 3 : x - 2, y
1221:                                        + (_boxPaddingY * 3) + (_boxHeight * 2)
1222:                                        + 1, _ltr ? x + _calendarWidth - 2 : x
1223:                                        - _calendarWidth + 3, y
1224:                                        + (_boxPaddingY * 3) + (_boxHeight * 2)
1225:                                        + 1);
1226:                                g.setColor(getForeground());
1227:                            }
1228:                        }
1229:
1230:                        // Check if the month to paint falls in the clip.
1231:                        _bounds.x = _startX
1232:                                + (_ltr ? column
1233:                                        * (_calendarWidth + CALENDAR_SPACING)
1234:                                        : -(column
1235:                                                * (_calendarWidth + CALENDAR_SPACING) + _calendarWidth));
1236:                        _bounds.y = _startY + row
1237:                                * (_calendarHeight + CALENDAR_SPACING);
1238:                        _bounds.width = _calendarWidth;
1239:                        _bounds.height = _calendarHeight;
1240:
1241:                        // Paint the month if it intersects the clip.  If we don't move
1242:                        // the calendar forward a month as it would have if paintMonth
1243:                        // was called.
1244:                        if (_bounds.intersects(clip)) {
1245:                            paintMonth(g, column, row);
1246:                        } else {
1247:                            _cal.add(Calendar.MONTH, 1);
1248:                        }
1249:
1250:                        x += _ltr ? _calendarWidth + CALENDAR_SPACING
1251:                                : -(_calendarWidth + CALENDAR_SPACING);
1252:                    }
1253:                    y += _calendarHeight + CALENDAR_SPACING;
1254:                }
1255:
1256:                // Restore the calendar.
1257:                _cal.setTimeInMillis(_firstDisplayedDate);
1258:                if (g2 != null && _antiAlias) {
1259:                    g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
1260:                            oldAAValue);
1261:                }
1262:            }
1263:
1264:            /**
1265:             * Paints a month.  It is assumed the calendar, _cal, is already set to the
1266:             * first day of the month to be painted.
1267:             *
1268:             * @param col X (column) the calendar is displayed in.
1269:             * @param row Y (row) the calendar is displayed in.
1270:             * @param g Graphics object.
1271:             */
1272:            private void paintMonth(Graphics g, int col, int row) {
1273:                String numericDay;
1274:                int days = _cal.getActualMaximum(Calendar.DAY_OF_MONTH);
1275:                FontMetrics fm = g.getFontMetrics();
1276:                Rectangle clip = g.getClipBounds();
1277:
1278:                long nextFlaggedDate = -1;
1279:                int flaggedDateIndex = 0;
1280:                if (_flaggedDates != null && _flaggedDates.length > 0) {
1281:                    nextFlaggedDate = _flaggedDates[flaggedDateIndex];
1282:                }
1283:
1284:                for (int i = 0; i < days; i++) {
1285:                    calculateBoundsForDay(_bounds);
1286:
1287:                    if (_bounds.intersects(clip)) {
1288:                        numericDay = _dayOfMonthFormatter
1289:                                .format(_cal.getTime());
1290:
1291:                        // Paint bounding box around any date that falls within the
1292:                        // selection.
1293:                        if (isSelectedDate(_cal.getTimeInMillis())) {
1294:                            // Keep track of the rectangle for the currently
1295:                            // selected date so we don't have to recalculate it
1296:                            // later when it becomes unselected.  This is only
1297:                            // useful for SINGLE_SELECTION mode.
1298:                            if (_selectionMode == SINGLE_SELECTION) {
1299:                                _dirtyRect.x = _bounds.x;
1300:                                _dirtyRect.y = _bounds.y;
1301:                                _dirtyRect.width = _bounds.width;
1302:                                _dirtyRect.height = _bounds.height;
1303:                            }
1304:
1305:                            paintSelectedDayBackground(g, _bounds.x, _bounds.y,
1306:                                    _bounds.width, _bounds.height);
1307:
1308:                            g.setColor(getForeground());
1309:                        }
1310:
1311:                        // Paint bounding box around today.
1312:                        if (_cal.getTimeInMillis() == _today) {
1313:                            paintTodayBackground(g, _bounds.x, _bounds.y,
1314:                                    _bounds.width, _bounds.height);
1315:
1316:                            g.setColor(getForeground());
1317:                        }
1318:
1319:                        // If the appointment date is less than the current
1320:                        // calendar date increment to the next appointment.
1321:                        while (nextFlaggedDate != -1
1322:                                && nextFlaggedDate < _cal.getTimeInMillis()) {
1323:                            flaggedDateIndex++;
1324:                            if (flaggedDateIndex < _flaggedDates.length) {
1325:                                nextFlaggedDate = _flaggedDates[flaggedDateIndex];
1326:                            } else {
1327:                                nextFlaggedDate = -1;
1328:                            }
1329:                        }
1330:
1331:                        // Paint numeric day of the month.
1332:                        if (nextFlaggedDate != -1
1333:                                && _cal.getTimeInMillis() == nextFlaggedDate) {
1334:                            Font oldFont = getFont();
1335:                            g.setFont(_derivedFont);
1336:                            g.drawString(numericDay, _ltr ? _bounds.x
1337:                                    + _boxPaddingX + _boxWidth
1338:                                    - fm.stringWidth(numericDay) : _bounds.x
1339:                                    + _boxPaddingX + _boxWidth
1340:                                    - fm.stringWidth(numericDay) - 1, _bounds.y
1341:                                    + _boxPaddingY + fm.getAscent());
1342:                            g.setFont(oldFont);
1343:                        } else {
1344:                            g.drawString(numericDay, _ltr ? _bounds.x
1345:                                    + _boxPaddingX + _boxWidth
1346:                                    - fm.stringWidth(numericDay) : _bounds.x
1347:                                    + _boxPaddingX + _boxWidth
1348:                                    - fm.stringWidth(numericDay) - 1, _bounds.y
1349:                                    + _boxPaddingY + fm.getAscent());
1350:                        }
1351:                    }
1352:                    _cal.add(Calendar.DAY_OF_MONTH, 1);
1353:                }
1354:            }
1355:
1356:            /**
1357:             * Paints the background of the month string.  The bounding box for this
1358:             * background can be modified by setting its insets via
1359:             * setMonthStringInsets.  The color of the background can be set via
1360:             * setMonthStringBackground.
1361:             *
1362:             * @see #setMonthStringBackground
1363:             * @see #setMonthStringInsets
1364:             * @param g Graphics object to paint to.
1365:             * @param x x-coordinate of upper left corner.
1366:             * @param y y-coordinate of upper left corner.
1367:             * @param width width of the bounding box.
1368:             * @param height height of the bounding box.
1369:             */
1370:            protected void paintMonthStringBackground(Graphics g, int x, int y,
1371:                    int width, int height) {
1372:                // Modify bounds by the month string insets.
1373:                x = _ltr ? x + _monthStringInsets.left : x
1374:                        + _monthStringInsets.left;
1375:                y = y + _monthStringInsets.top;
1376:                width = width - _monthStringInsets.left
1377:                        - _monthStringInsets.right;
1378:                height = height - _monthStringInsets.top
1379:                        - _monthStringInsets.bottom;
1380:
1381:                g.setColor(_monthStringBackground);
1382:                g.fillRect(x, y, width, height);
1383:            }
1384:
1385:            /**
1386:             * Paints the background for today.  The default is a rectangle drawn in
1387:             * using the color set by <code>setTodayBackground</code>
1388:             *
1389:             * @see #setTodayBackground
1390:             * @param g Graphics object to paint to.
1391:             * @param x x-coordinate of upper left corner.
1392:             * @param y y-coordinate of upper left corner.
1393:             * @param width width of bounding box for the day.
1394:             * @param height height of bounding box for the day.
1395:             */
1396:            protected void paintTodayBackground(Graphics g, int x, int y,
1397:                    int width, int height) {
1398:                g.setColor(_todayBackgroundColor);
1399:                g.drawRect(x, y, width - 1, height - 1);
1400:            }
1401:
1402:            /**
1403:             * Paint the background for a selected day.  The default is a filled
1404:             * rectangle in the in the component's background color.
1405:             *
1406:             * @param g Graphics object to paint to.
1407:             * @param x x-coordinate of upper left corner.
1408:             * @param y y-coordinate of upper left corner.
1409:             * @param width width of bounding box for the day.
1410:             * @param height height of bounding box for the day.
1411:             */
1412:            protected void paintSelectedDayBackground(Graphics g, int x, int y,
1413:                    int width, int height) {
1414:                g.setColor(getSelectedBackground());
1415:                g.fillRect(x, y, width, height);
1416:            }
1417:
1418:            /**
1419:             * Returns true if the specified time falls within the _startSelectedDate
1420:             * and _endSelectedDate range.
1421:             */
1422:            private boolean isSelectedDate(long time) {
1423:                if (time >= _startSelectedDate && time <= _endSelectedDate) {
1424:                    return true;
1425:                }
1426:                return false;
1427:            }
1428:
1429:            /**
1430:             * Calculates the _numCalCols/_numCalRows that determine the number of
1431:             * calendars that can be displayed.
1432:             */
1433:            private void calculateNumDisplayedCals() {
1434:                int oldNumCalCols = _numCalCols;
1435:                int oldNumCalRows = _numCalRows;
1436:
1437:                // Determine how many columns of calendars we want to paint.
1438:                _numCalCols = 1;
1439:                _numCalCols += (getWidth() - _calendarWidth)
1440:                        / (_calendarWidth + CALENDAR_SPACING);
1441:
1442:                // Determine how many rows of calendars we want to paint.
1443:                _numCalRows = 1;
1444:                _numCalRows += (getHeight() - _calendarHeight)
1445:                        / (_calendarHeight + CALENDAR_SPACING);
1446:
1447:                if (oldNumCalCols != _numCalCols
1448:                        || oldNumCalRows != _numCalRows) {
1449:                    calculateLastDisplayedDate();
1450:                }
1451:            }
1452:
1453:            /**
1454:             * Calculates the _startX/_startY position for centering the calendars
1455:             * within the available space.
1456:             */
1457:            private void calculateStartPosition() {
1458:                // Calculate offset in x-axis for centering calendars.
1459:                _startX = (getWidth() - ((_calendarWidth * _numCalCols) + (CALENDAR_SPACING * (_numCalCols - 1)))) / 2;
1460:                if (!_ltr) {
1461:                    _startX = getWidth() - _startX;
1462:                }
1463:
1464:                // Calculate offset in y-axis for centering calendars.
1465:                _startY = (getHeight() - ((_calendarHeight * _numCalRows) + (CALENDAR_SPACING * (_numCalRows - 1)))) / 2;
1466:            }
1467:
1468:            /**
1469:             * Returns the bounding box for drawing a date.  It is assumed that the
1470:             * calendar, _cal, is already set to the date you want to find the offset
1471:             * for.
1472:             *
1473:             * @param bounds Bounds of the date to draw in.
1474:             * @return Point X/Y coordinate to the upper left corner of the bounding
1475:             * box for date.
1476:             */
1477:            private void calculateBoundsForDay(Rectangle bounds) {
1478:                int year = _cal.get(Calendar.YEAR);
1479:                int month = _cal.get(Calendar.MONTH);
1480:                int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
1481:                int weekOfMonth = _cal.get(Calendar.WEEK_OF_MONTH);
1482:
1483:                // Determine what row/column we are in.
1484:                int diffMonths = month - _firstDisplayedMonth
1485:                        + ((year - _firstDisplayedYear) * 12);
1486:                int calRowIndex = diffMonths / _numCalCols;
1487:                int calColIndex = diffMonths - (calRowIndex * _numCalCols);
1488:
1489:                // Modify the index relative to the first day of the week.
1490:                bounds.x = dayOfWeek - _firstDayOfWeek;
1491:                if (bounds.x < 0) {
1492:                    bounds.x += DAYS_IN_WEEK;
1493:                }
1494:
1495:                // Offset for location of the day in the week.
1496:                bounds.x = _ltr ? bounds.x
1497:                        * (_boxPaddingX + _boxWidth + _boxPaddingX)
1498:                        : (bounds.x + 1)
1499:                                * (_boxPaddingX + _boxWidth + _boxPaddingX);
1500:
1501:                // Offset for the column the calendar is displayed in.
1502:                bounds.x += calColIndex * (_calendarWidth + CALENDAR_SPACING);
1503:
1504:                // Adjust by centering value.
1505:                bounds.x = _ltr ? _startX + bounds.x : _startX - bounds.x;
1506:
1507:                // Initial offset for Month and Days of the Week display.
1508:                bounds.y = 2 * (_boxPaddingY + _boxHeight + _boxPaddingY);
1509:
1510:                // Offset for centering and row the calendar is displayed in.
1511:                bounds.y += _startY + calRowIndex
1512:                        * (_calendarHeight + CALENDAR_SPACING);
1513:
1514:                // Offset for Week of the Month.
1515:                bounds.y += (weekOfMonth - 1)
1516:                        * (_boxPaddingY + _boxHeight + _boxPaddingY);
1517:
1518:                bounds.width = _boxPaddingX + _boxWidth + _boxPaddingX;
1519:                bounds.height = _boxPaddingY + _boxHeight + _boxPaddingY;
1520:            }
1521:
1522:            /**
1523:             * Return a long representing the date at the specified x/y position.
1524:             * The date returned will have a valid day, month and year.  Other fields
1525:             * such as hour, minute, second and milli-second will be set to 0.
1526:             *
1527:             * @param x X position
1528:             * @param y Y position
1529:             * @return long The date, -1 if position does not contain a date.
1530:             */
1531:            public long getDayAt(int x, int y) {
1532:                if (_ltr ? (_startX > x) : (_startX < x) || _startY > y) {
1533:                    return -1;
1534:                }
1535:
1536:                // Determine which column of calendars we're in.
1537:                int calCol = (_ltr ? (x - _startX) : (_startX - x))
1538:                        / (_calendarWidth + CALENDAR_SPACING);
1539:
1540:                // Determine which row of calendars we're in.
1541:                int calRow = (y - _startY)
1542:                        / (_calendarHeight + CALENDAR_SPACING);
1543:
1544:                if (calRow > _numCalRows - 1 || calCol > _numCalCols - 1) {
1545:                    return -1;
1546:                }
1547:
1548:                // Determine what row (week) in the selected month we're in.
1549:                int row;
1550:                row = ((y - _startY) - (calRow * (_calendarHeight + CALENDAR_SPACING)))
1551:                        / (_boxPaddingY + _boxHeight + _boxPaddingY);
1552:                // The first two lines in the calendar are the month and the days
1553:                // of the week.  Ignore them.
1554:                row -= 2;
1555:
1556:                if (row < 0 || row > 5) {
1557:                    return -1;
1558:                }
1559:
1560:                // Determine which column in the selected month we're in.
1561:                int col = ((_ltr ? (x - _startX) : (_startX - x)) - (calCol * (_calendarWidth + CALENDAR_SPACING)))
1562:                        / (_boxPaddingX + _boxWidth + _boxPaddingX);
1563:
1564:                if (col > DAYS_IN_WEEK - 1) {
1565:                    return -1;
1566:                }
1567:
1568:                // Use the first day of the month as a key point for determining the
1569:                // date of our click.
1570:                // The week index of the first day will always be 0.
1571:                _cal.setTimeInMillis(_firstDisplayedDate);
1572:                //_cal.set(Calendar.DAY_OF_MONTH, 1);
1573:                _cal.add(Calendar.MONTH, calCol + (calRow * _numCalCols));
1574:
1575:                int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
1576:                int firstDayIndex = dayOfWeek - _firstDayOfWeek;
1577:                if (firstDayIndex < 0) {
1578:                    firstDayIndex += DAYS_IN_WEEK;
1579:                }
1580:
1581:                int daysToAdd = (row * DAYS_IN_WEEK) + (col - firstDayIndex);
1582:                if (daysToAdd < 0
1583:                        || daysToAdd > (_cal
1584:                                .getActualMaximum(Calendar.DAY_OF_MONTH) - 1)) {
1585:                    return -1;
1586:                }
1587:
1588:                _cal.add(Calendar.DAY_OF_MONTH, daysToAdd);
1589:
1590:                long selected = _cal.getTimeInMillis();
1591:
1592:                // Restore the time.
1593:                _cal.setTimeInMillis(_firstDisplayedDate);
1594:
1595:                return selected;
1596:            }
1597:
1598:            private void calculateDirtyRectForSelection() {
1599:                if (_startSelectedDate == -1 || _endSelectedDate == -1) {
1600:                    _dirtyRect.x = 0;
1601:                    _dirtyRect.y = 0;
1602:                    _dirtyRect.width = 0;
1603:                    _dirtyRect.height = 0;
1604:                } else {
1605:                    _cal.setTimeInMillis(_startSelectedDate);
1606:                    calculateBoundsForDay(_dirtyRect);
1607:                    _cal.add(Calendar.DAY_OF_MONTH, 1);
1608:
1609:                    Rectangle tmpRect;
1610:                    while (_cal.getTimeInMillis() <= _endSelectedDate) {
1611:                        calculateBoundsForDay(_bounds);
1612:                        tmpRect = _dirtyRect.union(_bounds);
1613:                        _dirtyRect.x = tmpRect.x;
1614:                        _dirtyRect.y = tmpRect.y;
1615:                        _dirtyRect.width = tmpRect.width;
1616:                        _dirtyRect.height = tmpRect.height;
1617:                        _cal.add(Calendar.DAY_OF_MONTH, 1);
1618:                    }
1619:
1620:                    // Restore the time.
1621:                    _cal.setTimeInMillis(_firstDisplayedDate);
1622:                }
1623:            }
1624:
1625:            /**
1626:             * Returns the string currently used to identiy fired ActionEvents.
1627:             *
1628:             * @return String The string used for identifying ActionEvents.
1629:             */
1630:            public String getActionCommand() {
1631:                return _actionCommand;
1632:            }
1633:
1634:            /**
1635:             * Sets the string used to identify fired ActionEvents.
1636:             *
1637:             * @param actionCommand The string used for identifying ActionEvents.
1638:             */
1639:            public void setActionCommand(String actionCommand) {
1640:                _actionCommand = actionCommand;
1641:            }
1642:
1643:            /**
1644:             * Adds an ActionListener.
1645:             * <p>
1646:             * The ActionListener will receive an ActionEvent when a selection has
1647:             * been made. 
1648:             *
1649:             * @param l The ActionListener that is to be notified
1650:             */
1651:            public void addActionListener(ActionListener l) {
1652:                listenerList.add(ActionListener.class, l);
1653:            }
1654:
1655:            /**
1656:             * Removes an ActionListener.
1657:             *
1658:             * @param l The action listener to remove.
1659:             */
1660:            public void removeActionListener(ActionListener l) {
1661:                listenerList.remove(ActionListener.class, l);
1662:            }
1663:
1664:            /**
1665:             * Fires an ActionEvent to all listeners.
1666:             */
1667:            protected void fireActionPerformed() {
1668:                Object[] listeners = listenerList.getListenerList();
1669:                ActionEvent e = null;
1670:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
1671:                    if (listeners[i] == ActionListener.class) {
1672:                        if (e == null) {
1673:                            e = new ActionEvent(JXMonthView.this ,
1674:                                    ActionEvent.ACTION_PERFORMED,
1675:                                    _actionCommand);
1676:                        }
1677:                        ((ActionListener) listeners[i + 1]).actionPerformed(e);
1678:                    }
1679:                }
1680:            }
1681:
1682:            /**
1683:             * {@inheritDoc}
1684:             */
1685:            protected void processMouseEvent(MouseEvent e) {
1686:                if (!isEnabled() || _selectionMode == NO_SELECTION) {
1687:                    return;
1688:                }
1689:
1690:                int id = e.getID();
1691:
1692:                if (id == MouseEvent.MOUSE_PRESSED) {
1693:                    int x = e.getX();
1694:                    int y = e.getY();
1695:
1696:                    long selected = getDayAt(x, y);
1697:                    if (selected == -1) {
1698:                        return;
1699:                    }
1700:
1701:                    // Update the selected dates.
1702:                    _startSelectedDate = selected;
1703:                    _endSelectedDate = selected;
1704:
1705:                    if (_selectionMode == MULTIPLE_SELECTION
1706:                            || _selectionMode == WEEK_SELECTION) {
1707:                        _pivotDate = selected;
1708:                    }
1709:
1710:                    // Determine the dirty rectangle of the new selected date so we
1711:                    // draw the bounding box around it.  This dirty rect includes the
1712:                    // visual border of the selected date.
1713:                    _cal.setTimeInMillis(selected);
1714:
1715:                    calculateBoundsForDay(_bounds);
1716:                    _cal.setTimeInMillis(_firstDisplayedDate);
1717:
1718:                    // Repaint the old dirty area.
1719:                    repaint(_dirtyRect);
1720:
1721:                    // Repaint the new dirty area.
1722:                    repaint(_bounds);
1723:
1724:                    // Update the dirty area.
1725:                    _dirtyRect.x = _bounds.x;
1726:                    _dirtyRect.y = _bounds.y;
1727:                    _dirtyRect.width = _bounds.width;
1728:                    _dirtyRect.height = _bounds.height;
1729:
1730:                    // Arm so we fire action performed on mouse release.
1731:                    _asKirkWouldSay_FIRE = true;
1732:                } else if (id == MouseEvent.MOUSE_RELEASED) {
1733:                    if (_asKirkWouldSay_FIRE) {
1734:                        fireActionPerformed();
1735:                    }
1736:                    _asKirkWouldSay_FIRE = false;
1737:                }
1738:                super .processMouseEvent(e);
1739:            }
1740:
1741:            /**
1742:             * {@inheritDoc}
1743:             */
1744:            protected void processMouseMotionEvent(MouseEvent e) {
1745:                if (!isEnabled() || _selectionMode == NO_SELECTION) {
1746:                    return;
1747:                }
1748:
1749:                int id = e.getID();
1750:
1751:                if (id == MouseEvent.MOUSE_DRAGGED) {
1752:                    int x = e.getX();
1753:                    int y = e.getY();
1754:                    long selected = getDayAt(x, y);
1755:
1756:                    if (selected == -1) {
1757:                        return;
1758:                    }
1759:
1760:                    long oldStart = _startSelectedDate;
1761:                    long oldEnd = _endSelectedDate;
1762:
1763:                    if (_selectionMode == SINGLE_SELECTION) {
1764:                        if (selected == oldStart) {
1765:                            return;
1766:                        }
1767:                        _startSelectedDate = selected;
1768:                        _endSelectedDate = selected;
1769:                    } else {
1770:                        if (selected <= _pivotDate) {
1771:                            _startSelectedDate = selected;
1772:                            _endSelectedDate = _pivotDate;
1773:                        } else if (selected > _pivotDate) {
1774:                            _startSelectedDate = _pivotDate;
1775:                            _endSelectedDate = selected;
1776:                        }
1777:                    }
1778:
1779:                    if (_selectionMode == WEEK_SELECTION) {
1780:                        // Do we span a week.
1781:                        long start = (selected > _pivotDate) ? _pivotDate
1782:                                : selected;
1783:                        long end = (selected > _pivotDate) ? selected
1784:                                : _pivotDate;
1785:
1786:                        _cal.setTimeInMillis(start);
1787:                        int count = 1;
1788:                        while (_cal.getTimeInMillis() < end) {
1789:                            _cal.add(Calendar.DAY_OF_MONTH, 1);
1790:                            count++;
1791:                        }
1792:
1793:                        if (count > 7) {
1794:                            // Move the start date to the first day of the week.
1795:                            _cal.setTimeInMillis(start);
1796:                            int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
1797:                            int daysFromStart = dayOfWeek - _firstDayOfWeek;
1798:                            if (daysFromStart < 0) {
1799:                                daysFromStart += DAYS_IN_WEEK;
1800:                            }
1801:                            _cal.add(Calendar.DAY_OF_MONTH, -daysFromStart);
1802:
1803:                            _startSelectedDate = _cal.getTimeInMillis();
1804:
1805:                            // Move the end date to the last day of the week.
1806:                            _cal.setTimeInMillis(end);
1807:                            dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK);
1808:                            int lastDayOfWeek = _firstDayOfWeek - 1;
1809:                            if (lastDayOfWeek == 0) {
1810:                                lastDayOfWeek = Calendar.SATURDAY;
1811:                            }
1812:                            int daysTillEnd = lastDayOfWeek - dayOfWeek;
1813:                            if (daysTillEnd < 0) {
1814:                                daysTillEnd += DAYS_IN_WEEK;
1815:                            }
1816:                            _cal.add(Calendar.DAY_OF_MONTH, daysTillEnd);
1817:                            _endSelectedDate = _cal.getTimeInMillis();
1818:                        }
1819:                    }
1820:
1821:                    if (oldStart == _startSelectedDate
1822:                            && oldEnd == _endSelectedDate) {
1823:                        return;
1824:                    }
1825:
1826:                    // Repaint the old dirty area.
1827:                    repaint(_dirtyRect);
1828:
1829:                    // Repaint the new dirty area.
1830:                    calculateDirtyRectForSelection();
1831:                    repaint(_dirtyRect);
1832:
1833:                    // Set trigger.
1834:                    _asKirkWouldSay_FIRE = true;
1835:                }
1836:                super.processMouseMotionEvent(e);
1837:            }
1838:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.