[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 507
  • Last Modified:

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
0
mikexpert
Asked:
mikexpert
  • 3
2 Solutions
 
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
 
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

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now