/////////////////////////////////////////////////////////////////////////////
//
//	Copyright (c) 1999 Microsoft Corporation
//
//	Module Name:
//		DDxDDv.cpp
//
//	Description:
//		Implementation of custom dialog data exchange/dialog data validation
//		routines.
//
//	Author:
//		David Potter (DavidP)	March 24, 1999
//
//	Revision History:
//
//	Notes:
//		The IDS_REQUIRED_FIELD_EMPTY string resource must be defined in
//		the resource file.
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DDxDDv.h"

#include "resource.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
//++
//
//	DDX_Number
//
//	Description:
//		Do data exchange between the dialog and the class.
//
//	Arguments:
//		pDX			[IN OUT] Data exchange object 
//		nIDC		[IN] Control ID.
//		dwValue		[IN OUT] Value to set or get.
//		dwMin		[IN] Minimum value.
//		dwMax		[IN] Maximum value.
//		bSigned		[IN] TRUE = value is signed, FALSE = value is unsigned
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void AFXAPI DDX_Number(
	IN OUT CDataExchange *	pDX,
	IN int					nIDC,
	IN OUT DWORD &			rdwValue,
	IN DWORD				dwMin,
	IN DWORD				dwMax,
	IN BOOL					bSigned
	)
{
	HWND	hwndCtrl;
	DWORD	dwValue;

	ASSERT( pDX != NULL );
#ifdef _DEBUG
	if ( bSigned )
	{
		ASSERT( static_cast< LONG >( dwMin ) < static_cast< LONG >( dwMax ) );
	}
	else
	{
		ASSERT( dwMin < dwMax );
	}
#endif // _DEBUG

	AFX_MANAGE_STATE( AfxGetStaticModuleState() );

	// Get the control window handle.
	hwndCtrl = pDX->PrepareEditCtrl( nIDC );

	if ( pDX->m_bSaveAndValidate )
	{
		BOOL	bTranslated;

		// Get the number from the control.
		dwValue = GetDlgItemInt( pDX->m_pDlgWnd->m_hWnd, nIDC, &bTranslated, bSigned );

		// If the retrival failed, it is a signed number, and the minimum
		// value is the smallest negative value possible, check the string itself.
		if ( ! bTranslated && bSigned && (dwMin == 0x80000000) )
		{
			UINT	cch;
			TCHAR	szNumber[ 20 ];

			// See if it is the smallest negative number.
			cch = GetDlgItemText( pDX->m_pDlgWnd->m_hWnd, nIDC, szNumber, sizeof( szNumber ) / sizeof( TCHAR ) );
			if ( (cch != 0) && (lstrcmp( szNumber, _T("-2147483648") ) == 0) )
			{
				dwValue = 0x80000000;
				bTranslated = TRUE;
			} // if:  text retrieved successfully and is highest negative number
		} // if:  error translating number and getting signed number

		// If the retrieval failed or the specified number is
		// out of range, display an error.
		if (	! bTranslated
			||	(bSigned
				&& (	(static_cast< LONG >( dwValue ) < static_cast< LONG >( dwMin ))
					||	(static_cast< LONG >( dwValue ) > static_cast< LONG >( dwMax ))
					)
				)
			||	(!	bSigned
				&&	(	(dwValue < dwMin)
					||	(dwValue > dwMax)
					)
				)
			)
		{
			TCHAR szMin[ 32 ];
			TCHAR szMax[ 32 ];
			CString strPrompt;

			if ( bSigned )
			{
				wsprintf( szMin, _T("%d%"), dwMin );
				wsprintf( szMax, _T("%d%"), dwMax );
			} // if:  signed number
			else
			{
				wsprintf( szMin, _T("%u%"), dwMin );
				wsprintf( szMax, _T("%u%"), dwMax );
			} // else:  unsigned number
			AfxFormatString2( strPrompt, AFX_IDP_PARSE_INT_RANGE, szMin, szMax );
			AfxMessageBox( strPrompt, MB_ICONEXCLAMATION, AFX_IDP_PARSE_INT_RANGE );
			strPrompt.Empty(); // exception prep
			pDX->Fail();
		} // if:  invalid string
		else
		{
			rdwValue = dwValue;
		} // if:  number is in range
	} // if:  saving data
	else
	{
		CString		strMinValue;
		CString		strMaxValue;
		UINT		cchMax;

		// Set the maximum number of characters that can be entered.
		if ( bSigned )
		{
			strMinValue.Format( _T("%d"), dwMin );
			strMaxValue.Format( _T("%d"), dwMax );
		} // if:  signed value
		else
		{
			strMinValue.Format( _T("%u"), dwMin );
			strMaxValue.Format( _T("%u"), dwMax );
		} // else:  unsigned value
		cchMax = max( strMinValue.GetLength(), strMaxValue.GetLength() );
		SendMessage( hwndCtrl, EM_LIMITTEXT, cchMax, 0 );

		// Set the value into the control.
		if ( bSigned )
		{
			LONG lValue = static_cast< LONG >( rdwValue );
			DDX_Text( pDX, nIDC, lValue );
		} // if:  signed value
		else
			DDX_Text( pDX, nIDC, rdwValue );
	} // else:  setting data onto the dialog

} //*** DDX_Number()

/////////////////////////////////////////////////////////////////////////////
//++
//
//	DDV_RequiredText
//
//	Description:
//		Validate that the dialog string is present.
//
//	Arguments:
//		pDX			[IN OUT] Data exchange object 
//		nIDC		[IN] Control ID.
//		nIDCLabel	[IN] Label control ID.
//		rstrValue	[IN] Value to set or get.
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void AFXAPI DDV_RequiredText(
	IN OUT CDataExchange *	pDX,
	IN int					nIDC,
	IN int					nIDCLabel,
	IN const CString &		rstrValue
	)
{
	ASSERT( pDX != NULL );

	AFX_MANAGE_STATE( AfxGetStaticModuleState() );

	if ( pDX->m_bSaveAndValidate )
	{
		if ( rstrValue.GetLength() == 0 )
		{
			HWND		hwndLabel;
			TCHAR		szLabel[ 1024 ];
			CString		strPrompt;

			// Get the label window handle
			hwndLabel = pDX->PrepareEditCtrl( nIDCLabel );

			// Get the text of the label.
			GetWindowText( hwndLabel, szLabel, sizeof( szLabel ) / sizeof( TCHAR ) );

			// Remove ampersands (&) and colons (:).
			CleanupLabel( szLabel );

			// Format and display a message.
			strPrompt.FormatMessage( IDS_REQUIRED_FIELD_EMPTY, szLabel );
			AfxMessageBox( strPrompt, MB_ICONEXCLAMATION );

			// Do this so that the control receives focus.
			(void) pDX->PrepareEditCtrl( nIDC );

			// Fail the call.
			strPrompt.Empty();	// exception prep
			pDX->Fail();
		} // if:  field not specified
	} // if:  saving data

} //*** DDV_RequiredText()

/////////////////////////////////////////////////////////////////////////////
//++
//
//	CleanupLabel
//
//	Description:
//		Prepare a label read from a dialog to be used as a string in a
//		message by removing ampersands (&) and colons (:).
//
//	Arguments:
//		pszLabel	[IN OUT] Label to be cleaned up.
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CleanupLabel( LPTSTR pszLabel )
{
	LPTSTR	pIn, pOut;
	LANGID	langid;
	WORD	primarylangid;
	BOOL	bFELanguage;

	// Get the language ID.
	langid = GetUserDefaultLangID();
	primarylangid = static_cast< WORD >( PRIMARYLANGID( langid ) );
	bFELanguage = ((primarylangid == LANG_JAPANESE)
				|| (primarylangid == LANG_CHINESE)
				|| (primarylangid == LANG_KOREAN) );

	//
	// Copy the name sans '&' and ':' chars
	//

	pIn = pOut = pszLabel;
	do
	{
		//
		// Strip FE accelerators with parentheses. e.g. "foo(&F)" -> "foo"
		//
		if (	bFELanguage
			&&	(pIn[ 0 ] == _T('('))
			&&	(pIn[ 1 ] == _T('&'))
			&&	(pIn[ 2 ] != _T('\0'))
			&&	(pIn[ 3 ] == _T(')')) )
		{
			pIn += 3;
		} // if:  Far East language with accelerator
		else if ( (*pIn != _T('&')) && (*pIn != _T(':')) )
		{
			*pOut++ = *pIn;
		} // else if:  accelerator found
	} while ( *pIn++ != _T('\0') );

} //*** CleanupLabel()