home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CDateView.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  28.2 KB  |  967 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. /*====================================================================================*/
  21.     #pragma mark INCLUDE FILES
  22. /*====================================================================================*/
  23.  
  24. #include "CDateView.h"
  25.  
  26.  
  27. /*====================================================================================*/
  28.     #pragma mark TYPEDEFS
  29. /*====================================================================================*/
  30.  
  31.  
  32. /*====================================================================================*/
  33.     #pragma mark CONSTANTS
  34. /*====================================================================================*/
  35.  
  36. // Pane IDs
  37. static const PaneIDT eDayEditFieldID = 1;
  38. static const PaneIDT eMonthEditFieldID = 2;
  39. static const PaneIDT eYearEditFieldID = 3;
  40.  
  41. // Resource IDs
  42. static const short cArrowWidth = 11;
  43. static const short cArrowHeight = 9;
  44.  
  45. static const UInt32 cBroadcastMessageDelay = 12;
  46.  
  47.  
  48. /*====================================================================================*/
  49.     #pragma mark INTERNAL CLASS DECLARATIONS
  50. /*====================================================================================*/
  51.  
  52. class CDateArrowButton : public LButton {
  53.  
  54. public:
  55.  
  56.     enum { class_ID = 'DaBt' };
  57.                         CDateArrowButton(LStream *inStream);
  58.  
  59.     // When clicking in button, send these messages
  60.     enum { msg_ClickUpArrow = CDateView::paneID_UpButton, 
  61.            msg_ClickDownArrow = CDateView::paneID_DownButton };
  62.  
  63.     virtual void        SimulateHotSpotClick(Int16 inHotSpot);
  64.  
  65. protected:
  66.  
  67.     // Overriden methods
  68.  
  69.     virtual void        DisableSelf(void);
  70.     virtual void        EnableSelf(void);
  71.  
  72.     virtual Boolean        TrackHotSpot(Int16 inHotSpot, Point inPoint, Int16 inModifiers);
  73.     virtual void        HotSpotAction(Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside);
  74.     virtual void        HotSpotResult(short inHotSpot);
  75.  
  76.     // Instance variables ==========================================================
  77.     
  78.     UInt32                mNextBroadcastTime;        // Last time a message was broadcast
  79.     UInt16                mBroadcastCount;        // Number of continuous braodcast messages
  80. };
  81.  
  82.  
  83. /*====================================================================================*/
  84.     #pragma mark INTERNAL FUNCTION PROTOTYPES
  85. /*====================================================================================*/
  86.  
  87. #ifdef Debug_Signal
  88.     #define AssertFail_(test)        ThrowIfNot_(test)
  89. #else // Debug_Signal
  90.     #define AssertFail_(test)        ((void) 0)
  91. #endif // Debug_Signal
  92.  
  93. static inline Boolean IsBetween(long inVal, long inMin, long inMax) { 
  94.     return ((inVal >= inMin) && (inVal <= inMax)); 
  95. }
  96.  
  97.  
  98. /*====================================================================================*/
  99.     #pragma mark CLASS IMPLEMENTATIONS
  100. /*====================================================================================*/
  101.  
  102. #pragma mark -
  103.  
  104. /*======================================================================================
  105.     Register classes related to this class.
  106. ======================================================================================*/
  107.  
  108. void CDateView::RegisterDateClasses(void) {
  109.  
  110.     RegisterClass_(CDateView);
  111.     RegisterClass_(CDateField);
  112.     RegisterClass_(CDateArrowButton);
  113. }
  114.  
  115.  
  116. /*======================================================================================
  117.     Constructor.
  118. ======================================================================================*/
  119.  
  120. CDateView::CDateView(LStream *inStream) : 
  121.                      LView(inStream) {
  122.  
  123.     mDayField = mMonthField = mYearField = nil;
  124. }
  125.  
  126.  
  127. /*======================================================================================
  128.     Constructor.
  129. ======================================================================================*/
  130.  
  131. void CDateView::FinishCreateSelf(void) {
  132.  
  133.     // Load in date/time resources
  134.     
  135.     Intl0Hndl int0H = (Intl0Hndl) ::GetIntlResource(0);
  136.     UInt8 leadingDayChar, leadingMonthChar, separatingChar;
  137.     
  138.     if ( int0H ) {
  139.         switch ( (**int0H).dateOrder ) {
  140.             case mdy:    mDayPosition = 2; mMonthPosition = 1; mYearPosition = 3; break;
  141.             case dmy:    mDayPosition = 1; mMonthPosition = 2; mYearPosition = 3; break;
  142.             case ymd:    mDayPosition = 3; mMonthPosition = 2; mYearPosition = 1; break;
  143.             case myd:    mDayPosition = 3; mMonthPosition = 1; mYearPosition = 2; break;
  144.             case dym:    mDayPosition = 1; mMonthPosition = 3; mYearPosition = 2; break;
  145.             default: /* ydm */    mDayPosition = 2; mMonthPosition = 3; mYearPosition = 1; break;
  146.         }
  147.         leadingDayChar = ((**int0H).shrtDateFmt & dayLdingZ) ? '0' : ' ';
  148.         leadingMonthChar = ((**int0H).shrtDateFmt & mntLdingZ) ? '0' : ' ';
  149.         separatingChar = (**int0H).dateSep;
  150.     } else {
  151.         // Set to defaults
  152.         separatingChar = '/';
  153.         leadingDayChar = '0';
  154.         leadingMonthChar = '0';
  155.         mDayPosition = 2;
  156.         mMonthPosition = 1;
  157.         mYearPosition = 3;
  158.     }
  159.  
  160.     SetRefreshAllWhenResized(false);
  161.     
  162.     // Must create the subpanes here for correct function of tabbed edit fields
  163.     
  164.     CreateDateFields(leadingDayChar, leadingMonthChar, separatingChar);
  165. }
  166.  
  167.  
  168. /*======================================================================================
  169.     Destructor.
  170. ======================================================================================*/
  171.  
  172. CDateView::~CDateView(void) {
  173.  
  174. }
  175.  
  176.  
  177. /*======================================================================================
  178.     Determine if the specified date is valid.
  179.     
  180.     inYear         (cMinViewYear..cMaxViewYear)
  181.     inMonth     (1..12)
  182.     inDay         (1..31)
  183. ======================================================================================*/
  184.  
  185. Boolean CDateView::IsValidDate(Int16 inYear, UInt8 inMonth, UInt8 inDay) {
  186.  
  187.     if ( (inDay < 1) || (inDay > 31) || (inMonth < 1) || (inMonth > 12) ||
  188.          (inYear < cMinViewYear) || (inYear > cMaxViewYear) ) {
  189.          
  190.         return false;
  191.     }
  192.     
  193.     DateTimeRec dtRec = { inYear, inMonth, inDay, 1, 1, 1 };
  194.  
  195.     UInt32 seconds;
  196.     ::DateToSeconds(&dtRec, &seconds);
  197.     ::SecondsToDate(seconds, &dtRec);
  198.     
  199.     return ((inDay == dtRec.day) && (inMonth == dtRec.month) && (inYear == dtRec.year));
  200. }
  201.  
  202.  
  203. /*======================================================================================
  204.     Get the currently displayed date.
  205.     
  206.     outYear     (cMinViewYear..cMaxViewYear)
  207.     outMonth     (1..12)
  208.     outDay         (1..31)
  209. ======================================================================================*/
  210.  
  211. void CDateView::GetDate(Int16 *outYear, UInt8 *outMonth, UInt8 *outDay) {
  212.  
  213.     *outYear = mYearField->GetValue() + 2000;
  214.     *outMonth = mMonthField->GetValue();
  215.     *outDay = mDayField->GetValue();
  216.     if ( *outYear > cMaxViewYear ) *outYear -= 100;
  217. }
  218.  
  219.  
  220. /*======================================================================================
  221.     Set the displayed date to the date specified by the input parameters. If the
  222.     input parameters specify a date that is not valid, return false and don't do
  223.     anything; otherwise return true.
  224.     
  225.     inYear         (cMinViewYear..cMaxViewYear)
  226.     inMonth     (1..12)
  227.     inDay         (1..31)
  228. ======================================================================================*/
  229.  
  230. Boolean CDateView::SetDate(Int16 inYear, UInt8 inMonth, UInt8 inDay) {
  231.  
  232.     Boolean rtnVal = IsValidDate(inYear, inMonth, inDay);
  233.  
  234.     if ( rtnVal ) {
  235.         inYear -= ((inYear > 1999) ? 2000 : 1900);
  236.         SetDateString(mYearField, inYear, '0');
  237.         SetDateString(mMonthField, inMonth, mMonthField->GetLeadingChar());
  238.         SetDateString(mDayField, inDay, mDayField->GetLeadingChar());
  239.     }
  240.     
  241.     return rtnVal;
  242. }
  243.  
  244.  
  245. /*======================================================================================
  246.     Set the date displayed to today's date.
  247. ======================================================================================*/
  248.  
  249. void CDateView::SetToToday(void) {
  250.  
  251.     UInt32 seconds;
  252.     ::GetDateTime(&seconds);
  253.     DateTimeRec dtRec;
  254.     ::SecondsToDate(seconds, &dtRec);
  255.     
  256.     if ( dtRec.year < cMinViewYear ) {
  257.         dtRec.year = cMinViewYear;
  258.     } else if ( dtRec.year > cMaxViewYear ) {
  259.         dtRec.year = cMaxViewYear;
  260.     }
  261.  
  262.     SetDate(dtRec.year, dtRec.month, dtRec.day);
  263. }
  264.  
  265.  
  266. /*======================================================================================
  267.     Select the specified date field in this view.
  268. ======================================================================================*/
  269.  
  270. void CDateView::SelectDateField(Int16 inField) {
  271.  
  272.     PaneIDT paneID;
  273.     
  274.     switch ( inField ) {
  275.         case eYearField:     paneID = eYearEditFieldID; break;
  276.         case eMonthField:     paneID = eMonthEditFieldID; break;
  277.         case eDayField:        paneID = eDayEditFieldID; break;
  278.         default: Assert_(false); return;
  279.     }
  280.     
  281.     CDateField *newTarget = (CDateField *) FindPaneByID(paneID);
  282.     Assert_(newTarget != nil);
  283.     
  284.     if ( LCommander::SwitchTarget(newTarget) ) {
  285.         newTarget->SelectAll();
  286.     }
  287. }
  288.  
  289.  
  290. /*======================================================================================
  291.     Select the first date field in this view if one is not yet selected.
  292. ======================================================================================*/
  293.  
  294. void CDateView::Select(void) {
  295.  
  296.     // Check if we're already there
  297.     if ( ContainsTarget() ) return;
  298.     
  299.     // Find the first field
  300.     LEditField *newTarget;
  301.     if ( mDayPosition == 1 ) {
  302.         newTarget = mDayField;
  303.     } else if ( mMonthPosition == 1 ) {
  304.         newTarget = mMonthField;
  305.     } else {
  306.         Assert_(mYearPosition == 1);
  307.         newTarget = mYearField;
  308.     }
  309.     
  310.     if ( LCommander::SwitchTarget(newTarget) ) {
  311.         newTarget->SelectAll();
  312.     }
  313. }
  314.  
  315.  
  316. /*======================================================================================
  317.     Return true if one of the date fields in this view is the current target.
  318. ======================================================================================*/
  319.  
  320. Boolean CDateView::ContainsTarget(void) {
  321.  
  322.     return (mDayField->IsTarget() || mMonthField->IsTarget() || mYearField->IsTarget());
  323. }
  324.  
  325.  
  326. /*======================================================================================
  327.     Listen to message from broadcasters.
  328. ======================================================================================*/
  329.  
  330. void CDateView::ListenToMessage(MessageT inMessage, void *ioParam) {
  331.  
  332.     #pragma unused(ioParam)
  333.  
  334.     switch ( inMessage ) {
  335.     
  336.         case CDateArrowButton::msg_ClickUpArrow:
  337.         case CDateArrowButton::msg_ClickDownArrow:
  338.             DoClickArrow(inMessage == CDateArrowButton::msg_ClickUpArrow);
  339.             break;
  340.     
  341.         case CDateField::msg_HideDateArrows:
  342.         case CDateField::msg_ShowDateArrows:
  343.             ShowHideArrows(inMessage == CDateField::msg_ShowDateArrows);
  344.             break;
  345.  
  346.         case CDateField::msg_UserChangedText:
  347.             BroadcastMessage(msg_DateViewChanged, this);
  348.             break;
  349.     }
  350. }
  351.  
  352.  
  353. /*======================================================================================
  354.     Process a click in an arrow from a key.
  355. ======================================================================================*/
  356.  
  357. void CDateView::DoKeyArrow(Boolean inClickUpArrow) {
  358.  
  359.     LControl *theControl;
  360.     if ( inClickUpArrow ) {
  361.         theControl = (LControl *) FindPaneByID(paneID_UpButton);
  362.     } else {
  363.         theControl = (LControl *) FindPaneByID(paneID_DownButton);
  364.     }
  365.     if ( theControl && theControl->FocusDraw() ) {
  366.         theControl->SimulateHotSpotClick(1);
  367.     }
  368. }
  369.  
  370.  
  371. /*======================================================================================
  372.     Process a click in an arrow.
  373. ======================================================================================*/
  374.  
  375. void CDateView::DoClickArrow(Boolean inClickUpArrow) {
  376.  
  377.     #pragma unused(inClickUpArrow)
  378.  
  379.     CDateField *theDateField = (CDateField *) LCommander::GetTarget();
  380.     Assert_(theDateField);
  381.     if ( !theDateField ) return;
  382.         
  383.     Int16 year;
  384.     UInt8 month, day;
  385.     
  386.     GetDate(&year, &month, &day);
  387.     
  388.     // Validate that the current character is OK for the active field
  389.     
  390.     Int16 adder = inClickUpArrow ? 1 : -1;
  391.     switch ( theDateField->GetPaneID() ) {
  392.         case eDayEditFieldID: 
  393.             day += adder;
  394.             if ( day > 31 ) {
  395.                 day = 1;
  396.             } else if ( day < 1 ) {
  397.                 day = 31;
  398.             }
  399.             break;
  400.         case eMonthEditFieldID: 
  401.             month += adder; 
  402.             if ( month > 12 ) {
  403.                 month = 1;
  404.             } else if ( month < 1 ) {
  405.                 month = 12;
  406.             }
  407.             break;
  408.         default: 
  409.             year += adder;
  410.             if ( year > cMaxViewYear ) {
  411.                 year = cMinViewYear;
  412.             } else if ( year < cMinViewYear ) {
  413.                 year = cMaxViewYear;
  414.             }
  415.             break;
  416.     }
  417.     
  418.     if ( !SetDate(year, month, day) ) {
  419.         if ( adder > 0 ) {
  420.             // Day must be wrong, too large!
  421.             SetDate(year, month, 1);
  422.         } else {
  423.             while ( !SetDate(year, month, --day) ) {
  424.                 ;    // Nothing
  425.             }
  426.         }
  427.     }
  428. }
  429.  
  430.  
  431. /*======================================================================================
  432.     Hide or show the arrows.
  433. ======================================================================================*/
  434.  
  435. void CDateView::ShowHideArrows(Boolean inShow) {
  436.  
  437.     ShowHideArrow(FindPaneByID(paneID_UpButton), inShow);
  438.     ShowHideArrow(FindPaneByID(paneID_DownButton), inShow);
  439. }
  440.  
  441.  
  442. /*======================================================================================
  443.     Filter for incoming data characters.
  444. ======================================================================================*/
  445.  
  446. EKeyStatus CDateView::DateFieldFilter(TEHandle inMacTEH, Char16 theKey, Char16& theChar, SInt16 inModifiers) {
  447.  
  448.     EKeyStatus theKeyStatus = keyStatus_PassUp;
  449.     //Char16 theKey = inKeyEvent.message;
  450.     //Char16 theChar = theKey & charCodeMask;
  451.     
  452.     CDateField *theDateField = (CDateField *) LCommander::GetTarget();
  453.     Assert_(theDateField);
  454.     CDateView *theDateView = (CDateView *) theDateField->GetSuperView();
  455.     Assert_(theDateView);
  456.     
  457.     if ( !theDateField || !theDateView ) return theKeyStatus;
  458.         
  459.     switch (theChar)
  460.     {
  461.         case char_UpArrow:
  462.         case char_DownArrow:
  463.             theKeyStatus = keyStatus_Ignore;
  464.             theDateView->DoKeyArrow(theChar == char_UpArrow);
  465.             break;
  466.  
  467.         case char_Tab:
  468.         case char_Enter:
  469.         case char_Return:
  470.         case char_Escape:
  471.             theKeyStatus = keyStatus_PassUp;
  472.             break;
  473.  
  474.         default:
  475.             if ( UKeyFilters::IsPrintingChar(theChar) && UKeyFilters::IsNumberChar(theChar) ) {
  476.             
  477.                 PaneIDT paneID = theDateField->GetPaneID();
  478.                 Str15 currentText;
  479.                 theDateField->GetDescriptor(currentText);
  480.                 
  481.                 theKeyStatus = keyStatus_Input;
  482.                 
  483.                 Int16 year;
  484.                 UInt8 month, day;
  485.                 
  486.                 theDateView->GetDate(&year, &month, &day);
  487.                 
  488.                 // Validate that the current character is OK for the active field
  489.                 
  490.                 Str15 numString = { 2 };
  491.                 long wouldBeNumber;
  492.                 Assert_(currentText[0] == 2);
  493.                 numString[1] = currentText[2];
  494.                 numString[2] = theChar;
  495.                 ::StringToNum(numString, &wouldBeNumber);
  496.                 
  497.                 switch ( paneID ) {
  498.                     case eDayEditFieldID:
  499.                         day = wouldBeNumber;
  500.                         break;
  501.  
  502.                     case eMonthEditFieldID:
  503.                         month = wouldBeNumber;
  504.                         break;
  505.  
  506.                     default: // eYearEditFieldID
  507.                         year = wouldBeNumber + 2000;
  508.                         if ( year > cMaxViewYear ) year -= 100;
  509.                         break;
  510.                 }
  511.                 
  512.                 if ( !theDateView->IsValidDate(year, month, day) ||
  513.                      ((paneID != eYearEditFieldID) && (numString[1] == '0')) ) {
  514.                     if ( theChar == '0' ) {
  515.                         theKeyStatus = keyStatus_Reject;
  516.                     } else {
  517.                         currentText[1] = currentText[2] = theDateField->GetLeadingChar();
  518.                         theDateField->SetDescriptor(currentText);
  519.                     }
  520.                 }
  521.             } else {
  522.                 theKeyStatus = keyStatus_Reject;
  523.             }
  524.             break;
  525.     }
  526.     return theKeyStatus;
  527. }
  528.  
  529. /*======================================================================================
  530.     Set the edit field date.
  531. ======================================================================================*/
  532.  
  533. void CDateView::SetDateString(LEditField *inField, UInt8 inValue, UInt8 inLeadingChar) {
  534.  
  535.     Str15 valueString, tempString;
  536.  
  537.     ::NumToString(inValue, valueString);
  538.     if ( valueString[0] == 1 ) {
  539.         valueString[2] = valueString[1];
  540.         valueString[1] = inLeadingChar;
  541.         valueString[0] = 2;
  542.     }
  543.     inField->GetDescriptor(tempString);
  544.     if ( (tempString[0] != 2) || (tempString[1] != valueString[1]) || 
  545.          (tempString[2] != valueString[2]) ) {
  546.         
  547.         inField->SetDescriptor(valueString);
  548.         if ( inField->IsTarget() ) {
  549.             inField->SelectAll();
  550.         }
  551.         inField->Draw(nil);
  552.     }
  553. }
  554.  
  555.  
  556. /*======================================================================================
  557.     Show or hide the arrow nicely.
  558. ======================================================================================*/
  559.  
  560. void CDateView::ShowHideArrow(LPane *inArrow, Boolean inShow) {
  561.  
  562.     if ( inArrow ) {
  563.         if ( inShow ) {
  564.             inArrow->DontRefresh(true);
  565.             if ( !inArrow->IsVisible() ) {
  566.                 inArrow->Show();
  567.                 inArrow->DontRefresh();
  568.                 inArrow->Draw(nil);
  569.             }
  570.         } else {
  571.             inArrow->Hide();
  572.         }
  573.     }
  574. }
  575.  
  576.  
  577. /*======================================================================================
  578.     Finish creating the search dialog.
  579. ======================================================================================*/
  580.  
  581. void CDateView::CreateDateFields(UInt8 inLeadingDayChar, UInt8 inLeadingMonthChar, 
  582.                                  UInt8 inSeparatingChar) {
  583.  
  584.     // Init the panes in the view
  585.     
  586.     UInt8 separatingString[2] = { 1, inSeparatingChar };
  587.     
  588.     PaneIDT field1ID, field2ID, field3ID;
  589.     UInt8 leadingChar1, leadingChar2, leadingChar3;
  590.     
  591.     switch ( mDayPosition ) {
  592.         case 1:     
  593.             field1ID = eDayEditFieldID;
  594.             leadingChar1 = inLeadingDayChar;
  595.             if ( mMonthPosition == 2 ) {
  596.                 field2ID = eMonthEditFieldID;
  597.                 leadingChar2 = inLeadingMonthChar;
  598.                 field3ID = eYearEditFieldID;
  599.                 leadingChar3 = '0';
  600.             } else {
  601.                 field3ID = eMonthEditFieldID;
  602.                 leadingChar3 = inLeadingMonthChar;
  603.                 field2ID = eYearEditFieldID;
  604.                 leadingChar2 = '0';
  605.             }
  606.             break;
  607.         case 2:     
  608.             field2ID = eDayEditFieldID;
  609.             leadingChar2 = inLeadingDayChar;
  610.             if ( mMonthPosition == 1 ) {
  611.                 field1ID = eMonthEditFieldID;
  612.                 leadingChar1 = inLeadingMonthChar;
  613.                 field3ID = eYearEditFieldID;
  614.                 leadingChar3 = '0';
  615.             } else {
  616.                 field3ID = eMonthEditFieldID;
  617.                 leadingChar3 = inLeadingMonthChar;
  618.                 field1ID = eYearEditFieldID;
  619.                 leadingChar1 = '0';
  620.             }
  621.             break;
  622.         default:
  623.             field3ID = eDayEditFieldID;
  624.             leadingChar3 = inLeadingDayChar;
  625.             if ( mMonthPosition == 1 ) {
  626.                 field1ID = eMonthEditFieldID;
  627.                 leadingChar1 = inLeadingMonthChar;
  628.                 field2ID = eYearEditFieldID;
  629.                 leadingChar2 = '0';
  630.             } else {
  631.                 field2ID = eMonthEditFieldID;
  632.                 leadingChar2 = inLeadingMonthChar;
  633.                 field1ID = eYearEditFieldID;
  634.                 leadingChar1 = '0';
  635.             }
  636.             break;
  637.     }
  638.     
  639.     // Field 1
  640.     CDateField *theDateField = (CDateField *) FindPaneByID(paneID_DateField1);
  641.     ThrowIfResFail_(theDateField);
  642.     theDateField->SetPaneID(field1ID);
  643.     theDateField->SetLeadingChar(leadingChar1);
  644.     theDateField->SetKeyFilter(DateFieldFilter);
  645.     theDateField->AddListener(this);
  646.  
  647.     // Separator 1
  648.     LCaption *theCaption = (LCaption *) FindPaneByID(paneID_Separator1);
  649.     ThrowIfResFail_(theCaption);
  650.     theCaption->SetDescriptor(separatingString);
  651.  
  652.     // Field 2
  653.     theDateField = (CDateField *) FindPaneByID(paneID_DateField2);
  654.     ThrowIfResFail_(theDateField);
  655.     theDateField->SetPaneID(field2ID);
  656.     theDateField->SetLeadingChar(leadingChar2);
  657.     theDateField->SetKeyFilter(DateFieldFilter);
  658.     theDateField->AddListener(this);
  659.  
  660.     // Separator 2
  661.     theCaption = (LCaption *) FindPaneByID(paneID_Separator2);
  662.     ThrowIfResFail_(theCaption);
  663.     theCaption->SetDescriptor(separatingString);
  664.  
  665.     // Field 3
  666.     theDateField = (CDateField *) FindPaneByID(paneID_DateField3);
  667.     ThrowIfResFail_(theDateField);
  668.     theDateField->SetPaneID(field3ID);
  669.     theDateField->SetLeadingChar(leadingChar3);
  670.     theDateField->SetKeyFilter(DateFieldFilter);
  671.     theDateField->AddListener(this);
  672.  
  673.     // Up/down arrows
  674.  
  675.     LButton *theButton = (LButton *) FindPaneByID(paneID_UpButton);
  676.     ThrowIfResFail_(theButton);
  677.     theButton->AddListener(this);
  678.  
  679.     theButton = (LButton *) FindPaneByID(paneID_DownButton);
  680.     ThrowIfResFail_(theButton);
  681.     theButton->AddListener(this);
  682.  
  683.     mDayField = (CDateField *) FindPaneByID(eDayEditFieldID);
  684.     mMonthField = (CDateField *) FindPaneByID(eMonthEditFieldID);
  685.     mYearField = (CDateField *) FindPaneByID(eYearEditFieldID);
  686.  
  687.     // Set the date to the current date
  688.     
  689.     ShowHideArrows(eHideArrows);
  690.     SetToToday();
  691. }
  692.  
  693. #pragma mark -
  694.  
  695. /*======================================================================================
  696.     Constructor.
  697. ======================================================================================*/
  698.  
  699. CDateField::CDateField(LStream *inStream) :
  700.                        LGAEditField(inStream) {
  701.     mLeadingChar = '/';
  702.     Str15 initString = { 2, mLeadingChar, mLeadingChar };
  703.     SetDescriptor(initString);
  704. }
  705.  
  706.  
  707. /*======================================================================================
  708.     Set the text for the date field. This method does not refresh or redraw the
  709.     field after setting the text.
  710. ======================================================================================*/
  711.  
  712. void CDateField::SetDescriptor(ConstStr255Param inDescriptor) {
  713.  
  714.     if ( FocusExposed() ) {
  715.         //StEmptyVisRgn emptyRgn(GetMacPort());
  716.         ::TESetText(inDescriptor + 1, StrLength(inDescriptor), mTextEditH);
  717.     } else {
  718.         ::TESetText(inDescriptor + 1, StrLength(inDescriptor), mTextEditH);
  719.     }
  720. }
  721.  
  722.  
  723. /*======================================================================================
  724.     Disallow pasting and cutting.
  725. ======================================================================================*/
  726.  
  727. void CDateField::FindCommandStatus(CommandT    inCommand, Boolean &outEnabled,
  728.                                    Boolean &outUsesMark, Char16 &outMark,
  729.                                    Str255 outName) {
  730.  
  731.     switch ( inCommand ) {
  732.     
  733.         case cmd_Paste:
  734.         case cmd_Cut:
  735.         case cmd_Clear:
  736.         case cmd_SelectAll:
  737.             outEnabled = false;
  738.             break;
  739.     
  740.         default:
  741.             LEditField::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  742.             break;
  743.     }
  744. }
  745.  
  746.  
  747. /*======================================================================================
  748.     Select all text when clicking.
  749. ======================================================================================*/
  750.  
  751. void CDateField::ClickSelf(const SMouseDownEvent &inMouseDown) {
  752.  
  753.     #pragma unused(inMouseDown)
  754.     
  755.     if ( !IsTarget() ) {
  756.         if ( LCommander::SwitchTarget(this) ) {
  757.             this->SelectAll();
  758.         }
  759.     }
  760. }
  761.  
  762.  
  763. /*======================================================================================
  764.     Handle a key press.
  765. ======================================================================================*/
  766.  
  767. Boolean CDateField::HandleKeyPress(const EventRecord &inKeyEvent) {
  768.  
  769.     Boolean keyHandled;
  770.     
  771.     if ( (inKeyEvent.modifiers & cmdKey) || !mKeyFilter ) {
  772.     
  773.         keyHandled = LCommander::HandleKeyPress(inKeyEvent);
  774.     
  775.     } else {
  776.         
  777.         Char16 theChar = inKeyEvent.message & charCodeMask;
  778.         //EKeyStatus theKeyStatus = (*mKeyFilter)(inKeyEvent, (**mTextEditH).selStart);
  779.         EKeyStatus theKeyStatus = (*mKeyFilter)(mTextEditH, inKeyEvent.message & keyCodeMask, theChar, inKeyEvent.modifiers);
  780.         
  781.         switch ( theKeyStatus ) {
  782.         
  783.             case keyStatus_PassUp:
  784.                 keyHandled = LCommander::HandleKeyPress(inKeyEvent);
  785.                 break;
  786.  
  787.             case keyStatus_Reject:
  788.                 SysBeep(1);
  789.                 break;
  790.                 
  791.             case keyStatus_Input: {
  792.         
  793.                     // Get the current string
  794.                     
  795.                     Str15 numString;
  796.                     GetDescriptor(numString);
  797.                     
  798.                     Assert_(numString[0] == 2);
  799.                     
  800.                     numString[1] = numString[2];
  801.                     numString[2] = theChar;
  802.                     
  803.                     Boolean doDraw = FocusExposed();
  804.                     
  805.                     SetDescriptor(numString);
  806.                     SelectAll();
  807.                 
  808.                     if ( doDraw ) {
  809.                         DrawSelf();
  810.                     }
  811.                     
  812.                     keyHandled = true;
  813.                 }
  814.                 break;
  815.         }
  816.     }
  817.     
  818.     return keyHandled;
  819. }
  820.  
  821.  
  822. /*======================================================================================
  823.     Select all text when clicking.
  824. ======================================================================================*/
  825.  
  826. void CDateField::AdjustCursorSelf(Point inPortPt, const EventRecord &inMacEvent) {
  827.  
  828.     LPane::AdjustCursorSelf(inPortPt, inMacEvent);
  829. }
  830.  
  831.  
  832. /*======================================================================================
  833.     EditField is becoming the Target.
  834. ======================================================================================*/
  835.  
  836. void CDateField::BeTarget(void) {
  837.  
  838.     StFocusAndClipIfHidden focus(this);
  839.     ::TEActivate(mTextEditH);        // Show active selection
  840.     BroadcastMessage(msg_ShowDateArrows);
  841. }
  842.  
  843.  
  844. /*======================================================================================
  845.     EditField is no longer the Target.
  846. ======================================================================================*/
  847.  
  848. void CDateField::DontBeTarget(void) {
  849.  
  850.     StFocusAndClipIfHidden focus(this);
  851.     ::TEDeactivate(mTextEditH);        // Show inactive selection
  852.     BroadcastMessage(msg_HideDateArrows);
  853. }
  854.  
  855.  
  856. /*======================================================================================
  857.     The user has changed some text, broadcast a message.
  858. ======================================================================================*/
  859.  
  860. void CDateField::UserChangedText(void) {
  861.  
  862.     LEditField::UserChangedText();
  863.     BroadcastMessage(msg_UserChangedText, this);
  864. }
  865.  
  866.  
  867. #pragma mark -
  868.  
  869. /*======================================================================================
  870.     Constructor.
  871. ======================================================================================*/
  872.  
  873. CDateArrowButton::CDateArrowButton(LStream *inStream) :
  874.                                       LButton(inStream) {
  875.  
  876.     mNextBroadcastTime = 0;
  877.     mBroadcastCount = 0;
  878. }
  879.  
  880.  
  881. /*======================================================================================
  882. ======================================================================================*/
  883.  
  884. void CDateArrowButton::DisableSelf(void) {
  885.  
  886.     Draw(nil);
  887. }
  888.  
  889.  
  890. /*======================================================================================
  891. ======================================================================================*/
  892.  
  893. void CDateArrowButton::EnableSelf(void) {
  894.  
  895.     Draw(nil);
  896. }
  897.  
  898.  
  899. /*======================================================================================
  900. ======================================================================================*/
  901.  
  902. Boolean CDateArrowButton::TrackHotSpot(Int16 inHotSpot, Point inPoint, Int16 inModifiers) {
  903.  
  904.     mBroadcastCount = 0;
  905.     mNextBroadcastTime = 0;
  906.  
  907.     return LButton::TrackHotSpot(inHotSpot, inPoint, inModifiers);
  908. }
  909.  
  910.  
  911. /*======================================================================================
  912. ======================================================================================*/
  913.  
  914. void CDateArrowButton::HotSpotAction(Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside) {
  915.  
  916.     LButton::HotSpotAction(inHotSpot, inCurrInside, inPrevInside);
  917.     
  918.     if ( inCurrInside ) {
  919.         if ( mNextBroadcastTime < LMGetTicks() ) {
  920.             BroadcastValueMessage();
  921.             if ( mBroadcastCount > 4 ) {
  922.                 mNextBroadcastTime = LMGetTicks() + (cBroadcastMessageDelay/3);
  923.             } else {
  924.                 ++mBroadcastCount;
  925.                 mNextBroadcastTime = LMGetTicks() + cBroadcastMessageDelay;
  926.             }
  927.         }
  928.     } else {
  929.         mBroadcastCount = 0;
  930.     }
  931. }
  932.  
  933.  
  934. /*======================================================================================
  935. ======================================================================================*/
  936.  
  937. void CDateArrowButton::HotSpotResult(short inHotSpot) {
  938.  
  939.     if ( mBroadcastCount ) {
  940.         HotSpotAction(inHotSpot, false, true);
  941.     } else {
  942.         LButton::HotSpotResult(inHotSpot);
  943.     }
  944. }
  945.  
  946.  
  947. /*======================================================================================
  948. ======================================================================================*/
  949.  
  950. void CDateArrowButton::SimulateHotSpotClick(Int16 inHotSpot) {
  951.  
  952.     if ( IsEnabled() ) {
  953.         
  954.         mBroadcastCount = 0;
  955.         mNextBroadcastTime = 0;
  956.  
  957.         unsigned long endTicks;
  958.         HotSpotAction(inHotSpot, true, false);    // Do action for click inside
  959.         ::Delay(4, &endTicks);
  960.         //HotSpotAction(inHotSpot, false, true);    // Undo visual effect
  961.         HotSpotResult(inHotSpot);
  962.         ::Delay(4, &endTicks);
  963.     }
  964. }
  965.  
  966.  
  967.