Click here to Skip to main content
13,763,464 members
Click here to Skip to main content

Stats

81.2K views
1.1K downloads
49 bookmarked
Posted 24 Nov 2008
Licenced CPOL

The SBJ MVC Framework - The Model, from Abstraction to Realization

, 20 Mar 2009
A Model-View-Controller Framework that integrates with the MFC Doc/View architecture
XmlMvc2090.dll
Shapes.exe
SbjCore2090.dll
Shapes
Data
res
buttons.bmp
filelarge.bmp
filesmall.bmp
filesmall.png
main.bmp
Shapes.ico
ShapesDoc.ico
Toolbar.bmp
Toolbar256.bmp
treeimages.bmp
vssver.scc
Write - Copy.png
Write.png
Write1.png
writelarge.bmp
writesmall - Copy.bmp
writesmall - Copy.png
writesmall.bmp
writesmall.png
Shapes.vcproj
XmlMvc
res
vssver.scc
XmlMvc.vcproj
SbjCore
Registry.H
res
bigcat.ico
main.bmp
properties.bmp
properties_hc.bmp
properties_wnd_hc.ico
vssver.scc
SbjCore.vcproj
CommonSettings.vsprops
CommonAppDebugSettings.vsprops
CommonAppReleaseSettings.vsprops
CommonDLLDebugSettings.vsprops
CommonDLLReleaseSettings.vsprops
//------------------------------------------------------------------------------
// $Workfile: PropFactories.cpp $
// $Header: /SbjDev/SbjCore/PropFactories.cpp 2     11/12/08 2:22p Steve $
//
//	Copyright � 2008 SbjCat
// All rights reserved.
//
//
// *** Authors ***
//	 Steve Johnson
//
// $Revision: 2 $
//
//-----------------------------------------------------------------------------

#include "StdAfx.h"
#include "PropFactories.h"

#include "ModelController.h"



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

namespace localNS
{
	struct SColorAndName
	{
		COLORREF clr;
		CString sName;

		SColorAndName(COLORREF color, LPCTSTR lpszName) :
		clr(color),
			sName(lpszName)
		{

		}
	};

	SColorAndName namedColors[] =
	{
		SColorAndName( RGB( 0xFF, 0xB6, 0xC1 ), _T( "LightPink" ) ),
		SColorAndName( RGB( 0xFF, 0xC0, 0xCB ), _T( "Pink" ) ),
		SColorAndName( RGB( 0xDC, 0x14, 0x3C ), _T( "Crimson" ) ),
		SColorAndName( RGB( 0xFF, 0xF0, 0xF5 ), _T( "LavenderBlush" ) ),
		SColorAndName( RGB( 0xDB, 0x70, 0x93 ), _T( "PaleVioletRed" ) ),
		SColorAndName( RGB( 0xFF, 0x69, 0xB4 ), _T( "HotPink" ) ),
		SColorAndName( RGB( 0xFF, 0x14, 0x93 ), _T( "DeepPink" ) ),
		SColorAndName( RGB( 0xC7, 0x15, 0x85 ), _T( "MediumVioletRed" ) ),
		SColorAndName( RGB( 0xDA, 0x70, 0xD6 ), _T( "Orchid" ) ),
		SColorAndName( RGB( 0xD8, 0xBF, 0xD8 ), _T( "Thistle" ) ),
		SColorAndName( RGB( 0xDD, 0xA0, 0xDD ), _T( "Plum" ) ),
		SColorAndName( RGB( 0xEE, 0x82, 0xEE ), _T( "Violet" ) ),
		SColorAndName( RGB( 0xFF, 0x00, 0xFF ), _T( "Magenta" ) ),
		SColorAndName( RGB( 0xFF, 0x00, 0xFF ), _T( "Fuchsia" ) ),
		SColorAndName( RGB( 0x8B, 0x00, 0x8B ), _T( "DarkMagenta" ) ),

		SColorAndName( RGB( 0x80, 0x00, 0x80 ), _T( "Purple" ) ),

		SColorAndName( RGB( 0xBA, 0x55, 0xD3 ), _T( "MediumOrchid" ) ),
		SColorAndName( RGB( 0x94, 0x00, 0xD3 ), _T( "DarkViolet" ) ),
		SColorAndName( RGB( 0x99, 0x32, 0xCC ), _T( "DarkOrchid" ) ),
		SColorAndName( RGB( 0x4B, 0x00, 0x82 ), _T( "Indigo" ) ),
		SColorAndName( RGB( 0x8A, 0x2B, 0xE2 ), _T( "BlueViolet" ) ),
		SColorAndName( RGB( 0x93, 0x70, 0xDB ), _T( "MediumPurple" ) ),
		SColorAndName( RGB( 0x7B, 0x68, 0xEE ), _T( "MediumSlateBlue" ) ),
		SColorAndName( RGB( 0x6A, 0x5A, 0xCD ), _T( "SlateBlue" ) ),
		SColorAndName( RGB( 0x48, 0x3D, 0x8B ), _T( "DarkSlateBlue" ) ),
		SColorAndName( RGB( 0xE6, 0xE6, 0xFA ), _T( "Lavender" ) ),
		SColorAndName( RGB( 0xF8, 0xF8, 0xFF ), _T( "GhostWhite" ) ),

		SColorAndName( RGB( 0x00, 0x00, 0xFF ), _T( "Blue" ) ),

		SColorAndName( RGB( 0x00, 0x00, 0xCD ), _T( "MediumBlue" ) ),
		SColorAndName( RGB( 0x19, 0x19, 0x70 ), _T( "MidnightBlue" ) ),
		SColorAndName( RGB( 0x00, 0x00, 0x8B ), _T( "DarkBlue" ) ),
		SColorAndName( RGB( 0x00, 0x00, 0x80 ), _T( "Navy" ) ),
		SColorAndName( RGB( 0x41, 0x69, 0xE1 ), _T( "RoyalBlue" ) ),
		SColorAndName( RGB( 0x64, 0x95, 0xED ), _T( "CornflowerBlue" ) ),
		SColorAndName( RGB( 0xB0, 0xC4, 0xDE ), _T( "LightSteelBlue" ) ),
		SColorAndName( RGB( 0x77, 0x88, 0x99 ), _T( "LightSlateGray" ) ),
		SColorAndName( RGB( 0x70, 0x80, 0x90 ), _T( "SlateGray" ) ),
		SColorAndName( RGB( 0x1E, 0x90, 0xFF ), _T( "DodgerBlue" ) ) ,
		SColorAndName( RGB( 0xF0, 0xF8, 0xFF ), _T( "AliceBlue" ) ),
		SColorAndName( RGB( 0x46, 0x82, 0xB4 ), _T( "SteelBlue" ) ),
		SColorAndName( RGB( 0x87, 0xCE, 0xFA ), _T( "LightSkyBlue" ) ),
		SColorAndName( RGB( 0x87, 0xCE, 0xEB ), _T( "SkyBlue" ) ),
		SColorAndName( RGB( 0x00, 0xBF, 0xFF ), _T( "DeepSkyBlue" ) ),
		SColorAndName( RGB( 0xAD, 0xD8, 0xE6 ), _T( "LightBlue" ) ),
		SColorAndName( RGB( 0xB0, 0xE0, 0xE6 ), _T( "PowderBlue" ) ),
		SColorAndName( RGB( 0x5F, 0x9E, 0xA0 ), _T( "CadetBlue" ) ),
		SColorAndName( RGB( 0xF0, 0xFF, 0xFF ), _T( "Azure" ) ),
		SColorAndName( RGB( 0xE0, 0xFF, 0xFF ), _T( "LightCyan" ) ),
		SColorAndName( RGB( 0xAF, 0xEE, 0xEE ), _T( "PaleTurquoise" ) ),
		SColorAndName( RGB( 0x00, 0xFF, 0xFF ), _T( "Cyan" ) ),
		SColorAndName( RGB( 0x00, 0xFF, 0xFF ), _T( "Aqua" ) ),
		SColorAndName( RGB( 0x00, 0xCE, 0xD1 ), _T( "DarkTurquoise" ) ),
		SColorAndName( RGB( 0x2F, 0x4F, 0x4F ), _T( "DarkSlateGray" ) ),
		SColorAndName( RGB( 0x00, 0x8B, 0x8B ), _T( "DarkCyan" ) ),
		SColorAndName( RGB( 0x00, 0x80, 0x80 ), _T( "Teal" ) ),
		SColorAndName( RGB( 0x48, 0xD1, 0xCC ), _T( "MediumTurquoise" ) ),
		SColorAndName( RGB( 0x20, 0xB2, 0xAA ), _T( "LightSeaGreen" ) ),
		SColorAndName( RGB( 0x40, 0xE0, 0xD0 ), _T( "Turquoise" ) ),
		SColorAndName( RGB( 0x7F, 0xFF, 0xD4 ), _T( "Aquamarine" ) ),
		SColorAndName( RGB( 0x66, 0xCD, 0xAA ), _T( "MediumAquamarine" ) ),
		SColorAndName( RGB( 0x00, 0xFA, 0x9A ), _T( "MediumSpringGreen" ) ),
		SColorAndName( RGB( 0xF5, 0xFF, 0xFA ), _T( "MintCream" ) ),
		SColorAndName( RGB( 0xF0, 0xFF, 0xF0 ), _T( "Honeydew" ) ),
		SColorAndName( RGB( 0x00, 0xFF, 0x7F ), _T( "SpringGreen" ) ),
		SColorAndName( RGB( 0x3C, 0xB3, 0x71 ), _T( "MediumSeaGreen" ) ),
		SColorAndName( RGB( 0x2E, 0x8B, 0x57 ), _T( "SeaGreen" ) ),
		SColorAndName( RGB( 0x90, 0xEE, 0x90 ), _T( "LightGreen" ) ),
		SColorAndName( RGB( 0x98, 0xFB, 0x98 ), _T( "PaleGreen" ) ),
		SColorAndName( RGB( 0x8F, 0xBC, 0x8F ), _T( "DarkSeaGreen" ) ),
		SColorAndName( RGB( 0x32, 0xCD, 0x32 ), _T( "LimeGreen" ) ),
		SColorAndName( RGB( 0x00, 0xFF, 0x00 ), _T( "Lime" ) ),
		SColorAndName( RGB( 0x22, 0x8B, 0x22 ), _T( "ForestGreen" ) ),

		SColorAndName( RGB( 0x00, 0x80, 0x00 ), _T( "Green" ) ),

		SColorAndName( RGB( 0x00, 0x64, 0x00 ), _T( "DarkGreen" ) ),
		SColorAndName( RGB( 0x7F, 0xFF, 0x00 ), _T( "Chartreuse" ) ),
		SColorAndName( RGB( 0x7C, 0xFC, 0x00 ), _T( "LawnGreen" ) ),
		SColorAndName( RGB( 0xAD, 0xFF, 0x2F ), _T( "GreenYellow" ) ),
		SColorAndName( RGB( 0x55, 0x6B, 0x2F ), _T( "DarkOliveGreen" ) ),
		SColorAndName( RGB( 0x9A, 0xCD, 0x32 ), _T( "YellowGreen" ) ),
		SColorAndName( RGB( 0x6B, 0x8E, 0x23 ), _T( "OliveDrab" ) ),
		SColorAndName( RGB( 0xF5, 0xF5, 0xDC ), _T( "Beige" ) ),
		SColorAndName( RGB( 0xFA, 0xFA, 0xD2 ), _T( "LightGoldenrodYellow" ) ),
		SColorAndName( RGB( 0xFF, 0xFF, 0xF0 ), _T( "Ivory" ) ),
		SColorAndName( RGB( 0xFF, 0xFF, 0xE0 ), _T( "LightYellow" ) ),

		SColorAndName( RGB( 0xFF, 0xFF, 0x00 ), _T( "Yellow" ) ),

		SColorAndName( RGB( 0x80, 0x80, 0x00 ), _T( "Olive" ) ),
		SColorAndName( RGB( 0xBD, 0xB7, 0x6B ), _T( "DarkKhaki" ) ),
		SColorAndName( RGB( 0xFF, 0xFA, 0xCD ), _T( "LemonChiffon" ) ),
		SColorAndName( RGB( 0xEE, 0xE8, 0xAA ), _T( "PaleGoldenrod" ) ),
		SColorAndName( RGB( 0xF0, 0xE6, 0x8C ), _T( "Khaki" ) ),
		SColorAndName( RGB( 0xFF, 0xD7, 0x00 ), _T( "Gold" ) ),
		SColorAndName( RGB( 0xFF, 0xF8, 0xDC ), _T( "Cornsilk" ) ),
		SColorAndName( RGB( 0xDA, 0xA5, 0x20 ), _T( "Goldenrod" ) ),
		SColorAndName( RGB( 0xB8, 0x86, 0x0B ), _T( "DarkGoldenrod" ) ),
		SColorAndName( RGB( 0xFF, 0xFA, 0xF0 ), _T( "FloralWhite" ) ),
		SColorAndName( RGB( 0xFD, 0xF5, 0xE6 ), _T( "OldLace" ) ),
		SColorAndName( RGB( 0xFF, 0xEF, 0xD5 ), _T( "PapayaWhip" ) ),
		SColorAndName( RGB( 0xFA, 0xEB, 0xD7 ), _T( "AntiqueWhite" ) ),
		SColorAndName( RGB( 0xFF, 0xEB, 0xCD ), _T( "BlanchedAlmond" ) ),
		SColorAndName( RGB( 0xFF, 0xE4, 0xC4 ), _T( "Bisque" ) ),
		SColorAndName( RGB( 0xFF, 0xDE, 0xAD ), _T( "NavajoWhite" ) ),
		SColorAndName( RGB( 0xFF, 0xDA, 0xB9 ), _T( "PeachPuff" ) ),
		SColorAndName( RGB( 0xFF, 0xE4, 0xB5 ), _T( "Moccasin" ) ),
		SColorAndName( RGB( 0xF5, 0xDE, 0xB3 ), _T( "Wheat" ) ),
		SColorAndName( RGB( 0xD2, 0xB4, 0x8C ), _T( "Tan" ) ),
		SColorAndName( RGB( 0xDE, 0xB8, 0x87 ), _T( "BurlyWood" ) ),
		SColorAndName( RGB( 0xFA, 0xF0, 0xE6 ), _T( "Linen" ) ),
		SColorAndName( RGB( 0xF4, 0xA4, 0x60 ), _T( "SandyBrown" ) ),

		SColorAndName( RGB( 0xFF, 0xA5, 0x00 ), _T( "Orange" ) ),

		SColorAndName( RGB( 0xFF, 0x8C, 0x00 ), _T( "DarkOrange" ) ),
		SColorAndName( RGB( 0xD2, 0x69, 0x1E ), _T( "Chocolate" ) ),
		SColorAndName( RGB( 0xCD, 0x85, 0x3F ), _T( "Peru" ) ),
		SColorAndName( RGB( 0x8B, 0x45, 0x13 ), _T( "SaddleBrown" ) ),
		SColorAndName( RGB( 0xA0, 0x52, 0x2D ), _T( "Sienna" ) ),
		SColorAndName( RGB( 0xFF, 0xF5, 0xEE ), _T( "Seashell" ) ),
		SColorAndName( RGB( 0xFF, 0xA0, 0x7A ), _T( "LightSalmon" ) ),
		SColorAndName( RGB( 0xFF, 0x7F, 0x50 ), _T( "Coral" ) ),
		SColorAndName( RGB( 0xFF, 0x45, 0x00 ), _T( "OrangeRed" ) ),
		SColorAndName( RGB( 0xE9, 0x96, 0x7A ), _T( "DarkSalmon" ) ),
		SColorAndName( RGB( 0xFF, 0x63, 0x47 ), _T( "Tomato" ) ),
		SColorAndName( RGB( 0xFF, 0xE4, 0xE1 ), _T( "MistyRose" ) ),
		SColorAndName( RGB( 0xFA, 0x80, 0x72 ), _T( "Salmon" ) ),
		SColorAndName( RGB( 0xFF, 0xFA, 0xFA ), _T( "Snow" ) ),
		SColorAndName( RGB( 0xF0, 0x80, 0x80 ), _T( "LightCoral" ) ),
		SColorAndName( RGB( 0xBC, 0x8F, 0x8F ), _T( "RosyBrown" ) ),
		SColorAndName( RGB( 0xCD, 0x5C, 0x5C ), _T( "IndianRed" ) ),
		SColorAndName( RGB( 0xA5, 0x2A, 0x2A ), _T( "Brown" ) ),
		SColorAndName( RGB( 0xB2, 0x22, 0x22 ), _T( "FireBrick" ) ),
		SColorAndName( RGB( 0xFF, 0x00, 0x00 ), _T( "Red" ) ),
		SColorAndName( RGB( 0x8B, 0x00, 0x00 ), _T( "DarkRed" ) ),
		SColorAndName( RGB( 0x80, 0x00, 0x00 ), _T( "Maroon" ) ),

		SColorAndName( RGB( 0xF5, 0xF5, 0xF5 ), _T( "WhiteSmoke" ) ),
		SColorAndName( RGB( 0xDC, 0xDC, 0xDC ), _T( "Gainsboro" ) ),
		SColorAndName( RGB( 0xD3, 0xD3, 0xD3 ), _T( "LightGrey" ) ),
		SColorAndName( RGB( 0xC0, 0xC0, 0xC0 ), _T( "Silver" ) ),
		SColorAndName( RGB( 0xA9, 0xA9, 0xA9 ), _T( "DarkGray" ) ),
		SColorAndName( RGB( 0x80, 0x80, 0x80 ), _T( "Gray" ) ),
		SColorAndName( RGB( 0x69, 0x69, 0x69 ), _T( "DimGray" ) ),
		SColorAndName( RGB( 0x00, 0x00, 0x00 ), _T( "Black" ) ),
		SColorAndName( RGB( 0xFF, 0xFF, 0xFF ), _T( "White" ) ),	
	};

	class NamedColors
	{
	public:
		NamedColors()
		{
			nCount = _countof(namedColors);

			for (int nIndex = nCount - 1; nIndex >= 0; nIndex--)
			{
				CMFCColorBar::SetColorName(namedColors[nIndex].clr, namedColors[nIndex].sName);
				colors.Add(namedColors[nIndex].clr);
			}
		}

		virtual ~NamedColors()
		{
		}

		CString GetName(COLORREF clr)
		{
			CString sName(_T("Custom"));

			for (int nIndex = 0; nIndex < _countof(namedColors); nIndex++)
			{
				if (clr == namedColors[nIndex].clr)
				{
					sName = namedColors[nIndex].sName;
					break;
				}
			}
			return sName;
		}

		int nCount;
		CArray<COLORREF, COLORREF> colors;

	} theNamedColors;

	
	namespace Colors
	{
		int GetNamedColors(CArray<COLORREF, COLORREF>& colors)
		{
			colors.RemoveAll();
			colors.Append(theNamedColors.colors);
			return theNamedColors.nCount;
		}

		CString GetName(COLORREF clr)
		{
			return theNamedColors.GetName(clr);
		}
	}
	
	
	class ColorProp : public CMFCPropertyGridColorProperty
	{
	public:
		ColorProp(const CString& strName, const COLORREF& color, CPalette* pPalette = NULL, LPCTSTR lpszDescr = NULL, DWORD_PTR dwData = 0) :
			CMFCPropertyGridColorProperty(strName, color, pPalette, lpszDescr, dwData)
		{
			Colors::GetNamedColors(m_Colors);
			SetColumnsNumber(10);
			AllowEdit(false);
		}
		
		virtual BOOL OnUpdateValue ()
		{
			ASSERT_VALID (this);

			if (m_pWndInPlace == NULL)
			{
				return FALSE;
			}

			if ((COLORREF)-1 == GetColor())
			{
				SetColor(m_ColorAutomatic);
			}
			/*   // SBJ 08.02.08 The rest of this is only necessary if we 
			let the user edit rgb value directly, WHICH WE DON'T!!!

			ASSERT_VALID (m_pWndInPlace);
			ASSERT (::IsWindow (m_pWndInPlace->GetSafeHwnd ()));

			CString strText;
			m_pWndInPlace->GetWindowText (strText);

			COLORREF colorCurr = m_Color;
			int nR = 0, nG = 0, nB = 0;

			TCHAR sz[255];
			_stscanf_s (strText, _T("%s (%2x%2x%2x)"), &sz, &nR, &nG, &nB);

			m_Color = RGB (nR, nG, nB);

			if (colorCurr != m_Color)
			{
			m_pWndList->OnPropertyChanged (this);
			}
			*/
			return TRUE;
		}

		virtual CString FormatProperty ()
		{
			CString sRslt;
			CString sName(Colors::GetName(m_Color));
			if (0 == sName.Compare(_T("Custom")))
			{
				sRslt.Format (_T("%s (%d, %d, %d)"), sName, 
					GetRValue (m_Color), GetGValue (m_Color), GetBValue (m_Color));
			}
			else
			{
				sRslt = sName;
			}

			return sRslt;
		}

		virtual BOOL OnEdit (LPPOINT lptClick)
		{
			lptClick;
			m_pWndInPlace = NULL;

			CRect rectEdit;
			CRect rectSpin;

			AdjustInPlaceEditRect (rectEdit, rectSpin);

			CMFCMaskedEdit* pWndEdit = new CMFCMaskedEdit;
			DWORD dwStyle = WS_VISIBLE | WS_CHILD | ES_READONLY;

			pWndEdit->Create (dwStyle, rectEdit, m_pWndList, AFX_PROPLIST_ID_INPLACE);
			m_pWndInPlace = pWndEdit;

			m_pWndInPlace->SetWindowText (FormatProperty ());
			m_pWndInPlace->SetFont (m_pWndList->GetFont ());
			m_pWndInPlace->HideCaret ();

			m_pWndInPlace->SetFocus ();

			m_bInPlaceEdit = TRUE;
			return TRUE;
		}
		
		static COLORREF VariantToCOLORREF(const COleVariant& varValue)
		{
			COleVariant v(varValue);
			v.ChangeType(VT_I4);
			return (COLORREF)v.ulVal;
		}

		virtual void SetValue(const COleVariant& varValue)
		{
			COleVariant v(varValue);
			v.ChangeType(VT_I4);
			SetColor((COLORREF)v.ulVal);
		}
	};
}

///////////////////////////////////////////////////////////////////////////

namespace SbjCore
{
	namespace Mvc
	{
		namespace PropGrid
		{
			IMPLEMENT_DYNCREATE(PropFactory, CObject)

				PropFactory::PropFactory()
			{
			}

			PropFactory::~PropFactory(void)
			{
			}

			CMFCPropertyGridProperty* PropFactory::CreateProp(LPCTSTR lpszAttrName, int nAttrIndex, COleVariant val)
			{
				return OnCreateProp(lpszAttrName, nAttrIndex, val);
			}

			CMFCPropertyGridProperty* PropFactory::OnCreateProp(LPCTSTR lpszAttrName, int nAttrIndex, COleVariant val)
			{
				SbjCore::Mvc::Model::Controller* pModelCtrlr = SbjCore::Mvc::Model::GetCurController();
				CString sPropTitle(pModelCtrlr->CookAttrName(lpszAttrName));
				DWORD_PTR dw = (DWORD_PTR)nAttrIndex;
				CMFCPropertyGridProperty* pProp = new CMFCPropertyGridProperty(sPropTitle, val, NULL, dw);
				return pProp;
			}

			///////////////////////////////////////////////////////////////

			IMPLEMENT_DYNCREATE(ColorPropFactory, PropFactory)

			ColorPropFactory::ColorPropFactory()
			{
			}

			ColorPropFactory::~ColorPropFactory(void)
			{
			}

			CMFCPropertyGridProperty* ColorPropFactory::OnCreateProp(LPCTSTR lpszAttrName, int nAttrIndex, COleVariant val)
			{
				SbjCore::Mvc::Model::Controller* pModelCtrlr = SbjCore::Mvc::Model::GetCurController();
				CString sPropTitle(pModelCtrlr->CookAttrName(lpszAttrName));
				DWORD_PTR dw = (DWORD_PTR)nAttrIndex;
				localNS::ColorProp* pProp = new localNS::ColorProp(sPropTitle, ColorProp::VariantToCOLORREF(val), NULL, NULL, dw);
				pProp->EnableOtherButton (_T("Other..."));
				return pProp;
			}
		}
	}
}




//*** Modification History ***
// $Log: /SbjDev/SbjCore/PropFactories.cpp $
// 
// 2     11/12/08 2:22p Steve
// Finished Generalization of Model  v2.0.1
// 
// 1     10/29/08 3:36p Steve
// 
// 3     10/24/08 9:03a Steve

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

SBJ
United States United States
No Biography provided

You may also be interested in...

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.181112.3 | Last Updated 20 Mar 2009
Article Copyright 2008 by SBJ
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid