/** * @file XTPCalendarView.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" #include "Common/Base/Diagnostic/XTPDisableAdvancedWarnings.h" #include #include "Common/Base/Diagnostic/XTPEnableAdvancedWarnings.h" #include "Common/XTPTypeId.h" #include "Common/XTPCasting.h" #include "Common/XTPFramework.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPXMLHelpers.h" #include "Common/PropExchange/XTPPropExchangeSection.h" #include "Common/XTPPropExchange.h" #include "Common/PropExchange/XTPPropExchangeEnumerator.h" #include "Common/PropExchange/XTPPropExchangeEnumeratorPtr.h" #include "Common/PropExchange/XTPPropExchangeArchive.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPSmartPtrInternalT.h" #include "Common/XTPNotifyConnection.h" #include "Common/XTPColorManager.h" #include "Common/XTPImageManager.h" #include "Calendar/XTPCalendarDefines.h" #include "Calendar/XTPCalendarUtils.h" #include "Calendar/XTPCalendarPtrCollectionT.h" #include "Calendar/XTPCalendarNotifications.h" #include "Calendar/XTPCalendarOptions.h" #include "Calendar/XTPCalendarTimeZoneHelper.h" #include "Calendar/XTPCalendarResource.h" #include "Calendar/XTPCalendarEvent.h" #include "Calendar/XTPCalendarEvents.h" #include "Calendar/XTPCalendarView.h" #include "Calendar/XTPCalendarViewEvent.h" #include "Calendar/XTPCalendarViewDay.h" #include "Calendar/XTPCalendarTimeLineView.h" #include "Calendar/XTPCalendarViewPart.h" #include "Calendar/XTPCalendarControl.h" #include "Calendar/XTPCalendarData.h" #include "Calendar/XTPCalendarPaintManager.h" #include "Calendar/XTPCalendarTheme.h" #include "Calendar/XTPCalendarThemePrevNextEventButton.h" #include "Calendar/XTPCalendarThemePrevNextEventButtons.h" #include "Calendar/XTPCalendarThemeOffice2007.h" #include "Calendar/XTPCalendarIIDs.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define XTP_CLIPBOARD_EVENTS_DATA_VER 2 union XTP_EDIT_OPERATION_PARAMS { XTP_EVENT_EDIT_OPERATION_PARAMS header; XTP_EVENT_PASTE_OPERATION_PARAMS pasteParams; XTP_EVENT_IN_PLACE_CREATE_EVENT_OPERATION_PARAMS inPlaceCreateEventParams; XTP_EVENT_DRAG_OPERATION_PARAMS dragOperationParams; }; class CXTPCalendarView::CUndoBuffer { public: //----------------------------------------------------------------------- // Summary: // Default class constructor. //----------------------------------------------------------------------- CUndoBuffer(){}; //----------------------------------------------------------------------- // Summary: // Default class destructor. //----------------------------------------------------------------------- virtual ~CUndoBuffer() { RemoveAll(); }; //----------------------------------------------------------------------- // Summary: // This member function is used to add an Undo action to the buffer. // Parameters: // pPrev - A CXTPCalendarEvent object that contains the instance // before the edit action. // pNew - A CXTPCalendarEvent that contains the instance after // the edit action. //----------------------------------------------------------------------- void AddUndoAction(CXTPCalendarEvent* pPrev, CXTPCalendarEvent* pNew) { CXTPCalendarEventPtr ptrPrevCopy; if (pPrev) ptrPrevCopy = pPrev->CloneEvent(); CXTPCalendarEventPtr ptrNewCopy; if (pNew) ptrNewCopy = pNew->CloneEvent(); m_arUndoActions.Add(SUndoAction(ptrPrevCopy, ptrNewCopy)); } //----------------------------------------------------------------------- // Summary: // Call this member function to clear the Undo buffer. //----------------------------------------------------------------------- void RemoveAll() { m_arUndoActions.RemoveAll(); } //----------------------------------------------------------------------- // Summary: // This member function is used to search for an undo action for a // specified event in the buffer. // Parameters: // pEvent - A CXTPCalendarEvent object to search for in the buffer. // Returns: // A BOOL. TRUE if undo action for a specified event exists in the // buffer. FALSE otherwise. //----------------------------------------------------------------------- BOOL IsInUndoBuffer(CXTPCalendarEvent* pEvent) { int nCount = (int)m_arUndoActions.GetSize(); for (int i = nCount - 1; i >= 0; i--) { SUndoAction& rAction = m_arUndoActions.ElementAt(i); if (!!rAction.ptrPrev && rAction.ptrPrev->IsEqualIDs(pEvent) || !!rAction.ptrNew && rAction.ptrNew->IsEqualIDs(pEvent)) { return TRUE; } } return FALSE; } //----------------------------------------------------------------------- // Summary: // Call this member function to obtain the number of undo actions. // Returns: // An int that contains the number of Undo actions. //----------------------------------------------------------------------- int GetCount() const { return (int)m_arUndoActions.GetSize(); } //----------------------------------------------------------------------- // Summary: // Call this member function to obtain the first undo event. // Returns: // A CXTPCalendarEvent object that contains the first undo event // or NULL if there are no undo events. //----------------------------------------------------------------------- CXTPCalendarEventPtr GetFirstUndoEvent() { int nCount = (int)m_arUndoActions.GetSize(); if (nCount > 0) { SUndoAction& rAction = m_arUndoActions.ElementAt(0); if (rAction.ptrPrev) { return rAction.ptrPrev; } else if (rAction.ptrNew) { return rAction.ptrNew; } } return NULL; } //----------------------------------------------------------------------- // Summary: // This member function is used to search for the first action for // a specified event in the buffer. // Parameters: // pEvent - A CXTPCalendarEvent object that contains the event to // search for in the buffer. // Returns: // A CXTPCalendarEvent that contains the oldest event object from // all of the editing actions or NULL if there are no events. //----------------------------------------------------------------------- CXTPCalendarEventPtr UndoAllForEvent(CXTPCalendarEvent* pEvent) { int nCount = (int)m_arUndoActions.GetSize(); for (int i = 0; i < nCount; i++) { SUndoAction& rAction = m_arUndoActions.ElementAt(i); if (!!rAction.ptrPrev && rAction.ptrPrev->IsEqualIDs(pEvent) || !!rAction.ptrNew && rAction.ptrNew->IsEqualIDs(pEvent)) { return rAction.ptrPrev; } } return NULL; } //----------------------------------------------------------------------- // Summary: // This member function is used to search for last action for a // specified event in the buffer. // Parameters: // pEvent - A CXTPCalendarEvent object that contains the event // to search for in the buffer. // Returns: // A CXTPCalendarEvent that contains the latest event object from // all of the editing actions or NULL if there are no events. //----------------------------------------------------------------------- CXTPCalendarEventPtr RedoAllForEvent(CXTPCalendarEvent* pEvent) { CXTPCalendarEventPtr ptrResult; int nCount = (int)m_arUndoActions.GetSize(); for (int i = nCount - 1; i >= 0; i--) { SUndoAction& rAction = m_arUndoActions.ElementAt(i); if (!!rAction.ptrPrev && rAction.ptrPrev->IsEqualIDs(pEvent) || !!rAction.ptrNew && rAction.ptrNew->IsEqualIDs(pEvent)) { return rAction.ptrNew; } } return NULL; } //----------------------------------------------------------------------- // Summary: // This member function is used to clear the current buffer of all // undo actions and then add new undo actions to the buffer from // the source object. // Parameters: // rSrc - A CUndoBuffer object that contains the new undo actions // to add to the undo buffer object. //----------------------------------------------------------------------- void Set(CUndoBuffer& rSrc) { m_arUndoActions.RemoveAll(); m_arUndoActions.Append(rSrc.m_arUndoActions); } protected: //----------------------------------------------------------------------- // Remarks: // Helper structure to store editing/undo actions. //----------------------------------------------------------------------- struct SUndoAction { CXTPCalendarEventPtr ptrPrev; // Event instance before edit action. CXTPCalendarEventPtr ptrNew; // Event instance after edit action. //----------------------------------------------------------------------- // Summary: // Default class constructor. // Parameters: // pPrev - A CXTPCalendarEvent object that contains the instance // before the edit action. // pNew - A CXTPCalendarEvent object that contains the instance // after the edit action. //----------------------------------------------------------------------- SUndoAction(CXTPCalendarEvent* pPrev = NULL, CXTPCalendarEvent* pNew = NULL) : ptrPrev(pPrev, TRUE) , ptrNew(pNew, TRUE){}; //----------------------------------------------------------------------- // Parameters: // src - A SUndoAction object that contains the source object. // Summary: // Copy class constructor. //----------------------------------------------------------------------- SUndoAction(const SUndoAction& src) { *this = src; } //----------------------------------------------------------------------- // Summary: // Default class destructor. //----------------------------------------------------------------------- virtual ~SUndoAction() { } //----------------------------------------------------------------------- // Summary: // This is the overloaded assignment operator. // Parameters: // src - Source object. // Returns: // A reference to the current object. // Remarks: // Copy class operator. //----------------------------------------------------------------------- const SUndoAction& operator=(const SUndoAction& src) { ptrPrev = src.ptrPrev; ptrNew = src.ptrNew; return *this; } }; CArray m_arUndoActions; // Array of editing/undo actions. }; //=========================================================================== IMPLEMENT_DYNAMIC(CXTPCalendarWMHandler, CXTPCmdTarget) IMPLEMENT_DYNAMIC(CXTPCalendarView, CXTPCalendarWMHandler) ///////////////////////////////////////////////////////////////////////////// #ifdef _XTP_ACTIVEX # define XTP_CALENDAR_VIEWSELPROP_DECLARE(oleType, propName) \ oleType OleGet##propName(); \ void OleSet##propName(oleType); # define XTP_CALENDAR_VIEWSELPROP_IMPLEMENT(oleType, propName, sbMember) \ oleType CXTPCalendarViewSelection::OleGet##propName() \ { \ if (!m_pView) \ return 0; \ return m_pView->m_selectedBlock.##sbMember; \ } \ void CXTPCalendarViewSelection::OleSet##propName(oleType oleVal) \ { \ if (m_pView) \ m_pView->m_selectedBlock.##sbMember = oleVal; \ } class CXTPCalendarViewSelection : public CXTPCmdTarget { public: CXTPCalendarViewSelection(CXTPCalendarView* pOwnerView); virtual ~CXTPCalendarViewSelection(); // clear internal reference to CXTPCalendarView owner object. virtual void Detach(); protected: DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP() DECLARE_OLETYPELIB_EX(CXTPCalendarViewSelection); BOOL OleIsValid(); XTP_CALENDAR_VIEWSELPROP_DECLARE(DATE, Begin); XTP_CALENDAR_VIEWSELPROP_DECLARE(DATE, End); XTP_CALENDAR_VIEWSELPROP_DECLARE(BOOL, AllDay); XTP_CALENDAR_VIEWSELPROP_DECLARE(long, GroupIndex); protected: CXTPCalendarView* m_pView; LPDISPATCH OleGetBeginV(); LPDISPATCH OleGetEndV(); }; #endif ///////////////////////////////////////////////////////////////////////////// // CXTPCalendarView CXTPCalendarView::CXTPCalendarView(CXTPCalendarControl* pCalendarControl) : m_pControl(pCalendarControl) { // m_strDayHeaderFormatLong = _T("d MMMM"); // m_strDayHeaderFormatMiddle = _T("d MMM"); // m_strDayHeaderFormatShort = _T("d"); // m_strDayHeaderFormatShortest = _T("d"); m_rcView.SetRectEmpty(); m_rcTooltip.SetRectEmpty(); m_Layout.m_nRowHeight = XTP_DPI_Y(18); m_eDraggingMode = xtpCalendaDragModeUnknown; m_ptStartDragging.x = m_ptStartDragging.y = LONG_MAX; m_bStartedClickInside = FALSE; m_pLastEvent = NULL; m_nTimerID_StartEditSubject = 0; m_nTimerID_ShowToolTip = 0; m_eUndoMode = xtpCalendarUndoModeUnknown; m_bResetUndoBuffer = FALSE; m_nKeyStateTimerID = 0; m_pSelectedEvents = new CXTPCalendarViewEvents(); m_pResources = NULL; m_pUndoBuffer = new CUndoBuffer(); m_pPrevUndoBuffer = new CUndoBuffer(); _CalculateEventTimeFormat(); m_bScrollV_Disabled = FALSE; m_bScrollH_Disabled = FALSE; ClearDiscreteSelection(); m_ptLBtnDownMousePos = CPoint(0, 0); m_ptLBtnUpMousePos = CPoint(0, 0); #ifdef _XTP_ACTIVEX EnableAutomation(); EnableTypeLib(); m_pSelOleWrapper = NULL; #endif } CXTPCalendarView::~CXTPCalendarView() { CMDTARGET_RELEASE(m_pSelectedEvents); CMDTARGET_RELEASE(m_pResources); _ASSERTE(m_nTimerID_StartEditSubject == 0); _ASSERTE(m_nTimerID_ShowToolTip == 0); ClearDiscreteSelection(); #ifdef _XTP_ACTIVEX XTP_SAFE_CALL1(m_pSelOleWrapper, Detach()); // clear internal reference to CXTPCalendarView owner object. CMDTARGET_RELEASE(m_pSelOleWrapper); #endif SAFE_DELETE(m_pUndoBuffer); SAFE_DELETE(m_pPrevUndoBuffer); } CXTPCalendarViewDay* CXTPCalendarView::GetViewDay_(int nIndex) const { _ASSERTE(this); if (!this) return NULL; int nCount = m_arDays.GetCount(); _ASSERTE(0 < nCount ? (nIndex >= 0 && nIndex < nCount) : nIndex == 0); return (nIndex >= 0 && nIndex < nCount) ? m_arDays.GetAt(nIndex) : NULL; } BOOL CXTPCalendarView::IsInDiscreteSelection(UINT uDay) const { BOOL bFound = FALSE; for (int id = 0; id < (int)m_DiscreteSelection.GetSize(); id++) { if (uDay == m_DiscreteSelection.GetAt(id)) { bFound = TRUE; break; } } return bFound; } BOOL CXTPCalendarView::AddToDiscreteSelection(UINT uDay) { BOOL bAdd(TRUE); for (int id = 0; id < (int)m_DiscreteSelection.GetSize(); id++) { if (uDay == m_DiscreteSelection.GetAt(id)) { bAdd = FALSE; break; } } if (bAdd) { m_DiscreteSelection.Add(uDay); } return bAdd; } COleDateTime CXTPCalendarView::GetDiscreteSelectionValue(UINT id) const { COleDateTime dt; if (id < (UINT)m_DiscreteSelection.GetSize()) dt = COleDateTime((double)m_DiscreteSelection.GetAt(XTPToIntPtr(id))); return dt; } void CXTPCalendarView::OnBeforeDestroy() { // --- Kill Subject editor if (IsEditingSubject()) EndEditSubject(xtpCalendarEditSubjectCommit, FALSE); if (m_ptrDraggingEventNew) CommitDraggingEvent(); // --- Kill tooltip (and timer inside) ShowToolTip(FALSE); // --- Clear selected events collection if (m_pSelectedEvents) m_pSelectedEvents->RemoveAll(); // === Call base cleanup code TBase::OnBeforeDestroy(); } void CXTPCalendarView::OnActivateView(BOOL bActivate, CXTPCalendarView* pActivateView, CXTPCalendarView* pInactiveView) { UNREFERENCED_PARAMETER(pActivateView); UNREFERENCED_PARAMETER(pInactiveView); if (!bActivate && IsEditingSubject()) EndEditSubject(xtpCalendarEditSubjectCommit, FALSE); } void CXTPCalendarView::RedrawControl() { _ASSERTE(m_pControl); if (m_pControl) { m_pControl->RedrawControl(); } } void CXTPCalendarView::Populate() { if (IsEditingSubject()) { EndEditSubject(xtpCalendarEditSubjectCommit); } int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewDay* pViewDay = GetViewDay_(i); COleDateTime dtDay = GetViewDayDate(i); // _ASSERTE(pViewDay); if (pViewDay) pViewDay->Populate(dtDay); } _ReSelectSelectEvents(); } BOOL CXTPCalendarView::OnLButtonDown(UINT nFlags, CPoint point) { m_ptLBtnDownMousePos = point; CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedrawIfNeed); CSelectionChangedContext selChanged(this); if (!m_pControl->IsReadonlyMode()) m_bStartedClickInside = TRUE; //--------------------------------------------------------------------------- TBase::OnLButtonDown(nFlags, point); //= kill timeout request to edit subject===================================== if (m_nTimerID_StartEditSubject) { KillTimer(m_nTimerID_StartEditSubject); m_nTimerID_StartEditSubject = 0; m_ptrEditingViewEvent = NULL; } //--------------------------------------------------------------------------- XTP_CALENDAR_HITTESTINFO hitInfo; if (HitTest(point, &hitInfo)) { if (hitInfo.uHitCode & xtpCalendarHitTestDay_Mask) { CXTPCalendarControl::CUpdateContext updateContext1(m_pControl, xtpCalendarUpdateRedraw); ProcessDaySelection(&hitInfo, nFlags); } else if (hitInfo.uHitCode & xtpCalendarHitTestEvent_Mask && !m_pControl->IsReadonlyMode()) { CXTPCalendarControl::CUpdateContext updateContext1(m_pControl, xtpCalendarUpdateRedraw); ProcessEventSelection(&hitInfo, nFlags); // set request to start dragging when OnMouseMove() m_ptStartDragging = point; } } //--------------------------------------------------------------------------- BOOL bResetUndoLocal = TRUE; if (IsEditingSubject() && !m_pControl->IsReadonlyMode()) { if (!GetSubjectEditorRect().PtInRect(point)) { bResetUndoLocal = m_eDraggingMode != xtpCalendaDragModeEditSubject; EndEditSubject(xtpCalendarEditSubjectCommit); } } m_bResetUndoBuffer = bResetUndoLocal; //--------------------------------------------------------------------------- CXTPCalendarThemeOffice2007* pThemeX = DYNAMIC_DOWNCAST(CXTPCalendarThemeOffice2007, GetTheme()); if (pThemeX) { XTP_SAFE_CALL1(pThemeX->GetPrevNextEventButtonsPartX(), OnLButtonDown(this, nFlags, point)); } return TRUE; } BOOL CXTPCalendarView::OnLButtonUp(UINT nFlags, CPoint point) { m_ptLBtnUpMousePos = m_ptLBtnDownMousePos; m_ptLBtnDownMousePos = CPoint(0, 0); // way to support discrete selection - pick all days while ALT key hold XTP_CALENDAR_HITTESTINFO hitAltInfo; BOOL bAltHitTest = HitTest(point, &hitAltInfo); BOOL bVKAlt = (GetKeyState(VK_MENU) < 0); if (bAltHitTest && bVKAlt && nFlags == 0 && m_bStartedClickInside) { if (hitAltInfo.dt != NULL) { UINT uDay = (UINT)hitAltInfo.dt; AddToDiscreteSelection(uDay); return TRUE; } } else { ClearDiscreteSelection(); } CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedrawIfNeed); CSelectionChangedContext selChanged(this); const BOOL bHandled = TBase::OnLButtonUp(nFlags, point); //--------------------------------------------------------------------------- m_ptStartDragging.x = m_ptStartDragging.y = LONG_MAX; XTP_CALENDAR_HITTESTINFO hitInfo; BOOL bHitTest = HitTest(point, &hitInfo); if (GetViewType() == xtpCalendarTimeLineView) { CXTPCalendarTimeLineView* pView = (CXTPCalendarTimeLineView*)GetCalendarControl()->GetActiveView(); if (pView) pView->ShowCalendarPopup(hitInfo.dt, point); } int nDragMode = m_eDraggingMode; if (!OnEndDragging(point, &hitInfo) && !m_pControl->IsReadonlyMode()) { if (!bHandled && bHitTest) { UINT uESmask = xtpCalendarHitTestEventTextArea | xtpCalendarHitTestEventResizeArea_Mask; if ((hitInfo.uHitCode & uESmask) && !IsEditingSubject() && hitInfo.pViewEvent && hitInfo.pViewEvent->IsSelected()) { BOOL bEnabled = XTP_SAFE_GET1(GetCalendarOptions(), bEnableInPlaceEditEventSubject_ByMouseClick, FALSE); bEnabled = bEnabled && IsSingleEventSelected(); if (bEnabled) bEnabled = !OnBeforeEditOperationNotify(xtpCalendarEO_EditSubject_ByMouseClick, hitInfo.pViewEvent); //---------------- // Behavior: 1st click selects the event, 2nd click enables editor. if (bEnabled && (m_pLastEvent == hitInfo.pViewEvent)) { _ASSERTE(!m_ptrEditingViewEvent); m_ptrEditingViewEvent = hitInfo.pViewEvent; m_ptrEditingViewEvent->InternalAddRef(); if (m_nTimerID_StartEditSubject == 0) { UINT uTimeOut_ms = GetStartEditSubjectTimeOut(); m_nTimerID_StartEditSubject = SetTimer(uTimeOut_ms); } } m_pLastEvent = hitInfo.pViewEvent; } else { m_pLastEvent = NULL; } } } //--------------------------------------------------------------------------- if (_IsDragModeCopyMove(nDragMode) && bHitTest && hitInfo.pViewDay) { UnselectAllEvents(); SelectDay(hitInfo.pViewDay, hitInfo.nGroup); } if (GetCalendarControl()) GetCalendarControl()->m_mouseMode = xtpCalendarMouseNothing; m_bStartedClickInside = FALSE; OnMouseMove(nFlags, point); return TRUE; } void CXTPCalendarView::OnMouseMove(UINT nFlags, CPoint point) { CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedrawIfNeed); CSelectionChangedContext selChanged(this); CXTPCalendarThemeOffice2007* pThemeX = DYNAMIC_DOWNCAST(CXTPCalendarThemeOffice2007, GetTheme()); if (pThemeX) XTP_SAFE_CALL1(pThemeX->GetPrevNextEventButtonsPartX(), OnMouseMove(this, nFlags, point)); TBase::OnMouseMove(nFlags, point); XTP_CALENDAR_HITTESTINFO hitInfo; BOOL bHitTest = HitTest(point, &hitInfo); if (bHitTest && hitInfo != m_LastHitInfo) { m_LastHitInfo = hitInfo; BOOL bVKAlt = (GetKeyState(VK_MENU) < 0); if (bVKAlt && (nFlags & MK_LBUTTON && m_bStartedClickInside)) { // Preventing continues selection if ALT key hold if (m_LastHitInfo.dt != NULL) { UINT uDay = (UINT)m_LastHitInfo.dt; AddToDiscreteSelection(uDay); } } else if (nFlags & MK_LBUTTON && m_bStartedClickInside) { const int cEpsilon = 2; if (m_ptStartDragging.x == LONG_MAX || m_ptStartDragging.y == LONG_MAX || abs(point.x - m_ptStartDragging.x) >= XTP_DPI_X(cEpsilon) || abs(point.y - m_ptStartDragging.y) >= XTP_DPI_Y(cEpsilon)) { if (!m_ptrDraggingEventNew && !m_ptrDraggingEventOrig && m_eDraggingMode == xtpCalendaDragModeUnknown) { XTP_CALENDAR_HITTESTINFO hitInfoSD; if (HitTest(m_ptStartDragging, &hitInfoSD)) { if (hitInfoSD.uHitCode & xtpCalendarHitTestEvent_Mask) { int eDragMode = _GetDraggingMode(&hitInfoSD); if (!IsEditOperationDisabledNotify(_DragMod2Operation(eDragMode), hitInfoSD.pViewEvent)) OnStartDragging(m_ptStartDragging, &hitInfoSD); } } } m_ptStartDragging.x = m_ptStartDragging.y = LONG_MAX; BOOL bDragging = !!m_ptrDraggingEventNew && m_eDraggingMode != xtpCalendaDragModeEditSubject; if (bDragging) { CXTPCalendarEventPtr ptrDragEventPrev = m_ptrDraggingEventNew->CloneEvent(); BOOL bDragged = OnDragging(point, &hitInfo); if (bDragged) { XTP_EDIT_OPERATION_PARAMS* pOpParamsDrag = new XTP_EDIT_OPERATION_PARAMS; memset(pOpParamsDrag, 0, sizeof(*pOpParamsDrag)); pOpParamsDrag->header.eOperation = _DragMod2Operation(m_eDraggingMode); ++pOpParamsDrag->header.nRefCounter; pOpParamsDrag->dragOperationParams.pDraggingEventOriginal = m_ptrDraggingEventOrig; pOpParamsDrag->dragOperationParams.pDraggingEvent = ptrDragEventPrev; pOpParamsDrag->dragOperationParams.pDraggingEventNew = m_ptrDraggingEventNew; BOOL bHandled = FALSE; if (m_pControl) { m_pControl->SendNotification(XTP_NC_CALENDAR_BEFORE_EVENT_EDIT_OPERATION, (WPARAM)pOpParamsDrag, (LPARAM)&bHandled); } if (0 == --pOpParamsDrag->header.nRefCounter) { delete pOpParamsDrag; } if (bHandled) { // rollback m_ptrDraggingEventNew = ptrDragEventPrev; } XTP_SAFE_CALL1(GetCalendarControl(), Populate()); CXTPCalendarControl::CUpdateContext updateContext1( m_pControl, xtpCalendarUpdateLayout | xtpCalendarUpdateRedraw); if (!!m_ptrDraggingEventNew && !!m_ptrDraggingEventOrig && (!m_ptrDraggingEventNew->IsEqualStartEnd(m_ptrDraggingEventOrig) || m_ptrDraggingEventNew->GetScheduleID() != m_ptrDraggingEventOrig->GetScheduleID())) { SelectEvent(m_ptrDraggingEventNew); } } } } if (m_eDraggingMode == xtpCalendaDragModeUnknown && hitInfo.uHitCode & (xtpCalendarHitTestDay_Mask | xtpCalendarHitTestEvent_Mask)) { if ((hitInfo.uHitCode & xtpCalendarHitTestEvent_Mask) && hitInfo.pViewEvent && hitInfo.pViewEvent->IsSelected()) { } else { CXTPCalendarControl::CUpdateContext updateContext1(m_pControl, xtpCalendarUpdateRedraw); ProcessDaySelection(&hitInfo, nFlags | MK_SHIFT); } } } // process tooltip events (only when no buttons pressed) if (0 == nFlags) { CRect rcTooltip(GetTooltipRect(point, hitInfo)); if (m_rcTooltip != rcTooltip) { // -- kill waiting and hide a tooltip because we switched to another cell ShowToolTip(FALSE); // -- start waiting for mouse under regular empty cell // (to show later "click to add appointment" button) UINT uTimeOut_ms = GetShowToolTipTimeOut(); m_nTimerID_ShowToolTip = SetTimer(uTimeOut_ms); m_rcTooltip = rcTooltip; _ASSERTE(m_nTimerID_ShowToolTip); } } } else if (!bHitTest) { XTP_CALENDAR_HITTESTINFO hitInfoEmpty; m_LastHitInfo = hitInfoEmpty; } //=========================================================================== if (GetCalendarControl()) { if (_IsDragModeCopyMove(m_eDraggingMode) && GetCalendarControl()->m_mouseMode != xtpCalendarMouseEventDraggingOut) { GetCalendarControl()->m_mouseMode = m_eDraggingMode == xtpCalendaDragModeCopy ? xtpCalendarMouseEventDragCopy : xtpCalendarMouseEventDragMove; GetCalendarControl()->UpdateMouseCursor(); } } } void CXTPCalendarView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedrawIfNeed); CSelectionChangedContext selChanged(this); TBase::OnChar(nChar, nRepCnt, nFlags); BOOL bEnable = XTP_SAFE_GET1(GetCalendarOptions(), bEnableInPlaceCreateEvent, FALSE); if (nChar >= _T(' ') && bEnable && !m_pControl->IsReadonlyMode()) { CString strInitialSubj((TCHAR)nChar); if (!OnInPlaceCreateEvent(strInitialSubj)) StartEditNewEventInplace(strInitialSubj); } } void CXTPCalendarView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedrawIfNeed); CSelectionChangedContext selChanged(this); TBase::OnKeyDown(nChar, nRepCnt, nFlags); if (nChar == VK_RETURN || nChar == VK_ESCAPE) { if (IsEditingSubject()) { CXTPCalendarEventPtr ptrEditingEvent(m_ptrDraggingEventOrig, TRUE); EndEditSubject((nChar == VK_RETURN) ? xtpCalendarEditSubjectCommit : xtpCalendarEditSubjectCancel); if (nChar == VK_ESCAPE && !!ptrEditingEvent) { _Undo(ptrEditingEvent); m_pUndoBuffer->Set(*m_pPrevUndoBuffer); } } if (nChar == VK_ESCAPE && !!m_ptrDraggingEventNew) { CXTPCalendarEventPtr ptrEditingEvent(m_ptrDraggingEventOrig, TRUE); CancelDraggingEvent(); BOOL bControlUpdated = FALSE; if (!!ptrEditingEvent && !m_bResetUndoBuffer) { bControlUpdated = _Undo(ptrEditingEvent); m_pUndoBuffer->Set(*m_pPrevUndoBuffer); } if (!bControlUpdated && GetCalendarControl()) { CXTPCalendarControl::CUpdateContext updateContext1(GetCalendarControl(), xtpCalendarUpdateLayout | xtpCalendarUpdateRedraw); GetCalendarControl()->Populate(); } } } else if (nChar == VK_F2) { if (IsEditingSubject()) { return; } CXTPCalendarViewEvent* pViewEvent = GetLastSelectedViewEvent(); if (GetViewType() == xtpCalendarDayView || GetViewType() == xtpCalendarWorkWeekView || GetViewType() == xtpCalendarFullWeekView) { CPoint point = m_ptLBtnUpMousePos; XTP_CALENDAR_HITTESTINFO hitInfo; if (HitTest(point, &hitInfo)) { if (pViewEvent) { CXTPCalendarEvent* pEvent = pViewEvent->GetEvent(); if (pEvent) pViewEvent = FindViewEventByGroup(pEvent, pEvent->GetStartTime(), hitInfo.nGroup); } } } BOOL bEnabled = XTP_SAFE_GET1(GetCalendarOptions(), bEnableInPlaceEditEventSubject_ByF2, FALSE); bEnabled = bEnabled && m_eDraggingMode == xtpCalendaDragModeUnknown && pViewEvent; if (bEnabled) bEnabled = !OnBeforeEditOperationNotify(xtpCalendarEO_EditSubject_ByF2, pViewEvent); if (bEnabled) { _ASSERTE(!m_ptrDraggingEventOrig && !m_ptrDraggingEventNew && !m_ptrEditingViewEvent); if (pViewEvent) { CXTPCalendarControl::CUpdateContext updateContext1(m_pControl, xtpCalendarUpdateRedraw); EmptyUndoBuffer(); StartEditSubject(pViewEvent); } } } else if (nChar == VK_DELETE) { if (m_eDraggingMode == xtpCalendaDragModeUnknown && !m_ptrEditingViewEvent) { _ASSERTE(!m_ptrDraggingEventOrig && !m_ptrDraggingEventNew && !m_ptrEditingViewEvent); CXTPCalendarViewEvent* pViewEvent = GetLastSelectedViewEvent(); if (m_selectedBlock.dtEnd.GetStatus() == COleDateTime::valid && GetCalendarControl() && pViewEvent && pViewEvent->IsSelected()) { CXTPCalendarControl::CUpdateContext updateContext1(GetCalendarControl(), xtpCalendarUpdateRedraw | xtpCalendarUpdateLayout); VERIFY(GetCalendarControl()->DoDeleteSelectedEvents(pViewEvent)); GetCalendarControl()->Populate(); } } } else if (nChar == VK_TAB) { if (m_eDraggingMode == xtpCalendaDragModeUnknown || m_eDraggingMode == xtpCalendaDragModeEditSubject) { BOOL bShift = (GetKeyState(VK_SHIFT) < 0); CXTPCalendarControl::CUpdateContext updateContext1(m_pControl, xtpCalendarUpdateRedraw); if (IsEditingSubject()) { EndEditSubject(xtpCalendarEditSubjectCommit); } COleDateTime dtMinStart = GetNextTimeEditByTAB(); CXTPCalendarViewEvent* pViewEvent = GetLastSelectedViewEvent(); CXTPCalendarEvent* pLastEvent = pViewEvent ? pViewEvent->GetEvent() : NULL; const int cLoopMax = 5000; int i; for (i = 0; i < cLoopMax; i++) // to prevent infinite looping { pViewEvent = FindEventToEditByTAB(dtMinStart, bShift, pLastEvent); pLastEvent = pViewEvent ? pViewEvent->GetEvent() : NULL; if (!pViewEvent || pViewEvent->IsVisible()) { break; } } _ASSERTE(i < cLoopMax); // probably infinite looping ??? UnselectAllEvents(); if (pViewEvent && pViewEvent->IsVisible() && pViewEvent->GetEvent()) { dtMinStart = pViewEvent->GetEvent()->GetStartTime(); UpdateNextTimeEditByTAB(dtMinStart, bShift); EmptyUndoBuffer(); BOOL bEnabled = XTP_SAFE_GET1(GetCalendarOptions(), bEnableInPlaceEditEventSubject_ByTab, FALSE); if (bEnabled) { bEnabled = !OnBeforeEditOperationNotify(xtpCalendarEO_EditSubject_ByTab, pViewEvent); } if (bEnabled) { StartEditSubject(pViewEvent); } else { SelectEvent(pViewEvent->GetEvent()); } SelectDay(XTP_SAFE_GET2(pViewEvent, GetViewGroup_(), GetViewDay_(), NULL), XTP_SAFE_GET2(pViewEvent, GetViewGroup_(), GetGroupIndex(), -1)); } else { dtMinStart = GetViewDayDate(bShift ? GetViewDayCount() - 1 : 0); UpdateNextTimeEditByTAB(dtMinStart, bShift, TRUE); } } } } BOOL CXTPCalendarView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedrawIfNeed); CSelectionChangedContext selChanged(this); BOOL bHandled = TBase::OnSysKeyDown(nChar, nRepCnt, nFlags); UINT uAltBit = (((UINT)1) << 13); if (nChar == VK_BACK && (nFlags & uAltBit)) { bHandled = TRUE; if (CanUndo()) Undo(); else if (CanRedo()) Redo(); } return bHandled; } BOOL CXTPCalendarView::SetDraggingEvent(CXTPCalendarEvent* pEventOrig) { if (!!m_ptrDraggingEventOrig || !!m_ptrDraggingEventNew || !pEventOrig) return FALSE; // Dragging Event already set or CommitDraggingEvent() was not called or invalid parameter pEventOrig->InternalAddRef(); m_ptrDraggingEventOrig = pEventOrig; m_ptrDraggingEventNew = pEventOrig->CloneEvent(); if (!!m_ptrDraggingEventNew && m_ptrDraggingEventNew->GetRecurrenceState() == xtpCalendarRecurrenceOccurrence) { VERIFY(m_ptrDraggingEventNew->MakeAsRException()); } return TRUE; } CXTPCalendarEvent* CXTPCalendarView::GetDraggingEventOrig() const { return m_ptrDraggingEventOrig; } CXTPCalendarEvent* CXTPCalendarView::GetDraggingEventNew() const { return m_ptrDraggingEventNew; } BOOL CXTPCalendarView::CommitDraggingEvent() { _ASSERTE(!!m_ptrDraggingEventNew); if (!GetCalendarControl()) { return FALSE; } CXTPAutoResetValue autoSet_UpdateCtrlNf( GetCalendarControl()->m_bUpdateWhenEventChangedNotify); autoSet_UpdateCtrlNf = FALSE; if (!!m_ptrDraggingEventNew && !!m_ptrDraggingEventOrig) { BOOL bDPdiff = m_ptrDraggingEventNew->GetDataProvider() != m_ptrDraggingEventOrig->GetDataProvider(); BOOL bChanged = !m_ptrDraggingEventNew->IsEqualStartEnd(m_ptrDraggingEventOrig); bChanged = bChanged || m_ptrDraggingEventNew->GetSubject() != m_ptrDraggingEventOrig->GetSubject(); bChanged = bChanged || m_ptrDraggingEventNew->IsAllDayEvent() != m_ptrDraggingEventOrig->IsAllDayEvent(); bChanged = bChanged || m_ptrDraggingEventNew->GetScheduleID() != m_ptrDraggingEventOrig->GetScheduleID(); bChanged = bChanged || bDPdiff; if (bChanged || m_eDraggingMode == xtpCalendaDragModeCopy) { if (!m_pUndoBuffer->IsInUndoBuffer(m_ptrDraggingEventOrig) || m_bResetUndoBuffer) { m_pPrevUndoBuffer->Set(*m_pUndoBuffer); EmptyUndoBuffer(); } CXTPCalendarData* pDataNew = m_ptrDraggingEventNew ->GetDataProvider(); // _GetDataProviderForDraggingEvent(m_ptrDraggingEventNew); CXTPCalendarData* pDataOrig = m_ptrDraggingEventOrig->GetDataProvider(); if (m_eDraggingMode == xtpCalendaDragModeCopy) { if (m_ptrDraggingEventNew->GetRecurrenceState() != xtpCalendarRecurrenceNotRecurring) { VERIFY(m_ptrDraggingEventNew->RemoveRecurrence()); } if (pDataNew) { DBG_DATA_VERIFY(pDataNew->AddEvent(m_ptrDraggingEventNew)); } } else { m_pUndoBuffer->AddUndoAction(m_ptrDraggingEventOrig, m_ptrDraggingEventNew); m_eUndoMode = xtpCalendarUndoModeUndo; m_bResetUndoBuffer = FALSE; if (pDataNew) { if (!bDPdiff) { // restore event ID for case when m_ptrDraggingEventNew was recreated // during dragging between providers m_ptrDraggingEventNew->SetEventID(m_ptrDraggingEventOrig->GetEventID()); DBG_DATA_VERIFY(pDataNew->ChangeEvent(m_ptrDraggingEventNew)); } else { if (m_ptrDraggingEventNew->GetRecurrenceState() != xtpCalendarRecurrenceNotRecurring) { VERIFY(m_ptrDraggingEventNew->RemoveRecurrence()); } if (pDataOrig) { DBG_DATA_VERIFY(pDataOrig->DeleteEvent(m_ptrDraggingEventOrig)); } DBG_DATA_VERIFY(pDataNew->AddEvent(m_ptrDraggingEventNew)); } } } } m_ptrDraggingEventOrig = NULL; m_ptrDraggingEventNew = NULL; return bChanged; } else if (m_ptrDraggingEventNew) { if (!m_pUndoBuffer->IsInUndoBuffer(m_ptrDraggingEventNew) || m_bResetUndoBuffer) { m_pPrevUndoBuffer->Set(*m_pUndoBuffer); EmptyUndoBuffer(); } CXTPCalendarData* pData = m_ptrDraggingEventNew ->GetDataProvider(); //_GetDataProviderForDraggingEvent(m_ptrDraggingEventNew); _ASSERTE(m_ptrDraggingEventNew->GetRecurrenceState() == xtpCalendarRecurrenceNotRecurring); if (pData) { DBG_DATA_VERIFY(pData->AddEvent(m_ptrDraggingEventNew)); } m_pUndoBuffer->AddUndoAction(NULL, m_ptrDraggingEventNew); m_eUndoMode = xtpCalendarUndoModeUndo; m_bResetUndoBuffer = FALSE; m_ptrDraggingEventOrig = NULL; m_ptrDraggingEventNew = NULL; return TRUE; } return FALSE; } void CXTPCalendarView::CancelDraggingEvent() { _ASSERTE(!!m_ptrDraggingEventNew); m_eDraggingMode = xtpCalendaDragModeUnknown; if (GetCalendarControl()) { GetCalendarControl()->m_mouseMode = xtpCalendarMouseNothing; GetCalendarControl()->UpdateMouseCursor(); } m_ptrDraggingEventOrig = NULL; m_ptrDraggingEventNew = NULL; m_ptStartDragging.x = m_ptStartDragging.y = LONG_MAX; m_bStartedClickInside = FALSE; } CXTPCalendarEventsPtr CXTPCalendarView::RetrieveDayEvents(CXTPCalendarResource* pRC, COleDateTime dtDay) { ASSERT_VALID(pRC); dtDay = CXTPCalendarUtils::ResetTime(dtDay); CXTPCalendarEventsPtr ptrEvents = pRC ? pRC->RetrieveDayEvents(dtDay).Detach() : new CXTPCalendarEvents(); if (!m_ptrDraggingEventNew || !ptrEvents || !pRC) return ptrEvents; BOOL bIsDragCopy = m_eDraggingMode == xtpCalendaDragModeCopy; COleDateTime dtDay1 = GetDateTimeDay(m_ptrDraggingEventNew->GetStartTime(), m_ptrDraggingEventNew->IsAllDayEvent()); COleDateTime dtDay2 = GetDateTimeDay(m_ptrDraggingEventNew->GetEndTime(), m_ptrDraggingEventNew->IsAllDayEvent()); UINT uSchID = m_ptrDraggingEventNew->GetScheduleID(); BOOL bNewEventScheduleVisible = m_ptrDraggingEventNew->GetDataProvider() == pRC->GetDataProvider() && pRC->ExistsScheduleID(uSchID); if (!bIsDragCopy) { int nCount = ptrEvents->GetCount(); for (int i = nCount - 1; i >= 0; i--) { CXTPCalendarEvent* pEvent = ptrEvents->GetAt(i, FALSE); if (NULL == pEvent) continue; if (!!m_ptrDraggingEventOrig && m_ptrDraggingEventOrig->GetDataProvider() == pEvent->GetDataProvider() && m_ptrDraggingEventOrig->IsEqualIDs(pEvent) && m_ptrDraggingEventOrig->GetScheduleID() == pEvent->GetScheduleID()) { ptrEvents->RemoveAt(i); } } } if (dtDay >= dtDay1 && dtDay <= dtDay2 && bNewEventScheduleVisible) ptrEvents->Add(m_ptrDraggingEventNew); return ptrEvents; } XTPCalendarDraggingMode CXTPCalendarView::_GetDraggingMode(XTP_CALENDAR_HITTESTINFO* pHitTest) const { if (!pHitTest) { _ASSERTE(FALSE); return xtpCalendaDragModeUnknown; } if (pHitTest->uHitCode & xtpCalendarHitTestEventResizeArea_Mask) { if (pHitTest->uHitCode & xtpCalendarHitTestEventResizeBegin) { return xtpCalendaDragModeResizeBegin; } else if (pHitTest->uHitCode & xtpCalendarHitTestEventResizeEnd) { return xtpCalendaDragModeResizeEnd; } } else { BOOL bIsCtrl = (GetKeyState(VK_CONTROL) < 0); return bIsCtrl ? xtpCalendaDragModeCopy : xtpCalendaDragModeMove; } return xtpCalendaDragModeUnknown; } void CXTPCalendarView::OnStartDragging(CPoint /*point*/, XTP_CALENDAR_HITTESTINFO* pHitTest) { if (!pHitTest) return; if ((pHitTest->uHitCode & xtpCalendarHitTestEvent_Mask) == 0) return; if (IsEditingSubject()) EndEditSubject(xtpCalendarEditSubjectCommit, FALSE); m_spDraggingStartOffset.SetStatus(COleDateTimeSpan::null); m_eDraggingMode = xtpCalendaDragModeUnknown; if (!pHitTest->pViewEvent || !pHitTest->pViewEvent->GetEvent()) return; m_eDraggingMode = _GetDraggingMode(pHitTest); _ASSERTE(m_eDraggingMode != xtpCalendaDragModeUnknown); if (_IsDragModeCopyMove(m_eDraggingMode)) { if (pHitTest->bTimePartValid) { m_spDraggingStartOffset = pHitTest->dt - pHitTest->pViewEvent->GetEvent()->GetStartTime(); } else { m_spDraggingStartOffset = CXTPCalendarUtils::ResetTime(pHitTest->dt) - CXTPCalendarUtils::ResetTime( pHitTest->pViewEvent->GetEvent()->GetStartTime()); } if (!m_nKeyStateTimerID) m_nKeyStateTimerID = SetTimer(50); } //--------------------------------------------------------------------------- VERIFY(SetDraggingEvent(pHitTest->pViewEvent->GetEvent())); } BOOL CXTPCalendarView::OnEndDragging(CPoint point, XTP_CALENDAR_HITTESTINFO* phitInfo) { UNREFERENCED_PARAMETER(point); UNREFERENCED_PARAMETER(phitInfo); if (!m_ptrDraggingEventNew || !m_ptrDraggingEventOrig || m_eDraggingMode == xtpCalendaDragModeEditSubject) { return FALSE; } CXTPCalendarEventPtr ptrEventToSelect = m_ptrDraggingEventNew; BOOL bChanged = CommitDraggingEvent(); int nDragMode = m_eDraggingMode; m_eDraggingMode = xtpCalendaDragModeUnknown; if (bChanged && GetCalendarControl()) GetCalendarControl()->Populate(); UnselectAllEvents(); if (_IsDragModeCopyMove(nDragMode)) EmptyUndoBuffer(); if (!!ptrEventToSelect && (nDragMode == xtpCalendaDragModeResizeBegin || nDragMode == xtpCalendaDragModeResizeEnd)) { CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedraw); COleDateTime dtFVDate = GetDateTimeDay(ptrEventToSelect->GetStartTime(), ptrEventToSelect->IsAllDayEvent()); if (nDragMode == xtpCalendaDragModeResizeEnd) dtFVDate = CXTPCalendarUtils::RetriveEventEndDate(ptrEventToSelect); CXTPCalendarViewEvent* pViewEvent = FindViewEvent(ptrEventToSelect, dtFVDate); if (pViewEvent && pViewEvent->GetEvent()) { SelectDay(XTP_SAFE_GET2(pViewEvent, GetViewGroup_(), GetViewDay_(), NULL), XTP_SAFE_GET2(pViewEvent, GetViewGroup_(), GetGroupIndex(), -1)); BOOL bEnabled = XTP_SAFE_GET1(GetCalendarOptions(), bEnableInPlaceEditEventSubject_AfterEventResize, FALSE); if (bEnabled) bEnabled = !OnBeforeEditOperationNotify(xtpCalendarEO_EditSubject_AfterEventResize, pViewEvent); BOOL bNo = pViewEvent->GetEvent()->GetDurationMinutes() < 1440; if (bEnabled && bNo) StartEditSubject(pViewEvent); else SelectEvent(pViewEvent->GetEvent()); } } SelectEvent(ptrEventToSelect); return TRUE; } CXTPCalendarViewEvent* CXTPCalendarView::FindViewEvent(CXTPCalendarEvent* pEvent, COleDateTime dtDay) const { if (!pEvent) { _ASSERTE(FALSE); return NULL; } dtDay = CXTPCalendarUtils::ResetTime(dtDay); CXTPCalendarViewEvent* pFEView = NULL; BOOL bFDayProceessed = FALSE; int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewDay* pViewDay = GetViewDay_(i); if (!pViewDay) { _ASSERTE(FALSE); continue; } COleDateTime dtDayDate = pViewDay->GetDayDate(); int nGroupsCount = pViewDay->GetViewGroupsCount(); for (int g = 0; g < nGroupsCount; g++) { CXTPCalendarViewGroup* pViewGroup = pViewDay->GetViewGroup_(g); _ASSERTE(pViewGroup); if (!pViewGroup) { continue; } int nECount = pViewGroup->GetViewEventsCount(); for (int j = 0; j < nECount; j++) { CXTPCalendarViewEvent* pViewEvent = pViewGroup->GetViewEvent_(j); CXTPCalendarEvent* pEv = pViewEvent ? pViewEvent->GetEvent() : NULL; if (!pEv) { _ASSERTE(FALSE); continue; } if (pEvent->IsEqualIDs(pEv) && pEvent->IsEqualStartEnd(pEv)) { if (pViewEvent->IsVisible()) { pFEView = pViewEvent; } if (CXTPCalendarUtils::IsEqual(dtDay, dtDayDate)) { bFDayProceessed = TRUE; } if (pFEView && bFDayProceessed) { return pFEView; } } } } } return NULL; } CXTPCalendarViewEvent* CXTPCalendarView::FindViewEventByGroup(CXTPCalendarEvent* pEvent, COleDateTime dtDay, int nScheduleID) const { if (!pEvent) { _ASSERTE(FALSE); return NULL; } dtDay = CXTPCalendarUtils::ResetTime(dtDay); CXTPCalendarViewEvent* pFEView = NULL; BOOL bFDayProceessed = FALSE; int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewDay* pViewDay = GetViewDay_(i); if (!pViewDay) { _ASSERTE(FALSE); continue; } COleDateTime dtDayDate = pViewDay->GetDayDate(); int nGroupsCount = pViewDay->GetViewGroupsCount(); if (nScheduleID < nGroupsCount) { CXTPCalendarViewGroup* pViewGroup = pViewDay->GetViewGroup_(nScheduleID); _ASSERTE(pViewGroup); if (!pViewGroup) { continue; } int nECount = pViewGroup->GetViewEventsCount(); for (int j = 0; j < nECount; j++) { CXTPCalendarViewEvent* pViewEvent = pViewGroup->GetViewEvent_(j); CXTPCalendarEvent* pEv = pViewEvent ? pViewEvent->GetEvent() : NULL; if (!pEv) { _ASSERTE(FALSE); continue; } if (pEvent->IsEqualIDs(pEv) && pEvent->IsEqualStartEnd(pEv)) { if (pViewEvent->IsVisible()) { pFEView = pViewEvent; } if (CXTPCalendarUtils::IsEqual(dtDay, dtDayDate)) { bFDayProceessed = TRUE; } if (pFEView && bFDayProceessed) { return pFEView; } } } } } return NULL; } BOOL CXTPCalendarView::HasSelectedViewEvent() const { if (!m_pSelectedEvents) { return FALSE; } return m_pSelectedEvents->GetCount() > 0; } CXTPCalendarViewEvents* CXTPCalendarView::GetSelectedViewEvents() const { return m_pSelectedEvents; } BOOL CXTPCalendarView::IsSingleEventSelected() const { int nCount = m_pSelectedEvents ? m_pSelectedEvents->GetCount() : 0; if (nCount == 0) return FALSE; if (nCount == 1) return TRUE; CXTPCalendarEvent* pEvent = m_pSelectedEvents->GetAt(0)->GetEvent(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewEvent* pViewEvent = m_pSelectedEvents->GetAt(i); _ASSERTE(pViewEvent); if (pViewEvent && !pViewEvent->GetEvent()->IsEqualIDs(pEvent)) return FALSE; } return TRUE; } CXTPCalendarViewEventsPtr CXTPCalendarView::GetSelectedEvents() const { CXTPCalendarViewEventsPtr ptrEventsWithViews = new CXTPCalendarViewEvents(); CXTPCalendarEvents arEvents; _ASSERTE(m_pSelectedEvents); if (!ptrEventsWithViews || !m_pSelectedEvents) { return NULL; } int nCount = m_pSelectedEvents->GetCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewEvent* pViewEvent = m_pSelectedEvents->GetAt(i); CXTPCalendarEvent* pEvent = pViewEvent ? pViewEvent->GetEvent() : NULL; if (pEvent && arEvents.Find(pEvent) < 0) { arEvents.Add(pEvent, TRUE); ptrEventsWithViews->Add(pViewEvent, TRUE); } } return ptrEventsWithViews; } BOOL CXTPCalendarView::GetSelection(COleDateTime* pBegin, COleDateTime* pEnd, BOOL* pbAllDayEvent, int* pnGroupIndex, COleDateTimeSpan* pspSelectionResolution) const { if (!m_selectedBlock.IsValid()) { return FALSE; } if (pspSelectionResolution) { *pspSelectionResolution = COleDateTimeSpan(1, 0, 0, 0); } if (pbAllDayEvent) { *pbAllDayEvent = TRUE; } if (pnGroupIndex) { *pnGroupIndex = m_selectedBlock.nGroupIndex; } //--------------------------------------------------------------------------- if (pBegin) { *pBegin = min(m_selectedBlock.dtBegin, m_selectedBlock.dtEnd); } if (pEnd) { *pEnd = max(m_selectedBlock.dtBegin, m_selectedBlock.dtEnd) + COleDateTimeSpan(1, 0, 0, 0); } return TRUE; } void CXTPCalendarView::SetSelection(const COleDateTime& dtBegin, const COleDateTime& dtEnd, BOOL bAllDayEvent, int nGroupIndex) { m_selectedBlock.dtBegin = dtBegin; m_selectedBlock.dtEnd = dtEnd; m_selectedBlock.bAllDayEvent = bAllDayEvent; m_selectedBlock.nGroupIndex = nGroupIndex; CSelectionChangedContext selChanged(this, xtpCalendarSelectionDays); } void CXTPCalendarView::ResetSelection() { if (IsEditingSubject()) { CXTPCalendarEventPtr ptrEditingEvent(m_ptrDraggingEventOrig, TRUE); EndEditSubject(xtpCalendarEditSubjectCancel); } m_selectedBlock.dtBegin.SetStatus(COleDateTime::null); m_selectedBlock.dtEnd.SetStatus(COleDateTime::null); m_selectedBlock.bAllDayEvent = FALSE; m_selectedBlock.nGroupIndex = -1; CSelectionChangedContext selChanged(this, xtpCalendarSelectionDays); } BOOL CXTPCalendarView::SelectionContains(COleDateTime date, int nGroupIndex, BOOL* pbAllDaySelection) { COleDateTime dtBegin; COleDateTime dtEnd; int nSelGroupIndex; if (GetSelection(&dtBegin, &dtEnd, pbAllDaySelection, &nSelGroupIndex)) { if (nGroupIndex < 0 || nGroupIndex == nSelGroupIndex) { return (dtBegin <= date && (double)date <= (double)dtEnd - XTP_HALF_SECOND); } } return FALSE; } COleDateTime CXTPCalendarView::GetNextTimeEditByTAB() const { _ASSERTE(GetViewDayCount() != 0); COleDateTime dtDay; if (m_selectedBlock.dtEnd.GetStatus() == COleDateTime::valid) { dtDay = m_selectedBlock.dtEnd; } else { dtDay = GetViewDayDate(0); } dtDay = CXTPCalendarUtils::ResetTime(dtDay); return dtDay; } void CXTPCalendarView::UpdateNextTimeEditByTAB(COleDateTime dtNext, BOOL /*bReverse*/, BOOL /*bReset*/) { COleDateTime dtNextDay = CXTPCalendarUtils::ResetTime(dtNext); COleDateTime dtCurrDay = CXTPCalendarUtils::ResetTime(GetNextTimeEditByTAB()); if (dtNextDay != dtCurrDay) { SelectDay(dtNextDay); } } CXTPCalendarViewEvent* CXTPCalendarView::FindEventToEditByTAB(COleDateTime dtMinStart, BOOL bReverse, CXTPCalendarEvent* pAfterEvent) { COleDateTime dtMinStartDay = CXTPCalendarUtils::ResetTime(dtMinStart); COleDateTime dtMinStart2 = dtMinStartDay + COleDateTimeSpan(1, 0, 0, 0); BOOL bAfterEventWas = pAfterEvent == NULL; if (pAfterEvent) { COleDateTime dtAEStartDay = GetDateTimeDay(pAfterEvent->GetStartTime(), pAfterEvent->IsAllDayEvent()); if (bReverse ? dtAEStartDay > dtMinStartDay : dtAEStartDay < dtMinStartDay) { bAfterEventWas = TRUE; } } int nDays = GetViewDayCount(); for (int nDay = bReverse ? nDays - 1 : 0; bReverse ? nDay >= 0 : nDay < nDays; bReverse ? nDay-- : nDay++) { CXTPCalendarViewDay* pVDay = GetViewDay_(nDay); if (!pVDay) { _ASSERTE(FALSE); continue; } COleDateTime dtDay = pVDay->GetDayDate(); if (bReverse ? dtDay > dtMinStartDay : dtDay < dtMinStartDay) { continue; } int nGroupsCount = pVDay->GetViewGroupsCount(); for (int nGroup = bReverse ? nGroupsCount - 1 : 0; bReverse ? nGroup >= 0 : nGroup < nGroupsCount; bReverse ? nGroup-- : nGroup++) { CXTPCalendarViewGroup* pViewGroup = pVDay->GetViewGroup_(nGroup); _ASSERTE(pViewGroup); if (!pViewGroup) { continue; } int nEvents = pViewGroup->GetViewEventsCount(); for (int nEvent = bReverse ? nEvents - 1 : 0; bReverse ? nEvent >= 0 : nEvent < nEvents; bReverse ? nEvent-- : nEvent++) { CXTPCalendarViewEvent* pVEvent = pViewGroup->GetViewEvent_(nEvent); if (!pVEvent || !pVEvent->GetEvent()) { _ASSERTE(FALSE); continue; } if (pAfterEvent) { if (pAfterEvent->IsEqualIDs(pVEvent->GetEvent())) { bAfterEventWas = TRUE; continue; } } COleDateTime dtES = pVEvent->GetEvent()->GetStartTime(); COleDateTime dtESDay = GetDateTimeDay(dtES, pVEvent->GetEvent()->IsAllDayEvent()); if (bReverse ? (dtES > dtMinStart2 || dtESDay != dtDay) : (dtES < dtMinStart || dtESDay < dtDay)) { continue; } if (bAfterEventWas) { return pVEvent; } } } } return NULL; } void CXTPCalendarView::UnselectAllEvents() { if (!m_pSelectedEvents || !GetCalendarControl()) { return; } int nCount = m_pSelectedEvents->GetCount(); m_pSelectedEvents->RemoveAll(); if (nCount) { CXTPCalendarControl::CUpdateContext updateContext(GetCalendarControl(), xtpCalendarUpdateRedraw); CSelectionChangedContext selChanged(this, xtpCalendarSelectionEvents); } } void CXTPCalendarView::_ReSelectSelectEvents() { if (!m_pSelectedEvents) return; CXTPCalendarViewEventsPtr ptrSelEvents = GetSelectedEvents(); m_pSelectedEvents->RemoveAll(); CXTPCalendarEvent* pEvent; if (ptrSelEvents) { int nCount = ptrSelEvents->GetCount(); for (int i = 0; i < nCount; i++) { if (ptrSelEvents->GetAt(i)) { pEvent = ptrSelEvents->GetAt(i)->GetEvent(); if (pEvent) SelectEvent(pEvent); } } } } void CXTPCalendarView::SelectDays(COleDateTime dtNewSel) { CXTPCalendarControl::CUpdateContext updateContext(GetCalendarControl(), xtpCalendarUpdateRedraw); m_selectedBlock.dtEnd = dtNewSel; CSelectionChangedContext selChanged(this, xtpCalendarSelectionDays); } void CXTPCalendarView::SelectDay(COleDateTime dtSelDay, int nGroupIndex) { CXTPCalendarControl::CUpdateContext updateContext(GetCalendarControl(), xtpCalendarUpdateRedraw); m_selectedBlock.dtBegin = m_selectedBlock.dtEnd = dtSelDay; m_selectedBlock.nGroupIndex = nGroupIndex; CSelectionChangedContext selChanged(this, xtpCalendarSelectionDays); } void CXTPCalendarView::SelectDay(CXTPCalendarViewDay* pDay, int nGroupIndex) { _ASSERTE(pDay); if (pDay) { SelectDay(pDay->GetDayDate(), nGroupIndex); } } void CXTPCalendarView::SelectViewEvent(CXTPCalendarViewEvent* pViewEvent, BOOL bSelect) { if (!m_pSelectedEvents || !pViewEvent || !pViewEvent->GetEvent()) { _ASSERTE(FALSE); return; } if (bSelect) { int nIndex = m_pSelectedEvents->Find(pViewEvent->GetEvent()); if (-1 == nIndex) { m_pSelectedEvents->Add(pViewEvent); pViewEvent->InternalAddRef(); } } else { m_pSelectedEvents->Remove(pViewEvent->GetEvent()); } CXTPCalendarControl::CUpdateContext updateContext(GetCalendarControl(), xtpCalendarUpdateRedraw); CSelectionChangedContext selChanged(this, xtpCalendarSelectionEvents); } CXTPCalendarViewEvent* CXTPCalendarView::GetLastSelectedViewEvent() const { if (m_pSelectedEvents && m_pSelectedEvents->GetCount() > 0) return m_pSelectedEvents->GetAt(m_pSelectedEvents->GetCount() - 1); return NULL; } void CXTPCalendarView::SelectEvent(CXTPCalendarEvent* pEvent, BOOL bSelect) { if (!pEvent) { _ASSERTE(FALSE); return; } int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewDay* pViewDay = GetViewDay_(i); if (!pViewDay) { _ASSERTE(FALSE); continue; } int nGroupsCount = pViewDay->GetViewGroupsCount(); for (int g = 0; g < nGroupsCount; g++) { CXTPCalendarViewGroup* pViewGroup = pViewDay->GetViewGroup_(g); _ASSERTE(pViewGroup); if (!pViewGroup) { continue; } int nECount = pViewGroup->GetViewEventsCount(); for (int j = 0; j < nECount; j++) { CXTPCalendarViewEvent* pViewEvent = pViewGroup->GetViewEvent_(j); CXTPCalendarEvent* pEv = pViewEvent ? pViewEvent->GetEvent() : NULL; _ASSERTE(pEv); if (pEv && pEvent->IsEqualIDs(pEv) && pEvent->IsEqualStartEnd(pEv)) { SelectViewEvent(pViewEvent, bSelect); } } } } } BOOL CXTPCalendarView::OnDragging(CPoint /*point*/, XTP_CALENDAR_HITTESTINFO* pHitTest) { _ASSERTE(pHitTest); if (!pHitTest || !m_ptrDraggingEventNew || m_eDraggingMode == xtpCalendaDragModeEditSubject) { return FALSE; } //--------------------------------------------------------------------------- if (pHitTest->pViewDay) { if (m_eDraggingMode == xtpCalendaDragModeResizeBegin || m_eDraggingMode == xtpCalendaDragModeResizeEnd) { SelectDay(pHitTest->pViewDay, pHitTest->nGroup); } } //--------------------------------------------------------------------------- COleDateTime dtNewTime; if (_IsDragModeCopyMove(m_eDraggingMode)) { if (!pHitTest->bTimePartValid) { dtNewTime = CXTPCalendarUtils::UpdateDate(m_ptrDraggingEventNew->GetStartTime(), pHitTest->dt); } else { dtNewTime = pHitTest->dt; } dtNewTime -= m_spDraggingStartOffset; BOOL bChanged = FALSE; //------------------------------------ if (!CXTPCalendarUtils::IsEqual(dtNewTime, m_ptrDraggingEventNew->GetStartTime())) { m_ptrDraggingEventNew->MoveEvent(dtNewTime); bChanged = TRUE; } //*** if (bChanged) { return TRUE; } } else if (m_eDraggingMode == xtpCalendaDragModeResizeBegin) { dtNewTime = pHitTest->dt; COleDateTime dtEventEnd = m_ptrDraggingEventNew->GetEndTime(); if (!CXTPCalendarUtils::IsEqual(dtNewTime, m_ptrDraggingEventNew->GetStartTime())) { if (dtNewTime > dtEventEnd) { dtNewTime = dtEventEnd; } m_ptrDraggingEventNew->SetStartTime(dtNewTime); BOOL bIsZeroStartEnd = CXTPCalendarUtils::IsZeroTime(m_ptrDraggingEventNew->GetStartTime()) && CXTPCalendarUtils::IsZeroTime(m_ptrDraggingEventNew->GetEndTime()); BOOL bIsZeroLen = CXTPCalendarUtils::IsEqual(m_ptrDraggingEventNew->GetStartTime(), m_ptrDraggingEventNew->GetEndTime()); m_ptrDraggingEventNew->SetAllDayEvent(bIsZeroStartEnd && !bIsZeroLen); return TRUE; } } else if (m_eDraggingMode == xtpCalendaDragModeResizeEnd) { dtNewTime = pHitTest->dt; if (!pHitTest->bTimePartValid) { dtNewTime += COleDateTimeSpan(1, 0, 0, 0); } COleDateTime dtEventStart = m_ptrDraggingEventNew->GetStartTime(); if (!CXTPCalendarUtils::IsEqual(dtNewTime, m_ptrDraggingEventNew->GetEndTime())) { if ((pHitTest->uHitCode & xtpCalendarHitTestDayViewTimeScale) && (pHitTest->pViewDay == NULL)) { dtNewTime.SetDateTime(dtEventStart.GetYear(), dtEventStart.GetMonth(), dtEventStart.GetDay(), dtNewTime.GetHour(), dtNewTime.GetMinute(), dtNewTime.GetSecond()); } if (dtNewTime < dtEventStart) { dtNewTime = dtEventStart; } m_ptrDraggingEventNew->SetEndTime(dtNewTime); BOOL bIsZeroStartEnd = CXTPCalendarUtils::IsZeroTime(m_ptrDraggingEventNew->GetStartTime()) && CXTPCalendarUtils::IsZeroTime(m_ptrDraggingEventNew->GetEndTime()); BOOL bIsZeroLen = CXTPCalendarUtils::IsEqual(m_ptrDraggingEventNew->GetStartTime(), m_ptrDraggingEventNew->GetEndTime()); m_ptrDraggingEventNew->SetAllDayEvent(bIsZeroStartEnd && !bIsZeroLen); return TRUE; } } return FALSE; } COleDateTime CXTPCalendarView::GetLastSelectedDate() const { if (m_selectedBlock.dtEnd.GetStatus() != COleDateTime::valid) { return GetViewDayDate(GetViewDayCount() / 2); } return CXTPCalendarUtils::ResetTime(m_selectedBlock.dtEnd); } int CXTPCalendarView::FindLastSelectedDay() const { COleDateTime dt = GetLastSelectedDate(); int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewDay* pViewDay = GetViewDay_(i); _ASSERTE(pViewDay); if (pViewDay && CXTPCalendarUtils::IsEqual(pViewDay->GetDayDate(), dt)) return i; } return -1; } void CXTPCalendarView::ProcessDaySelection(XTP_CALENDAR_HITTESTINFO* pInfo, UINT nFlags) { _ASSERTE(pInfo); if (!pInfo) { UnselectAllEvents(); return; } if (nFlags & MK_SHIFT) { COleDateTime dtNewSelDay = GetViewDayDate(pInfo->nDay); SelectDays(dtNewSelDay); } else { UnselectAllEvents(); _ASSERTE(pInfo->pViewDay); if (pInfo->pViewDay) { pInfo->pViewDay->SetSelected(); } } } void CXTPCalendarView::ProcessEventSelection(XTP_CALENDAR_HITTESTINFO* pInfo, UINT nFlags) { _ASSERTE(pInfo); if (!pInfo) { return; } BOOL bUnselectEvents = !(nFlags & (MK_SHIFT | MK_CONTROL)); if (bUnselectEvents) UnselectAllEvents(); _ASSERTE(pInfo->pViewDay); _ASSERTE(pInfo->pViewEvent); if (pInfo->pViewDay) { pInfo->pViewDay->SetSelected(); } if (pInfo->pViewEvent) { BOOL bSelect = TRUE; if (nFlags & MK_CONTROL) { bSelect = !pInfo->pViewEvent->IsSelected(); } SelectEvent(pInfo->pViewEvent->GetEvent(), bSelect); } } UINT CXTPCalendarView::SetTimer(UINT uTimeOut_ms) { if (GetCalendarControl()) { return GetCalendarControl()->SetTimer(uTimeOut_ms); } return 0; } void CXTPCalendarView::KillTimer(UINT uTimerID) { if (GetCalendarControl()) { VERIFY(GetCalendarControl()->KillTimer(uTimerID)); } } BOOL CXTPCalendarView::OnTimer(UINT_PTR uTimerID) { if (TBase::OnTimer(uTimerID)) { return TRUE; } CXTPCalendarThemeOffice2007* pThemeX = DYNAMIC_DOWNCAST(CXTPCalendarThemeOffice2007, GetTheme()); if (pThemeX) { if (pThemeX->OnTimer(uTimerID)) return TRUE; } if (uTimerID == m_nTimerID_StartEditSubject) { KillTimer(m_nTimerID_StartEditSubject); m_nTimerID_StartEditSubject = 0; _ASSERTE(!!m_ptrEditingViewEvent); if (m_ptrEditingViewEvent) { EmptyUndoBuffer(); StartEditSubject(m_ptrEditingViewEvent); } return TRUE; } else if (uTimerID == m_nKeyStateTimerID) { BOOL bIsCtrl = (GetKeyState(VK_CONTROL) < 0); XTPCalendarDraggingMode eDraggingMode = bIsCtrl ? xtpCalendaDragModeCopy : xtpCalendaDragModeMove; BOOL bPopulate = FALSE; if (!_IsDragModeCopyMove(m_eDraggingMode)) { KillTimer(m_nKeyStateTimerID); m_nKeyStateTimerID = 0; } else if (m_eDraggingMode != eDraggingMode) { _ASSERTE(!!m_ptrDraggingEventNew); if (m_ptrDraggingEventNew) { CXTPCalendarViewEvent* pEventView = FindViewEvent(m_ptrDraggingEventNew, m_ptrDraggingEventNew->GetStartTime()); if (!IsEditOperationDisabledNotify(_DragMod2Operation(eDraggingMode), pEventView)) { m_eDraggingMode = eDraggingMode; bPopulate = TRUE; } } } if (bPopulate && GetCalendarControl()) { GetCalendarControl()->Populate(); GetCalendarControl()->m_mouseMode = m_eDraggingMode == xtpCalendaDragModeCopy ? xtpCalendarMouseEventDragCopy : xtpCalendarMouseEventDragMove; GetCalendarControl()->UpdateMouseCursor(); } return TRUE; } else if (uTimerID == m_nTimerID_ShowToolTip) { ShowToolTip(); return TRUE; } return FALSE; } BOOL CXTPCalendarView::OnLButtonDblClk(UINT nFlags, CPoint point) { if (m_nTimerID_StartEditSubject) { KillTimer(m_nTimerID_StartEditSubject); m_nTimerID_StartEditSubject = 0; m_ptrEditingViewEvent = NULL; } return TBase::OnLButtonDblClk(nFlags, point); } void CXTPCalendarView::OnDraw(CDC* pDC) { if (GetTheme()) Draw2(pDC); else Draw(pDC); } void CXTPCalendarView::AdjustLayout(CDC* pDC, const CRect& rcView, BOOL bCallPostAdjustLayout) { UNREFERENCED_PARAMETER(pDC); m_rcView = rcView; _CalculateEventTimeFormat(); if (bCallPostAdjustLayout) { OnPostAdjustLayout(); } } void CXTPCalendarView::AdjustLayout2(CDC* pDC, const CRect& rcView, BOOL bCallPostAdjustLayout) { UNREFERENCED_PARAMETER(pDC); UNREFERENCED_PARAMETER(bCallPostAdjustLayout); _ASSERTE(GetTheme()); m_rcView = rcView; //_CalculateEventTimeFormat(); // if (bCallPostAdjustLayout) // { // OnPostAdjustLayout(); // } } CXTPCalendarViewDay* CXTPCalendarView::_GetViewDay(const COleDateTime& dt) const { COleDateTime dtDay = CXTPCalendarUtils::ResetTime(dt); int nDaysCount = GetViewDayCount(); if (!nDaysCount || !GetViewDay_(0)) { return NULL; } COleDateTime dtDay0 = GetViewDay_(0)->GetDayDate(); COleDateTimeSpan spShift = dtDay - dtDay0; _ASSERTE((double)spShift == (double)((int)(double)spShift)); int nShift = CXTPCalendarUtils::GetTotalDays(spShift); //(int)(double)spShift if (nShift < 0) { nShift = 0; } if (nShift >= nDaysCount) { nShift = nDaysCount - 1; } if (nShift >= 0 && nShift < nDaysCount) { return GetViewDay_(nShift); } return NULL; } COleDateTime CXTPCalendarView::GetDateTimeDay(const COleDateTime& dt, BOOL bWholeDayEvent) const { CXTPCalendarOptions* pOptions = GetCalendarControl()->GetCalendarOptions(); if ((DATE)pOptions->dtScaleMaxTime <= 1 || bWholeDayEvent) return CXTPCalendarUtils::ResetTime(dt); return CXTPCalendarUtils::ResetTime(dt - pOptions->dtScaleMinTime); } void CXTPCalendarView::StartEditNewEventInplace(LPCTSTR pcszInitialSubject) { if (!!m_ptrDraggingEventOrig || !!m_ptrDraggingEventNew || IsEditingSubject()) { MessageBeep(0); return; } BOOL bAllDayEvent = FALSE; //--------------------------------------------------------------------------- COleDateTime dtSelBegin, dtSelEnd; int nGroup = 0; if (!GetSelection(&dtSelBegin, &dtSelEnd, &bAllDayEvent, &nGroup)) { return; } //--------------------------------------------------------------------------- CXTPCalendarData* pData = NULL; // XTP_SAFE_GET1(GetCalendarControl(), GetDataProvider(), NULL); CXTPCalendarViewDay* pViewDay = _GetViewDay(dtSelBegin); if (!pViewDay) return; CXTPCalendarViewGroup* pViewGroup = NULL; if (pViewDay && nGroup < pViewDay->GetViewGroupsCount()) { pViewGroup = pViewDay->GetViewGroup_(nGroup); pData = pViewGroup ? pViewGroup->GetDataProvider() : NULL; } m_ptrDraggingEventNew = pData ? pData->CreateNewEvent() : CXTPCalendarEventPtr(NULL); if (!m_ptrDraggingEventNew) return; //--------------------------------------------------------------------------- UINT uScheduleID = XTP_SAFE_GET1(pViewGroup, GetScheduleID(), 0); m_ptrDraggingEventNew->SetScheduleID(uScheduleID); m_ptrDraggingEventNew->SetStartTime(min(dtSelBegin, dtSelEnd)); m_ptrDraggingEventNew->SetEndTime(max(dtSelBegin, dtSelEnd)); m_ptrDraggingEventNew->SetBusyStatus(bAllDayEvent ? xtpCalendarBusyStatusFree : xtpCalendarBusyStatusBusy); m_ptrDraggingEventNew->SetAllDayEvent(bAllDayEvent); //=========================================================================== XTP_SAFE_CALL1(GetCalendarControl(), Populate()); XTP_SAFE_CALL1(GetCalendarControl(), AdjustLayout()); //--------------------------------------------------------------------------- COleDateTime dtEventDay = m_ptrDraggingEventNew->GetStartTime(); dtEventDay = GetDateTimeDay(dtEventDay, m_ptrDraggingEventNew->IsAllDayEvent()); CXTPCalendarViewEvent* pViewEvent = FindViewEvent(m_ptrDraggingEventNew, dtEventDay); if (!pViewEvent) { CancelDraggingEvent(); return; } StartEditSubject(pViewEvent); CEdit* pEditor = DYNAMIC_DOWNCAST(CEdit, pViewEvent->GetSubjectEditor()); if (pEditor) { pEditor->SetWindowText(pcszInitialSubject); int nInitTxtLen = (int)_tcsclen(pcszInitialSubject); pEditor->SetSel(nInitTxtLen, nInitTxtLen); } } void CXTPCalendarView::StartEditSubject(CXTPCalendarViewEvent* pViewEvent) { if (!pViewEvent) return; if (m_nTimerID_StartEditSubject) { KillTimer(m_nTimerID_StartEditSubject); m_nTimerID_StartEditSubject = 0; } m_ptrEditingViewEvent = pViewEvent->StartEditSubject(); if (!m_ptrEditingViewEvent) return; CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateRedraw); m_ptrEditingViewEvent->InternalAddRef(); m_eDraggingMode = xtpCalendaDragModeEditSubject; if (!m_ptrDraggingEventOrig && !m_ptrDraggingEventNew) SetDraggingEvent(m_ptrEditingViewEvent->GetEvent()); SelectEvent(m_ptrDraggingEventNew); } void CXTPCalendarView::EndEditSubject(XTPCalendarEndEditSubjectAction eAction, BOOL bUpdateControl) { m_eDraggingMode = xtpCalendaDragModeUnknown; // kill timeout request to edit subject if (m_nTimerID_StartEditSubject) { _ASSERTE(!!m_ptrEditingViewEvent && !m_ptrDraggingEventOrig && !m_ptrDraggingEventNew); KillTimer(m_nTimerID_StartEditSubject); m_nTimerID_StartEditSubject = 0; m_ptrEditingViewEvent = NULL; return; } _ASSERTE(!!m_ptrEditingViewEvent && !!m_ptrDraggingEventNew); CXTPCalendarEventPtr ptrEventToSelect(m_ptrDraggingEventNew, TRUE); BOOL bPopulate = FALSE; CString strNewSubject; //- end edit subject operation in Event view (kill edit wnd) ---------------- if (m_ptrEditingViewEvent) strNewSubject = m_ptrEditingViewEvent->EndEditSubject(); m_ptrEditingViewEvent = NULL; //--------------------------------------------------------------------------- if (m_ptrDraggingEventNew) { if (eAction == xtpCalendarEditSubjectCommit) { m_ptrDraggingEventNew->SetSubject(strNewSubject); if (!strNewSubject.IsEmpty()) bPopulate = CommitDraggingEvent(); else { ptrEventToSelect.SetPtr(m_ptrDraggingEventOrig, TRUE); CancelDraggingEvent(); bPopulate = TRUE; } } else if (eAction == xtpCalendarEditSubjectCancel) { ptrEventToSelect.SetPtr(m_ptrDraggingEventOrig, TRUE); CancelDraggingEvent(); bPopulate = TRUE; } else { _ASSERTE(FALSE); } } if (bUpdateControl && bPopulate && GetCalendarControl()) { GetCalendarControl()->Populate(); if (ptrEventToSelect) { SelectEvent(ptrEventToSelect, TRUE); } } } void CXTPCalendarView::OnUpdateEditingSubject(CString strNewSubject) { if (!!m_ptrEditingViewEvent && !!m_ptrDraggingEventNew) m_ptrDraggingEventNew->SetSubject(strNewSubject); } CRect CXTPCalendarView::GetSubjectEditorRect() const { _ASSERTE(!!m_ptrEditingViewEvent); if (m_ptrEditingViewEvent) { return m_ptrEditingViewEvent->GetSubjectEditorRect(); } return CRect(INT_MAX, INT_MAX, INT_MAX, INT_MAX); } CRect CXTPCalendarView::GetTooltipRect(const CPoint& ptHit, const XTP_CALENDAR_HITTESTINFO& hitInfo) const { CRect rcTip; rcTip.SetRectEmpty(); if (hitInfo.pViewGroup) { rcTip = hitInfo.pViewGroup->GetTooltipRect(ptHit, hitInfo); CXTPCalendarThemeOffice2007* pThemeX = DYNAMIC_DOWNCAST(CXTPCalendarThemeOffice2007, GetTheme()); if (pThemeX) { CRect rcExclude = XTP_SAFE_GET2(pThemeX->GetPrevNextEventButtonsPartX(), GetNextEventButtonPartX(), GetRect(), CRect(0, 0, 0, 0)); if (!(rcTip.top > rcExclude.bottom || rcTip.bottom < rcExclude.top) && rcTip.right >= rcExclude.left) { rcTip.right = rcExclude.left - XTP_DPI_X(1); } rcExclude = XTP_SAFE_GET2(pThemeX->GetPrevNextEventButtonsPartX(), GetPrevEventButtonPartX(), GetRect(), CRect(0, 0, 0, 0)); if (!(rcTip.top > rcExclude.bottom || rcTip.bottom < rcExclude.top) && rcTip.left <= rcExclude.right) { rcTip.left = rcExclude.right + XTP_DPI_X(1); } } } return rcTip; } void CXTPCalendarView::ShowToolTip(BOOL bShow) { if (m_nTimerID_ShowToolTip) { KillTimer(m_nTimerID_ShowToolTip); m_nTimerID_ShowToolTip = 0; } CXTPCalendarControl* pControl = GetCalendarControl(); if (!pControl) return; if (!bShow) { // hide a tooltip pControl->HideToolTip(); return; } if (pControl->IsToolTipVisible()) { return; } // Verify whether mouse is still under tooltip rect CRect rcTooltip; rcTooltip.SetRectEmpty(); CPoint pt; GetCursorPos(&pt); pControl->ScreenToClient(&pt); XTP_CALENDAR_HITTESTINFO hitInfo; BOOL bHitTest = HitTest(pt, &hitInfo); if (bHitTest) { rcTooltip = GetTooltipRect(pt, hitInfo); } if (m_rcTooltip != rcTooltip) m_rcTooltip.SetRectEmpty(); if (m_rcTooltip.IsRectEmpty()) return; CString strTip; if (GetViewType() != xtpCalendarTimeLineView) { // if we are under event view -- do not show this tooltip if (NULL != hitInfo.pViewEvent) return; BOOL bTipEnabled = XTP_SAFE_GET2(pControl, GetCalendarOptions(), bEnableAddNewTooltip, TRUE); BOOL bAllowCreate = XTP_SAFE_GET2(pControl, GetCalendarOptions(), bEnableInPlaceCreateEvent, TRUE); if (!bTipEnabled || !bAllowCreate) return; // create tooltip text if (!pControl->m_bReadOnlyMode) strTip = XTP_SAFE_GET2(pControl, GetCalendarOptions(), strTooltipAddNewText, CString(_T("Click to add appointment"))); else strTip.Empty(); } else if (hitInfo.pViewEvent) // TimeLine mode { if (hitInfo.pViewEvent->GetEvent() && hitInfo.pViewEvent->GetEvent()->IsEventVisible()) strTip = hitInfo.pViewEvent->GetEvent()->GetSubject(); } // show tooltip window if (pControl) { CFont* pFont = &XTP_SAFE_GET2(GetPaintManager(), GetDayViewEventPart(), GetTextFont(), *((CFont*)(NULL))); pControl->ShowToolTip(strTip, m_rcTooltip, pFont, TRUE); } } void CXTPCalendarView::_CalculateEventTimeFormat() { //////////////////////////////////////////////////////////////////////////// // LOCALE_STIME // time separator // // LOCALE_ITLZERO //leading zeros in time field // 0 No leading zeros for hours. // 1 Leading zeros for hours. // // LOCALE_ITIME // time format specifier // 0 AM / PM 12-hour format. // 1 24-hour format. // // LOCALE_ITIMEMARKPOSN // time marker position // 0 Use as suffix. // 1 Use as prefix. // // LOCALE_S1159 // AM designator // LOCALE_S2359 // PM designator //////////////////////////////////////////////////////////////////////////// if (m_EventTimeFormat.isCustom == TRUE) return; CString strTmp; CString strTimeSeparator = CXTPCalendarUtils::GetLocaleString(LOCALE_STIME, 16); strTmp = CXTPCalendarUtils::GetLocaleString(LOCALE_ITIME, 16); BOOL b24_HFormat = _ttoi(strTmp) == 1; strTmp = CXTPCalendarUtils::GetLocaleString(LOCALE_ITLZERO, 16); BOOL bH_LZero = _ttoi(strTmp) == 1; strTmp = CXTPCalendarUtils::GetLocaleString(LOCALE_ITIMEMARKPOSN, 16); BOOL bAM_PM_Prefix = _ttoi(strTmp) == 1; //--------------------------------------------------------------------------- CString strTimeFormat; strTimeFormat += strTimeSeparator; strTimeFormat += _T("mm"); if (b24_HFormat) { strTmp = bH_LZero ? _T("HH") : _T("H"); strTimeFormat = strTmp + strTimeFormat; } else // 12 AM/PM Format { strTmp = bH_LZero ? _T("hh") : _T("h"); strTimeFormat = strTmp + strTimeFormat; if (bAM_PM_Prefix) { strTimeFormat = _T("tt ") + strTimeFormat; } else { strTimeFormat = strTimeFormat + _T("tt"); } } //--------------------------------------------------------------------------- m_EventTimeFormat.strFormat = strTimeFormat; m_EventTimeFormat.b24_HFormat = b24_HFormat; m_EventTimeFormat.strAM = CXTPCalendarUtils::GetLocaleString(LOCALE_S1159, 20); m_EventTimeFormat.strPM = CXTPCalendarUtils::GetLocaleString(LOCALE_S2359, 20); } CString CXTPCalendarView::FormatEventTime(COleDateTime dtTime) const { CString strTime; SYSTEMTIME st; ZeroMemory(&st, sizeof(st)); if (CXTPCalendarUtils::GetAsSystemTime(dtTime, st)) { strTime = CXTPCalendarUtils::GetTimeFormat(&st, m_EventTimeFormat.strFormat); } if (strTime.IsEmpty()) { _ASSERTE(FALSE); strTime.Format(_T("%d:%02d"), dtTime.GetHour(), dtTime.GetMinute()); } //- make AM/PM as lower case --------------------------------------- if (!m_EventTimeFormat.b24_HFormat) { CString strAM_lower = m_EventTimeFormat.strAM; CString strPM_lower = m_EventTimeFormat.strPM; strAM_lower.MakeLower(); strPM_lower.MakeLower(); strTime.Replace(m_EventTimeFormat.strAM, strAM_lower); strTime.Replace(m_EventTimeFormat.strPM, strPM_lower); } return strTime; } void CXTPCalendarView::SetCustomTimeFormat(const CString& strFormat) { m_EventTimeFormat.strFormat = strFormat; m_EventTimeFormat.isCustom = TRUE; m_EventTimeFormat.b24_HFormat = TRUE; m_EventTimeFormat.strAM = _T(""); m_EventTimeFormat.strPM = _T(""); } void CXTPCalendarView::ResetCustomTimeFormat() { m_EventTimeFormat.isCustom = FALSE; _CalculateEventTimeFormat(); } CString CXTPCalendarView::GetItemTextEventTimeMax() const { COleDateTime dtTestTime; dtTestTime.SetTime(23, 59, 59); CString strTime = FormatEventTime(dtTestTime); DWORD dwFlags = GetCalendarControl()->GetAskItemTextFlags(); if (dwFlags & (xtpCalendarItemText_EventStartTimeText | xtpCalendarItemText_EventEndTimeText)) { XTP_CALENDAR_GETITEMTEXT_PARAMS objRequest; ::ZeroMemory(&objRequest, sizeof(objRequest)); objRequest.nItem = xtpCalendarItemText_EventStartTimeText /*| xtpCalendarItemText_EventEndTimeText*/; objRequest.pstrText = &strTime; GetCalendarControl()->SendNotificationAlways(XTP_NC_CALENDAR_GETITEMTEXT, (WPARAM)&objRequest, 0); } return strTime; } BOOL CXTPCalendarView::_Undo(CXTPCalendarEvent* pEvent) { if (IsEditingSubject()) EndEditSubject(xtpCalendarEditSubjectCommit); if (!GetCalendarControl()) return FALSE; CXTPAutoResetValue autoSet_UpdateCtrlNf( GetCalendarControl()->m_bUpdateWhenEventChangedNotify); autoSet_UpdateCtrlNf = FALSE; CXTPCalendarEventPtr ptrEventNew; CXTPCalendarEventPtr ptrEventOld; if (pEvent) { ptrEventNew = m_pUndoBuffer->UndoAllForEvent(pEvent); ptrEventOld = m_pUndoBuffer->RedoAllForEvent(pEvent); } else { CXTPCalendarEventPtr ptrUndoEvent = m_pUndoBuffer->GetFirstUndoEvent(); if (ptrUndoEvent) { if (m_eUndoMode == xtpCalendarUndoModeUndo) { ptrEventNew = m_pUndoBuffer->UndoAllForEvent(ptrUndoEvent); ptrEventOld = m_pUndoBuffer->RedoAllForEvent(ptrUndoEvent); m_eUndoMode = xtpCalendarUndoModeRedo; } else if (m_eUndoMode == xtpCalendarUndoModeRedo) { ptrEventNew = m_pUndoBuffer->RedoAllForEvent(ptrUndoEvent); ptrEventOld = m_pUndoBuffer->UndoAllForEvent(ptrUndoEvent); m_eUndoMode = xtpCalendarUndoModeUndo; } else { _ASSERTE(FALSE); return FALSE; } } } if (!!ptrEventNew || !!ptrEventOld) { CXTPCalendarControl::CUpdateContext updateContext(m_pControl, xtpCalendarUpdateLayout | xtpCalendarUpdateRedraw); if (!!ptrEventNew && !!ptrEventOld && ptrEventNew->GetDataProvider()) { VERIFY(ptrEventNew->GetDataProvider()->ChangeEvent(ptrEventNew)); } else if (!!ptrEventNew && !ptrEventOld && ptrEventNew->GetDataProvider()) { VERIFY(ptrEventNew->GetDataProvider()->AddEvent(ptrEventNew)); } else if (!ptrEventNew && !!ptrEventOld && ptrEventOld->GetDataProvider()) { VERIFY(ptrEventOld->GetDataProvider()->DeleteEvent(ptrEventOld)); } XTP_SAFE_CALL1(GetCalendarControl(), Populate()); return TRUE; } return FALSE; } BOOL CXTPCalendarView::CanUndo() const { if (m_eUndoMode == xtpCalendarUndoModeUndo && m_pUndoBuffer->GetCount()) return TRUE; return _CanSubjectEditor(ID_EDIT_UNDO); } CWnd* CXTPCalendarView::_GetSubjectEditorWnd() const { if (m_ptrEditingViewEvent) return m_ptrEditingViewEvent->GetSubjectEditor(); return NULL; } BOOL CXTPCalendarView::_CanSubjectEditor(UINT idEditCmd) const { CWnd* pSEditorWnd = _GetSubjectEditorWnd(); if (!pSEditorWnd) return FALSE; CEdit* pSEditor = DYNAMIC_DOWNCAST(CEdit, pSEditorWnd); if (!pSEditor) return FALSE; BOOL bSEFocused = CWnd::GetFocus() && CWnd::GetFocus()->GetSafeHwnd() == pSEditorWnd->GetSafeHwnd(); if (!bSEFocused) return FALSE; int nSel1 = -1, nSel2 = -1; pSEditor->GetSel(nSel1, nSel2); switch (idEditCmd) { case ID_EDIT_UNDO: return pSEditor->CanUndo(); case ID_EDIT_CUT: return nSel1 < nSel2; case ID_EDIT_COPY: return nSel1 < nSel2; case ID_EDIT_PASTE: return ::IsClipboardFormatAvailable(CF_TEXT); } return FALSE; } BOOL CXTPCalendarView::CanRedo() const { return m_eUndoMode == xtpCalendarUndoModeRedo && m_pUndoBuffer->GetCount(); } BOOL CXTPCalendarView::Undo() { _ASSERTE(m_eUndoMode == xtpCalendarUndoModeUndo || _CanSubjectEditor(ID_EDIT_UNDO)); return _Undo(); } BOOL CXTPCalendarView::Redo() { _ASSERTE(m_eUndoMode == xtpCalendarUndoModeRedo); return _Undo(); } CString CXTPCalendarView::_GetMaxWidthFormat(CDC* pDC, CString strFormat, BOOL bMonth) const { if (!pDC) { _ASSERTE(FALSE); return _T(""); } SYSTEMTIME st; ZeroMemory(&st, sizeof(st)); st.wDay = 20; st.wMonth = 1; st.wYear = (WORD)CXTPCalendarUtils::GetCurrentTime().GetYear(); int nMax = 0; CString str; int nCount = bMonth ? 12 : 7; for (int i = 0; i < nCount; i++) { CString strResult = CXTPCalendarUtils::GetDateFormat(&st, strFormat); int nLen = pDC->GetTextExtent(strResult).cx; if (nMax < nLen) { str = strResult; nMax = nLen; } if (bMonth) st.wMonth++; else st.wDay++; } return str; } int CXTPCalendarView::_GetMaxWidth(CDC* pDC, CString strFormat) const { if (!pDC) { _ASSERTE(FALSE); return 1; } const TCHAR* chFormats[] = { _T("yyyy"), _T("yyy"), _T("yy"), _T("y"), _T("MMMM"), _T("MMM"), _T("dddd"), _T("ddd"), _T("dd"), _T("d") }; for (int i = 0; i < _countof(chFormats); i++) { int nPos = strFormat.Find(chFormats[i]); if (nPos >= 0) { strFormat.Replace(chFormats[i], _GetMaxWidthFormat(pDC, chFormats[i], i < 2)); } } return pDC->GetTextExtent(strFormat).cx; } void CXTPCalendarView::_RemoveYearPart(CString& strFormat) { strFormat = CXTPCalendarUtils::RemoveFormatPart(strFormat, _T('y')); } void CXTPCalendarView::_ReadDefaultHeaderFormats() { m_strDayHeaderFormatDefaultLong = CXTPCalendarUtils::GetLocaleString(LOCALE_SLONGDATE, 81); if (!GetCalendarControl()->m_bFullDateMode) _RemoveYearPart(m_strDayHeaderFormatDefaultLong); m_strDayHeaderFormatDefaultMiddle = m_strDayHeaderFormatDefaultLong; m_strDayHeaderFormatDefaultMiddle.Replace(_T("MMMM"), _T("MMM")); m_strDayHeaderFormatDefaultShort = m_strDayHeaderFormatDefaultMiddle; m_strDayHeaderFormatDefaultShort.Replace(_T("dddd"), _T("ddd")); m_strDayHeaderFormatDefaultShortest = CXTPCalendarUtils::GetLocaleString(LOCALE_SSHORTDATE, 81); if (!GetCalendarControl()->m_bFullDateMode) _RemoveYearPart(m_strDayHeaderFormatDefaultShortest); } // nLevel = 0 - Long, 1 - Middle, 2 - Short, 3 - Shortest. CString CXTPCalendarView::_GetDayHeaderFormat(int nLevel) const { switch (nLevel) { case 0: return m_strDayHeaderFormatLong.IsEmpty() ? m_strDayHeaderFormatDefaultLong : m_strDayHeaderFormatLong; case 1: return m_strDayHeaderFormatMiddle.IsEmpty() ? m_strDayHeaderFormatDefaultMiddle : m_strDayHeaderFormatMiddle; case 2: return m_strDayHeaderFormatShort.IsEmpty() ? m_strDayHeaderFormatDefaultShort : m_strDayHeaderFormatShort; case 3: return m_strDayHeaderFormatShortest.IsEmpty() ? m_strDayHeaderFormatDefaultShortest : m_strDayHeaderFormatShortest; } _ASSERTE(FALSE); return _T(""); } void CXTPCalendarView::CalculateHeaderFormat(CDC* pDC, int nWidth, CFont* pTextFont) { if (!GetCalendarControl() || !pTextFont || !pDC) { _ASSERTE(FALSE); return; } _ReadDefaultHeaderFormats(); CXTPFontDC fnt(pDC, pTextFont); int arBorder[] = { XTP_DPI_X(40), XTP_DPI_X(35), XTP_DPI_X(20), 0 }; for (int i = 0; i <= 3; i++) { m_strHeaderFormat = _GetDayHeaderFormat(i); int nLen = _GetMaxWidth(pDC, m_strHeaderFormat); if (nLen < nWidth - arBorder[i]) { return; } } } COleDateTimeSpan CXTPCalendarView::GetEventDurationMin() const { return COleDateTimeSpan(0.); } BOOL CXTPCalendarView::CanCut() const { return !IsEditingSubject() && HasSelectedViewEvent() || IsEditingSubject() && _CanSubjectEditor(ID_EDIT_CUT); } BOOL CXTPCalendarView::CanCopy() const { return !IsEditingSubject() && HasSelectedViewEvent() || IsEditingSubject() && _CanSubjectEditor(ID_EDIT_COPY); } BOOL CXTPCalendarView::CanPaste() const { if (!GetSelection()) { return FALSE; } //- Register or get existing Clipboard Format ID ------------------------- UINT uCF_Event = ::RegisterClipboardFormat(XTPCALENDARCTRL_CF_EVENT); BOOL bIsEventInClipboard = ::IsClipboardFormatAvailable(uCF_Event); return !IsEditingSubject() && bIsEventInClipboard || IsEditingSubject() && _CanSubjectEditor(ID_EDIT_PASTE); } BOOL CXTPCalendarView::Cut() { if (IsEditingSubject() && _GetSubjectEditorWnd()) { if (CanCut()) { _GetSubjectEditorWnd()->SendMessage(WM_CUT); return TRUE; } return FALSE; } //=========================================================================== CXTPCalendarViewEventsPtr ptrSelViews = GetSelectedEvents(); if (!ptrSelViews || !ptrSelViews->GetCount()) { return FALSE; } if (OnBeforeEditOperationNotify(xtpCalendarEO_Cut, ptrSelViews)) { return FALSE; } //------------------------------------------------------------------------ DWORD dwCopyFlags = xtpCalendarCopyFlagCutMask; COleDataSource* pData = _CopySelectedEvents(dwCopyFlags); if (!pData) { return FALSE; } pData->SetClipboard(); int nCount = ptrSelViews->GetCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewEvent* pViewEvent = ptrSelViews->GetAt(i, FALSE); CXTPCalendarEvent* pEvent = pViewEvent ? pViewEvent->GetEvent() : NULL; VERIFY(XTP_SAFE_GET2(pEvent, GetDataProvider(), DeleteEvent(pEvent), FALSE)); } XTP_SAFE_CALL1(GetCalendarControl(), Populate()); return TRUE; } BOOL CXTPCalendarView::Copy() { if (IsEditingSubject() && _GetSubjectEditorWnd()) { if (CanCopy()) { _GetSubjectEditorWnd()->SendMessage(WM_COPY); return TRUE; } return FALSE; } CXTPCalendarViewEventsPtr ptrSelViews = GetSelectedEvents(); if (!ptrSelViews || !ptrSelViews->GetCount()) return FALSE; if (OnBeforeEditOperationNotify(xtpCalendarEO_Copy, ptrSelViews)) return FALSE; COleDataSource* pData = _CopySelectedEvents(); if (!pData) return FALSE; pData->SetClipboard(); return TRUE; } BOOL CXTPCalendarView::Paste() { if (IsEditingSubject() && _GetSubjectEditorWnd()) { if (CanPaste()) { _GetSubjectEditorWnd()->SendMessage(WM_PASTE); return TRUE; } return FALSE; } COleDateTime dtSelBegin, dtSelEnd; COleDateTimeSpan spSelectionResolution; if (!GetSelection(&dtSelBegin, &dtSelEnd, NULL, NULL, &spSelectionResolution)) { return FALSE; } dtSelBegin = min(dtSelBegin, dtSelEnd); // Attach a COleDataObject to the clipboard and paste the data COleDataObject objData; if (!objData.AttachClipboard()) { return FALSE; } DWORD dwCopyFlags = 0; CXTPCalendarEventsPtr ptrEventsFromCB = _ReadEventsFromClipboard(&objData, &dwCopyFlags); if (!ptrEventsFromCB) return FALSE; if (!GetCalendarControl()) return FALSE; CXTPAutoResetValue autoSet_UpdateCtrlNf( GetCalendarControl()->m_bUpdateWhenEventChangedNotify); autoSet_UpdateCtrlNf = FALSE; COleDateTimeSpan spStartShift; int nCount = ptrEventsFromCB->GetCount(); for (int i = 0; i < nCount; i++) { BOOL bUseChangeEvent = FALSE; CXTPCalendarEvent* pNewEvent = ptrEventsFromCB->GetAt(i, FALSE); if (!pNewEvent) { _ASSERTE(FALSE); continue; } int nRState = pNewEvent->GetRecurrenceState(); if (nRState == xtpCalendarRecurrenceMaster) { _ASSERTE(FALSE); // WARNING. Master event in the clipboard - ??? VERIFY(pNewEvent->RemoveRecurrence()); } if (nRState == xtpCalendarRecurrenceOccurrence && dwCopyFlags & xtpCalendarCopyFlagROccurrence2RException) { VERIFY(pNewEvent->MakeAsRException()); bUseChangeEvent = TRUE; } else { VERIFY(pNewEvent->RemoveRecurrence()); } // Update recurrence state nRState = pNewEvent->GetRecurrenceState(); if (nRState == xtpCalendarRecurrenceException && dwCopyFlags & xtpCalendarCopyFlagKeepRException) { CXTPCalendarRecurrencePatternPtr ptrPattern = pNewEvent->GetRecurrencePattern(); bUseChangeEvent = !!ptrPattern; } if (!bUseChangeEvent && nRState == xtpCalendarRecurrenceException) { VERIFY(pNewEvent->RemoveRecurrence()); } COleDateTime dtEventStart = pNewEvent->GetStartTime(); if (i == 0) { spStartShift = dtSelBegin - dtEventStart; spStartShift += ((double)spStartShift < 0 ? -1 : 1) * XTP_HALF_SECOND; double dCells = (double)spStartShift / (double)spSelectionResolution; int nCells = (int)dCells; //+ (dCells >= 0 ? 1 : 0); double dCellDrobTime = fabs(dCells - (DWORD)dCells) * (double)spSelectionResolution; double dCellDrobTimeLimit = XTP_HALF_SECOND * 2 * 10; if (dCells >= 0 && dCellDrobTime > dCellDrobTimeLimit) { nCells++; } spStartShift = (double)spSelectionResolution * (double)nCells; } dtEventStart += spStartShift; pNewEvent->MoveEvent(dtEventStart); if (OnBeforePasteNotify(pNewEvent, bUseChangeEvent)) continue; if (bUseChangeEvent) { VERIFY(XTP_SAFE_GET2(pNewEvent, GetDataProvider(), ChangeEvent(pNewEvent), FALSE)); } else { VERIFY(XTP_SAFE_GET2(pNewEvent, GetDataProvider(), AddEvent(pNewEvent), FALSE)); } } if (dwCopyFlags & xtpCalendarCopyFlagClearCBAfterPaste) { if (::OpenClipboard(NULL)) { ::EmptyClipboard(); ::CloseClipboard(); } } XTP_SAFE_CALL1(GetCalendarControl(), Populate()); return TRUE; } CXTPCalendarEventsPtr CXTPCalendarView::_ReadEventsFromClipboard(COleDataObject* pData, DWORD* pdwCopyFlags) { //- Register or get existing Clipboard Format ID ------------------------- CLIPFORMAT uCF_Event = (CLIPFORMAT)::RegisterClipboardFormat(XTPCALENDARCTRL_CF_EVENT); _ASSERTE(pData); if (!pData || !pData->IsDataAvailable(uCF_Event)) { return NULL; } CXTPCalendarEventsPtr ptrEvents = new CXTPCalendarEvents(); if (!ptrEvents) { return NULL; } const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; try { HGLOBAL hData = pData->GetGlobalData(uCF_Event); if (!hData) { return NULL; } CSharedFile fileSahred; fileSahred.SetHandle(hData, FALSE); CArchive ar(&fileSahred, CArchive::load); CXTPPropExchangeArchive px(ar); long nSchema = 0; DWORD dwCopyFlags = 0; PX_Long(&px, _T("Version"), (long&)nSchema); px.ExchangeLocale(); PX_DWord(&px, _T("CopyFlags"), (DWORD&)dwCopyFlags); if (nSchema != XTP_CLIPBOARD_EVENTS_DATA_VER) { _ASSERTE(FALSE); return NULL; } CXTPPropExchangeSection sec(px.GetSection(_T("Events"))); CXTPPropExchangeEnumeratorPtr pEnumerator(sec->GetEnumerator(_T("Event"))); POSITION pos = pEnumerator->GetPosition(); UINT uScheduleID = 0; CXTPCalendarData* pDPsel = _GetDataProviderBySelection(&uScheduleID); while (pos) { CXTPPropExchangeSection secEvent(pEnumerator->GetNext(pos)); CXTPCalendarData* pDPevent = NULL; //-- get data provider -------------------- CString strDataProvider; PX_String(&secEvent, _T("DataProvider_ConnectionString"), strDataProvider, _T("")); if (!strDataProvider.IsEmpty()) pDPevent = _GetDataProviderByConnStr(strDataProvider); CXTPCalendarData* pDataProvider = pDPevent ? pDPevent : pDPsel; _ASSERTE(pDataProvider); //-- create event and read its data --------- CXTPCalendarEventPtr ptrEvent; if (pDataProvider) ptrEvent = pDataProvider->CreateNewEvent(); if (!ptrEvent) return NULL; ptrEvent->DoPropExchange(&secEvent); if (!pDPevent || !_IsScheduleVisible(pDPevent, ptrEvent->GetScheduleID())) ptrEvent->SetScheduleID(uScheduleID); ptrEvents->Add(ptrEvent, TRUE); } ar.Close(); // detach from file if (pdwCopyFlags) *pdwCopyFlags = dwCopyFlags; return ptrEvents; } catch (CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPCalendarView::_ReadEventsFromClipboard() - %s\n"), szErrText); } pE->Delete(); } catch (CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPCalendarView::_ReadEventsFromClipboard() - %s\n"), szErrText); } pE->Delete(); } catch (...) { TRACE( _T("EXCEPTION: CXTPCalendarView::_ReadEventsFromClipboard() - Unhandled Exception!\n")); } _ASSERTE(FALSE); return NULL; } COleDataSource* CXTPCalendarView::_CopySelectedEvents(DWORD dwCopyFlags) { CXTPCalendarViewEventsPtr ptrSelViews = GetSelectedEvents(); if (!ptrSelViews || !ptrSelViews->GetCount()) return NULL; const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; try { CSharedFile fileSahred(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT); CArchive ar(&fileSahred, CArchive::store); CXTPPropExchangeArchive px(ar); long nSchema = XTP_CLIPBOARD_EVENTS_DATA_VER; PX_Long(&px, _T("Version"), (long&)nSchema); px.ExchangeLocale(); PX_DWord(&px, _T("CopyFlags"), (DWORD&)dwCopyFlags); int nCount = ptrSelViews->GetCount(); CXTPPropExchangeSection sec(px.GetSection(_T("Events"))); CXTPPropExchangeEnumeratorPtr pEnumerator(sec->GetEnumerator(_T("Event"))); POSITION posEnum = pEnumerator->GetPosition((DWORD)nCount); for (int i = 0; i < nCount; i++) { CXTPCalendarViewEvent* pViewEvent = ptrSelViews->GetAt(i, FALSE); CXTPCalendarEvent* pEvent = pViewEvent->GetEvent(); if (!pEvent) { _ASSERTE(FALSE); continue; } CXTPPropExchangeSection secEvent(pEnumerator->GetNext(posEnum)); CString strDataProvider = XTP_SAFE_GET2(pEvent, GetDataProvider(), GetConnectionString(), CString()); PX_String(&secEvent, _T("DataProvider_ConnectionString"), strDataProvider); pEvent->DoPropExchange(&secEvent); } ar.Close(); // perform Flush() and detach from file //- Prepare Global data ---------------------------------------------- DWORD dwDataSize = (DWORD)fileSahred.GetLength(); HGLOBAL hData = fileSahred.Detach(); if (!hData) { _ASSERTE(FALSE); return NULL; } hData = ::GlobalReAlloc(hData, dwDataSize, GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT); if (!hData) { _ASSERTE(FALSE); return NULL; } //- Register Clipboard Format ---------------------------------------- CLIPFORMAT uCF_Event = (CLIPFORMAT)::RegisterClipboardFormat(XTPCALENDARCTRL_CF_EVENT); // Cache data COleDataSource* pSource = new COleDataSource(); if (pSource) { pSource->CacheGlobalData(uCF_Event, hData); } return pSource; } catch (CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPCalendarView::_CopySelectedEvents() - %s\n"), szErrText); } pE->Delete(); } catch (CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPCalendarView::_CopySelectedEvents() - %s\n"), szErrText); } pE->Delete(); } catch (...) { TRACE(_T("EXCEPTION: CXTPCalendarView::_CopySelectedEvents() - Unhandled Exception!\n")); } _ASSERTE(FALSE); return NULL; } //////////////////////////////////////////////////////////////////////////// CXTPCalendarPaintManager* CXTPCalendarView::GetPaintManager() const { _ASSERTE(m_pControl); return m_pControl ? m_pControl->GetPaintManager() : NULL; } CXTPCalendarTheme* CXTPCalendarView::GetTheme() const { return m_pControl ? m_pControl->GetTheme() : NULL; } void CXTPCalendarView::SendNotification(XTP_NOTIFY_CODE EventCode, WPARAM wParam, LPARAM lParam) { if (m_pControl) m_pControl->SendNotification(EventCode, wParam, lParam); } BOOL CXTPCalendarView::IsEditOperationDisabledNotify(XTPCalendarEditOperation eOperation, CXTPCalendarViewEvent* pEventView) const { return _EditOperationNotify(XTP_NC_CALENDAR_IS_EVENT_EDIT_OPERATION_DISABLED, eOperation, pEventView); } BOOL CXTPCalendarView::OnBeforeEditOperationNotify(XTPCalendarEditOperation eOperation, CXTPCalendarViewEvent* pEventView) { if (IsEditOperationDisabledNotify(eOperation, pEventView)) return TRUE; return _EditOperationNotify(XTP_NC_CALENDAR_BEFORE_EVENT_EDIT_OPERATION, eOperation, pEventView); } BOOL CXTPCalendarView::OnBeforeEditOperationNotify(XTPCalendarEditOperation eOperation, CXTPCalendarViewEvents* pEventViews) { if (_EditOperationNotify(XTP_NC_CALENDAR_IS_EVENT_EDIT_OPERATION_DISABLED, eOperation, NULL, pEventViews)) return TRUE; return _EditOperationNotify(XTP_NC_CALENDAR_BEFORE_EVENT_EDIT_OPERATION, eOperation, NULL, pEventViews); } BOOL CXTPCalendarView::OnBeforePasteNotify(CXTPCalendarEvent* pEvent, BOOL bPasteWillChangeExistingEvent) { XTP_EDIT_OPERATION_PARAMS* pOpPasteParams = new XTP_EDIT_OPERATION_PARAMS; memset(pOpPasteParams, 0, sizeof(*pOpPasteParams)); pOpPasteParams->header.eOperation = xtpCalendarEO_Paste; ++pOpPasteParams->header.nRefCounter; pOpPasteParams->pasteParams.pEvent = pEvent; pOpPasteParams->pasteParams.bPasteWillChangeExistingEvent = bPasteWillChangeExistingEvent; BOOL bDisabledHandled = FALSE; if (m_pControl) { m_pControl->SendNotification(XTP_NC_CALENDAR_IS_EVENT_EDIT_OPERATION_DISABLED, (WPARAM)pOpPasteParams, (LPARAM)&bDisabledHandled); } if (bDisabledHandled) { return TRUE; } if (m_pControl) { m_pControl->SendNotification(XTP_NC_CALENDAR_BEFORE_EVENT_EDIT_OPERATION, (WPARAM)pOpPasteParams, (LPARAM)&bDisabledHandled); } if (0 == --pOpPasteParams->header.nRefCounter) { delete pOpPasteParams; } return bDisabledHandled; } BOOL CXTPCalendarView::OnInPlaceCreateEvent(LPCTSTR pcszInitialSubject) { XTP_EDIT_OPERATION_PARAMS* pOpParams = new XTP_EDIT_OPERATION_PARAMS; memset(pOpParams, 0, sizeof(*pOpParams)); pOpParams->header.eOperation = xtpCalendarEO_InPlaceCreateEvent; ++pOpParams->header.nRefCounter; pOpParams->inPlaceCreateEventParams.pcszInitialSubject = pcszInitialSubject; BOOL bDisabledHandled = FALSE; if (m_pControl) { m_pControl->SendNotification(XTP_NC_CALENDAR_IS_EVENT_EDIT_OPERATION_DISABLED, (WPARAM)pOpParams, (LPARAM)&bDisabledHandled); } if (bDisabledHandled) { return TRUE; } if (m_pControl) { m_pControl->SendNotification(XTP_NC_CALENDAR_BEFORE_EVENT_EDIT_OPERATION, (WPARAM)pOpParams, (LPARAM)&bDisabledHandled); } if (0 == --pOpParams->header.nRefCounter) { delete pOpParams; } return bDisabledHandled; } CXTPCalendarOptions* CXTPCalendarView::GetCalendarOptions() const { return this && m_pControl ? m_pControl->GetCalendarOptions() : NULL; } BOOL CXTPCalendarView::_EditOperationNotify(XTP_NOTIFY_CODE ncEvent, XTPCalendarEditOperation eOperation, CXTPCalendarViewEvent* pEventView, CXTPCalendarViewEvents* pEventViews) const { _ASSERTE(pEventView || pEventViews && !(pEventView && pEventViews)); XTP_EDIT_OPERATION_PARAMS* pOpParams = new XTP_EDIT_OPERATION_PARAMS; memset(pOpParams, 0, sizeof(*pOpParams)); BOOL bReleaseEvents = FALSE; pOpParams->header.eOperation = eOperation; ++pOpParams->header.nRefCounter; if (NULL != pEventViews) { pOpParams->header.pEventViews = pEventViews; } else { CXTPCalendarViewEvents* pEvents = new CXTPCalendarViewEvents(); pEvents->Add(pEventView, TRUE); pOpParams->header.pEventViews = pEvents; bReleaseEvents = TRUE; } BOOL bDisabledHandled = FALSE; if (m_pControl) { m_pControl->SendNotification(ncEvent, (WPARAM)pOpParams, (LPARAM)&bDisabledHandled); } if (bReleaseEvents) { pOpParams->header.pEventViews->InternalRelease(); } if (0 == --pOpParams->header.nRefCounter) { delete pOpParams; } return bDisabledHandled; } XTPEnumCalendarUpdateResult CXTPCalendarView::OnEventChanged_InDataProvider( XTP_NOTIFY_CODE nfCode, CXTPCalendarEvent* pEvent) { if (!pEvent) return xtpCalendar_Skip; if (nfCode != XTP_NC_CALENDAREVENTWASADDED && nfCode != XTP_NC_CALENDAREVENTWASDELETED && nfCode != XTP_NC_CALENDAREVENTWASCHANGED) return xtpCalendar_Skip; int nDaysCount = GetViewDayCount(); COleDateTime dtFirstDay = nDaysCount ? XTP_SAFE_GET1(GetViewDay_(0), GetDayDate().operator DATE(), (DATE)0) : (DATE)0; COleDateTime dtLastDay = nDaysCount ? XTP_SAFE_GET1(GetViewDay_(nDaysCount - 1), GetDayDate().operator DATE(), (DATE)0) : (DATE)0; if (nfCode == XTP_NC_CALENDAREVENTWASADDED || nfCode == XTP_NC_CALENDAREVENTWASDELETED) { if (GetDateTimeDay(pEvent->GetStartTime(), pEvent->IsAllDayEvent()) > dtLastDay || GetDateTimeDay(pEvent->GetEndTime(), pEvent->IsAllDayEvent()) < dtFirstDay) return xtpCalendar_Skip; return xtpCalendar_Populate; } return xtpCalendar_Populate; // ***** // An Idea how changing event processing can be optimized // from xtpCalendar_Populate to xtpCalendar_Redraw or even xtpCalendar_Skip. // // int nRState_new = pEvent->GetRecurrenceState(); // if (nRState_new == xtpCalendarRecurrenceMaster) { // return xtpCalendar_Populate; // } // // //----------------------------------------------------------------------- // BOOL bUpdateEvent = FALSE; // int nDays = GetViewDayCount(); // for (int nDay = 0; nDay < nDays; nDay++) // { // CXTPCalendarViewDay* pDay = GetViewDay_(nDay); // _ASSERTE(pDay); // if (!pDay) // continue; // // // int nEvents = pDay->GetViewEventsCount(); // for (int nEvent = 0; nEvent < nEvents; nEvent++) // { // CXTPCalendarViewEvent* pEventView = pDay->GetViewEvent_(nEvent); // if (!pEventView && !pEventView->GetEvent()) // { // _ASSERTE(FALSE); // continue; // } // CXTPCalendarEvent* pEvent_I = pEventView->GetEvent(); // if (pEvent_I->GetEventID() == dwEventID) // { // if (!bUpdateEvent) // { // if (pEvent_I->IsEqualStartEnd(pEvent)) // bUpdateEvent = TRUE; // else // return xtpCalendar_Populate; // } // // if (bUpdateEvent) // { // int nRState_I = pEvent_I->GetRecurrenceState(); // //int nRState_new = pEvent->GetRecurrenceState(); // // if (nRState_I == xtpCalendarRecurrenceOccurrence) // pEvent_I->SetRecurrenceState_ExceptionOccurrence(xtpCalendarRecurrenceException); // // pEvent_I->Update(pEvent); // // if (nRState_new == xtpCalendarRecurrenceOccurrence || // nRState_new == xtpCalendarRecurrenceException) // { // _ASSERTE(nRState_I == xtpCalendarRecurrenceOccurrence || // nRState_I == xtpCalendarRecurrenceException); // // pEvent_I->SetRecurrenceState_ExceptionOccurrence((XTPCalendarEventRecurrenceState)nRState_new); // } // } // } // } // // } // // //----------------------------------------------------------------------- // if (!bUpdateEvent && // !(CXTPCalendarUtils::ResetTime(pEvent->GetStartTime()) > dtLastDay || // CXTPCalendarUtils::ResetTime(pEvent->GetEndTime()) < dtFirstDay) // ) // { // return xtpCalendar_Populate; // } // return bUpdateEvent ? xtpCalendar_Redraw : xtpCalendar_Skip; } CXTPCalendarData* CXTPCalendarView::_GetDataProviderBySelection(UINT* puScheduleID) { COleDateTime dtSelBegin; int nGroup = 0; if (!GetSelection(&dtSelBegin, NULL, NULL, &nGroup)) return NULL; CXTPCalendarViewDay* pViewDay = _GetViewDay(dtSelBegin); if (!pViewDay) return NULL; CXTPCalendarData* pData = NULL; CXTPCalendarViewGroup* pViewGroup = NULL; if (pViewDay && nGroup < pViewDay->GetViewGroupsCount()) { pViewGroup = pViewDay->GetViewGroup_(nGroup); if (pViewGroup) { pData = pViewGroup->GetDataProvider(); if (puScheduleID) *puScheduleID = pViewGroup->GetScheduleID(); } } return pData; } CXTPCalendarData* CXTPCalendarView::_GetDataProviderByConnStr(LPCTSTR pcszConnStr, BOOL bCompareNoCase) { CXTPCalendarViewDay* pViewDay = GetViewDay_(0); COleDateTime dtSelBegin; if (GetSelection(&dtSelBegin)) pViewDay = _GetViewDay(dtSelBegin); if (!pViewDay) return NULL; int nGCount = pViewDay->GetViewGroupsCount(); for (int g = 0; g < nGCount; g++) { CXTPCalendarViewGroup* pViewGroup = pViewDay->GetViewGroup_(g); if (pViewGroup) { CXTPCalendarData* pData = pViewGroup->GetDataProvider(); if (pData) { CString strConn_i = pData->GetConnectionString(); int nCmp = bCompareNoCase ? strConn_i.CompareNoCase(pcszConnStr) : strConn_i.Compare(pcszConnStr); if (nCmp == 0) return pData; } } } return NULL; } BOOL CXTPCalendarView::_IsScheduleVisible(CXTPCalendarData* pDataProvider, UINT uScheduleID) { CXTPCalendarViewDay* pViewDay = GetViewDay_(0); COleDateTime dtSelBegin; if (GetSelection(&dtSelBegin)) pViewDay = _GetViewDay(dtSelBegin); if (!pViewDay) return FALSE; int nGCount = pViewDay->GetViewGroupsCount(); for (int g = 0; g < nGCount; g++) { CXTPCalendarViewGroup* pViewGroup = pViewDay->GetViewGroup_(g); CXTPCalendarData* pData = pViewGroup ? pViewGroup->GetDataProvider() : NULL; if (pData && pData == pDataProvider) { int nRCCount = XTP_SAFE_GET2(pViewGroup, GetResources(), GetCount(), 0); for (int i = 0; i < nRCCount; i++) { if (XTP_SAFE_GET3(pViewGroup, GetResources(), GetAt(i), ExistsScheduleID(uScheduleID), FALSE)) return TRUE; } } } return FALSE; } CXTPCalendarWMHandler* CXTPCalendarView::GetChildHandlerAt(int nIndex) const { CXTPCalendarWMHandler* pDay = GetViewDay_(nIndex); if (!pDay) return NULL; ASSERT_KINDOF(CXTPCalendarWMHandler, pDay); return pDay; } CXTPCalendarResources* CXTPCalendarView::GetResources() const { _ASSERTE(this); if (m_pResources) return m_pResources; return GetCalendarControl() ? GetCalendarControl()->GetResources() : NULL; } void CXTPCalendarView::SetResources(CXTPCalendarResources* pResources) { BOOL bChanged = TRUE; if (!pResources) { bChanged = m_pResources != NULL; CMDTARGET_RELEASE(m_pResources); } else { if (!m_pResources) m_pResources = new CXTPCalendarResources(); if (!m_pResources) return; // copy data to allow using self as input parameter CXTPCalendarResources arRes; arRes.Append(pResources); m_pResources->RemoveAll(); m_pResources->Append(&arRes); } if (bChanged) SendNotification(XTP_NC_CALENDAR_RESOURCES_WHERE_CHANGED, 1, (LPARAM)this); } BOOL CXTPCalendarView::IsTodayVisible() const { COleDateTime dtToday = CXTPCalendarUtils::GetCurrentTime(); dtToday = GetDateTimeDay(dtToday, FALSE); int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { COleDateTime dtDay = GetViewDayDate(i); if (CXTPCalendarUtils::IsEqual(dtDay, dtToday)) return TRUE; } return FALSE; } void CXTPCalendarView::EmptyUndoBuffer() { m_pUndoBuffer->RemoveAll(); m_eUndoMode = xtpCalendarUndoModeUnknown; } BOOL CXTPCalendarView::HitTest(CPoint pt, XTP_CALENDAR_HITTESTINFO* pHitTest) const { return HitTestEx(pt, pHitTest); } BOOL CXTPCalendarView::HitTestEx(CPoint pt, XTP_CALENDAR_HITTESTINFO* pHitTest) const { if (!pHitTest) { _ASSERTE(FALSE); return FALSE; } int nCount = GetViewDayCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarViewDay* pViewDay = GetViewDay_(i); _ASSERTE(pViewDay); if (pViewDay && pViewDay->HitTestEx(pt, pHitTest)) { _ASSERTE(!pHitTest->pViewDay || pHitTest->pViewDay == pViewDay); pHitTest->nDay = i; pHitTest->pViewDay = pViewDay; return TRUE; } } return FALSE; } ///////////////////////////////////////////////////////////////////////////// CXTPCalendarView::CSelectionChanged_ContextData::CSelectionChanged_ContextData() { m_nLockCount = 0; m_nLockCount_Day = 0; m_nLockCount_Event = 0; m_bRequest_Day = FALSE; m_bRequest_Event = FALSE; } ///////////////////////////////////////////////////////////////////////////// // class CSelectionChangedContext // CXTPCalendarView::CSelectionChangedContext::CSelectionChangedContext(CXTPCalendarView* pView, int eSelType) { if (!pView) { _ASSERTE(FALSE); return; } m_pView = pView; m_eSelType = eSelType; m_pView->m_cntSelChanged.m_nLockCount += eSelType == xtpCalendarSelectionUnknown ? 1 : 0; m_pView->m_cntSelChanged.m_nLockCount_Day += eSelType == xtpCalendarSelectionDays ? 1 : 0; m_pView->m_cntSelChanged.m_nLockCount_Event += eSelType == xtpCalendarSelectionEvents ? 1 : 0; } CXTPCalendarView::CSelectionChangedContext::~CSelectionChangedContext() { if (!m_pView) { _ASSERTE(FALSE); return; } if (m_eSelType == xtpCalendarSelectionUnknown) m_pView->m_cntSelChanged.m_nLockCount--; if (m_eSelType == xtpCalendarSelectionDays) { m_pView->m_cntSelChanged.m_nLockCount_Day--; if (m_pView->m_cntSelChanged.m_nLockCount_Day == 0) m_pView->m_cntSelChanged.m_bRequest_Day = TRUE; } if (m_eSelType == xtpCalendarSelectionEvents) { m_pView->m_cntSelChanged.m_nLockCount_Event--; if (m_pView->m_cntSelChanged.m_nLockCount_Event == 0) m_pView->m_cntSelChanged.m_bRequest_Event = TRUE; } if (m_pView->m_cntSelChanged.m_nLockCount == 0 && m_pView->m_cntSelChanged.m_bRequest_Day) { m_pView->m_cntSelChanged.m_bRequest_Day = FALSE; m_pView->SendNotification(XTP_NC_CALENDAR_SELECTION_CHANGED, (WPARAM)xtpCalendarSelectionDays); } if (m_pView->m_cntSelChanged.m_nLockCount == 0 && m_pView->m_cntSelChanged.m_bRequest_Event) { m_pView->m_cntSelChanged.m_bRequest_Event = FALSE; m_pView->SendNotification(XTP_NC_CALENDAR_SELECTION_CHANGED, (WPARAM)xtpCalendarSelectionEvents); } } ///////////////////////////////////////////////////////////////////////////// #ifdef _XTP_ACTIVEX CXTPCalendarViewSelection::CXTPCalendarViewSelection(CXTPCalendarView* pOwnerView) { _ASSERTE(pOwnerView); m_pView = pOwnerView; EnableAutomation(); EnableTypeLib(); } CXTPCalendarViewSelection::~CXTPCalendarViewSelection() { } void CXTPCalendarViewSelection::Detach() { m_pView = NULL; } BOOL CXTPCalendarViewSelection::OleIsValid() { return XTP_SAFE_GET1(m_pView, m_selectedBlock.IsValid(), FALSE); } XTP_CALENDAR_VIEWSELPROP_IMPLEMENT(DATE, Begin, dtBegin); XTP_CALENDAR_VIEWSELPROP_IMPLEMENT(DATE, End, dtEnd); XTP_CALENDAR_VIEWSELPROP_IMPLEMENT(BOOL, AllDay, bAllDayEvent); XTP_CALENDAR_VIEWSELPROP_IMPLEMENT(long, GroupIndex, nGroupIndex); BEGIN_DISPATCH_MAP(CXTPCalendarViewSelection, CXTPCmdTarget) DISP_PROPERTY_EX_ID(CXTPCalendarViewSelection, "Begin", 1, OleGetBegin, OleSetBegin, VT_DATE) DISP_PROPERTY_EX_ID(CXTPCalendarViewSelection, "End", 2, OleGetEnd, OleSetEnd, VT_DATE) DISP_PROPERTY_EX_ID(CXTPCalendarViewSelection, "AllDay", 3, OleGetAllDay, OleSetAllDay, VT_BOOL) DISP_PROPERTY_EX_ID(CXTPCalendarViewSelection, "GroupIndex", 4, OleGetGroupIndex, OleSetGroupIndex, VT_I4) DISP_FUNCTION_ID(CXTPCalendarViewSelection, "IsValid", 10, OleIsValid, VT_BOOL, VTS_NONE) DISP_PROPERTY_EX_ID(CXTPCalendarViewSelection, "BeginV", 36, OleGetBeginV, SetNotSupported, VT_DISPATCH) DISP_PROPERTY_EX_ID(CXTPCalendarViewSelection, "EndV", 37, OleGetEndV, SetNotSupported, VT_DISPATCH) END_DISPATCH_MAP() LPDISPATCH CXTPCalendarViewSelection::OleGetBeginV() { if (!m_pView) return 0; SYSTEMTIME st; m_pView->m_selectedBlock.dtBegin.GetAsSystemTime(st); CXTPCalendarSystemTime* lpDisp = new CXTPCalendarSystemTime(&st); return lpDisp->GetIDispatch(FALSE); } LPDISPATCH CXTPCalendarViewSelection::OleGetEndV() { if (!m_pView) return 0; SYSTEMTIME st; m_pView->m_selectedBlock.dtEnd.GetAsSystemTime(st); CXTPCalendarSystemTime* lpDisp = new CXTPCalendarSystemTime(&st); return lpDisp->GetIDispatch(FALSE); } BEGIN_INTERFACE_MAP(CXTPCalendarViewSelection, CXTPCmdTarget) INTERFACE_PART(CXTPCalendarViewSelection, XTPDIID_CalendarViewSelection, Dispatch) END_INTERFACE_MAP() IMPLEMENT_OLETYPELIB_EX(CXTPCalendarViewSelection, XTPDIID_CalendarViewSelection) class CXTPCalendarHitTestInfo : public CXTPCmdTarget , public XTP_CALENDAR_HITTESTINFO { public: CXTPCalendarHitTestInfo() { EnableAutomation(); EnableTypeLib(); } DECLARE_DISPATCH_MAP() DECLARE_INTERFACE_MAP() DECLARE_OLETYPELIB_EX(CXTPCalendarView); LPDISPATCH OleGetViewEvent(); LPDISPATCH OleGetViewDay(); LPDISPATCH OleGetViewGroup(); int OleGetHitCode(); DATE OleGetHitDateTime(); BOOL OleGetTimePartValid(); }; BEGIN_DISPATCH_MAP(CXTPCalendarView, CXTPCalendarWMHandler) DISP_PROPERTY_ID(CXTPCalendarView, "DayHeaderFormatLong", 50, m_strDayHeaderFormatLong, VT_BSTR) DISP_PROPERTY_ID(CXTPCalendarView, "DayHeaderFormatMiddle", 55, m_strDayHeaderFormatMiddle, VT_BSTR) DISP_PROPERTY_ID(CXTPCalendarView, "DayHeaderFormatShort", 60, m_strDayHeaderFormatShort, VT_BSTR) DISP_PROPERTY_ID(CXTPCalendarView, "DayHeaderFormatShortest", 65, m_strDayHeaderFormatShortest, VT_BSTR) DISP_FUNCTION_ID(CXTPCalendarView, "ResetSelection", 98, OleResetSelection, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "SetSelection", 99, OleSetSelection, VT_EMPTY, VTS_DATE VTS_DATE VTS_BOOL) DISP_FUNCTION_ID(CXTPCalendarView, "GetSelection", 100, OleGetSelection, VT_BOOL, VTS_PDATE VTS_PDATE VTS_PBOOL) DISP_FUNCTION_ID(CXTPCalendarView, "GetSelectionV", 150, OleGetSelectionV, VT_BOOL, VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT) DISP_FUNCTION_ID(CXTPCalendarView, "Selection", 132, OleSelection, VT_DISPATCH, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "HitTest", 101, OleHitTest, VT_DISPATCH, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "HitTestEx", 151, OleHitTestEx, VT_DISPATCH, VTS_I4 VTS_I4) DISP_FUNCTION_ID(CXTPCalendarView, "ShowDay", 102, OleShowDay, VT_EMPTY, VTS_DATE VTS_VARIANT) DISP_FUNCTION_ID(CXTPCalendarView, "DaysCount", 103, OleGetItemCount, VT_I4, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "Days", DISPID_VALUE, OleGetItem, VT_DISPATCH, VTS_I4) DISP_FUNCTION_ID(CXTPCalendarView, "_NewEnum", DISPID_NEWENUM, OleNewEnum, VT_UNKNOWN, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "GetSelectedEvents", 110, OleGetSelectedEvents, VT_DISPATCH, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "SelectViewEvent", 111, OleSelectViewEvent, VT_EMPTY, VTS_DISPATCH VTS_BOOL) DISP_FUNCTION_ID(CXTPCalendarView, "UnselectAllEvents", 112, OleUnselectAllEvents, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "EnableVScroll", 113, OleEnableVScroll, VT_EMPTY, VTS_BOOL) DISP_FUNCTION_ID(CXTPCalendarView, "EnableHScroll", 114, OleEnableHScroll, VT_EMPTY, VTS_BOOL) DISP_FUNCTION_ID(CXTPCalendarView, "CanCut", 120, CanCut, VT_BOOL, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "CanCopy", 121, CanCopy, VT_BOOL, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "CanPaste", 122, CanPaste, VT_BOOL, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "CanUndo", 123, CanUndo, VT_BOOL, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "CanRedo", 124, CanRedo, VT_BOOL, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "Cut", 125, Cut, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "Copy", 126, Copy, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "Paste", 127, Paste, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "Undo", 128, Undo, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "Redo", 129, Redo, VT_EMPTY, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "MultipleResources", 130, OleGetMultipleResources, VT_DISPATCH, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarView, "SetMultipleResources", 131, OleSetMultipleResources, VT_EMPTY, VTS_DISPATCH) DISP_FUNCTION_ID(CXTPCalendarView, "CanStartEdit", 133, OleCanStartEdit, VT_BOOL, VTS_NONE) END_DISPATCH_MAP() BEGIN_INTERFACE_MAP(CXTPCalendarView, CXTPCalendarWMHandler) INTERFACE_PART(CXTPCalendarView, XTPDIID_CalendarView, Dispatch) // INTERFACE_PART(CXTPCalendarView, IID_IEnumVARIANT, EnumVARIANT) END_INTERFACE_MAP() IMPLEMENT_OLETYPELIB_EX(CXTPCalendarView, XTPDIID_CalendarView) IMPLEMENT_ENUM_VARIANT(CXTPCalendarView) LPDISPATCH CXTPCalendarView::OleSelection() { if (!m_pSelOleWrapper) m_pSelOleWrapper = new CXTPCalendarViewSelection(this); return m_pSelOleWrapper ? m_pSelOleWrapper->GetIDispatch(TRUE) : NULL; } BOOL CXTPCalendarView::OleCanStartEdit() { return (!IsEditingSubject() && GetDraggingMode() == xtpCalendaDragModeUnknown); } BOOL CXTPCalendarView::OleGetSelection(DATE* pBegin, DATE* pEnd, VARIANT_BOOL* pvbAllDay) { COleDateTime dtBegin, dtEnd; BOOL bAllDay = FALSE; BOOL bSelection = GetSelection(&dtBegin, &dtEnd, &bAllDay); if (pBegin && dtBegin.GetStatus() == COleDateTime::valid) *pBegin = dtBegin; if (pEnd && dtEnd.GetStatus() == COleDateTime::valid) *pEnd = dtEnd; if (pvbAllDay) *pvbAllDay = bAllDay ? VARIANT_TRUE : VARIANT_FALSE; return bSelection; } BOOL CXTPCalendarView::OleGetSelectionV(VARIANT* pBegin, VARIANT* pEnd, VARIANT* pvbAllDay) { DATE dtBegin = 0, dtEnd = 0; VARIANT_BOOL vbAllDay = 0; BOOL bRes = OleGetSelection(&dtBegin, &dtEnd, &vbAllDay); if (bRes) { if (pBegin) *pBegin = COleVariant(COleDateTime(dtBegin)); if (pEnd) *pEnd = COleVariant(COleDateTime(dtEnd)); if (pvbAllDay) *pvbAllDay = COleVariant((short)vbAllDay, VT_BOOL); } return bRes; } void CXTPCalendarView::OleResetSelection() { ResetSelection(); } void CXTPCalendarView::OleSetSelection(DATE Begin, DATE End, BOOL bAllDay) { SetSelection(Begin, End, bAllDay); } LPDISPATCH CXTPCalendarView::OleHitTest() { CPoint pt; GetCursorPos(&pt); return OleHitTestEx(pt.x, pt.y); } LPDISPATCH CXTPCalendarView::OleHitTestEx(long X, long Y) { if (!m_pControl) { _ASSERTE(FALSE); return NULL; } CPoint pt(X, Y); m_pControl->ScreenToClient(&pt); CXTPCalendarHitTestInfo* pHitTestInfo = new CXTPCalendarHitTestInfo; if (!pHitTestInfo) return NULL; HitTest(pt, pHitTestInfo); return pHitTestInfo->GetIDispatch(FALSE); } void CXTPCalendarView::OleShowDay(DATE dt, const VARIANT& Select) { _variant_t vtSelect(Select); BOOL bSelect = TRUE; if (vtSelect.vt == VT_ERROR && vtSelect.scode == DISP_E_PARAMNOTFOUND) { // default } else { bSelect = (long)vtSelect != 0; } ShowDay(dt, bSelect); } int CXTPCalendarView::OleGetItemCount() { return GetViewDayCount(); } LPDISPATCH CXTPCalendarView::OleGetItem(long nIndex) { CXTPCalendarViewDay* pDay = GetViewDay_(nIndex); if (!pDay) AfxThrowOleException(DISP_E_BADINDEX); return pDay->GetIDispatch(TRUE); } LPDISPATCH CXTPCalendarView::OleGetSelectedEvents() { CXTPCalendarViewEventsPtr ptrEvents = GetSelectedEvents(); return ptrEvents ? ptrEvents->GetIDispatch(TRUE) : NULL; } void CXTPCalendarView::OleSelectViewEvent(LPDISPATCH pViewEventDisp, BOOL bSelect) { CXTPCalendarViewEvent* pViewEvent = XTP_DYNAMIC_DOWNCAST_REMOTE_( CXTPCalendarViewEvent, CXTPCalendarViewEvent::FromIDispatchSafe(pViewEventDisp)); if (!pViewEvent) { AfxThrowOleException(E_INVALIDARG); } SelectViewEvent(pViewEvent, bSelect); } void CXTPCalendarView::OleUnselectAllEvents() { UnselectAllEvents(); } void CXTPCalendarView::OleEnableVScroll(BOOL bEnable) { EnableVScroll(bEnable); } void CXTPCalendarView::OleEnableHScroll(BOOL bEnable) { EnableHScroll(bEnable); } LPDISPATCH CXTPCalendarView::OleGetMultipleResources() { return XTP_SAFE_GET1(GetResources(), GetIDispatch(TRUE), NULL); } void CXTPCalendarView::OleSetMultipleResources(LPDISPATCH pDispResources) { if (!pDispResources) { SetResources(NULL); return; } CXTPCalendarResources* pResources = XTP_DYNAMIC_DOWNCAST_REMOTE_( CXTPCalendarResources, CXTPCalendarResources::FromIDispatchSafe(pDispResources)); if (!pResources) { AfxThrowOleException(E_INVALIDARG); } SetResources(pResources); } ////////////////////////////////////////////////////////////////////////// // BEGIN_DISPATCH_MAP(CXTPCalendarHitTestInfo, CXTPCmdTarget) DISP_PROPERTY_EX_ID(CXTPCalendarHitTestInfo, "ViewEvent", 1, OleGetViewEvent, SetNotSupported, VT_DISPATCH) DISP_PROPERTY_EX_ID(CXTPCalendarHitTestInfo, "ViewDay", 2, OleGetViewDay, SetNotSupported, VT_DISPATCH) DISP_PROPERTY_EX_ID(CXTPCalendarHitTestInfo, "HitCode", 3, OleGetHitCode, SetNotSupported, VT_I4) DISP_FUNCTION_ID(CXTPCalendarHitTestInfo, "HitDateTime", 4, OleGetHitDateTime, VT_DATE, VTS_NONE) DISP_FUNCTION_ID(CXTPCalendarHitTestInfo, "TimePartValid", 5, OleGetTimePartValid, VT_BOOL, VTS_NONE) DISP_PROPERTY_EX_ID(CXTPCalendarHitTestInfo, "ViewGroup", 6, OleGetViewGroup, SetNotSupported, VT_DISPATCH) END_DISPATCH_MAP() BEGIN_INTERFACE_MAP(CXTPCalendarHitTestInfo, CXTPCmdTarget) INTERFACE_PART(CXTPCalendarHitTestInfo, XTPDIID_CalendarHitTestInfo, Dispatch) END_INTERFACE_MAP() IMPLEMENT_OLETYPELIB_EX(CXTPCalendarHitTestInfo, XTPDIID_CalendarHitTestInfo) LPDISPATCH CXTPCalendarHitTestInfo::OleGetViewEvent() { return pViewEvent ? pViewEvent->GetIDispatch(TRUE) : 0; } LPDISPATCH CXTPCalendarHitTestInfo::OleGetViewDay() { return pViewDay ? pViewDay->GetIDispatch(TRUE) : 0; } LPDISPATCH CXTPCalendarHitTestInfo::OleGetViewGroup() { return pViewGroup ? pViewGroup->GetIDispatch(TRUE) : 0; } int CXTPCalendarHitTestInfo::OleGetHitCode() { return uHitCode; } DATE CXTPCalendarHitTestInfo::OleGetHitDateTime() { return dt; } BOOL CXTPCalendarHitTestInfo::OleGetTimePartValid() { return bTimePartValid; } #endif ///////////////////////////////////////////////////////////////////////////// // CXTPCalendarWMHandler CXTPCalendarWMHandler::CXTPCalendarWMHandler() { } int CXTPCalendarWMHandler::GetChildHandlersCount() const { return 0; } CXTPCalendarWMHandler* CXTPCalendarWMHandler::GetChildHandlerAt(int nIndex) const { UNREFERENCED_PARAMETER(nIndex); return NULL; } BOOL CXTPCalendarWMHandler::OnLButtonDown(UINT nFlags, CPoint point) { BOOL bHandled = FALSE; int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild && pChild->OnLButtonDown(nFlags, point)) { bHandled = TRUE; break; } } return bHandled; } BOOL CXTPCalendarWMHandler::OnLButtonUp(UINT nFlags, CPoint point) { BOOL bHandled = FALSE; int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild && pChild->OnLButtonUp(nFlags, point)) { bHandled = TRUE; break; } } return bHandled; } BOOL CXTPCalendarWMHandler::OnLButtonDblClk(UINT nFlags, CPoint point) { BOOL bHandled = FALSE; int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild && pChild->OnLButtonDblClk(nFlags, point)) { bHandled = TRUE; break; } } return bHandled; } void CXTPCalendarWMHandler::OnMouseMove(UINT nFlags, CPoint point) { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild) pChild->OnMouseMove(nFlags, point); } } void CXTPCalendarWMHandler::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild) pChild->OnChar(nChar, nRepCnt, nFlags); } } void CXTPCalendarWMHandler::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild) pChild->OnKeyDown(nChar, nRepCnt, nFlags); } } void CXTPCalendarWMHandler::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild) pChild->OnKeyUp(nChar, nRepCnt, nFlags); } } BOOL CXTPCalendarWMHandler::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { BOOL bHandled = FALSE; int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild && pChild->OnSysKeyDown(nChar, nRepCnt, nFlags)) { bHandled = TRUE; break; } } return bHandled; } BOOL CXTPCalendarWMHandler::OnTimer(UINT_PTR uTimerID) { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild && pChild->OnTimer(uTimerID)) return TRUE; } return FALSE; } BOOL CXTPCalendarWMHandler::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { _ASSERTE(NULL != pResult); BOOL bHandled = FALSE; const int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (NULL != pChild && pChild->OnWndMsg(message, wParam, lParam, pResult)) { bHandled = TRUE; break; } } return bHandled; } void CXTPCalendarWMHandler::OnPostAdjustLayout() { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild) pChild->OnPostAdjustLayout(); } } void CXTPCalendarWMHandler::OnFinalRelease() { OnBeforeDestroy(); CXTPCmdTarget::OnFinalRelease(); } void CXTPCalendarWMHandler::OnBeforeDestroy() { int nCount = GetChildHandlersCount(); for (int i = 0; i < nCount; i++) { CXTPCalendarWMHandler* pChild = GetChildHandlerAt(i); if (pChild) pChild->OnBeforeDestroy(); } }