|
|
#include "stdafx.h"
#include "source.h"
#include "lcsource.h"
#include "regkey.h"
#include "source.h"
#include "utils.h"
#include "globals.h"
#include "busy.h"
#include "trapreg.h"
/////////////////////////////////////////////////////////////////////////////
// CLcSource
CLcSource::CLcSource() { }
CLcSource::~CLcSource() { }
//***************************************************************************
//
// CLcSource::AddMessage
//
// Add a message to the list control. This sets the text for each column in
// the list view and sets the lParam field of the list-view item to pMessage.
//
//
// Parameters:
// CMessage* pMessage
//
// Returns:
// Nothing.
//
// Status:
//
//***************************************************************************
void CLcSource::AddMessage(CXMessage* pMessage) { CString sText; pMessage->GetShortId(sText);
// Insert a new item into this list control.
LV_ITEM lvitem; lvitem.mask = LVIF_TEXT | LVIF_PARAM; lvitem.iSubItem = ICOL_LcSource_EVENTID; lvitem.cchTextMax = MAX_STRING; lvitem.lParam = (LPARAM)pMessage; lvitem.pszText = (LPTSTR)(LPCTSTR)sText; int nItem = InsertItem(&lvitem);
if (nItem >= 0) { CXEventSource* pEventSource = pMessage->m_pEventSource;
// Now set the string value for each sub-item.
pMessage->GetSeverity(sText); SetItemText(nItem, ICOL_LcSource_SEVERITY, (LPTSTR)(LPCTSTR) sText);
pMessage->IsTrapping(sText); SetItemText(nItem, ICOL_LcSource_TRAPPING, (LPTSTR)(LPCTSTR)sText); SetItemText(nItem, ICOL_LcSource_DESCRIPTION, (LPTSTR)(LPCTSTR) pMessage->m_sText); } }
//*******************************************************************
// CXMessageArray::SetDescriptionWidth
//
// Set the width of the description field so that it is wide enough to
// hold the widest message.
//
// Parameters:
// CXMessageArray& aMessages
// The message array that will be used to fill the list control.
//
// Returns:
// Nothing.
//
//*******************************************************************
void CLcSource::SetDescriptionWidth(CXMessageArray& aMessages) { LONG cxWidestMessage = CX_DEFAULT_DESCRIPTION_WIDTH; LONG nMessages = aMessages.GetSize(); for (LONG iMessage = 0; iMessage < nMessages; ++iMessage) { CXMessage* pMessage = aMessages[iMessage]; int cx = GetStringWidth(pMessage->m_sText); if (cx > cxWidestMessage) { cxWidestMessage = cx; } }
// Set the column width to the width of the widest string plus a little extra
// space for slop and to make it obvious to the user that the complete string
// is displayed.
SetColumnWidth(ICOL_LcSource_DESCRIPTION, cxWidestMessage + CX_DESCRIPTION_SLOP); }
//***************************************************************************
//
// CLcSource::LoadMessages
//
// Load the messages from the message library module and insert them into
// this list control.
//
// Parameters:
// CMessage* pMessage
//
// Returns:
// Nothing.
//
// Status:
//
//***************************************************************************
SCODE CLcSource::SetEventSource(CXEventSource* pEventSource) { CBusy busy;
DeleteAllItems();
if (pEventSource == NULL) { return S_OK; }
UpdateWindow(); //!!!CR: Should do something with the return code in case the
//!!!CR: messages weren't loaded.
SCODE sc = pEventSource->LoadMessages();
// Iterate through each of the messages and insert them into
// the list control.
CXMessageArray& aMessages = pEventSource->m_aMessages;
// Set the width of the description field so that it is wide enough to contain
// the widest message.
SetDescriptionWidth(aMessages);
LONG nMessages = aMessages.GetSize(); for (LONG iMessage=0; iMessage < nMessages; ++iMessage) { if ((iMessage < 40 && (iMessage % 10 == 9)) || (iMessage % 100 == 99)) { // Update the window often for the first few messages and less frequently
// thereafter for a good response time.
UpdateWindow(); }
AddMessage(aMessages[iMessage]); }
SortItems(ICOL_LcSource_EVENTID); SetRedraw(TRUE); UpdateWindow(); EnsureVisible(0, FALSE);
if (GetSize()) SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
return S_OK; }
BEGIN_MESSAGE_MAP(CLcSource, CListCtrl) //{{AFX_MSG_MAP(CLcSource)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLcSource message handlers
//***************************************************************************
//
// CLcSource::CreateWindowEpilogue()
//
// This method is called after a window has been created for this list
// control. Final initialization is done here.
//
// Parameters:
// None.
//
// Returns:
// SCODE
// S_OK if the initialization was successful, otherwise E_FAIL.
//
// Status:
//
//***************************************************************************
SCODE CLcSource::CreateWindowEpilogue() { ListView_SetExtendedListViewStyle(m_hWnd, LVS_EX_FULLROWSELECT); SetColumnHeadings(); return S_OK; }
//***************************************************************************
//
// CLcSource::SetColumnHeadings
//
// Define's the columns for this list control. The column title, width, and
// order is defined here.
//
// Parameters:
// None.
//
// Returns:
// Nothing.
//
// Status:
//
//***************************************************************************
void CLcSource::SetColumnHeadings() { static UINT auiResColumnTitle[ICOL_LcSource_MAX] = { IDS_LcSource_TITLE_EVENT_ID, IDS_LcSource_TITLE_SEVERITY, IDS_LcSource_TITLE_TRAPPING, IDS_LcSource_TITLE_DESCRIPTION };
static int aiColWidth[ICOL_LcSource_MAX] = {60, 75, 60, CX_DEFAULT_DESCRIPTION_WIDTH};
// Build the columns in the AllEventsList control.
LV_COLUMN lvcol; lvcol.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; for (int iCol=0; iCol<ICOL_LcSource_MAX; ++iCol) { CString sColTitle; sColTitle.LoadString(auiResColumnTitle[iCol]);
lvcol.pszText = sColTitle.GetBuffer(sColTitle.GetLength()); lvcol.iSubItem = iCol; lvcol.cx = aiColWidth[iCol]; InsertColumn(iCol, &lvcol); sColTitle.ReleaseBuffer(); } }
//******************************************************************
// CLcSource::Find
//
// Find the specified event source in this list control.
//
// Parameters:
// CString& sText
// A string containing the text to search for.
//
// BOOL bWholeWord
// TRUE if this is a "whole word" search. False if it
// is OK to match a partial word.
//
// BOOL bMatchCase
// TRUE if a case-sensitive comparison should be used.
//
// Returns:
// BOOL
// TRUE if the string was found, FALSE otherwise. If the specified
// text is found, then the selection is set on the corresponding
// list control item, the item is scrolled into view and the focus
// is set on the item.
//
//******************************************************************
BOOL CLcSource::Find(CString sText, BOOL bWholeWord, BOOL bMatchCase) { // Don't do anything if the list is empty.
if (GetSize() == 0) return FALSE;
if (!bMatchCase) sText.MakeUpper();
// Get the selected item.
LONG iItem = GetNextItem(-1, LVNI_SELECTED);
// Nothing selected; start from the top of the list.
if (iItem == -1) iItem = 0;
// Iterate through all of the items starting at one item past
// the currently selected item.
CXMessage* pMessage; CString sDescription; BOOL bFound = FALSE; LONG nItems = GetSize(); LONG iItemStart = iItem; for (long i=0; !bFound && i<nItems; ++i) { // Bump the item index to the next one and wrap it if its past the
// last item.
iItem = (iItem + 1) % nItems;
// Get the message description for this item.
pMessage = GetAt(iItem); sDescription = pMessage->m_sText;
if (!bMatchCase) sDescription.MakeUpper(); if (bWholeWord) { // Compare the whole word.
bFound = (FindWholeWord(sText, sDescription) != -1); } else { // Look for a substring.
if (sDescription.Find(sText) >= 0) bFound = TRUE; } }
// Found a match.
if (bFound) { // Unselect the selected item and select the found item.
SetItemState(iItemStart, 0, LVIS_SELECTED | LVIS_FOCUSED); SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); EnsureVisible(iItem, FALSE); return TRUE; }
return FALSE; }
//***************************************************************************
//
// fnCompareCLcSource
//
// This the item comparison callback method that is called from CLcSource::SortItems.
//
// Parameters:
// LPARAM lParam1
// This is the lparam for the first item to compare. This is a pointer to
// the associated CMessage object.
//
// LPARAM lParam2
// This is the lparam for the second item to compare. This is a pointer to
// the associated CMessage object.
//
// LPARAM lColumn
// This is the second parameter that was passed to CListCtrl::SortItems. This
// happens to be the list control column index.
//
// Returns:
// Nothing.
//
// Status:
//
//***************************************************************************
int CALLBACK fnCompareCLcSource(LPARAM lParam1, LPARAM lParam2, LPARAM lColumn) { // !!!CR: The LPARAM parameters are not event pointers in all cases because
// !!!CR: each subitem has its own LPARAM. What should I do?
CXMessage *pmsg1 = (CXMessage *)lParam1; CXMessage *pmsg2 = (CXMessage *)lParam2;
int nResult = 0; CString s1, s2;
if (pmsg1 && pmsg2) { switch( lColumn) { case ICOL_LcSource_EVENTID: nResult = ((LONG) pmsg1->GetShortId()) - ((LONG)pmsg2->GetShortId()); break; case ICOL_LcSource_SEVERITY: pmsg1->GetSeverity(s1); pmsg2->GetSeverity(s2); nResult = lstrcmpi(s1, s2); break; case ICOL_LcSource_TRAPPING: pmsg1->IsTrapping(s1); pmsg2->IsTrapping(s2); nResult = lstrcmpi(s1, s2); break; case ICOL_LcSource_DESCRIPTION: nResult = lstrcmpi(pmsg1->m_sText, pmsg2->m_sText); break; default: ASSERT(FALSE); nResult = 0; break; } }
if (!g_abLcSourceSortAscending[lColumn]) { if (nResult > 0) { nResult = -1; } else if (nResult < 0) { nResult = 1; } }
return(nResult); }
//***************************************************************************
//
// CLcSource::SortItems
//
// Sort the items in this list control given the column index. This method
// hides all details about the sort implementation from this class's clients.
//
// Parameters:
// DWORD dwColumn
// The column to use as the sort key.
//
// Returns:
// Nothing.
//
// Status:
//
//***************************************************************************
void CLcSource::SortItems(DWORD dwColumn) { CListCtrl::SortItems(fnCompareCLcSource, dwColumn); }
//***************************************************************************
//
// CLcSource::GetSelectedMessages
//
// Fill a message array with pointers to the messages that correspond to
// the selected items in this list control.
//
// Note: This list control continues to own the returned pointers. The
// caller should not delete them.
//
// Parameters:
// CMessageArray& amsg
// The message array where the pointers to the selected messages are
// returned.
//
// Returns:
// The message array is filled with pointers to the selected messages. Do
// not delete them, because they are owned by this object.
//
// Status:
//
//***************************************************************************
void CLcSource::GetSelectedMessages(CXMessageArray& amsg) { // Clear the message array
amsg.RemoveAll();
// Setup the LV_ITEM structure to retrieve the lparam field.
// This field contains the CMessage pointer.
LV_ITEM lvitem; lvitem.mask = LVIF_PARAM; lvitem.iSubItem = ICOL_LcSource_EVENTID;
// Loop to find all the selected items.
int nItem = -1; while (TRUE) { nItem = GetNextItem(nItem, LVNI_SELECTED); if (nItem == -1) { break; }
// Get the CMessage pointer for this item and add it to the
// array.
lvitem.iItem = nItem; GetItem(&lvitem); CXMessage* pmsg = (CXMessage*) (void*) lvitem.lParam; amsg.Add(pmsg); } }
//***************************************************************************
//
// CLcSource::FindItem
//
// Search through this list-controls's items to find the one with the
// specified message ID.
//
// Parameters:
// DWORD dwMessageId
// The message ID to search for.
//
// Returns:
// The index of the item with the specified message ID. If no such message ID
// was found, -1 is returned.
//
// Status:
//
//***************************************************************************
LONG CLcSource::FindItem(DWORD dwMessageId) { LONG nItems = GetItemCount(); for (LONG iItem = 0; iItem < nItems; ++iItem) { CXMessage* pMessage = GetAt(iItem); if (pMessage->m_dwId == dwMessageId) { return iItem; } } return -1; }
//***************************************************************************
//
// CLcSource::RefreshItem
//
// This method is called when some aspect of the message has changed and
// the display needs to be updated. This occurs when the trapping status
// of an event changes.
//
// Parameters:
// DWORD dwMessageId
// The message ID to search for.
//
// Returns:
// The index of the item with the specified message ID. If no such message ID
// was found, -1 is returned.
//
// Status:
//
//***************************************************************************
void CLcSource::RefreshItem(LONG iItem) { CXMessage* pMessage = GetAt(iItem); CString sText;
// Now set the text value for each column in the list control.
pMessage->GetSeverity(sText); SetItemText(iItem, ICOL_LcSource_SEVERITY, (LPTSTR)(LPCTSTR) sText);
// Check if we are trapping this event.
pMessage->IsTrapping(sText); SetItemText(iItem, ICOL_LcSource_TRAPPING, (LPTSTR)(LPCTSTR)sText);
SetItemText(iItem, ICOL_LcSource_DESCRIPTION, (LPTSTR)(LPCTSTR)pMessage->m_sText); }
//***************************************************************************
//
// CLcSource::GetAt
//
// This method returns the message pointer located at the given item index.
// This allows CLcSource to be used much as an array.
//
// Parameters:
// LONG iItem
// The item index.
//
// Returns:
// A pointer to the CMessage stored at the specified index.
//
// Status:
//
//***************************************************************************
CXMessage* CLcSource::GetAt(LONG iItem) { // Setup the LV_ITEM structure to retrieve the lparam field.
// This field contains the CMessage pointer.
LV_ITEM lvitem; lvitem.mask = LVIF_PARAM; lvitem.iSubItem = ICOL_LcSource_EVENTID; lvitem.iItem = iItem; GetItem(&lvitem);
CXMessage* pMessage = (CXMessage*) (void*) lvitem.lParam; return pMessage; }
//***************************************************************************
// CLcSource::NotifyTrappingChange
//
// This method is called when a message's trapping status changes. A message
// is considered trapped if it appears in the CLcEvents listbox.
//
// Parameters:
// DWORD dwMessageId
// The ID of the message who's trapping status is changing.
//
// BOOL bIsTrapping
// TRUE if the message is being trapped, FALSE otherwise.
//
// Returns:
// Nothing.
//
//***************************************************************************
void CLcSource::NotifyTrappingChange(DWORD dwMessageId, BOOL bIsTrapping) { LONG iItem = FindItem(dwMessageId); ASSERT(iItem != -1);
if (iItem != -1) { CString sTrapping; sTrapping.LoadString(bIsTrapping ? IDS_IS_TRAPPING : IDS_NOT_TRAPPING); SetItemText(iItem, ICOL_LcSource_TRAPPING, (LPTSTR)(LPCTSTR)sTrapping); } }
|