#include "stdafx.h"
#include "resource.h"
#include "TipDlg.h"
// CG: This file added by 'Tip of the Day' component.
#include <winreg.h>
#include <sys\stat.h>
#include <sys\types.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTipDlg dialog
#define MAX_BUFLEN 1000
static const TCHAR szSection[] = _T("Tip");
static const TCHAR szIntFilePos[] = _T("FilePos");
static const TCHAR szTimeStamp[] = _T("TimeStamp");
static const TCHAR szIntStartup[] = _T("StartUp");
CTipDlg::CTipDlg(CWnd* pParent /*=NULL*/)
: CDialog(IDD_TIP, pParent)
{
//{{AFX_DATA_INIT(CTipDlg)
m_bStartup = TRUE;
//}}AFX_DATA_INIT
// We need to find out what the startup and file position parameters are
// If startup does not exist, we assume that the Tips on startup is checked TRUE.
CWinApp* pApp = AfxGetApp();
m_bStartup = !pApp->GetProfileInt(szSection, szIntStartup, 0);
UINT iFilePos = pApp->GetProfileInt(szSection, szIntFilePos, 0);
m_nHelpID = 0;
// look in the application directory for the tip file
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
const char *path = _pgmptr ;
_splitpath(path, drive, dir, fname, ext );
CString sPath;
sPath.Format("%s%s%s", drive, dir, "Tips.txt");
TRACE("sPath is %s\n", sPath);
// Now try to open the tips file
m_pStream = fopen(sPath, "r");
if (m_pStream == NULL)
{
m_strHeader = "Oops!";
m_strTip.LoadString(CG_IDS_FILE_ABSENT);
return;
}
// If the timestamp in the INI file is different from the timestamp of
// the tips file, then we know that the tips file has been modified
// Reset the file position to 0 and write the latest timestamp to the
// ini file
struct _stat buf;
_fstat(_fileno(m_pStream), &buf);
CString strCurrentTime = ctime(&buf.st_ctime);
strCurrentTime.TrimRight();
CString strStoredTime =
pApp->GetProfileString(szSection, szTimeStamp, NULL);
if (strCurrentTime != strStoredTime)
{
iFilePos = 0;
pApp->WriteProfileString(szSection, szTimeStamp, strCurrentTime);
}
if (fseek(m_pStream, iFilePos, SEEK_SET) != 0)
{
AfxMessageBox(CG_IDP_FILE_CORRUPT);
}
else
{
GetNextTipString();
}
}
CTipDlg::~CTipDlg()
{
// This destructor is executed whether the user had pressed the escape key
// or clicked on the close button. If the user had pressed the escape key,
// it is still required to update the filepos in the ini file with the
// latest position so that we don't repeat the tips!
// But make sure the tips file existed in the first place....
if (m_pStream != NULL)
{
CWinApp* pApp = AfxGetApp();
pApp->WriteProfileInt(szSection, szIntFilePos, ftell(m_pStream));
fclose(m_pStream);
}
}
void CTipDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTipDlg)
DDX_Check(pDX, IDC_STARTUP, m_bStartup);
DDX_Text(pDX, ST_FOOTER, m_strFooter);
DDX_Text(pDX, ST_HEADER, m_strHeader);
DDX_Text(pDX, IDC_TIPSTRING, m_strTip);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTipDlg, CDialog)
//{{AFX_MSG_MAP(CTipDlg)
ON_BN_CLICKED(IDC_NEXTTIP, OnNextTip)
ON_BN_CLICKED(IDB_MORE, OnMore)
ON_WM_CTLCOLOR()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTipDlg message handlers
void CTipDlg::OnNextTip()
{
GetNextTipString();
// if the Help ID is 0, disable the Help button
GetDlgItem(IDB_MORE)->EnableWindow(m_nHelpID != 0);
UpdateData(FALSE);
}
// function to get a text string from the file
// the first half is mostly straight from the MFC component code
// it is followed by parsing of the string into its different
// components based on tab characters
// NOTE that I did remove the parameter that was passed to this
// function to recieve the string, and made the string a class member
void CTipDlg::GetNextTipString()
{
LPTSTR lpsz = m_strFileLine.GetBuffer(MAX_BUFLEN);
// This routine identifies the next string that needs to be
// read from the tips file
BOOL bStop = FALSE;
while (!bStop)
{
// reads up until the next newline character
if (_fgetts(lpsz, MAX_BUFLEN, m_pStream) == NULL)
{
// We have either reached EOF or enocuntered some problem
// In both cases reset the pointer to the beginning of the file
// This behavior is same as VC++ Tips file
if (fseek(m_pStream, 0, SEEK_SET) != 0)
AfxMessageBox(CG_IDP_FILE_CORRUPT);
}
else
{
if (*lpsz != ' ' && *lpsz != '\t' &&
*lpsz != '\n' && *lpsz != ';')
{
// There should be no space at the beginning of the tip
// This behavior is same as VC++ Tips file
// Comment lines are ignored and they start with a semicolon
bStop = TRUE;
}
}
}
m_strFileLine.ReleaseBuffer();
// here is where the standard tip component code ends
// and the enhanced code begins
TRACE("\nParsing help tip line\n");
// initialize the enhanced variables
// If there is no header, the default header of "Did You Know" is used
m_strHeader.LoadString(CG_IDS_DIDYOUKNOW);
m_strFooter.Empty();
m_nHelpID = 0;
int nIndex;
CString sTemp, sTemp2;
nIndex = m_strFileLine.Find('\t');
if (nIndex == -1)
{
m_strTip = m_strFileLine;
return;
}
m_strTip = m_strFileLine.Left(nIndex);
sTemp = m_strFileLine.Right(m_strFileLine.GetLength() - nIndex - 1);
TRACE("Tip is [%s]\n", m_strTip);
// parse the header line
nIndex = sTemp.Find('\t');
if (nIndex == -1)
{
m_strHeader = sTemp;
return;
}
if (nIndex != 0) m_strHeader = sTemp.Left(nIndex);
sTemp2 = sTemp.Right(sTemp.GetLength() - nIndex - 1);
TRACE("Header is [%s]\n", m_strHeader);
// parse the footer line
nIndex = sTemp2.Find('\t');
if (nIndex == -1)
{
m_strFooter = sTemp2;
return;
}
m_strFooter = sTemp2.Left(nIndex);
sTemp = sTemp.Right(sTemp2.GetLength() - nIndex - 1);
TRACE("Footer is [%s]\n", m_strFooter);
m_nHelpID = atoi(sTemp);
TRACE("Help ID is %d\n", m_nHelpID);
}
// draw text controls with a white background
HBRUSH CTipDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (pWnd->GetDlgCtrlID() == IDC_TIPSTRING)
return (HBRUSH)GetStockObject(WHITE_BRUSH);
if (pWnd->GetDlgCtrlID() == ST_FOOTER)
return (HBRUSH)GetStockObject(WHITE_BRUSH);
if (pWnd->GetDlgCtrlID() == ST_HEADER)
return (HBRUSH)GetStockObject(WHITE_BRUSH);
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
void CTipDlg::OnOK()
{
CDialog::OnOK();
// Update the startup information stored in the INI file
CWinApp* pApp = AfxGetApp();
pApp->WriteProfileInt(szSection, szIntStartup, !m_bStartup);
}
BOOL CTipDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// If Tips file does not exist then disable NextTip
if (m_pStream == NULL)
GetDlgItem(IDC_NEXTTIP)->EnableWindow(FALSE);
GetDlgItem(IDB_MORE)->EnableWindow(m_nHelpID != 0);
// set the font for the Header
CFont Font;
Font.CreatePointFont(12, "Arial");
GetDlgItem(ST_HEADER)->SetFont(&Font);
return TRUE; // return TRUE unless you set the focus to a control
}
void CTipDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// DoPaint (&dc, FALSE) ;
// return;
// Get paint area for the big static control
CWnd* pStatic = GetDlgItem(IDC_TIP_RECT);
CRect rcBig, rcBulb;
pStatic->GetWindowRect(&rcBig);
ScreenToClient(&rcBig);
// decrease the size slightly so there is a thin gray border between
// the white rectangle and the static control
rcBig.InflateRect(-6, -6, -6, -6);
// Paint the background white.
CBrush brush;
brush.CreateStockObject(WHITE_BRUSH);
dc.FillRect(rcBig, &brush);
brush.Detach();
// now change the brush to the button shadow color
brush.CreateSolidBrush( ::GetSysColor(COLOR_BTNSHADOW)) ;
// Get the position of the lightbulb
pStatic = GetDlgItem(IDB_LIGHTBULB);
pStatic->GetWindowRect(&rcBulb);
ScreenToClient(&rcBulb);
// Load bitmap and get dimensions of the bitmap
CBitmap bmp;
bmp.LoadBitmap(IDB_LIGHTBULB);
BITMAP bmpInfo;
bmp.GetBitmap(&bmpInfo);
rcBulb.bottom = bmpInfo.bmHeight + rcBulb.top;
rcBulb.right = bmpInfo.bmWidth + rcBulb.left;
// change that right side of rcBig so it is even with the right side of the bitmap
rcBig.right = rcBulb.right;
// draw the left side shadow
dc.FillRect(rcBig, &brush);
// select the bitmap into the device context and draw
CDC dcTmp;
dcTmp.CreateCompatibleDC(&dc);
dcTmp.SelectObject(&bmp);
dcTmp.SelectObject(&brush) ;
dcTmp.ExtFloodFill(0,0, 0x00ffffff, FLOODFILLSURFACE) ;
dc.BitBlt(rcBulb.left, rcBulb.top, rcBulb.Width(), rcBulb.Height(),
&dcTmp, 0, 0, SRCCOPY);
// Do not call CDialog::OnPaint() for painting messages
}
// if the user clicks the More Info button, display the help topic
// associated with the tip
void CTipDlg::OnMore()
{
ASSERT(m_nHelpID != 0);
AfxGetApp()->WinHelp(m_nHelpID);
}