Skip to main content

JXDatePicker some thought.

9 replies [Last post]
Anonymous

Thank's Joshua for a nice component.

I took a liberty to tune it up a little bit.
This is how it looks now: http://ivan.yourmail.com/JXDatePicker.gif
I am not a designer (it is about `today` icon) but I am sure that someone can donate an appropriate icon.

Also I add 2 more buttons - prev. year and next year.
Two classes been changed :
http://ivan.yourmail.com/JXDatePicker.java.html
http://ivan.yourmail.com/DateUtils.java.html

Most of the changes are minor, please check them out and if you think that they are good please commit into CVS.

This is jar with all resources and source code. You will need it (there are images)
http://ivan.yourmail.com/swingx-source.jar

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
dmouse
Offline
Joined: 2003-06-09
Points: 0

I probably wasn't realizing what you were referring to when I read your first e-mail about the null date value.

Since the editor is a formatted text field and I don't believe you can create a DatePicker with an empty date maybe it should revert to the last good value, which I believe it may do currently...

Anonymous

Null date works!
Formatted field uses JXDatePickerFormatterFactory that can handle null value.

When you are going to review changes that I submitted?
I have a few more.

dmouse
Offline
Joined: 2003-06-09
Points: 0

I'd like to use your changes, but it looks like you haven't signed the JCA agreement yet. Until that happens I'm keeping my eyes shut when I see your code :)

Anonymous

What the [beep] beAuAteful agreement :)
And how I can sight it :)

I am waiting for approval for my project where I agreed with term and conditions is it enough ?

dmouse
Offline
Joined: 2003-06-09
Points: 0

You're right Ivan this is ridiculous and I would like to get things moving as well. I would say e-mail the patches to the alias in the submitting patches FAQ. Just ensure that you do not have any copyright information in the diffs otherwise it would still be considered your code.

Message was edited by: dmouse

Anonymous

Method toggleShowPopup():
There are glitch, _popup.isVisible() - always return false.
Yet I can't find where is a problem, because after _popup.show(...) - isVisible() returns true, but when I click on the popup button while calendar opened, isVisible() returns false;
This why popup doesn't close when you click on the button next time.

Second issue:
_dateField.getValue() may return null. We should have something like this:
if (null==_dateField.getValue()) {
_dateField.setValue(Calendar.getInstance(Locale.getDefault()).getTime());
}
I know, it is ugly, we can use static CALENDAR from DateUtils if you make it public. Or even add a method getCurrentDate() or so.

Now about empty dates.
It works perfectly, except one place:
JXDatePickerFormatterFactory#stringToValue():
// We can treat an empty date string as null
if (text == null || text.trim().length()==0) {
return null;
}
IMHO for Date an empty string and NULL value are same.

dmouse
Offline
Joined: 2003-06-09
Points: 0

The problem you are seeing in toggleShowPopup is due to the way Swing coded JComboBox. BasicComboBoxUI and BasicPopupUI have special code to keep the popups from being hidden on the click. This similar code is needed in date picker so that we can handle the event ourselves. Otherwise, as you have seen the popup gets canceled and then when toggleShowPopup gets called it sees that the popup isn't visible.

The problem is the way Swing implemented this feature in combo boxes. It is a combination of a client property and a StringBuffer value which is private. Therefore we can not currently mimic this feature without re-writing a new plaf class for the date picker which was not my intention.

For the second issue I would agree that empty strings in the date field should be considered null. I wouldn't think that we would want to assume though that just because the value is null that we should set it t the current time.

Also, regarding your changes. I would love to review them, but I need diffs, not a jar file of the whole source. I believe there is a FAQ on the JDNC page on how to contribute changes. If you could please follow that it would be extremely helpful.

Josh

Anonymous

About toggle popup, I was guessing that it is Swing problems. It's ok, leave it as is.

[quote]
I wouldn't think that we would want to assume though that just because the value is null that we should set it t the current time.
[/quote]
But if date is null what date to show in the calendar when user opens it ?

I know that it make no sence to show you changed classes, this two links has _changes_ along:
http://ivan.yourmail.com/JXDatePicker.java.html - changed 2 methods
http://ivan.yourmail.com/DateUtils.java.html - 3 methods added.
You don't need to compare it, simply copy and paste this methods from the page to the code.

I will do cvs diff ...

Anonymous

[code]
Index: JXDatePicker.java
===================================================================
RCS file: /cvs/jdnc/swingx/src/java/org/jdesktop/swing/JXDatePicker.java,v
retrieving revision 1.3
diff -u -r1.3 JXDatePicker.java
--- JXDatePicker.java 13 Aug 2004 23:24:00 -0000 1.3
+++ JXDatePicker.java 25 Aug 2004 15:03:26 -0000
@@ -11,6 +11,8 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.Calendar;
+import java.util.Locale;
import javax.swing.*;
import javax.swing.JFormattedTextField.AbstractFormatterFactory;
import javax.swing.border.*;
@@ -120,8 +122,7 @@

Icon icon = UIManager.getIcon("JXDatePicker.arrowDown.image");
if (icon == null) {
- icon = new ImageIcon(getClass().getResource(
- "/toolbarButtonGraphics/navigation/Down24.gif"));
+ icon = new ImageIcon(getClass().getResource("resources/calendar.gif"));
}
_popupButton.setIcon(icon);

@@ -415,14 +416,16 @@
}

public void toggleShowPopup() {
- System.out.println("!");
+ // System.out.println("!");
if (_popup == null) {
_popup = new JXDatePickerPopup();
}
if (!_popup.isVisible()) {
- DateSpan span =
- new DateSpan((java.util.Date)_dateField.getValue(),
- (java.util.Date)_dateField.getValue());
+ if (null==_dateField.getValue()) {
+ // todo fix this ugly patch
+ _dateField.setValue(Calendar.getInstance(Locale.getDefault()).getTime());
+ }
+ DateSpan span = new DateSpan((java.util.Date)_dateField.getValue(), (java.util.Date)_dateField.getValue());
_monthView.setSelectedDateSpan(span);
_monthView.ensureDateVisible(
((Date)_dateField.getValue()).getTime());
@@ -443,8 +446,10 @@
*/
private class JXDatePickerPopup extends JPopupMenu
implements ActionListener {
- private JButton _nextButton;
- private JButton _previousButton;
+ private JButton _nextMonthButton;
+ private JButton _previousMonthButton;
+ private JButton _nextYearButton;
+ private JButton _previousYearButton;
private JButton _todayButton;

public JXDatePickerPopup() {
@@ -452,41 +457,75 @@
_monthView.setActionCommand("MONTH_VIEW");
_monthView.addActionListener(this);

- JPanel panel = new JPanel(new FlowLayout());
+ JPanel navPanel = new JPanel();
+ navPanel.setLayout(new BoxLayout(navPanel, BoxLayout.X_AXIS));
+
Icon icon = UIManager.getIcon("JXMonthView.monthUp.image");
if (icon == null) {
- icon = new ImageIcon(getClass().getResource(
- "/toolbarButtonGraphics/navigation/Up24.gif"));
+ icon = new ImageIcon(getClass().getResource("resources/Back16.gif"));
}
- _previousButton = new JButton(icon);
- _previousButton.setActionCommand("PREVIOUS_MONTH");
- _previousButton.addActionListener(this);
+ _previousMonthButton = new JButton(icon);
+ _previousMonthButton.setToolTipText("Previous month.");
+ _previousMonthButton.setActionCommand("PREVIOUS_MONTH");
+ _previousMonthButton.addActionListener(this);
+ _previousMonthButton.setPreferredSize(new Dimension(icon.getIconWidth()+2, icon.getIconHeight()+2));
+
+ icon = UIManager.getIcon("JXMonthView.yearUp.image");
+ if (icon == null) {
+ icon = new ImageIcon(getClass().getResource("resources/DoubleBack16.gif"));
+ }
+ _previousYearButton = new JButton(icon);
+ _previousYearButton.setToolTipText("Previous year.");
+ _previousYearButton.setActionCommand("PREVIOUS_YEAR");
+ _previousYearButton.addActionListener(this);
+ _previousYearButton.setPreferredSize(new Dimension(icon.getIconWidth()+2, icon.getIconHeight()+2));

icon = UIManager.getIcon("JXMonthView.monthDown.image");
if (icon == null) {
- icon = new ImageIcon(getClass().getResource(
- "/toolbarButtonGraphics/navigation/Down24.gif"));
+ icon = new ImageIcon(getClass().getResource("resources/Forward16.gif"));
}
- _nextButton = new JButton(icon);
- _nextButton.setActionCommand("NEXT_MONTH");
- _nextButton.addActionListener(this);
+ _nextMonthButton = new JButton(icon);
+ _nextMonthButton.setToolTipText("Next month.");
+ _nextMonthButton.setActionCommand("NEXT_MONTH");
+ _nextMonthButton.addActionListener(this);
+ _nextMonthButton.setPreferredSize(new Dimension(icon.getIconWidth()+2, icon.getIconHeight()+2));
+
+ icon = UIManager.getIcon("JXMonthView.yearDown.image");
+ if (icon == null) {
+ icon = new ImageIcon(getClass().getResource("resources/DoubleForward16.gif"));
+ }
+ _nextYearButton = new JButton(icon);
+ _nextYearButton.setToolTipText("Next year.");
+ _nextYearButton.setActionCommand("NEXT_YEAR");
+ _nextYearButton.addActionListener(this);
+ _nextYearButton.setPreferredSize(new Dimension(icon.getIconWidth()+2, icon.getIconHeight()+2));

icon = UIManager.getIcon("JXMonthView.monthCurrent.image");
if (icon == null) {
- icon = new ImageIcon(getClass().getResource(
- "/toolbarButtonGraphics/media/Stop24.gif"));
+ icon = new ImageIcon(getClass().getResource("resources/calendar_today.gif"));
}
+
_todayButton = new JButton(icon);
+ _todayButton.setPreferredSize(new Dimension(icon.getIconWidth()+2, icon.getIconHeight()+2));
+ _todayButton.setToolTipText("Today");
_todayButton.setActionCommand("TODAY");
_todayButton.addActionListener(this);

- setLayout(new BorderLayout());
- add(_monthView, BorderLayout.CENTER);
+ // Use Swing layout manager instead of AWT
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

- panel.add(_previousButton);
- panel.add(_todayButton);
- panel.add(_nextButton);
- add(panel, BorderLayout.NORTH);
+ navPanel.add(_previousMonthButton);
+ navPanel.add(_previousYearButton);
+ navPanel.add(Box.createHorizontalGlue());
+ navPanel.add(_todayButton);
+ navPanel.add(Box.createHorizontalGlue());
+ navPanel.add(_nextYearButton);
+ navPanel.add(_nextMonthButton);
+
+ // put this together
+ add(navPanel);
+ add(_monthView);
+ pack();
}

public void actionPerformed(ActionEvent ev) {
@@ -496,11 +535,17 @@
_dateField.setValue(span.getStartAsDate());
_popup.setVisible(false);
fireActionPerformed();
+ } else if ("PREVIOUS_YEAR" == command) {
+ _monthView.setFirstDisplayedDate(DateUtils.getPreviousYear(
+ _monthView.getFirstDisplayedDate()));
} else if ("PREVIOUS_MONTH" == command) {
_monthView.setFirstDisplayedDate(DateUtils.getPreviousMonth(
_monthView.getFirstDisplayedDate()));
} else if ("NEXT_MONTH" == command) {
_monthView.setFirstDisplayedDate(DateUtils.getNextMonth(
+ _monthView.getFirstDisplayedDate()));
+ } else if ("NEXT_YEAR" == command) {
+ _monthView.setFirstDisplayedDate(DateUtils.getNextYear(
_monthView.getFirstDisplayedDate()));
} else if ("TODAY" == command) {
DateSpan span = new DateSpan(System.currentTimeMillis(),
Index: DateUtils.java
===================================================================
RCS file: /cvs/jdnc/swingx/src/java/org/jdesktop/swing/calendar/DateUtils.java,v
retrieving revision 1.1
diff -u -r1.1 DateUtils.java
--- DateUtils.java 12 Aug 2004 00:24:33 -0000 1.1
+++ DateUtils.java 25 Aug 2004 15:04:39 -0000
@@ -299,6 +299,16 @@
}

/**
+ * Returns the previous year.
+ *
+ * @param date Base date
+ * @return previous year
+ */
+ public static long getPreviousYear(long date) {
+ return incrementYear(date, -1);
+ }
+
+ /**
* Returns the next month.
*
* @param date Base date
@@ -308,11 +318,36 @@
return incrementMonth(date, 1);
}

+ /**
+ * Returns the next year.
+ *
+ * @param date Base date
+ * @return next year
+ */
+ public static long getNextYear(long date) {
+ return incrementYear(date, 1);
+ }
+
private static long incrementMonth(long date, int increment) {
Calendar calendar = CALENDAR;
synchronized(calendar) {
calendar.setTimeInMillis(date);
calendar.add(Calendar.MONTH, increment);
+ return calendar.getTimeInMillis();
+ }
+ }
+
+ /**
+ * Increment given date for the given number of years.
+ *
+ * @param date date to increment
+ * @param increment increment
+ */
+ private static long incrementYear(long date, int increment) {
+ Calendar calendar = CALENDAR;
+ synchronized(calendar) {
+ calendar.setTimeInMillis(date);
+ calendar.add(Calendar.YEAR, increment);
return calendar.getTimeInMillis();
}
}
Index: JXDatePickerFormatterFactory.java
===================================================================
RCS file: /cvs/jdnc/swingx/src/java/org/jdesktop/swing/calendar/JXDatePickerFormatterFactory.java,v
retrieving revision 1.1
diff -u -r1.1 JXDatePickerFormatterFactory.java
--- JXDatePickerFormatterFactory.java 12 Aug 2004 00:24:33 -0000 1.1
+++ JXDatePickerFormatterFactory.java 25 Aug 2004 15:05:20 -0000
@@ -86,7 +86,8 @@
Object result = null;
ParseException pex = null;

- if (text == null) {
+ // We can treat an empty date string as null
+ if (text == null || text.trim().length()==0) {
return null;
}

[/code]