View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components;
21  
22  import java.awt.BorderLayout;
23  import java.awt.CardLayout;
24  import java.awt.Color;
25  import java.awt.Component;
26  import java.awt.Dimension;
27  import java.awt.Font;
28  import java.awt.Graphics;
29  import java.awt.Graphics2D;
30  import java.awt.GridBagConstraints;
31  import java.awt.GridBagLayout;
32  import java.awt.Point;
33  import java.awt.event.ActionEvent;
34  import java.awt.event.ActionListener;
35  import java.awt.event.ItemEvent;
36  import java.awt.event.ItemListener;
37  import java.awt.event.KeyEvent;
38  import java.awt.event.KeyListener;
39  import java.awt.event.MouseEvent;
40  import java.awt.event.MouseListener;
41  import java.awt.event.WindowAdapter;
42  import java.awt.event.WindowEvent;
43  import java.beans.PropertyChangeEvent;
44  import java.beans.PropertyChangeListener;
45  import java.text.DateFormatSymbols;
46  import java.util.ArrayList;
47  import java.util.Calendar;
48  import java.util.Date;
49  import java.util.GregorianCalendar;
50  import java.util.Iterator;
51  import java.util.List;
52  import java.util.Timer;
53  import java.util.TimerTask;
54  
55  import javax.swing.DefaultComboBoxModel;
56  import javax.swing.JComboBox;
57  import javax.swing.JComponent;
58  import javax.swing.JFrame;
59  import javax.swing.JLabel;
60  import javax.swing.JList;
61  import javax.swing.JMenuItem;
62  import javax.swing.JPanel;
63  import javax.swing.JPopupMenu;
64  import javax.swing.ListCellRenderer;
65  import javax.swing.SwingUtilities;
66  import javax.swing.border.LineBorder;
67  import javax.swing.event.ListSelectionEvent;
68  import javax.swing.plaf.basic.BasicComboBoxEditor;
69  
70  
71  import com.cosylab.gui.components.util.ColorHelper;
72  import com.cosylab.gui.components.util.CosyUIElements;
73  import com.cosylab.gui.components.util.PaintHelper;
74  import com.cosylab.util.DateSpan;
75  
76  
77  /**
78   * A simple graphical widget for selecting date intervals.  The component
79   * consists of a <code>SimpleComboBox</code> containing months and years and
80   * a panel of labels indicating days in the selected month. The user can
81   * select date intervals by dragging the mouse over the chosen set of date
82   * labels.  Selections of spanning over multiple months are possible by
83   * dragging the mouse outside the date panel area in the chosen direction.
84   * <p>
85   * When a date is selected PropertyChangeListeners are notified through the
86   * property <code>selectedDateSpan</code>. The new value indicates the current
87   * date selection. Date is always selected from the midnight of the beginning
88   * date till the end of the ending date.
89   * </p> 
90   *
91   * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
92   * @version $id$
93   */
94  public class DateSpanSelector extends JPanel
95  {
96  	private static final long serialVersionUID = -501052522043801432L;
97  	private static final Color EXTENDED_SELECTION_COLOR = Color.red;
98  
99  	private class YearButton extends ArrowButton {
100 
101 		private static final long serialVersionUID = -6687714559622460070L;
102 		private int orientation;
103 		public YearButton(int orientation){
104 			super(orientation);
105 			this.orientation = orientation;
106 		}
107 		@Override
108 		public void paintComponent(Graphics g) {
109 			((Graphics2D)g).addRenderingHints(PaintHelper.getAntialiasingHints());
110 			super.paintComponent(g);
111 
112 			int maxHeight = getBounds().height;
113 			int maxWidth = getBounds().width;
114 			int top=1;
115 			int bottom=1;
116 			int left=1;
117 			int right=1;
118 			top = Math.min(maxWidth, maxHeight) / 4;
119 			bottom = Math.min(maxWidth, maxHeight) / 4;
120 			left = Math.min(maxWidth, maxHeight) / 4;
121 			right = Math.min(maxWidth, maxHeight) / 4;
122 
123 			g.setColor(getForeground());
124 			if (orientation == RIGHT) {
125 				int middle = 2*(maxWidth - right)/3;
126 				middle = left+(maxWidth-right-left)/2;
127 				int[] ys = { top, maxHeight / 2, maxHeight / 2, top, maxHeight / 2, maxHeight - bottom, maxHeight / 2,maxHeight / 2,  maxHeight - bottom};
128 				int[] xs = { left, middle, middle, middle, maxWidth-right, middle, middle, middle, left };
129 				g.fillPolygon(xs, ys, 9);
130 			} else if (orientation == LEFT) {
131 				
132 				int middle = 2*(maxWidth - right)/3;
133 				middle = left+(maxWidth-right-left)/2;
134 				int[] ys = { top, maxHeight / 2, maxHeight / 2, top, maxHeight / 2, maxHeight - bottom, maxHeight / 2,maxHeight / 2,  maxHeight - bottom};
135 				int[] xs = { maxWidth-right, middle, middle, middle, left, middle, middle, middle, maxWidth-right };
136 				g.fillPolygon(xs, ys, 9);
137 			}
138 			
139 		}		
140 	}
141 	
142 	/* A container for date labels of one month,
143 	 * also manages all user actions.
144 	 */
145 	private class DatePanel extends JComponent implements ItemListener,
146 		MouseListener, KeyListener
147 	{
148 		private static final long serialVersionUID = 3649761076701751548L;
149 
150 		/* A simple extension of com.cosylab.gui.components.JResizableLabel
151 		 * designed for storing dates.
152 		 */
153 		private class DateCell extends ResizableTextLabel
154 		{
155 			private static final long serialVersionUID = -6558819543510561495L;
156 			private int date;
157 			private boolean adjustFont;
158 			private boolean paintForward;
159 			private boolean paintBackward;
160 
161 			/**
162 			 * Constructor for DateCell
163 			 */
164 			public DateCell()
165 			{
166 				super("  ");
167 				setResizable(true);
168 				setColumns(2);
169 				setOpaque(true);
170 				setHorizontalAlignment(JLabel.CENTER);
171 				setMinimumSize(new Dimension(30, 10));
172 				setEnhanced(true);
173 				setFocusable(true);
174 			}
175 
176 			/**
177 			 * Sets the day in the month to the date cell.
178 			 *
179 			 * @param newDate int
180 			 *
181 			 * @throws IllegalArgumentException if date value is less then 1 or
182 			 *         more than 31
183 			 */
184 			public void setDate(int newDate)
185 			{
186 				if ((newDate < 1) || (newDate > 31)) {
187 					throw new IllegalArgumentException(
188 					    "Date value out of bounds: " + newDate);
189 				}
190 
191 				date = newDate;
192 
193 				if (newDate < 10) {
194 					setText(" " + String.valueOf(newDate));
195 				} else {
196 					setText(String.valueOf(newDate));
197 				}
198 			}
199 
200 			/**
201 			 * Returns the day in the month stored in the date cell.
202 			 *
203 			 * @return int the number of the day in the month.
204 			 */
205 			public int getDate()
206 			{
207 				return date;
208 			}
209 			protected void resize()
210 			{
211 				if (adjustFont){
212 					super.resize();
213 					unifyFontSize();
214 				}
215 			}
216 
217 			public boolean isAdjustFont() {
218 				return adjustFont;
219 			}
220 
221 			public void setAdjustFont(boolean adjustFont) {
222 				this.adjustFont = adjustFont;
223 			}
224 
225 			@Override
226 			protected void paintComponent(Graphics g) {
227 				super.paintComponent(g);
228 				// painting symbols for extended selection
229 				//int maxHeight = getBounds().height;
230 				//int maxWidth = getBounds().width;
231 				//smaller arrows
232 				/*if (isPaintBackward()){
233 					int refX = 3*maxWidth/4;
234 					int refY = 3*maxHeight/4;
235 					int[] ys = { refY, refY+(maxHeight-refY)/2, maxHeight};
236 					int[] xs = { refX, maxWidth, refX};
237 					g.setColor(EXTENDED_SELECTION_COLOR);
238 					g.fillPolygon(xs, ys, 3);
239 				}
240 				else if (isPaintForward()){
241 					int[] ys = { 0, maxHeight/4, maxHeight/8  };
242 					int[] xs = { maxWidth/4, maxWidth/4, 0 };
243 					g.setColor(EXTENDED_SELECTION_COLOR);
244 					g.fillPolygon(xs, ys, 3);
245 				}*/
246 				//larger arrows
247 				/*if (isPaintBackward()){
248 					int refX = 0;
249 					int refY = 0;
250 					int[] ys = { refY, refY+(maxHeight-refY)/2, maxHeight};
251 					int[] xs = { refX, maxWidth, refX};
252 					g.setColor(EXTENDED_SELECTION_COLOR);
253 					g.fillPolygon(xs, ys, 3);
254 				}
255 				else if (isPaintForward()){
256 					int[] ys = { 0, maxHeight, maxHeight/2  };
257 					int[] xs = { maxWidth, maxWidth, 0 };
258 					g.setColor(EXTENDED_SELECTION_COLOR);
259 					g.fillPolygon(xs, ys, 3);
260 				}*/
261 				
262 				//slim arrows
263 				
264 				int maxHeight = getBounds().height;
265 				int maxWidth = getBounds().width/4;
266 				
267 				if ((isPaintForward())){
268 					int refX = (3*getBounds().width)/4;
269 					int refY = 0;
270 					int[] ys = { refY, refY+(maxHeight-refY)/2, refY+maxHeight};
271 					int[] xs = { refX, refX+maxWidth, refX};
272 					g.setColor(EXTENDED_SELECTION_COLOR);
273 					g.fillPolygon(xs, ys, 3);
274 				}
275 				else if (isPaintBackward()){
276 					int refX = 0;
277 					int refY = 0;
278 					int[] ys = {refY+0, refY+maxHeight, refY+maxHeight/2  };
279 					int[] xs = {refX+maxWidth, refX+maxWidth, refX+0 };
280 					g.setColor(EXTENDED_SELECTION_COLOR);
281 					g.fillPolygon(xs, ys, 3);
282 				}				
283 			}
284 
285 			public boolean isPaintForward() {
286 				return paintForward;
287 			}
288 
289 			public void setPaintForward(boolean paintForward) {
290 				this.paintForward = paintForward;
291 			}
292 
293 			public boolean isPaintBackward() {
294 				return paintBackward;
295 			}
296 
297 			public void setPaintBackward(boolean paintBackward) {
298 				this.paintBackward = paintBackward;
299 			}
300 		}
301 		private class DayNameCell extends ResizableTextLabel
302 		{
303 			private static final long serialVersionUID = -6558819541235431495L;
304 			private boolean adjustFont;
305 
306 			public DayNameCell(String string) {
307 				super(string);
308 			}
309 
310 			protected void resize()
311 			{
312 				if (adjustFont){
313 					super.resize();
314 					unifyFontSize();
315 				}
316 			}
317 
318 			public boolean isAdjustFont() {
319 				return adjustFont;
320 			}
321 
322 			public void setAdjustFont(boolean adjustFont) {
323 				this.adjustFont = adjustFont;
324 			}
325 		}		
326 
327 		private Calendar currentDate;
328 		private Calendar displayMonthDate;
329 		private Calendar selectionFinishDate;
330 		private Calendar selectionStartDate;
331 		//private Color dayNameBackground = ColorHelper.getControlShadow();
332 		//changed as per request 36667
333 		private Color dayNameBackground = new Color(218,226,234);
334 		
335 		private Color dayNameForeground = ColorHelper.getControlDarkShadow();//ColorHelper.getControlHighlight();
336 		private Color othersForeground = ColorHelper.getControlDarkShadow();
337 		//private Color sundayBackground = ColorHelper.getControlShadow();
338 		private Color sundayBackground = new Color(218,226,234);
339 		private Color sundayForeground = ColorHelper.getControlText();
340 		private Color sundaySelection = ColorHelper.getCosyControlShadow();
341 		private List<DateCell> dateCells;
342 		private List<DayNameCell> dayNameCells;
343 		
344 		private Timer switchTimer = null;
345 		private boolean selecting;
346 		private int switching;
347 
348 		/**
349 		 * Constructor for DatePanel
350 		 */
351 		public DatePanel()
352 		{
353 			super();
354 			setBackground(ColorHelper.getWindowBackground());
355 			currentDate = GregorianCalendar.getInstance();
356 			displayMonthDate = GregorianCalendar.getInstance();
357 			displayMonthDate.set(Calendar.DATE, 15);
358 			normalizeToMiddleOfDay(displayMonthDate);
359 			populateDateList();
360 			pupulateDayNamesList();
361 			init();
362 		}
363 
364 		private void pupulateDayNamesList() {
365 			if (dayNameCells == null) {
366 				dayNameCells = new ArrayList<DayNameCell>();
367 			}
368 			DayNameCell dateLabel = null;
369 			for (int i = 0; i < 7; i++) {
370 				dateLabel = new DayNameCell(DAYS[i]);
371 				if (i==0) dateLabel.setAdjustFont(true); 
372 				dateLabel.setOpaque(true);
373 				dateLabel.setBackground(dayNameBackground);
374 				dateLabel.setForeground(dayNameForeground);
375 				dateLabel.setResizable(true);
376 				dateLabel.setColumns(3);
377 				dateLabel.setHorizontalAlignment(JLabel.CENTER);
378 				Font f = dateLabel.getFont();
379 				dateLabel.setFont(f.deriveFont(f.getStyle() ^ Font.BOLD));
380 				dayNameCells.add(dateLabel);
381 			}
382 			
383 		}
384 
385 		/**
386 		 * Performs initialization of the DatePanel.
387 		 */
388 		public void init()
389 		{
390 			removeAll();
391 			setLayout(new CosyUIElements.FillingGridLayout(0, 7));
392 			setOpaque(true);
393 
394 			
395 
396 			for (int i = 0; i < 7; i++) {
397 				add(dayNameCells.get(i));
398 			}
399 
400 
401 			for (int i = 0; i < 42; i++) {
402 				add(dateCells.get(i));
403 			}
404 		}
405 
406 		/**
407 		 * Invoked when a different month was selected in MonthCombo that
408 		 * should be displayed
409 		 *
410 		 * @param e ListSelectionEvent
411 		 *
412 		 * @see javax.swing.event.ListSelectionListener#valueChanged(ListSelectionEvent)
413 		 */
414 		public void itemStateChanged(ItemEvent e)
415 		{
416 			Calendar monthDate = (Calendar)((JComboBox)e.getSource())
417 				.getSelectedItem();
418 
419 			if ((displayMonthDate.get(Calendar.YEAR) == monthDate.get(
420 			        Calendar.YEAR))
421 			    && (displayMonthDate.get(Calendar.MONTH) == monthDate.get(
422 			        Calendar.MONTH))) {
423 				return;
424 			}
425 
426 			displayMonthDate.set(Calendar.YEAR, monthDate.get(Calendar.YEAR));
427 			displayMonthDate.set(Calendar.MONTH, monthDate.get(Calendar.MONTH));
428 
429 			if (selecting) {
430 				ensureSelection();
431 				selectionFinishDate.set(Calendar.YEAR,
432 				    monthDate.get(Calendar.YEAR));
433 				selectionFinishDate.set(Calendar.MONTH,
434 				    monthDate.get(Calendar.MONTH));
435 			}
436 
437 			populateDateList();
438 		}
439 
440 		/* (non-Javadoc)
441 		 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
442 		 */
443 		public void keyPressed(KeyEvent e)
444 		{
445 			if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
446 				selecting = true;
447 
448 				return;
449 			}
450 
451 			int date = ((DateCell)e.getSource()).getDate();
452 
453 			if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
454 				displayMonthDate = Calendar.getInstance();
455 				normalizeToMiddleOfDay(displayMonthDate);
456 				date = displayMonthDate.get(Calendar.DAY_OF_MONTH);
457 			} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
458 				date++;
459 			} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
460 				date--;
461 			} else if (e.getKeyCode() == KeyEvent.VK_UP) {
462 				date -= 7;
463 			} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
464 				date += 7;
465 			} else {
466 				return;
467 			}
468 
469 			if (date > displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH)) {
470 				date = date
471 					- displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH);
472 				displayMonthDate.add(Calendar.MONTH, 1);
473 			} else if (date < 1) {
474 				displayMonthDate.add(Calendar.MONTH, -1);
475 				date = displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH)
476 					+ date;
477 			}
478 
479 			if ((e.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK) {
480 				ensureSelection();
481 				selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
482 				    displayMonthDate.get(Calendar.MONTH), date);
483 			} else {
484 				ensureSelection();
485 				selectionStartDate.set(displayMonthDate.get(Calendar.YEAR),
486 				    displayMonthDate.get(Calendar.MONTH), date);
487 				selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
488 				    displayMonthDate.get(Calendar.MONTH), date);
489 
490 				selectionStopped();
491 			}
492 
493 			Calendar datec = createCopy(displayMonthDate);
494 			datec.set(Calendar.DAY_OF_MONTH, 1);
495 			normalizeToBeginningOfDay(datec);
496 			monthCombo.setSelectedItem(datec);
497 
498 			populateDateList();
499 		}
500 
501 		/* (non-Javadoc)
502 		 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
503 		 */
504 		public void keyReleased(KeyEvent arg0)
505 		{
506 			if (arg0.getKeyCode() == KeyEvent.VK_SHIFT) {
507 				selectionStopped();
508 			}
509 		}
510 
511 		/* (non-Javadoc)
512 		 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
513 		 */
514 		public void keyTyped(KeyEvent arg0)
515 		{
516 		}
517 
518 		/**
519 		 * Invoked when the user clicks the mouse inside  one of the date
520 		 * cells. The cell is selected and the starting and finishing date
521 		 * selections are set to the same date.
522 		 *
523 		 * @param e MouseEvent
524 		 *
525 		 * @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
526 		 */
527 		public void mouseClicked(MouseEvent e)
528 		{	
529 			if (e.getButton()== MouseEvent.BUTTON3){
530 				getPopup().show(e.getComponent(),
531 	                       e.getX(), e.getY());
532 				return;
533 			}
534 			if (!this.isEnabled()) return;
535 			int date = ((DateCell)e.getSource()).getDate();
536 			int monthOffset = 0;
537 
538 			if ((date < 15) && !((DateCell)e.getSource()).isEnabled()) {
539 				monthOffset++;
540 			} else if ((date > 15) && !((DateCell)e.getSource()).isEnabled()) {
541 				monthOffset--;
542 			}
543 
544 			ensureSelection();
545 			selectionStartDate.set(displayMonthDate.get(Calendar.YEAR),
546 			    displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
547 			selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
548 			    displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
549 
550 			selectionStopped();
551 			populateDateList();
552 		}
553 
554 		/**
555 		 * Used during the date span selection procedure.
556 		 *
557 		 * @param e MouseEvent
558 		 *
559 		 * @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
560 		 */
561 		public void mouseEntered(MouseEvent e)
562 		{
563 			if (switching != 0) {
564 				switchTimer.cancel();
565 				switching = 0;
566 			}
567 
568 			if (selecting) {
569 				int date = ((DateCell)e.getSource()).getDate();
570 				int monthOffset = 0;
571 
572 				if ((date < 15) && !((DateCell)e.getSource()).isEnabled()) {
573 					monthOffset++;
574 				} else if ((date > 15)
575 				    && !((DateCell)e.getSource()).isEnabled()) {
576 					monthOffset--;
577 				}
578 
579 				ensureSelection();
580 				selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
581 				    displayMonthDate.get(Calendar.MONTH) + monthOffset, date,
582 				    12, 0, 0);
583 				populateDateList();
584 			}
585 		}
586 
587 		/**
588 		 * Used during the date span selection procedure for switching between
589 		 * selected months when the user drags the mouse outside the date
590 		 * panel.
591 		 *
592 		 * @param e MouseEvent
593 		 *
594 		 * @see java.awt.event.MouseListener#mouseExited(MouseEvent)
595 		 */
596 		public void mouseExited(MouseEvent e)
597 		{
598 			if (selecting) {
599 				Component eventSource = (Component)e.getSource();
600 				Point eventPoint = e.getPoint();
601 				int offset = eventSource.getWidth() + 1;
602 				eventPoint = SwingUtilities.convertPoint(eventSource,
603 					    eventPoint, this);
604 
605 				if (eventPoint.x >= ((getLocation().x + getWidth()) - offset)) {
606 					switching = 1;
607 				} else if (eventPoint.x <= (getLocation().x + offset)) {
608 					switching = -1;
609 				}
610 
611 				if (switching != 0) {
612 					switchTimer = new Timer();
613 					switchTimer.schedule(new TimerTask() {
614 							public void run()
615 							{
616 								if (selecting && (switching != 0)) {
617 									switchMonths();
618 								}
619 							}
620 
621 							private void switchMonths()
622 							{
623 								displayMonthDate.add(Calendar.MONTH, switching);
624 								ensureSelection();
625 								selectionFinishDate.add(Calendar.MONTH,
626 								    switching);
627 								populateDateList();
628 
629 								Calendar date = createCopy(displayMonthDate);
630 								date.set(Calendar.DAY_OF_MONTH, 1);
631 								normalizeToBeginningOfDay(date);
632 								monthCombo.setSelectedItem(date);
633 								monthCombo.repaint();
634 							}
635 						}, 300, 400);
636 				}
637 			}
638 		}
639 
640 		/**
641 		 * Invoked when the user presses the mouse button in one of the date
642 		 * cells. The date span selection procedure is started.
643 		 *
644 		 * @param e MouseEvent
645 		 *
646 		 * @see java.awt.event.MouseListener#mousePressed(MouseEvent)
647 		 */
648 		public void mousePressed(MouseEvent e)
649 		{
650 			if (e.getButton()== MouseEvent.BUTTON3){
651 				return;
652 			}
653 			if (!this.isEnabled()) return;
654 			selecting = true;
655 
656 			int date = ((DateCell)e.getSource()).getDate();
657 			int monthOffset = 0;
658 
659 			if ((date < 15) && !((DateCell)e.getSource()).isEnabled()) {
660 				monthOffset++;
661 			} else if ((date > 15) && !((DateCell)e.getSource()).isEnabled()) {
662 				monthOffset--;
663 			}
664 
665 			ensureSelection();
666 			selectionStartDate.set(displayMonthDate.get(Calendar.YEAR),
667 			    displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
668 			selectionFinishDate.set(displayMonthDate.get(Calendar.YEAR),
669 			    displayMonthDate.get(Calendar.MONTH) + monthOffset, date);
670 
671 			populateDateList();
672 		}
673 
674 		/**
675 		 * Invoked when the user releases the mouse  on one of the date cells.
676 		 * The date span  selection procedure is completed and a new selected
677 		 * date span is set.
678 		 *
679 		 * @param e MouseEvent
680 		 *
681 		 * @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
682 		 */
683 		public void mouseReleased(MouseEvent e)
684 		{
685 			if (e.getButton()== MouseEvent.BUTTON3){
686 				return;
687 			}
688 			if (!this.isEnabled()) return;
689 			selectionStopped();
690 		}
691 
692 		private void populateDateList()
693 		{
694 			currentDate = GregorianCalendar.getInstance();
695 			DateCell dateCell = null;
696 
697 			if (dateCells == null) {
698 				dateCells = new ArrayList<DateCell>();
699 
700 				for (int i = 0; i < 42; i++) {
701 					dateCell = new DateCell();
702 					if (i==0) dateCell.setAdjustFont(true); 
703 					dateCell.addMouseListener(this);
704 					dateCell.addKeyListener(this);
705 					dateCells.add(dateCell);
706 				}
707 			}
708 
709 			int dayInMonth = displayMonthDate.get(Calendar.DAY_OF_MONTH);
710 			displayMonthDate.add(Calendar.DATE, 1 - dayInMonth);
711 
712 			int firstDayOfMonth = displayMonthDate.get(Calendar.DAY_OF_WEEK)
713 				- 2;
714 			
715 			if (firstDayOfMonth < 0) {
716 				firstDayOfMonth += 7;
717 			}
718 
719 			int lastDayOfMonth = (firstDayOfMonth
720 				+ displayMonthDate.getActualMaximum(Calendar.DAY_OF_MONTH)) - 1;
721 			displayMonthDate.add(Calendar.DATE, -firstDayOfMonth);
722 			for (int i = 0; i < 42; i++) {
723 				dateCell = dateCells.get(i);
724 				dateCell.setEnabled(true);
725 				dateCell.setDate(displayMonthDate.get(Calendar.DAY_OF_MONTH));
726 
727 				if ((i < firstDayOfMonth) || (i > lastDayOfMonth)) {
728 					dateCell.setForeground(othersForeground);
729 					dateCell.setEnabled(false);
730 				} else {
731 					dateCell.setForeground(getForeground());
732 				}
733 
734 				if (displayMonthDate.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
735 					dateCell.setBackground(sundayBackground);
736 					dateCell.setForeground(sundayForeground);
737 				} else {
738 					dateCell.setBackground(getBackground());
739 				}
740 
741 				if ((displayMonthDate.get(Calendar.YEAR) == currentDate.get(
742 				        Calendar.YEAR))
743 				    && (displayMonthDate.get(Calendar.MONTH) == currentDate.get(
744 				        Calendar.MONTH))
745 				    && (displayMonthDate.get(Calendar.DATE) == currentDate.get(
746 				        Calendar.DATE))) {
747 					dateCell.setBorder(new LineBorder(Color.BLACK));
748 				} else {
749 					dateCell.setBorder(null);
750 				}
751 
752 				if (selectionFinishDate!=null && selectionStartDate!=null && (((displayMonthDate.getTimeInMillis() >= selectionStartDate
753 				    .getTimeInMillis())
754 				    && (displayMonthDate.getTimeInMillis() <= selectionFinishDate
755 				    .getTimeInMillis()))
756 				    || ((displayMonthDate.getTimeInMillis() <= selectionStartDate
757 				    .getTimeInMillis())
758 				    && (displayMonthDate.getTimeInMillis() >= selectionFinishDate
759 				    .getTimeInMillis())))) {
760 					if (displayMonthDate.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
761 						dateCell.setBackground(sundaySelection);
762 					} else {
763 						dateCell.setBackground(ColorHelper.getTextHighlight());
764 					}
765 				}
766 				
767 				if (displayMonthDate.equals(selectionFinishDate)) {
768 					if (!monthCombo.isPopupVisible()) {
769 						dateCell.requestFocusInWindow();
770 					}
771 				}
772 
773 				// painting the symbols for selection extending in next/previous month
774 				if (selectionFinishDate!=null && selectionStartDate!=null){
775 					
776 					
777 					if (i==41 
778 						&& selectionStartDate.getTimeInMillis()<=displayMonthDate.getTimeInMillis()
779 						&& selectionFinishDate.getTimeInMillis()>displayMonthDate.getTimeInMillis()){
780 							dateCell.setPaintForward(true);
781 					} else 
782 							dateCell.setPaintForward(false);
783 					if (i==0 
784 							&& selectionStartDate.getTimeInMillis()<displayMonthDate.getTimeInMillis()
785 							&& selectionFinishDate.getTimeInMillis()>=displayMonthDate.getTimeInMillis()){
786 							dateCell.setPaintBackward(true);
787 					} else 
788 							dateCell.setPaintBackward(false);
789 				} 
790 						
791 				
792 				displayMonthDate.add(Calendar.DATE, 1);
793 			}
794 
795 			displayMonthDate.add(Calendar.DATE,
796 			    (firstDayOfMonth + dayInMonth) - 1 - 42);
797 		}
798 
799 
800 
801 		private void selectionStopped()
802 		{
803 			selecting = false;
804 
805 			Calendar start = null;
806 			Calendar finish = null;
807 
808 			ensureSelection();
809 			if (selectionStartDate.getTimeInMillis() <= selectionFinishDate
810 			    .getTimeInMillis()) {
811 				start = createCopy(selectionStartDate);
812 				finish = createCopy(selectionFinishDate);
813 			} else {
814 				start = createCopy(selectionFinishDate);
815 				finish = createCopy(selectionStartDate);
816 			}
817 
818 			normalizeToBeginningOfDay(start);
819 			normalizeToEndOfDay(finish);
820 			setSelectedDateSpan(new DateSpan(start.getTime(), finish.getTime()));
821 		}
822 
823 		private void clearSelection() {
824 			selectionStartDate=null;
825 			selectionFinishDate=null;
826 		}
827 
828 		private void ensureSelection() {
829 			if (selectionStartDate==null) {
830 				selectionStartDate = GregorianCalendar.getInstance();
831 				normalizeToMiddleOfDay(selectionStartDate);
832 			}
833 			
834 			if (selectionFinishDate==null) {
835 				selectionFinishDate = GregorianCalendar.getInstance();
836 				normalizeToMiddleOfDay(selectionFinishDate);
837 			}
838 		}
839 
840 		@Override
841 		public void setEnabled(boolean enabled) {
842 			super.setEnabled(enabled);
843 			for (Iterator<DateCell> iterator = dateCells.iterator(); iterator.hasNext();) {
844 				DateCell cell = iterator.next();
845 				cell.setEnabled(enabled);
846 				
847 			}
848 		}
849 
850 		protected void unifyFontSize() {
851 			if (dayNameCells == null || dateCells == null) return;
852 			
853 			// unify the text size for day name cells
854 			Font fn= null;
855 			for (Iterator<DayNameCell> iterator = dayNameCells.iterator(); iterator.hasNext();) {
856 				DayNameCell cell = iterator.next();
857 				if (fn==null)fn=cell.getFont();
858 				cell.setFont(fn);
859 			}			
860 			// unify the text size for date cells
861 			Font fd = null;
862 			for (Iterator<DateCell> iterator = dateCells.iterator(); iterator.hasNext();) {
863 				DateCell cell = iterator.next();
864 				if (fd==null)fd=cell.getFont();
865 				cell.setFont(fd);
866 			}
867 			
868 		}
869 	}
870 
871 	/*
872 	 * A simple extension of com.cosylab.gui.components.SimpleComboBox
873 	 * for selecting months in years between 1950 and 2050
874 	 */
875 	private class MonthCombo extends SimpleComboBox
876 	{
877 		
878 		private static final long serialVersionUID = -848887269904982102L;
879 		/*
880 		 * Renderer for MONTH and YEAR fields od java.util.Calendar objects.
881 		 */
882 		private class MonthCellRenderer extends JLabel
883 			implements ListCellRenderer
884 		{
885 			private static final long serialVersionUID = -7240298232411247122L;
886 
887 			/**
888 			 * Constructor for MonthCellRenderer.
889 			 */
890 			public MonthCellRenderer()
891 			{
892 				super();
893 				setHorizontalAlignment(JLabel.CENTER);
894 				setOpaque(true);
895 				setEditor(new BasicComboBoxEditor());
896 			}
897 
898 			/**
899 			 * Returns the rendered cell.
900 			 *
901 			 * @param list JList
902 			 * @param value Object
903 			 * @param index int
904 			 * @param isSelected boolean
905 			 * @param cellHasFocus boolean
906 			 *
907 			 * @return Component
908 			 *
909 			 * @see javax.swing.ListCellRenderer#getListCellRendererComponent(JList,
910 			 *      Object, int, boolean, boolean)
911 			 */
912 			public Component getListCellRendererComponent(JList list,
913 			    Object value, int index, boolean isSelected,
914 			    boolean cellHasFocus)
915 			{
916 				if (isSelected) {
917 					setBackground(ColorHelper.getControl());
918 				} else {
919 					setBackground(ColorHelper.getControlHighlight());
920 				}
921 
922 				Calendar date = (Calendar)value;
923 				String name = MONTHS[date.get(Calendar.MONTH)] + " "
924 					+ date.get(Calendar.YEAR);
925 				setText(name);
926 				return this;
927 			}
928 		}
929 
930 		/**
931 		 * Constructor for MonthCombo.
932 		 */
933 		public MonthCombo()
934 		{
935 			super();
936 			setStyle(Style.SWITCH_STYLE_POPUP_ENABLED);
937 			setMaximumRowCount(12);
938 			setRenderer(new MonthCellRenderer());
939 			setBorder(null);
940 			populateMonthList();
941 			addMouseListener(new MouseListener(){
942 				public void mouseClicked(MouseEvent e) {
943 					if (e.getButton()==MouseEvent.BUTTON3){
944 						getPopup().show(e.getComponent(),
945 			                       e.getX(), e.getY());
946 					}										
947 				}
948 				public void mouseEntered(MouseEvent e) {
949 				}
950 				public void mouseExited(MouseEvent e) {
951 				}
952 				public void mousePressed(MouseEvent e) {					
953 				}
954 				public void mouseReleased(MouseEvent e) {
955 					
956 				}});
957 		}
958 
959 		private void populateMonthList()
960 		{
961 			for (int i = 1950; i <= 2050; i++) {
962 				for (int j = 1; j <= 12; j++) {
963 					((DefaultComboBoxModel)getModel()).addElement(new GregorianCalendar(
964 					        i, j, 1));
965 				}
966 			}
967 
968 			Calendar date = Calendar.getInstance();
969 			date.set(Calendar.DAY_OF_MONTH, 1);
970 			normalizeToBeginningOfDay(date);
971 			setSelectedItem(date);
972 		}
973 	}
974 
975 	/** Names of week days. */
976 	public static final String[] DAYS; 
977 	/** Names of months. */
978 	public static final String[] MONTHS; 
979 	
980 	static {
981 		String[] data = new DateFormatSymbols().getShortWeekdays();
982 		DAYS = new String[]{data[Calendar.MONDAY],data[Calendar.TUESDAY],
983 				data[Calendar.WEDNESDAY],data[Calendar.THURSDAY],data[Calendar.FRIDAY],
984 				data[Calendar.SATURDAY],data[Calendar.SUNDAY]};
985 		data = new DateFormatSymbols().getMonths();
986 		MONTHS = new String[]{
987 				data[Calendar.JANUARY],data[Calendar.FEBRUARY],data[Calendar.MARCH],
988 				data[Calendar.APRIL],data[Calendar.MAY],data[Calendar.JUNE],
989 				data[Calendar.JULY],data[Calendar.AUGUST],data[Calendar.SEPTEMBER],
990 				data[Calendar.OCTOBER],data[Calendar.NOVEMBER],data[Calendar.DECEMBER]};
991 	}
992 	
993 	private Date selectedDate;
994 	private DatePanel datePanel;
995 	private DateSpan selectedDateSpan;
996 	private MonthCombo monthCombo;
997 	private SimpleButton leftYear = null;
998 	private SimpleButton rightYear = null;
999 	private JPopupMenu popup = null;
1000 
1001 	/**
1002 	 * Constructs the DateSpanSelector.
1003 	 */
1004 	public DateSpanSelector()
1005 	{
1006 		monthCombo = new MonthCombo();
1007 
1008 		datePanel = new DatePanel();
1009 
1010 		monthCombo.addItemListener(datePanel);
1011 
1012 		setPreferredSize(new Dimension(154, 154));
1013 		setOpaque(true);
1014 		setBackground(ColorHelper.getControl());
1015 		setBorder(CosyUIElements.getPlainBorder(false));
1016 
1017 		setLayout(new GridBagLayout());
1018 
1019 		JPanel monthPanel = new JPanel(new BorderLayout());
1020 		
1021 		SimpleButton leftYear = getLeftYearButton();		
1022 		SimpleButton rightYear = getRightYearButton();
1023 		//add(leftYear, new GridBagConstraints(0,0,1,1,0,0,GridBagConstraints.CENTER,GridBagConstraints.NONE, new Insets(0,0,0,0),0,0));
1024 		//add(rightYear, new GridBagConstraints(2,0,1,1,0,0,GridBagConstraints.CENTER,GridBagConstraints.NONE, new Insets(0,0,0,0),0,0));
1025 		monthPanel.add(monthCombo,BorderLayout.CENTER);
1026 		monthPanel.add(leftYear,BorderLayout.WEST);
1027 		monthPanel.add(rightYear,BorderLayout.EAST);
1028 		
1029 		GridBagConstraints constraints = new GridBagConstraints();
1030 		constraints.fill = GridBagConstraints.BOTH;
1031 		constraints.gridx = 1;
1032 		constraints.gridy = 0;
1033 		constraints.weightx = 1;
1034 		constraints.weighty = 0;
1035 		constraints.anchor = GridBagConstraints.CENTER;
1036 		add(monthPanel, constraints);
1037 		constraints.gridx = 0;
1038 		constraints.gridy = 1;
1039 		constraints.weightx = 1;
1040 		constraints.weighty = 1;
1041 		constraints.gridwidth = 3;
1042 		constraints.anchor = GridBagConstraints.CENTER;
1043 		add(datePanel, constraints);
1044 			
1045 		
1046 		
1047 		
1048 	}
1049 
1050 	private SimpleButton getLeftYearButton() {
1051 		if (leftYear  == null){
1052 			leftYear = new YearButton(ArrowButton.LEFT);
1053 			leftYear.addActionListener(new ActionListener() {
1054 				public void actionPerformed(ActionEvent e){
1055 					if (monthCombo.getSelectedIndex() > 12) {
1056 						monthCombo.setSelectedIndex(monthCombo
1057 					    .getSelectedIndex() - 12);
1058 					}
1059 				}
1060 			});
1061 	
1062 			leftYear.setBackground(ColorHelper.getControl());
1063 			leftYear.setBorder(null);
1064 			leftYear.setPressedBorder(null);
1065 		}
1066 		return leftYear;
1067 	}
1068 
1069 	private SimpleButton getRightYearButton() {
1070 		if (rightYear == null){
1071 			rightYear = new YearButton(ArrowButton.RIGHT);
1072 			rightYear.addActionListener(new ActionListener() {
1073 				public void actionPerformed(ActionEvent e){
1074 					if (monthCombo.getSelectedIndex() < (monthCombo
1075 						    .getItemCount() - 13)) {
1076 						monthCombo.setSelectedIndex(monthCombo
1077 							    .getSelectedIndex() + 12);
1078 						}
1079 				}
1080 			});
1081 			rightYear.setBackground(ColorHelper.getControl());
1082 			rightYear.setBorder(null);
1083 			rightYear.setPressedBorder(null);
1084 		}
1085 		return rightYear;
1086 	}
1087 
1088 	/**
1089 	 * Returns true if the two dates are the same for the selector. Dates are the
1090 	 * same if they have the same year and the same day of year.
1091 	 *
1092 	 * @param date1
1093 	 * @param date2
1094 	 *
1095 	 * @return
1096 	 */
1097 	public static boolean isSameDate(Date date1, Date date2)
1098 	{
1099 		Calendar c1 = new GregorianCalendar();
1100 		Calendar c2 = new GregorianCalendar();
1101 		c1.setTime(date1);
1102 		c2.setTime(date2);
1103 		
1104 		return (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) 
1105 			&&  c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR));
1106 //		return date1.getYear() == date2.getYear()
1107 //		&& date1.getMonth() == date2.getMonth()
1108 //		&& date1.getDate() == date2.getDate();
1109 	}
1110 
1111 	public void setSelectedDateSpan(DateSpan newSpan) {
1112 		setSelectedDateSpan(newSpan,false);
1113 	}
1114 	
1115 	/**
1116 	 * Sets a new date interval to be selected. If null, the selection is
1117 	 * reset to current date. Also triggers single date selection: if the datespan points to
1118 	 * the single day, the single selection is synchronized. Otherwise, single
1119 	 * selection is removed.
1120 	 *
1121 	 * @param newSpan
1122 	 * @param shouldScroll flag indicates whether the calendar should scroll to the 
1123 	 * 			selected finishing date 
1124 	 */
1125 	public void setSelectedDateSpan(DateSpan newSpan, boolean shouldScroll)
1126 	{
1127 		DateSpan oldSpan = selectedDateSpan;
1128 		Date oldDate = selectedDate;
1129 
1130 		if (((newSpan != null) && newSpan.equals(oldSpan))
1131 		    || (newSpan == null && oldSpan == null)) {
1132 			return;
1133 		}
1134 
1135 		//if (newSpan==null) {
1136 		//	Date d = GregorianCalendar.getInstance().getTime();	
1137 		//	newSpan = new DateSpan(d,d);
1138 		//} 
1139 
1140 		selectedDateSpan = newSpan;
1141 
1142 		if (newSpan!=null && isSameDate(newSpan.getStartingDate(), newSpan.getFinishingDate())) {
1143 			selectedDate = newSpan.getFinishingDate();
1144 		} else {
1145 			selectedDate = null;
1146 		}
1147 
1148 		if (newSpan==null) {
1149 			datePanel.clearSelection();
1150 		} else {
1151 			datePanel.ensureSelection();
1152 			datePanel.selectionStartDate.setTime(newSpan.getStartingDate());
1153 			normalizeToMiddleOfDay(datePanel.selectionStartDate);
1154 			datePanel.selectionFinishDate.setTime(newSpan.getFinishingDate());
1155 			normalizeToMiddleOfDay(datePanel.selectionFinishDate);
1156 		}
1157 
1158 		if (shouldScroll) {
1159 			Calendar finish = GregorianCalendar.getInstance();
1160 			if (newSpan != null) {
1161 				finish.setTime(newSpan.getFinishingDate());
1162 			}
1163 			datePanel.displayMonthDate.set(Calendar.YEAR, finish.get(Calendar.YEAR));
1164 			datePanel.displayMonthDate.set(Calendar.MONTH, finish.get(Calendar.MONTH));
1165 			Calendar date = createCopy(datePanel.displayMonthDate);
1166 			date.set(Calendar.DAY_OF_MONTH, 1);
1167 			normalizeToBeginningOfDay(date);
1168 			monthCombo.setSelectedItem(date);
1169 			monthCombo.repaint();
1170 		}
1171 		
1172 		datePanel.populateDateList();
1173 		
1174 		firePropertyChange("selectedDateSpan", oldSpan, selectedDateSpan);
1175 		firePropertyChange("selectedDate", oldDate, selectedDate);
1176 	}
1177 
1178 	/**
1179 	 * Returns the selected date interval.
1180 	 *
1181 	 * @return DateSpan
1182 	 */
1183 	public DateSpan getSelectedDateSpan()
1184 	{
1185 		return selectedDateSpan;
1186 	}
1187 
1188 	/**
1189 	 * Copies date from te source to the destination.
1190 	 *
1191 	 * @param source source calendar
1192 	 * @param destination destination calendar
1193 	 */
1194 	public static void copyDate(Calendar source, Calendar destination)
1195 	{
1196 		destination.set(source.get(Calendar.YEAR), source.get(Calendar.MONTH),
1197 		    source.get(Calendar.DAY_OF_MONTH),
1198 		    source.get(Calendar.HOUR_OF_DAY), source.get(Calendar.MINUTE),
1199 		    source.get(Calendar.SECOND));
1200 	}
1201 
1202 	/**
1203 	 * Creates a copy of the calendar.
1204 	 *
1205 	 * @param source calendar to be copies
1206 	 *
1207 	 * @return a copy of the given calendar
1208 	 */
1209 	public static Calendar createCopy(Calendar source)
1210 	{
1211 		Calendar retVal = Calendar.getInstance();
1212 		copyDate(source, retVal);
1213 
1214 		return retVal;
1215 	}
1216 
1217 	/**
1218 	 * Normalizes date to the beginning of the day. Needed for
1219 	 * comparison of Calendars, when only  DAY, MONTH and YEAR values are
1220 	 * relevant.
1221 	 *
1222 	 * @param date Calendar
1223 	 */
1224 	public static void normalizeToBeginningOfDay(Calendar date)
1225 	{
1226 		date.set(Calendar.HOUR_OF_DAY, 0);
1227 		date.set(Calendar.MINUTE, 0);
1228 		date.set(Calendar.SECOND, 0);
1229 		date.set(Calendar.MILLISECOND, 0);
1230 	}
1231 
1232 	/**
1233 	 * Normalizes date to the last milisecond of the day. Needed for
1234 	 * comparison of Calendars, when only  DAY, MONTH and YEAR values are
1235 	 * relevant.
1236 	 *
1237 	 * @param date Calendar
1238 	 */
1239 	public static void normalizeToEndOfDay(Calendar date)
1240 	{
1241 		date.set(Calendar.HOUR_OF_DAY, 23);
1242 		date.set(Calendar.MINUTE, 59);
1243 		date.set(Calendar.SECOND, 59);
1244 		date.set(Calendar.MILLISECOND, 999);
1245 	}
1246 
1247 	/**
1248 	 * Normalizes date to the middle of the day. Needed for comparison
1249 	 * of Calendars, when only  DAY, MONTH and YEAR values are relevant.
1250 	 *
1251 	 * @param date Calendar
1252 	 */
1253 	public static void normalizeToMiddleOfDay(Calendar date)
1254 	{
1255 		date.set(Calendar.HOUR_OF_DAY, 12);
1256 		date.set(Calendar.MINUTE, 0);
1257 		date.set(Calendar.SECOND, 0);
1258 		date.set(Calendar.MILLISECOND, 0);
1259 	}
1260 
1261 	/**
1262 	 * Sets the single selected date. If null is set, the current selection is
1263 	 * reset to current date. Also triggers dateSpan selection to reflect the date
1264 	 * selection.
1265 	 *
1266 	 * @param date
1267 	 */
1268 	public void setSelectedDate(Date date)
1269 	{
1270 		Date oldDate = selectedDate;
1271 
1272 		if (((date != null) && date.equals(oldDate)
1273 		    || date == null && selectedDate == null)) {
1274 			return;
1275 		}
1276 
1277 		if (date == null) {
1278 			setSelectedDateSpan(null);
1279 		} else {
1280 			setSelectedDateSpan(new DateSpan(date, date));
1281 		}
1282 	}
1283 
1284 	/**
1285 	 * Returns the selected date if single date is selected otherwise null.
1286 	 *
1287 	 * @return single date selection
1288 	 */
1289 	public Date getSelectedDate()
1290 	{
1291 		return selectedDate;
1292 	}
1293 
1294 	/**
1295 	 * Returns whether a single date is selected.
1296 	 *
1297 	 * @return true if a single date is selected, false otherwise.
1298 	 */
1299 	public boolean isSingleDateSelected()
1300 	{
1301 		return (selectedDate != null);
1302 	}
1303 	
1304 	/*
1305 	 * (non-Javadoc)
1306 	 * @see javax.swing.JComponent#setEnabled(boolean)
1307 	 */
1308 	@Override
1309 	public void setEnabled(boolean enabled) {
1310 		super.setEnabled(enabled);
1311 		monthCombo.setEnabled(enabled);
1312 		datePanel.setEnabled(enabled);
1313 		getLeftYearButton().setEnabled(enabled);
1314 		getRightYearButton().setEnabled(enabled);
1315 	}
1316 
1317 	private JPopupMenu getPopup() {
1318 		if (popup == null){
1319 			// create popup
1320 			popup = new JPopupMenu("");
1321 			
1322 			JMenuItem todayItem = new JMenuItem("Go to today");
1323 			todayItem.addActionListener(new ActionListener(){
1324 				public void actionPerformed(ActionEvent e) {
1325 					//setSelectedDateSpan(new DateSpan(new Date(), new Date()), true);
1326 					if (getSelectedDateSpan() == null) return;
1327 					Calendar start = GregorianCalendar.getInstance();
1328 					datePanel.displayMonthDate.set(Calendar.YEAR, start.get(Calendar.YEAR));
1329 					datePanel.displayMonthDate.set(Calendar.MONTH, start.get(Calendar.MONTH));
1330 					Calendar date = createCopy(datePanel.displayMonthDate);
1331 					date.set(Calendar.DAY_OF_MONTH, 1);
1332 					normalizeToBeginningOfDay(date);
1333 					monthCombo.setSelectedItem(date);
1334 					monthCombo.repaint();
1335 					datePanel.populateDateList();
1336 				}			
1337 			});
1338 			popup.add(todayItem);
1339 			
1340 			JMenuItem selStartItem = new JMenuItem("Go to selection start");
1341 			selStartItem.addActionListener(new ActionListener(){
1342 				public void actionPerformed(ActionEvent e) {
1343 					if (getSelectedDateSpan() == null) return;
1344 					Calendar start = GregorianCalendar.getInstance();
1345 					start.setTime(getSelectedDateSpan().getStartingDate());
1346 					datePanel.displayMonthDate.set(Calendar.YEAR, start.get(Calendar.YEAR));
1347 					datePanel.displayMonthDate.set(Calendar.MONTH, start.get(Calendar.MONTH));
1348 					Calendar date = createCopy(datePanel.displayMonthDate);
1349 					date.set(Calendar.DAY_OF_MONTH, 1);
1350 					normalizeToBeginningOfDay(date);
1351 					monthCombo.setSelectedItem(date);
1352 					monthCombo.repaint();
1353 					datePanel.populateDateList();						
1354 				}			
1355 			});
1356 			popup.add(selStartItem);
1357 			
1358 			JMenuItem selEndItem = new JMenuItem("Go to selection end");
1359 			selEndItem.addActionListener(new ActionListener(){
1360 				public void actionPerformed(ActionEvent e) {
1361 					if (getSelectedDateSpan() == null) return;
1362 					Calendar end = GregorianCalendar.getInstance();
1363 					end.setTime(getSelectedDateSpan().getFinishingDate());
1364 					datePanel.displayMonthDate.set(Calendar.YEAR, end.get(Calendar.YEAR));
1365 					datePanel.displayMonthDate.set(Calendar.MONTH, end.get(Calendar.MONTH));
1366 					Calendar date = createCopy(datePanel.displayMonthDate);
1367 					date.set(Calendar.DAY_OF_MONTH, 1);
1368 					normalizeToBeginningOfDay(date);
1369 					monthCombo.setSelectedItem(date);
1370 					monthCombo.repaint();
1371 					datePanel.populateDateList();
1372 				}			
1373 			});
1374 			popup.add(selEndItem);
1375 			
1376 		}
1377 		return popup;
1378 	}
1379 	
1380 	/**
1381 	 * For testing and demonstration purposes only.
1382 	 *
1383 	 * @param args String[]
1384 	 */
1385 	public static void main(String[] args)
1386 	{
1387 		JPanel pan = new JPanel();
1388 		pan.setLayout(new CardLayout(10, 10));
1389 		DateSpanSelector selector = new DateSpanSelector();
1390 		//DateSpan span = new DateSpan(new Date(System.currentTimeMillis() + 86400000L*60), 1000000000L);
1391 		//DateSpan span = new DateSpan(new Date(System.currentTimeMillis()), 500000000L);
1392 		//selector.setSelectedDateSpan(span, true);
1393 		pan.add(selector, "Date");
1394 		selector.addPropertyChangeListener("selectedDateSpan", new PropertyChangeListener(){
1395 			public void propertyChange(PropertyChangeEvent evt) {
1396 				System.out.println(evt.getNewValue());
1397 			}
1398 		});
1399 		JFrame frame = new JFrame("CalendarSelector Testing Applet");
1400 		frame.getContentPane().add(pan);
1401 		frame.setSize(300, 300);
1402 		frame.addWindowListener(new WindowAdapter() {
1403 				public void windowClosing(WindowEvent e)
1404 				{
1405 					System.exit(0);
1406 				}
1407 			});
1408 		frame.setVisible(true);
1409 		
1410 		try {
1411 //			Thread.sleep(2000);
1412 //			selector.setEnabled(false);
1413 //			Thread.sleep(2000);
1414 //			selector.setEnabled(true);
1415 //			Thread.sleep(2000);
1416 //			selector.setEnabled(false);
1417 			Thread.sleep(2000);
1418 			selector.setEnabled(true);
1419 			
1420 		} catch (InterruptedException e1) {
1421 			// TODO Auto-generated catch block
1422 			e1.printStackTrace();
1423 		}
1424 		
1425 		
1426 	}
1427 }
1428 
1429 /* __oOo__ */