0001: /*
0002: * The contents of this file are subject to the
0003: * Mozilla Public License Version 1.1 (the "License");
0004: * you may not use this file except in compliance with the License.
0005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0006: *
0007: * Software distributed under the License is distributed on an "AS IS"
0008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
0009: * See the License for the specific language governing rights and
0010: * limitations under the License.
0011: *
0012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
0013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
0014: *
0015: * All Rights Reserved.
0016: *
0017: * Contributor(s):
0018: */
0019: package org.openharmonise.swing.datefield;
0020:
0021: import java.awt.*;
0022: import java.awt.event.*;
0023: import java.util.*;
0024: import java.util.List;
0025:
0026: import javax.swing.*;
0027: import javax.swing.text.*;
0028:
0029: /**
0030: * <p>JDateField is a lightweight component that allows constrained free text date
0031: * entry. The format string is based on the {@link java.text.SimpleDateFormat} one with some
0032: * caveats:</p>
0033: * <ol>
0034: * <li> Only numerical representations of dates are allowed, except for the Era
0035: * field with can only be represented as "AD" or "BC".</li>
0036: *
0037: * <li>The format length for each field needs to be the same length as the expected
0038: * input. So for a 4 digit year you must use "yyyy", where as the {@link java.text.SimpleDateFormat}
0039: * class will accept "yyy" and "yyyyy". The only excpetion to this rule is the Era field
0040: * which must be represented as "G".</li>
0041: * </ol>
0042: *
0043: * @author Matthew Large
0044: * @version $Revision: 1.1 $
0045: *
0046: */
0047: public class JDateField extends JTextField implements KeyListener,
0048: FocusListener, MouseWheelListener, MouseListener {
0049:
0050: /**
0051: * Date format string.
0052: */
0053: private String m_sFormat = null;
0054:
0055: /**
0056: * Date format parser.
0057: */
0058: private DateFormatParser m_dateFormatParser = null;
0059:
0060: /**
0061: * List of {@link DateBlock} objects.
0062: */
0063: private List m_aDateBlocks = new ArrayList();
0064:
0065: /**
0066: * Index of the currently active date block.
0067: */
0068: private int m_nActiveBlockIndex = -1;
0069:
0070: /**
0071: * List of allowed characters.
0072: */
0073: private static final ArrayList m_aAllowedChars = new ArrayList();
0074:
0075: /**
0076: * List of allowed numbers.
0077: */
0078: private static final ArrayList m_aAllowedNums = new ArrayList();
0079:
0080: /**
0081: * Calendar adaptor containing the current date value.
0082: */
0083: private CalendarAdaptor m_calendar = new CalendarAdaptor();
0084:
0085: /**
0086: * Reusable temporary calendar adaptor, used for testing values against constraints before allowing them to be set.
0087: */
0088: private CalendarAdaptor m_tempCalendar = new CalendarAdaptor();
0089:
0090: /**
0091: * Calendar adaptor representing the minimum allowed date, or null if one isn't set.
0092: */
0093: private CalendarAdaptor m_minCalendar = null;
0094:
0095: /**
0096: * Calendar adaptor representing the maximum allowed date, or null if one isn't set.
0097: */
0098: private CalendarAdaptor m_maxCalendar = null;
0099:
0100: /**
0101: * List of {@link DateFieldListener} objects.
0102: */
0103: private ArrayList m_dateFieldListeners = new ArrayList();
0104:
0105: static {
0106: m_aAllowedNums.add("0");
0107: m_aAllowedNums.add("1");
0108: m_aAllowedNums.add("2");
0109: m_aAllowedNums.add("3");
0110: m_aAllowedNums.add("4");
0111: m_aAllowedNums.add("5");
0112: m_aAllowedNums.add("6");
0113: m_aAllowedNums.add("7");
0114: m_aAllowedNums.add("8");
0115: m_aAllowedNums.add("9");
0116:
0117: m_aAllowedChars.add("a");
0118: m_aAllowedChars.add("b");
0119: m_aAllowedChars.add("c");
0120: m_aAllowedChars.add("d");
0121: m_aAllowedChars.add("A");
0122: m_aAllowedChars.add("B");
0123: m_aAllowedChars.add("C");
0124: m_aAllowedChars.add("D");
0125: }
0126:
0127: /**
0128: * Constructs a new date field.
0129: *
0130: * @param sFormat Format string
0131: */
0132: public JDateField(String sFormat) {
0133: super ();
0134: this .m_sFormat = sFormat;
0135: this .setup();
0136: }
0137:
0138: /**
0139: * Configures this date field.
0140: *
0141: */
0142: private void setup() {
0143: this .setFocusTraversalKeysEnabled(false);
0144: this .addKeyListener(this );
0145: this .addFocusListener(this );
0146: this .addMouseListener(this );
0147: this .addMouseWheelListener(this );
0148:
0149: this .m_dateFormatParser = new DateFormatParser(this .m_sFormat);
0150:
0151: int nPos = 0;
0152: this .m_aDateBlocks.clear();
0153:
0154: Iterator itor = this .m_dateFormatParser.getFormatBlocks()
0155: .iterator();
0156: while (itor.hasNext()) {
0157: DateFormatBlock formatBlock = (DateFormatBlock) itor.next();
0158:
0159: DateBlock dateBlock = new DateBlock(formatBlock, nPos, "");
0160: this .m_aDateBlocks.add(dateBlock);
0161:
0162: nPos = nPos + formatBlock.getInputLength();
0163: }
0164:
0165: this .clear();
0166:
0167: this .highlightNextActiveBlock(-1);
0168: }
0169:
0170: /**
0171: * Clears the date field, resetting the display to the input
0172: * format string.
0173: *
0174: */
0175: public void clear() {
0176: Iterator itor = this .m_aDateBlocks.iterator();
0177: while (itor.hasNext()) {
0178: DateBlock dateBlock = (DateBlock) itor.next();
0179: dateBlock.clear();
0180: if (dateBlock.getFormatBlock().isActiveBlock()
0181: && !dateBlock.getValue()
0182: .equalsIgnoreCase(
0183: dateBlock.getFormatBlock()
0184: .getEntryFormat())) {
0185: this .m_calendar.setStringValue(dateBlock
0186: .getFormatBlock().getCalendarField(), dateBlock
0187: .getValue());
0188: }
0189: }
0190: this .redisplayDate(0);
0191: }
0192:
0193: /**
0194: * Returns the active date block.
0195: *
0196: * @return Active date block
0197: */
0198: private DateBlock getActiveBlock() {
0199: DateBlock activeBlock = null;
0200:
0201: if (this .m_nActiveBlockIndex > -1) {
0202: activeBlock = (DateBlock) this .m_aDateBlocks
0203: .get(m_nActiveBlockIndex);
0204: }
0205:
0206: return activeBlock;
0207: }
0208:
0209: /**
0210: * Returns the date format string used when constructing this date
0211: * field.
0212: *
0213: * @return Format string
0214: */
0215: public String getDateFormat() {
0216: return this .m_sFormat;
0217: }
0218:
0219: /**
0220: * Handles all key events for this component.
0221: *
0222: * @param ke Key event
0223: * @param nType Type of event 0=pressed, 1=released and 2=typed
0224: */
0225: private void keyEventHandler(KeyEvent ke, int nType) {
0226:
0227: if (nType == 0
0228: && ke.getKeyCode() == KeyEvent.VK_TAB
0229: && ((ke.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) == KeyEvent.SHIFT_DOWN_MASK)) {
0230: DateBlock dateBlock = this .getActiveBlock();
0231: this .handleFieldExit(dateBlock);
0232: boolean bBlockFound = this
0233: .highlightPreviousActiveBlock(this .m_nActiveBlockIndex);
0234: if (!bBlockFound) {
0235: this .transferFocusBackward();
0236: }
0237:
0238: ke.consume();
0239:
0240: } else if (nType == 0 && ke.getKeyCode() == KeyEvent.VK_ESCAPE) {
0241: this .replaceWithPreviousValues(1);
0242: this .highlightActiveBlock();
0243:
0244: ke.consume();
0245: } else if (nType == 0 && (ke.getKeyCode() == KeyEvent.VK_ENTER)) {
0246: DateBlock dateBlock = this .getActiveBlock();
0247: this .handleFieldExit(dateBlock);
0248: this .transferFocus();
0249: ke.consume();
0250: } else if (nType == 0 && ke.getKeyCode() == KeyEvent.VK_TAB) {
0251:
0252: DateBlock dateBlock = this .getActiveBlock();
0253: this .handleFieldExit(dateBlock);
0254:
0255: boolean bBlockFound = this
0256: .highlightNextActiveBlock(this .m_nActiveBlockIndex);
0257: if (!bBlockFound) {
0258: this .transferFocus();
0259: }
0260:
0261: ke.consume();
0262: } else if (nType == 0 && ke.getKeyCode() == KeyEvent.VK_RIGHT) {
0263:
0264: DateBlock dateBlock = this .getActiveBlock();
0265: this .handleFieldExit(dateBlock);
0266:
0267: boolean bBlockFound = this
0268: .highlightNextActiveBlock(this .m_nActiveBlockIndex);
0269: if (!bBlockFound) {
0270: this .highlightActiveBlock();
0271: }
0272: ke.consume();
0273: } else if (nType == 0 && ke.getKeyCode() == KeyEvent.VK_LEFT) {
0274:
0275: DateBlock dateBlock = this .getActiveBlock();
0276: this .handleFieldExit(dateBlock);
0277: boolean bBlockFound = this
0278: .highlightPreviousActiveBlock(this .m_nActiveBlockIndex);
0279: if (!bBlockFound) {
0280: this .highlightActiveBlock();
0281: }
0282: ke.consume();
0283: } else if (nType == 0 && ke.getKeyCode() == KeyEvent.VK_UP) {
0284: this .handleUpEvent();
0285: ke.consume();
0286: } else if (nType == 0 && ke.getKeyCode() == KeyEvent.VK_DOWN) {
0287: this .handleDownEvent();
0288: ke.consume();
0289: } else if (nType == 2 && ke.getKeyCode() == KeyEvent.VK_DELETE
0290: || ke.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
0291: ke.consume();
0292: if (this .getSelectedText() != null
0293: && this .getSelectedText().length() == this
0294: .getText().length()) {
0295: this .setText("");
0296: this .clear();
0297: this .fireValueChanged();
0298: }
0299: } else {
0300: DateBlock dateBlock = this .getActiveBlock();
0301:
0302: String sKeyText = KeyEvent.getKeyText(ke.getKeyCode());
0303: sKeyText = sKeyText.replaceAll("NumPad-", "");
0304:
0305: if (nType == 1
0306: && ((dateBlock.getFormatBlock().getCalendarField() == Calendar.ERA && JDateField.m_aAllowedChars
0307: .contains(sKeyText)) || (dateBlock
0308: .getFormatBlock().getCalendarField() != Calendar.ERA && JDateField.m_aAllowedNums
0309: .contains(sKeyText)))) {
0310:
0311: if (dateBlock != null) {
0312: String sValue = null;
0313:
0314: DateFormatBlock formatBlock = dateBlock
0315: .getFormatBlock();
0316:
0317: String sCurrentValue = dateBlock.getValue();
0318: StringBuffer sBuff = new StringBuffer();
0319:
0320: sCurrentValue = this .rTrim(sCurrentValue);
0321:
0322: if (sCurrentValue.equalsIgnoreCase(formatBlock
0323: .getFormat())
0324: || sCurrentValue.trim().startsWith("cc")
0325: || sCurrentValue.length() >= formatBlock
0326: .getInputLength()) {
0327: sCurrentValue = "";
0328: }
0329:
0330: sBuff = new StringBuffer(sCurrentValue);
0331:
0332: sBuff.append(sKeyText);
0333: if (sBuff.length() < formatBlock.getInputLength()) {
0334: for (int i = sBuff.length(); i < formatBlock
0335: .getInputLength(); i++) {
0336: sBuff.append(" ");
0337: }
0338: }
0339: sValue = sBuff.toString();
0340:
0341: dateBlock.setValue(sValue);
0342: this .redisplayDate(dateBlock.getStartPos()
0343: + sCurrentValue.length() + 1);
0344: if (sCurrentValue.length() + 1 >= formatBlock
0345: .getInputLength()) {
0346:
0347: if (dateBlock.getFormatBlock()
0348: .getCalendarField() == Calendar.ERA
0349: && !sValue.equalsIgnoreCase("ad")
0350: && !sValue.equalsIgnoreCase("bc")) {
0351: dateBlock.setValue(this .m_calendar
0352: .getStringValue(Calendar.ERA));
0353: }
0354:
0355: this .m_calendar.setStringValue(dateBlock
0356: .getFormatBlock().getCalendarField(),
0357: dateBlock.getValue());
0358:
0359: if (!this .m_calendar.getStringValue(
0360: dateBlock.getFormatBlock()
0361: .getCalendarField())
0362: .equalsIgnoreCase(dateBlock.getValue())) {
0363: dateBlock.setValue(this .m_calendar
0364: .getStringValue(dateBlock
0365: .getFormatBlock()
0366: .getCalendarField()));
0367: }
0368: this .updateValuesFromCalendar(dateBlock
0369: .getStartPos()
0370: + sCurrentValue.length() + 1);
0371: this
0372: .highlightNextActiveBlock(this .m_nActiveBlockIndex);
0373:
0374: if (!this .isAboveMin(dateBlock)
0375: || !this .isUnderMax(dateBlock)) {
0376: if (this .isAboveMin(dateBlock)) {
0377: this
0378: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_BELOW_MIN);
0379: }
0380: if (this .isUnderMax(dateBlock)) {
0381: this
0382: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_ABOVE_MAX);
0383: }
0384: } else {
0385: this .fireValueChanged();
0386: }
0387: }
0388:
0389: }
0390: }
0391:
0392: ke.consume();
0393: }
0394:
0395: }
0396:
0397: public String rTrim(String sValue) {
0398: StringBuffer sBuff = new StringBuffer();
0399: boolean bFoundRight = false;
0400:
0401: for (int i = sValue.length() - 1; i > -1; i--) {
0402: if (sValue.charAt(i) != ' ') {
0403: bFoundRight = true;
0404: }
0405: if (bFoundRight) {
0406: sBuff.append(sValue.charAt(i));
0407: }
0408: }
0409:
0410: StringBuffer sNewBuff = new StringBuffer();
0411: for (int i = sBuff.length() - 1; i > -1; i--) {
0412: sNewBuff.append(sBuff.charAt(i));
0413: }
0414: return sNewBuff.toString();
0415: }
0416:
0417: /**
0418: * Fires a validation failed message to all the {@link DateFieldListener}
0419: * objects.
0420: *
0421: * @param nReason Reason for failure
0422: */
0423: private void fireValidationMessage(int nReason) {
0424: Iterator itor = this .m_dateFieldListeners.iterator();
0425: while (itor.hasNext()) {
0426: DateFieldListener listener = (DateFieldListener) itor
0427: .next();
0428: listener.validationFailed(this , nReason);
0429: }
0430: }
0431:
0432: /**
0433: * Checks if the current date is above the minimum allowed.
0434: *
0435: * @param dateBlock Changed date block
0436: * @return true if the current date is above the minimum
0437: */
0438: private boolean isAboveMin(DateBlock dateBlock) {
0439: boolean bReturn = true;
0440:
0441: if (this .m_minCalendar != null) {
0442: try {
0443: this .m_tempCalendar.setStringValue(dateBlock
0444: .getFormatBlock().getCalendarField(), dateBlock
0445: .getValue());
0446: bReturn = (this .m_tempCalendar.getTime().getTime() >= this .m_minCalendar
0447: .getTime().getTime());
0448: } catch (NumberFormatException nfe) {
0449: //NO-OP
0450: }
0451: }
0452:
0453: return bReturn;
0454: }
0455:
0456: /**
0457: * Checks if the current date is below the maximum allowed.
0458: *
0459: * @param dateBlock Changed date block
0460: * @return true if the current date is below the maximum
0461: */
0462: private boolean isUnderMax(DateBlock dateBlock) {
0463: boolean bReturn = true;
0464:
0465: if (this .m_maxCalendar != null) {
0466: try {
0467: this .m_tempCalendar.setStringValue(dateBlock
0468: .getFormatBlock().getCalendarField(), dateBlock
0469: .getValue());
0470: bReturn = (this .m_tempCalendar.getTime().getTime() <= this .m_maxCalendar
0471: .getTime().getTime());
0472: } catch (NumberFormatException nfe) {
0473: //NO-OP
0474: }
0475: }
0476:
0477: return bReturn;
0478: }
0479:
0480: /**
0481: * Handles the situation where a date field is exited early by the user
0482: * by using the tab or arrow keys.
0483: *
0484: * @param dateBlock Date block exited
0485: */
0486: private void handleFieldExit(DateBlock dateBlock) {
0487: String sDatePreviousValue = dateBlock.getPreviousValue();
0488:
0489: if (this .rTrim(dateBlock.getValue()).length() < dateBlock
0490: .getFormatBlock().getInputLength()) {
0491: if (dateBlock.getFormatBlock().getCalendarField() == Calendar.YEAR) {
0492: StringBuffer sBuff = new StringBuffer();
0493: if (dateBlock.getValue().trim().length() < 8) {
0494: sBuff.append(" ");
0495: }
0496: if (dateBlock.getValue().trim().length() < 7) {
0497: sBuff.append(" ");
0498: }
0499: if (dateBlock.getValue().trim().length() < 6) {
0500: sBuff.append(" ");
0501: }
0502: if (dateBlock.getValue().trim().length() < 5) {
0503: sBuff.append(" ");
0504: }
0505: if (dateBlock.getValue().trim().length() < 4) {
0506: sBuff.append("0");
0507: }
0508: if (dateBlock.getValue().trim().length() < 3) {
0509: sBuff.append("0");
0510: }
0511: if (dateBlock.getValue().trim().length() < 2) {
0512: sBuff.append("0");
0513: }
0514: sBuff.append(dateBlock.getValue().trim());
0515: dateBlock.setPreviousValue(sBuff.toString());
0516: dateBlock.setValue(sBuff.toString());
0517: this .m_calendar.setStringValue(dateBlock
0518: .getFormatBlock().getCalendarField(), dateBlock
0519: .getValue());
0520: System.out.println("Comparing cal="
0521: + this .m_calendar.getStringValue(
0522: dateBlock.getFormatBlock()
0523: .getCalendarField())
0524: .replaceAll("0", "") + " with val="
0525: + dateBlock.getValue().replaceAll("0", ""));
0526: if (!this .m_calendar.getStringValue(
0527: dateBlock.getFormatBlock().getCalendarField())
0528: .replaceAll("0", "").equalsIgnoreCase(
0529: dateBlock.getValue()
0530: .replaceAll("0", ""))) {
0531: dateBlock.setValue(this .m_calendar
0532: .getStringValue(dateBlock.getFormatBlock()
0533: .getCalendarField()));
0534: dateBlock.setPreviousValue(dateBlock.getValue());
0535: }
0536: } else if (dateBlock.getFormatBlock().getCalendarField() == Calendar.ERA) {
0537: dateBlock.setValue(dateBlock.getPreviousValue());
0538: this .m_calendar.setStringValue(dateBlock
0539: .getFormatBlock().getCalendarField(), dateBlock
0540: .getValue());
0541: } else {
0542: StringBuffer sBuff = new StringBuffer();
0543: for (int i = 0; i < dateBlock.getFormatBlock()
0544: .getInputLength()
0545: - dateBlock.getValue().trim().length(); i++) {
0546: sBuff.append("0");
0547: }
0548: sBuff.append(dateBlock.getValue().trim());
0549: dateBlock.setPreviousValue(sBuff.toString());
0550: dateBlock.setValue(sBuff.toString());
0551: this .m_calendar.setStringValue(dateBlock
0552: .getFormatBlock().getCalendarField(), dateBlock
0553: .getValue());
0554:
0555: if (!this .m_calendar.getStringValue(
0556: dateBlock.getFormatBlock().getCalendarField())
0557: .equalsIgnoreCase(dateBlock.getValue())) {
0558: dateBlock.setValue(this .m_calendar
0559: .getStringValue(dateBlock.getFormatBlock()
0560: .getCalendarField()));
0561: dateBlock.setPreviousValue(dateBlock.getValue());
0562: }
0563: }
0564: }
0565:
0566: if (!this .isAboveMin(dateBlock) || !this .isUnderMax(dateBlock)) {
0567: if (this .isAboveMin(dateBlock)) {
0568: this
0569: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_BELOW_MIN);
0570: }
0571: if (this .isUnderMax(dateBlock)) {
0572: this
0573: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_ABOVE_MAX);
0574: }
0575: } else if (!dateBlock.getValue().equalsIgnoreCase(
0576: sDatePreviousValue)) {
0577: this .fireValueChanged();
0578: }
0579: this .redisplayDate(1);
0580: }
0581:
0582: /**
0583: * Fires a value changed event to all the {@link DateFieldListener} objects.
0584: *
0585: */
0586: private void fireValueChanged() {
0587:
0588: if (this .hasValue()) {
0589: Iterator itor = this .m_dateFieldListeners.iterator();
0590: while (itor.hasNext()) {
0591: DateFieldListener listener = (DateFieldListener) itor
0592: .next();
0593: listener.valueChanged(this );
0594: }
0595: }
0596: }
0597:
0598: /**
0599: * Checks if the date field as a complete value.
0600: *
0601: * @return true if the date field has a complete value
0602: */
0603: public boolean hasValue() {
0604: boolean bHasValue = true;
0605: Iterator itor = this .m_aDateBlocks.iterator();
0606: while (itor.hasNext()) {
0607: DateBlock dateBlock = (DateBlock) itor.next();
0608: if (!dateBlock.hasValue()) {
0609: bHasValue = false;
0610: break;
0611: }
0612: }
0613: return bHasValue;
0614: }
0615:
0616: /**
0617: * Highlights the currently active block.
0618: *
0619: */
0620: private void highlightActiveBlock() {
0621: int nIndex = 0;
0622:
0623: if (this .m_nActiveBlockIndex > -1
0624: && this .m_nActiveBlockIndex < this .m_aDateBlocks.size()) {
0625: nIndex = this .m_nActiveBlockIndex;
0626: }
0627: DateFormatBlock block = ((DateBlock) this .m_aDateBlocks
0628: .get(nIndex)).getFormatBlock();
0629: this .setCaretPosition(block.getStartPosition());
0630: this .moveCaretPosition(block.getStartPosition()
0631: + block.getInputLength());
0632: }
0633:
0634: /**
0635: * Replaces the date blocks with their
0636: * previous value. Used when a user is part way through entering a value
0637: * and then presses the escape key.
0638: *
0639: * @param nCarretPosition Current carret position
0640: */
0641: private void replaceWithPreviousValues(int nCarretPosition) {
0642: Iterator itor = this .m_aDateBlocks.iterator();
0643: while (itor.hasNext()) {
0644: DateBlock dateBlock = (DateBlock) itor.next();
0645: dateBlock.setValue(dateBlock.getPreviousValue());
0646: }
0647: this .redisplayDate(nCarretPosition);
0648: }
0649:
0650: /**
0651: * Updates date blocks with values from the current date value. Used
0652: * to make sure other fields roll over correctly with the current field,
0653: * e.g. the year rolls over then the month goes up from 12 to 1.
0654: *
0655: * @param nCarretPosition
0656: */
0657: private void updateValuesFromCalendar(int nCarretPosition) {
0658: Iterator itor = this .m_aDateBlocks.iterator();
0659: while (itor.hasNext()) {
0660: DateBlock dateBlock = (DateBlock) itor.next();
0661: if (dateBlock.getFormatBlock().isActiveBlock()
0662: && !dateBlock.getValue()
0663: .equalsIgnoreCase(
0664: dateBlock.getFormatBlock()
0665: .getEntryFormat())) {
0666: String sCalValue = this .m_calendar
0667: .getStringValue(dateBlock.getFormatBlock()
0668: .getCalendarField());
0669: dateBlock.setPreviousValue(dateBlock.getValue());
0670: dateBlock.setValue(sCalValue);
0671: }
0672: }
0673: this .m_tempCalendar.setTime(this .m_calendar.getTime());
0674: this .redisplayDate(nCarretPosition);
0675: }
0676:
0677: /**
0678: * Sets the date value.
0679: *
0680: * @param dt Date value
0681: */
0682: public void setDate(Date dt) {
0683: if (dt != null) {
0684: this .m_calendar.setTime(dt);
0685: Iterator itor = this .m_aDateBlocks.iterator();
0686: while (itor.hasNext()) {
0687: DateBlock dateBlock = (DateBlock) itor.next();
0688: if (dateBlock.getFormatBlock().isActiveBlock()) {
0689: dateBlock.setValue(this .m_calendar
0690: .getStringValue(dateBlock.getFormatBlock()
0691: .getCalendarField()));
0692: dateBlock.setPreviousValue(this .m_calendar
0693: .getStringValue(dateBlock.getFormatBlock()
0694: .getCalendarField()));
0695: }
0696: }
0697: this .redisplayDate(1);
0698: }
0699: }
0700:
0701: /**
0702: * Returns the date value.
0703: *
0704: * @return Date value or null if there isn'n one
0705: */
0706: public Date getDate() {
0707: if (this .hasValue()) {
0708: return this .m_calendar.getTime();
0709: } else {
0710: return null;
0711: }
0712: }
0713:
0714: /**
0715: * Sets the maximum allowed date.
0716: *
0717: * @param dtMax Maximum date
0718: */
0719: public void setMaximumDate(Date dtMax) {
0720: if (dtMax != null) {
0721: this .m_maxCalendar = new CalendarAdaptor();
0722: this .m_maxCalendar.setTime(dtMax);
0723: }
0724: }
0725:
0726: /**
0727: * Sets the minium allowed date.
0728: *
0729: * @param dtMin Minimum date
0730: */
0731: public void setMinimumDate(Date dtMin) {
0732: if (dtMin != null) {
0733: this .m_minCalendar = new CalendarAdaptor();
0734: this .m_minCalendar.setTime(dtMin);
0735: }
0736: }
0737:
0738: /**
0739: * Redisplays the values from all the date blocks.
0740: *
0741: * @param nCarretPosition Current carret position
0742: */
0743: private void redisplayDate(int nCarretPosition) {
0744:
0745: StringBuffer sBuff = new StringBuffer();
0746:
0747: Iterator itor = this .m_aDateBlocks.iterator();
0748: while (itor.hasNext()) {
0749: DateBlock dateBlock = (DateBlock) itor.next();
0750: sBuff.append(dateBlock.getValue());
0751: }
0752:
0753: this .setText(sBuff.toString());
0754: this .setCaretPosition(nCarretPosition);
0755: }
0756:
0757: /**
0758: * Highlights the next active block from the given index.
0759: *
0760: * @param nActiveBlock Index to start from
0761: * @return true if a block was found
0762: */
0763: private boolean highlightNextActiveBlock(int nActiveBlock) {
0764: boolean bBlockFound = false;
0765:
0766: Iterator itor = this .m_dateFormatParser.getFormatBlocks()
0767: .iterator();
0768:
0769: DateFormatBlock block = null;
0770:
0771: while (itor.hasNext() && !bBlockFound) {
0772: block = (DateFormatBlock) itor.next();
0773: bBlockFound = (block.isActiveBlock() && this .m_dateFormatParser
0774: .getFormatBlocks().indexOf(block) > nActiveBlock);
0775: }
0776:
0777: if (bBlockFound && block != null) {
0778: this .m_nActiveBlockIndex = this .m_dateFormatParser
0779: .getFormatBlocks().indexOf(block);
0780: this .setCaretPosition(block.getStartPosition());
0781: this .moveCaretPosition(block.getStartPosition()
0782: + block.getInputLength());
0783: }
0784:
0785: return bBlockFound;
0786: }
0787:
0788: /**
0789: * Highlights the previous active block from the given index.
0790: *
0791: * @param nActiveBlock Index to start from
0792: * @return true if a block was found
0793: */
0794: private boolean highlightPreviousActiveBlock(int nActiveBlock) {
0795: boolean bBlockFound = false;
0796:
0797: Iterator itor = this .m_dateFormatParser.getFormatBlocks()
0798: .iterator();
0799:
0800: DateFormatBlock block = null;
0801: DateFormatBlock previousBlock = null;
0802:
0803: while (itor.hasNext() && !bBlockFound) {
0804: block = (DateFormatBlock) itor.next();
0805: bBlockFound = (block.isActiveBlock() && this .m_dateFormatParser
0806: .getFormatBlocks().indexOf(block) == nActiveBlock);
0807: if (!bBlockFound && block.isActiveBlock()) {
0808: previousBlock = block;
0809: }
0810: }
0811:
0812: if (bBlockFound && previousBlock != null) {
0813: this .m_nActiveBlockIndex = this .m_dateFormatParser
0814: .getFormatBlocks().indexOf(previousBlock);
0815: this .setCaretPosition(previousBlock.getStartPosition());
0816: this .moveCaretPosition(previousBlock.getStartPosition()
0817: + previousBlock.getInputLength());
0818: }
0819:
0820: return bBlockFound && previousBlock != null;
0821: }
0822:
0823: /* (non-Javadoc)
0824: * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
0825: */
0826: public void keyPressed(KeyEvent ke) {
0827: this .keyEventHandler(ke, 0);
0828: }
0829:
0830: /* (non-Javadoc)
0831: * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
0832: */
0833: public void keyReleased(KeyEvent ke) {
0834: this .keyEventHandler(ke, 1);
0835: }
0836:
0837: /* (non-Javadoc)
0838: * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
0839: */
0840: public void keyTyped(KeyEvent ke) {
0841: this .keyEventHandler(ke, 2);
0842: }
0843:
0844: /**
0845: *
0846: */
0847: private JDateField() {
0848: super ();
0849: this .setup();
0850: }
0851:
0852: /**
0853: * @param arg0
0854: */
0855: private JDateField(int arg0) {
0856: super (arg0);
0857: this .setup();
0858: }
0859:
0860: /**
0861: * @param arg0
0862: * @param arg1
0863: */
0864: private JDateField(String arg0, int arg1) {
0865: super (arg0, arg1);
0866: this .setup();
0867: }
0868:
0869: /**
0870: * @param arg0
0871: * @param arg1
0872: * @param arg2
0873: */
0874: private JDateField(Document arg0, String arg1, int arg2) {
0875: super (arg0, arg1, arg2);
0876: this .setup();
0877: }
0878:
0879: /* (non-Javadoc)
0880: * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
0881: */
0882: public void focusGained(FocusEvent fe) {
0883: this .highlightNextActiveBlock(-1);
0884: }
0885:
0886: /* (non-Javadoc)
0887: * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
0888: */
0889: public void focusLost(FocusEvent arg0) {
0890:
0891: }
0892:
0893: /* (non-Javadoc)
0894: * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
0895: */
0896: public void mouseClicked(MouseEvent me) {
0897: if (me.getClickCount() > 1) {
0898: this .setCaretPosition(0);
0899: this .moveCaretPosition(this .getText().length());
0900: } else {
0901: int nCarretPos = this .getCaretPosition();
0902:
0903: Iterator itor = this .m_dateFormatParser.getFormatBlocks()
0904: .iterator();
0905: DateFormatBlock block = null;
0906:
0907: while (itor.hasNext()) {
0908: block = (DateFormatBlock) itor.next();
0909:
0910: if (block.isActiveBlock()
0911: && block.getStartPosition() <= nCarretPos
0912: && (block.getStartPosition() + block
0913: .getInputLength()) >= nCarretPos) {
0914: break;
0915: }
0916: }
0917: this .highlightNextActiveBlock(this .m_dateFormatParser
0918: .getFormatBlocks().indexOf(block) - 1);
0919: }
0920: }
0921:
0922: /* (non-Javadoc)
0923: * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
0924: */
0925: public void mouseEntered(MouseEvent arg0) {
0926:
0927: }
0928:
0929: /* (non-Javadoc)
0930: * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
0931: */
0932: public void mouseExited(MouseEvent arg0) {
0933:
0934: }
0935:
0936: /* (non-Javadoc)
0937: * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
0938: */
0939: public void mousePressed(MouseEvent arg0) {
0940:
0941: }
0942:
0943: /* (non-Javadoc)
0944: * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
0945: */
0946: public void mouseReleased(MouseEvent arg0) {
0947:
0948: }
0949:
0950: /**
0951: * Adds a date field listener.
0952: *
0953: * @param listener Listener to add
0954: */
0955: public void addDateFieldListener(DateFieldListener listener) {
0956: this .m_dateFieldListeners.add(listener);
0957: }
0958:
0959: /**
0960: * Removes a date field listener.
0961: *
0962: * @param listener Listener to remove
0963: */
0964: public void removeDateFieldListener(DateFieldListener listener) {
0965: this .m_dateFieldListeners.remove(listener);
0966: }
0967:
0968: /* (non-Javadoc)
0969: * @see java.awt.Component#getPreferredSize()
0970: */
0971: public Dimension getPreferredSize() {
0972: Dimension dim = super .getPreferredSize();
0973: dim.height = dim.height + 5;
0974: dim.width = dim.width + 20;
0975: return dim;
0976: }
0977:
0978: /* (non-Javadoc)
0979: * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
0980: */
0981: public void mouseWheelMoved(MouseWheelEvent mwe) {
0982: if (mwe.getUnitsToScroll() < 0) {
0983: this .handleUpEvent();
0984: } else {
0985: this .handleDownEvent();
0986: }
0987: }
0988:
0989: /**
0990: * Handles a down arrow key event.
0991: *
0992: */
0993: private void handleDownEvent() {
0994: DateBlock dateBlock = this .getActiveBlock();
0995:
0996: this .m_calendar.add(dateBlock.getFormatBlock()
0997: .getCalendarField(), -1);
0998: dateBlock.setValue(this .m_calendar.getStringValue(dateBlock
0999: .getFormatBlock().getCalendarField()));
1000: this .updateValuesFromCalendar(0);
1001: this .highlightActiveBlock();
1002: if (!this .isAboveMin(dateBlock) || !this .isUnderMax(dateBlock)) {
1003: if (this .isAboveMin(dateBlock)) {
1004: this
1005: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_BELOW_MIN);
1006: }
1007: if (this .isUnderMax(dateBlock)) {
1008: this
1009: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_ABOVE_MAX);
1010: }
1011: } else {
1012: this .fireValueChanged();
1013: }
1014: }
1015:
1016: /**
1017: * Handles an up arrow key event.
1018: *
1019: */
1020: private void handleUpEvent() {
1021: DateBlock dateBlock = this .getActiveBlock();
1022:
1023: this .m_calendar.add(dateBlock.getFormatBlock()
1024: .getCalendarField(), 1);
1025: dateBlock.setValue(this .m_calendar.getStringValue(dateBlock
1026: .getFormatBlock().getCalendarField()));
1027:
1028: this .updateValuesFromCalendar(0);
1029: this.highlightActiveBlock();
1030: if (!this.isAboveMin(dateBlock) || !this.isUnderMax(dateBlock)) {
1031: if (this.isAboveMin(dateBlock)) {
1032: this
1033: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_BELOW_MIN);
1034: }
1035: if (this.isUnderMax(dateBlock)) {
1036: this
1037: .fireValidationMessage(DateFieldListener.VALIDATION_FAIL_ABOVE_MAX);
1038: }
1039: } else {
1040: this.fireValueChanged();
1041: }
1042: }
1043:
1044: }
|