1 7 package org.jdesktop.swing.calendar; 8 9 import java.awt.*; 10 import java.awt.event.*; 11 import java.text.SimpleDateFormat ; 12 import java.util.Calendar ; 13 import java.util.Date ; 14 import java.util.Locale ; 15 import java.util.TimeZone ; 16 import javax.swing.*; 17 import javax.swing.border.Border ; 18 import org.jdesktop.swing.calendar.*; 19 20 97 public class JXMonthView extends JComponent { 98 99 public static final int NO_SELECTION = 0; 100 101 public static final int SINGLE_SELECTION = 1; 102 103 public static final int MULTIPLE_SELECTION = 2; 104 108 public static final int WEEK_SELECTION = 3; 109 110 114 protected Insets _monthStringInsets = new Insets(0,8,0,8); 115 116 private static final int MONTH_DROP_SHADOW = 1; 117 private static final int MONTH_LINE_DROP_SHADOW = 2; 118 private static final int WEEK_DROP_SHADOW = 4; 119 120 private int _boxPaddingX = 3; 121 private int _boxPaddingY = 3; 122 private static final int CALENDAR_SPACING = 10; 123 private static final int DAYS_IN_WEEK = 7; 124 private static final int MONTHS_IN_YEAR = 12; 125 126 130 private long _firstDisplayedDate; 131 private int _firstDisplayedMonth; 132 private int _firstDisplayedYear; 133 134 private long _lastDisplayedDate; 135 private Font _derivedFont; 136 137 138 private long _startSelectedDate = -1; 139 140 141 private long _endSelectedDate = -1; 142 143 144 private long _pivotDate = -1; 145 146 147 private Rectangle _selectedDateRect = new Rectangle(); 148 149 150 private int _numCalCols = 1; 151 152 153 private int _numCalRows = 1; 154 155 private int _minCalCols = 1; 156 private int _minCalRows = 1; 157 private long _today; 158 private long[] _flaggedDates; 159 private int _selectionMode = SINGLE_SELECTION; 160 private int _boxHeight; 161 private int _boxWidth; 162 private int _calendarWidth; 163 private int _calendarHeight; 164 private int _firstDayOfWeek = Calendar.SUNDAY; 165 private int _startX; 166 private int _startY; 167 private int _dropShadowMask = MONTH_DROP_SHADOW; 168 private boolean _dirty = false; 169 private boolean _antiAlias = false; 170 private boolean _ltr; 171 private boolean _asKirkWouldSay_FIRE = false; 172 private Calendar _cal; 173 private String [] _daysOfTheWeek; 174 private static String [] _monthsOfTheYear; 175 private Dimension _dim = new Dimension(); 176 private Rectangle _bounds = new Rectangle(); 177 private Rectangle _dirtyRect = new Rectangle(); 178 private Color _todayBackgroundColor; 179 private Color _monthStringBackground = Color.LIGHT_GRAY; 180 private Color _selectedBackground = Color.LIGHT_GRAY; 181 private SimpleDateFormat _dayOfMonthFormatter = new SimpleDateFormat ("d"); 182 private String _actionCommand = "selectionChanged"; 183 private Timer _todayTimer = null; 184 185 189 public JXMonthView() { 190 this(new Date ().getTime()); 191 } 192 193 200 public JXMonthView(long initialTime) { 201 super(); 202 203 _ltr = getComponentOrientation().isLeftToRight(); 204 205 _cal = Calendar.getInstance(getLocale()); 207 _cal.setFirstDayOfWeek(_firstDayOfWeek); 208 209 _cal.set(Calendar.HOUR_OF_DAY, 0); 211 _cal.set(Calendar.MINUTE, 0); 212 _cal.set(Calendar.SECOND, 0); 213 _cal.set(Calendar.MILLISECOND, 0); 214 _today = _cal.getTimeInMillis(); 215 216 _cal.setTimeInMillis(initialTime); 217 setFirstDisplayedDate(_cal.getTimeInMillis()); 218 219 _cal.set(Calendar.MONTH, _cal.getMinimum(Calendar.MONTH)); 221 _cal.set(Calendar.DAY_OF_MONTH, 222 _cal.getActualMinimum(Calendar.DAY_OF_MONTH)); 223 _monthsOfTheYear = new String [MONTHS_IN_YEAR]; 224 SimpleDateFormat fullMonthNameFormatter = 225 new SimpleDateFormat ("MMMM"); 226 for (int i = 0; i < MONTHS_IN_YEAR; i++) { 227 _monthsOfTheYear[i] = 228 fullMonthNameFormatter.format(_cal.getTime()); 229 _cal.add(Calendar.MONTH, 1); 230 } 231 232 setOpaque(true); 233 setBackground(Color.WHITE); 234 setFont(new Font("Dialog", Font.PLAIN, 12)); 235 _todayBackgroundColor = getForeground(); 236 237 _cal.setTimeInMillis(_firstDisplayedDate); 239 240 enableEvents(AWTEvent.MOUSE_EVENT_MASK); 241 enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); 242 243 updateUI(); 244 } 245 246 249 public void updateUI() { 250 super.updateUI(); 251 252 String [] daysOfTheWeek = 253 (String [])UIManager.get("JXMonthView.daysOfTheWeek"); 254 if (daysOfTheWeek == null) { 257 daysOfTheWeek = new String [] {"S", "M", "T", "W", "R", "F", "S"}; 258 } 259 setDaysOfTheWeek(daysOfTheWeek); 260 261 Color color = UIManager.getColor("JXMonthView.monthStringBackground"); 262 if (color == null) { 265 color = Color.LIGHT_GRAY; 266 } 267 setMonthStringBackground(color); 268 269 color = UIManager.getColor("JXMonthView.selectedBackground"); 270 if (color == null) { 273 color = Color.LIGHT_GRAY; 274 } 275 setSelectedBackground(color); 276 } 277 278 279 284 public long getFirstDisplayedDate() { 285 return _firstDisplayedDate; 286 } 287 288 296 public void setFirstDisplayedDate(long date) { 297 long old = _firstDisplayedDate; 298 299 _cal.setTimeInMillis(date); 300 _cal.set(Calendar.DAY_OF_MONTH, 1); 301 _cal.set(Calendar.HOUR_OF_DAY, 0); 302 _cal.set(Calendar.MINUTE, 0); 303 _cal.set(Calendar.SECOND, 0); 304 _cal.set(Calendar.MILLISECOND, 0); 305 306 _firstDisplayedDate = _cal.getTimeInMillis(); 307 _firstDisplayedMonth = _cal.get(Calendar.MONTH); 308 _firstDisplayedYear = _cal.get(Calendar.YEAR); 309 310 calculateLastDisplayedDate(); 311 firePropertyChange("firstDisplayedDate", old, _firstDisplayedDate); 312 313 repaint(); 314 } 315 316 322 public long getLastDisplayedDate() { 323 return _lastDisplayedDate; 324 } 325 326 private void calculateLastDisplayedDate() { 327 long old = _lastDisplayedDate; 328 329 _cal.setTimeInMillis(_firstDisplayedDate); 330 331 _cal.add(Calendar.MONTH, ((_numCalCols * _numCalRows) - 1)); 333 _cal.set(Calendar.DAY_OF_MONTH, 334 _cal.getActualMaximum(Calendar.DAY_OF_MONTH)); 335 _cal.set(Calendar.HOUR_OF_DAY, 23); 336 _cal.set(Calendar.MINUTE, 59); 337 _cal.set(Calendar.SECOND, 59); 338 339 _lastDisplayedDate = _cal.getTimeInMillis(); 340 341 firePropertyChange("lastDisplayedDate", old, _lastDisplayedDate); 342 } 343 344 352 public void ensureDateVisible(long date) { 353 if (date < _firstDisplayedDate) { 354 setFirstDisplayedDate(date); 355 } else if (date > _lastDisplayedDate) { 356 _cal.setTimeInMillis(date); 357 int month = _cal.get(Calendar.MONTH); 358 int year = _cal.get(Calendar.YEAR); 359 360 _cal.setTimeInMillis(_lastDisplayedDate); 361 int lastMonth = _cal.get(Calendar.MONTH); 362 int lastYear = _cal.get(Calendar.YEAR); 363 364 int diffMonths = month - lastMonth + 365 ((year - lastYear) * 12); 366 367 _cal.setTimeInMillis(_firstDisplayedDate); 368 _cal.add(Calendar.MONTH, diffMonths); 369 setFirstDisplayedDate(_cal.getTimeInMillis()); 370 } 371 372 if (_startSelectedDate != -1 || _endSelectedDate != -1) { 373 calculateDirtyRectForSelection(); 374 } 375 } 376 377 381 public DateSpan getSelectedDateSpan() { 382 DateSpan result = null; 383 if (_startSelectedDate != -1) { 384 result = new DateSpan(new Date (_startSelectedDate), 385 new Date (_endSelectedDate)); 386 } 387 return result; 388 } 389 390 400 public void setSelectedDateSpan(DateSpan dateSpan) { 401 DateSpan oldSpan = null; 402 if (_startSelectedDate != -1 && _endSelectedDate != -1) { 403 oldSpan = new DateSpan(_startSelectedDate, _endSelectedDate); 404 } 405 406 if (dateSpan == null) { 407 _startSelectedDate = -1; 408 _endSelectedDate = -1; 409 } else { 410 _cal.setTimeInMillis(dateSpan.getStart()); 411 _cal.set(Calendar.HOUR_OF_DAY, 0); 412 _cal.set(Calendar.MINUTE, 0); 413 _cal.set(Calendar.SECOND, 0); 414 _cal.set(Calendar.MILLISECOND, 0); 415 _startSelectedDate = _cal.getTimeInMillis(); 416 417 if (_selectionMode == SINGLE_SELECTION) { 418 _endSelectedDate = _startSelectedDate; 419 } else { 420 _cal.setTimeInMillis(dateSpan.getEnd()); 421 _cal.set(Calendar.HOUR_OF_DAY, 0); 422 _cal.set(Calendar.MINUTE, 0); 423 _cal.set(Calendar.SECOND, 0); 424 _cal.set(Calendar.MILLISECOND, 0); 425 _endSelectedDate = _cal.getTimeInMillis(); 426 427 if (_selectionMode == WEEK_SELECTION) { 428 _cal.setTimeInMillis(_startSelectedDate); 430 int count = 1; 431 while (_cal.getTimeInMillis() < _endSelectedDate) { 432 _cal.add(Calendar.DAY_OF_MONTH, 1); 433 count++; 434 } 435 if (count > 7) { 436 _cal.setTimeInMillis(_startSelectedDate); 439 int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK); 440 if (dayOfWeek != _firstDayOfWeek) { 441 int daysFromStart = dayOfWeek - _firstDayOfWeek; 444 if (daysFromStart < 0) { 445 daysFromStart += DAYS_IN_WEEK; 446 } 447 _cal.add(Calendar.DAY_OF_MONTH, -daysFromStart); 448 count += daysFromStart; 449 _startSelectedDate = _cal.getTimeInMillis(); 450 } 451 452 int remainder = count % 7; 455 if (remainder != 0) { 456 _cal.setTimeInMillis(_endSelectedDate); 457 _cal.add(Calendar.DAY_OF_MONTH, (7 - remainder)); 458 _endSelectedDate = _cal.getTimeInMillis(); 459 } 460 } 461 } 462 } 463 _cal.setTimeInMillis(_firstDisplayedDate); 465 } 466 467 repaint(_dirtyRect); 468 calculateDirtyRectForSelection(); 469 repaint(_dirtyRect); 470 471 firePropertyChange("selectedDates", oldSpan, dateSpan); 473 } 474 475 480 public int getSelectionMode() { 481 return _selectionMode; 482 } 483 484 489 public void setSelectionMode(int mode) throws IllegalArgumentException { 490 if (mode != SINGLE_SELECTION && mode != MULTIPLE_SELECTION && 491 mode != WEEK_SELECTION && mode != NO_SELECTION) { 492 throw new IllegalArgumentException (mode + 493 " is not a valid selection mode"); 494 } 495 _selectionMode = mode; 496 } 497 498 502 public void setFlaggedDates(long[] flaggedDates) { 503 _flaggedDates = flaggedDates; 504 505 if (_flaggedDates == null) { 506 repaint(); 507 return; 508 } 509 510 for (int i = 0; i < _flaggedDates.length; i++) { 513 _cal.setTimeInMillis(_flaggedDates[i]); 514 515 _cal.set(Calendar.HOUR_OF_DAY, 0); 518 _cal.set(Calendar.MINUTE, 0); 519 _cal.set(Calendar.SECOND, 0); 520 _cal.set(Calendar.MILLISECOND, 0); 521 522 _flaggedDates[i] = _cal.getTimeInMillis(); 523 } 524 525 _cal.setTimeInMillis(_firstDisplayedDate); 527 528 repaint(); 529 } 530 531 534 public int getBoxPaddingX() { 535 return _boxPaddingX; 536 } 537 538 544 public void setBoxPaddingX(int _boxPaddingX) { 545 this._boxPaddingX = _boxPaddingX; 546 _dirty = true; 547 } 548 549 552 public int getBoxPaddingY() { 553 return _boxPaddingY; 554 } 555 556 562 public void setBoxPaddingY(int _boxPaddingY) { 563 this._boxPaddingY = _boxPaddingY; 564 _dirty = true; 565 } 566 567 575 public void setDaysOfTheWeek(String [] days) 576 throws IllegalArgumentException , NullPointerException { 577 if (days == null) { 578 throw new NullPointerException ("Array of days is null."); 579 } else if (days.length != 7) { 580 throw new IllegalArgumentException ( 581 "Array of days is not of length 7 as expected."); 582 } 583 _daysOfTheWeek = days; 584 } 585 586 592 public String [] getDaysOfTheWeek() { 593 String [] days = new String [7]; 594 System.arraycopy(_daysOfTheWeek, 0, days, 0, 7); 595 return days; 596 } 597 598 605 public int getFirstDayOfWeek() { 606 return _firstDayOfWeek; 607 } 608 609 618 public void setFirstDayOfWeek(int firstDayOfWeek) { 619 if (firstDayOfWeek == _firstDayOfWeek) { 620 return; 621 } 622 623 _firstDayOfWeek = firstDayOfWeek; 624 _cal.setFirstDayOfWeek(_firstDayOfWeek); 625 626 repaint(); 627 } 628 629 634 public TimeZone getTimeZone() { 635 return _cal.getTimeZone(); 636 } 637 638 643 public void setTimeZone(TimeZone tz) { 644 _cal.setTimeZone(tz); 645 } 646 647 654 public boolean getAntialiased() { 655 return _antiAlias; 656 } 657 658 664 public void setAntialiased(boolean antiAlias) { 665 if (_antiAlias == antiAlias) { 666 return; 667 } 668 _antiAlias = antiAlias; 669 repaint(); 670 } 671 672 678 679 684 public Color getSelectedBackground() { 685 return _selectedBackground; 686 } 687 688 694 public void setSelectedBackground(Color c) { 695 _selectedBackground = c; 696 } 697 698 703 public Color getTodayBackground() { 704 return _todayBackgroundColor; 705 } 706 707 711 public void setTodayBackground(Color c) { 712 _todayBackgroundColor = c; 713 repaint(); 714 } 715 716 721 public Color getMonthStringBackground() { 722 return _monthStringBackground; 723 } 724 725 729 public void setMonthStringBackground(Color c) { 730 _monthStringBackground = c; 731 repaint(); 732 } 733 734 739 public Insets getMonthStringInsets() { 740 return (Insets)_monthStringInsets.clone(); 741 } 742 743 749 public void setMonthStringInsets(Insets insets) { 750 if (insets == null) { 751 _monthStringInsets.top = 0; 752 _monthStringInsets.left = 0; 753 _monthStringInsets.bottom = 0; 754 _monthStringInsets.right = 0; 755 } else { 756 _monthStringInsets.top = insets.top; 757 _monthStringInsets.left = insets.left; 758 _monthStringInsets.bottom = insets.bottom; 759 _monthStringInsets.right = insets.right; 760 } 761 repaint(); 762 } 763 764 769 public int getPreferredCols() { 770 return _minCalCols; 771 } 772 773 778 public void setPreferredCols(int cols) { 779 if (cols <= 0) { 780 return; 781 } 782 _minCalCols = cols; 783 _dirty = true; 784 revalidate(); 785 repaint(); 786 } 787 788 793 public int getPreferredRows() { 794 return _minCalRows; 795 } 796 797 802 public void setPreferredRows(int rows) { 803 if (rows <= 0) { 804 return; 805 } 806 _minCalRows = rows; 807 _dirty = true; 808 revalidate(); 809 repaint(); 810 } 811 812 private void updateIfNecessary() { 813 if (_dirty) { 814 update(); 815 _dirty = false; 816 } 817 } 818 819 822 private void update() { 823 int currDays; 827 int longestMonth = 0; 828 int daysInLongestMonth = 0; 829 830 int currWidth; 831 int longestMonthWidth = 0; 832 833 _derivedFont = getFont().deriveFont(Font.BOLD); 836 FontMetrics fm = getFontMetrics(_derivedFont); 837 838 _cal.set(Calendar.MONTH, _cal.getMinimum(Calendar.MONTH)); 839 _cal.set(Calendar.DAY_OF_MONTH, 840 _cal.getActualMinimum(Calendar.DAY_OF_MONTH)); 841 for (int i = 0; i < _cal.getMaximum(Calendar.MONTH); i++) { 842 currWidth = fm.stringWidth(_monthsOfTheYear[i]); 843 if (currWidth > longestMonthWidth) { 844 longestMonthWidth = currWidth; 845 } 846 currDays = _cal.getActualMaximum(Calendar.DAY_OF_MONTH); 847 if (currDays > daysInLongestMonth) { 848 longestMonth = _cal.get(Calendar.MONTH); 849 daysInLongestMonth = currDays; 850 } 851 _cal.add(Calendar.MONTH, 1); 852 } 853 854 _cal.set(Calendar.MONTH, longestMonth); 857 _cal.set(Calendar.DAY_OF_MONTH, 858 _cal.getActualMinimum(Calendar.DAY_OF_MONTH)); 859 _boxHeight = fm.getHeight(); 860 for (int i = 0; i < daysInLongestMonth; i++) { 861 currWidth = fm.stringWidth( 862 _dayOfMonthFormatter.format(_cal.getTime())); 863 if (currWidth > _boxWidth) { 864 _boxWidth = currWidth; 865 } 866 _cal.add(Calendar.DAY_OF_MONTH, 1); 867 } 868 869 _dim.width = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK; 871 if (_dim.width < longestMonthWidth) { 872 double diff = longestMonthWidth - _dim.width; 873 _boxWidth += Math.ceil(diff / (double)DAYS_IN_WEEK); 874 _dim.width = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK; 875 } 876 877 _calendarWidth = (_boxWidth + (2 * _boxPaddingX)) * DAYS_IN_WEEK; 879 _calendarHeight = (_boxPaddingY + _boxHeight + _boxPaddingY) * 8; 880 881 _dim.height = (_calendarHeight * _minCalRows) + 883 (CALENDAR_SPACING * (_minCalRows - 1)); 884 885 _dim.width = (_calendarWidth * _minCalCols) + 886 (CALENDAR_SPACING * (_minCalCols - 1)); 887 888 Insets insets = getInsets(); 890 _dim.width += insets.left + insets.right; 891 _dim.height += insets.top + insets.bottom; 892 893 _cal.setTimeInMillis(_firstDisplayedDate); 895 } 896 897 private void updateToday() { 898 _cal.setTimeInMillis(_today); 900 _cal.add(Calendar.DAY_OF_MONTH, 1); 901 _today = _cal.getTimeInMillis(); 902 903 _cal.setTimeInMillis(_firstDisplayedDate); 905 repaint(); 906 } 907 908 913 public Dimension getMinimumSize() { 914 return getPreferredSize(); 915 } 916 917 922 public Dimension getPreferredSize() { 923 updateIfNecessary(); 924 return new Dimension(_dim); 925 } 926 927 932 public Dimension getMaximumSize() { 933 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 934 } 935 936 950 public void setBorder(Border border) { 951 super.setBorder(border); 952 calculateNumDisplayedCals(); 953 calculateStartPosition(); 954 _dirty = true; 955 } 956 957 967 public void setBounds(int x, int y, int width, int height) { 968 super.setBounds(x, y, width, height); 969 970 calculateNumDisplayedCals(); 971 calculateStartPosition(); 972 973 if (_startSelectedDate != -1 || _endSelectedDate != -1) { 974 if (_startSelectedDate > _lastDisplayedDate || 975 _startSelectedDate < _firstDisplayedDate) { 976 ensureDateVisible(_startSelectedDate); 978 } else { 979 calculateDirtyRectForSelection(); 980 } 981 } 982 } 983 984 991 public void setBounds(Rectangle r) { 992 setBounds(r.x, r.y, r.width, r.height); 993 } 994 995 1008 public void setComponentOrientation(ComponentOrientation o) { 1009 super.setComponentOrientation(o); 1010 _ltr = o.isLeftToRight(); 1011 calculateStartPosition(); 1012 } 1013 1014 1020 public void setFont(Font font) { 1021 super.setFont(font); 1022 _dirty = true; 1023 } 1024 1025 1028 public void removeNotify() { 1029 _todayTimer.stop(); 1030 super.removeNotify(); 1031 } 1032 1033 1036 public void addNotify() { 1037 super.addNotify(); 1038 1039 int secondsTillTomorrow = 86400; 1041 1042 if (_todayTimer == null) { 1043 _todayTimer = new Timer(secondsTillTomorrow * 1000, 1044 new ActionListener() { 1045 public void actionPerformed(ActionEvent e) { 1046 updateToday(); 1047 } 1048 }); 1049 } 1050 1051 _cal.setTimeInMillis(System.currentTimeMillis()); 1053 secondsTillTomorrow = secondsTillTomorrow - 1054 (_cal.get(Calendar.HOUR_OF_DAY) * 3600) - 1055 (_cal.get(Calendar.MINUTE) * 60) - 1056 _cal.get(Calendar.SECOND); 1057 _todayTimer.setInitialDelay(secondsTillTomorrow * 1000); 1058 _todayTimer.start(); 1059 1060 _cal.setTimeInMillis(_firstDisplayedDate); 1062 } 1063 1064 1067 protected void paintComponent(Graphics g) { 1068 Object oldAAValue = null; 1069 Graphics2D g2 = (g instanceof Graphics2D) ? (Graphics2D)g : null; 1070 if (g2 != null && _antiAlias) { 1071 oldAAValue = g2.getRenderingHint( 1072 RenderingHints.KEY_TEXT_ANTIALIASING); 1073 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 1074 RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 1075 } 1076 1077 Rectangle clip = g.getClipBounds(); 1078 1079 updateIfNecessary(); 1080 1081 if (isOpaque()) { 1082 g.setColor(getBackground()); 1083 g.fillRect(clip.x, clip.y, clip.width, clip.height); 1084 } 1085 g.setColor(getForeground()); 1086 Color shadowColor = g.getColor(); 1087 shadowColor = new Color(shadowColor.getRed(), shadowColor.getGreen(), 1088 shadowColor.getBlue(), (int)(.20 * 255)); 1089 1090 FontMetrics fm = g.getFontMetrics(); 1091 1092 _cal.setTimeInMillis(_firstDisplayedDate); 1094 1095 int y = _startY; 1097 for (int row = 0; row < _numCalRows; row++) { 1098 int x = _startX; 1100 int tmpX, tmpY; 1101 1102 _bounds.x = 0; 1104 _bounds.y = _startY + 1105 row * (_calendarHeight + CALENDAR_SPACING); 1106 _bounds.width = getWidth(); 1107 _bounds.height = _calendarHeight; 1108 1109 if (!_bounds.intersects(clip)) { 1110 _cal.add(Calendar.MONTH, _numCalCols); 1111 y += _calendarHeight + CALENDAR_SPACING; 1112 continue; 1113 } 1114 1115 for (int column = 0; column < _numCalCols; column++) { 1116 String monthName = _monthsOfTheYear[_cal.get(Calendar.MONTH)]; 1117 monthName = monthName + " " + _cal.get(Calendar.YEAR); 1118 1119 _bounds.x = _ltr ? x : x - _calendarWidth; 1120 _bounds.y = y + _boxPaddingY; 1121 _bounds.width = _calendarWidth; 1122 _bounds.height = _boxHeight; 1123 1124 if (_bounds.intersects(clip)) { 1125 paintMonthStringBackground(g, _bounds.x, _bounds.y, 1127 _bounds.width, _bounds.height); 1128 1129 g.setColor(getForeground()); 1131 tmpX = _ltr ? 1132 x + (_calendarWidth / 2) - 1133 (fm.stringWidth(monthName) / 2) : 1134 x - (_calendarWidth / 2) - 1135 (fm.stringWidth(monthName) / 2) - 1; 1136 tmpY = y + _boxPaddingY + _boxHeight - fm.getDescent(); 1137 1138 g.drawString(monthName, tmpX, tmpY); 1139 1140 if ((_dropShadowMask & MONTH_DROP_SHADOW) != 0) { 1141 g.setColor(shadowColor); 1142 g.drawString(monthName, tmpX + 1, tmpY + 1); 1143 g.setColor(getForeground()); 1144 } 1145 } 1146 1147 _bounds.x = _ltr ? x : x - _calendarWidth; 1148 _bounds.y = y + _boxPaddingY + _boxHeight + 1149 _boxPaddingY + _boxPaddingY; 1150 _bounds.width = _calendarWidth; 1151 _bounds.height = _boxHeight; 1152 1153 if (_bounds.intersects(clip)) { 1154 _cal.set(Calendar.DAY_OF_MONTH, 1155 _cal.getActualMinimum(Calendar.DAY_OF_MONTH)); 1156 1157 int dayIndex = _firstDayOfWeek - 1; 1159 for (int i = 0; i < DAYS_IN_WEEK; i++) { 1160 tmpX = _ltr ? 1161 x + (i * (_boxPaddingX + _boxWidth + 1162 _boxPaddingX)) + _boxPaddingX + 1163 (_boxWidth / 2) - 1164 (fm.stringWidth(_daysOfTheWeek[dayIndex]) / 1165 2) : 1166 x - (i * (_boxPaddingX + _boxWidth + 1167 _boxPaddingX)) - _boxPaddingX - 1168 (_boxWidth / 2) - 1169 (fm.stringWidth(_daysOfTheWeek[dayIndex]) / 1170 2); 1171 tmpY = y + _boxPaddingY + _boxHeight + 1172 _boxPaddingY + _boxPaddingY + 1173 fm.getAscent(); 1174 g.drawString(_daysOfTheWeek[dayIndex], tmpX, tmpY); 1175 if ((_dropShadowMask & WEEK_DROP_SHADOW) != 0) { 1176 g.setColor(shadowColor); 1177 g.drawString(_daysOfTheWeek[dayIndex], 1178 tmpX + 1, tmpY + 1); 1179 g.setColor(getForeground()); 1180 } 1181 dayIndex++; 1182 if (dayIndex == 7) { 1183 dayIndex = 0; 1184 } 1185 } 1186 1187 g.drawLine(_ltr ? 1189 x + 2 : x - 3, 1190 y + (_boxPaddingY * 3) + (_boxHeight * 2), 1191 _ltr ? 1192 x + _calendarWidth - 3 : 1193 x - _calendarWidth + 2, 1194 y + (_boxPaddingY * 3) + (_boxHeight * 2)); 1195 if ((_dropShadowMask & MONTH_LINE_DROP_SHADOW) != 0) { 1196 g.setColor(shadowColor); 1197 g.drawLine(_ltr ? 1198 x + 3 : x - 2, 1199 y + (_boxPaddingY * 3) + (_boxHeight * 2) + 1, 1200 _ltr ? 1201 x + _calendarWidth - 2 : 1202 x - _calendarWidth + 3, 1203 y + (_boxPaddingY * 3) + (_boxHeight * 2) + 1); 1204 g.setColor(getForeground()); 1205 } 1206 } 1207 1208 _bounds.x = _startX + 1210 (_ltr ? 1211 column * (_calendarWidth + CALENDAR_SPACING) : 1212 -(column * (_calendarWidth + CALENDAR_SPACING) + 1213 _calendarWidth)); 1214 _bounds.y = _startY + 1215 row * (_calendarHeight + CALENDAR_SPACING); 1216 _bounds.width = _calendarWidth; 1217 _bounds.height = _calendarHeight; 1218 1219 if (_bounds.intersects(clip)) { 1223 paintMonth(g, column, row); 1224 } else { 1225 _cal.add(Calendar.MONTH, 1); 1226 } 1227 1228 x += _ltr ? 1229 _calendarWidth + CALENDAR_SPACING : 1230 -(_calendarWidth + CALENDAR_SPACING); 1231 } 1232 y += _calendarHeight + CALENDAR_SPACING; 1233 } 1234 1235 _cal.setTimeInMillis(_firstDisplayedDate); 1237 if (g2 != null && _antiAlias) { 1238 g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 1239 oldAAValue); 1240 } 1241 } 1242 1243 1251 private void paintMonth(Graphics g, int col, int row) { 1252 String numericDay; 1253 int days = _cal.getActualMaximum(Calendar.DAY_OF_MONTH); 1254 FontMetrics fm = g.getFontMetrics(); 1255 Rectangle clip = g.getClipBounds(); 1256 1257 long nextFlaggedDate = -1; 1258 int flaggedDateIndex = 0; 1259 if (_flaggedDates != null && _flaggedDates.length > 0) { 1260 nextFlaggedDate = _flaggedDates[flaggedDateIndex]; 1261 } 1262 1263 for (int i = 0; i < days; i++) { 1264 calculateBoundsForDay(_bounds); 1265 1266 if (_bounds.intersects(clip)) { 1267 numericDay = _dayOfMonthFormatter.format(_cal.getTime()); 1268 1269 if (isSelectedDate(_cal.getTimeInMillis())) { 1272 if (_selectionMode == SINGLE_SELECTION) { 1277 _dirtyRect.x = _bounds.x; 1278 _dirtyRect.y = _bounds.y; 1279 _dirtyRect.width = _bounds.width; 1280 _dirtyRect.height = _bounds.height; 1281 } 1282 1283 paintSelectedDayBackground(g, _bounds.x, _bounds.y, 1284 _bounds.width, _bounds.height); 1285 1286 g.setColor(getForeground()); 1287 } 1288 1289 if (_cal.getTimeInMillis() == _today) { 1291 paintTodayBackground(g, _bounds.x, _bounds.y, 1292 _bounds.width, _bounds.height); 1293 1294 g.setColor(getForeground()); 1295 } 1296 1297 while (nextFlaggedDate != -1 && 1300 nextFlaggedDate < _cal.getTimeInMillis()) { 1301 flaggedDateIndex++; 1302 if (flaggedDateIndex < _flaggedDates.length) { 1303 nextFlaggedDate = _flaggedDates[flaggedDateIndex]; 1304 } else { 1305 nextFlaggedDate = -1; 1306 } 1307 } 1308 1309 if (nextFlaggedDate != -1 && 1311 _cal.getTimeInMillis() == nextFlaggedDate) { 1312 Font oldFont = getFont(); 1313 g.setFont(_derivedFont); 1314 g.drawString(numericDay, 1315 _ltr ? 1316 _bounds.x + _boxPaddingX + 1317 _boxWidth - fm.stringWidth(numericDay): 1318 _bounds.x + _boxPaddingX + 1319 _boxWidth - fm.stringWidth(numericDay) - 1, 1320 _bounds.y + _boxPaddingY + fm.getAscent()); 1321 g.setFont(oldFont); 1322 } else { 1323 g.drawString(numericDay, 1324 _ltr ? 1325 _bounds.x + _boxPaddingX + 1326 _boxWidth - fm.stringWidth(numericDay): 1327 _bounds.x + _boxPaddingX + 1328 _boxWidth - fm.stringWidth(numericDay) - 1, 1329 _bounds.y + _boxPaddingY + fm.getAscent()); 1330 } 1331 } 1332 _cal.add(Calendar.DAY_OF_MONTH, 1); 1333 } 1334 } 1335 1336 1350 protected void paintMonthStringBackground(Graphics g, int x, int y, 1351 int width, int height) { 1352 x = _ltr ? x + _monthStringInsets.left : x + _monthStringInsets.left; 1354 y = y + _monthStringInsets.top; 1355 width = width - _monthStringInsets.left - _monthStringInsets.right; 1356 height = height - _monthStringInsets.top - _monthStringInsets.bottom; 1357 1358 g.setColor(_monthStringBackground); 1359 g.fillRect(x, y, width, height); 1360 } 1361 1362 1373 protected void paintTodayBackground(Graphics g, int x, int y, int width, 1374 int height) { 1375 g.setColor(_todayBackgroundColor); 1376 g.drawRect(x, y, width - 1, height - 1); 1377 } 1378 1379 1389 protected void paintSelectedDayBackground(Graphics g, int x, int y, 1390 int width, int height) { 1391 g.setColor(getSelectedBackground()); 1392 g.fillRect(x, y, width, height); 1393 } 1394 1395 1399 private boolean isSelectedDate(long time) { 1400 if (time >= _startSelectedDate && time <= _endSelectedDate) { 1401 return true; 1402 } 1403 return false; 1404 } 1405 1406 1410 private void calculateNumDisplayedCals() { 1411 int oldNumCalCols = _numCalCols; 1412 int oldNumCalRows = _numCalRows; 1413 1414 _numCalCols = 1; 1416 _numCalCols += (getWidth() - _calendarWidth) / 1417 (_calendarWidth + CALENDAR_SPACING); 1418 1419 _numCalRows = 1; 1421 _numCalRows += (getHeight() - _calendarHeight) / 1422 (_calendarHeight + CALENDAR_SPACING); 1423 1424 if (oldNumCalCols != _numCalCols || 1425 oldNumCalRows != _numCalRows) { 1426 calculateLastDisplayedDate(); 1427 } 1428 } 1429 1430 1434 private void calculateStartPosition() { 1435 _startX = (getWidth() - ((_calendarWidth * _numCalCols) + 1437 (CALENDAR_SPACING * (_numCalCols - 1)))) / 2; 1438 if (!_ltr) { 1439 _startX = getWidth() - _startX; 1440 } 1441 1442 _startY = (getHeight() - ((_calendarHeight * _numCalRows) + 1444 (CALENDAR_SPACING * (_numCalRows - 1 )))) / 2; 1445 } 1446 1447 1456 private void calculateBoundsForDay(Rectangle bounds) { 1457 int year = _cal.get(Calendar.YEAR); 1458 int month = _cal.get(Calendar.MONTH); 1459 int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK); 1460 int weekOfMonth = _cal.get(Calendar.WEEK_OF_MONTH); 1461 1462 int diffMonths = month - _firstDisplayedMonth + 1464 ((year - _firstDisplayedYear) * 12); 1465 int calRowIndex = diffMonths / _numCalCols; 1466 int calColIndex = diffMonths - (calRowIndex * _numCalCols); 1467 1468 bounds.x = dayOfWeek - _firstDayOfWeek; 1470 if (bounds.x < 0) { 1471 bounds.x += DAYS_IN_WEEK; 1472 } 1473 1474 bounds.x = _ltr ? 1476 bounds.x * (_boxPaddingX + _boxWidth + _boxPaddingX) : 1477 (bounds.x + 1) * (_boxPaddingX + _boxWidth + _boxPaddingX); 1478 1479 bounds.x += calColIndex * (_calendarWidth + CALENDAR_SPACING); 1481 1482 bounds.x = _ltr ? _startX + bounds.x : _startX - bounds.x; 1484 1485 bounds.y = 2 * (_boxPaddingY + _boxHeight + _boxPaddingY); 1487 1488 bounds.y += _startY + calRowIndex * 1490 (_calendarHeight + CALENDAR_SPACING); 1491 1492 bounds.y += (weekOfMonth - 1) * 1494 (_boxPaddingY + _boxHeight + _boxPaddingY); 1495 1496 bounds.width = _boxPaddingX + _boxWidth + _boxPaddingX; 1497 bounds.height = _boxPaddingY + _boxHeight + _boxPaddingY; 1498 } 1499 1500 1509 public long getDayAt(int x, int y) { 1510 if (_ltr ? (_startX > x) : (_startX < x) || _startY > y) { 1511 return -1; 1512 } 1513 1514 int calCol = (_ltr ? (x - _startX) : (_startX - x)) / 1516 (_calendarWidth + CALENDAR_SPACING); 1517 1518 int calRow = (y - _startY) / (_calendarHeight + CALENDAR_SPACING); 1520 1521 if (calRow > _numCalRows - 1 || calCol > _numCalCols - 1) { 1522 return -1; 1523 } 1524 1525 int row; 1527 row = ((y - _startY) - 1528 (calRow * (_calendarHeight + CALENDAR_SPACING))) / 1529 (_boxPaddingY + _boxHeight + _boxPaddingY); 1530 row -= 2; 1533 1534 if (row < 0 || row > 5) { 1535 return -1; 1536 } 1537 1538 int col = ((_ltr ? (x - _startX) : (_startX - x)) - 1540 (calCol * (_calendarWidth + CALENDAR_SPACING))) / 1541 (_boxPaddingX + _boxWidth + _boxPaddingX); 1542 1543 if (col > DAYS_IN_WEEK - 1) { 1544 return -1; 1545 } 1546 1547 _cal.setTimeInMillis(_firstDisplayedDate); 1551 _cal.add(Calendar.MONTH, calCol + (calRow * _numCalCols)); 1553 1554 int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK); 1555 int firstDayIndex = dayOfWeek - _firstDayOfWeek; 1556 if (firstDayIndex < 0) { 1557 firstDayIndex += DAYS_IN_WEEK; 1558 } 1559 1560 int daysToAdd = (row * DAYS_IN_WEEK) + (col - firstDayIndex); 1561 if (daysToAdd < 0 || daysToAdd > 1562 (_cal.getActualMaximum(Calendar.DAY_OF_MONTH) - 1)) { 1563 return -1; 1564 } 1565 1566 _cal.add(Calendar.DAY_OF_MONTH, daysToAdd); 1567 1568 long selected = _cal.getTimeInMillis(); 1569 1570 _cal.setTimeInMillis(_firstDisplayedDate); 1572 1573 return selected; 1574 } 1575 1576 private void calculateDirtyRectForSelection() { 1577 if (_startSelectedDate == -1 || _endSelectedDate == -1) { 1578 _dirtyRect.x = 0; 1579 _dirtyRect.y = 0; 1580 _dirtyRect.width = 0; 1581 _dirtyRect.height = 0; 1582 } else { 1583 _cal.setTimeInMillis(_startSelectedDate); 1584 calculateBoundsForDay(_dirtyRect); 1585 _cal.add(Calendar.DAY_OF_MONTH, 1); 1586 1587 Rectangle tmpRect; 1588 while (_cal.getTimeInMillis() <= _endSelectedDate) { 1589 calculateBoundsForDay(_bounds); 1590 tmpRect = _dirtyRect.union(_bounds); 1591 _dirtyRect.x = tmpRect.x; 1592 _dirtyRect.y = tmpRect.y; 1593 _dirtyRect.width = tmpRect.width; 1594 _dirtyRect.height = tmpRect.height; 1595 _cal.add(Calendar.DAY_OF_MONTH, 1); 1596 } 1597 1598 _cal.setTimeInMillis(_firstDisplayedDate); 1600 } 1601 } 1602 1603 1608 public String getActionCommand() { 1609 return _actionCommand; 1610 } 1611 1612 1617 public void setActionCommand(String actionCommand) { 1618 _actionCommand = actionCommand; 1619 } 1620 1621 1629 public void addActionListener(ActionListener l) { 1630 listenerList.add(ActionListener.class, l); 1631 } 1632 1633 1638 public void removeActionListener(ActionListener l) { 1639 listenerList.remove(ActionListener.class, l); 1640 } 1641 1642 1645 protected void fireActionPerformed() { 1646 Object [] listeners = listenerList.getListenerList(); 1647 ActionEvent e = null; 1648 for (int i = listeners.length - 2; i >= 0; i -=2) { 1649 if (listeners[i] == ActionListener.class) { 1650 if (e == null) { 1651 e = new ActionEvent(JXMonthView.this, 1652 ActionEvent.ACTION_PERFORMED, 1653 _actionCommand); 1654 } 1655 ((ActionListener)listeners[i + 1]).actionPerformed(e); 1656 } 1657 } 1658 } 1659 1660 1663 protected void processMouseEvent(MouseEvent e) { 1664 if (!isEnabled() || _selectionMode == NO_SELECTION) { 1665 return; 1666 } 1667 1668 int id = e.getID(); 1669 1670 if (id == MouseEvent.MOUSE_PRESSED) { 1671 int x = e.getX(); 1672 int y = e.getY(); 1673 1674 long selected = getDayAt(x, y); 1675 if (selected == -1) { 1676 return; 1677 } 1678 1679 _startSelectedDate = selected; 1681 _endSelectedDate = selected; 1682 1683 if (_selectionMode == MULTIPLE_SELECTION || 1684 _selectionMode == WEEK_SELECTION) { 1685 _pivotDate = selected; 1686 } 1687 1688 _cal.setTimeInMillis(selected); 1692 1693 calculateBoundsForDay(_bounds); 1694 _cal.setTimeInMillis(_firstDisplayedDate); 1695 1696 repaint(_dirtyRect); 1698 1699 repaint(_bounds); 1701 1702 _dirtyRect.x = _bounds.x; 1704 _dirtyRect.y = _bounds.y; 1705 _dirtyRect.width = _bounds.width; 1706 _dirtyRect.height = _bounds.height; 1707 1708 _asKirkWouldSay_FIRE = true; 1710 } else if (id == MouseEvent.MOUSE_RELEASED) { 1711 if (_asKirkWouldSay_FIRE) { 1712 fireActionPerformed(); 1713 } 1714 _asKirkWouldSay_FIRE = false; 1715 } 1716 super.processMouseEvent(e); 1717 } 1718 1719 1722 protected void processMouseMotionEvent(MouseEvent e) { 1723 if (!isEnabled() || _selectionMode == NO_SELECTION) { 1724 return; 1725 } 1726 1727 int id = e.getID(); 1728 1729 if (id == MouseEvent.MOUSE_DRAGGED) { 1730 int x = e.getX(); 1731 int y = e.getY(); 1732 long selected = getDayAt(x, y); 1733 1734 if (selected == -1) { 1735 return; 1736 } 1737 1738 long oldStart = _startSelectedDate; 1739 long oldEnd = _endSelectedDate; 1740 1741 if (_selectionMode == SINGLE_SELECTION) { 1742 if (selected == oldStart) { 1743 return; 1744 } 1745 _startSelectedDate = selected; 1746 _endSelectedDate = selected; 1747 } else { 1748 if (selected <= _pivotDate) { 1749 _startSelectedDate = selected; 1750 _endSelectedDate = _pivotDate; 1751 } else if (selected > _pivotDate) { 1752 _startSelectedDate = _pivotDate; 1753 _endSelectedDate = selected; 1754 } 1755 } 1756 1757 if (_selectionMode == WEEK_SELECTION) { 1758 long start = (selected > _pivotDate) ? _pivotDate : selected; 1760 long end = (selected > _pivotDate) ? selected : _pivotDate; 1761 1762 _cal.setTimeInMillis(start); 1763 int count = 1; 1764 while (_cal.getTimeInMillis() < end) { 1765 _cal.add(Calendar.DAY_OF_MONTH, 1); 1766 count++; 1767 } 1768 1769 if (count > 7) { 1770 _cal.setTimeInMillis(start); 1772 int dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK); 1773 int daysFromStart = dayOfWeek - _firstDayOfWeek; 1774 if (daysFromStart < 0) { 1775 daysFromStart += DAYS_IN_WEEK; 1776 } 1777 _cal.add(Calendar.DAY_OF_MONTH, -daysFromStart); 1778 1779 _startSelectedDate = _cal.getTimeInMillis(); 1780 1781 _cal.setTimeInMillis(end); 1783 dayOfWeek = _cal.get(Calendar.DAY_OF_WEEK); 1784 int lastDayOfWeek = _firstDayOfWeek - 1; 1785 if (lastDayOfWeek == 0) { 1786 lastDayOfWeek = Calendar.SATURDAY; 1787 } 1788 int daysTillEnd = lastDayOfWeek - dayOfWeek; 1789 if (daysTillEnd < 0) { 1790 daysTillEnd += DAYS_IN_WEEK; 1791 } 1792 _cal.add(Calendar.DAY_OF_MONTH, daysTillEnd); 1793 _endSelectedDate = _cal.getTimeInMillis(); 1794 } 1795 } 1796 1797 if (oldStart == _startSelectedDate && oldEnd == _endSelectedDate) { 1798 return; 1799 } 1800 1801 repaint(_dirtyRect); 1803 1804 calculateDirtyRectForSelection(); 1806 repaint(_dirtyRect); 1807 1808 _asKirkWouldSay_FIRE = true; 1810 } 1811 super.processMouseMotionEvent(e); 1812 } 1813} 1814 | Popular Tags |