/src/mpv5/ui/panels/calendar/ScheduleCalendarDayChooser.java
Java | 693 lines | 454 code | 97 blank | 142 comment | 91 complexity | dd5904e4e5dae87e574ed2d7ea3db77e MD5 | raw file
1/* 2 * JDayChooser.java - A bean for choosing a day 3 * Copyright (C) 2004 Kai Toedter 4 * kai@toedter.com 5 * www.toedter.com 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21package mpv5.ui.panels.calendar; 22 23import java.awt.BorderLayout; 24import java.awt.Color; 25import java.awt.Font; 26import java.awt.Graphics; 27import java.awt.GridLayout; 28import java.awt.Insets; 29import java.awt.event.KeyEvent; 30import java.awt.event.KeyListener; 31import java.awt.event.MouseListener; 32 33import java.text.DateFormatSymbols; 34 35import java.util.ArrayList; 36import java.util.Calendar; 37import java.util.Date; 38import java.util.Locale; 39 40import javax.swing.JButton; 41import javax.swing.JPanel; 42import javax.swing.UIManager; 43import javax.swing.border.LineBorder; 44import mpv5.db.objects.Schedule; 45import mpv5.logging.Log; 46import mpv5.ui.panels.ScheduleDayEventsPanel; 47import mpv5.utils.date.DateConverter; 48import mpv5.utils.date.vTimeframe; 49 50/** 51 * JDayChooser is a bean for choosing a day. 52 * 53 * @author Kai Toedter 54 * @version $LastChangedRevision: 104 $ 55 * @version $LastChangedDate: 2006-06-04 15:20:45 +0200 (So, 04 Jun 2006) $ 56 */ 57public final class ScheduleCalendarDayChooser extends JPanel implements KeyListener { 58 59 private static final long serialVersionUID = 5876398337018781820L; 60 protected ScheduleCalendarButton[] days; 61 protected JButton[] weeks; 62 protected ScheduleCalendarButton selectedDay; 63 protected JPanel weekPanel; 64 protected JPanel dayPanel; 65 protected int day; 66 protected Color oldDayBackgroundColor; 67 protected Color selectedColor; 68 protected Color sundayForeground; 69 protected Color weekdayForeground; 70 protected Color decorationBackgroundColor; 71 protected String[] dayNames; 72 protected Calendar calendar; 73 protected Calendar today; 74 protected Locale locale; 75 protected boolean initialized; 76 protected boolean weekOfYearVisible; 77 protected boolean decorationBackgroundVisible = false; 78 protected boolean decorationBordersVisible; 79 protected boolean dayBordersVisible; 80 private boolean alwaysFireDayProperty; 81 protected Date minSelectableDate; 82 protected Date maxSelectableDate; 83 protected Date defaultMinSelectableDate; 84 protected Date defaultMaxSelectableDate; 85 protected int maxDayCharacters; 86 private static ArrayList<Schedule> events; 87 private static ScheduleCalendarDayChooser icke; 88 89 /** 90 * The dc instance 91 * @return 92 */ 93 public static ScheduleCalendarDayChooser instanceOf() { 94 if (icke == null) { 95 icke = new ScheduleCalendarDayChooser(true); 96 } 97 return icke; 98 } 99 100 /** 101 * JDayChooser constructor. 102 * 103 * @param weekOfYearVisible 104 * true, if the weeks of a year shall be shown 105 */ 106 private ScheduleCalendarDayChooser(boolean weekOfYearVisible) { 107 setName("JDayChooser"); 108 setBackground(Color.blue); 109 this.weekOfYearVisible = weekOfYearVisible; 110 locale = Locale.getDefault(); 111 days = new ScheduleCalendarButton[49]; 112 selectedDay = null; 113 calendar = Calendar.getInstance(locale); 114 today = (Calendar) calendar.clone(); 115 116 setLayout(new BorderLayout()); 117 118 dayPanel = new JPanel(); 119 dayPanel.setLayout(new GridLayout(7, 7)); 120 121 maxDayCharacters = 2; 122 123 sundayForeground = new Color(164, 0, 0); 124 weekdayForeground = new Color(0, 90, 164); 125 126 decorationBackgroundColor = new Color(238, 238, 238); 127 128 for (int y = 0; y < 7; y++) { 129 for (int x = 0; x < 7; x++) { 130 int index = x + (7 * y); 131 132 if (y == 0) { 133 // Create a button that doesn't react on clicks or focus 134 // changes. 135 // Thanks to Thomas Schaefer for the focus hint :) 136 days[index] = new DecoratorButton(); 137 } else { 138 days[index] = new ScheduleCalendarButton(new Date()) { 139 140 private static final long serialVersionUID = -7433645992591669725L; 141 142 @Override 143 public void paint(Graphics g) { 144 if ("Windows".equals(UIManager.getLookAndFeel().getID())) { 145 // this is a hack to get the background painted 146 // when using Windows Look & Feel 147 if (selectedDay == this) { 148 g.setColor(selectedColor); 149 g.fillRect(0, 0, getWidth(), getHeight()); 150 } 151 } 152 super.paint(g); 153 } 154 }; 155 days[index].addActionListener(days[index]); 156 days[index].addKeyListener(this); 157 } 158 159 days[index].setMargin(new Insets(1, 1, 1, 1)); 160 days[index].setFocusPainted(true); 161 days[index].setContentAreaFilled(true); 162 days[index].setBorderPainted(true); 163 dayPanel.add(days[index]); 164 } 165 } 166 167 weekPanel = new JPanel(); 168 weekPanel.setLayout(new GridLayout(7, 1)); 169 weeks = new JButton[7]; 170 171 for (int i = 0; i < 7; i++) { 172 weeks[i] = new DecoratorButton(); 173 weeks[i].setMargin(new Insets(0, 0, 0, 0)); 174 weeks[i].setFocusPainted(false); 175 weeks[i].setForeground(new Color(100, 100, 100)); 176 177 if (i != 0) { 178 weeks[i].setText("0" + (i + 1)); 179 } 180 181 weekPanel.add(weeks[i]); 182 } 183 184 Calendar tmpCalendar = Calendar.getInstance(); 185 tmpCalendar.set(1, 0, 1, 1, 1); 186 defaultMinSelectableDate = tmpCalendar.getTime(); 187 minSelectableDate = defaultMinSelectableDate; 188 tmpCalendar.set(9999, 0, 1, 1, 1); 189 defaultMaxSelectableDate = tmpCalendar.getTime(); 190 maxSelectableDate = defaultMaxSelectableDate; 191 192 init(); 193 194 setDay(Calendar.getInstance().get(Calendar.DAY_OF_MONTH)); 195 add(dayPanel, BorderLayout.CENTER); 196 add(weekPanel, BorderLayout.WEST); 197 updateUI(); 198 } 199 200 /** 201 * Initilizes the locale specific names for the days of the week. 202 */ 203 protected void init() { 204 205 oldDayBackgroundColor = Color.WHITE; 206 selectedColor = new Color(160, 160, 160); 207 208 Date date = calendar.getTime(); 209 calendar = Calendar.getInstance(locale); 210 calendar.setTime(date); 211 212 drawDayNames(); 213 drawDays(Schedule.getEvents2(new vTimeframe(DateConverter.getStartOfMonth(new Date()), DateConverter.getEndOfMonth(new Date())))); 214 } 215 216 /** 217 * Draws the day names of the day columnes. 218 * 219 */ 220 protected void drawDayNames() { 221 int firstDayOfWeek = calendar.getFirstDayOfWeek(); 222 DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale); 223 dayNames = dateFormatSymbols.getShortWeekdays(); 224 225 int fwd = firstDayOfWeek; 226 227 for (int i = 0; i < 7; i++) { 228 if (maxDayCharacters > 0 && maxDayCharacters < 5) { 229 if (dayNames[fwd].length() >= maxDayCharacters) { 230 dayNames[fwd] = dayNames[fwd].substring(0, maxDayCharacters); 231 } 232 } 233 234 days[i].setText(dayNames[fwd]); 235 days[i].setFont(days[i].getFont().deriveFont(Font.BOLD)); 236 237 if (fwd == 1) { 238 days[i].setForeground(sundayForeground); 239 } else { 240 days[i].setForeground(weekdayForeground); 241 } 242 243 if (fwd < 7) { 244 fwd++; 245 } else { 246 fwd -= 6; 247 } 248 } 249 } 250 251 /** 252 * Hides and shows the week buttons. 253 */ 254 protected void drawWeeks() { 255 Calendar tmpCalendar = (Calendar) calendar.clone(); 256 257 for (int i = 1; i < 7; i++) { 258 tmpCalendar.set(Calendar.DAY_OF_MONTH, (i * 7) - 6); 259 260 int week = tmpCalendar.get(Calendar.WEEK_OF_YEAR); 261 String buttonText = Integer.toString(week); 262 263 if (week < 10) { 264 buttonText = "0" + buttonText; 265 } 266 267 weeks[i].setText(buttonText); 268 weeks[i].setContentAreaFilled(false); 269 270 if ((i == 5) || (i == 6)) { 271 weeks[i].setVisible(days[i * 7].isVisible()); 272 } 273 } 274 275 setDayBordersVisible(true); 276 277 } 278 279 /** 280 * Hides and shows the day buttons. 281 * @param list 282 */ 283 protected void drawDays(ArrayList<Schedule> list) { 284 285 if (list != null) { 286 events = list; 287 } 288 289 Calendar tmpCalendar = (Calendar) calendar.clone(); 290 tmpCalendar.set(Calendar.HOUR_OF_DAY, 0); 291 tmpCalendar.set(Calendar.MINUTE, 0); 292 tmpCalendar.set(Calendar.SECOND, 0); 293 tmpCalendar.set(Calendar.MILLISECOND, 0); 294 295 Calendar minCal = Calendar.getInstance(); 296 minCal.setTime(minSelectableDate); 297 minCal.set(Calendar.HOUR_OF_DAY, 0); 298 minCal.set(Calendar.MINUTE, 0); 299 minCal.set(Calendar.SECOND, 0); 300 minCal.set(Calendar.MILLISECOND, 0); 301 302 Calendar maxCal = Calendar.getInstance(); 303 maxCal.setTime(maxSelectableDate); 304 maxCal.set(Calendar.HOUR_OF_DAY, 0); 305 maxCal.set(Calendar.MINUTE, 0); 306 maxCal.set(Calendar.SECOND, 0); 307 maxCal.set(Calendar.MILLISECOND, 0); 308 309 int firstDayOfWeek = tmpCalendar.getFirstDayOfWeek(); 310 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1); 311 312 int firstDay = tmpCalendar.get(Calendar.DAY_OF_WEEK) - firstDayOfWeek; 313 314 if (firstDay < 0) { 315 firstDay += 7; 316 } 317 318 int i; 319 320 for (i = 0; i < firstDay; i++) { 321 days[i + 7].setVisible(false); 322 days[i + 7].setText(""); 323 } 324 325 tmpCalendar.add(Calendar.MONTH, 1); 326 327 Date firstDayInNextMonth = tmpCalendar.getTime(); 328 tmpCalendar.add(Calendar.MONTH, -1); 329 330 Date time = tmpCalendar.getTime(); 331 int n = 0; 332 Color foregroundColor = getForeground(); 333 334 while (time.before(firstDayInNextMonth)) { 335 days[i + n + 7].setDate(time); 336 days[i + n + 7].setText(Integer.toString(n + 1)); 337 days[i + n + 7].setVisible(true); 338 Log.Debug(this, "Creating Day: " + days[i + n + 7].getText()); 339 340 if ((tmpCalendar.get(Calendar.DAY_OF_YEAR) == today.get(Calendar.DAY_OF_YEAR)) && (tmpCalendar.get(Calendar.YEAR) == today.get(Calendar.YEAR))) { 341 days[i + n + 7].setForeground(sundayForeground); 342 } else { 343 days[i + n + 7].setForeground(foregroundColor); 344 } 345 346 if ((n + 1) == this.day) { 347 days[i + n + 7].setBackground(selectedColor); 348 selectedDay = days[i + n + 7]; 349 } else { 350 days[i + n + 7].setBackground(oldDayBackgroundColor); 351 } 352 353 if (tmpCalendar.before(minCal) || tmpCalendar.after(maxCal)) { 354 days[i + n + 7].setEnabled(false); 355 } else { 356 days[i + n + 7].setEnabled(true); 357 } 358 359 Log.Debug(this, "Checking events"); 360 int j = 0; 361 if (events != null) { 362 days[i + n + 7].clearScheduledEvents(); 363 while (!events.isEmpty() && events.size() > j) { 364 Schedule schedule = events.get(j); 365 Log.Debug(this, "Checking date: " 366 + schedule.getDate() 367 + " against " 368 + days[i + n + 7].getText()); 369 if (schedule.getDate().contains(time)) { 370 Log.Debug(this, "Found date: " + schedule.getDate()); 371 days[i + n + 7].addScheduledEvent(schedule); 372 events.remove(j); 373 } else { 374 j++; 375 } 376 } 377 } 378 379 n++; 380 tmpCalendar.add(Calendar.DATE, 1); 381 time = tmpCalendar.getTime(); 382 } 383 384 for (int k = n + i + 7; k < 49; k++) { 385 days[k].setVisible(false); 386 days[k].setText(""); 387 } 388 389 drawWeeks(); 390 } 391 392 /** 393 * Returns the locale. 394 * 395 * @return the locale value 396 * 397 * @see #setLocale 398 */ 399 @Override 400 public Locale getLocale() { 401 return locale; 402 } 403 404 /** 405 * Sets the locale. 406 * 407 * @param locale 408 * the new locale value 409 * 410 * @see #getLocale 411 */ 412 @Override 413 public void setLocale(Locale locale) { 414 if (!initialized) { 415 super.setLocale(locale); 416 } else { 417 this.locale = locale; 418 super.setLocale(locale); 419 init(); 420 } 421 } 422 423 /** 424 * Sets the day. This is a bound property. 425 * 426 * @param d 427 * the day 428 * 429 * @see #getDay 430 */ 431 public void setDay(int d) { 432 if (d < 1) { 433 d = 1; 434 } 435 Calendar tmpCalendar = (Calendar) calendar.clone(); 436 tmpCalendar.set(Calendar.DAY_OF_MONTH, 1); 437 tmpCalendar.add(Calendar.MONTH, 1); 438 tmpCalendar.add(Calendar.DATE, -1); 439 440 int maxDaysInMonth = tmpCalendar.get(Calendar.DATE); 441 442 if (d > maxDaysInMonth) { 443 d = maxDaysInMonth; 444 } 445 446 int oldDay = day; 447 day = d; 448 449 if (selectedDay != null) { 450 selectedDay.setBackground(oldDayBackgroundColor); 451 selectedDay.repaint(); 452 } 453 454 for (int i = 7; i < 49; i++) { 455 if (days[i].getText().equals(Integer.toString(day))) { 456 selectedDay = days[i]; 457 selectedDay.setBackground(selectedColor); 458 } else if (days[i].hasEvents()) { 459 days[i].setBackground(Color.GREEN); 460 } 461 } 462 463 if (alwaysFireDayProperty) { 464 firePropertyChange("day", 0, day); 465 } else { 466 firePropertyChange("day", oldDay, day); 467 } 468 } 469 470 /** 471 * Returns the selected day. 472 * 473 * @return the day value 474 * 475 * @see #setDay 476 */ 477 public int getDay() { 478 return day; 479 } 480 481 /** 482 * Sets a specific month. This is needed for correct graphical 483 * representation of the days. 484 * 485 * @param month 486 * the new month 487 */ 488 public void setMonth(int month) { 489 int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); 490 calendar.set(Calendar.MONTH, month); 491 if (maxDays == day) { 492 day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); 493 } 494 Log.Debug(this, 495 "Setting Month to: " + calendar.getDisplayName( 496 month, 497 Calendar.LONG, 498 locale)); 499 setDay(day); 500 501 drawDays( 502 Schedule.getEvents2( 503 new vTimeframe( 504 DateConverter.getStartOfMonth(calendar.getTime()), 505 DateConverter.getEndOfMonth(calendar.getTime())))); 506 } 507 508 /** 509 * Sets a specific year. This is needed for correct graphical representation 510 * of the days. 511 * 512 * @param year 513 * the new year 514 */ 515 public void setYear(int year) { 516 calendar.set(Calendar.YEAR, year); 517 drawDays( 518 Schedule.getEvents2( 519 new vTimeframe( 520 DateConverter.getStartOfMonth(calendar.getTime()), 521 DateConverter.getEndOfMonth(calendar.getTime())))); 522 523 ScheduleDayEventsPanel.instanceOf().setDayEvents(null); 524 } 525 526 /** 527 * Sets a specific calendar. This is needed for correct graphical 528 * representation of the days. 529 * 530 * @param calendar 531 * the new calendar 532 */ 533 public void setCalendar(Calendar calendar) { 534 this.calendar = calendar; 535 drawDays( 536 Schedule.getEvents2( 537 new vTimeframe( 538 DateConverter.getStartOfMonth(calendar.getTime()), 539 DateConverter.getEndOfMonth(calendar.getTime())))); 540 } 541 542 /** 543 * Sets the font property. 544 * 545 * @param font 546 * the new font 547 */ 548 @Override 549 public void setFont(Font font) { 550 if (days != null) { 551 for (int i = 0; i < 49; i++) { 552 days[i].setFont(font); 553 } 554 } 555 if (weeks != null) { 556 for (int i = 0; i < 7; i++) { 557 weeks[i].setFont(font); 558 } 559 } 560 } 561 562 /** 563 * JDayChooser is the KeyListener for all day buttons. (Added by Thomas 564 * Schaefer and modified by Austin Moore) 565 * 566 * @param e 567 * the KeyEvent 568 */ 569 public void keyPressed(KeyEvent e) { 570 int offset = (e.getKeyCode() == KeyEvent.VK_UP) ? (-7) 571 : ((e.getKeyCode() == KeyEvent.VK_DOWN) ? (+7) 572 : ((e.getKeyCode() == KeyEvent.VK_LEFT) ? (-1) 573 : ((e.getKeyCode() == KeyEvent.VK_RIGHT) ? (+1) : 0))); 574 575 int newDay = getDay() + offset; 576 577 if ((newDay >= 1) && (newDay <= calendar.getMaximum(Calendar.DAY_OF_MONTH))) { 578 setDay(newDay); 579 } 580 } 581 582 /** 583 * Does nothing. 584 * 585 * @param e 586 * the KeyEvent 587 */ 588 public void keyTyped(KeyEvent e) { 589 } 590 591 /** 592 * Does nothing. 593 * 594 * @param e 595 * the KeyEvent 596 */ 597 public void keyReleased(KeyEvent e) { 598 } 599 600 public void setDayBordersVisible(boolean dayBordersVisible) { 601 this.dayBordersVisible = dayBordersVisible; 602 if (initialized) { 603 604 for (int x = 0; x < 7; x++) { 605 606 days[x].setContentAreaFilled(false); 607 days[x].setBorder(new LineBorder(Color.white, 1, false)); 608 days[x].setBorderPainted(true); 609 days[x].setBackground(Color.LIGHT_GRAY); 610 } 611 612 for (int x = 7; x < 49; x++) { 613 days[x].setContentAreaFilled(false); 614 days[x].setBorderPainted(dayBordersVisible); 615 days[x].setBorder(new LineBorder(Color.darkGray, 1, false)); 616 } 617 } 618 } 619 620 public void refreshDayPanels(Date nday, Schedule sched, Boolean add) { 621 Log.Debug(this, "aktualisieren DaySelektor ... geklickt"); 622 for (int o = 0; o < days.length; o++) { 623// Log.Debug(this, "Checking ..." + days[o].getDate() + "\n" 624// + "angainst ..." + nday ); 625 if (days[o].getDate().equals(nday)) { 626 if (add) { 627 Log.Debug(this, "aktualisieren DaySelektor ... a"); 628 days[o].addScheduledEvent(sched); 629 } else { 630 Log.Debug(this, "aktualisieren DaySelektor ... b"); 631 days[o].removeScheduledEvent(sched); 632 } 633 } 634 } 635 Log.Debug(this, "aktualisieren DaySelektor ... fertig"); 636 } 637 638 public ArrayList<Schedule> getScheduledEvents(Date nday) { 639 for (int o = 0; o < days.length; o++) { 640 if (days[o].getDate().equals(nday)) { 641 return days[o].getScheduledEvents(); 642 } 643 } 644 return null; 645 } 646 647 /** 648 * Creates a JFrame with a JDayChooser inside and can be used for testing. 649 * 650 * @param s 651 * The command line arguments 652 */ 653 class DecoratorButton extends ScheduleCalendarButton { 654 655 private static final long serialVersionUID = -5306477668406547496L; 656 657 public DecoratorButton() { 658 super(new Date()); 659 setBackground(decorationBackgroundColor); 660 setContentAreaFilled(decorationBackgroundVisible); 661 setBorderPainted(decorationBordersVisible); 662 } 663 664 @Override 665 public void addMouseListener(MouseListener l) { 666 } 667 668 @Override 669 public boolean isFocusable() { 670 return false; 671 } 672 673 @Override 674 public void paint(Graphics g) { 675 if ("Windows".equals(UIManager.getLookAndFeel().getID())) { 676 // this is a hack to get the background painted 677 // when using Windows Look & Feel 678 if (decorationBackgroundVisible) { 679 g.setColor(decorationBackgroundColor); 680 } else { 681 g.setColor(days[7].getBackground()); 682 } 683 g.fillRect(0, 0, getWidth(), getHeight()); 684 if (isBorderPainted()) { 685 setContentAreaFilled(true); 686 } else { 687 setContentAreaFilled(false); 688 } 689 } 690 super.paint(g); 691 } 692 }; 693}