/////////////////////////////////////////////////////////////////////////////////////////
// Project: SP Numeric Edit Control 1.2
//
// File: NumericEditCore.h
//
// Developer(s): Sergei Pavlovsky
// sergei_vp@hotmail.com
// Copyright (c) 2004-2005
//
// Description: Interface for CCoreFormatter class
// Declaration of CCoreNumericEdit class template.
//
// Platforms: Win32
//
// 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.
/////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "resource.h"
#include "spDataFormatter.h"
#include "spStlLogError.h"
#include "spAtlLogError.h"
#include "AppLogError.h"
#include "spStringUtils.h"
/////////////////////////////////////////////////////////////////////////////////////////
// Declarations
/////////////////////////////////////////////////////////////////////////////////////////
using SP::ELogError;
using SP::EStlLogError;
using SP::EAtlLogError;
using SP::CDataFormatter;
/////////////////////////////////////////////////////////////////////////////////////////
// Types
/////////////////////////////////////////////////////////////////////////////////////////
enum FormatModeEnum
{
FM_NON = 0x00000000,
FM_DISPLAY = 0x00000001,
FM_EDITING = 0x00000002
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreFormatterParams class
/////////////////////////////////////////////////////////////////////////////////////////
class CCoreFormatterParams
{
// Declarations
private:
friend class CCoreFormatter;
// Types
public:
typedef CDataFormatter::EnumDataType EnumDataType;
typedef CDataFormatter::EnumFormatTrait EnumFormatTrait;
typedef CDataFormatter::EnumPropertyID EnumPropertyID;
typedef CDataFormatter::Property Property;
// Constants
private:
static const EnumPropertyID ms_aPropertyIDs[];
static const SIZE_T ms_cPropertyIDs;
static const Property ms_aNonStdDefEditingPrpos[];
static const SIZE_T ms_cNonStdDefEditingPrpos;
// Types
protected:
typedef std::map<EnumPropertyID, tstring> CPropertyMap;
// Utilities
public:
static BOOL IsPropertyUsed(EnumDataType enType, WORD fTraits,
EnumPropertyID enProperty) throw();
// Construction & destruction
public:
CCoreFormatterParams(); // throw(ELogError)
CCoreFormatterParams(EnumDataType enDataType, WORD fFmtTraits,
const Property* pcaDisplayFmtProps = NULL,
const SIZE_T cDisplayFmtProps = 0,
LPCTSTR lpcszDisplayMask = NULL,
const Property* pcaEditingFmtProps = NULL,
const SIZE_T cEditingFmtProps = 0,
LPCTSTR lpcszEditingMask = NULL); // throw(ELogError)
CCoreFormatterParams(const CCoreFormatterParams& params); // throw(ELogError)
private:
CCoreFormatterParams(const CDataFormatter* pcDisplayFmt,
const CDataFormatter* pcEditingFmt); // throw(ELogError)
// Operators
public:
CCoreFormatterParams& operator=(const CCoreFormatterParams& src); // throw(ELogError)
// Helpers
private:
void InitNonStandardDefaultEditingProperties(); // throw(ELogError)
void AssignMaskAndProperties(FormatModeEnum enMode, const CDataFormatter* pcFmt);
// throw(ELogError)
// Helpers
protected:
const tstring& _GetMaskString(FormatModeEnum enMode) const throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
return m_aMasks[static_cast<SIZE_T>(enMode) - 1];
}
tstring& _GetMaskString(FormatModeEnum enMode) throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
return m_aMasks[static_cast<SIZE_T>(enMode) - 1];
}
const CPropertyMap& _GetPropertyMap(FormatModeEnum enMode) const throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
return m_aPropMaps[static_cast<SIZE_T>(enMode) - 1];
}
CPropertyMap& _GetPropertyMap(FormatModeEnum enMode) throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
return m_aPropMaps[static_cast<SIZE_T>(enMode) - 1];
}
// Accessors & mutators
protected:
LPCTSTR _GetProperty(FormatModeEnum enMode, EnumPropertyID enPropID) const throw()
{
const CPropertyMap& mapProps = _GetPropertyMap(enMode);
CPropertyMap::const_iterator it = mapProps.find(enPropID);
return ( it != mapProps.end() ) ? (*it).second.c_str() : NULL;
}
void _SetProperty(FormatModeEnum enMode, EnumPropertyID enPropID,
LPCTSTR lpcszValue); // throw(ELogError)
SIZE_T _GetProperties(FormatModeEnum enMode, Property* paProps,
SIZE_T cProps) const throw();
void _SetProperties(FormatModeEnum enMode, const Property* pcaProps = NULL,
SIZE_T cProps = 0); // throw(ELogError)
void _ClearProperties(FormatModeEnum enMode) throw()
{
_GetPropertyMap(enMode).clear();
if ( enMode == FM_EDITING )
InitNonStandardDefaultEditingProperties();
}
LPCTSTR _GetMask(FormatModeEnum enMode) const throw()
{
return _GetMaskString(enMode).empty() ? NULL : _GetMaskString(enMode).c_str();
}
void _SetMask(FormatModeEnum enMode, LPCTSTR lpcszValue); // throw(ELogError)
// Accessors & mutators
public:
EnumDataType GetDataType() const throw()
{
return m_enDataType;
}
WORD GetFormatTraits() const throw()
{
return m_fFmtTraits;
}
LPCTSTR GetProperty(FormatModeEnum enMode, EnumPropertyID enPropID) const throw()
{
return _GetProperty(enMode, enPropID);
}
void SetProperty(FormatModeEnum enMode, EnumPropertyID enPropID,
LPCTSTR lpcszValue) // throw(ELogError)
{
try
{
_SetProperty(enMode, enPropID, lpcszValue);
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SETFMTPROPVALUE, &e);
}
}
SIZE_T GetProperties(FormatModeEnum enMode, Property* paProps,
SIZE_T cProps) const throw()
{
return _GetProperties(enMode, paProps, cProps);
}
void SetProperties(FormatModeEnum enMode, const Property* pcaProps = NULL,
SIZE_T cProps = 0) // throw(ELogError)
{
try
{
_SetProperties(enMode, pcaProps, cProps);
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SETFMTPROPVALUES, &e);
}
}
void ClearProperties(FormatModeEnum enMode) throw()
{
_ClearProperties(enMode);
}
LPCTSTR GetMask(FormatModeEnum enMode) const throw()
{
return _GetMask(enMode);
}
void SetMask(FormatModeEnum enMode, LPCTSTR lpcszValue) // throw(ELogError)
{
try
{
_SetMask(enMode, lpcszValue);
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SETFMTMASK, &e);
}
}
// Data members
private:
EnumDataType m_enDataType;
WORD m_fFmtTraits;
tstring m_aMasks[2];
CPropertyMap m_aPropMaps[2];
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreFormatter class
/////////////////////////////////////////////////////////////////////////////////////////
class CCoreFormatter
{
// Types
public:
typedef CDataFormatter::EnumDataType EnumDataType;
typedef CDataFormatter::EnumFormatTrait EnumFormatTrait;
typedef CDataFormatter::EnumPropertyID EnumPropertyID;
typedef CDataFormatter::Property Property;
typedef std::vector<Property> CPropertyVector;
// Utilities
public:
static DWORD GetMaskCompositionOptions(FormatModeEnum enMode) throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
const DWORD adwCompositionOptions[] =
{
0,
CDataFormatter::CMO_OPTFRACTIONPART|
CDataFormatter::CMO_OPTEXPONENTPART
};
return adwCompositionOptions[static_cast<SIZE_T>(enMode) - 1];
}
// Construction & destruction
public:
CCoreFormatter() throw()
{
m_paFormatters[0] = NULL;
m_paFormatters[1] = NULL;
}
~CCoreFormatter() throw()
{
if ( m_paFormatters[0] )
m_paFormatters[0]->Release();
if ( m_paFormatters[1] )
m_paFormatters[1]->Release();
}
// Helpers
private:
const CDataFormatter* GetRawFormatter(FormatModeEnum enMode) const throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
return m_paFormatters[static_cast<SIZE_T>(enMode) - 1];
}
CDataFormatter* GetRawFormatter(FormatModeEnum enMode) throw()
{
ATLASSERT( enMode == FM_DISPLAY || enMode == FM_EDITING );
return m_paFormatters[static_cast<SIZE_T>(enMode) - 1];
}
static void CreateRawFormatter(FormatModeEnum enMode,
const CCoreFormatterParams& params,
CDataFormatter** ppFmt); // throw(ELogError)
// Operations: Formatter configuration
public:
void Configure(const CCoreFormatterParams& params); // throw(ELogError)
void Unconfigure() throw();
BOOL IsConfigured() const throw()
{
ATLASSERT( (m_paFormatters[0] && m_paFormatters[1]) ||
(!m_paFormatters[0] && !m_paFormatters[1]) );
return m_paFormatters[0] != NULL;
}
const CCoreFormatterParams GetParams() const // throw(ELogError)
{
ATLASSERT( IsConfigured() );
return CCoreFormatterParams(GetRawFormatter(FM_DISPLAY),
GetRawFormatter(FM_EDITING));
}
// Operations: Formatting
public:
SIZE_T FormatDisplayText(const void* lpcValue, LPTSTR lpBuffer,
SIZE_T cchBuffer) const; // throw(ELogError)
SIZE_T FormatEditingText(const void* lpcValue, LPTSTR lpBuffer,
SIZE_T cchBuffer) const; // throw(ELogError)
void ScanEditingText(LPCTSTR lpszText, SIZE_T cchText, void* lpValue,
BOOL* pbIsValid, BOOL* pbIsNull) const; // throw(ELogError)
// Accessors
protected:
BOOL _IsPropertyUserValue(FormatModeEnum enMode, EnumPropertyID enID) const throw()
{
ATLASSERT( IsConfigured() );
return GetRawFormatter(enMode)->IsPropertyUserValue(enID);
}
SIZE_T _GetPropertyValue(FormatModeEnum enMode, EnumPropertyID enID,
LPTSTR lpBuf = NULL, SIZE_T cchBuf = 0) const
// throw(ELogError)
{
return GetRawFormatter(enMode)->GetProperty(enID, lpBuf, cchBuf);
}
BOOL _IsUserMask(FormatModeEnum enMode) const throw()
{
ATLASSERT( IsConfigured() );
return GetRawFormatter(enMode)->IsUserMask();
}
SIZE_T _GetMask(FormatModeEnum enMode, LPTSTR lpszMask = NULL,
SIZE_T cchMask = 0) const // throw(ELogError)
{
return GetRawFormatter(enMode)->GetMask(lpszMask, cchMask);
}
// Accessors
public:
EnumDataType GetDataType() const throw()
{
ATLASSERT( IsConfigured() );
return (*m_paFormatters)->GetDataType();
}
SIZE_T GetDataSize() const throw()
{
ATLASSERT( IsConfigured() );
return (*m_paFormatters)->GetDataSize();
}
WORD GetFormatTraits() const throw()
{
ATLASSERT( IsConfigured() );
return (*m_paFormatters)->GetTraits();
}
BOOL IsPropertyUserValue(FormatModeEnum enMode, EnumPropertyID enID) const throw()
{
ATLASSERT( IsConfigured() );
return GetRawFormatter(enMode)->IsPropertyUserValue(enID);
}
SIZE_T GetPropertyValue(FormatModeEnum enMode, EnumPropertyID enID,
LPTSTR lpBuf = NULL, SIZE_T cchBuf = 0) const;
// throw(ELogError)
BOOL IsUserMask(FormatModeEnum enMode) const throw()
{
ATLASSERT( IsConfigured() );
return GetRawFormatter(enMode)->IsUserMask();
}
SIZE_T GetMask(FormatModeEnum enMode, LPTSTR lpszMask = NULL,
SIZE_T cchMask = 0) const; // throw(ELogError)
// Data members
private:
CDataFormatter* m_paFormatters[2];
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreNumericEditEvents class
/////////////////////////////////////////////////////////////////////////////////////////
class CCoreNumericEditEventSink
{
// Event
public:
virtual void _OnModified() = 0;
virtual BOOL _OnValueChanging(const void* lpcNewValue, BOOL bValid) = 0;
virtual void _OnValueChanged() = 0;
virtual void _OnError(ELogError& e) = 0;
};
/////////////////////////////////////////////////////////////////////////////////////////
// CCoreNumericEdit class template
/////////////////////////////////////////////////////////////////////////////////////////
template < class TWindow, class TFormatter, class TParams >
class CCoreNumericEdit : public TParams,
public TWindow
{
// Constants
private:
enum EnumValueStatus
{
VS_VALUENULL = 0x0001,
VS_VALUEVALID = 0x0002
};
enum EnumControlState
{
CST_MODIFY = 0x0001,
CST_EDITING = 0x0001,
CST_ALL = 0xffff
};
// Types
private:
union Numeric
{
char Int8;
unsigned char UInt8;
short Int16;
unsigned short UInt16;
int Int32;
unsigned int UInt32;
__int64 Int64;
unsigned __int64 UInt64;
float Float;
double Double;
};
// Construction & destruction
protected:
CCoreNumericEdit() throw()
: m_fVlaueStatus(VS_VALUENULL|VS_VALUEVALID),
m_lpszCurrentText(NULL),
m_fStates(0),
m_hbrBkg(NULL),
m_pEventSink(NULL)
{
::ZeroMemory(m_rgValue, sizeof(Numeric));
}
~CCoreNumericEdit() throw()
{
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
free(m_lpszCurrentText);
}
// Helpers
private:
void ReallocCurrentTextBuf(SIZE_T cchBuf) const // throw(ELogError)
{
void* lpBuf = realloc(m_lpszCurrentText, (cchBuf + 1) * sizeof(TCHAR));
ATLASSERT( lpBuf );
if ( !lpBuf )
throw EAppLogError(ENEC_OUTOFMEMORY);
m_lpszCurrentText = reinterpret_cast<LPTSTR>(lpBuf);
}
BOOL IsSameValue(const BYTE* lpcValue, WORD fValueStatus) const throw()
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( !lpcValue || !::IsBadReadPtr(lpcValue, m_formatter.GetDataSize()) );
if ( fValueStatus != m_fVlaueStatus )
return FALSE;
if ( IsValueValid() && !IsValueNull() )
{
const SIZE_T sizeValue = m_formatter.GetDataSize();
for ( SIZE_T i = 0; i < sizeValue; i++ )
{
if ( lpcValue[i] != m_rgValue[i] )
return FALSE;
}
}
return TRUE;
}
void SetEditingText() // throw(ELogError)
{
ATLASSERT( IsWindow() );
try
{
if ( IsValueValid() )
{
const SIZE_T cchText = GetEditingText(NULL, 0);
ReallocCurrentTextBuf(cchText);
GetEditingText(m_lpszCurrentText, cchText);
m_lpszCurrentText[cchText] = _T('\x0');
}
// Set text in the control
SetWindowText(m_lpszCurrentText);
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SETEDITINGTEXT, &e);
}
}
void SetDisplayText() // throw(ELogError)
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( IsWindow() );
try
{
if ( IsValueValid() )
{
const SIZE_T cchText = GetDisplayText(NULL, 0);
ReallocCurrentTextBuf(cchText);
GetDisplayText(m_lpszCurrentText, cchText);
m_lpszCurrentText[cchText] = _T('\x0');
// Set text in the control
SetWindowText(m_lpszCurrentText);
}
else
{
try
{
const SIZE_T cchText = GetDisplayText(NULL, 0);
const SIZE_T cchTextBuf = cchText + 1;
CTempBuffer<TCHAR> bufText(cchTextBuf);
GetDisplayText(bufText, cchTextBuf);
ATLASSERT( bufText[cchText] == _T('\x0') );
// Set text in the control
SetWindowText(bufText);
}
catch( CAtlException& e )
{
throw EAtlLogError(e);
}
}
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SETDISPLAYTEXT, &e);
}
}
void SaveEditText() const // throw(ELogError)
{
ATLASSERT( IsWindow() );
try
{
// Save edit text
const SIZE_T cchText = static_cast<SIZE_T>(GetWindowTextLength());
ReallocCurrentTextBuf(cchText);
GetWindowText(m_lpszCurrentText, static_cast<int>(cchText + 1));
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SAVEEDITTEXT, &e);
}
}
void ScanValue() const // throw(ELogError)
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( IsWindow() );
ATLASSERT( m_lpszCurrentText );
try
{
const SIZE_T sizeValue = m_formatter.GetDataSize();
WORD fNewVlaueState = 0;
BYTE rgNewValue[sizeof(Numeric)];
BOOL bIsValid;
BOOL bIsNull;
// Read value from control
m_formatter.ScanEditingText(m_lpszCurrentText, _tcslen(m_lpszCurrentText),
rgNewValue, &bIsValid, &bIsNull);
if ( bIsValid )
fNewVlaueState |= VS_VALUEVALID;
if ( bIsNull )
fNewVlaueState |= VS_VALUENULL;
// Assign new value
if ( !IsSameValue(rgNewValue, fNewVlaueState) )
{
if ( m_pEventSink )
{
// Fire OnValueChanging
if ( m_pEventSink->_OnValueChanging(bIsNull ? NULL : rgNewValue,
bIsValid) )
{
// Set new value
m_fVlaueStatus = fNewVlaueState;
CopyMemory(m_rgValue, rgNewValue, sizeValue);
// Fire OnValueChanged
m_pEventSink->_OnValueChanged();
}
}
else
{
// Set new value
m_fVlaueStatus = fNewVlaueState;
CopyMemory(m_rgValue, rgNewValue, sizeValue);
}
}
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SCANEDITTEXT, &e);
}
}
// Operations
public:
void BeginEdit() // throw(ELogError)
{
ATLASSERT( IsWindow() );
if ( m_formatter.IsConfigured() )
{
// Set editing text
SetEditingText();
// Change state
SetEditing(TRUE);
}
// Update modified flag
SendMessage(EM_SETMODIFY, IsModified());
}
void EndEdit() // throw(ELogError)
{
if ( m_formatter.IsConfigured() )
{
// Save text edit control
if ( IsEditing() )
{
try
{
SaveEditText();
}
catch( ... )
{
// Change state
SetEditing(FALSE);
throw;
}
// Change state
SetEditing(FALSE);
}
// Get user value
ScanValue();
// Update display text
SetDisplayText();
}
}
// Operations: Event Sink
public:
void AdviseEventSink(CCoreNumericEditEventSink* pEventSink) throw()
{
ATLASSERT( pEventSink );
ATLASSERT( !m_pEventSink );
m_pEventSink = pEventSink;
}
void UnadviseEventSink() throw()
{
ATLASSERT( m_pEventSink );
m_pEventSink = NULL;
}
// Event handlers
public:
void _OnAppearanceChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnAppearanceChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_APPEARANCE);
}
}
void _OnBorderVisibleChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnBorderVisibleChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_BORDER);
}
}
void _OnAlignmentChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnAlignmentChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_ALIGNMENT);
}
}
void _OnForeColorChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnForeColorChanged\n") );
if ( IsWindow() && !GetReadOnly() )
{
InvalidateRect(NULL);
}
}
void _OnBackColorChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnBackColorChanged\n") );
if ( IsWindow() && !GetReadOnly() )
{
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
try
{
m_hbrBkg = ::CreateSolidBrush(GetBackColor());
}
catch( ELogError& )
{
ATLASSERT( 0 );
m_hbrBkg = NULL;
}
InvalidateRect(NULL);
}
}
void _OnReadOnlyForeColorChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnReadOnlyForeColorChanged\n") );
if ( IsWindow() && GetReadOnly() )
{
InvalidateRect(NULL);
}
}
void _OnReadOnlyBackColorChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnReadOnlyBackColorChanged\n") );
if ( IsWindow() && GetReadOnly() )
{
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
try
{
m_hbrBkg = ::CreateSolidBrush(GetReadOnlyBackColor());
}
catch( ELogError& )
{
ATLASSERT( 0 );
m_hbrBkg = NULL;
}
InvalidateRect(NULL);
}
}
void _OnFontChanging() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnFontChanging\n") );
if ( IsWindow() )
{
HFONT hFont = GetFont();
if ( hFont )
{
SetFont(NULL, FALSE);
FreeFontHandle(hFont);
}
}
}
void _OnFontChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnFontChanged\n") );
if ( IsWindow() )
{
try
{
if ( HFONT hFont = GetFontHandle() )
SetFont(hFont, TRUE);
InvalidateRect(NULL);
}
catch( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
catch( ... )
{
ATLASSERT( 0 );
if ( m_pEventSink )
m_pEventSink->_OnError(EAppLogError(ENEC_UNEXPECTED));
}
}
}
void _OnReadOnlyChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnReadOnlyChanged\n") );
if ( IsWindow() )
{
UpdateReadOnly(GetReadOnly());
}
}
void _OnRightToLeftChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnRightToLeftChanged\n") );
if ( IsWindow() )
{
UpdateWindowStyles(MES_RIGHTTOLEFT);
}
}
void _OnErrorSymbolChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnErrorSymbolChanged\n") );
if ( IsWindow() && !IsEditing() && !IsValueValid() )
{
try
{
SetDisplayText();
}
catch ( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
catch( ... )
{
ATLASSERT( 0 );
if ( m_pEventSink )
m_pEventSink->_OnError(EAppLogError(ENEC_UNEXPECTED));
}
}
}
void _OnFormatterChanged(BOOL bValueTypeChanged) throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnFormatterChanged\n") );
// Update current text
if ( IsWindow() )
{
try
{
if ( bValueTypeChanged )
{
m_fVlaueStatus = VS_VALUENULL|VS_VALUEVALID;
}
UpdateReadOnly(GetReadOnly() || !m_formatter.IsConfigured());
if ( IsEditing() )
SetEditingText();
else
SetDisplayText();
}
catch ( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
catch( ... )
{
ATLASSERT( 0 );
if ( m_pEventSink )
m_pEventSink->_OnError(EAppLogError(ENEC_UNEXPECTED));
}
}
}
void _OnModifyChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnModifyChanged\n") );
}
void _OnValueChanged() throw()
{
ATLTRACE( _T("CCoreNumericEdit::_OnValueChanged\n") );
// Update current text
if ( IsWindow() )
{
try
{
if ( IsEditing() )
SetEditingText();
else
SetDisplayText();
}
catch ( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
catch( ... )
{
ATLASSERT( 0 );
if ( m_pEventSink )
m_pEventSink->_OnError(EAppLogError(ENEC_UNEXPECTED));
}
}
}
// Operations: Window
public:
void DefineWindowStyles(DWORD* pdwStyle, DWORD* pdwStyleEx,
DWORD fProperties) const throw()
{
ATLASSERT( !::IsBadReadPtr(pdwStyle, sizeof(DWORD)) );
ATLASSERT( !::IsBadReadPtr(pdwStyleEx, sizeof(DWORD)) );
// Set Autoscroll
*pdwStyle |= ES_AUTOHSCROLL;
// Set border
if ( fProperties & MES_BORDER )
{
const DWORD fBorderMask = WS_BORDER;
const DWORD fBorderMaskEx = WS_EX_CLIENTEDGE|WS_EX_STATICEDGE;
*pdwStyle &= (~fBorderMask);
*pdwStyleEx &= (~fBorderMaskEx);
if ( GetBorderVisible() )
{
const DWORD adwBorderStyles[] =
{
WS_BORDER, 0, 0
};
ATLASSERT( GetAppearance() < sizeof(adwBorderStyles)/sizeof(DWORD) );
const DWORD adwBorderExStyles[] =
{
0, WS_EX_CLIENTEDGE, WS_EX_STATICEDGE
};
ATLASSERT( GetAppearance() < sizeof(adwBorderExStyles)/sizeof(DWORD) );
*pdwStyle |= adwBorderStyles[GetAppearance()];
*pdwStyleEx |= adwBorderExStyles[GetAppearance()];
}
}
// Set Text alignment
if ( fProperties & MES_ALIGNMENT )
{
const DWORD fAlignmentMask = ES_LEFT|ES_CENTER|ES_RIGHT;
*pdwStyle &= (~fAlignmentMask);
const DWORD adwAlign[] =
{
ES_RIGHT, ES_LEFT, ES_CENTER, ES_RIGHT
};
ATLASSERT( GetAlignment() < sizeof(adwAlign)/sizeof(DWORD) );
*pdwStyle |= adwAlign[GetAlignment()];
}
// Set ReadOnly
if ( fProperties & MES_READONLY )
{
if ( GetReadOnly() || !m_formatter.IsConfigured() )
*pdwStyle |= ES_READONLY;
else
*pdwStyle &= (~ES_READONLY);
}
// Set RightToLeft
if ( fProperties & MES_RIGHTTOLEFT)
{
if ( GetRightToLeft() )
{
*pdwStyleEx &= (~WS_EX_LTRREADING);
*pdwStyleEx |= WS_EX_RTLREADING;
}
else
{
*pdwStyleEx &= (~WS_EX_RTLREADING);
*pdwStyleEx |= WS_EX_LTRREADING;
}
}
}
void UpdateWindowStyles(DWORD fProperties) throw()
{
ATLASSERT( IsWindow() );
// Get current window styles
DWORD dwStyle = GetWindowLong(GWL_STYLE);
DWORD dwStyleEx = GetWindowLong(GWL_EXSTYLE);
// Correct styles
DefineWindowStyles(&dwStyle, &dwStyleEx, fProperties);
// Update window styles
SetWindowLong(GWL_STYLE, dwStyle);
SetWindowLong(GWL_EXSTYLE, dwStyleEx);
// Redraw window
if ( fProperties & (MES_BORDER|MES_APPEARANCE) )
{
const DWORD fOptions = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|
SWP_NOACTIVATE|SWP_FRAMECHANGED;
SetWindowPos(NULL, 0, 0, 0, 0, fOptions);
}
if ( fProperties & (MES_ALIGNMENT|MES_READONLY|MES_RIGHTTOLEFT) )
{
InvalidateRect(NULL);
}
}
void UpdateFont() throw()
{
ATLASSERT( IsWindow() );
try
{
HFONT hFont = GetFont();
if ( hFont )
{
SetFont(NULL, FALSE);
FreeFontHandle(hFont);
}
if ( GetRefOleFont() )
{
hFont = GetFontHandle();
if ( hFont )
SetFont(hFont, FALSE);
}
}
catch( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
}
void UpdateReadOnly(BOOL bReadOnly) throw()
{
ATLASSERT( IsWindow() );
if ( m_hbrBkg )
::DeleteObject(m_hbrBkg);
try
{
m_hbrBkg = ( bReadOnly )
? ::CreateSolidBrush(GetReadOnlyBackColor())
: ::CreateSolidBrush(GetBackColor());
}
catch( ELogError& e )
{
m_hbrBkg = NULL;
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
SendMessage(EM_SETREADONLY, bReadOnly);
}
void UpdateEditDC(HDC hdc, HBRUSH* phbrBkg) throw()
{
ATLASSERT( !::IsBadWritePtr(phbrBkg, sizeof(HBRUSH)) );
try
{
::SetTextColor(hdc, GetForeColor());
::SetBkColor(hdc, GetBackColor());
}
catch ( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
*phbrBkg = m_hbrBkg;
}
void UpdateStaticDC(HDC hdc, HBRUSH* phbrBkg) throw()
{
ATLASSERT( !::IsBadWritePtr(phbrBkg, sizeof(HBRUSH)) );
try
{
::SetTextColor(hdc, GetReadOnlyForeColor());
::SetBkColor(hdc, GetReadOnlyBackColor());
}
catch ( ELogError& e )
{
if ( m_pEventSink )
m_pEventSink->_OnError(e);
}
*phbrBkg = m_hbrBkg;
}
// Accessors & mutators
protected:
// Value
const void* _GetValue() const // throw(ELogError)
{
ATLASSERT( m_formatter.IsConfigured() );
if ( IsEditing() )
{
try
{
// Save text edit control
SaveEditText();
// Get user value
ScanValue();
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_SAVEEDITTEXT, &e);
}
}
return IsValueNull() ? NULL : m_rgValue;
}
void _SetValue(const void* lpcValue, BOOL bValid) throw()
{
ATLASSERT( m_formatter.IsConfigured() );
ATLASSERT( !lpcValue || !::IsBadReadPtr(lpcValue, m_formatter.GetDataSize()) );
if ( bValid )
{
if ( lpcValue )
{
::CopyMemory(m_rgValue, lpcValue, m_formatter.GetDataSize());
m_fVlaueStatus &= (~VS_VALUENULL);
}
else
{
m_fVlaueStatus |= VS_VALUENULL;
}
m_fVlaueStatus |= VS_VALUEVALID;
}
else
{
m_fVlaueStatus &= (~VS_VALUEVALID);
}
}
// Display text
SIZE_T _GetDisplayText(LPTSTR lpszText, SIZE_T cchText) const // throw(ELogError)
{
ATLASSERT( !::IsBadWritePtr(lpszText, cchText * sizeof(TCHAR)) );
ATLASSERT( m_formatter.IsConfigured() );
SIZE_T cchResult;
if ( IsValueValid() )
{
cchResult = m_formatter.FormatDisplayText(GetValue(), lpszText,
cchText);
}
else if ( m_lpszCurrentText )
{
LPCTSTR lpcszErrorSymbol = GetErrorSymbol();
ATLASSERT( lpcszErrorSymbol );
const SIZE_T cchErrorSymbol = _tcslen(lpcszErrorSymbol);
cchResult = _tcslen(m_lpszCurrentText) * cchErrorSymbol;
if ( cchResult > 64 )
cchResult = 64;
if ( lpszText )
{
SIZE_T iSrcErrorSymbol = 0;
for ( SIZE_T i = 0; i < cchText - 1; i++ )
{
lpszText[i] = lpcszErrorSymbol[iSrcErrorSymbol];
if ( ++iSrcErrorSymbol == cchErrorSymbol )
iSrcErrorSymbol = 0;
}
if ( cchText )
lpszText[i] = _T('\x0');
return i;
}
}
return cchResult;
}
// Editing text
SIZE_T _GetEditingText(LPTSTR lpszText, SIZE_T cchText) const // throw(ELogError)
{
ATLASSERT( !::IsBadWritePtr(lpszText, cchText * sizeof(TCHAR)) );
ATLASSERT( m_formatter.IsConfigured() );
if ( IsValueValid() )
{
return m_formatter.FormatEditingText(GetValue(), lpszText, cchText);
}
else if ( m_lpszCurrentText )
{
if ( lpszText )
return SP::StrCopy(m_lpszCurrentText, lpszText, cchText);
else
return _tcslen(m_lpszCurrentText);
}
return cchText ? SP::StrCopy(_T(""), lpszText, cchText) : 0;
}
// Accessors & mutators
public:
// Modify
BOOL IsModified() const throw()
{
return m_fStates & CST_MODIFY;
}
void SetModify(BOOL bValue) throw()
{
if ( bValue )
m_fStates |= CST_MODIFY;
else
m_fStates &= (~CST_MODIFY);
}
// Editing
BOOL IsEditing() const throw()
{
return m_fStates & CST_EDITING;
}
void SetEditing(BOOL bValue) throw()
{
if ( bValue )
m_fStates |= CST_EDITING;
else
m_fStates &= (~CST_EDITING);
}
// Formatter
const TFormatter& GetFormatter() const throw()
{
return m_formatter;
}
TFormatter& GetFormatter() throw()
{
return m_formatter;
}
// Value
BOOL IsValueNull() const throw()
{
return m_fVlaueStatus & VS_VALUENULL;
}
BOOL IsValueValid() const throw()
{
return m_fVlaueStatus & VS_VALUEVALID;
}
const void* GetValue() const // throw(ELogError)
{
try
{
return _GetValue();
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_GETVALUE, &e);
}
}
void SetValue(const void* lpcValue, BOOL bValid) throw()
{
_SetValue(lpcValue, bValid);
}
// Display text
SIZE_T GetDisplayText(LPTSTR lpszText, SIZE_T cchText) const // throw(ELogError)
{
try
{
return _GetDisplayText(lpszText, cchText);
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_FORMATDISPLAYTEXT, &e);
}
}
// Editing text
SIZE_T GetEditingText(LPTSTR lpszText, SIZE_T cchText) const // throw(ELogError)
{
try
{
return _GetEditingText(lpszText, cchText);
}
catch( ELogError& e )
{
throw EAppLogError(ENEC_FORMATEDITINGTEXT, &e);
}
}
// Data members
private:
TFormatter m_formatter;
mutable WORD m_fVlaueStatus;
mutable BYTE m_rgValue[sizeof(Numeric)];
mutable LPTSTR m_lpszCurrentText;
WORD m_fStates;
HBRUSH m_hbrBkg;
CCoreNumericEditEventSink* m_pEventSink;
};