Click here to Skip to main content
15,895,667 members
Articles / Desktop Programming / ATL

SP Numeric Edit Control

Rate me:
Please Sign up or sign in to vote.
4.78/5 (11 votes)
16 Nov 200511 min read 75K   3.6K   36  
Masked numeric edit ActiveX control.
/////////////////////////////////////////////////////////////////////////////////////////
//	Project:		SP Data Formatting Library 1.5
//
//	File:			RealEFormatter.h		
//
//	Developer(s):	Sergei Pavlovsky
//					sergei_vp@hotmail.com
//					Copyright (c) 2004-2005
//
//	Description:	
//
//	Platforms:		Win32, ATL
//
//	This code may be used in compiled form in any way you desire. This file may be 
//	redistributed unmodified by any means PROVIDING it is not sold for profit without 
//	the authors written consent, and providing that this notice and the authors name 
//	is included. If the source code in this file is used in any commercial application 
//	then acknowledgement must be made to the author of this file (in whatever form 
//	you wish).
//
//	This file is provided "as is" with no expressed or implied warranty. The author 
//	accepts no liability for any damage/loss of business that this product may cause.
/////////////////////////////////////////////////////////////////////////////////////////

#if !defined(__SP_REALEFORMATTER_H__INCLUDED__)
#define __SP_REALEFORMATTER_H__INCLUDED__

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "RealFormatter.h"

namespace SP
{

/////////////////////////////////////////////////////////////////////////////////////////
// Formatting objects
/////////////////////////////////////////////////////////////////////////////////////////

class CExponentSegment;
class CRealELiteralSegment;

class CRealEDigitalPattern;
class CRealELiteralPattern;

class CRealEFormatter;

/////////////////////////////////////////////////////////////////////////////////////////
// CRealECompositionCtx class
/////////////////////////////////////////////////////////////////////////////////////////

class CRealECompositionCtx : public CRealCompositionCtx
{
// Declarations
public:
	friend class CRealEFormatter;

// Construction
public:
	CRealECompositionCtx(const CRealEFormatter* pcFormatter, DWORD fOptions);

// Operations
public:
	void ChangePattern(const CRealEDigitalPattern* pcPattern);
	void ChangePattern(const CRealELiteralPattern* pcPattern);

// Accessors & mutators
public:
	UINT_PTR GetMinExponentDigits() const
	{
		return m_cMinExponentDigits;
	}

	UINT_PTR GetMaxExponentDigits() const
	{
		return m_cMaxExponentDigits;
	}

protected:
	const CRealEFormatter* GetFormatter() const;

// Data members
private:
	UINT_PTR m_cMinExponentDigits;
	UINT_PTR m_cMaxExponentDigits;
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealDataCtx class
/////////////////////////////////////////////////////////////////////////////////////////

class CRealEDataCtx : public CRealDataCtx
{
// Declarations
public:
	friend class CRealEFormatter;

// Construction
public:
	CRealEDataCtx(const CRealEFormatter* pcFormatter);

// Accessors & mutators
protected:
	const CRealEFormatter* GetFormatter() const;

public:
	SIZE_T GetDigitalPatterns(const CRealEDigitalPattern** prgPatters) const;
	const CRealEDigitalPattern& GetPatternForExponent(char nSign) const;
};

/////////////////////////////////////////////////////////////////////////////////////////
// CExponentSegment class
/////////////////////////////////////////////////////////////////////////////////////////

class CExponentSegment : public CNumericDigitalRTLSegment
{
// Types
public:	
	typedef CRealECompositionCtx	TCompCtx;
	typedef CNumericGenerationCtx	TGenrCtx;
	typedef CNumericTranslationCtx	TTranCtx;
	typedef CRealEDataCtx			TDataCtx;

// Types
private:
	typedef CCtxAutoSwitch<TCompCtx, CExponentSegment> CCompCtxAutoSwitch;
	typedef CCtxAutoSwitch<TGenrCtx, CExponentSegment> CGenrCtxAutoSwitch;
	typedef CCtxAutoSwitch<TTranCtx, CExponentSegment> CTranCtxAutoSwitch;
	typedef CCtxAutoSwitch<TDataCtx, CExponentSegment> CDataCtxAutoSwitch;

// Constants
protected:
	enum EnumTokens
	{
		TN_EXPONENT	= _T('e')
	};

// Constants: Formatting & scanning
protected:
	enum StandardValues
	{
		SV_PLUS		= _T('+'),
		SV_MINUS	= _T('-'),
		SV_EXPONENT	= _T('e')
	};

// Construction & destruction
public:
	CExponentSegment()
	{
	}

	CExponentSegment(const CExponentSegment& src)
		: CNumericDigitalRTLSegment(src)
	{
	}

	~CExponentSegment()
	{
	}

// Operators
public:
	CExponentSegment& operator=(const CExponentSegment& right)
	{
		CNumericDigitalRTLSegment::operator=(right);

		return *this;
	}

// Operations: Common
public:
	UINT _GetGeneralOperationErrorReason(EnumGeneralOperations enOp) const;

// Helpers: Expression
protected:
	SIZE_T ComposeTraitsToken(CNumericCompositionCtx& ctx, 
								CNumericFormatTraits::TokensEnum enToken,
								LPTSTR& lpBuf, SIZE_T& cchBuf) const;

	void GenerateToken(const CToken& token, TCHAR& chToken, 
					   LPCTSTR* ppcSymbol, SIZE_T* pcchSymbol) const throw();

	CToken TranslateToken(TCHAR chEntry, LPCTSTR lpcChar, SIZE_T cchChar) const;

// Operations: Expression
public:
	bool IsReservedSymbol(LPCTSTR lpcSymbol, SIZE_T cchSymbol) const
	{
		ATLASSERT( !::IsBadReadPtr(lpcSymbol, cchSymbol * sizeof(TCHAR)) );
		ATLASSERT( cchSymbol > 0 );
		
		return *lpcSymbol == TN_EXPONENT ||
				CNumericDigitalRTLSegment::IsReservedSymbol(lpcSymbol, cchSymbol);
	}

	SIZE_T ComposeExpression(CCompositionCtx& ctx, LPTSTR& lpBuf, SIZE_T& cchBuf) const;

// Operations: Formatting & scanning
public:
	SIZE_T Format(CNumericDataCtx& ctx, LPCTSTR lpcValue, SIZE_T cchValue,
					LPTSTR& lpBuffer, SIZE_T& cchBuffer) const;

	SIZE_T Scan(CNumericDataCtx& ctx, LPCTSTR lpcText, SIZE_T cchText, 
				  LPTSTR& lpBuffer, SIZE_T& cchBuffer) const;
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealELiteralSegment class
/////////////////////////////////////////////////////////////////////////////////////////

class CRealELiteralSegment : public CRealLiteralSegment
{
// Types
public:	
	typedef CRealECompositionCtx	TCompCtx;
	typedef CNumericGenerationCtx	TGenrCtx;
	typedef CNumericTranslationCtx	TTranCtx;
	typedef CRealEDataCtx			TDataCtx;

// Types
private:
	typedef CCtxAutoSwitch<TCompCtx, CRealELiteralSegment> CCompCtxAutoSwitch;
	typedef CCtxAutoSwitch<TGenrCtx, CRealELiteralSegment> CGenrCtxAutoSwitch;
	typedef CCtxAutoSwitch<TTranCtx, CRealELiteralSegment> CTranCtxAutoSwitch;
	typedef CCtxAutoSwitch<TDataCtx, CRealELiteralSegment> CDataCtxAutoSwitch;

// Constants
protected:
	enum EnumTokens
	{
		TN_EXPONENT	= _T('e')
	};

// Construction & destruction
public:
	CRealELiteralSegment()
	{
	}

	CRealELiteralSegment(const CRealELiteralSegment& src)
		: CRealLiteralSegment(src)
	{
	}

	~CRealELiteralSegment()
	{
	}

// Operators
public:
	CRealELiteralSegment& operator=(const CRealELiteralSegment& right)
	{
		CRealLiteralSegment::operator=(right);

		return *this;
	}

// Operations: Common
public:
	UINT _GetGeneralOperationErrorReason(EnumGeneralOperations enOp) const;

// Helpers: Expression
protected:
	SIZE_T ComposeTraitsToken(CNumericCompositionCtx& ctx, 
								CNumericFormatTraits::TokensEnum enToken,
								LPTSTR& lpBuf, SIZE_T& cchBuf) const
	{
		if ( enToken == CNumericFormatTraits::TK_GROUPSEPARATOR )
			return CFormatter::WriteTokenFwd(ctx, lpBuf, cchBuf, TN_THOUSANDSSEPARATOR);
		else
			return CRealLiteralSegment::ComposeTraitsToken(ctx, enToken, lpBuf, cchBuf);
	}

	void GenerateToken(const CToken& token, TCHAR& chToken, LPCTSTR* ppcSymbol, 
					   SIZE_T* pcchSymbol) const throw()
	{
		ATLASSERT( !::IsBadWritePtr(ppcSymbol, sizeof(LPCTSTR)) );
		ATLASSERT( !::IsBadWritePtr(pcchSymbol, sizeof(SIZE_T)) );
		ATLASSERT( *ppcSymbol == &chToken && *pcchSymbol == 1 && chToken == _T('\x0') );

		if ( token.GetAction() == CToken::CA_SETEXPONENT )
			chToken = TN_EXPONENT;
		else
			CRealLiteralSegment::GenerateToken(token, chToken, ppcSymbol, pcchSymbol);
	}

	CToken TranslateToken(TCHAR chToken, LPCTSTR lpcChar, SIZE_T cchChar) const
	{
		ATLASSERT( !::IsBadReadPtr(lpcChar, cchChar * sizeof(TCHAR)) );

		// Define command and its parameter
		if ( chToken == TN_EXPONENT )
			return CToken(CToken::CA_SETEXPONENT, CToken::CC_NON);
		else
			return CRealLiteralSegment::TranslateToken(chToken, lpcChar, cchChar);
	}

// Operations: Expression
public:
	bool IsReservedSymbol(LPCTSTR lpcSymbol, SIZE_T cchSymbol) const
	{
		ATLASSERT( !::IsBadReadPtr(lpcSymbol, cchSymbol * sizeof(TCHAR)) );
		ATLASSERT( cchSymbol > 0 );
		
		return *lpcSymbol == TN_EXPONENT ||
				CRealLiteralSegment::IsReservedSymbol(lpcSymbol, cchSymbol);
	}
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealEDigitalPattern class
/////////////////////////////////////////////////////////////////////////////////////////

class CRealEDigitalPattern : public CRealDigitalPattern
{
// Types
public:
	typedef CRealECompositionCtx	TCompCtx;
	typedef CNumericGenerationCtx	TGenrCtx;
	typedef CNumericTranslationCtx	TTranCtx;
	typedef CRealEDataCtx			TDataCtx;

// Types
private:
	typedef CCtxAutoSwitch<TCompCtx, CRealEDigitalPattern> CCompCtxAutoSwitch;
	typedef CCtxAutoSwitch<TGenrCtx, CRealEDigitalPattern> CGenrCtxAutoSwitch;
	typedef CCtxAutoSwitch<TTranCtx, CRealEDigitalPattern> CTranCtxAutoSwitch;
	typedef CCtxAutoSwitch<TDataCtx, CRealEDigitalPattern> CDataCtxAutoSwitch;

// Constants: Common
public:
	enum EnumSegments
	{
		SG_EXPONENT = 0x00000500
	};

private:
	static const UINT ms_aDigitalSegmentIDs[];

// Constants: Expression
protected:
	enum EnumTokens
	{
		TN_EXPONENT	= _T('e')
	};

// Constants: Formatting & scanning
protected:
	enum StandardValues
	{
		SV_EXPONENT	= _T('e')
	};

// Types: Expression
protected:
	struct EExpression : FExpression
	{
		LPCTSTR		lpcExponent; 
		SIZE_T		cchExponent;
		UINT_PTR	cExponentBaseLevel;
	};

// Types: Formatting & scanning
protected:
	struct EValueParts : FValueParts
	{
		char nExponentSign;
		LPCTSTR lpcExponent;
		SIZE_T cchExponent;
	};

// Construction & destruction
protected:
	CRealEDigitalPattern()
	{
	}

	CRealEDigitalPattern(const CRealEDigitalPattern& src)
		: CRealDigitalPattern(src),
		  m_segExponent(src.m_segExponent)
	{
	}

// Operators
protected:
	CRealEDigitalPattern& operator=(const CRealEDigitalPattern& right)
	{
		CRealDigitalPattern::operator=(right);

		// Segment class handles self assignment
		m_segExponent = right.m_segExponent;

		return *this;
	}

#ifdef _DEBUG

// Debug
public:
//	CTString DumpContent() const;

#endif // _DEBUG

// Helpers: Common
protected:
	SIZE_T GetDigitalSegments(const CNumericDigitalSegment** prgSegments) const;
	SIZE_T GetDigitalSegments(CNumericDigitalSegment** prgSegments);

// Helpers: Expression
protected:
	void ParseEExpression(CExpressionCtx& ctx, LPCTSTR lpcSrc, SIZE_T cchSrc, 
						  EExpression* pExpr) const;

	void ParseExpression(CExpressionCtx& ctx, LPCTSTR lpcSrc, SIZE_T cchSrc,
						 SExpression* prgSExpressions) const;

// Operations: Expression
public:
	void Clear()
	{
		m_segExponent.Clear();

		CRealDigitalPattern::Clear();
	}

	bool IsEmpty() const
	{
		return m_segExponent.IsEmpty() && CRealDigitalPattern::IsEmpty();
	}

	SIZE_T ComposeExpression(CCompositionCtx& ctx, LPTSTR& lpBuf, SIZE_T& cchBuf) const
	{
		ATLASSERT( !::IsBadWritePtr(lpBuf, cchBuf * sizeof(TCHAR)) );
		
		CCompCtxAutoSwitch ctxSwitch(ctx, this);

		return Compose(ctxSwitch.GetCtx(), lpBuf, cchBuf);
	}

// Helpers: Formatting & scanning
protected:
	void ParseStdTextEValue(CRealEDataCtx& ctx,  LPCTSTR lpcValue, SIZE_T cchValue, 
						    EValueParts* pVP) const;

	SIZE_T FormatExponent(CRealEDataCtx& ctx, char nSigh, 
							LPCTSTR lpcValue, SIZE_T cchValue,
						    LPTSTR& lpBuffer, SIZE_T& cchBuffer) const;


	void ParseTextEValue(CRealEDataCtx& ctx, LPCTSTR lpcText, SIZE_T cchText, 
						 EValueParts* pVP) const;

	SIZE_T ScanExponent(CRealEDataCtx& ctx, LPCTSTR lpcText, SIZE_T cchText, 
						  LPTSTR& lpBuffer, SIZE_T& cchBuffer) const;


	SIZE_T _Format(CRealEDataCtx& ctx, LPCTSTR lpcValue, SIZE_T cchValue,
					 LPTSTR lpBuffer, SIZE_T cchBuffer) const;

	SIZE_T _Scan(CRealEDataCtx& ctx, LPCTSTR lpcText, SIZE_T cchText, 
				   LPTSTR lpBuffer, SIZE_T cchBuffer) const;

// Data members
protected:
	CExponentSegment m_segExponent;
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealELiteralPattern class
/////////////////////////////////////////////////////////////////////////////////////////

class CRealELiteralPattern : public CRealLiteralPattern
{
// Types
public:
	typedef CRealECompositionCtx	TCompCtx;
	typedef CNumericGenerationCtx	TGenrCtx;
	typedef CNumericTranslationCtx	TTranCtx;
	typedef CRealEDataCtx			TDataCtx;

	typedef CRealELiteralSegment	TSegment;

// Types
private:
	typedef CCtxAutoSwitch<TCompCtx, CRealEDigitalPattern> CCompCtxAutoSwitch;
	typedef CCtxAutoSwitch<TGenrCtx, CRealEDigitalPattern> CGenrCtxAutoSwitch;
	typedef CCtxAutoSwitch<TTranCtx, CRealEDigitalPattern> CTranCtxAutoSwitch;
	typedef CCtxAutoSwitch<TDataCtx, CRealEDigitalPattern> CDataCtxAutoSwitch;

// Construction & destruction
protected:
	CRealELiteralPattern()
	{
	}

	CRealELiteralPattern(const CRealELiteralPattern& src)
		: CRealLiteralPattern(src)
	{
	}

// Operators
protected:
	CRealELiteralPattern& operator=(const CRealELiteralPattern& right)
	{
		return static_cast<CRealELiteralPattern&>(CRealLiteralPattern::operator=(right));
	}
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealENullPattern class template
/////////////////////////////////////////////////////////////////////////////////////////

class CRealENullPattern : public CRealELiteralPattern
{
// Types
private:	
	typedef CCtxAutoSwitch<TCompCtx, CRealENullPattern> CCompCtxAutoSwitch;
	typedef CCtxAutoSwitch<TGenrCtx, CRealENullPattern> CGenrCtxAutoSwitch;
	typedef CCtxAutoSwitch<TTranCtx, CRealENullPattern> CTranCtxAutoSwitch;
	typedef CCtxAutoSwitch<TDataCtx, CRealENullPattern> CDataCtxAutoSwitch;

// Construction & destruction
public:
	CRealENullPattern()
	{
	}

	CRealENullPattern(const CRealENullPattern& src)
		: CRealELiteralPattern(src)
	{
	}

	~CRealENullPattern()
	{
	}

// Operators
public:
	CRealENullPattern& operator=(const CRealENullPattern& right)
	{
		CRealELiteralPattern::operator=(right);

		return *this;
	}

// Helpers: Common
protected:
	const CNumericLiteralSegment& GetSegment() const
	{
		return m_segment;
	}

	CNumericLiteralSegment& GetSegment()
	{
		return m_segment;
	}

// Operarions: Common
public:
	CNumericFormatTraits::TokensEnum GetDefultTraitsToken() const
	{
		return CNumericFormatTraits::TK_NULL;	
	}

	UINT _GetGeneralOperationErrorReason(EnumGeneralOperations enOp) const;

// Operations: Formatting & scanning
public:
	SIZE_T Format(CDataCtx& ctx, const void* lpcValue, 
					LPTSTR lpBuffer, SIZE_T cchBuffer) const;

	bool Matches(CDataCtx& ctx, LPCTSTR lpcText, SIZE_T cchText) const;

	bool Scan(CDataCtx& ctx, LPCTSTR lpcText, SIZE_T cchText, 
			  void* lpValue, bool* pbNotNull) const;

// Data members
private:
	TSegment m_segment;
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealEFormatter class
/////////////////////////////////////////////////////////////////////////////////////////

class CRealEFormatter : public CRealFormatter
{
// Declarations
public:
	friend class CRealEDataCtx;

// Types
public:
	typedef CRealECompositionCtx	TCompCtx;
	typedef CNumericGenerationCtx	TGenrCtx;
	typedef CNumericTranslationCtx	TTranCtx;
	typedef CRealEDataCtx			TDataCtx;

	typedef CRealEDigitalPattern	TDigitalPattern;
	typedef CRealELiteralPattern	TLiteralPattern;
	typedef CRealENullPattern		TNullPattern;

// Construction & destruction
protected:
	CRealEFormatter(LCID lcid, WORD fTraits = TRAIT_NUMBER)
		: CRealFormatter(lcid, fTraits)
	{
	}

// Helpers: Common
protected:
	virtual SIZE_T GetDigitalPatterns(
							const CRealEDigitalPattern** prgPatters) const = 0;

// Operations: Expression
public:
	SIZE_T ComposeMaskExpression(LPTSTR lpBuffer, SIZE_T cchBuffer, 
								 DWORD fOptions = 0) const // throw (ELogError)
	{
		return _ComposeMask(CRealECompositionCtx(this, fOptions), lpBuffer, cchBuffer);
	}

// Helpers: Formatting & scanning
protected:
	virtual const CRealEDigitalPattern& GetPatternForExponent(char nSign) const = 0;

// Operations: Formatting & scanning
public:
	SIZE_T Format(const void* lpcValue, LPTSTR lpBuffer, SIZE_T cchBuffer) const;
	bool Matches(LPCTSTR lpcText, SIZE_T cchText) const;
	bool Scan(LPCTSTR lpcText, SIZE_T cchText, void* lpValue, bool* pbNotNull) const;
};

/////////////////////////////////////////////////////////////////////////////////////////
// CRealCompositionCtx class implementation
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Construction

inline CRealECompositionCtx::CRealECompositionCtx(const CRealEFormatter* pcFormatter, 
												  DWORD fOptions)
	: CRealCompositionCtx(pcFormatter, fOptions),	  
	  m_cMinExponentDigits(0),
	  m_cMaxExponentDigits(CNumericSegment::DC_UNLIMITED)
{
}

/////////////////////////////////////////////////////////////////////////////////////////
// Operations

inline void CRealECompositionCtx::ChangePattern(const CRealEDigitalPattern* pcPattern)
{
	CRealCompositionCtx::ChangePattern(pcPattern);

	if ( pcPattern )
	{
		const CNumericFormatTraits& ft = 
			static_cast<const CNumericFormatTraits&>(GetFormatter()->GetFormatTraits());

		m_cMinExponentDigits = ft.GetExponentDigitsNumber();	
		m_cMaxExponentDigits = pcPattern->IsZero() 
								? m_cMinExponentDigits 
								: CNumericSegment::DC_UNLIMITED;
	}
}

inline void CRealECompositionCtx::ChangePattern(const CRealELiteralPattern* pcPattern)
{
	CRealCompositionCtx::ChangePattern(pcPattern);
}

/////////////////////////////////////////////////////////////////////////////////////////
// Accessors & mutators

inline const CRealEFormatter* CRealECompositionCtx::GetFormatter() const
{
	return static_cast<const CRealEFormatter*>(CRealCompositionCtx::GetFormatter());
}

/////////////////////////////////////////////////////////////////////////////////////////
// CRealEDataCtx class
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Construction

inline CRealEDataCtx::CRealEDataCtx(const CRealEFormatter* pcFormatter)
	: CRealDataCtx(pcFormatter)
{
}

/////////////////////////////////////////////////////////////////////////////////////////
// Accessors & mutators

inline const CRealEFormatter* CRealEDataCtx::GetFormatter() const
{
	return static_cast<const CRealEFormatter*>(CRealDataCtx::GetFormatter());
}

inline SIZE_T CRealEDataCtx::GetDigitalPatterns(const CRealEDigitalPattern** prgPatters) const
{
	return GetFormatter()->GetDigitalPatterns(prgPatters);
}

inline const CRealEDigitalPattern& CRealEDataCtx::GetPatternForExponent(char nSign) const
{
	return GetFormatter()->GetPatternForExponent(nSign);
}

}; // namespace SP

#endif // !defined(__SP_REALEFORMATTER_H__INCLUDED__)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions