Source Code Cross Referenced for JXXMonthView.java in  » Project-Management » OpenProj » com » projity » dialog » 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 » com.projity.dialog.calendar 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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