You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1563 lines
36 KiB
C++

// XTPCalendarData.cpp: implementation of the CXTPCalendarData class.
//
// This file is a part of the XTREME CALENDAR MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Common/XTPNotifyConnection.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPSmartPtrInternalT.h"
#include "XTPCalendarDefines.h"
#include "XTPCalendarUtils.h"
#include "XTPCalendarNotifications.h"
#include "XTPCalendarOptions.h"
#include "XTPCalendarPtrCollectionT.h"
#include "XTPCalendarEvent.h"
#include "XTPCalendarEvents.h"
#include "XTPCalendarRecurrencePattern.h"
#include "XTPCalendarCustomProperties.h"
#include "XTPCalendarEventLabel.h"
#include "XTPCalendarResource.h"
#include "XTPCalendarData.h"
#include "XTPCalendarMemoryDataProvider.h"
#include "XTPCalendarADO.h"
#include "XTPCalendarDatabaseDataProvider.h"
#include "XTPCalendarMAPIWrapper.h"
#include "XTPCalendarMAPIDataProvider.h"
#include "XTPCalendarCustomDataProvider.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DBG_CACHE_ASSERT ASSERT
#ifndef DBG_CACHE_ASSERT
#define DBG_CACHE_ASSERT
#endif
//===========================================================================
// Summary:
// Define data provider cache hash table size. Should be a prime number!
// like: 503, 1021, 1511, 2003, 3001, 4001, 5003, 6007, 8009, 12007,
// 16001, 32003, 48017, 64007
// See Also: CMap overview
//===========================================================================
#define XTP_DP_CACHE_HASH_TABLE_SIZE 1021
long VAR2long(const COleVariant& oleVar)
{
try
{
_variant_t vtValue((const VARIANT*)&oleVar);
return (long)vtValue;
}
//catch(_com_error e)
catch(...)
{
ASSERT(FALSE);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////
CXTPCalendarData::CXTPDPCache::CXTPDPCache()
{
m_pCacheDP = NULL;
m_eCacheMode = xtpCalendarDPCacheModeOff;
m_mapIsDayInCache.InitHashTable(XTP_DP_CACHE_HASH_TABLE_SIZE, FALSE);
}
CXTPCalendarData::CXTPDPCache::~CXTPDPCache()
{
SafeClose();
}
void CXTPCalendarData::CXTPDPCache::SafeClose()
{
if (m_pCacheDP)
{
if (m_pCacheDP->IsOpen())
{
m_pCacheDP->Close();
}
}
CMDTARGET_RELEASE(m_pCacheDP);
m_eCacheMode = xtpCalendarDPCacheModeOff;
}
void CXTPCalendarData::CXTPDPCache::SafeRemoveAll()
{
if (m_pCacheDP)
{
m_pCacheDP->RemoveAllEvents();
}
m_mapIsDayInCache.RemoveAll();
}
BOOL CXTPCalendarData::CXTPDPCache::IsDayInCache(COleDateTime dtDay)
{
BOOL bIs = FALSE;
return m_mapIsDayInCache.Lookup((DWORD)(DATE)dtDay, bIs) && bIs;
}
void CXTPCalendarData::CXTPDPCache::SetDayInCache(COleDateTime dtDay, BOOL bSet)
{
if (bSet)
{
m_mapIsDayInCache.SetAt((DWORD)(DATE)dtDay, TRUE);
}
else
{
m_mapIsDayInCache.RemoveKey((DWORD)(DATE)dtDay);
}
}
BOOL CXTPCalendarData::CXTPDPCache::IsEventInCache(CXTPCalendarEvent* pEvent)
{
if (!pEvent || !m_pCacheDP)
{
ASSERT(FALSE);
return FALSE;
}
int nRState = pEvent->GetRecurrenceState();
if (nRState == xtpCalendarRecurrenceNotRecurring ||
nRState == xtpCalendarRecurrenceMaster)
{
DWORD dwEventID = pEvent->GetEventID();
CXTPCalendarEventPtr ptrEvInCache = m_pCacheDP->GetEvent(dwEventID);
return ptrEvInCache != NULL;
}
else
{
ASSERT(nRState == xtpCalendarRecurrenceOccurrence || nRState == xtpCalendarRecurrenceException);
DWORD dwRPatternID = pEvent->GetRecurrencePatternID();
CXTPCalendarRecurrencePatternPtr ptrRPattern = m_pCacheDP->GetRecurrencePattern(dwRPatternID);
return ptrRPattern != NULL;
}
}
void CXTPCalendarData::CXTPDPCache::_AddToCacheIfNeed(CXTPCalendarRecurrencePattern* pPattern)
{
ASSERT(pPattern);
if (!pPattern || !m_pCacheDP)
{
return;
}
DWORD dwRPatternID = pPattern->GetPatternID();
CXTPCalendarRecurrencePatternPtr ptrRPattern = m_pCacheDP->GetRecurrencePattern(dwRPatternID);
if (ptrRPattern)
{
return;
}
#ifdef _DEBUG
{
DWORD dwMasterEventID = pPattern->GetMasterEventID();
CXTPCalendarEventPtr ptrMasterEvent = m_pCacheDP->GetEvent(dwMasterEventID);
ASSERT(ptrMasterEvent == NULL);
}
#endif
CXTPCalendarEventPtr ptrMasterEvent = pPattern->GetMasterEvent(); // this call also add master event to cache
ASSERT(ptrMasterEvent);
if (ptrMasterEvent)
{
// Must be added to cache in call: pPattern->GetMasterEvent();
//
DWORD dwMasterEventID = ptrMasterEvent->GetEventID();
CXTPCalendarEventPtr ptrEvInCache = m_pCacheDP->GetEvent(dwMasterEventID);
DBG_CACHE_ASSERT(ptrEvInCache);
if (!ptrEvInCache)
{
// this strange, but add if it is still not here
VERIFY(m_pCacheDP->AddEvent(ptrMasterEvent));
}
}
}
void CXTPCalendarData::CXTPDPCache::AddToCacheIfNeed(CXTPCalendarEvent* pEvent)
{
ASSERT(pEvent);
if (!pEvent || !m_pCacheDP)
{
return;
}
int nRState = pEvent->GetRecurrenceState();
if (nRState == xtpCalendarRecurrenceNotRecurring ||
nRState == xtpCalendarRecurrenceMaster)
{
DWORD dwEventID = pEvent->GetEventID();
CXTPCalendarEventPtr ptrEvInCache = m_pCacheDP->GetEvent(dwEventID);
if (!ptrEvInCache)
{
VERIFY(m_pCacheDP->AddEvent(pEvent));
}
}
else
{
// From previous version.
// Non-Optimal. Should not be called.
ASSERT(FALSE);
}
}
void CXTPCalendarData::CXTPDPCache::AddToCache(CXTPCalendarEvents* pEvents, COleDateTime dtDay)
{
if (!pEvents)
{
return;
}
int nCount = pEvents->GetCount();
for (int i = 0; i < nCount; i++)
{
CXTPCalendarEvent* pEvent = pEvents->GetAt(i ,FALSE);
AddToCacheIfNeed(pEvent);
}
SetDayInCache(dtDay, TRUE);
}
void CXTPCalendarData::SetCacheMode(int eCacheMode, CXTPCalendarData* pCacheDataProvider)
{
if (eCacheMode == xtpCalendarDPCacheModeOff)
{
m_cache.SafeClose();
}
else
{
if (!m_cache.m_pCacheDP && !pCacheDataProvider)
{
m_cache.m_pCacheDP = new CXTPCalendarMemoryDataProvider();
}
else if (!m_cache.m_pCacheDP && pCacheDataProvider)
{
m_cache.m_pCacheDP = pCacheDataProvider;
}
else if (m_cache.m_pCacheDP && pCacheDataProvider)
{
m_cache.SafeClose();
m_cache.m_pCacheDP = pCacheDataProvider;
}
else
{
ASSERT(m_cache.m_pCacheDP && !pCacheDataProvider);
}
if (!m_cache.m_pCacheDP)
{
return;
}
if (!m_cache.m_pCacheDP->IsOpen())
{
VERIFY( m_cache.m_pCacheDP->Open() );
}
m_cache.SafeRemoveAll();
m_cache.m_eCacheMode = eCacheMode;
}
}
void CXTPCalendarData::ClearCache()
{
m_cache.SafeRemoveAll();
}
void CXTPCalendarData::RemoveAllEvents()
{
if (!IsOpen())
{
ASSERT(FALSE);
return;
}
m_cache.SafeRemoveAll();
DoRemoveAllEvents();
}
//////////////////////////////////////////////////////////////////////////
DWORD CXTPCalendarData::ms_dwNextFreeTempID = DWORD(-1);
//===========================================================================
IMPLEMENT_DYNAMIC(CXTPCalendarData, CCmdTarget)
CXTPCalendarData::CXTPCalendarData()
{
m_pCalendarOptions = NULL;
m_bOwnershipMode = FALSE;
m_bOpened = FALSE;
m_pConnection = new CXTPNotifyConnection();
m_bDisableNotificationsSending = FALSE;
m_pLabelList = new CXTPCalendarEventLabels();
m_pLabelList->InitDefaultValues();
m_typeProvider = xtpCalendarDataProviderUnknown;
m_pCustomProperties = new CXTPCalendarCustomProperties();
m_pSchedules = new CXTPCalendarSchedules();
m_pEventCategories = new CXTPCalendarEventCategories();
m_pEventCategories->InitDefaultValues();
}
CXTPCalendarData::~CXTPCalendarData()
{
if (m_pCalendarOptions)
{
m_pCalendarOptions->SetDataProvider(NULL);
}
ASSERT(!m_pCalendarOptions);
//CMDTARGET_RELEASE(m_pCalendarOptions);
CMDTARGET_RELEASE(m_pLabelList);
CMDTARGET_RELEASE(m_pConnection);
CMDTARGET_RELEASE(m_pCustomProperties);
CMDTARGET_RELEASE(m_pSchedules);
CMDTARGET_RELEASE(m_pEventCategories);
}
void CXTPCalendarData::SetLabelList(CXTPCalendarEventLabels* pLabelList)
{
CMDTARGET_RELEASE(m_pLabelList);
m_pLabelList = pLabelList;
CMDTARGET_ADDREF(m_pLabelList);
}
CXTPCalendarEventPtr CXTPCalendarData::CreateNewEvent(DWORD dwEventID)
{
CXTPCalendarEventPtr ptrEvent = new CXTPCalendarEvent(this);
if (ptrEvent)
{
DWORD dwTempID = dwEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID ? dwEventID: GetNextFreeTempID();
ptrEvent->SetEventID(dwTempID);
}
return ptrEvent;
}
CXTPCalendarRecurrencePatternPtr CXTPCalendarData::CreateNewRecurrencePattern(DWORD dwPatternID)
{
CXTPCalendarRecurrencePatternPtr ptrPattern = new CXTPCalendarRecurrencePattern(this);
if (ptrPattern)
{
DWORD dwTempID = dwPatternID != XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID? dwPatternID : GetNextFreeTempID();
ptrPattern->SetPatternID(dwTempID);
}
return ptrPattern;
}
CString CXTPCalendarData::GetDataSource()
{
return DataSourceFromConStr(m_strConnectionString);
}
CXTPCalendarEventsPtr CXTPCalendarData::RetrieveDayEvents(COleDateTime dtDay)
{
if (!IsOpen())
{
DBG_DATA_ASSERT(FALSE);
return NULL;
}
dtDay = CXTPCalendarUtils::ResetTime(dtDay);
CXTPCalendarEventsPtr ptrResult = NULL;
if ((m_cache.m_eCacheMode & xtpCalendarDPCacheModeOnMask) &&
m_cache.IsDayInCache(dtDay))
{
ASSERT(m_cache.m_pCacheDP);
ptrResult = m_cache.m_pCacheDP->RetrieveDayEvents(dtDay);
}
else
{
ptrResult = DoRetrieveDayEvents(dtDay);
if (!ptrResult)
{
return NULL;
}
_PostProcessRecurrenceIfNeed(ptrResult);
if (m_cache.m_eCacheMode & xtpCalendarDPCacheModeOnMask)
{
ASSERT(m_cache.m_pCacheDP);
m_cache.AddToCache(ptrResult, dtDay);
}
_PostProcessOccurrencesFromMaster(dtDay, ptrResult);
_FilterDayEventsInstancesByEndTime(dtDay, ptrResult);
}
return ptrResult;
}
BOOL CXTPCalendarData::AddEvents(CXTPCalendarEvents* pEvents)
{
BOOL bResult = TRUE;
int nEventsCount = pEvents->GetCount();
for (int i = 0; i < nEventsCount; i++)
{
CXTPCalendarEvent* pEvent = pEvents->GetAt(i, FALSE);
if (!AddEvent(pEvent))
{
bResult = FALSE;
}
}
return bResult;
}
BOOL CXTPCalendarData::AddEvent(CXTPCalendarEvent* pEvent)
{
if (!IsOpen())
{
return FALSE;
}
if (!pEvent)
{
ASSERT(FALSE);
return FALSE;
}
pEvent->ClearIntermediateData();
COleDateTime dtNow = CXTPCalendarUtils::GetCurrentTime();
pEvent->SetLastModificationTime(dtNow);
DWORD dwNewEventID = pEvent->GetEventID();
if (!DoCreate_Event(pEvent, dwNewEventID))
{
DBG_DATA_ASSERT(FALSE);
return FALSE;
}
ASSERT(dwNewEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID);
pEvent->SetEventID(dwNewEventID);
int nRState = (long)pEvent->GetRecurrenceState();
BOOL bSendPatternAddedEvent = FALSE;
DWORD dwPatternID = XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID;
//- Process Recurrence Pattern for Master event -------------------------
if (nRState == xtpCalendarRecurrenceMaster)
{
CXTPCalendarRecurrencePattern* pPatternRef = pEvent->GetRPatternRef();
if (!pPatternRef)
{
ASSERT(FALSE);
return FALSE;
}
pPatternRef->SetMasterEventID(dwNewEventID);
//pPatternRef->ResetReminderForOccFromThePast(pEvent);
VERIFY( pPatternRef->GetOccReminders()->Save(pPatternRef->GetCustomProperties(), pPatternRef) );
BOOL bRes = DoCreate_RPattern(pPatternRef, dwPatternID);
DBG_DATA_ASSERT(bRes);
pPatternRef->GetOccReminders()->ClearProperties(pPatternRef->GetCustomProperties());
if (!bRes)
{
return FALSE;
}
ASSERT(dwPatternID != XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID);
DWORD dwPatternID_prev = pEvent->GetRecurrencePatternID();
pEvent->SetRecurrencePatternID(dwPatternID);
if (dwPatternID_prev != dwPatternID)
{
bRes = DoUpdate_Event(pEvent);
DBG_DATA_ASSERT(bRes);
if (!bRes)
{
return FALSE;
}
}
bSendPatternAddedEvent = TRUE;
}
//---------------------------------------------------------------------------
if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnRepeat)
{
ASSERT(m_cache.m_pCacheDP);
if (m_cache.m_pCacheDP) VERIFY( m_cache.m_pCacheDP->AddEvent(pEvent) );
}
else if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnClear)
{
ASSERT(m_cache.m_pCacheDP);
//m_cache.m_pCacheDP->RemoveAllEvents();
m_cache.SafeRemoveAll();
}
//---------------------------------------------------------------------------
SendNotification(XTP_NC_CALENDAREVENTWASADDED, (WPARAM)pEvent->GetEventID(), (LPARAM)pEvent);
if (bSendPatternAddedEvent)
{
SendNotification(XTP_NC_CALENDARPATTERNWASADDED, dwPatternID, 0);
}
return TRUE;
}
BOOL CXTPCalendarData::ChangeEvent(CXTPCalendarEvent* pEvent)
{
if (!IsOpen())
{
return FALSE;
}
if (!pEvent)
{
ASSERT(FALSE);
return FALSE;
}
pEvent->ClearIntermediateData();
COleDateTime dtNow = CXTPCalendarUtils::GetCurrentTime();
pEvent->SetLastModificationTime(dtNow);
DWORD dwEventID = pEvent->GetEventID();
ASSERT(dwEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID);
//- new recurrence state ---------------------------
CXTPCalendarRecurrencePatternPtr ptrPattern_new;
int nRState_new = pEvent->GetRecurrenceState();
// - Add/Update/Remove Recurrence Exception --------------------
if (nRState_new == xtpCalendarRecurrenceException ||
nRState_new == xtpCalendarRecurrenceOccurrence)
{
return _ChangeRExceptionOccurrence_nf(pEvent, FALSE);
}
//===========================================================================
//CXTPCalendarEventPtr ptrEventPrev = _GetEvent_UseCache(dwEventID);
CXTPCalendarEventPtr ptrEventPrev = GetEvent(dwEventID);
if (!ptrEventPrev)
{
ASSERT(FALSE);
return FALSE;
}
//************************************************************
CXTPCalendarRecurrencePatternPtr ptrPattern_prev;
BOOL bSendPatternAddedEvent = FALSE;
BOOL bSendPatternChangedEvent = FALSE;
BOOL bSendPatternDeletedEvent = FALSE;
DWORD dwPatternID = XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID;
//- previous recurrence state ---------------------
int nRState_prev = ptrEventPrev->GetRecurrenceState();
//=== Update Event Recurrence Properties. IF NEED.
//
// 1.Event become recurrence
if (nRState_prev == xtpCalendarRecurrenceNotRecurring &&
nRState_new == xtpCalendarRecurrenceMaster)
{
ptrPattern_new.SetPtr(pEvent->GetRPatternRef(), TRUE);
// ptrPattern_new->ResetReminderForOccFromThePast(pEvent);
if (!_AddRPatternWithExceptions(ptrPattern_new))
{
ASSERT(FALSE);
return FALSE;
}
dwPatternID = ptrPattern_new->GetPatternID();
ASSERT(dwPatternID != XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID);
pEvent->SetRecurrencePatternID(dwPatternID);
bSendPatternAddedEvent = TRUE;
}
// 2.Event become Not Recurrence
else if (nRState_prev == xtpCalendarRecurrenceMaster &&
nRState_new == xtpCalendarRecurrenceNotRecurring)
{
ptrPattern_prev.SetPtr(ptrEventPrev->GetRPatternRef(), TRUE);
dwPatternID = ptrPattern_prev->GetPatternID();
bSendPatternDeletedEvent = TRUE;
if (!_RemoveRPatternWithExceptions(ptrPattern_prev))
{
ASSERT(FALSE);
return FALSE;
}
}
// 3. Update Recurrence Event
else if (nRState_prev == xtpCalendarRecurrenceMaster &&
nRState_new == xtpCalendarRecurrenceMaster)
{
ptrPattern_new.SetPtr(pEvent->GetRPatternRef(), TRUE);
//ptrPattern_new->ResetReminderForOccFromThePast(pEvent);
if (!_ChangeRPatternWithExceptions(ptrPattern_new))
{
DBG_DATA_ASSERT(FALSE);
return FALSE;
}
dwPatternID = ptrPattern_new->GetPatternID();
bSendPatternChangedEvent = TRUE;
}
// Update Event properties
BOOL bRes = DoUpdate_Event(pEvent);
DBG_DATA_ASSERT(bRes);
if (!bRes)
{
return FALSE;
}
//---------------------------------------------------------------------------
if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnRepeat)
{
ASSERT(m_cache.m_pCacheDP);
if (m_cache.IsEventInCache(pEvent))
{
if (m_cache.m_pCacheDP) VERIFY( m_cache.m_pCacheDP->ChangeEvent(pEvent) );
}
}
else if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnClear)
{
ASSERT(m_cache.m_pCacheDP);
//m_cache.m_pCacheDP->RemoveAllEvents();
m_cache.SafeRemoveAll();
}
//---------------------------------------------------------------------------
SendNotification(XTP_NC_CALENDAREVENTWASCHANGED, (WPARAM)pEvent->GetEventID(), (LPARAM)pEvent);
if (bSendPatternAddedEvent)
{
SendNotification(XTP_NC_CALENDARPATTERNWASADDED, dwPatternID, 0);
}
else if (bSendPatternChangedEvent)
{
SendNotification(XTP_NC_CALENDARPATTERNWASCHANGED, dwPatternID, 0);
}
else if (bSendPatternDeletedEvent)
{
SendNotification(XTP_NC_CALENDARPATTERNWASDELETED, dwPatternID, 0);
}
return TRUE;
}
BOOL CXTPCalendarData::DeleteEvent(CXTPCalendarEvent* pEvent)
{
if (!IsOpen())
{
return FALSE;
}
if (!pEvent)
{
ASSERT(FALSE);
return FALSE;
}
DWORD dwEventID = pEvent->GetEventID();
ASSERT(dwEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID);
BOOL bRes = TRUE;
BOOL bSendPatternDeletedEvent = FALSE;
DWORD dwPatternID = XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID;
//- recurrence state ---------------------
int nRState = pEvent->GetRecurrenceState();
//1. remove occurrence (set deleted property to exception)
if (nRState == xtpCalendarRecurrenceOccurrence || nRState == xtpCalendarRecurrenceException)
{
CXTPCalendarEventPtr ptrException = pEvent->CloneEvent();
if (!ptrException)
{
return FALSE;
}
if (nRState == xtpCalendarRecurrenceOccurrence)
{
// make exception from Occurrence
ptrException->MakeAsRException();
}
ptrException->SetRExceptionDeleted(TRUE);
return _ChangeRExceptionOccurrence_nf(ptrException, TRUE);
}
else
{
if (!DoDelete_Event(pEvent))
{
bRes = FALSE;
}
//-----------------------------------------------------------------
if (nRState == xtpCalendarRecurrenceMaster)
{
dwPatternID = pEvent->GetRecurrencePatternID();
CXTPCalendarRecurrencePattern* pPattern = pEvent->GetRPatternRef();
if (!_RemoveRPatternWithExceptions(pPattern))
{
bRes = FALSE;
}
bSendPatternDeletedEvent = bRes;
}
}
//---------------------------------------------------------------------------
if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnRepeat)
{
ASSERT(m_cache.m_pCacheDP);
if (m_cache.IsEventInCache(pEvent))
{
if (m_cache.m_pCacheDP) VERIFY( m_cache.m_pCacheDP->DeleteEvent(pEvent) );
}
}
else if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnClear)
{
ASSERT(m_cache.m_pCacheDP);
//m_cache.m_pCacheDP->RemoveAllEvents();
m_cache.SafeRemoveAll();
}
//---------------------------------------------------------------------------
if (bRes)
{
SendNotification(XTP_NC_CALENDAREVENTWASDELETED, (WPARAM)pEvent->GetEventID(), (LPARAM)pEvent);
}
if (bSendPatternDeletedEvent)
{
SendNotification(XTP_NC_CALENDARPATTERNWASDELETED, dwPatternID, 0);
}
return bRes;
}
CXTPCalendarEventPtr CXTPCalendarData::GetEvent(DWORD dwEventID)
{
if (!IsOpen())
{
return NULL;
}
CXTPCalendarEventPtr ptrEvent;
if ((m_cache.m_eCacheMode & xtpCalendarDPCacheModeOnMask))
{
ASSERT(m_cache.m_pCacheDP);
if (m_cache.m_pCacheDP) ptrEvent = m_cache.m_pCacheDP->GetEvent(dwEventID);
}
if (!ptrEvent)
{
ptrEvent = _GetEvent_raw(dwEventID);
if (!ptrEvent)
return NULL;
if (ptrEvent->GetRecurrenceState() != xtpCalendarRecurrenceNotRecurring &&
ptrEvent->GetRecurrenceState() != xtpCalendarRecurrenceMaster)
{
return NULL;
}
if (m_cache.m_eCacheMode & xtpCalendarDPCacheModeOnMask)
{
ASSERT(m_cache.m_pCacheDP);
m_cache.AddToCacheIfNeed(ptrEvent);
}
}
return ptrEvent;
}
BOOL CXTPCalendarData::_PostProcessRecurrenceIfNeed(CXTPCalendarEvent* pEvent)
{
COleVariant varRState;
COleVariant varRPatternID;
BOOL bRState_prop = pEvent->GetCustomProperties()->GetProperty(cszProcess_RecurrenceState, varRState);
BOOL bRPatternID_prop = pEvent->GetCustomProperties()->GetProperty(cszProcess_RecurrencePatternID, varRPatternID);
pEvent->GetCustomProperties()->RemoveProperty(cszProcess_RecurrenceState);
pEvent->GetCustomProperties()->RemoveProperty(cszProcess_RecurrencePatternID);
if (!bRState_prop)
{
return FALSE;
}
int nRState = VAR2long(varRState);
if (xtpCalendarRecurrenceMaster == nRState)
{
if (!bRPatternID_prop)
{
ASSERT(FALSE);
return FALSE;
}
DWORD dwRPatternID = (DWORD)VAR2long(varRPatternID);
CXTPCalendarRecurrencePatternPtr ptrPattern = _GetRecurrencePattern_raw(dwRPatternID);
if (!ptrPattern)
{
ASSERT(FALSE);
return FALSE;
}
VERIFY( pEvent->MakeEventAsRecurrence() );
pEvent->SetRecurrencePatternID(dwRPatternID);
VERIFY( pEvent->UpdateRecurrence(ptrPattern) );
return TRUE;
}
else if (xtpCalendarRecurrenceException == nRState)
{
DWORD dwRPatternID = bRPatternID_prop ? (DWORD)VAR2long(varRPatternID) : 0;
pEvent->SetRecurrencePatternID(dwRPatternID);
if (pEvent->GetRecurrenceState() != xtpCalendarRecurrenceException)
{
pEvent->MakeAsRException(dwRPatternID);
}
}
return FALSE;
}
void CXTPCalendarData::_PostProcessRecurrenceIfNeed(CXTPCalendarEvents* pEvents)
{
int nCount = pEvents ? pEvents->GetCount() : 0;
for (int i = 0; i < nCount; i++)
{
CXTPCalendarEvent* pEvent = pEvents->GetAt(i, FALSE);
ASSERT(pEvent);
if (pEvent)
{
_PostProcessRecurrenceIfNeed(pEvent);
}
}
}
CXTPCalendarEventPtr CXTPCalendarData::_GetEvent_raw(DWORD dwEventID)
{
if (!IsOpen())
{
return NULL;
}
CXTPCalendarEventPtr ptrEvent = DoRead_Event(dwEventID);
if (!ptrEvent)
{
return NULL;
}
_PostProcessRecurrenceIfNeed(ptrEvent);
return ptrEvent;
}
CXTPCalendarRecurrencePatternPtr CXTPCalendarData::_GetRecurrencePattern_raw(DWORD dwPatternID)
{
CXTPCalendarRecurrencePatternPtr ptrPattern = DoRead_RPattern(dwPatternID);
if (ptrPattern)
{
VERIFY( ptrPattern->GetOccReminders()->Load(ptrPattern->GetCustomProperties()) );
ptrPattern->GetOccReminders()->ClearProperties(ptrPattern->GetCustomProperties());
}
return ptrPattern;
}
CXTPCalendarRecurrencePatternPtr CXTPCalendarData::GetRecurrencePattern(DWORD dwPatternID)
{
if (!IsOpen())
{
return NULL;
}
CXTPCalendarRecurrencePatternPtr ptrPattern;
if ((m_cache.m_eCacheMode & xtpCalendarDPCacheModeOnMask))
{
ASSERT(m_cache.m_pCacheDP);
if (m_cache.m_pCacheDP) ptrPattern = m_cache.m_pCacheDP->GetRecurrencePattern(dwPatternID);
}
if (!ptrPattern)
{
ptrPattern = _GetRecurrencePattern_raw(dwPatternID);
if (ptrPattern && (m_cache.m_eCacheMode & xtpCalendarDPCacheModeOnMask))
{
m_cache._AddToCacheIfNeed(ptrPattern);
}
}
return ptrPattern;
}
BOOL CXTPCalendarData::_AddRPatternWithExceptions(CXTPCalendarRecurrencePattern* pPattern)
{
if (!IsOpen())
{
return FALSE;
}
if (!pPattern)
{
ASSERT(FALSE);
return FALSE;
}
VERIFY( pPattern->GetOccReminders()->Save(pPattern->GetCustomProperties(), pPattern) );
DWORD dwNewPatternID = XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID;
BOOL bRes = DoCreate_RPattern(pPattern, dwNewPatternID);
DBG_DATA_ASSERT(bRes);
pPattern->GetOccReminders()->ClearProperties(pPattern->GetCustomProperties());
if (!bRes)
{
return FALSE;
}
ASSERT(dwNewPatternID != XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID);
pPattern->SetPatternID(dwNewPatternID);
BOOL bResult = TRUE;
//-- Process exceptions ---------------------------------------------------
CXTPCalendarEventsPtr prtExceptions = pPattern->GetExceptions();
pPattern->RemoveAllExceptions();
int nCount = prtExceptions ? prtExceptions->GetCount() : 0;
for (int i = 0; i < nCount; i++)
{
CXTPCalendarEvent* pExc = prtExceptions->GetAt(i);
ASSERT(pExc);
if (!pExc)
continue;
DWORD dwNewEventID = XTP_CALENDAR_UNKNOWN_EVENT_ID;
if (!DoCreate_Event(pExc, dwNewEventID))
{
bResult = FALSE;
continue;
}
ASSERT(dwNewEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID);
pExc->SetEventID(dwNewEventID);
pPattern->SetException(pExc);
}
//-------------------------------------------
return bResult;
}
BOOL CXTPCalendarData::_RemoveRPatternWithExceptions(CXTPCalendarRecurrencePattern* pPattern)
{
if (!IsOpen())
{
return FALSE;
}
if (!pPattern)
{
ASSERT(FALSE);
return FALSE;
}
BOOL bResult = TRUE;
//-- Process exceptions ---------------------------------------------------
CXTPCalendarEventsPtr prtExceptions = pPattern->GetExceptions();
int nCount = prtExceptions ? prtExceptions->GetCount() : 0;
for (int i = 0; i < nCount; i++)
{
CXTPCalendarEvent *pExc = prtExceptions->GetAt(i);
ASSERT(pExc);
if (!DoDelete_Event(pExc))
{
bResult = FALSE;
}
}
//-------------------------------------------
if (!DoDelete_RPattern(pPattern))
{
return FALSE;
}
//-------------------------------------------
return bResult;
}
BOOL CXTPCalendarData::_ChangeRPatternWithExceptions(CXTPCalendarRecurrencePattern* pPattern)
{
if (!IsOpen())
{
return FALSE;
}
if (!pPattern)
{
ASSERT(FALSE);
return FALSE;
}
DWORD dwPatternID = pPattern->GetPatternID();
//CXTPCalendarRecurrencePatternPtr ptrPatternPrev = _GetRecurrencePattern_UseCache(dwPatternID);
CXTPCalendarRecurrencePatternPtr ptrPatternPrev = GetRecurrencePattern(dwPatternID);
if (!ptrPatternPrev)
{
ASSERT(FALSE);
return FALSE;
}
//-------------------------------------
VERIFY( pPattern->GetOccReminders()->Save(pPattern->GetCustomProperties(), pPattern) );
BOOL bRes = DoUpdate_RPattern(pPattern);
pPattern->GetOccReminders()->ClearProperties(pPattern->GetCustomProperties());
if (!bRes)
{
return FALSE;
}
//-------------------------------------
BOOL bResult = TRUE;
//-- Process exceptions ---------------------------------------------------
CXTPCalendarEventsPtr prtExceptions_prev = ptrPatternPrev->GetExceptions();
CXTPCalendarEventsPtr prtExceptions_new = pPattern->GetExceptions();
//-- find deleted exceptions and remove them from DB
int nCount = (prtExceptions_prev && prtExceptions_new) ? prtExceptions_prev->GetCount() : 0;
int i;
for (i = 0; i < nCount; i++)
{
CXTPCalendarEvent* pExc = prtExceptions_prev->GetAt(i);
DWORD dwExcID = pExc ? pExc->GetEventID() : XTP_CALENDAR_UNKNOWN_EVENT_ID;
int nFIndex = prtExceptions_new->Find(dwExcID);
if (nFIndex < 0)
{
if (!DoDelete_Event(pExc))
{
bResult = FALSE;
}
}
}
//-- update existing or add new exceptions (int DB)
nCount = (prtExceptions_prev && prtExceptions_new) ? prtExceptions_new->GetCount() : 0;
for (i = 0; i < nCount; i++)
{
CXTPCalendarEvent* pExc = prtExceptions_new->GetAt(i);
if (!pExc)
{
ASSERT(FALSE);
continue;
}
DWORD dwExcID = pExc->GetEventID();
int nFIndex = prtExceptions_prev->Find(dwExcID);
if (nFIndex < 0)
{
// Add new exception
DWORD dwNewEventID = XTP_CALENDAR_UNKNOWN_EVENT_ID;
if (!DoCreate_Event(pExc, dwNewEventID))
{
bResult = FALSE;
continue;
}
ASSERT(dwNewEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID);
pExc->SetEventID(dwNewEventID);
VERIFY( pPattern->RemoveException(pExc) );
if (!pPattern->SetException(pExc))
{
bResult = FALSE;
}
}
else
{
// Update existing exception
if (!DoUpdate_Event(pExc))
{
bResult = FALSE;
}
}
}
return bResult;
}
BOOL CXTPCalendarData::_ChangeRExceptionOccurrence_nf(CXTPCalendarEvent* pExcOcc, BOOL bSend_EventDeleted)
{
if (!pExcOcc)
{
ASSERT(FALSE);
return FALSE;
}
pExcOcc->ClearIntermediateData();
DWORD dwEventID = pExcOcc->GetEventID();
ASSERT(dwEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID);
//- new recurrence state ---------------------------
CXTPCalendarRecurrencePatternPtr ptrPattern;
int nRState_new = pExcOcc->GetRecurrenceState();
// - Add/Update/Remove Recurrence Exception --------------------
if (nRState_new != xtpCalendarRecurrenceException &&
nRState_new != xtpCalendarRecurrenceOccurrence)
{
ASSERT(FALSE);
return FALSE;
}
DWORD dwPatternID_new = pExcOcc->GetRecurrencePatternID();
//ptrPattern = _GetRecurrencePattern_UseCache(dwPatternID_new);
ptrPattern = GetRecurrencePattern(dwPatternID_new);
if (!ptrPattern)
{
ASSERT(FALSE);
return FALSE;
}
DWORD dwMasterEventID = ptrPattern->GetMasterEventID();
//CXTPCalendarEventPtr ptrMasterEvent = _GetEvent_UseCache(dwMasterEventID);
CXTPCalendarEventPtr ptrMasterEvent = GetEvent(dwMasterEventID);
if (!ptrMasterEvent)
{
ASSERT(FALSE);
return FALSE;
}
ptrPattern.SetPtr(ptrMasterEvent->GetRPatternRef(), TRUE);
if (!ptrPattern)
{
ASSERT(FALSE);
return FALSE;
}
BOOL bSendPatternChangedEvent = FALSE;
BOOL bRes = FALSE;
if (nRState_new == xtpCalendarRecurrenceException)
{
bRes = ptrPattern->SetException(pExcOcc, ptrMasterEvent);
}
else if (nRState_new == xtpCalendarRecurrenceOccurrence)
{
bRes = ptrPattern->RemoveException(pExcOcc, ptrMasterEvent);
}
else
{
ASSERT(FALSE);
}
if (bRes)
{
bRes = _ChangeRPatternWithExceptions(ptrPattern);
bSendPatternChangedEvent = bRes;
}
if (bRes)
{
bRes = DoUpdate_Event(ptrMasterEvent);
}
//---------------------------------------------------------------------------
if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnRepeat)
{
ASSERT(m_cache.m_pCacheDP);
if (m_cache.IsEventInCache(ptrMasterEvent))
{
if (m_cache.m_pCacheDP) VERIFY( m_cache.m_pCacheDP->ChangeEvent(ptrMasterEvent) );
}
}
else if (m_cache.m_eCacheMode == xtpCalendarDPCacheModeOnClear)
{
ASSERT(m_cache.m_pCacheDP);
//m_cache.m_pCacheDP->RemoveAllEvents();
m_cache.SafeRemoveAll();
}
//---------------------------------------------------------------------------
if (bRes)
{
XTP_NOTIFY_CODE nfCode = bSend_EventDeleted ?
XTP_NC_CALENDAREVENTWASDELETED : XTP_NC_CALENDAREVENTWASCHANGED;
SendNotification(nfCode, (WPARAM)pExcOcc->GetEventID(), (LPARAM)pExcOcc);
}
if (bSendPatternChangedEvent)
{
SendNotification(XTP_NC_CALENDARPATTERNWASCHANGED, ptrPattern->GetPatternID(), 0);
}
return bRes;
}
void CXTPCalendarData::_PostProcessOccurrencesFromMaster(COleDateTime dtDay, CXTPCalendarEvents* pEvents)
{
_PostProcessOccurrencesFromMaster2(dtDay, dtDay, pEvents);
}
void CXTPCalendarData::_PostProcessOccurrencesFromMaster2(COleDateTime dtDayFrom, COleDateTime dtDayTo, CXTPCalendarEvents* pEvents)
{
if (!pEvents)
{
return;
}
int nCount = pEvents->GetCount();
for (int i = nCount - 1; i >= 0; i--)
{
CXTPCalendarEventPtr ptrEvent = pEvents->GetAt(i, TRUE);
if (!ptrEvent)
{
ASSERT(FALSE);
continue;
}
int nRState = ptrEvent->GetRecurrenceState();
if (xtpCalendarRecurrenceMaster == nRState)
{
pEvents->RemoveAt(i);
CXTPCalendarRecurrencePattern* pPattern = ptrEvent->GetRPatternRef();
if (!pPattern)
{
ASSERT(FALSE);
continue;
}
VERIFY(pPattern->GetOccurrences(pEvents, dtDayFrom, dtDayTo, ptrEvent));
}
}
}
void CXTPCalendarData::_FilterDayEventsInstancesByEndTime(COleDateTime dtDay,
CXTPCalendarEvents* pEvents)
{
ASSERT(pEvents);
if (!pEvents)
{
return;
}
dtDay = CXTPCalendarUtils::ResetTime(dtDay);
// filter events;
int nCount = pEvents->GetCount();
for (int i = nCount-1; i >= 0; i--)
{
CXTPCalendarEvent* pEvent = pEvents->GetAt(i);
if (!pEvent)
{
ASSERT(FALSE);
continue;
}
if (pEvent->GetRecurrenceState() == xtpCalendarRecurrenceMaster)
{
continue;
}
if (CXTPCalendarUtils::ResetTime(pEvent->GetStartTime()) < dtDay &&
CXTPCalendarUtils::IsEqual(pEvent->GetEndTime(), dtDay) )
{
pEvents->RemoveAt(i);
}
}
}
void CXTPCalendarData::SendNotification(XTP_NOTIFY_CODE EventCode, WPARAM wParam , LPARAM lParam)
{
if (m_pConnection && !m_bDisableNotificationsSending)
{
m_pConnection->SendEvent(EventCode, wParam, lParam);
}
}
CXTPCalendarEventsPtr CXTPCalendarData::GetUpcomingEvents(COleDateTime dtFrom, COleDateTimeSpan spPeriod)
{
CXTPCalendarEventsPtr ptrEvents = DoGetUpcomingEvents(dtFrom, spPeriod);
_PostProcessRecurrenceIfNeed(ptrEvents);
return ptrEvents;
}
CXTPCalendarEventsPtr CXTPCalendarData::GetAllEvents_raw()
{
CXTPCalendarEventsPtr ptrEvents = DoGetAllEvents_raw();
_PostProcessRecurrenceIfNeed(ptrEvents);
return ptrEvents;
}
void CXTPCalendarData::SetOptionsToUpdate(CXTPCalendarOptions* pOptions)
{
CMDTARGET_ADDREF(pOptions);
CMDTARGET_RELEASE(m_pCalendarOptions);
m_pCalendarOptions = pOptions;
}
CXTPCalendarEventsPtr CXTPCalendarData::DoGetAllEvents_raw()
{
return NULL;
}
CXTPCalendarEventsPtr CXTPCalendarData::DoGetUpcomingEvents(
COleDateTime dtFrom, COleDateTimeSpan spPeriod)
{
UNREFERENCED_PARAMETER(dtFrom); UNREFERENCED_PARAMETER(spPeriod);
//return DoRetrieveAllEvents_raw();
return NULL;
}
CXTPCalendarEventsPtr CXTPCalendarData::DoRetrieveDayEvents(COleDateTime dtDay)
{
UNREFERENCED_PARAMETER(dtDay);
return NULL;
}
void CXTPCalendarData::DoRemoveAllEvents()
{
}
CXTPCalendarEventPtr CXTPCalendarData::DoRead_Event(DWORD dwEventID)
{
UNREFERENCED_PARAMETER(dwEventID);
return NULL;
}
CXTPCalendarRecurrencePatternPtr CXTPCalendarData::DoRead_RPattern(DWORD dwPatternID)
{
UNREFERENCED_PARAMETER(dwPatternID);
return NULL;
}
BOOL CXTPCalendarData::DoCreate_Event(CXTPCalendarEvent* pEvent, DWORD& rdwNewEventID)
{
UNREFERENCED_PARAMETER(pEvent);
UNREFERENCED_PARAMETER(rdwNewEventID);
return TRUE;
}
BOOL CXTPCalendarData::DoUpdate_Event(CXTPCalendarEvent* pEvent)
{
UNREFERENCED_PARAMETER(pEvent);
return TRUE;
}
BOOL CXTPCalendarData::DoDelete_Event(CXTPCalendarEvent* pEvent)
{
UNREFERENCED_PARAMETER(pEvent);
return TRUE;
}
BOOL CXTPCalendarData::DoCreate_RPattern(CXTPCalendarRecurrencePattern* pPattern, DWORD& rdwNewPatternID)
{
UNREFERENCED_PARAMETER(pPattern);
UNREFERENCED_PARAMETER(rdwNewPatternID);
return TRUE;
}
BOOL CXTPCalendarData::DoUpdate_RPattern(CXTPCalendarRecurrencePattern* pPattern)
{
UNREFERENCED_PARAMETER(pPattern);
return TRUE;
}
BOOL CXTPCalendarData::DoDelete_RPattern(CXTPCalendarRecurrencePattern* pPattern)
{
UNREFERENCED_PARAMETER(pPattern);
return TRUE;
}
CString CXTPCalendarData::DataSourceFromConStr(LPCTSTR lpszConnectionString)
{
ASSERT(lpszConnectionString);
if (!lpszConnectionString || 0 == _tcslen(lpszConnectionString))
return _T("");
CString strConnStr_lower = lpszConnectionString;
strConnStr_lower.MakeLower();
int nIndex = strConnStr_lower.Find(_T("data source="));
if (nIndex != -1)
{
CString strDataSource = strConnStr_lower.Mid(nIndex + 12);
if (strDataSource.IsEmpty())
return _T("");
if ((strDataSource[0] == _T('\'') || strDataSource[0] == _T('"')) && strDataSource.GetLength() > 2)
{
TCHAR chQuot = strDataSource[0];
strDataSource.Delete(0);
int nQuot2Idx = strDataSource.Find(chQuot, 0);
if (nQuot2Idx >= 0)
{
strDataSource.Delete(nQuot2Idx, strDataSource.GetLength() - nQuot2Idx);
}
}
return strDataSource;
}
return strConnStr_lower;
}
XTPCalendarDataProvider CXTPCalendarData::DataProviderTypeFromConStr(
LPCTSTR lpszConnectionString,
XTPCalendarDataProvider eDPDefault)
{
ASSERT(lpszConnectionString);
if (!lpszConnectionString)
{
return eDPDefault;
}
CString strConnStr_lower(lpszConnectionString);
strConnStr_lower.MakeLower();
BOOL bProviderCustom = strConnStr_lower.Find(_T("provider=custom")) != -1;
if (bProviderCustom)
{
return xtpCalendarDataProviderCustom;
}
BOOL bProviderMAPI = strConnStr_lower.Find(_T("provider=mapi")) != -1;
if (bProviderMAPI)
{
return xtpCalendarDataProviderMAPI;
}
BOOL bProviderXML = strConnStr_lower.Find(_T("provider=xml")) != -1;
if (bProviderXML)
{
return xtpCalendarDataProviderMemory;
}
BOOL bProvider = strConnStr_lower.Find(_T("provider=")) != -1;
BOOL bDSN = strConnStr_lower.Find(_T("dsn=")) != -1;
if (bProvider || bDSN)
{
return xtpCalendarDataProviderDatabase;
}
return eDPDefault;
}
CXTPCalendarData* CXTPCalendarData::CreateDataProvider(LPCTSTR lpszConnectionString)
{
ASSERT(lpszConnectionString);
if (!lpszConnectionString)
{
return NULL;
}
XTPCalendarDataProvider eDPType = DataProviderTypeFromConStr(lpszConnectionString, xtpCalendarDataProviderMemory);
CXTPCalendarData* pDataProvider = CreateDataProvider(eDPType);
if (pDataProvider)
{
pDataProvider->SetConnectionString(lpszConnectionString);
}
return pDataProvider;
}
CXTPCalendarData* CXTPCalendarData::CreateDataProvider(XTPCalendarDataProvider eDataProvider)
{
CXTPCalendarData* pDataProvider = NULL;
switch (eDataProvider)
{
case xtpCalendarDataProviderMemory:
pDataProvider = new CXTPCalendarMemoryDataProvider();
break;
case xtpCalendarDataProviderDatabase:
pDataProvider = new CXTPCalendarDatabaseDataProvider();
break;
case xtpCalendarDataProviderMAPI:
pDataProvider = new CXTPCalendarMAPIDataProvider();
break;
case xtpCalendarDataProviderCustom:
pDataProvider = new CXTPCalendarCustomDataProvider();
break;
default:
ASSERT(FALSE);
}
return pDataProvider;
}