Many calls to OnPaint in my CWnd derived object - scalar deleting destructor

Hi Experts,

The question title is fairly self-explanatory.  I'm deleting something twice.  But it's really a synchronization problem I'm dealing with here.  I'm hoping that there are some sort of "gotchas" that I don't know about when painting or something silly I'm doing wrong with my synchronization.  Maybe if I tell you what I'm doing - you can tell me what to look out for and help me solve my problem!  I reproduce this problem by causing lots of repaints and by having my OnLButtonClick and OnMouseWheel functions called by these event handlers.  I'm also using CStrings and I notice a lot of the time the errors come from their use.

Upon entering OnPaint, OnMouseWheel and OnLButtonClick, I EnterCriticalSection and upon leaving the functions, I LeaveCriticalSection.  These 3 functions contain the bulk of the work and they are the ones that cause my member array to have its contents deleted and recreated.  It takes quite a lot of quick clicking and moving the mouse wheel to cause repaints before I get errors like "HEAP: Free Heap block cc6988 modified at cc6ba4 after it was freed" or "scalar deleting destructor".

Any suggestions?

Thank you very much,
Mike
mikexpertAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AlexFMCommented:
Please show your code.
0
mikexpertAuthor Commented:
Hi AlexFM,

Thanks for taking a look!  :-)  It won't work since there are too many dependencies...

Here's the .h file:
============================================
#if !defined(AFX_MYCALENDAR_H__9483600D_26E0_476F_B3BF_8DFA49AF0EF6__INCLUDED_)
#define AFX_MYCALENDAR_H__9483600D_26E0_476F_B3BF_8DFA49AF0EF6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MyCalendar.h : header file
//
#include "afxtempl.h"
#include "afxcoll.h"

#define MAX_SLOTS 10

/////////////////////////////////////////////////////////////////////////////
// CMyCalendar window

#define RECURRENCE_NONE                  0
#define RECURRENCE_DAILY                 1
#define RECURRENCE_WEEKLY_SPECIFIC_DAYS  2
#define RECURRENCE_MONTHLY_SPECIFIC_DAY  3
#define RECURRENCE_YEARLY_SPECIFIC_DATE  4

// CALENDAR EVENTS:
#define LBUTTONDOWN      WM_USER + 0x0001
#define LBUTTONUP        WM_USER + 0x0010
#define RBUTTONUP        WM_USER + 0x0011
#define RBUTTONDOWN      WM_USER + 0x0100
#define LBUTTONDBLCLICK  WM_USER + 0x0101
 
#define FONT_NAME "TAHOMA"
#define FONT_SIZE 85

class CMyEvent
{
public:
  CMyEvent::CMyEvent()
  {
    m_nRecurrenceType = RECURRENCE_NONE;
    m_bNoEndDate = FALSE;
    m_pReminderEvent = NULL;
            m_nSlot = -1;
            m_bSelected = FALSE;
  }

  CMyEvent::~CMyEvent()
  {
    if(m_pReminderEvent)
      delete m_pReminderEvent;
  }

      static CMyEvent * CreateEvent()
      {
            CMyEvent * pEvent = new CMyEvent();
            pEvent->m_nID = -1;
            pEvent->m_bNoEndDate = FALSE;
            pEvent->m_nDayOfMonth = -1;
            pEvent->m_nEndAfterNTimes = -1;
            pEvent->m_nEveryNTH = -1;
            pEvent->m_nMonth = -1;
            pEvent->m_nRecurrenceType = RECURRENCE_NONE;
            pEvent->m_pReminderEvent = NULL;
            pEvent->m_strCategory = "";
            pEvent->m_strLocation = "";
            pEvent->m_strSubject = "";
            COleDateTime d = COleDateTime::GetCurrentTime();
            pEvent->m_StartDate.SetDate(d.GetYear(), d.GetMonth(), d.GetDay());
            pEvent->m_EndDate = pEvent->m_StartDate;
            pEvent->m_StartTime.SetTime(6, 0,0);
            pEvent->m_EndTime.SetTime(6, 30,0);
            return pEvent;
      }

      void SetID(int nID)
      {
            m_nID = nID;
      }
      
      int GetID()
      {
            return m_nID;
      }

      void SetSelected(BOOL bSelected)
      {
            m_bSelected = bSelected;
      }

      BOOL IsSelected()
      {
            return m_bSelected;
      }
 
      void SetReminder(CMyEvent * pReminderEvent)
  {
    m_pReminderEvent = pReminderEvent;
  }

  void SetSubjectAndLocation(CString strSubject, CString strLocation)
  {
    m_strSubject = strSubject;
    m_strLocation = strLocation;
  }

  void SetDailyRecurrence(int nEveryNDays = 1)
  {
    m_nRecurrenceType = RECURRENCE_DAILY;
    m_nEveryNTH = nEveryNDays;
  }

  void SetWeeklyRecurrence(int nDaysOfWeekMask, int nEveryNWeeks = 1)
  {
    m_nRecurrenceType = RECURRENCE_WEEKLY_SPECIFIC_DAYS;
    m_nEveryNTH = nEveryNWeeks;
  }

  void SetMonthlyRecurrence(int nDayOfMonth, int nEveryNMonths = 1)
  {
    m_nRecurrenceType = RECURRENCE_MONTHLY_SPECIFIC_DAY;
    m_nDayOfMonth = nDayOfMonth;
    m_nEveryNTH = nEveryNMonths;
  }

  void SetYearlyRecurrence(int nMonth, int nDayOfMonth)
  {
    m_nRecurrenceType = RECURRENCE_YEARLY_SPECIFIC_DATE;
    m_nMonth = nMonth;
    m_nDayOfMonth = nDayOfMonth;
  }

  void SetRecurrenceRangeNoEndDate(COleDateTime startNextOnOrAfter)
  {
    m_StartNextOnOrAfter = startNextOnOrAfter;
    m_bNoEndDate = TRUE;
  }

  void SetRecurrenceRangeEndAfter(int nTimes)
  {
    m_bNoEndDate = FALSE;
    m_nEndAfterNTimes = nTimes;
  }

  void SetRecurrenceRange(COleDateTime StartNextOnOrAfter, COleDateTime EndOnOrBefore)
  {
    m_StartNextOnOrAfter = StartNextOnOrAfter;
    m_EndOnOrBefore = EndOnOrBefore;
  }

      BOOL SameStartDate(CMyEvent * pEvent)
      {
            return m_StartTime.GetYear() == pEvent->m_StartTime.GetYear() &&
                       m_StartTime.GetMonth() == pEvent->m_StartTime.GetMonth() &&
                               m_StartTime.GetDay() == pEvent->m_StartTime.GetDay();
      }

      CString ToString()
      {
            CString S;
            S.Format("%d/%d/%d --> %d/%d/%d", m_StartTime.GetYear(), m_StartTime.GetMonth(), m_StartTime.GetDay(),
                  m_EndTime.GetYear(), m_EndTime.GetMonth(), m_EndTime.GetDay());
            return S;
      }

      CMyEvent * Clone()
      {
            CMyEvent * pClone = new CMyEvent();
            pClone->m_strSubject = m_strSubject;
            pClone->m_strLocation = m_strLocation;
            pClone->m_strCategory = m_strCategory;
            pClone->m_strEventInfo = m_strEventInfo;
            pClone->m_StartDate = m_StartDate;
            pClone->m_EndDate = m_EndDate;
            pClone->m_StartTime = m_StartTime;
            pClone->m_EndTime = m_EndTime;
            pClone->m_StartNextOnOrAfter = m_StartNextOnOrAfter;
            pClone->m_EndOnOrBefore = m_EndOnOrBefore;
            pClone->m_nID = m_nID;
            pClone->m_nMonth = m_nMonth;
            pClone->m_nDayOfMonth = m_nDayOfMonth;
            pClone->m_nRecurrenceType = m_nRecurrenceType;
            pClone->m_nEveryNTH = m_nEveryNTH;
            pClone->m_bNoEndDate = m_bNoEndDate;
            pClone->m_nEndAfterNTimes = m_nEndAfterNTimes;
            if(m_pReminderEvent)
                  pClone->m_pReminderEvent = m_pReminderEvent->Clone();
            pClone->m_strCategory = m_strCategory;
            pClone->m_nSlot = m_nSlot;
            pClone->m_bSelected = m_bSelected;
            return pClone;
      }

public:
      CString m_strSubject;
      CString m_strLocation;
      CString m_strCategory;
      CString m_strEventInfo;
      COleDateTime m_StartDate;
      COleDateTime m_EndDate;
  COleDateTime m_StartTime;
  COleDateTime m_EndTime;
 
  // recurrence pattern:
  COleDateTime m_StartNextOnOrAfter;
  COleDateTime m_EndOnOrBefore;

      int m_nID;     // ID for this record in the database...
      int m_nMonth;
      int m_nDayOfMonth;
  int m_nRecurrenceType;
  int m_nEveryNTH;
  BOOL m_bNoEndDate;
  int m_nEndAfterNTimes;
  CMyEvent * m_pReminderEvent;

      // for ease of drawing:
      int m_nSlot;
      BOOL m_bSelected;
};

typedef CTypedPtrArray<CPtrArray, CMyEvent*> EVENT_ARRAY;

class CMyCell
{
public:
  CMyCell::CMyCell()
      {
            m_InBrush.CreateSolidBrush(RGB(255,255,214));
            m_OutBrush.CreateSolidBrush(RGB(255,247,189));
            m_GradLine = RGB(187, 85, 3);      // Gradient line color

            //COLORREF clrHL = GetSysColor(COLOR_HIGHLIGHT);      // Highlight color
            //COLORREF clrFace = GetSysColor(COLOR_BTNFACE);      // Header color
      }

  CMyCell::~CMyCell() {}

      void InitSlots()
      {
            for(int i = 0; i < MAX_SLOTS; i++)
                  m_SlotAvailable[i] = TRUE;
      }

      void SetRectAndIntervals(CRect rect, int xInterval, int yInterval)
      {
            m_Rect = rect;
            m_TextRect = m_Rect;
            m_TextRect.right = m_TextRect.left + xInterval;
            m_xInterval = xInterval;
            m_yInterval = yInterval;
      }

      RECT GetRect()
      {
            return m_Rect;
      }

      void SetDate(COleDateTime * pDate)
      {
            COleDateTime newDate;
            newDate.SetDate(pDate->GetYear(), pDate->GetMonth(), pDate->GetDay());
            m_Date = newDate;
      }

      void SetInMonthBk(BOOL bInMonth)
      {
            if(bInMonth)
                  m_pCurrentBrush = &m_InBrush;
            else
                  m_pCurrentBrush = &m_OutBrush;
      }

      void OnPaint(CDC *pDC, COleDateTime date)
      {
            pDC->FillRect(&m_Rect, m_pCurrentBrush);
      
            CString S;
            if(m_Date.GetDay() == 1)
                  S.Format("%s %d ", m_Date.Format("%B"), m_Date.GetDay());
            else
                  S.Format("%d ", m_Date.GetDay());
            m_Font.DeleteObject();
            m_Font.CreatePointFont(FONT_SIZE, FONT_NAME, pDC);
            pDC->SelectObject(&m_Font);

            if(m_Date == date)
    {
      int nHeaderHeight = GetSystemMetrics(SM_CXVSCROLL);
      if(m_Rect.bottom-m_Rect.top < nHeaderHeight)
                  {
                    FillGradientRect(pDC, &m_Rect);
      }
                  else
      {
        CRect r = m_Rect;
        r.bottom = r.top + nHeaderHeight;
        FillGradientRect(pDC, &r);
      }
    }

            // Draw text on text area
            pDC->SetTextColor(RGB(0,0,0));
            pDC->DrawText(S, &m_TextRect, DT_SINGLELINE | DT_TOP | DT_RIGHT | DT_END_ELLIPSIS);
      }

      void FillGradientRect(CDC *pDC, CRect *pRect)
      {
            // Gradient Fill Header
            TRIVERTEX        vert[2] ;
            GRADIENT_RECT    gRect;

            vert [0] .x      = pRect->left;
            vert [0] .y      = pRect->top;
            vert [0] .Alpha  = 0x0000;
            vert [1] .x      = pRect->right;
            vert [1] .y      = pRect->bottom;
            vert [1] .Alpha  = 0x0000;

//            if (!bMonthView)
            {
/*                  // Week View Gradient Colors
                  vert [0] .Red    = 0xEC00;
                  vert [0] .Green  = 0xE900;
                  vert [0] .Blue   = 0xD800;

                  vert [1] .Red    = 0xF900;
                  vert [1] .Green  = 0xCC00;
                  vert [1] .Blue   = 0x5F00;
            }
            else
            {
*/                  // Month View Gradient Colors
                  vert [0] .Red    = 0xFF00;
                  vert [0] .Green  = 0xFF00;
                  vert [0] .Blue   = 0xD500;

                  vert [1] .Red    = 0xF900;
                  vert [1] .Green  = 0xCC00;
                  vert [1] .Blue   = 0x5F00;
            }

            gRect.UpperLeft  = 0;
            gRect.LowerRight = 1;
            GradientFill(pDC->m_hDC, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_V);

            // Draw Gradient dividing line
            CPen pLine(PS_SOLID, 1, m_GradLine);
            
            pDC->SelectObject(pLine);
            pDC->MoveTo(pRect->left, pRect->bottom);
            pDC->LineTo(pRect->right, pRect->bottom);
            pLine.DeleteObject();
            CPen pPen(PS_SOLID, 1, RGB(0,0,0));
            pDC->SelectObject(pPen);
      }

      COleDateTime GetDate()
      {
            return m_Date;
      }

      void SetBkColor(COLORREF Color)
      {
            m_BkColor = Color;
      }

      // returns the first available slot.  A slot is line in a cell that has no event drawn in it
      // if no slots are available because events take all the place available, -1 is returned.
      int GetNextAvailableSlot()
      {
            for(int i = 0; i < MAX_SLOTS; i++)
            {
                  if(m_SlotAvailable[i])
                        return i;
            }
            return -1;
      }

      void SetSlotTaken(int nSlot)
      {
            m_SlotAvailable[nSlot] = FALSE;
      }

protected:
  COleDateTime m_Date;
      CRect m_Rect;
      CRect m_TextRect;
      int m_xInterval;
      int m_yInterval;
  EVENT_ARRAY m_Events;   // events that start in this cell
      COLORREF m_BkColor,      m_GradLine;
      CBrush m_InBrush;
      CBrush m_OutBrush;
      CBrush * m_pCurrentBrush;
      CFont m_Font;
      BOOL m_SlotAvailable[MAX_SLOTS];
};

typedef CTypedPtrArray<CPtrArray, CMyCell*> CELL_ARRAY;

class CMyCalendarDataProvider
{
public:
      CMyCalendarDataProvider() {}
      
      // returns pEvents for events that intersect events in Start to End
      virtual BOOL GetEventsForDateRange(EVENT_ARRAY * pEvents, COleDateTime Start, COleDateTime End) = 0;
      virtual BOOL SaveEvent(CMyEvent * pEvent) = 0;
      virtual BOOL DeleteEvent(CMyEvent * pEvent) = 0;
};

class CMyCalendar : public CWnd
{
// Construction
public:
      CMyCalendar();
      BOOL RegisterWindowClass();

// Attributes
public:

// Operations
public:
      void SetCurrentDate(COleDateTime date);
      void SetDataProvider(CMyCalendarDataProvider * pProvider);
      static CString PrintDate(COleDateTime pDate, BOOL bMessageBox = TRUE);

// Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CMyCalendar)
      protected:
      virtual void PreSubclassWindow();
      //}}AFX_VIRTUAL

// Implementation
public:
      virtual ~CMyCalendar();
      virtual BOOL PreTranslateMessage(MSG* pMsg);

      // Generated message map functions
protected:
      //{{AFX_MSG(CMyCalendar)
      afx_msg BOOL OnEraseBkgnd(CDC* pDC);
      afx_msg void OnPaint();
      afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
      afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
      afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
      afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()

      CMyEvent * SelectClickedEvent(CPoint point);
      void OnAddEvent();
      void OnDeleteEvent();
      void OnJumpToDate();
      void DeleteEvents();
      
      void SetCellDates(COleDateTime date);
      void MoveView(int nNumberOfDays);

      void DoPaint(CDC * pDC);
      void PrintEvents();
      int NumberOfDaysEventInWeek(CMyEvent * pEvent, int nWeek);
      void DrawEvent(CDC * pDC, CMyEvent * pEvent, int nSlot);
      void DrawEvents(CDC * pDC);
      void TellCellsInEventAboutSlotTaken(CMyEvent * pEvent, int nSlot);
      CMyCell * GetFirstCell(COleDateTime StartDate, COleDateTime EndDate);
  int DrawMonthHeader(CDC *pDC);   // returns the height of the month header
      void SetCellPaintDataMonthView(int nInterval, int yInterval, int nTopSpace);
      BOOL PointInDay(CPoint * p);
      BOOL PointOnEvent(CPoint * p);
      int GetSlotForPoint(CPoint point);
      CMyEvent * GetEventAtPoint(CPoint point);
      CMyCell * GetCellForPoint(CPoint point);
      CMyEvent * FindEvent(COleDateTime Date, int nSlot);
      int IndexOf(CMyEvent * pEvent);
      int IndexOf(CMyCell * pCell);
      BOOL EndDateComesBefore(CMyEvent * pEvent1, CMyEvent * pEvent2);
      void SortEventsForProperRedrawing();
      void InitCellSlots();
      void GoToLastDayInMonth(COleDateTime Date);
      void GetEventsForCurrentDateRange();

      RECT m_HighlightRect; // the rectangle used to highlight the day the mouse is over
      CBrush WHITEBRUSH;
      CBrush YELLOWBRUSH;
      CBrush m_ControlBKBrush;

       COleDateTime m_CurrentDate;
      COleDateTime m_CurrentMonth;

      int m_nHorizontalInterval;
      int m_nVerticalInterval;
      int m_nEventHeight;
      int m_nHeaderHeight;

  int m_nFontSize;
  CString m_strFontName;

  COLORREF m_clrBackGrnd;
      CELL_ARRAY m_Cells;      // used to draw the square backgrounds only)
      EVENT_ARRAY m_Events;    // stores all the events that take place in the current view
      
      CRITICAL_SECTION m_EventCS;

      int m_nMaxRows;
      int m_nDaysPerWeek;

      // different brushes
      CBrush m_RedBrush;
      CBrush m_GreenBrush;
      CBrush m_BlueBrush;
      CBrush m_DarkBlueBrush;

      // pens
//      CPen m_BlackPen;

      CMyEvent * m_pCurrentSelectedEvent;
      CMyEvent * m_pLastSelectedEvent;
      CMyEvent * m_pModifyingEvent;

      CMyCell * m_pLastCell;
      CPoint m_LastPoint;

      CMyCalendarDataProvider * m_pDataProvider;
  BOOL m_bInitializedEvents;
};

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

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MYCALENDAR_H__9483600D_26E0_476F_B3BF_8DFA49AF0EF6__INCLUDED_)


And the .cpp file:
============================================

#include "stdafx.h"
#include "MyCalendar.h"
#include "EventDlg.h"
#include "..\inc\MemoryDC.h"
#include "CalendarPicker.h"
#include "StringHelper.h"

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

#define CALENDAR_CLASSNAME "MyCalendar"
#define MAX_CELLS 42

#define SPACER 1
#define DATE_HEADER_SPACER 2
#define EVENT_PADDING 5

// COMMANDS
#define ID_ADD_EVENT       900
#define ID_DELETE_EVENT    901
#define ID_JUMP_TO_DATE    902

/////////////////////////////////////////////////////////////////////////////
// CMyCalendar

CMyCalendar::CMyCalendar()
{
      m_clrBackGrnd = RGB(255,255,213);

  m_nMaxRows = 6;
      m_nDaysPerWeek = 7;
  m_CurrentDate.SetDate(COleDateTime::GetCurrentTime().GetYear(), COleDateTime::GetCurrentTime().GetMonth(), COleDateTime::GetCurrentTime().GetDay());

  m_nFontSize = 85;
  m_strFontName = "TAHOMA";
  m_bInitializedEvents = FALSE;
      //COleDateTime date;
      //date.SetDate(COleDateTime::GetCurrentTime().GetYear(), COleDateTime::GetCurrentTime().GetMonth(), 1);

      for(int i = 0; i < MAX_CELLS; i++)
            m_Cells.Add(new CMyCell());

      SetCurrentDate(m_CurrentDate);
  RegisterWindowClass();
      m_pCurrentSelectedEvent = NULL;
      m_pLastSelectedEvent = NULL;

      m_pLastCell = NULL;
      InitializeCriticalSection(&m_EventCS);
}

CMyCalendar::~CMyCalendar()
{
      for(int i = 0; i < MAX_CELLS; i++)
      {
            delete m_Cells.GetAt(i);
            m_Cells.SetAt(i, NULL);   // ZZZZZ
      }
      DeleteEvents();
      DeleteCriticalSection(&m_EventCS);
      if(m_pDataProvider)
      {
            delete m_pDataProvider;
            m_pDataProvider = NULL;
      }
}

void CMyCalendar::DeleteEvents()
{
      while(m_Events.GetSize())
      {
            delete m_Events.GetAt(0);
            m_Events.SetAt(0, NULL);  // ZZZZZ
            m_Events.RemoveAt(0);
      }
}

void CMyCalendar::SetDataProvider(CMyCalendarDataProvider * pDataProvider)
{
      m_pDataProvider = pDataProvider;
}

BOOL CMyCalendar::RegisterWindowClass()
{
  WNDCLASS wndcls;
  HINSTANCE hInst = AfxGetInstanceHandle();

  if (!(::GetClassInfo(hInst, CALENDAR_CLASSNAME, &wndcls)))
  {
    // otherwise we need to register a new class
    wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
    wndcls.lpfnWndProc      = ::DefWindowProc;
    wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
    wndcls.hInstance        = hInst;
    wndcls.hIcon            = NULL;
    wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
    wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
    wndcls.lpszMenuName     = NULL;
    wndcls.lpszClassName    = CALENDAR_CLASSNAME;

    if (!AfxRegisterClass(&wndcls))
    {
      AfxThrowResourceException();
      return FALSE;
    }
  }

  return TRUE;
}

BEGIN_MESSAGE_MAP(CMyCalendar, CWnd)
      //{{AFX_MSG_MAP(CMyCalendar)
      ON_WM_ERASEBKGND()
      ON_WM_PAINT()
      ON_WM_LBUTTONDOWN()
      ON_WM_LBUTTONDBLCLK()
      ON_WM_RBUTTONUP()
      ON_WM_RBUTTONDOWN()
      ON_COMMAND(ID_ADD_EVENT, OnAddEvent)
      ON_COMMAND(ID_DELETE_EVENT, OnDeleteEvent)
      ON_COMMAND(ID_JUMP_TO_DATE, OnJumpToDate)
      ON_WM_MOUSEWHEEL()
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CMyCalendar message handlers

BOOL CMyCalendar::OnEraseBkgnd(CDC* pDC)
{
      // TODO: Add your message handler code here and/or call default
      return TRUE;

      //return CWnd::OnEraseBkgnd(pDC);
}

CString CMyCalendar::PrintDate(COleDateTime Date, BOOL bMessageBox)
{
      CString S;
      S.Format("%d/%d/%d", Date.GetYear(), Date.GetMonth(), Date.GetDay());
      if(bMessageBox)
            ::MessageBox(NULL, S, "Date", MB_OK);
      return S;
}

// sets all the dates of the cells in the current view starting with date...
void CMyCalendar::SetCellDates(COleDateTime date)
{
      CMyCell * pCell = NULL;
      for(int i = 0; i < MAX_CELLS; i++)
      {
            pCell = m_Cells.GetAt(i);
            pCell->SetDate(&date);
            date += 1;
      }
}

void CMyCalendar::SetCurrentDate(COleDateTime date)
{
      // remove the time from the date:
      date.SetDate(date.GetYear(), date.GetMonth(), date.GetDay());
      m_CurrentDate = date;

      // set date to the beginning of the month
      date.SetDate(date.GetYear(), date.GetMonth(), 1);
      // Find the first Sunday starting from the 1st of the month looking back...
      while (date.GetDayOfWeek() != 1)
            date -= 1;

      SetCellDates(date);
}

void CMyCalendar::SetCellPaintDataMonthView(int xInterval, int yInterval, int nTopSpace)
{
      int nCell = 0;
      CMyCell * pCell = NULL;
      CRect rect;
      int nCurrentMonth = m_CurrentDate.GetMonth();
      int nCellMonth;
      CString S;
      for(int y = 0; y < 6; y++)
      {
            for(int x = 0; x < 7; x++)
            {
                  pCell = m_Cells.GetAt(nCell);
                  nCellMonth = pCell->GetDate().GetMonth();
                  S.Format("%d %d, %d", pCell->GetDate().GetMonth(), pCell->GetDate().GetDay(), pCell->GetDate().GetYear());
                  pCell->SetInMonthBk((nCellMonth + nCurrentMonth) % 2 == 0);
                  rect.top = y * yInterval + nTopSpace + SPACER;
                  rect.bottom = rect.top + yInterval - (y == 5 ? -50 : SPACER); // -50 just to make sure there's no rounding errors
                  rect.left = x * xInterval + SPACER;
                  rect.right = rect.left + xInterval - (x == 6 ? -50 : SPACER); // -50 just to make sure there's no rounding errors
                  pCell->SetRectAndIntervals(rect, xInterval, yInterval);
                  nCell++;
            }
      }
}

void CMyCalendar::InitCellSlots()
{
      for(int i = 0; i < m_Cells.GetSize(); i++)
            m_Cells.GetAt(i)->InitSlots();
}

void CMyCalendar::DoPaint(CDC * pDC)
{
      InitCellSlots();
  m_nHeaderHeight = DrawMonthHeader(pDC);

      // Calculate Real Grid Area - without the day of week header
      RECT rect;
      GetClientRect(&rect);
  rect.top += m_nHeaderHeight;

      CPen penBlack(PS_SOLID, 1, RGB(0,0,0));
  CBrush brBkGrnd(m_clrBackGrnd);
  pDC->SelectObject(penBlack);
      pDC->SelectObject(brBkGrnd);

      pDC->FillRect(&rect, &m_ControlBKBrush);
      
  int nVerticalSquares = m_nMaxRows;
      int nHorizontalSquares = m_nDaysPerWeek;

      // intervals are the multiples of height and width
      m_nVerticalInterval = (rect.bottom-rect.top) / nVerticalSquares;
      m_nHorizontalInterval = rect.right / nHorizontalSquares;

      SetCellPaintDataMonthView(m_nHorizontalInterval, m_nVerticalInterval, m_nHeaderHeight);

      // draw the horizontal lines first:
      int nY;
      for(int y = 0; y < nVerticalSquares -1; y++)
      {
            nY = rect.top + ((y+1) * m_nVerticalInterval);
            pDC->MoveTo(rect.left, nY);
            pDC->LineTo(rect.right, nY);
      }

      // now draw the vertical lines:
      int nX;
      for(int x = 0; x < nHorizontalSquares -1; x++)
      {
            nX = rect.left + ((x+1) * m_nHorizontalInterval);
            pDC->MoveTo(nX, rect.top);
            pDC->LineTo(nX, rect.bottom);
      }

/*      CString S;
      S.Format("%d %d, %d", m_CurrentDate.GetMonth(), m_CurrentDate.GetDay(), m_CurrentDate.GetYear());
      ::MessageBox(m_hWnd, S, "", MB_OK);*/
      for(int i = 0; i < MAX_CELLS; i++)
            m_Cells.GetAt(i)->OnPaint(pDC, m_CurrentDate);

      DrawEvents(pDC);
}

void CMyCalendar::OnPaint()
{
      EnterCriticalSection(&m_EventCS);
      if(!m_bInitializedEvents)
      {
            GetEventsForCurrentDateRange();
            SortEventsForProperRedrawing();
            m_bInitializedEvents = TRUE;
      }
      CPaintDC dc(this); // device context for painting

      CMemoryDC dcMem(&dc);
      DoPaint(&dcMem);
      LeaveCriticalSection(&m_EventCS);
}

// returns true if event1's end date comes before event2's end date
BOOL CMyCalendar::EndDateComesBefore(CMyEvent * pEvent1, CMyEvent * pEvent2)
{
      COleDateTime EndTime1 = pEvent1->m_EndTime;
      COleDateTime EndTime2 = pEvent2->m_EndTime;

      if(EndTime1.GetYear() < EndTime2.GetYear())
            return TRUE;

      if(EndTime1.GetMonth() < EndTime2.GetMonth())
            return TRUE;

      if(EndTime1.GetDay() < EndTime2.GetDay())
            return TRUE;
      
      return FALSE;
}

// first sorts all events by start date and then sorts all events of the same date, placing
// events that last more days first.
void CMyCalendar::SortEventsForProperRedrawing()
{
      // simple bubble sort:
      BOOL bMovedStuff = TRUE;
      CMyEvent * pEvent1;
      CMyEvent * pEvent2;

      do
      {
            bMovedStuff = FALSE;
            
            for(int i = 0; i < m_Events.GetSize()-1; i++)
            {
                  pEvent1 = m_Events.GetAt(i);
                  pEvent2 = m_Events.GetAt(i+1);
                  if(pEvent1->m_StartDate > pEvent2->m_StartDate)
                  {
                        m_Events.SetAt(i, pEvent2);
                        m_Events.SetAt(i+1, pEvent1);
                        bMovedStuff = TRUE;
                  }
            }
      } while(bMovedStuff);

      do
      {
            bMovedStuff = FALSE;
            for(int i = 0; i < m_Events.GetSize()-1; i++)
            {
                  pEvent1 = m_Events.GetAt(i);
                  pEvent2 = m_Events.GetAt(i+1);
                  if(pEvent1->SameStartDate(pEvent2) && EndDateComesBefore(pEvent1, pEvent2))
                  {
                        m_Events.SetAt(i, pEvent2);
                        m_Events.SetAt(i+1, pEvent1);
                        bMovedStuff = TRUE;
                  }
            }
      } while(bMovedStuff);
}

// returns the first cell from the given date range
CMyCell * CMyCalendar::GetFirstCell(COleDateTime StartDate, COleDateTime EndDate)
{
      StartDate.SetDate(StartDate.GetYear(), StartDate.GetMonth(), StartDate.GetDay());
      EndDate.SetDate(EndDate.GetYear(), EndDate.GetMonth(), EndDate.GetDay());
      CMyCell * pCell = NULL;
      COleDateTime CurrentDate;
      for(int i = 0; i < m_Cells.GetSize(); i++)
      {
            pCell = m_Cells.GetAt(i);
            CurrentDate = pCell->GetDate();
            if(StartDate <= CurrentDate && CurrentDate <= EndDate)
                  return pCell;
      }
      return NULL;
}

//CMyEvent

void CMyCalendar::DrawEvent(CDC * pDC, CMyEvent * pEvent, int nSlot)
{
      COleDateTime StartDay = pEvent->m_StartDate;
      COleDateTime EndDay = pEvent->m_EndDate;
      StartDay.SetDate(StartDay.GetYear(), StartDay.GetMonth(), StartDay.GetDay());
      EndDay.SetDate(EndDay.GetYear(), EndDay.GetMonth(), EndDay.GetDay());
      pEvent->m_nSlot = nSlot;

      int nWeek = 0;
      while(TRUE)
      {
            CMyCell * pCell = GetFirstCell(StartDay, EndDay);
            if(!pCell)
                  return;

            RECT r = pCell->GetRect();
            
            // Now we draw the rectangle - we add event height for the date header
            r.top += m_nEventHeight + DATE_HEADER_SPACER + nSlot * 1 + nSlot * m_nEventHeight;

            if(m_nEventHeight + r.top < r.bottom)
                  r.bottom = m_nEventHeight + r.top;

            int nNumberOfDaysEventInWeek = NumberOfDaysEventInWeek(pEvent, nWeek);
            r.right = r.left + m_nHorizontalInterval * nNumberOfDaysEventInWeek - EVENT_PADDING;
            r.left += EVENT_PADDING;

            // sanity check
            if(r.bottom > r.top)
            {
                  if(pEvent->IsSelected())
                        pDC->SelectObject(&m_DarkBlueBrush);
                  else
                        pDC->SelectObject(&m_BlueBrush);

                  pDC->Rectangle(&r);
                  if(pEvent->IsSelected())
                        pDC->SetTextColor(RGB(255,255,255));
                  else
                        pDC->SetTextColor(RGB(0,0,0));
                  pDC->DrawText(pEvent->m_strSubject, &r, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
            }

            StartDay += nNumberOfDaysEventInWeek;
            if(StartDay > EndDay)
                  break;
            nWeek++;
      }
}

// returns the number of days pEvent has in the nth week (nWeek)  (0 based)
int CMyCalendar::NumberOfDaysEventInWeek(CMyEvent * pEvent, int nWeek)
{
      COleDateTime StartTime = pEvent->m_StartDate;
      COleDateTime EndDay = pEvent->m_EndDate;
      
      // first advance StartTime by the number of days to get to the nWeek in question.
      if(nWeek == 1)
            StartTime += 8 - StartTime.GetDayOfWeek();
      else if(nWeek > 1)
            StartTime += 7 * (nWeek-1) + 8 - StartTime.GetDayOfWeek();
      
      // get rid of time
      EndDay.SetDate(EndDay.GetYear(), EndDay.GetMonth(), EndDay.GetDay());
      COleDateTime CurrentEventDay;
      CurrentEventDay.SetDate(StartTime.GetYear(), StartTime.GetMonth(), StartTime.GetDay());
      int nDays = 1;
      int nDayOfWeek = CurrentEventDay.GetDayOfWeek();
      
      while(nDayOfWeek < 7)
      {
            if(CurrentEventDay == EndDay)
                  return nDays;

            CurrentEventDay += 1;
            nDays++;
            nDayOfWeek = CurrentEventDay.GetDayOfWeek();
      }

      return nDays;
}

// assumes events have been properly sorted
void CMyCalendar::DrawEvents(CDC * pDC)
{
      CMyEvent * pEvent = NULL;
//      COleDateTime StartDate = m_Cells.GetAt(0)->GetDate();
//      COleDateTime EndDate = m_Cells.GetAt(m_Cells.GetSize()-1)->GetDate();
      CMyCell * pCell = NULL;
      int nSlot;
      CString S;
      
      for(int i = 0; i < m_Events.GetSize(); i++)
      {
            pEvent = m_Events.GetAt(i);
            pCell = GetFirstCell(pEvent->m_StartDate, pEvent->m_EndDate);
            if(!pCell)
                  continue;

            nSlot = pCell->GetNextAvailableSlot();
            if(nSlot == -1)
                  continue;

            TellCellsInEventAboutSlotTaken(pEvent, nSlot);
            DrawEvent(pDC, pEvent, nSlot);
      }
}

void CMyCalendar::TellCellsInEventAboutSlotTaken(CMyEvent * pEvent, int nSlot)
{
      COleDateTime StartDate = pEvent->m_StartDate;
      COleDateTime EndDate = pEvent->m_EndDate;
      COleDateTime CurrentCellDate;
      CurrentCellDate.SetDate(StartDate.GetYear(), StartDate.GetMonth(), StartDate.GetDay());
      EndDate.SetDate(EndDate.GetYear(), EndDate.GetMonth(), EndDate.GetDay());

      CMyCell * pCurrentCell = GetFirstCell(CurrentCellDate, EndDate);
      while(pCurrentCell)
      {
            pCurrentCell->SetSlotTaken(nSlot);
            CurrentCellDate += 1;
            pCurrentCell = GetFirstCell(CurrentCellDate, EndDate);
            if(pCurrentCell && CurrentCellDate == EndDate)
            {
                  pCurrentCell->SetSlotTaken(nSlot);
                  break;
            }
      }
}

// Draw Days of the Week for the Month View
int CMyCalendar::DrawMonthHeader(CDC *pDC)
{
      // Area to paint
      CRect rArea(0,0,0,0);
      GetClientRect(&rArea);

      CRect rHdrArea, rHdr;
      CRect rHdrText(0,0,0,0);
      int nHdrHeight = GetSystemMetrics(SM_CXVSCROLL);
      int nInterval = (int)(rArea.right / 7);           // was / 6
      CPen penLLine(PS_SOLID, 1, RGB(172, 168,153));
      CPen penRLine(PS_SOLID, 1, RGB(255,255,255));
      CFont fFont, *pOldFont;
      COleDateTime dtDate = m_CurrentDate;
      CString strText = "";

      // Initialize variables
      rHdrArea.left = 0;
      rHdrArea.top = 0;
      rHdrArea.right = rArea.right;
      rHdrArea.bottom = nHdrHeight;

      // Fillin background color
      pDC->FillSolidRect(&rHdrArea, RGB(236, 233, 216));

      // Monday Header
      rHdr.left = rHdrArea.left;
      rHdr.top = rHdrArea.top;
      rHdr.right = rHdrArea.right;
      rHdr.bottom = nHdrHeight;
      pDC->Draw3dRect(rHdrArea, RGB(255,255,255), RGB(172, 168, 153));

      // Draw column separator bars
      rHdr.top = 1;
      rHdr.bottom = nHdrHeight - 1;

      // Make sure we start at Sunday
      while (dtDate.GetDayOfWeek() != 1)
            dtDate -= 1;

      // Select current font
      fFont.CreatePointFont(m_nFontSize, m_strFontName, pDC);
      pOldFont = pDC->SelectObject(&fFont);

      // Header Rect Area
      rHdrArea.left = 2;
      rHdrArea.top = 2;
      rHdrArea.right = nInterval - 1;
      rHdrArea.bottom = nHdrHeight - 1;

      // Make drawing text transparent
      pDC->SetBkMode(TRANSPARENT);

      for (int x = 1; x <= 7; x++)
      {
            // Draw Day of week text
            pDC->DrawText(dtDate.Format("%A"), &rHdrText,
                  DT_SINGLELINE | DT_CALCRECT);
            rHdrText.left = rHdrArea.left;

            if (x <= 7)   // was < 6
            {
                  // Draw full day text
                  pDC->DrawText(dtDate.Format("%A"), &rHdrArea,
                        DT_SINGLELINE | DT_VCENTER | DT_CENTER | DT_END_ELLIPSIS);
            }
            else
            {
                  // Always Draw Saturday and Sunday in one cell  - NO!!!
                  /*strText = dtDate.Format("%a") + "/";
                  dtDate += 1;
                  strText += dtDate.Format("%a");
                  pDC->DrawText(strText, &rHdrArea,
                        DT_SINGLELINE | DT_BOTTOM | DT_CENTER | DT_END_ELLIPSIS);*/
            }
            // Increment day of week
            dtDate += 1;
            // Recalculate Header rect area
            rHdrArea.left = rHdrArea.right + 1;
            rHdrArea.right = rHdrArea.left + nInterval;

            rHdr.left += nInterval;
            rHdr.right = rHdr.left + 2;

            // Select Gray Pen and draw line
            pDC->SelectObject(penLLine);
            pDC->MoveTo(rHdr.left, rHdr.top + 1);
            pDC->LineTo(rHdr.left, rHdr.bottom - 1);

            // Select White Pen and draw line
            pDC->SelectObject(penRLine);
            pDC->MoveTo(rHdr.left, rHdr.top + 1);
            pDC->LineTo(rHdr.left, rHdr.bottom - 1);
            // Move to next column separator
            rHdr.right += nInterval;
      }
      pDC->SelectObject(pOldFont);
  return nHdrHeight;
}

void CMyCalendar::PreSubclassWindow()
{
      // THIS FUNCTION IS HERE IN CASE YOU NEED TO DO ANY INITIALIZATION THAT REQUIRES THE
      // WINDOW TO HAVE BEEN CREATED...
      m_ControlBKBrush.CreateSolidBrush(RGB(190,190,190));
      WHITEBRUSH.CreateSolidBrush(RGB(255,255,255));
      YELLOWBRUSH.CreateSolidBrush(RGB(255,255,175));
      m_nEventHeight = GetSystemMetrics(SM_CXVSCROLL);

      CWnd::PreSubclassWindow();

      // create brushes:
      m_RedBrush.CreateSolidBrush(RGB(255,64,64));
      m_GreenBrush.CreateSolidBrush(RGB(0,255-64,0));
      m_BlueBrush.CreateSolidBrush(RGB(123,154,222));
      m_DarkBlueBrush.CreateSolidBrush(RGB(8,36,107));

      // create pens:
//      m_BlackPen.CreatePen(PS_SOLID, 1, RGB(0,0,0));
}

void CMyCalendar::PrintEvents()
{
      CString S = "";
      CString strTemp;
      CMyEvent * pEvent = NULL;

      for(int i = 0; i < m_Events.GetSize(); i++)
      {
            pEvent = m_Events.GetAt(i);
            strTemp.Format("%d/%d/%d --> %d/%d/%d\n", pEvent->m_StartDate.GetYear(), pEvent->m_StartDate.GetMonth(), pEvent->m_StartDate.GetDay(),
                  pEvent->m_EndDate.GetYear(), pEvent->m_EndDate.GetMonth(), pEvent->m_EndDate.GetDay());
            S += strTemp;
      }
      
      ::MessageBox(NULL, S, "", MB_OK);
}

BOOL CMyCalendar::PointInDay(CPoint * p)
{
      return TRUE;
}

BOOL CMyCalendar::PointOnEvent(CPoint * p)
{
      return TRUE;
}

void CMyCalendar::OnRButtonUp(UINT nFlags, CPoint point)
{
      EnterCriticalSection(&m_EventCS);
      m_pLastCell = GetCellForPoint(point);
      m_LastPoint = point;

      RECT r;
      GetClientRect(&r);
      ScreenToClient(&r);
      point.x -= r.left;
      point.y -= r.top;

  CMenu menu;
      menu.CreatePopupMenu();
      
      if(m_pLastCell)
            menu.AppendMenu(MF_ENABLED | MF_STRING, ID_ADD_EVENT, _T("&Add Event"));

      if(m_pCurrentSelectedEvent)
            menu.AppendMenu(MF_ENABLED | MF_STRING, ID_DELETE_EVENT, _T("&Delete Event"));

      menu.AppendMenu(MF_SEPARATOR, -1, "");
      menu.AppendMenu(MF_ENABLED | MF_STRING, ID_JUMP_TO_DATE, _T("&Jump to date..."));

      menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON,point.x,point.y,this);
      
      CWnd::OnRButtonUp(nFlags, point);
      LeaveCriticalSection(&m_EventCS);
}

CMyCell * CMyCalendar::GetCellForPoint(CPoint point)
{
      RECT rect;
      GetClientRect(&rect);
  rect.top += m_nHeaderHeight;

      // find the (x,y) position of the point in cell to easily calculate the index of the
      // cell in m_Cells
      int x = (point.x - rect.left) / m_nHorizontalInterval + 1;
      int y = (point.y - rect.top) / m_nVerticalInterval + 1;

      // sanity check:
      if(x == 8) x = 7;  // x has a maximum of 7
      if(y == 7) y = 6;  // y has a maximum of 6

      CMyCell * pCell = m_Cells.GetAt((y-1) * 7 + x - 1);

      COleDateTime date = pCell->GetDate();
      return pCell;
}

int CMyCalendar::GetSlotForPoint(CPoint point)
{
      point.y = (point.y - m_nHeaderHeight) % m_nVerticalInterval;
      point.y -= DATE_HEADER_SPACER;

      // slots are ranges in y with height m_nEventHeight
      int nSlot = -1;
      while(TRUE)
      {
            point.y = point.y - m_nEventHeight - 1;
            if(point.y <= 0)
                  break;
            nSlot++;
      }
      return nSlot;
}

CMyEvent * CMyCalendar::GetEventAtPoint(CPoint point)
{
      int nSlot = GetSlotForPoint(point);
      if(nSlot == -1)
            return NULL;
      
      CMyCell * pCell = GetCellForPoint(point);
      if(!pCell)
            return NULL;

      COleDateTime Date = pCell->GetDate();
      return FindEvent(Date, nSlot);
}

CMyEvent * CMyCalendar::FindEvent(COleDateTime Date, int nSlot)
{
      CMyEvent * pEvent = NULL;
      COleDateTime Start;
      COleDateTime End;
      Date.SetDate(Date.GetYear(), Date.GetMonth(), Date.GetDay());

      for(int i = 0; i < m_Events.GetSize(); i++)
      {
            pEvent = m_Events.GetAt(i);
            if(pEvent->m_nSlot == nSlot)
            {
                  // slots are the same - do we have the right date?
                  if(pEvent->m_StartDate <= Date && Date <= pEvent->m_EndDate)
                  {
                        return pEvent;
                  }
            }
      }
      return NULL;
}

int CMyCalendar::IndexOf(CMyEvent * pEvent)
{
      CMyEvent * pCurrent = NULL;

      for(int i = 0; i < m_Events.GetSize(); i++)
      {
            pCurrent = m_Events.GetAt(i);
            if(pCurrent == pEvent)
            {
                  return i;
            }
      }
      return -1;
}

int CMyCalendar::IndexOf(CMyCell * pCell)
{
      CMyCell * pCurrent = NULL;
      for(int i = 0; i < m_Cells.GetSize(); i++)
      {
            pCurrent = m_Cells.GetAt(i);
            if(pCurrent == pCell)
                  return i;
      }
      return -1;
}

void CMyCalendar::OnRButtonDown(UINT nFlags, CPoint point)
{
      EnterCriticalSection(&m_EventCS);
      SelectClickedEvent(point);
      LeaveCriticalSection(&m_EventCS);
}

CMyEvent * CMyCalendar::SelectClickedEvent(CPoint point)
{
      CMyEvent * pEvent = GetEventAtPoint(point);
      m_LastPoint = point;
      if(!pEvent)
            return NULL;

      // an event was found, select it and tell the parent about the selection
      if(m_pCurrentSelectedEvent)
      {
            m_pCurrentSelectedEvent->SetSelected(FALSE);
            m_pLastSelectedEvent = m_pCurrentSelectedEvent;
      }
      m_pCurrentSelectedEvent = pEvent;
      m_pCurrentSelectedEvent->SetSelected(TRUE);

      Invalidate();
      return pEvent;
}

void CMyCalendar::OnLButtonDown(UINT nFlags, CPoint point)
{
      EnterCriticalSection(&m_EventCS);
      SelectClickedEvent(point);
      LeaveCriticalSection(&m_EventCS);
}

void CMyCalendar::OnLButtonDblClk(UINT nFlags, CPoint point)
{
      EnterCriticalSection(&m_EventCS);
      CMyEvent * pEvent = SelectClickedEvent(point);
      
      CEventDlg dlg;
      dlg.SetDate(GetCellForPoint(point)->GetDate());
      
      if(pEvent)
            dlg.SetEvent(pEvent);
      
      if(dlg.DoModal() == IDOK)
      {
            if(m_pDataProvider->SaveEvent(dlg.GetEvent()->Clone()))
            {
                  if(!pEvent)
                  {
                        m_Events.Add(dlg.GetEvent()->Clone());
                  }
                  SortEventsForProperRedrawing();
                  Invalidate();
            }
      }
      LeaveCriticalSection(&m_EventCS);
}

void CMyCalendar::OnAddEvent()
{
      CEventDlg dlg;
      dlg.SetDate(GetCellForPoint(m_LastPoint)->GetDate());
      if(dlg.DoModal() != IDOK)
            return;

      if(m_pDataProvider->SaveEvent(dlg.GetEvent()))
      {
            m_Events.Add(dlg.GetEvent()->Clone());
            SortEventsForProperRedrawing();
            Invalidate();
      }
}

void CMyCalendar::OnDeleteEvent()
{
      if(!m_pCurrentSelectedEvent)
            return;

      int nIndex = IndexOf(m_pCurrentSelectedEvent);
      if(nIndex == -1 || m_Events.GetSize() <= nIndex)
      {
            return;
      }
      
      if(m_pDataProvider->DeleteEvent(m_pCurrentSelectedEvent))
      {
            delete m_pCurrentSelectedEvent;
            m_pCurrentSelectedEvent = NULL;
            m_Events.RemoveAt(nIndex);
            Invalidate();
      }
}

void CMyCalendar::OnJumpToDate()
{
      CCalendarPicker dlg;
      int nResponse = dlg.DoModal();
      if(nResponse != IDOK)
            return;

}

BOOL CMyCalendar::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
      EnterCriticalSection(&m_EventCS);
      if(zDelta > 0)
            MoveView(-7);
      else
            MoveView(7);
      LeaveCriticalSection(&m_EventCS);
      return TRUE;
}

void CMyCalendar::GetEventsForCurrentDateRange()
{
      COleDateTime date = m_Cells.GetAt(0)->GetDate();
      DeleteEvents();

      if(!m_pDataProvider->GetEventsForDateRange(&m_Events, date, m_Cells.GetAt(m_Cells.GetSize()-1)->GetDate()))
            ::MessageBox(m_hWnd, "Unable to get events in the view", "Error", MB_ICONWARNING);
}

void CMyCalendar::MoveView(int nNumberOfDays)
{
      COleDateTime date = m_Cells.GetAt(0)->GetDate();
      date += nNumberOfDays;
      SetCellDates(date);

      GetEventsForCurrentDateRange();
      SortEventsForProperRedrawing();
      Invalidate();      
}

void CMyCalendar::GoToLastDayInMonth(COleDateTime Date)
{
      int nMonth = Date.GetMonth();
  // Set Date to the last day of its month
  Date.SetDate(Date.GetYear(), Date.GetMonth(), 28);  // there are at least 28 days in the month
  while(Date.GetMonth() == nMonth)
    Date += 1;
  Date -= 1;
}

BOOL CMyCalendar::PreTranslateMessage(MSG* pMsg)
{
      EnterCriticalSection(&m_EventCS);
      int i = 0;
      switch(pMsg->message)
      {
            case WM_KEYDOWN:
                  if(pMsg->wParam == 38)  // UP ARROW
                  {
                        MoveView(-7);
                        LeaveCriticalSection(&m_EventCS);
                        return TRUE;
                  }
                  else if(pMsg->wParam == 40) // DOWN ARROW
                  {
                        MoveView(7);
                        LeaveCriticalSection(&m_EventCS);
                        return TRUE;
                  }
                  else if(pMsg->wParam == 33)  // PAGE UP
                  {
                        MoveView(-42);
                        LeaveCriticalSection(&m_EventCS);
                        return TRUE;
                  }
                  else if(pMsg->wParam == 34)  // PAGE DOWN
                  {
                        MoveView(42);
                        LeaveCriticalSection(&m_EventCS);
                        return TRUE;
                  }

                  break;
      }
      
      LeaveCriticalSection(&m_EventCS);
      return CWnd::PreTranslateMessage(pMsg);
}

0
cookreCommented:
It probably has nothing to do with your problem, but using WM_USER+x for custom message codes is highly deprecated.  You really ought to use RegisterWindowMessage().
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mikexpertAuthor Commented:
Hi cookre,

Thanks for your response.  I took those out and then realized I wasn't even using custom messages (they were defined but I'm not using them)...   As for the RegisterWindowMessage thing, that's good to know.

Cheers,
Mike
0
mikexpertAuthor Commented:
Figured it out - stray pointer...

Thanks for looking guys....

Mike
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Programming

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.