553 lines
12 KiB
C++
553 lines
12 KiB
C++
// ==========================================================================
|
|
// Class Implementation
|
|
// COXHistoryCtrl
|
|
// ==========================================================================
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "OXHistoryCtrl.h"
|
|
|
|
#include <afxdisp.h>
|
|
|
|
// default maximum number of history entries displayed in the control window
|
|
const int OXHISTCTRL_MAXENTRIES=100;
|
|
|
|
|
|
IMPLEMENT_DYNCREATE(COXHistoryCtrl, COXScrollWnd)
|
|
|
|
BEGIN_MESSAGE_MAP(COXHistoryCtrl, COXScrollWnd)
|
|
//{{AFX_MSG_MAP(COXHistoryCtrl)
|
|
ON_WM_PAINT()
|
|
ON_WM_ERASEBKGND()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
COXHistoryCtrl::COXHistoryCtrl()
|
|
{
|
|
//setup the critical section variable
|
|
InitializeCriticalSection(&m_criticalSection);
|
|
|
|
//logging variables
|
|
m_sLogFileName=_T("");
|
|
m_bEnableLog=FALSE;
|
|
m_bTimeStampedLog=FALSE;
|
|
m_logDay=0;
|
|
m_logMonth=0;
|
|
m_logYear=0;
|
|
m_bTruncateLogFile=FALSE;
|
|
|
|
//display properties
|
|
m_clrText=::GetSysColor(COLOR_WINDOWTEXT);
|
|
m_clrBack=::GetSysColor(COLOR_WINDOW);
|
|
m_clrLeftOverBack=::GetSysColor(COLOR_WINDOW);
|
|
m_nAlignment=DT_LEFT;
|
|
m_nOffset=0;
|
|
|
|
m_sizeSymbol=CSize(0,0);
|
|
|
|
//max number of entries
|
|
m_nMaxNumEntries=OXHISTCTRL_MAXENTRIES;
|
|
|
|
//max line length
|
|
m_nMaxLengthEntry=0;
|
|
|
|
//datestamp to string format
|
|
SetTimeStampFormat(_T("%X"));
|
|
}
|
|
|
|
COXHistoryCtrl::~COXHistoryCtrl()
|
|
{
|
|
CloseLog();
|
|
|
|
m_arrEntries.RemoveAll();
|
|
|
|
//release the critical section
|
|
DeleteCriticalSection(&m_criticalSection);
|
|
}
|
|
|
|
|
|
void COXHistoryCtrl::EnableLog(BOOL bYesNo)
|
|
{
|
|
m_bEnableLog=bYesNo;
|
|
if(m_bEnableLog)
|
|
OpenLog();
|
|
else
|
|
CloseLog();
|
|
}
|
|
|
|
|
|
BOOL COXHistoryCtrl::AddLine(CString string, BOOL bAddToLog/*=TRUE*/)
|
|
{
|
|
//enter into a critical section
|
|
EnterCriticalSection(&m_criticalSection);
|
|
|
|
//update the log file
|
|
if(bAddToLog && m_bEnableLog)
|
|
WriteToLog(string,TRUE);
|
|
|
|
BOOL bUpdateScroll=FALSE;
|
|
|
|
ASSERT(m_arrEntries.GetCount()<=GetMaxNumEntries());
|
|
|
|
HISTORYENTRY entry(string,m_clrText,m_clrBack,m_nOffset,m_nAlignment);
|
|
m_arrEntries.AddTail(entry);
|
|
|
|
if(m_arrEntries.GetCount()==GetMaxNumEntries()+1)
|
|
{
|
|
entry=m_arrEntries.RemoveHead();
|
|
ASSERT(entry.m_sText.GetLength()<=m_nMaxLengthEntry);
|
|
if(entry.m_sText.GetLength()==m_nMaxLengthEntry)
|
|
{
|
|
UpdateMaxLengthInfo();
|
|
bUpdateScroll=TRUE;
|
|
}
|
|
}
|
|
else
|
|
bUpdateScroll=TRUE;
|
|
|
|
int nLength=string.GetLength();
|
|
if(m_nMaxLengthEntry<nLength)
|
|
{
|
|
m_nMaxLengthEntry=nLength;
|
|
bUpdateScroll=TRUE;
|
|
}
|
|
|
|
if(bUpdateScroll)
|
|
UpdateScrollInfo();
|
|
|
|
ScrollToEnd();
|
|
RedrawWindow();
|
|
|
|
//exit the critical section
|
|
LeaveCriticalSection(&m_criticalSection);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXHistoryCtrl::AddStampedLine(CString string,
|
|
BOOL bAddToLog/*=TRUE*/)
|
|
{
|
|
CString sStampedString=GetTimeDateStamp()+_T(" ")+string;
|
|
BOOL bReturn=AddLine(sStampedString,bAddToLog);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL COXHistoryCtrl::AppendToLine(CString string,
|
|
BOOL bAddToLog/*=TRUE*/)
|
|
{
|
|
//enter into a critical section
|
|
EnterCriticalSection(&m_criticalSection);
|
|
|
|
if(m_arrEntries.IsEmpty())
|
|
return FALSE;
|
|
|
|
//update the log file
|
|
if(bAddToLog && m_bEnableLog)
|
|
WriteToLog(string,FALSE);
|
|
|
|
HISTORYENTRY entry=m_arrEntries.GetTail();
|
|
entry.m_sText+=string;
|
|
m_arrEntries.SetAt(m_arrEntries.GetTailPosition(),entry);
|
|
|
|
int nLength=entry.m_sText.GetLength();
|
|
if(m_nMaxLengthEntry<nLength)
|
|
{
|
|
m_nMaxLengthEntry=nLength;
|
|
UpdateScrollInfo();
|
|
}
|
|
|
|
ScrollToEnd();
|
|
RedrawWindow();
|
|
|
|
//exit the critical section
|
|
LeaveCriticalSection(&m_criticalSection);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL COXHistoryCtrl::ClearHistory()
|
|
{
|
|
//enter into a critical section
|
|
EnterCriticalSection(&m_criticalSection);
|
|
|
|
m_arrEntries.RemoveAll();
|
|
|
|
//max line length
|
|
m_nMaxLengthEntry=0;
|
|
|
|
UpdateScrollInfo();
|
|
RedrawWindow();
|
|
|
|
//exit the critical section
|
|
LeaveCriticalSection(&m_criticalSection);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
CString COXHistoryCtrl::GetTimeDateStamp() const
|
|
{
|
|
//get the time/date
|
|
COleDateTime time=COleDateTime::GetCurrentTime();
|
|
return time.Format(GetTimeStampFormat());
|
|
}
|
|
|
|
|
|
int COXHistoryCtrl::OpenLog()
|
|
{
|
|
CloseLog();
|
|
|
|
CString sFileName=m_sLogFileName;
|
|
if(m_bTimeStampedLog)
|
|
{
|
|
//get the time/date
|
|
COleDateTime date=COleDateTime::GetCurrentTime();
|
|
m_logDay=date.GetDay();
|
|
m_logMonth=date.GetMonth();
|
|
m_logYear=date.GetYear();
|
|
CString sStampedLogFileName;
|
|
sStampedLogFileName.Format(_T("%2.2d%2.2d%4.4d"),
|
|
m_logDay,m_logMonth,m_logYear);
|
|
|
|
//find the extension
|
|
int nPos=m_sLogFileName.Find(_T("."));
|
|
if(nPos!=-1)
|
|
sStampedLogFileName+=m_sLogFileName.Mid(nPos);
|
|
m_sTimeStampedLogFileName=sFileName=sStampedLogFileName;
|
|
}
|
|
|
|
BOOL bResult=m_fileLog.Open(sFileName,CFile::modeCreate|CFile::modeWrite|
|
|
(GetTruncateLogFile() ? 0 : CFile::modeNoTruncate));
|
|
if(bResult && !GetTruncateLogFile())
|
|
m_fileLog.SeekToEnd();
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL COXHistoryCtrl::CloseLog()
|
|
{
|
|
if(m_fileLog.m_hFile!=CFile::hFileNull)
|
|
{
|
|
TRY
|
|
{
|
|
m_fileLog.Close();
|
|
}
|
|
CATCH(CFileException,pException)
|
|
{
|
|
UNREFERENCED_PARAMETER(pException);
|
|
return FALSE;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXHistoryCtrl::WriteToLog(CString string, BOOL bNewLine)
|
|
{
|
|
if(!m_bEnableLog)
|
|
return;
|
|
|
|
COleDateTime date=COleDateTime::GetCurrentTime();
|
|
//check to see if the date has changed
|
|
if(m_bTimeStampedLog)
|
|
{
|
|
if(m_logDay!=date.GetDay() || m_logMonth!=date.GetMonth() ||
|
|
m_logYear!=date.GetYear())
|
|
{
|
|
OpenLog();
|
|
}
|
|
else if(m_logDay==date.GetDay() || m_logMonth!=date.GetMonth() ||
|
|
m_logYear!=date.GetYear())
|
|
{
|
|
if(bNewLine && m_fileLog.m_hFile != CFile::hFileNull)
|
|
m_fileLog.Write(_T("\r\n"),2*sizeof(TCHAR));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_fileLog.m_hFile == CFile::hFileNull)
|
|
{
|
|
OpenLog();
|
|
}
|
|
else
|
|
{
|
|
if(bNewLine && m_fileLog.m_hFile != CFile::hFileNull)
|
|
m_fileLog.Write(_T("\r\n"),2*sizeof(TCHAR));
|
|
}
|
|
}
|
|
|
|
if(m_fileLog.m_hFile != CFile::hFileNull)
|
|
m_fileLog.Write(string,string.GetLength()*sizeof(TCHAR));
|
|
}
|
|
|
|
|
|
void COXHistoryCtrl::SetMaxNumEntries(int nMaxNum)
|
|
{
|
|
if(nMaxNum<0)
|
|
return;
|
|
|
|
BOOL bUpdateScroll=FALSE;
|
|
|
|
if(nMaxNum<GetMaxNumEntries())
|
|
{
|
|
int nEntriesToDelete=GetNumEntries()-nMaxNum;
|
|
HISTORYENTRY entry;
|
|
for(int nIndex=0; nIndex<nEntriesToDelete; nIndex++)
|
|
{
|
|
entry=m_arrEntries.RemoveHead();
|
|
ASSERT(entry.m_sText.GetLength()<=m_nMaxLengthEntry);
|
|
if(entry.m_sText.GetLength()==m_nMaxLengthEntry)
|
|
{
|
|
UpdateMaxLengthInfo();
|
|
}
|
|
}
|
|
bUpdateScroll=TRUE;
|
|
}
|
|
|
|
m_nMaxNumEntries=nMaxNum;
|
|
|
|
if(bUpdateScroll)
|
|
UpdateScrollInfo();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
void COXHistoryCtrl::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
// TODO: Add your message handler code here
|
|
|
|
OnPrepareDC(&dc);
|
|
|
|
int nSavedDC=dc.SaveDC();
|
|
ASSERT(nSavedDC!=0);
|
|
|
|
ASSERT((HFONT)m_font!=NULL);
|
|
dc.SelectObject(&m_font);
|
|
|
|
//start from the bottom of the rect and work up
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
CSize sizeTotal=GetTotalSize();
|
|
if(sizeTotal.cx>rect.Width())
|
|
rect.right=rect.left+sizeTotal.cx;
|
|
if(sizeTotal.cy>rect.Height())
|
|
rect.bottom=rect.top+sizeTotal.cy;
|
|
|
|
CRect rectCopy=rect;
|
|
|
|
|
|
HISTORYENTRY entry;
|
|
POSITION pos=m_arrEntries.GetHeadPosition();
|
|
|
|
int nEntries=GetNumEntries();
|
|
rectCopy.top =0;
|
|
rectCopy.bottom =0;
|
|
for(int nIndex=0; nIndex<nEntries; nIndex++)
|
|
{
|
|
if(pos!=NULL)
|
|
{
|
|
entry=m_arrEntries.GetNext(pos);
|
|
rectCopy.bottom+=m_sizeSymbol.cy;
|
|
|
|
dc.SetTextColor(entry.m_clrText);
|
|
dc.SetBkMode(TRANSPARENT);
|
|
CRect rectItem=rectCopy;
|
|
CBrush brush(entry.m_clrBack);
|
|
dc.FillRect(rectItem,&brush);
|
|
rectItem.left+=entry.m_nOffset;
|
|
dc.DrawText(entry.m_sText,rectItem,
|
|
DT_SINGLELINE|DT_VCENTER|entry.m_nAlignment);
|
|
|
|
rectCopy.top=rectCopy.bottom;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
if(rectCopy.bottom<rect.bottom)
|
|
{
|
|
rectCopy.bottom=rect.bottom;
|
|
dc.FillSolidRect(rectCopy,m_clrLeftOverBack);
|
|
}
|
|
|
|
VERIFY(dc.RestoreDC(nSavedDC));
|
|
|
|
// Do not call COXScrollWnd::OnPaint() for painting messages
|
|
}
|
|
|
|
BOOL COXHistoryCtrl::Initialize()
|
|
{
|
|
if(!COXScrollWnd::Initialize())
|
|
return FALSE;
|
|
|
|
#ifdef OXSCRLWND_USE_RULER
|
|
DetachRuler();
|
|
#endif // OXSCRLWND_USE_RULER
|
|
|
|
SetScrollSizes(MM_TEXT,CSize(0,0),CSize(0,0),CSize(0,0));
|
|
|
|
// Create a fixed size font
|
|
CFont font;
|
|
font.CreateFont( 0, // nHeight
|
|
0, // nWidth
|
|
0, // nEscapement
|
|
0, // nOrientation
|
|
FW_DONTCARE, // nWeight
|
|
FALSE, // bItalic
|
|
FALSE, // bUnderline
|
|
0, // cStrikeOut
|
|
DEFAULT_CHARSET, // nCharSet
|
|
OUT_DEFAULT_PRECIS, // nOutPrecision
|
|
CLIP_DEFAULT_PRECIS, // nClipPrecision
|
|
DEFAULT_QUALITY, // nQuality
|
|
FIXED_PITCH, // nPitchAndFamily
|
|
NULL); // lpszFacename
|
|
|
|
SetFont(&font, FALSE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXHistoryCtrl::SetFont(CFont* pFont, BOOL bRedraw/*=TRUE*/)
|
|
{
|
|
ASSERT(pFont!=NULL);
|
|
ASSERT((HFONT)*pFont!=NULL);
|
|
|
|
if((HFONT)m_font!=NULL)
|
|
m_font.DeleteObject();
|
|
|
|
LOGFONT lf;
|
|
VERIFY(pFont->GetLogFont(&lf)!=0);
|
|
VERIFY(m_font.CreateFontIndirect(&lf));
|
|
|
|
UpdateFontInfo();
|
|
UpdateScrollInfo();
|
|
|
|
if(bRedraw)
|
|
RedrawWindow();
|
|
}
|
|
|
|
BOOL COXHistoryCtrl::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
UNREFERENCED_PARAMETER(pDC);
|
|
return TRUE;
|
|
}
|
|
|
|
void COXHistoryCtrl::UpdateFontInfo()
|
|
{
|
|
//get the symbol height and width
|
|
CDC* pDC=GetDC();
|
|
ASSERT_VALID(pDC);
|
|
|
|
CFont* pOldFont=pDC->SelectObject(&m_font);
|
|
|
|
::GetTextExtentPoint(pDC->GetSafeHdc(),_T("X"),1,&m_sizeSymbol);
|
|
|
|
if(pOldFont!=NULL)
|
|
{
|
|
pDC->SelectObject(pOldFont);
|
|
}
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
|
|
void COXHistoryCtrl::UpdateScrollInfo()
|
|
{
|
|
// CPoint ptCurrent=GetDeviceScrollPosition();
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
CSize sizeTotal(m_nMaxLengthEntry*m_sizeSymbol.cx,
|
|
GetNumEntries()*m_sizeSymbol.cy+rect.Height()%m_sizeSymbol.cy);
|
|
CSize sizePage(m_sizeSymbol.cx,m_sizeSymbol.cy);
|
|
if(m_sizeSymbol.cx<rect.Width())
|
|
{
|
|
sizePage.cx=(rect.Width()/m_sizeSymbol.cx)*m_sizeSymbol.cx;
|
|
}
|
|
if(m_sizeSymbol.cy<rect.Height())
|
|
{
|
|
sizePage.cy=(rect.Height()/m_sizeSymbol.cy)*m_sizeSymbol.cy;
|
|
}
|
|
CSize sizeLine=m_sizeSymbol;
|
|
|
|
SetScrollSizes(MM_TEXT,sizeTotal,sizePage,sizeLine);
|
|
|
|
// ScrollToDevicePosition(ptCurrent);
|
|
}
|
|
|
|
void COXHistoryCtrl::UpdateMaxLengthInfo()
|
|
{
|
|
m_nMaxLengthEntry=0;
|
|
HISTORYENTRY entry;
|
|
POSITION pos=m_arrEntries.GetHeadPosition();
|
|
while(pos!=NULL)
|
|
{
|
|
entry=m_arrEntries.GetNext(pos);
|
|
int nLength=entry.m_sText.GetLength();
|
|
if(m_nMaxLengthEntry<nLength)
|
|
{
|
|
m_nMaxLengthEntry=nLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
int COXHistoryCtrl::GetVisibleCount()
|
|
{
|
|
ASSERT(::IsWindow(GetSafeHwnd()));
|
|
|
|
CRect rect;
|
|
GetClientRect(rect);
|
|
|
|
int nResult=rect.Height()/m_sizeSymbol.cy;
|
|
nResult=(nResult>GetNumEntries() ? GetNumEntries() : nResult);
|
|
|
|
return nResult;
|
|
}
|
|
|
|
|
|
void COXHistoryCtrl::ScrollToEnd()
|
|
{
|
|
CPoint ptScroll=GetScrollPosition();
|
|
ptScroll.y=GetNumEntries()*m_sizeSymbol.cy;
|
|
ScrollToPosition(ptScroll);
|
|
}
|
|
|
|
|
|
|
|
CString COXHistoryCtrl::GetTimeStampedFileName()
|
|
{
|
|
COleDateTime date=COleDateTime::GetCurrentTime();
|
|
int logDay=date.GetDay();
|
|
int logMonth=date.GetMonth();
|
|
int logYear=date.GetYear();
|
|
m_sTimeStampedLogFileName.Format(_T("%2.2d%2.2d%4.4d"),
|
|
logDay,logMonth,logYear);
|
|
|
|
//find the extension
|
|
int nPos=m_sLogFileName.Find(_T("."));
|
|
if(nPos!=-1)
|
|
m_sTimeStampedLogFileName+=m_sLogFileName.Mid(nPos);
|
|
return m_sTimeStampedLogFileName;
|
|
}
|