home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / dateedit.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  14.8 KB  |  583 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. #include "stdafx.h"
  20. #include "DateEdit.h"
  21.  
  22.  
  23. #ifdef DEBUG_mitch
  24. #define DEBUGONLY( stmt ) stmt;
  25. #define DEBUGOUT(s) OutputDebugString(s)
  26. #else
  27. #define DEBUGONLY( stmt ) ;
  28. #define DEBUGOUT(s)
  29. #endif
  30.  
  31. #ifdef DEBUG
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35.  
  36. #define ID_DAY        101
  37. #define ID_MONTH    102
  38. #define ID_YEAR        103
  39.  
  40. static int _GetMonthDays(int nYear, int nMonth)
  41. {
  42.     static int cDaysInMonth[] = {
  43.         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  44.     };
  45.  
  46.     if( nYear % 100 != 0 && nYear % 4 == 0 && nMonth == 2)
  47.         return 29;
  48.  
  49.     return cDaysInMonth[nMonth - 1];
  50. }
  51.  
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CNSDateEdit public API
  54.  
  55.  
  56. //=============================================================== CNSDateEdit
  57. CNSDateEdit::CNSDateEdit()
  58. {
  59.     m_bNeedControls = TRUE;
  60.     m_nDay = m_nMonth = m_nYear = 0;
  61.     m_iCurrentField = 0;
  62.     m_pFields[0] = m_pFields[1] = m_pFields[2] = NULL;
  63. }
  64.  
  65.  
  66. //============================================================== ~CNSDateEdit
  67. CNSDateEdit::~CNSDateEdit()
  68. {
  69. }
  70.  
  71.  
  72. //=================================================================== SetDate
  73. BOOL CNSDateEdit::SetDate( CTime &d )
  74. {
  75.     return SetDate( d.GetYear(), d.GetMonth(), d.GetDay() );
  76. }
  77.  
  78.  
  79. //=================================================================== SetDate
  80. BOOL CNSDateEdit::SetDate( int nYear, int nMonth, int nDay )
  81. {
  82.     m_nDay = nDay;
  83.     m_nMonth = nMonth;
  84.     m_nYear = nYear;
  85.     if ( !m_bNeedControls )
  86.     {
  87.         m_DayField.SetValue( m_nDay );
  88.         m_MonthField.SetValue( m_nMonth );
  89.         m_YearField.SetValue( m_nYear );
  90.     }
  91.     return TRUE;
  92. }
  93.  
  94.  
  95. //=================================================================== GetDate
  96. BOOL CNSDateEdit::GetDate( CTime &d )
  97. {
  98.     int nYear, nMonth, nDay;
  99.     if ( !GetDate( nYear, nMonth, nDay ) )
  100.         return FALSE;
  101.     d = CTime( nYear, nMonth, nDay, 0, 0, 0 );
  102.     return TRUE;
  103. }
  104.  
  105.  
  106. //=================================================================== GetDate
  107. BOOL CNSDateEdit::GetDate( int &nYear, int &nMonth, int &nDay )
  108. {
  109.     if (Validate()) {
  110.         nYear = m_nYear;
  111.         nMonth = m_nMonth;
  112.         nDay = m_nDay;
  113.  
  114.         return TRUE;
  115.     }
  116.     return FALSE;
  117. }
  118.  
  119.  
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CNSDateEdit message handlers
  122.  
  123. BEGIN_MESSAGE_MAP(CNSDateEdit, CStatic)
  124.     ON_WM_PAINT()
  125.     ON_WM_SETFOCUS()
  126.     ON_WM_SIZE()
  127.     ON_WM_ENABLE()
  128.     ON_WM_GETDLGCODE()
  129.     ON_EN_MAXTEXT(ID_DAY, OnMaxText)
  130.     ON_EN_MAXTEXT(ID_MONTH, OnMaxText)
  131.     ON_EN_MAXTEXT(ID_YEAR, OnMaxText)
  132.     ON_EN_SETFOCUS(ID_DAY, OnFocusDay)
  133.     ON_EN_SETFOCUS(ID_MONTH, OnFocusMonth)
  134.     ON_EN_SETFOCUS(ID_YEAR, OnFocusYear)
  135.     ON_EN_KILLFOCUS(ID_DAY, OnKillFocusDay)
  136.     ON_EN_KILLFOCUS(ID_MONTH, OnKillFocusMonth)
  137.     ON_EN_KILLFOCUS(ID_YEAR, OnKillFocusYear)
  138.     ON_MESSAGE(NSDE_RELAYEVENT, OnRelayEvent)
  139. END_MESSAGE_MAP()
  140.  
  141.  
  142. //=================================================================== OnPaint
  143. void CNSDateEdit::OnPaint() 
  144. {
  145.     ASSERT( IsWindow( m_hWnd ) );
  146.  
  147.     char szSeparator[2];
  148. #ifdef WIN32
  149.     VERIFY( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SDATE, szSeparator, 2 ) == 2 );
  150. #else
  151.      static char cName [] = "intl" ;
  152.      GetProfileString (cName, "sDate",  "/", szSeparator,     2) ;
  153. #endif
  154.  
  155.     BOOL bEnabled = IsWindowEnabled();
  156.     CPaintDC dc(this);
  157.     CBrush winBrush( GetSysColor( bEnabled ? COLOR_WINDOW : COLOR_BTNFACE ) );
  158.     dc.FillRect( &dc.m_ps.rcPaint, &winBrush );
  159.  
  160.     if ( m_bNeedControls )
  161.         CreateSubWindows( );
  162.  
  163.     CFont *pOldFont = dc.SelectObject( CFont::FromHandle( (HFONT)::GetStockObject( ANSI_VAR_FONT ) ) );
  164.     int oldMode = dc.SetBkMode( TRANSPARENT );
  165.     COLORREF oldTextColor = dc.SetTextColor( GetSysColor( bEnabled ? COLOR_BTNTEXT : COLOR_GRAYTEXT ) );
  166.  
  167.     dc.DrawText( szSeparator, -1, m_Sep1, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
  168.     dc.DrawText( szSeparator, -1, m_Sep2, DT_SINGLELINE | DT_CENTER | DT_VCENTER );
  169.  
  170.     dc.SelectObject( pOldFont );
  171.     dc.SetBkMode( oldMode );
  172.     dc.SetTextColor( oldTextColor );
  173. }
  174.  
  175.  
  176. void CNSDateEdit::OnSetFocus(CWnd* pOldWnd) 
  177. {
  178.     if ( m_bNeedControls )
  179.         CreateSubWindows( );
  180.  
  181.     m_pFields[0]->SetFocus();
  182.     m_iCurrentField = 0;
  183. }
  184.  
  185. void CNSDateEdit::OnSize( UINT nType, int cx, int cy )
  186. {
  187.     if ( m_bNeedControls )
  188.         CreateSubWindows( );
  189.  
  190.     if ( nType != SIZE_MINIMIZED ) {
  191.         RECT r;
  192.         ::SetRect( &r, 0, 0, cx, cy );
  193.         LayoutSubWindows( &r );
  194.     }
  195. }
  196.  
  197. void CNSDateEdit::OnEnable( BOOL bEnable )
  198. {
  199.     if ( m_bNeedControls )
  200.         CreateSubWindows( );
  201.  
  202.     m_YearField.EnableWindow( bEnable );
  203.     m_MonthField.EnableWindow( bEnable );
  204.     m_DayField.EnableWindow( bEnable );
  205.  
  206.     CStatic::OnEnable( bEnable );
  207.  
  208.     Invalidate();
  209. }
  210.  
  211. /////////////////////////////////////////////////////////////////////////////
  212. // CNSDateEdit protected & private methods
  213.  
  214.  
  215. //========================================================== CreateSubWindows
  216. void CNSDateEdit::CreateSubWindows( )
  217. {
  218.     m_bNeedControls = FALSE;
  219.  
  220.     RECT r, rcClient;
  221.  
  222.     ::SetRectEmpty(&r);
  223.     GetClientRect( &rcClient );
  224.  
  225.     VERIFY( m_YearField.Create( WS_VISIBLE, r, this, (UINT)ID_YEAR ) );
  226.     m_YearField.LimitText( 4 );
  227.  
  228.     if ( m_nYear != 0 )
  229.         m_YearField.SetValue( m_nYear );
  230.     
  231.     VERIFY( m_MonthField.Create( WS_VISIBLE, r, this, (UINT)ID_MONTH ) );
  232.     m_MonthField.LimitText( 2 );
  233.     if ( m_nMonth != 0 )
  234.         m_MonthField.SetValue( m_nMonth );
  235.     
  236.     VERIFY( m_DayField.Create( WS_VISIBLE, r, this, (UINT)ID_DAY ) );
  237.     m_DayField.LimitText( 2 );
  238.     if ( m_nDay != 0 )
  239.         m_DayField.SetValue( m_nDay );
  240.  
  241.     m_wndSpin.Create(UDS_WRAP|UDS_ARROWKEYS|UDS_SETBUDDYINT|UDS_NOTHOUSANDS|WS_CHILD|WS_VISIBLE, 
  242.                      CRect(0,0,0,0), this, 104 );
  243.  
  244.     LayoutSubWindows( &rcClient );
  245.  
  246.     m_wndSpin.SetBuddy(m_pFields[0]);
  247.     if (m_pFields[0] == &m_DayField) {
  248.         int nDays = _GetMonthDays(m_nYear, m_nMonth);
  249.         m_wndSpin.SetRange(1, nDays);
  250.         m_wndSpin.SetPos(m_nDay);
  251.     } else if (m_pFields[0] == &m_MonthField) {
  252.         m_wndSpin.SetRange(1, 12);
  253.         m_wndSpin.SetPos(m_nMonth);
  254.     } else {
  255.         m_wndSpin.SetRange(1970, 2037);
  256.         m_wndSpin.SetPos(m_nMonth);
  257.     }
  258. }
  259.  
  260. void CNSDateEdit::LayoutSubWindows( RECT *pRect )
  261. {
  262.     HDC hDC = ::GetDC( m_hWnd );
  263.     ASSERT( hDC );
  264.  
  265.     int w = pRect->right - pRect->left;
  266.     RECT r, rcSep, rcNum;
  267.     TCHAR szSeparator[2], szFormat[30], *s;
  268.     HFONT hFont =  (HFONT)::GetStockObject( ANSI_VAR_FONT );
  269.     CFont *fontCur = CFont::FromHandle( hFont );
  270.  
  271.     LOGFONT lf;
  272.     GetObject( hFont, sizeof(lf), &lf);
  273.  
  274.     // Get locale info
  275. #ifdef WIN32
  276.     VERIFY( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szFormat, 30 ) > 0 );
  277.     VERIFY( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_SDATE, szSeparator, 2 ) > 0 );
  278. #else
  279.     static char cName [] = "intl" ;
  280.     GetProfileString (cName, "sDate",  "/", szSeparator,     2) ;
  281.  
  282.     int iDate = GetProfileInt (cName, "iDate", 0) ;
  283.     sprintf( szFormat, "%c%s%c%s%c",
  284.              iDate == 1 ? 'd' : iDate == 2 ? 'y' : 'M', szSeparator,
  285.              iDate == 1 ? 'M' : iDate == 2 ? 'M' : 'd', szSeparator,
  286.              iDate == 1 ? 'y' : iDate == 2 ? 'd' : 'y' );
  287. #endif
  288.     
  289.     // Get font info
  290.     ::SetRectEmpty(&rcSep);
  291.     ::SetRectEmpty(&rcNum);
  292.  
  293.     DrawText( hDC, szSeparator, -1, &rcSep, 
  294.               DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_CALCRECT );
  295.     DrawText( hDC, _T("0"), -1, &rcNum, 
  296.               DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE | DT_CALCRECT );
  297.     
  298.     ASSERT( w >= ( rcSep.right * 2 + rcNum.right * 8 ) );
  299.  
  300.     // Start on the left
  301.  
  302.     int iHeight = lf.lfHeight;
  303.     int iWidth = 0;
  304.  
  305.     r.top = pRect->top - ((pRect->top-pRect->bottom)+iHeight)/2 - 1;
  306.     r.bottom = r.top + iHeight + 2;
  307.  
  308.     r.right = pRect->left + 1;
  309.  
  310.     // this loop parses the short date format, creating the fields as it goes
  311.     s = strtok( szFormat, szSeparator );
  312.     for( int i = 0; (i < 3) && (s != NULL); i++ )
  313.     {
  314.         switch ( s[0] )
  315.         {
  316.         case 'M':
  317.         case 'm':
  318.             r.left = r.right + 1;
  319.             r.right = r.left + rcNum.right * 2 + iWidth; // room for two characters
  320.             m_MonthField.MoveWindow( &r );
  321.             m_MonthField.SetFont( fontCur );
  322.             m_pFields[i] = &m_MonthField;
  323.             break;
  324.         case 'Y':
  325.         case 'y':
  326.             r.left = r.right + 1;
  327.             r.right = r.left + rcNum.right * 4 + iWidth; // room for four characters
  328.             m_YearField.MoveWindow( &r );
  329.             m_YearField.SetFont( fontCur );
  330.             m_pFields[i] = &m_YearField;
  331.             break;
  332.         case 'D':
  333.         case 'd':
  334.             r.left = r.right + 1;
  335.             r.right = r.left + rcNum.right * 2 + iWidth; // room for two characters
  336.             m_DayField.MoveWindow( &r );
  337.             m_DayField.SetFont( fontCur );
  338.             m_pFields[i] = &m_DayField;
  339.             break;
  340.         default:
  341.             DebugBreak();
  342.         }
  343.         if ( i == 0 )
  344.         {
  345.             r.left = r.right + 1;
  346.             r.right = r.left + rcSep.right;
  347.             m_Sep1 = r;
  348.         }
  349.         else if ( i == 1 )
  350.         {
  351.             r.left = r.right + 1;
  352.             r.right = r.left + rcSep.right;
  353.             m_Sep2 = r;
  354.         }
  355.  
  356.         s = strtok( NULL, szSeparator );
  357.     }
  358.  
  359.     r = *pRect;
  360.     r.left = r.right - GetSystemMetrics(SM_CXVSCROLL);
  361.  
  362.     m_wndSpin.MoveWindow(&r);
  363.  
  364.     ::ReleaseDC( m_hWnd, hDC );
  365. }
  366.  
  367. //================================================================ Validate
  368. BOOL CNSDateEdit::Validate()
  369. {
  370.     int nYear = m_YearField.GetValue();
  371.     int nMonth = m_MonthField.GetValue();
  372.     int nDay = m_DayField.GetValue();
  373.  
  374.     BOOL res = TRUE;
  375.  
  376.     if (nYear >= 1970 && nYear < 2038 && nMonth >= 1 && nMonth <= 12 && nDay >= 1 && nDay <= 31) {
  377.         CTime ctime(nYear, nMonth, nDay, 0, 0, 0);
  378.  
  379.         res = (ctime.GetYear() == nYear) && 
  380.               (ctime.GetMonth() == nMonth) && 
  381.               (ctime.GetDay() == nDay);
  382.     } else {
  383.         res = FALSE;
  384.     }
  385.  
  386.     if (res) {
  387.         m_nDay = nDay;
  388.         m_nMonth = nMonth;
  389.         m_nYear = nYear;
  390.     } else {
  391.         m_DayField.SetValue(m_nDay);
  392.         m_MonthField.SetValue(m_nMonth);
  393.         m_YearField.SetValue(m_nYear);
  394.     }
  395.     return res;
  396. }
  397.  
  398. //================================================================ OnKeyPress
  399. BOOL CNSDateEdit::OnKeyPress( UINT nKey, UINT nRepCnt, UINT nFlags )
  400. {
  401.     if (nKey == VK_TAB || nKey == VK_SPACE)
  402.     {
  403.         // Don't move on to the next field/window if the current
  404.         // value is invalid.
  405.         if ( !Validate() )
  406.         {
  407.             MessageBeep( MB_OK );
  408.             m_pFields[m_iCurrentField]->SetSel( 0, -1 );
  409.             return TRUE;
  410.         }
  411.         // Move the focus to the next field or control
  412.         BOOL bShift = GetKeyState( VK_SHIFT ) & 0x8000;
  413.  
  414.         if (bShift) {
  415.             if (m_iCurrentField > 0 || nKey == VK_SPACE)
  416.                 m_iCurrentField += 2;
  417.             else
  418.                 return FALSE;
  419.         } else {
  420.             if (m_iCurrentField < 2 || nKey == VK_SPACE)
  421.                 m_iCurrentField += 1;
  422.             else
  423.                 return FALSE;
  424.         }
  425.  
  426.         m_iCurrentField %= 3;
  427.  
  428.         m_pFields[m_iCurrentField]->SetFocus();
  429.  
  430.         return TRUE; // handled
  431.     }
  432.  
  433.     return FALSE; // not handled - let the child continue processing this key
  434. }
  435.  
  436. //============================================================= OnMaxText
  437. void CNSDateEdit::OnMaxText()
  438. {
  439. }
  440.  
  441. //============================================================= OnFocusDay
  442. void CNSDateEdit::OnFocusDay()
  443. {
  444.     int nDays = _GetMonthDays(m_nYear, m_nMonth);
  445.  
  446.     for (int i = 0; i < 3; i++) {
  447.         if (m_pFields[i] == &m_DayField)
  448.             m_iCurrentField = i;
  449.     }
  450.     m_wndSpin.SetBuddy(&m_DayField);
  451.     m_wndSpin.SetRange(1, nDays);
  452.     m_wndSpin.SetPos(m_nDay);
  453. }
  454.  
  455. //============================================================= OnFocusMonth
  456. void CNSDateEdit::OnFocusMonth()
  457. {
  458.     for (int i = 0; i < 3; i++) {
  459.         if (m_pFields[i] == &m_MonthField)
  460.             m_iCurrentField = i;
  461.     }
  462.     m_wndSpin.SetBuddy(&m_MonthField);
  463.     m_wndSpin.SetRange(1, 12);
  464.     m_wndSpin.SetPos(m_nMonth);
  465. }
  466.  
  467. //============================================================= OnFocusYear
  468. void CNSDateEdit::OnFocusYear()
  469. {
  470.     for (int i = 0; i < 3; i++) {
  471.         if (m_pFields[i] == &m_YearField)
  472.             m_iCurrentField = i;
  473.     }
  474.     m_wndSpin.SetBuddy(&m_YearField);
  475.     m_wndSpin.SetRange(1970, 2037);
  476.     m_wndSpin.SetPos(m_nYear);
  477. }
  478.  
  479. //============================================================= OnKillFocusDay
  480. void CNSDateEdit::OnKillFocusDay()
  481. {
  482.     if (!Validate()) {
  483.         MessageBeep( MB_OK );
  484.     }
  485. }
  486.  
  487. //============================================================= OnKillFocusMonth
  488. void CNSDateEdit::OnKillFocusMonth()
  489. {
  490.     if (!Validate()) {
  491.         MessageBeep( MB_OK );
  492.     }
  493. }
  494.  
  495. //============================================================= OnKillFocusYear
  496. void CNSDateEdit::OnKillFocusYear()
  497. {
  498.     if (!Validate()) {
  499.         MessageBeep( MB_OK );
  500.     }
  501. }
  502.  
  503. LRESULT CNSDateEdit::OnRelayEvent(WPARAM wParam, LPARAM lParam)
  504. {
  505.     LPMSG pMsg = (LPMSG) lParam; 
  506.     if (pMsg->message == WM_KEYDOWN) {
  507.         return (LRESULT) OnKeyPress( (UINT) pMsg->wParam, (UINT) LOWORD(pMsg->lParam), (UINT) HIWORD(pMsg->lParam));
  508.     }
  509.     return (LRESULT) FALSE;
  510. }
  511.  
  512. /////////////////////////////////////////////////////////////////////////////
  513. // CNSDateSubedit
  514.  
  515. //============================================================ CNSDateSubedit
  516. CNSDateSubedit::CNSDateSubedit()
  517. {
  518. }
  519.  
  520.  
  521. //=========================================================== ~CNSDateSubedit
  522. CNSDateSubedit::~CNSDateSubedit()
  523. {
  524. }
  525.  
  526. BOOL CNSDateSubedit::PreTranslateMessage( MSG* pMsg )
  527. {
  528.     if (GetParent()->SendMessage(NSDE_RELAYEVENT, (WPARAM) 0, (LPARAM) pMsg))
  529.         return TRUE;
  530.  
  531.     return CEdit::PreTranslateMessage(pMsg);
  532. }
  533.  
  534.  
  535. /////////////////////////////////////////////////////////////////////////////
  536. // CNSDateSubedit message handlers
  537.  
  538. BEGIN_MESSAGE_MAP(CNSDateSubedit, CEdit)
  539.     ON_WM_CHAR()
  540.     ON_WM_SETFOCUS()
  541. END_MESSAGE_MAP()
  542.  
  543. //==================================================================== OnChar
  544. void CNSDateSubedit::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ) 
  545. {
  546.     if ( ((nChar >= '0') && (nChar <= '9')) || (nChar == 0x08) ) {
  547.         CEdit::OnChar(nChar, nRepCnt, nFlags);
  548.     } else if (nChar == ' ') {
  549.         MSG msg;
  550.         msg.message = WM_KEYDOWN;
  551.         msg.wParam = (WPARAM) VK_SPACE;
  552.         GetParent()->SendMessage(NSDE_RELAYEVENT, (WPARAM) 0, (LPARAM) &msg);
  553.     } else {
  554.         MessageBeep( MB_OK );
  555.     }
  556. }
  557.  
  558. //=============================================================== OnSetFocus
  559. void CNSDateSubedit::OnSetFocus( CWnd* pOldWnd )
  560. {
  561.     CEdit::OnSetFocus( pOldWnd );
  562.     SetSel(0,-1);
  563. }
  564.  
  565. //================================================================== SetValue
  566. int CNSDateSubedit::SetValue( int nNewValue )
  567. {
  568.     char buff[10];
  569.     SetWindowText( itoa( nNewValue, buff, 10 ) );
  570.     return nNewValue;
  571. }
  572.  
  573.  
  574. //================================================================== GetValue
  575. int CNSDateSubedit::GetValue( void )
  576. {
  577.     char buff[10];
  578.     GetWindowText( buff, 10 );
  579.     if ( strlen( buff ) > 0 )
  580.         return atoi( buff );
  581.     return 0;
  582. }
  583.