Click here to Skip to main content
15,892,809 members
Articles / Desktop Programming / MFC

Another Enum Viewer

Rate me:
Please Sign up or sign in to vote.
4.50/5 (2 votes)
22 Oct 20015 min read 83K   1.3K   19  
An article on the usage and design of another Enum Viewer
// enum_view.cpp : implementation of the CEnumView class
//
// $Header$
//
// All of this source code is copyright (C) 2001 Tim Finer.
// You have permission to use this code in any way.  
// My only restriction is that you must not claim you wrote this code.
//

#include "stdafx.h"
#include "enum_view.h"
#include "enum_doc.h"

#include "stl_index.h"

#include "resource.h"

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


using namespace tfiner;


CEnumView::CEnumView() {
	m_sortColumn = eNONE;
	InitCache();
}


CEnumView::~CEnumView() {}


void CEnumView::InitCache() {
	m_cacheRowStart = m_cacheRowFinish = -1;
	m_strCache.clear();
	if ( GetSafeHwnd() )
		Invalidate();
}


BOOL CEnumView::PreCreateWindow(CREATESTRUCT& cs) {
	cs.style |= LVS_REPORT | LVS_OWNERDATA;
	return CListView::PreCreateWindow(cs);
}


void CEnumView::OnInitialUpdate() {
	CListView::OnInitialUpdate();

	CListCtrl& listCtrl = GetListCtrl();
	listCtrl.SetExtendedStyle( 
		LVS_EX_GRIDLINES | 
		LVS_EX_FULLROWSELECT );

	if ( !listCtrl.GetHeaderCtrl()->GetItemCount() ) {
		CString col;

		col.LoadString( IDS_NAME );
		listCtrl.InsertColumn( eNAME, col );
		int width = listCtrl.GetStringWidth( col );
		listCtrl.SetColumnWidth( eNAME, width * 4 );

		col.LoadString( IDS_VALUE );
		listCtrl.InsertColumn( eVALUE, col );
		width = listCtrl.GetStringWidth( col );
		listCtrl.SetColumnWidth( eVALUE, width * 4 );
	}

	m_viewHex = 1 == AfxGetApp()->GetProfileInt( "View", "Hex", true );

	m_font.CreateStockObject( ANSI_FIXED_FONT );
	SetFont( &m_font );
}


BOOL CEnumView::OnPreparePrinting(CPrintInfo* pInfo) {
	return DoPreparePrinting(pInfo);
}

void CEnumView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {}
void CEnumView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {}


void CEnumView::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint ) {
	CEnumDoc* pDoc			= GetDocument();
	const size_t NUM_CONSTS = pDoc->GetNumConstants();

	if ( pDoc->IsOpen() && 0 == NUM_CONSTS )
		AfxMessageBox( IDS_NO_ENUMS_FOUND );

	GetListCtrl().SetItemCountEx( NUM_CONSTS, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL );

	//default order, none
	m_rowOrder.resize( NUM_CONSTS );
	for ( size_t i = 0; i < NUM_CONSTS; ++i )
		m_rowOrder[ i ] = i;

	// parser by default returns alphabetical order for names
	m_sortColumn = eNAME;

	Invalidate();
}


void CEnumView::OnHex() {
	m_viewHex = !m_viewHex;
	AfxGetApp()->WriteProfileInt( "View", "Hex", m_viewHex );
	InitCache();
}


void CEnumView::OnUpdateHex( CCmdUI* pCmdUI ) {
	pCmdUI->SetCheck( m_viewHex );
}


void CEnumView::OnGetDispInfo( NMHDR* pNMHDR, LRESULT* pResult ) {
	LV_DISPINFO* pDispInfo = reinterpret_cast<LV_DISPINFO*>(pNMHDR);
	if ( pDispInfo->item.mask & LVIF_TEXT ) {
		const int ROW	= pDispInfo->item.iItem;
		const int COL	= pDispInfo->item.iSubItem;

		// It turns out that this condition actually happens!
		// It looks like cache msgs don't always get handled before disp info msgs.
		if ( m_cacheRowStart > ROW || ROW > m_cacheRowFinish )
			return;

		const int CACHE_ROW		= ROW - m_cacheRowStart;
		const int CACHE_SIZE	= static_cast<int>(m_strCache.size());
		if ( CACHE_ROW >= CACHE_SIZE )
			return;

		const int CACHE_COLS = static_cast<int>(m_strCache[ CACHE_ROW ].size());
		if ( COL >= CACHE_COLS )
			return;

		// Locking semantics not needed as this is the only routine to actually read the cache.
		pDispInfo->item.pszText = m_strCache[CACHE_ROW][COL].GetBuffer( 0 );
	}
	*pResult = 0;
}


// Refreshes the string cache, as necessary.
void CEnumView::OnCacheHint( NMHDR* pNMHDR, LRESULT* pResult ) {
	const NMLVCACHEHINT* pCacheHint = reinterpret_cast<NMLVCACHEHINT*>(pNMHDR);
	const size_t NUM_ROWS			= pCacheHint->iTo - pCacheHint->iFrom + 1;

	CHeaderCtrl* pHead = GetListCtrl().GetHeaderCtrl();
	ASSERT_VALID( pHead );
	if ( !pHead ) 
		return;

	const size_t NUM_COLS = pHead->GetItemCount();
	
	// resize necessary? (note that this routine only grows the cache, never trims).
	if ( m_strCache.size() < NUM_ROWS ) {

		const size_t NUM_OLD_ROWS = m_strCache.size();

		m_strCache.resize( NUM_ROWS );

		// if out of memory, bail
		if ( m_strCache.size() < NUM_ROWS )
			return;

		// resize only the new rows
		for( size_t i = NUM_OLD_ROWS; i != NUM_ROWS; ++i ) {
			m_strCache[i].resize( NUM_COLS );
			if ( m_strCache[i].size() < NUM_COLS )
				return;
		}
	}

	// new content?
	if ( m_cacheRowStart != pCacheHint->iFrom || 
		m_cacheRowFinish != pCacheHint->iTo ) {

		m_cacheRowStart		= pCacheHint->iFrom;
		m_cacheRowFinish	= pCacheHint->iTo;

		CEnumDoc* pDoc		= GetDocument();

		for ( int rowIdx = m_cacheRowStart; rowIdx <= m_cacheRowFinish; rowIdx++ ) {

			CString name;
			int value;

			const size_t REC_IDX = m_rowOrder[ rowIdx ];

			if ( !pDoc->GetConstant(REC_IDX, name, value) )
				break;

			for ( size_t cacheCol = 0; cacheCol < NUM_COLS; cacheCol++ ) {
				CString& cell = m_strCache[ rowIdx - m_cacheRowStart ][cacheCol];

				// OK to call even if GetBuffer was never called.
				cell.ReleaseBuffer( 0 );

				// NOT OK to call if LockBuffer wasn't called - also UnlockBuffer causes a memory allocation.
//				strRec.UnlockBuffer();

				if ( 0 == cacheCol )
					cell = name;
				else if ( 1 == cacheCol )
					cell.Format( m_viewHex ? "0x%08x" : "%d", value );

			}
		}
	}

	*pResult = 0;
}


void CEnumView::OnColumnClick( NMHDR* pNMHDR, LRESULT* pResult ) {
	const NMLISTVIEW* pLIST_VIEW = reinterpret_cast<NMLISTVIEW*>(pNMHDR);

	if ( -1 == pLIST_VIEW->iItem ) {

		// simple flip, no sorting or loading needed.
		if ( m_sortColumn == pLIST_VIEW->iSubItem )
			std::reverse( m_rowOrder.begin(), m_rowOrder.end() );

		// loading, sorting...
		else {
			CEnumDoc* pDoc = GetDocument();

			const size_t NUM_ROWS = m_rowOrder.size();
			std::vector< CString > names( NUM_ROWS );
			std::vector< int > values( NUM_ROWS );

			for ( size_t i = 0; i < NUM_ROWS; ++i ) {
				m_rowOrder[ i ] = i;
				VERIFY( pDoc->GetConstant( i, names[i], values[i] ) );
			}

			if ( eNAME == pLIST_VIEW->iSubItem )
				create_index( names.begin(), names.end(), m_rowOrder.begin() );

			else if ( eVALUE == pLIST_VIEW->iSubItem )
				create_index( values.begin(), values.end(), m_rowOrder.begin() );

			m_sortColumn = static_cast<eColumn>(pLIST_VIEW->iSubItem);
		}

		InitCache();
	}
}


#ifdef _DEBUG
	void CEnumView::AssertValid() const {
		CListView::AssertValid();
	}

	void CEnumView::Dump(CDumpContext& dc) const {
		CListView::Dump(dc);
	}

	CEnumDoc* CEnumView::GetDocument() {
		ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEnumDoc)));
		return (CEnumDoc*)m_pDocument;
	}
#endif //_DEBUG

IMPLEMENT_DYNCREATE(CEnumView, CListView)

BEGIN_MESSAGE_MAP(CEnumView, CListView)
	//{{AFX_MSG_MAP(CEnumView)
	ON_COMMAND(ID_HEX, OnHex)
	ON_UPDATE_COMMAND_UI(ID_HEX, OnUpdateHex)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CListView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CListView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CListView::OnFilePrintPreview)

	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetDispInfo)
	ON_NOTIFY_REFLECT(LVN_ODCACHEHINT, OnCacheHint)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
END_MESSAGE_MAP()



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
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions