// XTPReportControl.cpp : implementation of the CXTPReportControl class. // // This file is a part of the XTREME REPORTCONTROL MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPImageManager.h" #include "Common/XTPPropExchange.h" #include "Common/XTPToolTipContext.h" #include "Common/XTPResourceManager.h" #include "Common/XTPMarkupRender.h" #include "Common/XTPCustomHeap.h" #include "Common/XTPSmartPtrInternalT.h" #include "Common/XTPColorManager.h" #include "XTPReportDefines.h" #include "Behavior/XTPReportBehavior.h" #include "XTPReportRows.h" #include "XTPReportSelectedRows.h" #include "XTPReportTip.h" #include "XTPReportRecordItem.h" #include "XTPReportRecord.h" #include "XTPReportRecords.h" #include "XTPReportHeader.h" #include "XTPReportColumn.h" #include "XTPReportColumns.h" #include "XTPReportRow.h" #include "XTPReportControl.h" #include "XTPReportPaintManager.h" #include "XTPReportNavigator.h" #include "XTPReportSubListControl.h" #include "XTPReportGroupRow.h" #include "XTPReportInplaceControls.h" #include "XTPReportRecordItemControls.h" #include "XTPReportHyperlink.h" #include "XTPReportRecordItemRange.h" #include "XTPReportSection.h" #include "XTPReportSections.h" #include "XTPReportBorder.h" #include "XTPReportThickness.h" #include "XTPReportHitTestInfo.h" #include "XTPReportADO.h" #include "XTPReportDataManager.h" #include "ItemTypes/XTPReportRecordItemPreview.h" #include "ItemTypes/XTPReportRecordItemVariant.h" #include "ItemTypes/XTPReportRecordItemIcon.h" #include "ItemTypes/XTPReportRecordItemText.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define XTP_REPORT_HSCROLL_STEP 7 #define XTP_REPORT_VSCROLL_STEP 7 #define XTP_REPORT_AUTO_SCROLL_TIMER_ID 7 #define XTP_REPORT_AUTO_SCROLL_TIMER_RESOLUTION_MS 200 #define XTP_REPORT_DELAY_CLICK_TIMER_ID 10 #define XTP_REPORT_DELAYEDIT_CLICK_TIMER_ID 20 #define XTP_REPORT_CB_RECORDS_DATA_VER 1 #ifndef _UNICODE #define XTP_CF_TEXT_T CF_TEXT #else #define XTP_CF_TEXT_T CF_UNICODETEXT #endif ////////////////////////////////////////////////////////////////////////// XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportDataAllocator, FALSE) XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator, FALSE) // to allocate in app default heap XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportAllocatorDefault, FALSE) class CXTPReportRow_Batch : public CXTPBatchAllocObjT {}; class CXTPReportGroupRow_Batch : public CXTPBatchAllocObjT {}; XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CXTPReportRow_BatchData, CXTPReportRow_Batch, FALSE) XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CXTPReportGroupRow_BatchData, CXTPReportGroupRow_Batch, FALSE) //=========================================================================== HGLOBAL XTPAllocStrInGlobalMem(const CString& strText) { int nLen = (strText.GetLength() + 1) * sizeof(TCHAR); UINT nAllocFlags = GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT; HGLOBAL hText = ::GlobalAlloc(nAllocFlags, nLen); if (hText != NULL) { LPTSTR lptstrCopy = (TCHAR*)GlobalLock(hText); STRCPY_S(lptstrCopy, strText.GetLength() + 1, (LPCTSTR)strText); GlobalUnlock(hText); } return hText; } //=========================================================================== BOOL CXTPReportControl::UseReportCustomHeap() { ASSERT(CXTPReportDataAllocator::ms_dwRefs == 0 || CXTPReportDataAllocator::ms_bUseCustomHeap); ASSERT(CXTPReportRowAllocator::ms_dwRefs == 0 || CXTPReportRowAllocator::ms_bUseCustomHeap); if (CXTPReportDataAllocator::ms_dwRefs == 0) CXTPReportDataAllocator::ms_bUseCustomHeap = TRUE; if (CXTPReportRowAllocator::ms_dwRefs == 0) CXTPReportRowAllocator::ms_bUseCustomHeap = TRUE; return CXTPReportDataAllocator::ms_bUseCustomHeap && CXTPReportRowAllocator::ms_bUseCustomHeap; } BOOL CXTPReportControl::UseRowBatchAllocation() { ASSERT(CXTPReportRow_BatchData::IsDataEmpty() || CXTPReportRow_BatchData::m_bBatchAllocationEnabled); ASSERT(CXTPReportGroupRow_BatchData::IsDataEmpty() || CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled); if (CXTPReportRow_BatchData::IsDataEmpty()) CXTPReportRow_BatchData::m_bBatchAllocationEnabled = TRUE; if (CXTPReportGroupRow_BatchData::IsDataEmpty()) CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled = TRUE; return CXTPReportRow_BatchData::m_bBatchAllocationEnabled && CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled; } void CXTPReportControl::FreeRowBatchExtraData() { CXTPReportRow_Batch::FreeExtraData(); CXTPReportGroupRow_Batch::FreeExtraData(); } CArray CXTPReportControlLocale::s_arMappedSpecs; ////////////////////////////////////////////////////////////////////////// // CReportDropTarget class CXTPReportControl::CReportDropTarget : public COleDropTarget { public: virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) { CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd); if (!pReport) return DROPEFFECT_NONE; return pReport->OnDragOver(pDataObject, dwKeyState, point, 0); } virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) { CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd); if (!pReport) return DROPEFFECT_NONE; return pReport->OnDragOver(pDataObject, dwKeyState, point, 2); } virtual void OnDragLeave(CWnd* pWnd) { CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd); if (pReport) pReport->OnDragOver(NULL, 0, CPoint(-1, -1), 1); } virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) { CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd); if (pReport) return pReport->OnDrop(pDataObject, dropEffect, point); return FALSE; } }; ///////////////////////////////////////////////////////////////////////////// void XTPStrSplit(LPCTSTR pcszString, LPCTSTR pcszSeparator, CStringArray& rarStrings) { rarStrings.RemoveAll(); int nSeparatorLen = (int)_tcslen(pcszSeparator); CString strString(pcszString); CString strItem; int nIndex_start = 0; // parse data BOOL bBreak = FALSE; do { int nIndex = strString.Find(pcszSeparator, nIndex_start); if (nIndex >= 0) { strItem = strString.Mid(nIndex_start, nIndex - nIndex_start); } else { strItem = strString.Mid(nIndex_start); bBreak = TRUE; } //--------------------------------------- rarStrings.Add(strItem); nIndex_start = nIndex + nSeparatorLen; } while (!bBreak); } CString XTPStrMake(const CStringArray& arStrings, LPCTSTR pcszSeparator) { CString strString; int nCount = (int)arStrings.GetSize(); for (int i = 0; i < nCount; i++) { if (i > 0) strString += pcszSeparator; strString += arStrings[i]; } return strString; } // CXTPReportControl IMPLEMENT_DYNCREATE(CXTPReportControl, CWnd) BEGIN_MESSAGE_MAP(CXTPReportControl, CWnd) //{{AFX_MSG_MAP(CXTPReportControl) // Window ON_WM_CREATE() ON_WM_PAINT() ON_WM_ERASEBKGND() ON_WM_SIZE() ON_WM_ENABLE() ON_WM_TIMER() ON_WM_NCHITTEST_EX() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() // Mouse ON_WM_MOUSEMOVE() ON_WM_MOUSEWHEEL() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_LBUTTONDBLCLK() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_CONTEXTMENU() ON_WM_SETCURSOR() // Key events ON_WM_CHAR() ON_WM_KEYDOWN() ON_WM_KEYUP() ON_WM_SYSKEYDOWN() ON_WM_SYSKEYUP() // Scrolling ON_WM_VSCROLL() ON_WM_HSCROLL() ON_WM_CAPTURECHANGED() ON_WM_SYSCOLORCHANGE() ON_WM_GETDLGCODE() ON_WM_STYLECHANGED() ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient) ON_MESSAGE(WM_GETOBJECT, OnGetObject) ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE_VOID(XTP_WM_MARKUPREDRAW, RedrawControl) //}}AFX_MSG_MAP END_MESSAGE_MAP() CXTPReportControl::CXTPReportControl() : m_bCreated (FALSE) , m_bLockExpand(FALSE) , m_bEditOnClick (TRUE) , m_bEditOnDelayClick (FALSE) , m_bEditOnDoubleClick(TRUE) , m_bPinFooterRows (FALSE) , m_bPinFooterRowsPrinted(TRUE) , m_bDoubleBuffering (TRUE) , m_nFixedColumnsCount(0) , m_pSectionHeader(NULL) , m_pSectionBody (NULL) , m_pSectionFooter(NULL) , m_pSectionScroll(NULL) , m_dwLastMouseMessage(WM_NULL) , m_scrollModeH(xtpReportScrollModeSmooth) , m_scrollModeV(xtpReportScrollModeBlock) , m_nScrollOffsetH(0) , m_nScrollStepH(XTP_REPORT_HSCROLL_STEP) , m_nScrollStepV(XTP_REPORT_VSCROLL_STEP) , m_pMarkupContext(NULL) { RegisterWindowClass(); m_pBehavior = new CXTPReportBehavior(xtpReportBehaviorCodejockDefault); m_pTip = new CXTPReportTip(); m_nLockUpdateCount = 0; m_nRowsPerWheel = GetMouseScrollLines(); m_pSections = new CXTPReportSections(this); m_pSectionHeader = m_pSections->GetAt(xtpReportSectionHeader); m_pSectionBody = m_pSections->GetAt(xtpReportSectionBody); m_pSectionFooter = m_pSections->GetAt(xtpReportSectionFooter); m_pSectionScroll = m_pSectionBody; // Default scroll section m_pSectionFooter->GetBorder()->GetBorderThickness()->SetTop(1); m_pSectionHeader->SetHeightMode(xtpReportSectionHeightModeAuto); m_pSectionBody ->SetHeightMode(xtpReportSectionHeightModeExpand); m_pSectionFooter->SetHeightMode(xtpReportSectionHeightModeAuto); m_pSectionHeader->SetDividerPosition(xtpReportSectionDividerPositionBottom); m_pSectionFooter->SetDividerPosition(xtpReportSectionDividerPositionTop); m_pSectionHeader->SetDividerStyle(xtpReportFixedRowsDividerThin); m_pSectionFooter->SetDividerStyle(xtpReportFixedRowsDividerThin); // Allow group m_pSectionHeader->AllowGroup(FALSE); m_pSectionBody ->AllowGroup(TRUE); m_pSectionFooter->AllowGroup(FALSE); // Allow sort m_pSectionHeader->AllowSort(FALSE); m_pSectionBody ->AllowSort(TRUE); m_pSectionFooter->AllowSort(FALSE); // Allow filter m_pSectionHeader->AllowFilter(FALSE); m_pSectionBody ->AllowFilter(TRUE); m_pSectionFooter->AllowFilter(FALSE); m_pSectionBody->SetVisible(TRUE); m_pRows = m_pSectionBody->GetRows(); m_pColumns = new CXTPReportColumns(this); m_pReportHeader = new CXTPReportHeader(this, m_pColumns); //ICON_VIEW_MODE RELATED << m_bIconView = FALSE; m_iIconWidth = 0; m_iIconHeight = 0; m_iIconWidthSpacing = 0; m_iIconHeightSpacing = 0; m_iIconViewColumn = -1; m_iIconViewRowsPerLine = 0; m_bUseIconColumnForNum = FALSE; m_iColumnForNumPrev = -1; m_iColumnForNum = -1; m_bPrevFocusSubItems = FALSE; m_bPrevHeaderAutoSize = FALSE; m_iIconPropNum = 0; m_iIconNum = 0; m_pPrevVisible = NULL; m_pPrevGroupsOrder = NULL; m_nPrevTreeIndent = 0; m_bIconColumnIndexNotValid = FALSE; m_bPrevHeaderRows = FALSE; m_bPrevFooterRows = FALSE; m_bPrevHeaderShow = FALSE; m_bPrevFooterShow = FALSE; m_bRClickDrag = FALSE; //ICON_VIEW_MODE RELATED >> m_pPaintManager = new CXTPReportPaintManager(); m_pPaintManager->SetReportControl(this); m_pNavigatorReport = new CXTPReportNavigator(this); m_pNavigatorIcon = new CXTPReportIconNavigator(this); m_pNavigator = m_pNavigatorReport; //m_nSelectionLastBlockStartRow = -1; m_bKeepSelectionAfterSort = TRUE; m_bUnrestrictedDragDrop = FALSE; m_bFreeHeightMode = FALSE; m_nDefaultRowFreeHeight = 20; m_uiDelayEditTimer = NULL; m_uiDelayEditMaxTime = GetDoubleClickTime() + 50; m_iLastRqstEditRow = -1; m_iLastRqstEditCol = -1; m_uRqstEditTimer = 0; m_mouseMode = xtpReportMouseNothing; m_bWasShiftKey = FALSE; m_bSortedDragDrop = FALSE; m_bNoNeedSortedDragDrop = TRUE; m_bInternalMove = FALSE; m_bTrapTabKey = FALSE; m_pSelectedRows = new CXTPReportSelectedRows(this); m_bStrictBestFit = FALSE; m_bChanged = TRUE; m_bRefreshIndexes = FALSE; m_bGroupByEnabled = FALSE; m_bHeaderVisible = TRUE; m_bFooterVisible = FALSE; m_bBlockSelection = TRUE; m_bMultiSelectionMode = FALSE; m_bShowTooltips = TRUE; m_bSkipGroupsFocus = TRUE; m_bSelectionExcludeGroupRows = TRUE; m_pImageManager = new CXTPImageManager(); m_pFocusedColumn = NULL; m_pActiveItem = NULL; m_bEnsureFocusedRowVisible = TRUE; m_bFocusSubItems = FALSE; m_bPreviewAllowEdit = FALSE; m_bInitialSelectionEnable = TRUE; m_bRowFocusVisible = TRUE; m_bAutoCheckItems = TRUE; m_bShowIconWhenEditing = TRUE; m_pInplaceEdit = new CXTPReportInplaceEdit(); m_pInplaceButtons = new CXTPReportInplaceButtons(); m_pInplaceList = new CXTPReportInplaceList(); m_rcGroupByArea.SetRectEmpty(); m_rcHeaderArea.SetRectEmpty(); m_rcFooterArea.SetRectEmpty(); m_bMovePivot = FALSE; m_bForcePagination = FALSE; m_nDisableReorderColumnsCount = 0; m_pHotRow = NULL; m_pHotExpandButtonRow = NULL; m_pHotHyperlink = NULL; m_nOLEDropMode = 0; m_nOLEDropAbove = FALSE; m_bVScrollBarVisible = FALSE; m_bHScrollBarVisible = FALSE; m_bPrepareDrag = FALSE; m_ptDrag = CPoint(0, 0); m_pToolTipContext = new CXTPToolTipContext; m_pCachedToolTipInfo = new XTP_NM_REPORTTOOLTIPINFO; m_cfReport = NULL; m_pDropTarget = new CReportDropTarget; m_bDragMode = FALSE; m_bInternalDrag = FALSE; m_dwDragDropFlags = 0; m_dwDropMarkerFlags = xtpReportDropBetween; // Default to how it has always been. m_pSelectedRowsBeforeDrag = NULL; m_nDropPos = -1; m_pDropRecords = NULL; m_bFastDeselectMode = FALSE; m_bAdjustLayoutRunning = FALSE; m_uAutoScrollTimerID = 0; m_bSortRecordChilds = FALSE; m_pRowsCompareFunc = NULL; m_ptrVirtualEditingRow = NULL; m_bFilterHiddenColumns = FALSE; m_nRecordsTreeFilterMode = xtpReportFilterTreeSimple; m_hbmpWatermark = NULL; m_WatermarkTransparency = 100; m_WatermarkAlignment = xtpReportWatermarkStretch; m_nEnsureVisibleRowIdx = m_nEnsureVisibleColumnIdx = -1; m_pDataManager = NULL; m_nAutoVScrollTimerResolution = XTP_REPORT_AUTO_SCROLL_TIMER_RESOLUTION_MS; m_bMarkupEnabled = FALSE; m_bDesktopTrackerMode = FALSE; m_bStrictFiltering = FALSE; m_pTip->m_pReportControl = this; EnableAutomation(); } CXTPReportControl::~CXTPReportControl() { if (::IsWindow(m_pTip->GetSafeHwnd())) m_pTip->DestroyWindow(); EditItem(NULL); ResetContent(FALSE); EnableMarkup(FALSE); m_UaSelected.RemoveAll(); CMDTARGET_RELEASE(m_pSelectedRows); CMDTARGET_RELEASE(m_pColumns); CMDTARGET_RELEASE(m_pPaintManager); CMDTARGET_RELEASE(m_pNavigatorReport); CMDTARGET_RELEASE(m_pNavigatorIcon); CMDTARGET_RELEASE(m_pImageManager); CMDTARGET_RELEASE(m_pReportHeader); CMDTARGET_RELEASE(m_pToolTipContext); SAFE_DELETE(m_pCachedToolTipInfo); SAFE_DELETE(m_pInplaceEdit); SAFE_DELETE(m_pInplaceButtons); SAFE_DELETE(m_pInplaceList); CMDTARGET_RELEASE(m_pDropTarget); CMDTARGET_RELEASE(m_pSelectedRowsBeforeDrag); CMDTARGET_RELEASE(m_ptrVirtualEditingRow); CMDTARGET_RELEASE(m_pDropRecords); if (m_hbmpWatermark) ::DeleteObject(m_hbmpWatermark); //ICON_VIEW_MODE RELATED << CMDTARGET_RELEASE(m_pPrevVisible); CMDTARGET_RELEASE(m_pPrevGroupsOrder); //ICON_VIEW_MODE RELATED >> CMDTARGET_RELEASE(m_pDataManager); SAFE_DELETE(m_pBehavior); SAFE_DELETE(m_pTip); SAFE_DELETE(m_pSections); } BOOL CXTPReportControl::RegisterWindowClass(HINSTANCE hInstance) { return XTPDrawHelpers()->RegisterWndClass(hInstance, XTPREPORTCTRL_CLASSNAME, CS_DBLCLKS); } void CXTPReportControl::ResetContent(BOOL bUpdateControl) { EditItem(NULL); m_pSectionBody->ResetContent(); if (m_pSelectedRows) m_pSelectedRows->Clear(); if (bUpdateControl) { AdjustIndentation(); AdjustScrollBars(); RedrawControl(); } } void CXTPReportControl::SetReportHeader(CXTPReportHeader *pReportHeader) { if (NULL != pReportHeader) { m_pReportHeader->InternalRelease(); m_pReportHeader = pReportHeader; AdjustLayout(); } } void CXTPReportControl::SetImageManager(CXTPImageManager *pImageManager) { if (NULL != pImageManager) { m_pImageManager->InternalRelease(); m_pImageManager = pImageManager; } } void CXTPReportControl::SetImageList(CImageList *pImageList) { for (int i=0; iGetImageCount(); i++) { HICON hIcon = pImageList->ExtractIcon(i); m_pImageManager->SetIcon(hIcon, i); DestroyIcon(hIcon); } } void CXTPReportControl::SetPaintManager(CXTPReportPaintManager *pPaintManager) { if (NULL != pPaintManager) { m_pPaintManager->SetReportControl(NULL); m_pPaintManager->InternalRelease(); m_pPaintManager = pPaintManager; m_pPaintManager->SetReportControl(this); AdjustLayout(); AdjustScrollBars(); } } int CXTPReportControl::GetIndent(int nLevel) const { return max(0, (nLevel - 1) * m_pPaintManager->m_nTreeIndent); } void CXTPReportControl::SetTreeIndent(int nIndent) { m_pPaintManager->m_nTreeIndent = nIndent; } void CXTPReportControl::BeginUpdate() { m_nLockUpdateCount++; m_bRefreshIndexes = FALSE; } void CXTPReportControl::EndUpdate() { SetChanged(); m_nLockUpdateCount--; if (m_nLockUpdateCount == 0) { if (m_bRefreshIndexes) { m_bRefreshIndexes = FALSE; _RefreshIndexes(); } RedrawControl(); } } void CXTPReportControl::RedrawControl() { SetChanged(); if (m_nLockUpdateCount == 0 && GetSafeHwnd()) Invalidate(FALSE); } void CXTPReportControl::UpdateSubList() { CXTPReportHeader* pHeader = GetReportHeader(); if (pHeader && pHeader->m_pSubList && (pHeader->m_pSubList->GetReportCtrl() == this)) { pHeader->m_pSubList->UpdateList(); } } void CXTPReportControl::_DoCollapse(CXTPReportRow* pRow) { ASSERT(NULL != pRow); int nCount = 0; if (NULL != pRow && NULL != pRow->m_pSection) { pRow->m_pSection->_DoCollapse(pRow); } if (nCount > 0) { m_pSelectedRows->_OnCollapsed(pRow->GetIndex(), nCount); } AdjustLayout(); RedrawControl(); } void CXTPReportControl::_DoExpand(CXTPReportRow* pRow) { int nIndex = pRow->m_nIndex; int nCount = _DoExpand(nIndex, pRow); if (nCount > 0) { m_pSelectedRows->_OnExpanded(nIndex, nCount); CXTPReportRows *pRows = pRow->GetSection()->GetRows(); if (pRows->m_nFocusedRow > nIndex) { pRows->m_nFocusedRow += nCount; } } } int CXTPReportControl::_DoExpand(int nIndex, CXTPReportRow *pRow) { ASSERT(NULL != pRow); int nExpand = 0; if (NULL != pRow && NULL != pRow->m_pSection) { nExpand = pRow->m_pSection->_DoExpand(nIndex, pRow); } AdjustLayout(); RedrawControl(); return nExpand; } void CXTPReportControl::RefreshIndexes(BOOL bAdjustLayout, BOOL bReverseOrder) { m_pSections->RefreshIndexes(bAdjustLayout, bReverseOrder); } void CXTPReportControl::_RefreshIndexes(BOOL bAdjustLayout, BOOL bReverseOrder) { if (m_nLockUpdateCount != 0) { m_bRefreshIndexes = TRUE; return; } RefreshIndexes(bAdjustLayout, bReverseOrder); } CLIPFORMAT CXTPReportControl::EnableDragDrop(LPCTSTR lpszClipboardFormat, DWORD dwFlags, DWORD dwDropMarkerFlags) { if (m_dwDragDropFlags != 0) { if (m_pDropTarget) m_pDropTarget->Revoke(); } m_dwDragDropFlags = dwFlags; m_dwDropMarkerFlags = dwDropMarkerFlags; m_cfReport = NULL; if (m_dwDragDropFlags != 0) { if (m_pDropTarget) { m_cfReport = (CLIPFORMAT)::RegisterClipboardFormat(lpszClipboardFormat); m_pDropTarget->Revoke(); // to ensure kill previous registration. m_pDropTarget->Register(this); } } return m_cfReport; } BOOL CXTPReportControl::ApplyFilter(CXTPReportRecord *pRecord, CString strFilterText, BOOL bIncludePreview) { // not filtered if filter text is empty if (!pRecord) return FALSE; if (pRecord->IsFiltered()) return TRUE; if (strFilterText.IsEmpty()) return FALSE; BOOL bFilterSimple = GetRecordsTreeFilterMode() == xtpReportFilterTreeSimple; if (!bFilterSimple && pRecord->HasChildren() && pRecord->GetChilds()) { CXTPReportRecords* pChildren = pRecord->GetChilds(); int nCount = pChildren->GetCount(); for (int i = 0; i < nCount; i++) { CXTPReportRecord* pR = pChildren->GetAt(i); if (!ApplyFilter(pR, strFilterText, bIncludePreview)) return FALSE; } } if (GetRecordsTreeFilterMode() == xtpReportFilterTreeByEndChildrenOnly && pRecord->HasChildren()) return TRUE; return _ApplyFilter(pRecord, strFilterText, bIncludePreview); } BOOL CXTPReportControl::_ApplyFilter(CXTPReportRecord* pRecord, CString strFilterText, BOOL bIncludePreview) { // not filtered if filter text is empty if (!pRecord) return FALSE; if (pRecord->IsFiltered()) return TRUE; if (strFilterText.IsEmpty()) return FALSE; BOOL bFilterHidden = IsFilterHiddenColumns(); // process each token in the filter string TCHAR szSeps[] = _T(" \t"); TCHAR szSepsStrict[] = _T("\t"); TCHAR *szToken, *lpszContext = 0; //int nCurPos = 0; if (m_bStrictFiltering) szToken = STRTOK_S(strFilterText.GetBuffer(strFilterText.GetLength()), szSepsStrict, &lpszContext); else szToken = STRTOK_S(strFilterText.GetBuffer(strFilterText.GetLength()), szSeps, &lpszContext); while (szToken != NULL) { CString strToken(szToken); strToken.MakeLower(); BOOL bTokenFound = FALSE; // enumerate all visible columns int nColumnsCount = m_pColumns->GetCount(); for (int nCol = 0; nCol < nColumnsCount; nCol++) { CXTPReportColumn* pCol = m_pColumns->GetAt(nCol); if (pCol && (pCol->IsVisible() || bFilterHidden) && pCol->IsFilterable()) { CXTPReportRecordItem* pItem = pRecord->GetItem(pCol); if (pItem) { CString sItemText = pItem->GetCaption(pCol); // case-insensitive search sItemText.MakeLower(); bTokenFound = sItemText.Find(strToken) != -1; if (bTokenFound) { // stop search current token - passed break; } } } } // also check preview text if (bIncludePreview && !bTokenFound && pRecord->GetItemPreview()) { CString sItemText = pRecord->GetItemPreview()->GetCaption(NULL); // case-insensitive search sItemText.MakeLower(); bTokenFound = sItemText.Find(strToken) != -1; } // Token not found - filter this record if (!bTokenFound) { return TRUE; } // get next token if (m_bStrictFiltering) szToken = STRTOK_S(NULL, szSepsStrict, &lpszContext); else szToken = STRTOK_S(NULL, szSeps, &lpszContext); } return FALSE; } void CXTPReportControl::Populate() { EditItem(NULL); BeginUpdate(); m_pSelectedRows->Clear(); m_pSectionHeader->Populate(FALSE); m_pSectionBody ->Populate(FALSE); m_pSectionFooter->Populate(FALSE); AdjustIndentation(); AdjustLayout(); AdjustScrollBars(); UpdateSubList(); if (GetRows()->m_nFocusedRow == -1) { SetTopRow(0); if (GetRows()->GetCount() > 0) { GetRows()->m_nFocusedRow = 0; if (IsSelectionEnabled() && IsInitialSelectionEnabled()) { CXTPReportRow* pFirst = m_pRows->GetAt(0); if (pFirst) { if (!IsSkipGroupsFocusEnabled() || !pFirst->IsGroupRow()) m_pSelectedRows->Select(pFirst); else { while (pFirst->IsGroupRow()) { if (pFirst->HasChildren()) pFirst = pFirst->GetChilds()->GetAt(0); } m_pSelectedRows->Select(pFirst); } } } } } else { EnsureVisible(GetFocusedRow()); } if (m_pFocusedColumn == NULL && m_bFocusSubItems) { m_pFocusedColumn = m_pColumns->GetFirstVisibleColumn(); //------------ Forum proposal 2009 June 19 ---------------------------- << if (GetRows()) { CXTPReportRow* pRow = GetRows()->GetAt(GetTopRowIndex()); if (pRow) m_pFocusedColumn = GetNextFocusableColumn(pRow, 0, 1); } //------------ Forum proposal 2009 June 19 ---------------------------- >> } EndUpdate(); if (GetBehavior()->Notifications->Populate->bSelectionChanged) { if (m_pSelectedRows->IsChanged()) { OnSelectionChanged(); m_pSelectedRows->SetChanged(FALSE); } } } void CXTPReportControl::AdjustIndentation() { GetReportHeader()->m_nIndentLevel = m_pColumns->GetGroupsOrder()->GetCount(); } CXTPReportColumn* CXTPReportControl::AddColumn(CXTPReportColumn* pColumn) { ASSERT(pColumn); m_pColumns->Add(pColumn); return pColumn; } void CXTPReportControl::DrawNoItems(CDC* pDC, const CRect& rcClient) { pDC->SetTextColor(GetPaintManager()->m_clrWindowText); CString strNoItems = GetPaintManager()->m_strNoItems; if (!strNoItems.IsEmpty()) { CRect rcText(rcClient); rcText.DeflateRect(5, 5, 5, 5); CXTPFontDC font(pDC, &GetPaintManager()->m_fontText); UINT uFlags = DT_CENTER | DT_TOP | DT_NOPREFIX | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_EDITCONTROL; XTPMarkupDrawText(GetMarkupContext(), pDC->GetSafeHdc(), strNoItems, rcText, uFlags); } } int CXTPReportControl::DrawRows(CDC *pDC, CRect &rcClient, int y, CXTPReportRows *pRows, int nTopRow, int nColumnFrom, int nColumnTo, int *pnHeight) { const BOOL bIsPrinting = pDC->IsPrinting(); CXTPReportRecordMergeItems mergeItems; CXTPReportScreenRows *pScreenRows = pRows->GetScreenRows(); pScreenRows->Clear(); pScreenRows->SetSize(0, 100); CXTPReportHeader *pHeader = GetReportHeader(); CRgn rgnClip; int nRow = nTopRow; // Row index if (NULL != pHeader->GetNextVisibleColumn(-1, xtpReportColumnDirectionRight)) { int nRowCount = pRows->GetCount(); // Number of rows in the rows collection int nRowWidth = 0; int nRowHeight = 0; if (bIsPrinting) { nRowWidth = rcClient.Width(); } else { nRowWidth = pHeader->GetWidth(); } ////////////////////////////////////////////////////////////////////////// // Draw non-merged items ////////////////////////////////////////////////////////////////////////// #if 1 int nFreezeRight = 0; if (GetFreezeColumnsCount() > 0) { CXTPReportColumn *pColumn = GetColumns()->GetAt(GetFreezeColumnsCount()-1); if (NULL != pColumn) { nFreezeRight = pColumn->GetRect().right; } } for (nRow=nTopRow; nRowGetAt(nRow); ASSERT(pRow); if (NULL != pRow) { nRowHeight = pRow->GetHeight(pDC, nRowWidth); // Test if row is outside of client rectangle if (bIsPrinting) { // Clipped rows are printed on the next page if (y + nRowHeight > rcClient.bottom) { break; } } else { // Clipped rows are drawn if (y > rcClient.bottom) { break; } } // Rectangles in Windows don't include the right and bottom edge. CRect rcRow(rcClient.left, y, rcClient.left + nRowWidth, y + nRowHeight); int nLeftOffset = 0; if (!pDC->IsPrinting()) { nLeftOffset = m_nScrollOffsetH; } // Draw row pRow->Draw(pDC, rcRow, rcClient, nLeftOffset, mergeItems, nColumnFrom, nColumnTo); y += nRowHeight; CXTPReportRow *pScreenRow = NULL; if (IsVirtualMode()) { pScreenRow = CreateRow(); pScreenRow->InitRow(pRow); } else { pScreenRow = pRow; pScreenRow->InternalAddRef(); } pScreenRows->InsertAt(pScreenRows->GetSize(), pScreenRow); } } // for (nRow) #endif ////////////////////////////////////////////////////////////////////////// // Draw merged items ////////////////////////////////////////////////////////////////////////// #if 1 VERIFY(rgnClip.CreateRectRgn(nFreezeRight, rcClient.top, rcClient.right, rcClient.bottom)); if (!pDC->IsPrinting()) { pDC->SelectClipRgn(&rgnClip, RGN_COPY); } POSITION pos = mergeItems.GetStartPosition(); while (pos) { CXTPReportRecordItem *pItem; CXTPReportRecordMergeItem mergeItem; mergeItems.GetNextAssoc(pos, pItem, mergeItem); CXTPReportRecordItemRange range; CRect rcItem; while (mergeItem.FindRange(range, rcItem)) { //rcItem.left = GetColumns()->GetAt(range.m_nColumnFrom)->GetRect().left; //rcItem.right = GetColumns()->GetAt(range.m_nColumnTo )->GetRect().right; //rcItem.top = pRows->GetAt(range.m_nRecordFrom)->GetRect().top; //rcItem.bottom = pRows->GetAt(range.m_nRecordTo )->GetRect().bottom; CRect rcGrid(rcItem); rcItem.DeflateRect(0,0,1,1); XTP_REPORTRECORDITEM_DRAWARGS drawArgs; drawArgs.pDC = pDC; drawArgs.pControl = this; drawArgs.pColumn = GetColumns()->GetAt(range.m_nColumnFrom); drawArgs.pRow = pRows->GetAt(range.m_nRecordFrom); drawArgs.rcItem = rcItem; drawArgs.nTextAlign = drawArgs.pColumn->GetAlignment(); drawArgs.pItem = pItem; pItem->Draw(&drawArgs); drawArgs.pRow->DrawItemGrid(pDC, drawArgs.pColumn, rcGrid); } } if (!pDC->IsPrinting()) { pDC->SelectClipRgn(NULL, RGN_COPY); } VERIFY(rgnClip.DeleteObject()); #endif } ////////////////////////////////////////////////////////////////////////// // Fill the rest of space with empty grid ////////////////////////////////////////////////////////////////////////// if (GetPaintManager()->IsDrawGridForEmptySpace() && y < rcClient.bottom) { VERIFY(rgnClip.CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom)); if (!pDC->IsPrinting()) { pDC->SelectClipRgn(&rgnClip, RGN_COPY); } CRect rcEmpty(rcClient); rcEmpty.top = y; DrawDefaultGrid(pDC, rcEmpty, GetPaintManager()->m_nRowHeight, m_nScrollOffsetH); //always use standard row height if (!pDC->IsPrinting()) { pDC->SelectClipRgn(NULL, RGN_COPY); } VERIFY(rgnClip.DeleteObject()); } if (0 == pRows->GetCount()) { DrawNoItems(pDC, rcClient); } if (NULL != pnHeight) { *pnHeight = y - rcClient.top; } return nRow; } void CXTPReportControl::DrawIconView(CDC *pDC, CRect &rcClient) { CXTPReportRecordMergeItems mergeItems; int nHeaderWidth = GetReportHeader()->GetWidth(); int nRowCount = m_pRows->GetCount(); int y = rcClient.top; m_iIconViewRowsPerLine = GetNumRowsOnLine(nHeaderWidth); int x = rcClient.left; int iLastMainRow = m_pSectionBody->GetScrollIndexV(); while(iLastMainRow % m_iIconViewRowsPerLine) { iLastMainRow++; } for (int i = iLastMainRow; i < nRowCount; i++) { CXTPReportRow* pRow = m_pRows->GetAt(i); ASSERT(pRow); if (!pRow) continue; if (y > rcClient.bottom) break; if (pRow->GetIndex() % m_iIconViewRowsPerLine) { x += m_iIconWidthSpacing; CRect rcRow(x, y, x + m_iIconWidthSpacing, y + m_iIconHeightSpacing); pRow->Draw(pDC, rcRow, GetReportRectangle(), 0, mergeItems, 0, GetColumns()->GetCount()); } else { x = rcClient.left; if (iLastMainRow != pRow->GetIndex()) { y += m_iIconHeightSpacing; iLastMainRow = pRow->GetIndex(); } CRect rcRow(x, y, x + m_iIconWidthSpacing, y + m_iIconHeightSpacing); pRow->Draw(pDC, rcRow, GetReportRectangle(), 0, mergeItems, 0, GetColumns()->GetCount()); } CXTPReportRow* pScreenRow = NULL; if (IsVirtualMode()) { pScreenRow = CreateRow(); pScreenRow->InitRow(pRow); pScreenRow->SetExpanded(pRow->IsExpanded()); pScreenRow->m_rcCollapse = pRow->m_rcCollapse; } else { pScreenRow = pRow; pScreenRow->InternalAddRef(); } CXTPReportScreenRows *pScreenRows = GetRows()->GetScreenRows(); pScreenRows->InsertAt(pScreenRows->GetSize(), pScreenRow); } } void CXTPReportControl::OnSelectionChanged() { SetLastRqstEdit(-1, -1); //m_iLastRqstEditCol = -1; //m_iLastRqstEditRow = -1; SendNotifyMessage(XTP_NM_REPORT_SELCHANGED); if (m_pSelectedRows) m_pSelectedRows->SetChanged(FALSE); } BOOL CXTPReportControl::OnFocusChanging(CXTPReportRow* pNewRow, CXTPReportColumn* pNewCol) { XTP_NM_REPORTREQUESTEDIT nm; ::ZeroMemory(&nm, sizeof(nm)); nm.bCancel = FALSE; nm.pRow = pNewRow ? pNewRow : GetFocusedRow(); nm.pColumn = pNewCol ? pNewCol : GetFocusedColumn(); nm.pItem = nm.pRow && nm.pColumn ? (nm.pRow->GetRecord() ? nm.pRow->GetRecord()->GetItem(nm.pColumn) : NULL) : NULL; SendNotifyMessage(XTP_NM_REPORT_FOCUS_CHANGING, (NMHDR*)&nm); return !nm.bCancel; } void CXTPReportControl::GetItemMetrics( XTP_REPORTRECORDITEM_DRAWARGS *pDrawArgs, XTP_REPORTRECORDITEM_METRICS *pMetrics) { XTP_NM_REPORTITEMMETRICS nmData; nmData.pDrawArgs = pDrawArgs; nmData.pItemMetrics = pMetrics; SendNotifyMessage(XTP_NM_REPORT_GETITEMMETRICS, (NMHDR*) &nmData); } BOOL CXTPReportControl::SetFocusedColumn(CXTPReportColumn* pColumn) { if (m_pFocusedColumn != pColumn) { if (m_bFocusSubItems && pColumn) { if (!OnFocusChanging(NULL, pColumn)) return FALSE; } m_pFocusedColumn = pColumn; if (m_pFocusedColumn && m_bFocusSubItems) { CRect rc(m_pFocusedColumn->GetRect()); if (rc.right >= m_pSectionBody->GetRect().Width()) { SetScrollOffsetH(m_nScrollOffsetH + min(rc.left, rc.right - m_pSectionBody->m_rcSection.Width())); } else { int nFreezeColumnWidth = 0; int nFreezeColumnsCount = GetFreezeColumnsCount(); if (nFreezeColumnsCount > 0) { for (int i = 0; (i < m_pColumns->GetCount()) && (nFreezeColumnsCount > 0); i++) { CXTPReportColumn* pColumnCheck = m_pColumns->GetAt(i); if (pColumnCheck == m_pFocusedColumn) { nFreezeColumnWidth = 0; break; } if (pColumnCheck && pColumnCheck->IsVisible()) { nFreezeColumnsCount--; nFreezeColumnWidth = pColumnCheck->GetRect().right; } } } if (rc.left - nFreezeColumnWidth <= 0 && m_nScrollOffsetH != 0) { SetScrollOffsetH(m_nScrollOffsetH + rc.left - nFreezeColumnWidth); } } } if (m_bFocusSubItems) OnSelectionChanged(); } return TRUE; } BOOL CXTPReportControl::SetFocusedRow(CXTPReportRow* pRow, BOOL bShiftKey, BOOL bControlKey) { return SetFocusedRow(TRUE, pRow, bShiftKey, bControlKey); } BOOL CXTPReportControl::SetFocusedRow(CXTPReportRow* pRow, BOOL bControlKey) { return SetFocusedRow(TRUE, pRow, FALSE, bControlKey); } int CXTPReportControl::_GetFocusedRowType() const { int nFocusedRowType = -1; if (GetRows()->GetFocusedRowIndex() != -1) { nFocusedRowType = xtpRowTypeBody; } if (GetHeaderRows()->GetFocusedRowIndex() != -1) { nFocusedRowType = xtpRowTypeHeader; } if (GetFooterRows()->GetFocusedRowIndex() != -1) { nFocusedRowType = xtpRowTypeFooter; } return nFocusedRowType; } int CXTPReportControl::_GetFocusedRowIndex() const { int nFocusedRowIndex = -1; if (GetRows()->GetFocusedRowIndex() != -1) { nFocusedRowIndex = GetRows()->GetFocusedRowIndex(); } if (GetHeaderRows()->GetFocusedRowIndex() != -1) { nFocusedRowIndex = GetHeaderRows()->GetFocusedRowIndex(); } if (GetFooterRows()->GetFocusedRowIndex() != -1) { nFocusedRowIndex = GetFooterRows()->GetFocusedRowIndex(); } return nFocusedRowIndex; } BOOL CXTPReportControl::_SetFocusedRow(CXTPReportRow *pRow) { ////////////////////////////////////////////////////////////////////////// // Current focused row ////////////////////////////////////////////////////////////////////////// int nFocusedRowType = _GetFocusedRowType(); int nFocusedRowIndex = _GetFocusedRowIndex(); ////////////////////////////////////////////////////////////////////////// // New focused row ////////////////////////////////////////////////////////////////////////// int nRowType = -1; int nRowIndex = -1; if (NULL != pRow) { nRowType = pRow->GetType(); nRowIndex = pRow->GetIndex(); } ////////////////////////////////////////////////////////////////////////// // Notify OnFocusChanging ////////////////////////////////////////////////////////////////////////// BOOL bApply = TRUE; if (nFocusedRowType != nRowType || nFocusedRowIndex != nRowIndex) { if (NULL != pRow) { pRow->InternalAddRef(); bApply = OnFocusChanging(pRow, NULL); if (1 == pRow->m_dwRef) { // Removed bApply = FALSE; } pRow->InternalRelease(); } } ////////////////////////////////////////////////////////////////////////// // Set new focused row ////////////////////////////////////////////////////////////////////////// GetRows()->SetFocusedRowIndex(-1); GetFooterRows()->SetFocusedRowIndex(-1); GetHeaderRows()->SetFocusedRowIndex(-1); if (NULL != pRow && bApply) { switch (pRow->GetType()) { case xtpRowTypeBody: GetRows()->SetFocusedRowIndex(pRow->GetIndex()); break; case xtpRowTypeHeader: GetHeaderRows()->SetFocusedRowIndex(pRow->GetIndex()); break; case xtpRowTypeFooter: GetFooterRows()->SetFocusedRowIndex(pRow->GetIndex()); break; } } return bApply; } BOOL CXTPReportControl::_SetSelectedRow(CXTPReportRow *pRow, int nFocusedRowIndex, BOOL bShiftKey, BOOL bControlKey) { BOOL bEnableSelection = FALSE; if (NULL != pRow) { bEnableSelection = pRow->GetSection()->IsSelectionEnabled(); } if (bEnableSelection) { if (m_bBlockSelection) { if (bShiftKey && nFocusedRowIndex != -1) { int nSelRow = pRow->GetIndex(); m_pSelectedRows->SelectBlock(nFocusedRowIndex, nSelRow, bControlKey); } else if (!bControlKey) { m_pSelectedRows->Select(pRow); } } else { m_pSelectedRows->Select(pRow); } } return TRUE; } BOOL CXTPReportControl::SetFocusedRow(BOOL bEnsureVisible, CXTPReportRow *pRow, BOOL bShiftKey, BOOL bControlKey) { int nFocusedRowIndex = _GetFocusedRowIndex(); // Current focused row EditItem(NULL); BeginUpdate(); _SetFocusedRow(pRow); // Null pointer clears focus _SetSelectedRow(pRow, nFocusedRowIndex, bShiftKey, bControlKey); // Null pointer clears selection if (bEnsureVisible && (NULL != pRow)) { EnsureVisible(pRow); // Null pointer not allowed } EndUpdate(); if (m_pSelectedRows->IsChanged()) { OnSelectionChanged(); } return TRUE; } void CXTPReportControl::SetScrollOffsetH(int nOffset) { if (nOffset < 0) { nOffset = 0; } if (nOffset != m_nScrollOffsetH) { m_nScrollOffsetH = nOffset; AdjustScrollBarH(TRUE, SIF_PAGE | SIF_POS); // Only update page and position // Send notification XTP_NM_REPORTSCROLL msg; msg.nSection = m_pSectionScroll->GetIndex(); msg.nPosition = nOffset; SendNotifyMessage(XTP_NM_REPORT_HSCROLL, &msg); } } void CXTPReportControl::SetScrollOffsetV(int nOffset) { if (nOffset < 0) { nOffset = 0; } if (nOffset != m_pSectionScroll->GetScrollOffsetV()) { m_pSectionScroll->SetScrollOffsetV(nOffset); AdjustScrollBarV(TRUE, SIF_PAGE | SIF_POS); // Only update page and position // Send notification XTP_NM_REPORTSCROLL msg; msg.nSection = m_pSectionScroll->GetIndex(); msg.nPosition = nOffset; SendNotifyMessage(XTP_NM_REPORT_VSCROLL, &msg); } } void CXTPReportControl::SetTopRow(int nIndex) { if (nIndex < 0) { nIndex = 0; } if (nIndex != GetTopRowIndex()) { if (IsIconView()) { // Must get first row on the same line. while(nIndex % GetRowsPerLine()) { nIndex--; } } m_pSectionScroll->SetScrollIndexV(nIndex); } } void CXTPReportControl::EnsureVisible(CXTPReportRow *pRow) { if (NULL != pRow) { if (NULL == GetSafeHwnd()) { m_nEnsureVisibleRowIdx = pRow->GetIndex(); } else { CXTPReportSection *pSection = pRow->GetSection(); ASSERT(NULL != pSection); if (NULL != pSection) { if (pSection->GetRect().IsRectNull()) { m_nEnsureVisibleRowIdx = pRow->GetIndex(); } else { CClientDC dc(this); pSection->EnsureVisible(&dc, pRow); } } } } } void CXTPReportControl::EnsureVisible(CXTPReportColumn* pCheckColumn) { int nCheckIndex = pCheckColumn ? pCheckColumn->GetIndex() : -1; if (nCheckIndex == -1 || !pCheckColumn->m_bVisible || nCheckIndex >= m_pColumns->GetCount()) return; if (m_pSectionBody->m_rcSection.Height() <= 0) { m_nEnsureVisibleRowIdx = nCheckIndex; return; } CRect rc(pCheckColumn->GetRect()); if (rc.right >= m_pSectionBody->m_rcSection.Width()) { SetScrollOffsetH(m_nScrollOffsetH + min(rc.left, rc.right - m_pSectionBody->m_rcSection.Width())); } else { int nFreezeColumnWidth = 0; int nFreezeColumnsCount = GetFreezeColumnsCount(); if (nFreezeColumnsCount > 0) { for (int i = 0; (i < m_pColumns->GetCount()) && (nFreezeColumnsCount > 0); i++) { CXTPReportColumn* pColumn = m_pColumns->GetAt(i); if (pColumn == pCheckColumn) { nFreezeColumnWidth = 0; break; } if (pColumn && pColumn->IsVisible()) { nFreezeColumnsCount--; nFreezeColumnWidth = pColumn->GetRect().right; } } } if (rc.left - nFreezeColumnWidth <= 0 && m_nScrollOffsetH != 0) { SetScrollOffsetH(m_nScrollOffsetH + rc.left - nFreezeColumnWidth); } } } BOOL CXTPReportControl::HitTest(CPoint pt, CXTPReportHitTestInfo *pInfo) const { if (NULL == pInfo) { return FALSE; } pInfo->m_pColumn = NULL; pInfo->m_pRow = NULL; pInfo->m_pItem = NULL; pInfo->m_pBlock = NULL; pInfo->m_htCode = xtpReportHitTestUnknown; pInfo->m_iTrackPosition = 0; if (m_rcHeaderArea.PtInRect(pt)) { pInfo->m_htCode = xtpReportHitTestHeader; pInfo->m_pColumn = GetReportHeader()->HitTest(pt); } else if (m_rcGroupByArea.PtInRect(pt)) { pInfo->m_htCode = xtpReportHitTestGroupBox; int nColumn = GetReportHeader()->FindGroupByColumn(pt, TRUE); pInfo->m_pColumn = GetColumns()->GetGroupsOrder()->GetAt(nColumn); } else if (m_pSections->GetRect().PtInRect(pt)) { const CXTPReportSection *pSection = m_pSections->HitTest(pt); if (NULL != pSection) { switch(pSection->GetRowType()) { case xtpRowTypeBody: pInfo->m_htCode = xtpReportHitTestBodyRows; break; case xtpRowTypeHeader: pInfo->m_htCode = xtpReportHitTestHeaderRows; break; case xtpRowTypeFooter: pInfo->m_htCode = xtpReportHitTestFooterRows; break; } } pInfo->m_pRow = HitTest(pt); if (NULL != pInfo->m_pRow) { pInfo->m_pItem = pInfo->m_pRow->HitTest(pt, NULL, &pInfo->m_pColumn); } } return TRUE; } CXTPReportRow* CXTPReportControl::HitTest(CPoint pt) const { CXTPReportRow *pRow = NULL; CXTPReportSection *pSection = m_pSections->HitTest(pt); if (NULL != pSection) { pRow = pSection->GetRows()->GetScreenRows()->HitTest(pt); } return pRow; } int CXTPReportControl::GetReportAreaRows(int nStartRow, BOOL bMoveDown) { int nDirection = bMoveDown ? +1 : -1; int top = m_pSectionBody->m_rcSection.top; CClientDC dc(this); int nHeaderWidth = GetReportHeader()->GetWidth(); int i = nStartRow; if (IsIconView()) { // Find the first row, to account for the height of the row we are in. while(i % GetRowsPerLine() != 0) { i--; } } for (; (i < m_pRows->GetCount() && i >= 0); i += nDirection) { CXTPReportRow* pRow = m_pRows->GetAt(i); ASSERT(pRow); if (!pRow) continue; int rowHeight = pRow->GetHeight(&dc, nHeaderWidth); if (top + rowHeight > m_pSectionBody->m_rcSection.bottom) return bMoveDown ? i - nStartRow - 1 : nStartRow - i - 1; top += rowHeight; } //return bMoveDown ? m_pRows->GetCount() - nStartRow : nStartRow; return bMoveDown ? m_pRows->GetCount() - nStartRow - 1: nStartRow; //-this is better way! } void CXTPReportControl::AdjustLayout() { /* ------------------------------ | Group by | ------------------------------ | Header | ------------------------------ | Sections | ------------------------------ | Footer | ------------------------------ */ if (NULL == GetSafeHwnd()) return; CXTPClientRect rcClient(this); CClientDC dc(this); if (rcClient.IsRectEmpty()) { // Avoid unnecessary layout calculations during creation return; } ASSERT(!m_bAdjustLayoutRunning); if (m_bAdjustLayoutRunning) //guard to prevent the recursion similar to OnSize function { return; } m_bAdjustLayoutRunning = TRUE; int nHeaderWidth = m_rcHeaderArea.Width(); CXTPReportHeader *pHeader = GetReportHeader(); int nHeightGroupBy = 0; int nHeightHeader = 0; int nHeightSections = 0; int nHeightFooter = 0; if (NULL != pHeader && m_bGroupByEnabled) { nHeightGroupBy = pHeader->GetGroupByHeight(); } if (m_bHeaderVisible) { nHeightHeader = GetPaintManager()->GetHeaderHeight(this, &dc); } if (m_bFooterVisible) { nHeightFooter = GetPaintManager()->GetFooterHeight(this, &dc); } // Group by rect m_rcGroupByArea.SetRect(0, 0, rcClient.Width(), nHeightGroupBy); // Header m_rcHeaderArea.SetRect(0, m_rcGroupByArea.bottom, rcClient.Width(), m_rcGroupByArea.bottom + nHeightHeader); // Sections nHeightSections = rcClient.Height() - nHeightGroupBy - nHeightHeader - nHeightFooter; CRect rcSections(0, m_rcHeaderArea.bottom, rcClient.Width(), m_rcHeaderArea.bottom+nHeightSections); m_pSections->AdjustLayout(&dc, rcSections); // Footer m_rcFooterArea.SetRect(0, rcClient.Height() - nHeightFooter, rcClient.Width(), rcClient.Height()); if (nHeaderWidth != m_rcHeaderArea.Width() && pHeader) { pHeader->AdjustColumnsWidth(m_rcHeaderArea.Width()); } m_bAdjustLayoutRunning = FALSE; } CScrollBar* CXTPReportControl::GetScrollBarCtrl(int nBar) const { if (DYNAMIC_DOWNCAST(CView, GetParent())) return GetParent()->GetScrollBarCtrl(nBar); return NULL; } void CXTPReportControl::RedrawScrollBar(int nBar) { CScrollBar *pScrollBar = GetScrollBarCtrl(nBar); if (NULL != pScrollBar) { SAFE_INVALIDATE(pScrollBar); } else { if (NULL != m_hWnd) { SendMessage(WM_NCPAINT); } } } void CXTPReportControl::GetColumnTotalSize(int &nTotalCount, int &nTotalWidth) const { nTotalCount = 0; nTotalWidth = 0; for (int nColumn=0; nColumnGetCount(); nColumn++) { const CXTPReportColumn *pColumn = GetColumns()->GetAt(nColumn); if (pColumn->IsVisible()) { nTotalCount += 1; nTotalWidth += pColumn->GetWidth(); } } } void CXTPReportControl::GetColumnOutOfViewSize(int &nOutOfViewCount, int &nOutOfViewWidth) const { int nLeft = 0; int nRight = 0; nOutOfViewCount = 0; nOutOfViewWidth = 0; for (int nColumn=0; nColumnGetCount(); nColumn++) { const CXTPReportColumn *pColumn = GetColumns()->GetAt(nColumn); if (pColumn->IsVisible()) { nRight = nLeft + pColumn->GetWidth(); if (nRight > GetReportRectangle().right) { nOutOfViewCount += 1; nOutOfViewWidth += pColumn->GetWidth() - max(0, GetReportRectangle().right-nLeft); } nLeft = nRight; } } } void CXTPReportControl::GetColumnScrollSize(int nOutOfViewWidth, int &nScrollCount, int &nScrollWidth) const { nScrollCount = 0; nScrollWidth = 0; for (int nColumn=0; nColumnGetCount(); nColumn++) { const CXTPReportColumn *pColumn = GetColumns()->GetAt(nColumn); if (pColumn->IsVisible() && !pColumn->IsFrozen()) { if (nOutOfViewWidth > nScrollWidth) { nScrollCount += 1; nScrollWidth += pColumn->GetWidth(); } } } } void CXTPReportControl::AdjustScrollBarH(BOOL bUpdate, UINT nMask) { if (bUpdate) { EditItem(NULL); BeginUpdate(); } SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); // Get current values GetScrollInfo(SB_HORZ, &si, SIF_ALL); if (xtpReportScrollModeBlockCount == m_scrollModeH || xtpReportScrollModeBlockSize == m_scrollModeH) { const CXTPReportColumns *pColumns = GetColumns(); int nTotalCount, nTotalWidth; GetColumnTotalSize(nTotalCount, nTotalWidth); int nOutOfViewCount, nOutOfViewWidth; GetColumnOutOfViewSize(nOutOfViewCount, nOutOfViewWidth); int nScrollCount, nScrollWidth; GetColumnScrollSize(nOutOfViewWidth, nScrollCount, nScrollWidth); if (xtpReportScrollModeBlockCount == m_scrollModeH) { if (SIF_RANGE & nMask) si.nMin = 0; if (SIF_RANGE & nMask) si.nMax = nTotalCount - 1; if (SIF_PAGE & nMask) si.nPage = nTotalCount - nScrollCount; if (SIF_POS & nMask) si.nPos = pColumns->GetAtOffset(m_nScrollOffsetH, TRUE); } if (xtpReportScrollModeBlockSize == m_scrollModeH) { if (SIF_RANGE & nMask) si.nMin = 0; if (SIF_RANGE & nMask) si.nMax = nTotalWidth - 1; if (SIF_PAGE & nMask) si.nPage = nTotalWidth - nScrollWidth; if (SIF_POS & nMask) si.nPos = m_nScrollOffsetH; } } if (xtpReportScrollModeSmooth == m_scrollModeH) { // Update requested values if (SIF_RANGE & nMask) si.nMin = 0; if (SIF_RANGE & nMask) si.nMax = GetReportHeader()->GetWidth() - 1; if (SIF_PAGE & nMask) si.nPage = m_pSectionBody->GetRect().Width(); if (SIF_POS & nMask) si.nPos = m_nScrollOffsetH; } if (xtpReportScrollModeSmooth == m_scrollModeH || xtpReportScrollModeBlockSize == m_scrollModeH) { si.nPage = min(si.nPage, UINT(si.nMax)+1); // Adjust scroll offset when increasing the section size if ((si.nPos > 0) && (si.nPos + int(si.nPage) - 1 > si.nMax)) { m_nScrollOffsetH = si.nMax - si.nPage + 1; si.nPos = m_nScrollOffsetH; } } // Set new values si.fMask = nMask; SetScrollInfo(SB_HORZ, &si); // Note: Causes an OnSize message // si.nMax is -1 for no rows BOOL bEnabled = (-1 != si.nMax) && (UINT(si.nMax) >= UINT(si.nPage)); CWnd::EnableScrollBarCtrl(SB_HORZ, bEnabled); ::EnableScrollBar(m_hWnd, SB_HORZ, (bEnabled && IsWindowEnabled()) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH); if (m_bHScrollBarVisible != bEnabled) { m_bHScrollBarVisible = bEnabled; } if (bUpdate) { EndUpdate(); } } int CXTPReportControl::GetPageRowCount(CDC *pDC) const { int nCount = m_pRows->GetCount() - 1; int nLinesCount = nCount; int nHeight = m_pSectionBody->GetRect().Height(); int nWidth = m_pSectionBody->GetRect().Width(); for (; nLinesCount >= 0; nLinesCount--) { nHeight -= m_pRows->GetAt(nLinesCount)->GetHeight(pDC, nWidth); if (nHeight < 0) { if (nLinesCount != nCount) nLinesCount += IsIconView() ? GetRowsPerLine() : 1; // Want the next row, in icon view, that is an addition of an entire row. break; } } nLinesCount = max(nLinesCount, 0); return nLinesCount; } void CXTPReportControl::AdjustScrollBarV(BOOL bUpdate, UINT nMask) { CClientDC dc(this); if (bUpdate) { EditItem(NULL); BeginUpdate(); } SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); // Get current values GetScrollInfo(SB_VERT, &si, SIF_ALL); if (xtpReportScrollModeBlockCount == m_scrollModeV || xtpReportScrollModeBlockSize == m_scrollModeV) { int nMax = m_pSectionBody->GetRows()->GetCount() - 1; int nPage = GetPageRowCount(&dc); // Update requested values if (SIF_RANGE & nMask) si.nMin = 0; if (SIF_RANGE & nMask) si.nMax = nMax; if (SIF_PAGE & nMask) si.nPage = nMax - nPage + 1; if (SIF_POS & nMask) si.nPos = GetTopRowIndex(); si.nPage = min(si.nPage, UINT(si.nMax)+1); // Adjust scroll offset when increasing the section size if ((si.nPos > 0) && (si.nPos + int(si.nPage) - 1 > si.nMax)) { si.nPos = si.nMax - si.nPage + 1; m_pSectionScroll->SetScrollIndexV(si.nPos); } } if (xtpReportScrollModeSmooth == m_scrollModeV) { // Update requested values if (SIF_RANGE & nMask) si.nMin = 0; if (SIF_RANGE & nMask) si.nMax = m_pSectionScroll->GetRowsHeight(&dc) - 1; if (SIF_PAGE & nMask) si.nPage = m_pSectionScroll->GetRect().Height(); if (SIF_POS & nMask) si.nPos = m_pSectionScroll->GetScrollOffsetV(); si.nPage = min(si.nPage, UINT(si.nMax)+1); // Adjust scroll offset when increasing the section size if ((si.nPos > 0) && (si.nPos + int(si.nPage) - 1 > si.nMax)) { si.nPos = si.nMax - si.nPage + 1; m_pSectionScroll->SetScrollOffsetV(si.nPos); } } // Set new values si.fMask = nMask; SetScrollInfo(SB_VERT, &si); // Note: Causes an OnSize message // si.nMax is -1 for no rows BOOL bEnabled = (-1 != si.nMax) && (UINT(si.nMax) >= UINT(si.nPage)); CWnd::EnableScrollBarCtrl(SB_VERT, bEnabled); ::EnableScrollBar(m_hWnd, SB_VERT, (bEnabled && IsWindowEnabled()) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH); if (m_bVScrollBarVisible != bEnabled) { m_bVScrollBarVisible = bEnabled; } if (bUpdate) { EndUpdate(); } } void CXTPReportControl::UpdateScrollBarV() { AdjustScrollBarV(TRUE, SIF_PAGE | SIF_POS); // Only update page and position // Send notification XTP_NM_REPORTSCROLL msg; msg.nSection = m_pSectionScroll->GetIndex(); switch(m_scrollModeV) { case xtpReportScrollModeSmooth: msg.nPosition = m_pSectionScroll->GetScrollOffsetV(); break; case xtpReportScrollModeBlockCount: case xtpReportScrollModeBlockSize: msg.nPosition = m_pSectionScroll->GetScrollIndexV(); break; } SendNotifyMessage(XTP_NM_REPORT_VSCROLL, &msg); } void CXTPReportControl::AdjustScrollBars() { if (GetSafeHwnd() == NULL) return; EditItem(NULL); int nHeight = m_pSectionBody->GetRect().Height(); if (nHeight <= 0) return; BeginUpdate(); AdjustScrollBarH(FALSE, SIF_ALL); AdjustScrollBarV(FALSE, SIF_ALL); EndUpdate(); } void CXTPReportControl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { if (pScrollBar != NULL) { CWnd::OnVScroll(nSBCode, nPos, pScrollBar); return; } if (!m_bIconView) { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); GetScrollInfo(SB_VERT, &si, SIF_ALL); const int nLimit = si.nMax - si.nPage + 1; // GetScrollLimit if (xtpReportScrollModeSmooth == m_scrollModeV) { int nScrollOffsetV = m_pSectionScroll->GetScrollOffsetV(); switch (nSBCode) { case SB_LINEUP: // 0 nScrollOffsetV = max(nScrollOffsetV - m_nScrollStepV, 0); break; case SB_LINEDOWN: // 1 nScrollOffsetV = min(nScrollOffsetV + m_nScrollStepV, nLimit); break; case SB_PAGEUP: // 2 nScrollOffsetV = max(nScrollOffsetV - int(si.nPage), 0); break; case SB_PAGEDOWN: // 3 nScrollOffsetV = min(nScrollOffsetV + int(si.nPage), nLimit); break; case SB_THUMBPOSITION: // 4 case SB_THUMBTRACK: // 5 nScrollOffsetV = si.nTrackPos; break; case SB_TOP: // 6 nScrollOffsetV = 0; break; case SB_BOTTOM: // 7 nScrollOffsetV = nLimit; break; case SB_ENDSCROLL: // 8 break; } if (-1 != nScrollOffsetV) { SetScrollOffsetV(nScrollOffsetV); } } // smooth if (xtpReportScrollModeBlockCount == m_scrollModeV || xtpReportScrollModeBlockSize == m_scrollModeV) { int nPos = -1; switch (nSBCode) { case SB_LINEUP: // 0 nPos = max(si.nPos - 1, 0); break; case SB_LINEDOWN: // 1 nPos = min(si.nPos + 1, nLimit); break; case SB_PAGEUP: // 2 nPos = max(si.nPos - max(1, GetReportAreaRows(si.nPos, FALSE)), 0); break; case SB_PAGEDOWN: // 3 nPos = min(si.nPos + max(1, GetReportAreaRows(si.nPos, TRUE)), nLimit); break; case SB_THUMBPOSITION: // 4 case SB_THUMBTRACK: // 5 nPos = si.nTrackPos; break; case SB_TOP: // 6 nPos = 0; break; case SB_BOTTOM: // 7 nPos = nLimit; break; case SB_ENDSCROLL: // 8 break; } if (-1 != nPos) { SetTopRow(nPos); } } } else { int nCurPos = GetTopRowIndex(); CXTPReportColumn* pColumn = GetColumns()->Find(m_iIconViewColumn); if (!pColumn) { CXTPReportControl::OnVScroll(nSBCode, nPos, pScrollBar); return; } // decide what to do for each diffrent scroll event switch (nSBCode) { case SB_TOP: nCurPos = 0; break; case SB_BOTTOM: nCurPos = GetScrollLimit(SB_VERT); break; case SB_LINEUP: nCurPos = max(nCurPos - m_iIconViewRowsPerLine, 0); break; case SB_LINEDOWN: nCurPos = min(nCurPos + m_iIconViewRowsPerLine, GetScrollLimit(SB_VERT)); break; case SB_PAGEUP: nCurPos = max(nCurPos - GetReportAreaRows(nCurPos, FALSE), 0); break; case SB_PAGEDOWN: nCurPos = min(nCurPos + GetReportAreaRows(nCurPos, TRUE), GetScrollLimit(SB_VERT)); break; case SB_THUMBTRACK: case SB_THUMBPOSITION: { SCROLLINFO si; ZeroMemory(&si, sizeof(SCROLLINFO)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_TRACKPOS; if (!GetScrollInfo(SB_VERT, &si)) return; nCurPos = si.nTrackPos; } break; } SetTopRow(nCurPos); } } void CXTPReportControl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) { if (pScrollBar != NULL) { CWnd::OnHScroll(nSBCode, nPos, pScrollBar); return; } int nCurPos = m_nScrollOffsetH; SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); GetScrollInfo(SB_HORZ, &si, SIF_ALL); const int nLimit = si.nMax - si.nPage + 1; // GetScrollLimit if (xtpReportScrollModeSmooth == m_scrollModeH) { switch (nSBCode) { case SB_LINEUP: // 0 nCurPos = max(nCurPos - m_nScrollStepH, 0); break; case SB_LINEDOWN: // 1 nCurPos = min(nCurPos + m_nScrollStepH, nLimit); break; case SB_PAGEUP: // 2 nCurPos = max(nCurPos - m_pSectionBody->GetRect().Width(), 0); break; case SB_PAGEDOWN: // 3 nCurPos = min(nCurPos + m_pSectionBody->m_rcSection.Width(), nLimit); break; case SB_THUMBPOSITION: // 4 case SB_THUMBTRACK: // 5 nCurPos = si.nTrackPos; break; case SB_TOP: // 6 nCurPos = 0; break; case SB_BOTTOM: // 7 nCurPos = nLimit; break; case SB_ENDSCROLL: // 8 break; } } if (xtpReportScrollModeBlockCount == m_scrollModeH) { CXTPReportColumn *pPrev = NULL, *pCurr = NULL, *pNext = NULL; int nScrollPos = 0, nScrollMax = 0; GetReportHeader()->GetFullColScrollInfo(pPrev, pCurr, pNext, nScrollPos, nScrollMax); int nOutOfViewCount, nOutOfViewWidth; GetColumnOutOfViewSize(nOutOfViewCount, nOutOfViewWidth); int nScrollCount, nScrollWidth; GetColumnScrollSize(nOutOfViewWidth, nScrollCount, nScrollWidth); switch (nSBCode) { case SB_LINEUP: // 0 case SB_PAGEUP: // 2 { if (NULL != pPrev) { nCurPos = max(nCurPos - pPrev->GetWidth(), 0); } break; } case SB_LINEDOWN: // 1 case SB_PAGEDOWN: // 3 { if (NULL != pCurr) { nCurPos = min(nCurPos + pCurr->GetWidth(), nScrollWidth); } break; } case SB_THUMBPOSITION: // 4 case SB_THUMBTRACK: // 5 { nCurPos = GetColumns()->GetOffset(si.nTrackPos); break; } case SB_TOP: // 6 nCurPos = 0; break; case SB_BOTTOM: // 7 nCurPos = nScrollWidth; break; case SB_ENDSCROLL: // 8 break; } } if (xtpReportScrollModeBlockSize == m_scrollModeH) { CXTPReportColumn *pPrev = NULL, *pCurr = NULL, *pNext = NULL; int nScrollPos = 0, nScrollMax = 0; GetReportHeader()->GetFullColScrollInfo(pPrev, pCurr, pNext, nScrollPos, nScrollMax); switch (nSBCode) { case SB_LINEUP: // 0 case SB_PAGEUP: // 2 { if (NULL != pPrev) { nCurPos = max(nCurPos - pPrev->GetWidth(), 0); } break; } case SB_LINEDOWN: // 1 case SB_PAGEDOWN: // 3 { if (NULL != pCurr) { nCurPos = min(nCurPos + pCurr->GetWidth(), nLimit); } break; } case SB_THUMBPOSITION: // 4 case SB_THUMBTRACK: // 5 { int nColumn = GetColumns()->GetAtOffset(si.nTrackPos, TRUE); nCurPos = GetColumns()->GetOffset(nColumn); break; } case SB_TOP: // 6 nCurPos = 0; break; case SB_BOTTOM: // 7 nCurPos = nLimit; break; case SB_ENDSCROLL: // 8 break; } } SetScrollOffsetH(nCurPos); } HBITMAP CXTPReportControl::GetWatermarkBitmap() const { return m_hbmpWatermark; } BOOL CXTPReportControl::SetWatermarkBitmap(HBITMAP hBitmap, BYTE Transparency) { m_WatermarkTransparency = Transparency; // remove old watermark bitmap if one is if (m_hbmpWatermark) { ::DeleteObject(m_hbmpWatermark); m_hbmpWatermark = NULL; } if (hBitmap) { // add new watermark bitmap BITMAP bmSrc; if (!CBitmap::FromHandle(hBitmap)->GetBitmap(&bmSrc)) return FALSE; BOOL bAlphaBitmap = bmSrc.bmBitsPixel == 32; // create an alpha bitmap if the bitmap supplied isn't an alpha one if (!bAlphaBitmap) { m_hbmpWatermark = ::CreateBitmap(bmSrc.bmWidth, bmSrc.bmHeight, bmSrc.bmPlanes, 32, NULL); ASSERT(m_hbmpWatermark); if (!m_hbmpWatermark) return FALSE; CXTPCompatibleDC memWatermarkDC(NULL, m_hbmpWatermark); CXTPCompatibleDC memScrDC(NULL, hBitmap); memWatermarkDC.BitBlt(0, 0, bmSrc.bmWidth, bmSrc.bmHeight, &memScrDC, 0, 0, SRCCOPY); } else { m_hbmpWatermark = CXTPImageManagerIcon::CopyAlphaBitmap(hBitmap); } if (!m_hbmpWatermark) return FALSE; if (!CBitmap::FromHandle(m_hbmpWatermark)->GetBitmap(&m_bmWatermark)) { ::DeleteObject(m_hbmpWatermark); m_hbmpWatermark = NULL; return FALSE; } } return TRUE; } BOOL CXTPReportControl::SetWatermarkBitmap(LPCTSTR szPath, BYTE Transparency) { m_WatermarkTransparency = Transparency; // if path is empty, remove watermark bitmap if (_tcslen(szPath) == 0) { ::DeleteObject(m_hbmpWatermark); m_hbmpWatermark = NULL; } else { // remove old watermark bitmap if one is if (m_hbmpWatermark) { ::DeleteObject(m_hbmpWatermark); m_hbmpWatermark = NULL; } // add new watermark bitmap BOOL bAlphaBitmap = FALSE; m_hbmpWatermark = CXTPImageManagerIcon::LoadBitmapFromFile(szPath, &bAlphaBitmap); if (!m_hbmpWatermark) return FALSE; if (!CBitmap::FromHandle(m_hbmpWatermark)->GetBitmap(&m_bmWatermark)) { ::DeleteObject(m_hbmpWatermark); m_hbmpWatermark = NULL; return FALSE; } // create an alpha bitmap if the bitmap supplied isn't an alpha one if (!bAlphaBitmap) { CXTPCompatibleDC memWatermarkDC(NULL, m_hbmpWatermark); CXTPImageManagerIcon::DrawAlphaBitmap(&memWatermarkDC, m_hbmpWatermark, CPoint(0, 0), CSize(m_bmWatermark.bmWidth, m_bmWatermark.bmHeight)); } } return TRUE; } ////////////////////////////////////////////////////////////////////////// // CXTPReportControl message handlers void CXTPReportControl::Paint(CDC *pDC) { OnDraw(pDC); // Update flag SetChanged(FALSE); if (!IsWindowEnabled() && GetPaintManager()->m_bGrayIfDisable) { CXTPClientRect rcClient(this); XTPImageManager()->DisableBitmap(*pDC, rcClient, RGB(250, 250, 250), RGB(128, 128, 128)); } } void CXTPReportControl::EnableDoubleBuffering(BOOL bEnable) { m_bDoubleBuffering = bEnable; // Delete buffer if (!m_bDoubleBuffering && NULL != m_bmpCache.GetSafeHandle()) { m_bmpCache.DeleteObject(); } } void CXTPReportControl::OnPaint() { CPaintDC dc(this); // device context for painting CXTPClientRect rcClient(this); // ensure visible row and column if first started if (m_nEnsureVisibleRowIdx >= 0) { CXTPReportRow *pRow = GetRows()->GetAt(m_nEnsureVisibleRowIdx); if (NULL != pRow) { EnsureVisible(pRow); } m_nEnsureVisibleRowIdx = -1; } if (m_nEnsureVisibleColumnIdx >= 0) { EnsureVisible(GetColumns()->GetAt(m_nEnsureVisibleColumnIdx)); m_nEnsureVisibleColumnIdx = -1; } // start counting drawing time #ifdef XTP_DEBUG LARGE_INTEGER iStartCount; QueryPerformanceCounter(&iStartCount); #endif if (m_bDoubleBuffering) { // Update cached bitmap if (m_nLockUpdateCount == 0 && (IsChanged() || NULL == m_bmpCache.GetSafeHandle())) { m_bmpCache.DeleteObject(); CDC memDC; if (memDC.CreateCompatibleDC(&dc)) { if (m_bmpCache.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height())) { CBitmap *pOldBitmap = memDC.SelectObject(&m_bmpCache); Paint(&memDC); memDC.SelectObject(pOldBitmap); } } } } // Draw cached bitmap if available if (NULL != m_bmpCache.GetSafeHandle()) { CXTPCompatibleDC memDC(&dc, &m_bmpCache); dc.BitBlt(0, 0, rcClient.right, rcClient.bottom, &memDC, 0, 0, SRCCOPY); } // Draw directly to device context else { Paint(&dc); } // count drawing time #ifdef XTP_DEBUG LARGE_INTEGER iEndCount; QueryPerformanceCounter(&iEndCount); XTP_TRACE(_T("Draw counter ticks: %d\n"), iEndCount.LowPart-iStartCount.LowPart); #endif } void CXTPReportControl::DrawWatermark(CDC *pDC, CRect rcWatermark, CRect rcClient) { if (m_hbmpWatermark) { CRect rcDst(rcWatermark); CRect rcSrc(0, 0, m_bmWatermark.bmWidth, m_bmWatermark.bmHeight); // no stretch if (!(GetWatermarkAlignment() & xtpReportWatermarkStretch)) { if (rcSrc.Width() > rcDst.Width()) { rcSrc.right = rcSrc.left + rcDst.Width(); } else { rcDst.right = rcDst.left + rcSrc.Width(); } if (rcSrc.Height() > rcDst.Height()) { rcSrc.bottom = rcSrc.top + rcDst.Height(); } else { rcDst.bottom = rcDst.top + rcSrc.Height(); } } // enlarge only if ((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkEnlargeOnly)) { if (rcSrc.Width() > rcDst.Width()) { rcSrc.right = rcSrc.left + rcDst.Width(); } if (rcSrc.Height() > rcDst.Height()) { rcSrc.bottom = rcSrc.top + rcDst.Height(); } } // shrink only if ((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkShrinkOnly)) { if (rcSrc.Width() < rcDst.Width()) { rcDst.right = rcDst.left + rcSrc.Width(); } if (rcSrc.Height() < rcDst.Height()) { rcDst.bottom = rcDst.top + rcSrc.Height(); } } // preserve aspect ratio if ((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkPreserveRatio)) { if (rcDst.Width() > (rcDst.Height() * rcSrc.Width() / rcSrc.Height())) { rcDst.right = rcDst.left + rcDst.Height() * rcSrc.Width() / rcSrc.Height(); } if (rcDst.Height() > (rcDst.Width() * rcSrc.Height() / rcSrc.Width())) { rcDst.bottom = rcDst.top + rcDst.Width() * rcSrc.Height() / rcSrc.Width(); } } // horizontal switch (GetWatermarkAlignment() & xtpReportWatermarkHmask) { // center case xtpReportWatermarkCenter : rcDst.OffsetRect((rcWatermark.Width() - rcDst.Width()) / 2, 0); break; // right case xtpReportWatermarkRight : rcDst.OffsetRect(rcWatermark.Width() - rcDst.Width(), 0); break; // left default : break; } // vertical switch (GetWatermarkAlignment() & xtpReportWatermarkVmask) { // center case xtpReportWatermarkVCenter : rcDst.OffsetRect(0, (rcWatermark.Height() - rcDst.Height()) / 2); break; // bottom case xtpReportWatermarkBottom: rcDst.OffsetRect(0, rcWatermark.Height() - rcDst.Height()); break; // top default : break; } CXTPCompatibleDC memWatermarkDC(pDC, m_hbmpWatermark); if (GetWatermarkAlignment() & xtpReportWatermarkStretch) { CBitmap bmpWatermark; bmpWatermark.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height()); CXTPCompatibleDC dcWatermark(pDC, &bmpWatermark); dcWatermark.FillSolidRect(&rcClient, RGB(255, 255, 255)); dcWatermark.SetStretchBltMode(HALFTONE); dcWatermark.StretchBlt(rcDst.left, rcDst.top, rcDst.Width(), rcDst.Height(), &memWatermarkDC, 0, 0, rcSrc.Width(), rcSrc.Height(), SRCCOPY); XTPImageManager()->AlphaBlend2(*pDC, rcClient, dcWatermark, rcClient, m_WatermarkTransparency); } else { XTPImageManager()->AlphaBlend2(*pDC, rcDst, memWatermarkDC, rcSrc, m_WatermarkTransparency); } } } LRESULT CXTPReportControl::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/) { CDC* pDC = CDC::FromHandle((HDC)wParam); if (pDC) { if (m_bmpCache.GetSafeHandle() == 0) OnDraw(pDC); else { CXTPCompatibleDC memDC(pDC, &m_bmpCache); CXTPClientRect rc(this); pDC->BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY); } } return TRUE; } BOOL CXTPReportControl::OnEraseBkgnd(CDC *pDC) { UNREFERENCED_PARAMETER(pDC); return TRUE; // Don't erase the background. } void CXTPReportControl::OnDraw(CDC *pDC) { CXTPClientRect rcClient(this); pDC->SetBkMode(TRANSPARENT); if (GetExStyle() & WS_EX_RTLREADING) { pDC->SetTextAlign(TA_RTLREADING); } // Fill background pDC->FillSolidRect(rcClient, GetPaintManager()->GetControlBackColor(this)); // Draw watermark DrawWatermark(pDC, m_pSections->GetRect(), rcClient); // Draw header CXTPReportHeader *pHeader = GetReportHeader(); if (NULL != pHeader) { CRect rcHeader = m_rcHeaderArea; rcHeader.right = rcHeader.left + pHeader->GetWidth(); pHeader->Draw(pDC, rcHeader, m_nScrollOffsetH); // draw header pHeader->DrawGroupByControl(pDC, m_rcGroupByArea); // draw group by box } if (m_bIconView) { DrawIconView(pDC, m_pSectionBody->m_rcSection); } else { m_pSections->Draw(pDC); } CRect rcFooter = m_rcFooterArea; if (rcFooter.Height() > 0) pHeader->DrawFooter(pDC, rcFooter, m_nScrollOffsetH); BOOL bForce(FALSE); BOOL bDrawBetween = FALSE; int yForce(-1); if (m_bDragMode && GetPaintManager() && !IsIconView()) { bForce = GetPaintManager()->m_bForceShowDropMarker; CPoint ptMouse; if (::GetCursorPos(&ptMouse)) { ScreenToClient(&ptMouse); EnsureStartAutoVertScroll(); if (m_dwDropMarkerFlags & xtpReportDropBetween) { CXTPReportRow* pHitRow = HitTest(ptMouse); if (pHitRow && pHitRow->GetRecord()) { if(bForce || !(m_dwDropMarkerFlags & xtpReportDropSelect) || (m_pSelectedRows->GetCount() == 0 && (ptMouse.y <= (pHitRow->GetRect().top + 4) || ptMouse.y >= (pHitRow->GetRect().bottom - 4)))) { bDrawBetween = TRUE; BOOL bAbove = TRUE; if (pHitRow->GetRect().CenterPoint().y < ptMouse.y) bAbove = FALSE; if (bAbove) yForce = pHitRow->GetRect().top - 1; else yForce = pHitRow->GetRect().bottom - 1; } } } } } if (bDrawBetween) { if (m_nDropPos != -1 && GetPaintManager()->m_bUseDropMarker) { DrawDropMarker(pDC); } else if (bForce && yForce > 0 && GetPaintManager()->m_bUseDropMarker) { DrawExtDropMarker(pDC, yForce); } } // update flag SetChanged(FALSE); } void CXTPReportControl::DrawDropMarker(CDC *pDC) { if (m_nDropPos == 0 && GetRows()->GetCount() == 0) { m_nDropPos = m_pSectionBody->m_rcSection.top; } else if (m_nDropPos < m_pSectionBody->m_rcSection.top - 1 || m_nDropPos > m_pSectionBody->m_rcSection.bottom) { return; } CRect rc(m_pSectionBody->m_rcSection.left, m_nDropPos, m_pSectionBody->m_rcSection.right, m_nDropPos + 1); pDC->FillSolidRect(rc, GetPaintManager()->m_clrHotDivider); CXTPPenDC pen(*pDC, GetPaintManager()->m_clrHotDivider); CXTPBrushDC brush(*pDC, GetPaintManager()->m_clrHotDivider); int x = rc.left; int y = m_nDropPos; POINT ptsLeftArrow[] = { {x, y - 2}, {x + 2, y - 2}, {x + 2, y - 5}, {x + 7, y }, {x + 2, y + 5}, {x + 2, y + 2}, {x, y + 2} }; pDC->Polygon(ptsLeftArrow, 7); x = rc.right - 1; POINT ptsRightArrow[] = { {x, y - 2}, {x - 2, y - 2}, {x - 2, y - 5}, {x - 7, y }, {x - 2, y + 5}, {x - 2, y + 2}, {x, y + 2} }; pDC->Polygon(ptsRightArrow, 7); } void CXTPReportControl::DrawExtDropMarker(CDC* pDC, int y) { CRect rc(m_pSectionBody->m_rcSection.left, y, m_pSectionBody->m_rcSection.right, y + 1); pDC->FillSolidRect(rc, GetPaintManager()->m_clrHotDivider); CXTPPenDC pen(*pDC, GetPaintManager()->m_clrHotDivider); CXTPBrushDC brush(*pDC, GetPaintManager()->m_clrHotDivider); int x = rc.left; POINT ptsLeftArrow[] = { {x, y - 2}, {x + 2, y - 2}, {x + 2, y - 5}, {x + 7, y}, {x + 2, y + 5}, {x + 2, y + 2}, {x, y + 2} }; pDC->Polygon(ptsLeftArrow, 7); x = rc.right - 1; POINT ptsRightArrow[] = { {x, y - 2}, {x - 2, y - 2}, {x - 2, y - 5}, {x - 7, y}, {x - 2, y + 5}, {x - 2, y + 2}, {x, y + 2} }; pDC->Polygon(ptsRightArrow, 7); } BOOL CXTPReportControl::Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID, CCreateContext *pContext) { return CXTPReportControl::Create(XTPREPORTCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext); } BOOL CXTPReportControl::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID, CCreateContext *pContext) { m_bCreated = TRUE; return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); } void CXTPReportControl::PreSubclassWindow() { CWnd::PreSubclassWindow(); // DDX_Control subclasses the window and OnCreate and OnSize will not be called if (!m_bCreated) { AdjustLayout(); AdjustScrollBars(); } } int CXTPReportControl::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (0 != CWnd::OnCreate(lpCreateStruct)) { // CWnd creation failed return -1; } return 0; } void CXTPReportControl::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); BeginUpdate(); EditItem(NULL); AdjustLayout(); AdjustScrollBars(); EndUpdate(); } ///////////////////////////////////////////////////////////////////////////// // Left button ///////////////////////////////////////////////////////////////////////////// void CXTPReportControl::OnButton(UINT nFlags, CPoint point, CXTPReportBehaviorRowMouseButton* pBehavior) { UNREFERENCED_PARAMETER(nFlags); XTPReportInputState inputState; // Get input states inputState.ptMouse = point; inputState.bKeyControl = (::GetKeyState(VK_CONTROL) < 0) || m_bMultiSelectionMode; inputState.bKeyShift = (::GetKeyState(VK_SHIFT) < 0); inputState.nRow = -1; inputState.bSelected = FALSE; // Click arguments XTP_REPORTRECORDITEM_CLICKARGS clickArgs; clickArgs.pControl = this; clickArgs.ptClient = point; clickArgs.pColumn = NULL; clickArgs.pRow = NULL; clickArgs.pItem = NULL; // Find clicked row clickArgs.pRow = HitTest(point); CXTPSmartPtrInternalT ptrRowLock(clickArgs.pRow, TRUE); if (NULL != clickArgs.pRow) { inputState.nRow = clickArgs.pRow->GetIndex(); inputState.bSelected = clickArgs.pRow->IsSelected(); // Find clicked item and column clickArgs.pItem = clickArgs.pRow->HitTest(point, &clickArgs.rcItem, &clickArgs.pColumn); } // Store state if (xtpReportMouseEventButtonDown == pBehavior->m_event) { m_mouseDownState = inputState; } CXTPReportBehaviorRowModifier *pModifier = NULL; if (m_mouseDownState.bKeyShift) pModifier = pBehavior->Shift; // Shift else if (m_mouseDownState.bKeyControl) pModifier = pBehavior->Control; // Control else pModifier = pBehavior->None; // No modifier // Current focused row index const int nFocusedRowIndex = _GetFocusedRowIndex(); if (xtpReportMouseEventButtonDown == pBehavior->m_event) { SetFocus(); // If an item is currently edited, this need to be ended first. // EditItem(NULL) sends a XTP_NM_REPORT_VALUECHANGED message // and the user may modify the rows. EditItem(NULL); } // Notify header CXTPReportHeader *pHeader = GetReportHeader(); if (NULL != pHeader) { if (xtpReportMouseButtonLeft == pBehavior->m_button) { if (xtpReportMouseEventButtonDown == pBehavior->m_event) { pHeader->OnLButtonDown(point); } if (xtpReportMouseEventButtonUp == pBehavior->m_event) { pHeader->OnLButtonUp(nFlags, point); } } } if (NULL != clickArgs.pRow) { BOOL bHandled = FALSE; // Notify row if (xtpReportMouseButtonLeft == pBehavior->m_button) { if (xtpReportMouseEventButtonDown == pBehavior->m_event) { bHandled = clickArgs.pRow->OnLButtonDown(&clickArgs); } if (xtpReportMouseEventButtonUp == pBehavior->m_event) { bHandled = clickArgs.pRow->OnLButtonUp(&clickArgs); } } // Notify inplace control if (NULL != clickArgs.pItem) { } if (!bHandled && clickArgs.pRow->GetSection()->IsAllowAccess()) { BeginUpdate(); // Begin drag if (pBehavior->bDragBegin) { m_ptDrag = point; m_bPrepareDrag = TRUE; } // End drag if (pBehavior->bDragEnd) { // Stop dragging m_bPrepareDrag = FALSE; // Stop auto scrolling EnsureStopAutoVertScroll(); } BOOL bKeepSelection = FALSE; BOOL bKeepFocus = FALSE; BOOL bDeferredDeselection = FALSE; BOOL bFocused = TRUE; const BOOL bSelected = clickArgs.pRow->IsSelected(); if (bSelected) { if (pModifier->bKeepSelection) { bKeepSelection = TRUE; } if (pModifier->bKeepFocus) { bKeepFocus = TRUE; } } // Focus column if (pBehavior->bFocusColumn && m_bFocusSubItems) { if (clickArgs.pItem && clickArgs.pItem->IsFocusable()) { bFocused = SetFocusedColumn(clickArgs.pColumn); } else { bFocused = SetFocusedColumn(NULL); } } // Focus row if ((pModifier->bFocusRow || pModifier->bFocusRowTemporarily) && !bKeepFocus) { bFocused = _SetFocusedRow(clickArgs.pRow); } // Deferred deselection if (m_mouseDownState.bKeyControl && m_mouseDownState.bSelected && m_mouseDownState.nRow == clickArgs.pRow->GetIndex() && xtpReportMouseEventButtonUp == pBehavior->m_event) { bDeferredDeselection = TRUE; } // Select row(s) if ((pModifier->bSelectRow && !bKeepSelection) || bDeferredDeselection) { if (pModifier->bMultipleSelection) { _SetSelectedRow(clickArgs.pRow, nFocusedRowIndex, inputState.bKeyShift, inputState.bKeyControl); if (IsSelectionEnabled() && IsMultipleSelection() && !inputState.bKeyShift && inputState.bKeyControl) { m_pSelectedRows->Invert(clickArgs.pRow); } } else { _SetSelectedRow(clickArgs.pRow, nFocusedRowIndex, FALSE, FALSE); } } // Ensure visible if (pBehavior->bEnsureVisible) { EnsureVisible(clickArgs.pRow); } // Row click if (pBehavior->bClick) { clickArgs.pRow->OnClick(point); if (pBehavior->bCheckSelectedRows && clickArgs.pItem) { SetSelectionState(clickArgs.pItem->GetIndex(), clickArgs.pItem->GetCheckedState()); } } EndUpdate(); } // !bHandled } else if (m_bFastDeselectMode) { if (!inputState.bKeyControl && !inputState.bKeyShift) { m_pSelectedRows->Clear(); } } // Context menu if (pBehavior->bContextMenu) { if (NULL != m_pSections->HitTest(point)) { CXTPReportColumn *pColumn = NULL; CXTPReportRecordItem *pItem = NULL; if (NULL != clickArgs.pRow) { //clickArgs.pRow->HitTest(point, NULL, &pColumn); clickArgs.pRow->OnContextMenu(point); } else { ClientToScreen(&point); SendMessageToParent(clickArgs.pRow, pItem, pColumn, NM_RCLICK, &point); } } } // Restore focus if (pModifier->bFocusRowTemporarily) { CXTPReportRow *pRow = NULL; pRow = GetRows()->GetAt(nFocusedRowIndex); BeginUpdate(); _SetFocusedRow(pRow); EndUpdate(); } if (m_pSelectedRows->IsChanged()) { //TRACE(_T("OnSelectionChanged\n")); OnSelectionChanged(); } } void CXTPReportControl::OnLButtonDown(UINT nFlags, CPoint point) { CWnd::OnLButtonDown(nFlags, point); m_dwLastMouseMessage = WM_LBUTTONDOWN; OnButton(nFlags, point, m_pBehavior->Row->MouseDown->Left); } void CXTPReportControl::OnLButtonUp(UINT nFlags, CPoint point) { //TRACE(_T("CXTPReportControl::OnLButtonUp\n")); CWnd::OnLButtonUp(nFlags, point); /* The Windows window manager sends an unwanted WM_LBUTTONDOWN message if the window is maximized with a double-click on the caption bar. Window messages for double-click: - WM_LBUTTONDOWN - WM_LBUTTONUP - WM_LBUTTONDBLCLK - WM_LBUTTONUP */ if (WM_LBUTTONDOWN == m_dwLastMouseMessage || WM_LBUTTONDBLCLK == m_dwLastMouseMessage || xtpReportMouseNothing != GetMouseMode()) { m_dwLastMouseMessage = WM_LBUTTONUP; OnButton(nFlags, point, m_pBehavior->Row->MouseUp->Left); } } void CXTPReportControl::OnLButtonDblClk(UINT nFlags, CPoint ptDblClick) { CWnd::OnLButtonDblClk(nFlags, ptDblClick); m_dwLastMouseMessage = WM_LBUTTONDBLCLK; EditItem(NULL); // Information for delay editing EnsureStopDelayEditTimer(); SetLastRqstEdit(-1, -1); // columns processing CXTPReportHeader *pHeader = GetReportHeader(); if (NULL != pHeader) { pHeader->OnLButtonDblClk(ptDblClick); } // rows processing CXTPReportRow *pRow = HitTest(ptDblClick); if (NULL != pRow) { pRow->OnDblClick(ptDblClick); } else // just notify parent { SendMessageToParent(NULL, NULL, NULL, NM_DBLCLK, &ptDblClick); } } ///////////////////////////////////////////////////////////////////////////// // Right button ///////////////////////////////////////////////////////////////////////////// void CXTPReportControl::OnRButtonDown(UINT nFlags, CPoint point) { CWnd::OnRButtonDown(nFlags, point); OnButton(nFlags, point, m_pBehavior->Row->MouseDown->Right); } void CXTPReportControl::OnRButtonUp(UINT nFlags, CPoint point) { CWnd::OnRButtonUp(nFlags, point); if (!IsWindow(m_hWnd)) // Can be destroyed in WM_CONTEXTMENU return; OnButton(nFlags, point, m_pBehavior->Row->MouseUp->Right); } LRESULT CXTPReportControl::OnNcHitTest(CPoint point) { LRESULT ht = CWnd::OnNcHitTest(point); if (ht != HTCLIENT) return ht; DWORD dwStyle = GetStyle(); if ((dwStyle & (WS_VSCROLL | WS_HSCROLL)) == 0) return ht; CXTPWindowRect rcWindow(this); if (dwStyle & WS_VSCROLL) { if (IsLayoutRTL() || !!(GetWindowLong(m_hWnd, GWL_EXSTYLE) & WS_EX_LEFTSCROLLBAR)) { CRect rc(rcWindow.left, rcWindow.top, GetSystemMetrics(SM_CXVSCROLL), rcWindow.bottom - (dwStyle & WS_HSCROLL ? GetSystemMetrics(SM_CYHSCROLL) : 0)); if (rc.PtInRect(point)) return HTVSCROLL; } else { CRect rc(rcWindow.right- GetSystemMetrics(SM_CXVSCROLL), rcWindow.top, rcWindow.right, rcWindow.bottom - (dwStyle & WS_HSCROLL ? GetSystemMetrics(SM_CYHSCROLL) : 0)); if (rc.PtInRect(point)) return HTVSCROLL; } } if (dwStyle & WS_HSCROLL) { CRect rc(rcWindow.left, rcWindow.bottom - GetSystemMetrics(SM_CYHSCROLL), rcWindow.right - (dwStyle & WS_VSCROLL ? GetSystemMetrics(SM_CXVSCROLL) : 0), rcWindow.bottom); if (rc.PtInRect(point)) return HTHSCROLL; } return ht; } void CXTPReportControl::OnContextMenu(CWnd *pWnd, CPoint pos) { UNREFERENCED_PARAMETER(pWnd); if (GetMouseMode() != xtpReportMouseNothing) return; CPoint ptClient = pos; ScreenToClient(&ptClient); // call context menu handler for report header if clicked inside if (m_rcHeaderArea.PtInRect(ptClient) || m_rcGroupByArea.PtInRect(ptClient)) { CXTPReportHeader *pHeader = GetReportHeader(); if (pHeader) pHeader->OnContextMenu(ptClient); return; } // Context menu key if (pos == CPoint(-1, -1)) { CXTPReportRow *pFocusedRow = GetFocusedRow(); if (pFocusedRow) { // Menu position below row ptClient = CPoint( pFocusedRow->GetRect().left, pFocusedRow->GetRect().bottom ); pFocusedRow->OnContextMenu(ptClient); } else { pos = m_pSectionBody->m_rcSection.TopLeft(); ClientToScreen(&pos); SendMessageToParent(NULL, NULL, NULL, NM_RCLICK, &pos); } } } CXTPReportColumn* CXTPReportControl::GetNextFocusableColumn(CXTPReportRow* pRow, int nColumnIndex, int nDirection) { if (!pRow->GetRecord()) return NULL; for (;;) { CXTPReportColumn* pColumn = GetReportHeader()->GetNextVisibleColumn(nColumnIndex, nDirection); if (!pColumn) return NULL; CXTPReportRecordItem* pItem = pRow->GetRecord()->GetItem(pColumn); if (pItem && pItem->IsFocusable()) return pColumn; nColumnIndex = pColumn->GetIndex(); } } BOOL CXTPReportControl::OnPreviewKeyDown(UINT& rnChar, UINT nRepCnt, UINT nFlags) { XTP_NM_REPORTPREVIEWKEYDOWN nmParams; ::ZeroMemory(&nmParams, sizeof(nmParams)); nmParams.nChar = rnChar; nmParams.nRepCnt = nRepCnt; nmParams.nFlags = nFlags; nmParams.bCancel = FALSE; SendNotifyMessage(XTP_NM_REPORT_PREVIEWKEYDOWN, (NMHDR*)&nmParams); rnChar = nmParams.nChar; return !nmParams.bCancel; } void CXTPReportControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CWnd::OnKeyDown(nChar, nRepCnt, nFlags); BOOL bControlKeyOnly = (::GetKeyState(VK_CONTROL) < 0); BOOL bControlKey = (::GetKeyState(VK_CONTROL) < 0) || m_bMultiSelectionMode; BOOL bShiftKey = (::GetKeyState(VK_SHIFT) < 0); CXTPReportRow* pFocusedRow = GetFocusedRow(); CXTPDrawHelpers::KeyToLayout(this, nChar); int nRows = GetRows()->GetCount(); int nHeadRows = GetHeaderRows()->GetCount(); int nFootRows = GetFooterRows()->GetCount(); // Increase reference Count for pFocusedRow to be sure it won't be destroyed inside function. CXTPSmartPtrInternalT ptrRowLock(pFocusedRow, TRUE); if (nRows > 0 || nHeadRows > 0 || nFootRows > 0) switch (nChar) { case VK_F5: Recalc(bShiftKey); break; case VK_ADD: { if (bControlKeyOnly) { if (!IsLockExpand()) { ExpandAll(); } } else if ( pFocusedRow && pFocusedRow->HasChildren() && !pFocusedRow->IsExpanded() && !pFocusedRow->IsLockExpand()) { pFocusedRow->SetExpanded(TRUE); } } break; case VK_SUBTRACT: { if (bControlKeyOnly) { if (!IsLockExpand()) { CollapseAll(); } } else if ( pFocusedRow && pFocusedRow->HasChildren() && pFocusedRow->IsExpanded() && !pFocusedRow->IsLockExpand()) { pFocusedRow->SetExpanded(FALSE); } } break; case VK_LEFT: if (m_bIconView) { GetNavigator()->MoveLeft(bShiftKey, bControlKey); } else { /** [0] if FocusSubItems we need check first if we can move one column left. if not - "fall down" for cases [1][2][3] [1] If a row without children has the focus, focus shall be put on the parent row [2] If a row with expanded children has the focus, children shall be collapsed [3] If a row with collapsed children has the focus, focus shall be put on the parent row */ if (pFocusedRow) { if (m_bFocusSubItems && m_pFocusedColumn) { CXTPReportColumn* pColumn = GetNextFocusableColumn(pFocusedRow, m_pFocusedColumn->GetIndex(), -1); if (pColumn) { SetFocusedColumn(pColumn); SetFocusedRow(GetFocusedRow()); break; } } /* [1], Row without children */ if (!pFocusedRow->HasChildren()) { CXTPReportRow *pParent = pFocusedRow->GetParentRow(); if (NULL != pParent) { SetFocusedRow(pParent); } else { GetNavigator()->MoveUp(bShiftKey, bControlKey); } } /* [2][3] Row with children */ else // if (pFocusedRow->HasChildren()) { /* [2] Row with expanded children */ if (pFocusedRow->IsExpanded()) { if (!pFocusedRow->IsLockExpand()) { pFocusedRow->SetExpanded(FALSE); } else { GetNavigator()->MoveUp(bShiftKey, bControlKey); } } /* [3] Row with collapsed children */ else { CXTPReportRow* pParent = pFocusedRow->GetParentRow(); // if we don't have parent just go up, like Outlook. if (NULL != pParent) { SetFocusedRow(pParent); } else { GetNavigator()->MoveUp(bShiftKey, bControlKey); } } } } } break; case VK_RIGHT: if (m_bIconView) { GetNavigator()->MoveRight(bShiftKey, bControlKey); break; } else { /** [0] if FocusSubItems we need check first if we can move one column right. if not - "fall down" for cases [1][2][3] [1] If a row with expanded children has the focus, focus shall be put on first children [2] If a row with collapsed children has the focus, children shall be expanded [3] If a row with no children has the focus, we go down like Outlook */ if (pFocusedRow) { if (m_bFocusSubItems && m_pFocusedColumn) { CXTPReportColumn* pColumn = GetNextFocusableColumn(pFocusedRow, m_pFocusedColumn->GetIndex(), +1); if (pColumn) { SetFocusedColumn(pColumn); SetFocusedRow(GetFocusedRow()); break; } } if (pFocusedRow->HasChildren()) { /* [1] Row with expanded children */ if (pFocusedRow->IsExpanded()) { CXTPReportRows *pChildRows = pFocusedRow->GetChilds(); CXTPReportRow *pChildRow = pChildRows->GetAt(0); SetFocusedRow(pChildRow); } /* [2] Row with collapsed children */ else { if (!pFocusedRow->IsLockExpand()) { pFocusedRow->SetExpanded(TRUE, bControlKeyOnly); } else { GetNavigator()->MoveDown(bShiftKey, bControlKey); } } } else { GetNavigator()->MoveDown(bShiftKey, bControlKey); } } } break; case VK_DOWN: GetNavigator()->MoveDown(bShiftKey, bControlKey); break; case VK_UP: GetNavigator()->MoveUp(bShiftKey, bControlKey); break; case VK_HOME: GetNavigator()->MoveFirstRow(bShiftKey, FALSE); break; case VK_END: GetNavigator()->MoveLastRow(bShiftKey, FALSE); break; case VK_NEXT: GetNavigator()->MovePageDown(bShiftKey, FALSE); break; case VK_PRIOR: GetNavigator()->MovePageUp(bShiftKey, FALSE); break; case VK_RETURN: if (pFocusedRow && pFocusedRow->HasChildren() && !pFocusedRow->IsLockExpand()) { pFocusedRow->SetExpanded(!pFocusedRow->IsExpanded()); } break; case VK_ESCAPE: if (m_mouseMode != xtpReportMouseNothing) GetReportHeader()->CancelMouseMode(); break; case VK_F2: GetNavigator()->BeginEdit(); break; case VK_SPACE: if (IsSelectionEnabled() && bControlKey && pFocusedRow) { if (pFocusedRow->IsSelected()) m_pSelectedRows->Remove(pFocusedRow); else m_pSelectedRows->Add(pFocusedRow); OnSelectionChanged(); //OnSelectionChanged set Selection flag m_bChanged = FALSE; } break; case 'A': if (IsSelectionEnabled() && !bShiftKey && bControlKeyOnly && IsMultipleSelection()) { if (IsVirtualMode()) { GetNavigator()->MoveToRow(0); GetNavigator()->MoveToRow(GetRecords()->GetCount() - 1, TRUE); } else { _SelectRows(GetRecords()); } RedrawControl(); } break; } NMKEY nmgv; nmgv.nVKey = nChar; nmgv.uFlags = nFlags; SendNotifyMessage(NM_KEYDOWN, (NMHDR*)&nmgv); } //ICON_VIEW_MODE RELATED << void CXTPReportControl::SetNavigator(CXTPReportNavigator* pNavigator) { if (pNavigator) { CMDTARGET_RELEASE(m_pNavigator); m_pNavigator = pNavigator; } } void CXTPReportControl::SetIconViewToDefaults() { m_bIconView = FALSE; m_iIconWidth = 0; m_iIconHeight = 0; m_iIconWidthSpacing = 0; m_iIconHeightSpacing = 0; m_iIconViewColumn = -1; m_iIconViewRowsPerLine = 0; m_bUseIconColumnForNum = FALSE; m_iColumnForNum = -1; m_bPrevFocusSubItems = FALSE; m_bPrevHeaderAutoSize = FALSE; m_iIconPropNum = 0; m_iIconNum = 0; m_pPrevVisible = NULL; m_pPrevGroupsOrder = NULL; m_nPrevTreeIndent = 0; m_bIconColumnIndexNotValid = FALSE; m_bPrevHeaderRows = FALSE; m_bPrevFooterRows = FALSE; m_bPrevHeaderShow = FALSE; m_bPrevFooterShow = FALSE; m_bRClickDrag = FALSE; } void CXTPReportControl::SetIconColumn(CXTPReportColumn* pColumn) { ASSERT(pColumn); m_iIconViewColumn = pColumn ? pColumn->GetItemIndex() : -1; } void CXTPReportControl::CreateIconColumn(BOOL bUseColumnForNum, int nWidth) { if (GetColumns()) { if (!m_bUseIconColumnForNum) m_bUseIconColumnForNum = bUseColumnForNum; if (m_iIconViewColumn == -1) { int iCnt = GetColumns()->GetCount(); if (GetRecords()) { int iCnt0 = iCnt; if (GetRecords()->GetAt(0)) iCnt = max(iCnt, GetRecords()->GetAt(0)->GetItemCount()); if (iCnt > iCnt0) for (int iIc = 0; iIc < iCnt - iCnt0; iIc++) AddColumn(new CXTPReportColumn(iIc,_T(""), 0, FALSE,XTP_REPORT_NOICON,FALSE,FALSE)); } CXTPReportColumn* pIconCol = AddColumn(new CXTPReportColumn(iCnt, _T(""), 0)); pIconCol->SetVisible(FALSE); if (m_bUseIconColumnForNum) { pIconCol->SetCaption(_T("#")); pIconCol->SetVisible(TRUE); pIconCol->SetHeaderAlignment(DT_CENTER); pIconCol->SetWidth(nWidth); if (GetColumns()->GetGroupsOrder()->GetCount() > 0 && nWidth < 30) nWidth = 30; GetPaintManager()->m_RecordNumberWidth = nWidth; pIconCol->AllowRemove(FALSE); pIconCol->EnableResize(FALSE); //pIconCol->SetAutoSize(FALSE); pIconCol->SetAllowDrag(FALSE); pIconCol->SetEditable(FALSE); pIconCol->SetGroupable(FALSE); pIconCol->SetSortable(FALSE); } m_iIconViewColumn = pIconCol->GetIndex(); m_iColumnForNum = m_iIconViewColumn; } } } void CXTPReportControl::AssignIconViewPropNumAndIconNum(int nCol, int nIcon, BOOL bUseColumnForNum, int nWidth) { BOOL bAlreadyUsed = m_bUseIconColumnForNum; m_bIconColumnIndexNotValid = TRUE; CreateIconColumn(bUseColumnForNum, nWidth); m_bIconColumnIndexNotValid = FALSE; if (!bAlreadyUsed && bUseColumnForNum) { m_bUseIconColumnForNum = bUseColumnForNum; if (m_iIconViewColumn > -1) { CXTPReportColumn* pIconCol = GetColumns()->GetAt(m_iIconViewColumn); if (m_bUseIconColumnForNum) { pIconCol->SetCaption(_T("#")); pIconCol->SetVisible(TRUE); pIconCol->SetHeaderAlignment(DT_CENTER); pIconCol->SetWidth(nWidth); if (GetColumns()->GetGroupsOrder()->GetCount() > 0 && nWidth < 30) nWidth = 30; GetPaintManager()->m_RecordNumberWidth = nWidth; pIconCol->AllowRemove(FALSE); pIconCol->EnableResize(FALSE); pIconCol->SetEditable(FALSE); pIconCol->SetGroupable(FALSE); pIconCol->SetSortable(FALSE); } } } if (nCol > -1) m_iIconPropNum = nCol; if (nIcon > -1) m_iIconNum = nIcon; if (!bAlreadyUsed && m_iColumnForNum > -1 && bUseColumnForNum) GetColumns()->ChangeColumnOrder(0, m_iColumnForNum); } //ICON_VIEW_MODE RELATED >> void CXTPReportControl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags); } void CXTPReportControl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { m_bWasShiftKey = (GetKeyState(VK_SHIFT) < 0); CWnd::OnKeyUp(nChar, nRepCnt, nFlags); } void CXTPReportControl::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { CWnd::OnSysKeyUp(nChar, nRepCnt, nFlags); } void CXTPReportControl::OnChar(UINT nChar, UINT nRepCntr, UINT nFlags) { NMCHAR nmgv; ZeroMemory(&nmgv, sizeof(NMCHAR)); nmgv.ch = nChar; SendNotifyMessage(NM_CHAR, (NMHDR*)&nmgv); CXTPReportRow* pFocusedRow = GetFocusedRow(); if (pFocusedRow && (nChar == VK_TAB)) { if (m_bFocusSubItems) { CXTPSmartPtrInternalT ptrRowLock(pFocusedRow, TRUE); EditItem(NULL); BOOL bBack = (GetKeyState(VK_SHIFT) < 0); GetNavigator()->MoveLeftRight(bBack); if (IsAllowEdit() && m_bEditOnClick && !m_bTrapTabKey) { GetNavigator()->BeginEdit(); } } return; } if (m_pFocusedColumn && pFocusedRow && pFocusedRow->GetRecord() && (nChar != VK_RETURN) && (nChar != VK_ESCAPE)) { XTP_REPORTRECORDITEM_ARGS itemArgs(this, pFocusedRow, m_pFocusedColumn); if (itemArgs.pItem && itemArgs.pItem->OnChar(&itemArgs, nChar)) return; } CWnd::OnChar(nChar, nRepCntr, nFlags); } void CXTPReportControl::OnCaptureChanged(CWnd* pWnd) { if (m_mouseMode != xtpReportMouseNothing) GetReportHeader()->CancelMouseMode(); CWnd::OnCaptureChanged(pWnd); } void CXTPReportControl::OnEnable(BOOL bEnable) { UNREFERENCED_PARAMETER(bEnable); AdjustScrollBars(); } UINT CXTPReportControl::GetMouseScrollLines() { UINT nScrollLines = 3; // default value if (XTPSystemVersion()->IsWin95()) { HKEY hKey; if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE, &hKey)) { TCHAR szData[128]; DWORD dwKeyDataType; DWORD dwDataBufSize = sizeof(szData); if (ERROR_SUCCESS == ::RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType, (LPBYTE) &szData, &dwDataBufSize)) { nScrollLines = _tcstoul(szData, NULL, 10); } ::RegCloseKey(hKey); } } // win98 or greater else { ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0); } return nScrollLines; } BOOL CXTPReportControl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { if (!m_bVScrollBarVisible) return CWnd::OnMouseWheel(nFlags, zDelta, pt); UINT uiMsg; int nScrollsCount = 0; // calculate what should be sent if (m_nRowsPerWheel == -1) { // A m_nRowsPerWheel value less than 0 indicates that the mouse wheel scrolls whole pages, not just lines. int nPagesScrolled = zDelta / 120; uiMsg = nPagesScrolled > 0 ? SB_PAGEUP : SB_PAGEDOWN; nScrollsCount = nPagesScrolled > 0 ? nPagesScrolled : -nPagesScrolled; } else { int nRowsScrolled = m_nRowsPerWheel * zDelta / 120; uiMsg = nRowsScrolled > 0 ? SB_LINEUP : SB_LINEDOWN; nScrollsCount = nRowsScrolled > 0 ? nRowsScrolled : -nRowsScrolled; } BeginUpdate(); // send scroll messages for (int i = 0; i < nScrollsCount; i++) { OnVScroll(uiMsg, 0, NULL); } EndUpdate(); UpdateWindow(); return CWnd::OnMouseWheel(nFlags, zDelta, pt); } void CXTPReportControl::OnMouseLeave() { OnMouseMove(0, CPoint(-1, -1)); } void CXTPReportControl::OnMouseMove(UINT nFlags, CPoint point) { CWnd::OnMouseMove(nFlags, point); CXTPReportHeader *pHeader = GetReportHeader(); CXTPReportColumn *pColumn = NULL; CXTPReportRow *pRow = NULL; CXTPReportRecordItem *pItem = NULL; if (NULL != pHeader) { pHeader->OnMouseMove(nFlags, point); } CXTPReportRow* pHotExpandButtonRow = NULL; CXTPReportHyperlink *pHotHyperlink = NULL; if (GetMouseMode() == xtpReportMouseNothing) { pRow = HitTest(point); if (NULL != pRow) { pRow->OnMouseMove(nFlags, point); // Hyperlink hit test pItem = pRow->HitTest(point); if (NULL != pItem) { pColumn = pItem->GetColumn(); int nHyperlink = pItem->HitTestHyperlink(point); if (nHyperlink >= 0) { pHotHyperlink = pItem->GetHyperlinks()->GetAt(nHyperlink); } } if (m_bShowTooltips && nFlags == 0) { pRow->ShowToolTip(point, m_pTip); } } if (pRow && pRow->IsGroupRow() && m_pPaintManager->m_columnStyle == xtpReportColumnResource) { if (pRow->m_rcCollapse.PtInRect(point)) { pHotExpandButtonRow = pRow; } } if (m_pHotRow != pRow) { TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, GetSafeHwnd(), 0 }; _TrackMouseEvent (&tme); m_pHotRow = pRow; } // If mouse moved some since down... if (m_bPrepareDrag && (labs (point.x - m_ptDrag.x) > 3 || labs (point.y - m_ptDrag.y) > 3)) { // Prevent duplicate m_bPrepareDrag = FALSE; // Begin a drag operation OnBeginDrag(m_ptDrag, nFlags); } } if (m_pHotHyperlink != pHotHyperlink) { m_pHotHyperlink = pHotHyperlink; RedrawControl(); } if (m_pHotExpandButtonRow != pHotExpandButtonRow) { m_pHotExpandButtonRow = pHotExpandButtonRow; RedrawControl(); } SendMessageToParent(pRow, pItem, pColumn, XTP_NM_REPORT_MOUSEMOVE, &point); } class CXTPReportDropSource : public COleDropSource { public: CXTPReportDropSource(CXTPReportControl *pControl) : m_pControl(pControl) { } virtual SCODE GiveFeedback(DROPEFFECT dropEffect) { SCODE sCode = NOERROR; XTP_NM_REPORTGIVEFEEDBACK giveFeedback; giveFeedback.dropEffect = dropEffect; giveFeedback.bDragStarted = m_bDragStarted; LRESULT lResult = m_pControl->SendNotifyMessage(XTP_NM_REPORT_GIVEFEEDBACK, &giveFeedback); if (0 != lResult) { sCode = S_OK; } else { sCode = COleDropSource::GiveFeedback(dropEffect); } return sCode; } protected: CXTPReportControl *m_pControl; }; void CXTPReportControl::OnBeginDrag(CPoint point) { OnBeginDrag(point, 0); } void CXTPReportControl::OnBeginDrag(CPoint point, UINT nFlags) { if (SendMessageToParent(NULL, NULL, NULL, LVN_BEGINDRAG, &point)) return; //R-DD << if ((nFlags & MK_RBUTTON) && SendMessageToParent(NULL, NULL, NULL, LVN_BEGINRDRAG, &point)) return; //R-DD >> if (m_cfReport == NULL) return; CXTPReportSelectedRows* pSelectedRows = GetSelectedRows(); if (!pSelectedRows) return; if ((m_dwDragDropFlags & xtpReportAllowDrag) == 0) return; if (pSelectedRows->m_nRowType == xtpRowTypeHeader || pSelectedRows->m_nRowType == xtpRowTypeFooter) return; int nCount = pSelectedRows->GetCount(); for (int i = nCount - 1; i >= 0; i--) { CXTPReportRow* pRow = pSelectedRows->GetAt(i); if (pRow->IsGroupRow()) { pRow->SetExpanded(TRUE); pRow->SelectChilds(); } } int nRowsCount = pSelectedRows->GetCount(); if (nRowsCount < 1) return; // minimize memory reallocs to improve performance UINT nAveRecordsSize = 1500; // bytes UINT nGrowBytes = ((nRowsCount * nAveRecordsSize) / 4096 + 1) * 4096; UINT nAllocFlags = GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT; CSharedFile fileRecords(nAllocFlags, nGrowBytes); BOOL bSucceed = FALSE; //------------------------------------------------------------------------ const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; CXTPReportRecords* pDragRecords = new CXTPReportRecords(TRUE); if (!_GetSelectedRows(pDragRecords)) { CMDTARGET_RELEASE(pDragRecords); return; } try { CArchive ar(&fileRecords, CArchive::store); CXTPPropExchangeArchive px(ar); bSucceed = _WriteRecordsData(&px, pDragRecords); ar.Close(); // perform Flush() and detach from file } catch(CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::OnBeginDrag() - %s\n"), szErrText); } pE->Delete(); } catch(CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::OnBeginDrag() - %s\n"), szErrText); } pE->Delete(); } catch(...) { TRACE(_T("EXCEPTION: CXTPReportControl::OnBeginDrag() - Unhandled Exception!\n")); } if (!bSucceed) { CMDTARGET_RELEASE(pDragRecords); return; } HGLOBAL hGlobal = fileRecords.Detach(); m_bDragMode = TRUE; m_bInternalDrag = TRUE; DROPEFFECT dropEffectMask = ((m_dwDragDropFlags & xtpReportAllowDragCopy) ? DROPEFFECT_COPY : 0) + ((m_dwDragDropFlags & xtpReportAllowDragMove) ? DROPEFFECT_MOVE : 0); COleDataSource* pds = new COleDataSource(); XTP_NM_REPORTDRAGDROP nmData; ZeroMemory(&nmData, sizeof(nmData)); nmData.pRecords = pDragRecords; nmData.pDataSource = pds; // Data Source - issue 22675 if (SendNotifyMessage(XTP_NM_REPORT_BEGINDRAG, (NMHDR*) &nmData) == -1) { CMDTARGET_RELEASE(pDragRecords); CMDTARGET_RELEASE(m_pSelectedRowsBeforeDrag) m_bDragMode = FALSE; m_bInternalDrag = FALSE; pds->InternalRelease(); return; } pds->CacheGlobalData(m_cfReport, hGlobal); if (!(m_dwDragDropFlags & xtpReportDontDropAsText)) { // Get As Text CString strDropText = _GetSelectedRowsVisibleColsText(); HGLOBAL hDropText = XTPAllocStrInGlobalMem(strDropText); if (hDropText) pds->CacheGlobalData(XTP_CF_TEXT_T, hDropText); } CXTPReportDropSource dropSource(this); DROPEFFECT dropEffect = pds->DoDragDrop(dropEffectMask, NULL, &dropSource); m_bDragMode = FALSE; m_bInternalDrag = FALSE; if ((m_dwDropMarkerFlags & xtpReportDropSelect) && m_pSelectedRowsBeforeDrag) { // Must remember the selected items before drag. m_pSelectedRows->Clear(); for (int i = 0; i < m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks.GetSize(); i++) m_pSelectedRows->m_arrSelectedBlocks.Add(m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks[i]); CMDTARGET_RELEASE(m_pSelectedRowsBeforeDrag); } nmData.dropEffect = dropEffect; SendNotifyMessage(XTP_NM_REPORT_DRAGDROP_COMPLETED, (NMHDR*) &nmData); if ((dropEffect == DROPEFFECT_MOVE) && (dropEffectMask & DROPEFFECT_MOVE)) { Cut(); } CMDTARGET_RELEASE(pDragRecords); EnsureStopAutoVertScroll(); pds->InternalRelease(); } DROPEFFECT CXTPReportControl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point, int nState) { DROPEFFECT dropEffect = DROPEFFECT_MOVE; BOOL bAbove = TRUE; CXTPReportRecord* pTargetRecord = NULL; int nTargetRow = -1; if (nState == 0) { // Must get the selected rows before the selection changes. if(m_dwDropMarkerFlags & xtpReportDropSelect) { // Must remember the selected items before drag. m_pSelectedRowsBeforeDrag = new CXTPReportSelectedRows(this); for (int i=0; im_arrSelectedBlocks.GetSize(); i++) { m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks.Add(m_pSelectedRows->m_arrSelectedBlocks[i]); } } } if ((dwKeyState & MK_CONTROL) == MK_CONTROL) { dropEffect = DROPEFFECT_COPY; } if (!m_nOLEDropMode) { if (m_cfReport == NULL) dropEffect = DROPEFFECT_NONE; if ((m_dwDragDropFlags & xtpReportAllowDrop) == 0) dropEffect = DROPEFFECT_NONE; XTP_NM_REPORTDRAGDROP nmData; nmData.dropEffect = dropEffect; nmData.pDataObject = pDataObject; nmData.pt = point; //R-DD << nmData.dwKeyState = dwKeyState; //R-DD >> int iValid = (int) SendNotifyMessage(XTP_NM_REPORT_HASVALIDDROPTYPE, (NMHDR*) &nmData); m_nOLEDropAbove = nmData.bAbove; if ((dropEffect != DROPEFFECT_NONE) && (!pDataObject || (!pDataObject->IsDataAvailable(m_cfReport) && iValid != 1))) dropEffect = DROPEFFECT_NONE; } int nDropPos = m_nDropPos; m_nDropPos = -1; if (dropEffect != DROPEFFECT_NONE) { EnsureStartAutoVertScroll(); // DoAutoVertScrollIfNeed(m_ptDrag, point); m_bNoNeedSortedDragDrop = (GetColumns()->GetSortOrder()->GetCount() == 0 && GetColumns()->GetGroupsOrder()->GetCount() == 0); if (m_bNoNeedSortedDragDrop || m_bSortedDragDrop) { CXTPReportRow *pRow = HitTest(point); if (pRow && pRow->GetRecord()) { if (pRow->GetRect().CenterPoint().y < point.y) bAbove = FALSE; if (bAbove) m_nDropPos = pRow->GetRect().top == 0 ? 0 : pRow->GetRect().top - 1; //m_nDropPos = pRow->GetRect().top - 1; else m_nDropPos = pRow->GetRect().bottom - 1; pTargetRecord = pRow->GetRecord(); nTargetRow = pRow->GetIndex(); if (((m_dwDropMarkerFlags & xtpReportDropSelect) && (m_dwDropMarkerFlags & xtpReportDropBetween) && point.y > (pRow->GetRect().top + 3) && point.y < (pRow->GetRect().bottom - 3)) || ((m_dwDropMarkerFlags & xtpReportDropSelect) && point.y > pRow->GetRect().top && point.y < pRow->GetRect().bottom)) { XTP_NM_REPORTDRAGDROP nmData; nmData.dropEffect = dropEffect; nmData.pDataObject = pDataObject; nmData.pTargetRecord = pTargetRecord; nmData.nTargetRow = nTargetRow; nmData.pt = point; //R-DD << nmData.dwKeyState = dwKeyState; //R-DD >> int iValid = (int) SendNotifyMessage(XTP_NM_REPORT_VALIDDROPTARGET, (NMHDR*) &nmData); if (iValid == 1) m_pSelectedRows->Select(pRow); else m_pSelectedRows->Clear(); m_nOLEDropAbove = nmData.bAbove; } else if(m_dwDropMarkerFlags & xtpReportDropSelect) { m_pSelectedRows->Clear(); } } else { if ((m_nDropPos > m_pSectionBody->m_rcSection.top - 1 || m_nDropPos < m_pSectionBody->m_rcSection.bottom - 1)) m_nDropPos = point.y; if (GetRows()->GetCount() == 0) m_nDropPos = 0; if (m_dwDropMarkerFlags & xtpReportDropSelect) m_pSelectedRows->Clear(); } if (m_nDropPos == 0 && GetRows()->GetCount() == 0) m_nDropPos = m_pSectionBody->m_rcSection.top; else if ((m_nDropPos < m_pSectionBody->m_rcSection.top - 1 || m_nDropPos > m_pSectionBody->m_rcSection.bottom - 1)) dropEffect = DROPEFFECT_NONE; } } if (nState == 0) { // entering, get report records CMDTARGET_RELEASE(m_pDropRecords); CFile* pFile = m_cfReport ? pDataObject->GetFileData(m_cfReport) : NULL; if (pFile) { m_pDropRecords = new CXTPReportRecords(); const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; try { CArchive ar(pFile, CArchive::load); CXTPPropExchangeArchive px(ar); if (!_ReadRecordsFromData(&px, *m_pDropRecords)) { m_pDropRecords->RemoveAll(); } ar.Close(); // detach from file } catch(CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::OnDragOver() - %s\n"), szErrText); } pE->Delete(); } catch(CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::OnDragOver() - %s\n"), szErrText); } pE->Delete(); } catch(...) { TRACE(_T("EXCEPTION: CXTPReportControl::OnDragOver() - Unhandled Exception!\n")); } delete pFile; } m_bDragMode = TRUE; } else if (nState == 1) { // leaving, release drop records CMDTARGET_RELEASE(m_pDropRecords); if ((m_dwDropMarkerFlags & xtpReportDropSelect) && m_pSelectedRowsBeforeDrag) { // Must remember the selected items before drag. m_pSelectedRows->Clear(); for (int i = 0; i < m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks.GetSize(); i++) m_pSelectedRows->m_arrSelectedBlocks.Add(m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks[i]); CMDTARGET_RELEASE(m_pSelectedRowsBeforeDrag); } m_bDragMode = FALSE; } COleDataSource* pds = new COleDataSource(); XTP_NM_REPORTDRAGDROP nmData; nmData.pRecords = m_pDropRecords; nmData.pTargetRecord = pTargetRecord; nmData.nTargetRow = nTargetRow; nmData.bAbove = bAbove; nmData.dropEffect = dropEffect; nmData.pt = point; nmData.nState = nState; nmData.pDataSource = pds; // Data Source - issue 22675 nmData.pDataObject = pDataObject; //R-DD << nmData.dwKeyState = dwKeyState; //R-DD >> m_nOLEDropAbove = nmData.bAbove; SendNotifyMessage(XTP_NM_REPORT_DRAGOVER, (NMHDR*) &nmData); m_nOLEDropAbove = nmData.bAbove; if (nState != 1 && nmData.dropEffect == DROPEFFECT_NONE && (m_dwDropMarkerFlags & xtpReportDropSelect)) m_pSelectedRows->Clear(); if (m_nDropPos != nDropPos) RedrawControl(); pds->InternalRelease(); return nmData.dropEffect; } BOOL CXTPReportControl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) { CMDTARGET_RELEASE(m_pDropRecords); EnsureStopAutoVertScroll(); m_bDragMode = FALSE; if (m_nDropPos == -1) return FALSE; CUpdateContext updateContext(this); int nDropPos = m_nDropPos; m_nDropPos = -1; if (dropEffect != DROPEFFECT_COPY && dropEffect != DROPEFFECT_MOVE) return FALSE; //if (IsVirtualMode()) return FALSE; int nTargetRow = -1; if ((m_dwDropMarkerFlags & xtpReportDropSelect) && m_pSelectedRows->GetCount() == 1) nTargetRow = m_pSelectedRows->GetAt(0)->GetIndex(); XTP_NM_REPORTDRAGDROP nmData; nmData.dropEffect = dropEffect; nmData.pDataObject = pDataObject; nmData.pt = point; int iValid = (int) SendNotifyMessage(XTP_NM_REPORT_HASVALIDDROPTYPE, (NMHDR*) &nmData); m_nOLEDropAbove = nmData.bAbove; if (iValid != -1 && nmData.dropEffect == DROPEFFECT_NONE) { // Drop handled or not allowed. if ((m_dwDropMarkerFlags & xtpReportDropSelect) && m_pSelectedRowsBeforeDrag) { // Must remember the selected items before drag. m_pSelectedRows->Clear(); for (int i = 0; i < m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks.GetSize(); i++) m_pSelectedRows->m_arrSelectedBlocks.Add(m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks[i]); CMDTARGET_RELEASE(m_pSelectedRowsBeforeDrag); } return FALSE; } if ((m_dwDropMarkerFlags & xtpReportDropSelect) && m_pSelectedRowsBeforeDrag) { // Must remember the selected items before drag. m_pSelectedRows->Clear(); for (int i = 0; i < m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks.GetSize(); i++) m_pSelectedRows->m_arrSelectedBlocks.Add(m_pSelectedRowsBeforeDrag->m_arrSelectedBlocks[i]); CMDTARGET_RELEASE(m_pSelectedRowsBeforeDrag); } if (!pDataObject || (!pDataObject->IsDataAvailable(m_cfReport) && iValid != 1)) return FALSE; if ((m_dwDragDropFlags & xtpReportAllowDrop) == 0) return FALSE; int nInsert = GetRecords()->GetCount(); BOOL bAbove = TRUE; CXTPReportRecord* pTargetRecord = NULL; CXTPReportRecord* pOriginalTargetRecord = NULL; CXTPReportRow* pRow = HitTest(point); if (pRow) { if (pRow->GetRect().CenterPoint().y < point.y) bAbove = FALSE; pTargetRecord = pRow->GetRecord(); if (pTargetRecord) { if (m_bUnrestrictedDragDrop) pOriginalTargetRecord = pTargetRecord; while (pTargetRecord->GetParentRecord() != NULL) pTargetRecord = pTargetRecord->GetParentRecord(); nInsert = pTargetRecord->GetIndex(); if (!m_bNoNeedSortedDragDrop && m_bSortedDragDrop && nInsert != -1 && m_pSectionBody->m_UaSorted.GetSize() > nInsert) nInsert = m_pSectionBody->m_UaSorted.GetAt(nInsert); if (!bAbove) nInsert++; } } m_bInternalMove = FALSE; if (m_bInternalDrag && dropEffect == DROPEFFECT_MOVE) { m_bInternalMove = TRUE; if (nDropPos == -1) return FALSE; BOOL bRedraw = FALSE; if (!m_bNoNeedSortedDragDrop && m_bSortedDragDrop && GetColumns()->GetGroupsOrder()->GetCount() == 0) { ReleaseSorted(); bRedraw = TRUE; } CXTPReportRecords* pDropRecords = new CXTPReportRecords(TRUE); if (!iValid && (!_GetSelectedRows(pDropRecords) || pDropRecords->GetCount() == GetRows()->GetCount())) { CMDTARGET_RELEASE(pDropRecords); return FALSE; } if (bRedraw) { Populate(); RedrawControl(); } nmData.pRecords = pDropRecords; nmData.pTargetRecord = pTargetRecord; nmData.nTargetRow = nTargetRow; if (m_bUnrestrictedDragDrop) nmData.pTargetRecord = pOriginalTargetRecord; nmData.bAbove = bAbove; nmData.dropEffect = dropEffect; nmData.pDataObject = pDataObject; //nmData.bReturnValue = TRUE; //James proposal (wrong!) nmData.bReturnValue = FALSE; m_nOLEDropAbove = nmData.bAbove; CMDTARGET_ADDREF(pTargetRecord); if (SendNotifyMessage(XTP_NM_REPORT_DROP, (NMHDR*) &nmData) == -1) { CMDTARGET_RELEASE(pDropRecords); CMDTARGET_RELEASE(pTargetRecord); return nmData.bReturnValue; } if (!IsVirtualMode()) { if (!pTargetRecord == NULL) nInsert = pTargetRecord->GetIndex(); else nInsert = GetRows()->GetCount(); if (!bAbove) nInsert++; GetRecords()->Move(nInsert, pDropRecords); Populate(); _SelectRows(pDropRecords); RedrawControl(); } m_nOLEDropAbove = nmData.bAbove; SendNotifyMessage(XTP_NM_REPORT_RECORDS_DROPPED, (NMHDR*) &nmData); CMDTARGET_RELEASE(pDropRecords); CMDTARGET_RELEASE(pTargetRecord); return nmData.bReturnValue; } CXTPReportRecords* pDropRecords = NULL; if (pDataObject->IsDataAvailable(m_cfReport)) { CFile* pFile = pDataObject->GetFileData(m_cfReport); if (pFile) { pDropRecords = new CXTPReportRecords(); const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; try { CArchive ar(pFile, CArchive::load); CXTPPropExchangeArchive px(ar); if (!_ReadRecordsFromData(&px, *pDropRecords)) { pDropRecords->RemoveAll(); } ar.Close(); // detach from file } catch(CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::OnDrop() - %s\n"), szErrText); } pE->Delete(); } catch(CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::OnDrop() - %s\n"), szErrText); } pE->Delete(); } catch(...) { TRACE(_T("EXCEPTION: CXTPReportControl::OnDrop() - Unhandled Exception!\n")); } delete pFile; } } nmData.pRecords = pDropRecords; nmData.pTargetRecord = pTargetRecord; if (m_bUnrestrictedDragDrop) nmData.pTargetRecord = pOriginalTargetRecord; nmData.nTargetRow = nTargetRow; nmData.bAbove = bAbove; nmData.dropEffect = dropEffect; nmData.pDataObject = pDataObject; nmData.bReturnValue = TRUE; m_nOLEDropAbove = nmData.bAbove; if (SendNotifyMessage(XTP_NM_REPORT_DROP, (NMHDR*) &nmData) == -1) { CMDTARGET_RELEASE(pDropRecords); return nmData.bReturnValue; } m_nOLEDropAbove = nmData.bAbove; if (!IsVirtualMode() && pDropRecords) { // Add and Populate records int nRecordsCount = pDropRecords->GetCount(); if (nRecordsCount > 0) { // Add for (int i = 0; i < nRecordsCount; i++) { CXTPReportRecord* pRecord = pDropRecords->GetAt(i); if (pRecord) { CMDTARGET_ADDREF(pRecord); GetRecords()->InsertAt(nInsert, pRecord); nInsert++; } } Populate(); _SelectRows(pDropRecords); RedrawControl(); SendNotifyMessage(XTP_NM_REPORT_RECORDS_DROPPED, (NMHDR*) &nmData); } } else { SendNotifyMessage(XTP_NM_REPORT_RECORDS_DROPPED, (NMHDR*) &nmData); } CMDTARGET_RELEASE(pDropRecords); //return TRUE; return nmData.bReturnValue; } void CXTPReportControl::ReleaseSorted() { int nSortCnt = GetColumns()->GetSortOrder()->GetCount(); if (nSortCnt > 0) { GetColumns()->GetSortOrder()->Clear(); CXTPReportRecord* pDropRec; int N = (int) m_pSectionBody->m_UaSorted.GetSize(); for (int J = 0; J < N; J++) { pDropRec = GetRows()->GetAt(J)->GetRecord(); if (pDropRec) { CXTPReportRecords* pDropRecs = new CXTPReportRecords(TRUE); pDropRecs->Add(pDropRec); GetRecords()->Move(J, pDropRecs); delete pDropRecs; } } } if (GetColumns()->GetGroupsOrder()->GetCount() > 0) GetColumns()->GetGroupsOrder()->Clear(); m_bNoNeedSortedDragDrop = TRUE; m_bSortedDragDrop = TRUE; } void CXTPReportControl::OnTimer(UINT_PTR uTimerID) { if (m_uAutoScrollTimerID == uTimerID) { CPoint ptMouse; if (::GetCursorPos(&ptMouse)) { ScreenToClient(&ptMouse); DoAutoVertScrollIfNeed(m_ptDrag, ptMouse); } } if (m_uRqstEditTimer == uTimerID) { m_iLastRqstEditRow = -1; m_iLastRqstEditCol = -1; } // Information for delay editing. if (m_uiDelayEditTimer == uTimerID) { EnsureStopDelayEditTimer(); ASSERT(!IsEditMode()); if ( m_iLastRqstEditRow != -1 && m_iLastRqstEditCol != -1 && m_iLastRqstEditRow < GetRows()->GetCount() && IsEditOnDelayClick()) { XTP_REPORTRECORDITEM_ARGS args(this, GetRows()->GetAt(m_iLastRqstEditRow), GetColumns()->Find(m_iLastRqstEditCol)); EditItem(&args); StartLastRqstTimer(); } } CWnd::OnTimer(uTimerID); } void CXTPReportControl::EnsureStopAutoVertScroll() { if (m_uAutoScrollTimerID) { KillTimer(m_uAutoScrollTimerID); m_uAutoScrollTimerID = 0; } } void CXTPReportControl::EnsureStartAutoVertScroll() { if (0 == m_uAutoScrollTimerID) { m_uAutoScrollTimerID = SetTimer(XTP_REPORT_AUTO_SCROLL_TIMER_ID, m_nAutoVScrollTimerResolution, NULL); } } void CXTPReportControl::SetAutoVScrollTimerResolution(UINT nNewTimerResolution) { if (nNewTimerResolution == m_nAutoVScrollTimerResolution) return; BOOL bStartTimer = (m_uAutoScrollTimerID != 0); EnsureStopAutoVertScroll(); m_nAutoVScrollTimerResolution = nNewTimerResolution; if (bStartTimer) EnsureStartAutoVertScroll(); } void CXTPReportControl::DoAutoVertScrollIfNeed(CPoint ptClick, CPoint pt) { enum XTPReportControlDirection { xtpReportControlDirectionNone = 0, xtpReportControlDirectionUp = -1, xtpReportControlDirectionDown = 1 }; CXTPReportScreenRows *pScreenRows = GetRows()->GetScreenRows(); if (0 == pScreenRows->GetSize()) { EnsureStopAutoVertScroll(); return; } CXTPReportRow *pRowUp = pScreenRows->GetAt(0); CXTPReportRow *pRowDown = pScreenRows->GetAt(pScreenRows->GetSize() - 1); if (NULL == pRowUp || NULL == pRowDown) { EnsureStopAutoVertScroll(); return; } XTPReportControlDirection nDirection = xtpReportControlDirectionNone; CRect rcUp = m_pSectionBody->m_rcSection; CRect rcDown = m_pSectionBody->m_rcSection; rcUp.bottom = m_pSectionBody->m_rcSection.top + 20; //while dragging item rcDown.top = m_pSectionBody->m_rcSection.bottom - 20; if (rcUp.PtInRect(pt)) { nDirection = xtpReportControlDirectionUp; } if (rcDown.PtInRect(pt)) { nDirection = xtpReportControlDirectionDown; } if (xtpReportControlDirectionNone == nDirection || m_bDragMode && ((xtpReportControlDirectionDown == nDirection && pt.y - ptClick.y < 3) || (xtpReportControlDirectionUp == nDirection && ptClick.y - pt.y < 3))) { EnsureStopAutoVertScroll(); return; } SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); GetScrollInfo(SB_VERT, &si, SIF_ALL); const int nScrollFactor = 2; // Factor to speed up smooth scrolling if (xtpReportControlDirectionUp == nDirection && si.nPos > 0) { m_nScrollStepV *= nScrollFactor; OnVScroll(SB_LINEUP, 0, NULL); m_nScrollStepV /= nScrollFactor; EnsureStartAutoVertScroll(); } else if (xtpReportControlDirectionDown == nDirection && si.nPos + int(si.nPage) - 1 < si.nMax) { m_nScrollStepV *= nScrollFactor; OnVScroll(SB_LINEDOWN, 0, NULL); m_nScrollStepV /= nScrollFactor; EnsureStartAutoVertScroll(); } else { EnsureStopAutoVertScroll(); } } BOOL CXTPReportControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if (nHitTest == HTCLIENT) { switch (m_mouseMode) { case xtpReportMouseOverColumnDivide: SetCursor(GetReportHeader()->m_hResizeCursor); return TRUE; } } return CWnd::OnSetCursor(pWnd, nHitTest, message); } LRESULT CXTPReportControl::SendNotifyMessage(UINT nMessage, NMHDR *pNMHDR) const { if (!IsWindow(m_hWnd)) return 0; NMHDR nmhdr; if (pNMHDR == NULL) pNMHDR = &nmhdr; pNMHDR->hwndFrom = GetSafeHwnd(); pNMHDR->idFrom = GetDlgCtrlID(); pNMHDR->code = nMessage; CWnd *pOwner = GetOwner(); if (pOwner && IsWindow(pOwner->m_hWnd)) return pOwner->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM)pNMHDR); else return 0; } LRESULT CXTPReportControl::SendMessageToParent(CXTPReportRow* pRow, CXTPReportRecordItem* pItem, CXTPReportColumn* pColumn, UINT nMessage, CPoint* pPoint, int nHyperlink) const { if (!IsWindow(m_hWnd)) return 0; XTP_NM_REPORTRECORDITEM nmgv; nmgv.pItem = pItem; nmgv.pColumn = pColumn; nmgv.pRow = pRow; nmgv.nHyperlink = nHyperlink; nmgv.pt.x = 0; nmgv.pt.y = 0; if (pPoint) nmgv.pt = *pPoint; return SendNotifyMessage(nMessage, (NMHDR*)&nmgv); } void CXTPReportControl::DoPropExchange(CXTPPropExchange *pPX) { /* 9.8.1 (_XTP_SCHEMA_98) 10.1.0 (_XTP_SCHEMA_1000) 10.2.0 (_XTP_SCHEMA_1000) 10.3.0 (_XTP_SCHEMA_1030) 10.3.1 (_XTP_SCHEMA_1030) 10.4.0 (_XTP_SCHEMA_1040) 10.4.1 (_XTP_SCHEMA_1041) 10.4.2 (_XTP_SCHEMA_1041) - [Columns] - ShowGroupBox - FreezeColumnsCount - [Header] 11.1.0 (_XTP_SCHEMA_1100) 11.1.2 (_XTP_SCHEMA_1100) 12.0.1 (_XTP_SCHEMA_1200) 12.1.0 (_XTP_SCHEMA_1210) 13.0.0 (_XTP_SCHEMA_1210) - [Columns] - ShowGroupBox - FreezeColumnsCount - FullColumnScrolling >= _XTP_SCHEMA_1100 - HScrollStep >= _XTP_SCHEMA_1100 - [Header] 13.1.0 (_XTP_SCHEMA_1210) - [Columns] - ShowGroupBox - FreezeColumnsCount - FullColumnScrolling >= _XTP_SCHEMA_1100 - HScrollStep >= _XTP_SCHEMA_1100 - [Header] - ShowIconView 13.2.0 (_XTP_SCHEMA_1310) - [Columns] - ShowGroupBox - FullColumnScrolling >= _XTP_SCHEMA_1100 - HScrollStep >= _XTP_SCHEMA_1100 - FreezeColumnsCount !! Order changed !! - FreezeColumnsAbs >= _XTP_SCHEMA_1310 - MovePivot >= _XTP_SCHEMA_1310 - ForcePagination >= _XTP_SCHEMA_1310 - StrictBestFit >= _XTP_SCHEMA_1310 - SelectionExcludeGroupRows >= _XTP_SCHEMA_1310 - DesktopTrackerMode >= _XTP_SCHEMA_1310 - [Header] - ShowIconView */ //ICON_VIEW_MODE RELATED << BeginUpdate(); BOOL bCurIconView = IsIconView(); BOOL bSetBackToIconView = bCurIconView; if (bSetBackToIconView) SetIconView(FALSE); //ICON_VIEW_MODE RELATED >> TRY { pPX->ExchangeSchemaSafe(); CXTPPropExchangeSection secColumns(pPX->GetSection(_T("Columns"))); m_pColumns->DoPropExchange(&secColumns); PX_Bool(pPX, _T("ShowGroupBox"), m_bGroupByEnabled, FALSE); if (pPX->GetSchema() >= _XTP_SCHEMA_1100) { BOOL bFullColumnScrolling = IsFullColumnScrolling(); PX_Bool(pPX, _T("FullColumnScrolling"), bFullColumnScrolling, FALSE); PX_Int (pPX, _T("HScrollStep"), m_nScrollStepH, XTP_REPORT_HSCROLL_STEP); if (pPX->IsLoading()) { SetFullColumnScrolling(bFullColumnScrolling); } } if (pPX->GetSchema() >= _XTP_SCHEMA_1310) { // The order of "FreezeColumnsCount" has been changed with 13.2.0 int nFreezeColumnsCount = GetFreezeColumnsCount(); BOOL bFreezeColumnsAbs = FALSE; PX_Int (pPX, _T("FreezeColumnsCount"), nFreezeColumnsCount, 0); PX_Bool(pPX, _T("FreezeColumnsAbs"), bFreezeColumnsAbs, FALSE); // Removed PX_Bool(pPX, _T("MovePivot"), m_bMovePivot, FALSE); PX_Bool(pPX, _T("ForcePagination"), m_bForcePagination, FALSE); PX_Bool(pPX, _T("StrictBestFit"), m_bStrictBestFit, FALSE); PX_Bool(pPX, _T("SelectionExcludeGroupRows"), m_bSelectionExcludeGroupRows, TRUE); PX_Bool(pPX, _T("DesktopTrackerMode"), m_bDesktopTrackerMode, FALSE); if (pPX->IsLoading()) { SetFreezeColumnsCount(nFreezeColumnsCount); } } CXTPPropExchangeSection secHeader(pPX->GetSection(_T("Header"))); GetReportHeader()->DoPropExchange(&secHeader); if (pPX->IsLoading()) { GetReportHeader()->OnColumnsChanged(xtpReportColumnOrderChanged | xtpReportColumnPropExchange, NULL); Populate(); } } CATCH(CArchiveException, e) { ASSERT(FALSE); } END_CATCH //ICON_VIEW_MODE RELATED << TRY { pPX->ExchangeSchemaSafe(); PX_Bool(pPX, _T("ShowIconView"), bCurIconView); if (pPX->IsLoading() && bCurIconView) SetIconView(bCurIconView); } CATCH(CArchiveException, e) { } END_CATCH if (pPX->IsStoring() && bSetBackToIconView) SetIconView(TRUE); EndUpdate(); //ICON_VIEW_MODE RELATED >> } //ICON_VIEW_MODE RELATED << void CXTPReportControl::SetIconView(BOOL bIconView /* = TRUE */) { if (m_iIconViewColumn == -1) //No Icon Column Set { m_bIconView = FALSE; return; } if (m_bIconView == bIconView) return; CXTPReportColumn* pColumn = NULL; m_UaSelected.RemoveAll(); CXTPReportSelectedRows* pSel = GetSelectedRows(); for (int i = 0; i < pSel->GetCount(); i++) { if (pSel->GetAt(i)) m_UaSelected.Add(pSel->GetAt(i)->GetIndex()); } if (bIconView) { m_pNavigator = m_pNavigatorIcon; if (!m_pPrevGroupsOrder) m_pPrevGroupsOrder = new CXTPReportColumnOrder(GetColumns()); if (!m_pPrevVisible) m_pPrevVisible = new CXTPReportColumnOrder(GetColumns()); if (m_pPrevGroupsOrder) { m_pPrevGroupsOrder->Clear(); CXTPReportColumnOrder* pCurrentColumnOrder = GetColumns()->GetGroupsOrder(); if (pCurrentColumnOrder->GetCount()) { for (int i = 0; i < GetColumns()->GetCount(); i++) { pColumn = pCurrentColumnOrder->GetAt(i); if (pColumn) { m_pPrevGroupsOrder->Add(pColumn); pColumn->SetVisible(FALSE); } } pCurrentColumnOrder->Clear(); Populate(); } } if (m_pPrevVisible) { m_pPrevVisible->Clear(); for (int i = 0; i < GetColumns()->GetCount(); i++) { pColumn = GetColumns()->GetAt(i); if (pColumn && pColumn->IsVisible()) { m_pPrevVisible->Add(pColumn); pColumn->SetVisible(FALSE); } } } m_iIconWidth = GetSystemMetrics(SM_CXICON); m_iIconHeight = GetSystemMetrics(SM_CYICON); m_iIconWidthSpacing = GetSystemMetrics(SM_CXICONSPACING) + 5; m_iIconHeightSpacing = GetSystemMetrics(SM_CYICONSPACING); m_iIconHeightSpacing = max(m_iIconHeightSpacing, (((CXTPReportPaintManager* ) GetPaintManager())->m_nRowHeight << 1) + m_iIconHeight); pColumn = GetColumns()->Find(m_iIconViewColumn); if (pColumn) { pColumn->SetVisible(TRUE); if (pColumn->IsResizable()) GetPaintManager()->m_RecordNumberWidth = pColumn->GetWidth(); pColumn->SetWidth(m_iIconWidth); pColumn->SetEditable(TRUE); } m_bPrevHeaderShow = IsHeaderVisible(); m_bPrevFooterShow = IsFooterVisible(); ShowHeader(FALSE); ShowFooter(FALSE); m_bPrevFocusSubItems = IsFocusSubItems(); m_bPrevHeaderAutoSize = GetReportHeader()->IsAutoColumnSizing(); // This is not needed since we only have one column and it screws up the selection. FocusSubItems(FALSE); GetReportHeader()->SetAutoColumnSizing(TRUE); m_bPrevHeaderRows = IsHeaderRowsVisible(); m_bPrevFooterRows = IsFooterRowsVisible(); ShowHeaderRows(FALSE); ShowFooterRows(FALSE); // Need this so the scrollbar is correct at the beginning. m_iIconViewRowsPerLine = GetNumRowsOnLine(GetReportHeader()->GetWidth()); m_nPrevTreeIndent = GetPaintManager()->m_nTreeIndent; GetPaintManager()->m_nTreeIndent = 0; m_bPrevPreviewMode = IsPreviewMode(); GetPaintManager()->EnablePreviewMode(FALSE); } else { m_pNavigator = m_pNavigatorReport; GetPaintManager()->m_nTreeIndent = m_nPrevTreeIndent; GetReportHeader()->SetAutoColumnSizing(m_bPrevHeaderAutoSize); pColumn = GetColumns()->Find(m_iIconViewColumn); if (pColumn) { if (m_bUseIconColumnForNum) { if (m_iColumnForNum > -1) { if (m_pPrevGroupsOrder && m_pPrevGroupsOrder->GetCount() > 0 && GetPaintManager()->m_RecordNumberWidth < 30) GetPaintManager()->m_RecordNumberWidth = 30; pColumn->SetWidth(GetPaintManager()->m_RecordNumberWidth); pColumn->SetMinWidth(GetPaintManager()->m_RecordNumberWidth); pColumn->SetVisible(TRUE); } else pColumn->SetVisible(FALSE); pColumn->SetHeaderAlignment(DT_CENTER); pColumn->SetEditable(FALSE); } else { pColumn->SetVisible(FALSE); pColumn->SetWidth(0); } } if (m_pPrevVisible) { for (int i = 0; i < m_pPrevVisible->GetCount(); i++) { pColumn = m_pPrevVisible->GetAt(i); if (pColumn) { pColumn->SetVisible(TRUE); if (pColumn->GetWidth() == 0) pColumn->SetWidth(pColumn->GetMinWidth()); } } } if (m_pPrevGroupsOrder) { for (int i = 0; i < m_pPrevGroupsOrder->GetCount(); i++) { pColumn = m_pPrevGroupsOrder->GetAt(i); if (pColumn) { GetColumns()->GetGroupsOrder()->Add(pColumn); pColumn->SetVisible(TRUE); } } Populate(); } ShowHeader(m_bPrevHeaderShow); ShowFooter(m_bPrevFooterShow); if (m_bPrevFocusSubItems) FocusSubItems(m_bPrevFocusSubItems); ShowHeaderRows(m_bPrevHeaderRows); ShowFooterRows(m_bPrevFooterRows); GetPaintManager()->EnablePreviewMode(m_bPrevPreviewMode); } BOOL bOldFirst(TRUE); for (int ii = 0; ii < m_UaSelected.GetSize(); ii++) { int j = (int) m_UaSelected.GetAt(ii); if (j == 0) bOldFirst = FALSE; if (j > -1) { if (GetRows()->GetAt(j)) GetRows()->GetAt(j)->SetSelected(TRUE); } } if (bOldFirst) { if (GetRows()->GetAt(0)) GetRows()->GetAt(0)->SetSelected(FALSE); } m_bIconView = bIconView; AdjustScrollBars(); } int CXTPReportControl::GetNumRowsOnLine(int iTotalWidth) const { return max(iTotalWidth / m_iIconWidthSpacing, 1); } //ICON_VIEW_MODE RELATED >> void CXTPReportControl::SerializeState(CArchive& ar) { CXTPPropExchangeArchive px(ar); DoPropExchange(&px); } void CXTPReportControl::CollapseAll() { CXTPReportRows *pRows = GetRows(); BeginUpdate(); m_UaSelected.RemoveAll(); CXTPReportSelectedRows *pSelelectedRows = GetSelectedRows(); for (int i=0; iGetCount(); i++) { const CXTPReportRow *pRow = pSelelectedRows->GetAt(i); if (NULL != pRow) { m_UaSelected.Add(pRow->GetIndex()); } } for (int j=pRows->GetCount()-1; j>=0; j--) { pRows->GetAt(j)->SetExpanded(FALSE); } EndUpdate(); EnsureVisible(GetFocusedRow()); pSelelectedRows->Clear(TRUE); } void CXTPReportControl::ExpandAll(BOOL bRecursive) { CXTPReportRows *pRows = m_pSectionBody->GetRows(); if (pRows->GetCount() == 0) return; BeginUpdate(); for (int i = pRows->GetCount() - 1; i >= 0; i--) { CXTPReportRow* pRow = pRows->GetAt(i); if (pRow) pRow->SetExpanded(TRUE, bRecursive); } BOOL bOldFirst(TRUE); for (int j = 0; j < m_UaSelected.GetSize(); j++) { int jj = (int) m_UaSelected.GetAt(j); if (jj == 0) bOldFirst = FALSE; CXTPReportRow* pRow = pRows->GetAt(jj); if (pRow) pRow->SetSelected(TRUE); } int nTopRowIndex = GetTopRowIndex(); if (bOldFirst && nTopRowIndex >= 0 && nTopRowIndex < pRows->GetCount()) pRows->GetAt(nTopRowIndex)->SetSelected(FALSE); EndUpdate(); EnsureVisible(GetFocusedRow()); } void CXTPReportControl::SetMouseMode(XTPReportMouseMode nMode) { XTP_TRACE(_T("SetMouseMode: Switching from %d to %d\n"), m_mouseMode, nMode); m_mouseMode = nMode; } void CXTPReportControl::RelayToolTipEvent(UINT message) { if (m_pTip->GetSafeHwnd() && m_pTip->IsWindowVisible()) { CPoint pt; GetCursorPos(&pt); if (!m_pTip->GetHoverRect().PtInRect(pt)) { m_pTip->SetTooltipText(NULL); m_pTip->Activate(FALSE, FALSE); } switch (message) { case WM_MOUSEWHEEL: case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_MOUSELEAVE: m_pTip->Activate(FALSE, FALSE); } } } BOOL CXTPReportControl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { static BOOL bRelay = FALSE; if (m_pTip->GetSafeHwnd() && m_pTip->IsWindowVisible() && !bRelay) { bRelay = TRUE; RelayToolTipEvent(message); bRelay = FALSE; } if (m_pToolTipContext && m_bShowTooltips) { m_pToolTipContext->FilterToolTipMessage(this, message, wParam, lParam); } if (GetMarkupContext()) { CPoint ptMouse(0); GetCursorPos(&ptMouse); ScreenToClient(&ptMouse); BOOL bRelay = FALSE; CXTPReportRow* pRow = HitTest(ptMouse); if (pRow) { CXTPReportRecordItem* pItem = pRow->HitTest(ptMouse); if (pItem && pItem->GetMarkupUIElement()) { bRelay = TRUE; if (XTPMarkupRelayMessage(pItem->GetMarkupUIElement(), message, wParam, lParam, pResult)) return TRUE; } //13.2.2 << //enable markup mouse move for groups else if (pRow->IsGroupRow()) { bRelay = TRUE; if (XTPMarkupRelayMessage(((CXTPReportGroupRow*) pRow)->m_pMarkupUIElement, message, wParam, lParam, pResult)) return TRUE; } //13.2.2 >> } if (!bRelay) { if (XTPMarkupRelayMessage(GetMarkupContext(), message, wParam, lParam, pResult)) return TRUE; } } return CWnd::OnWndMsg(message, wParam, lParam, pResult); } void CXTPReportControl::OnSysColorChange() { CWnd::OnSysColorChange(); m_pPaintManager->RefreshMetrics(); RedrawControl(); } UINT CXTPReportControl::OnGetDlgCode() { return (m_bFocusSubItems ? DLGC_WANTTAB : 0) | DLGC_WANTARROWS | DLGC_WANTCHARS; } void CXTPReportControl::OnSetFocus(CWnd* pOldWnd) { CWnd::OnSetFocus(pOldWnd); RedrawControl(); } void CXTPReportControl::OnKillFocus (CWnd* pNewWnd) { CWnd::OnKillFocus(pNewWnd); EnsureStopAutoVertScroll(); RedrawControl(); } int CXTPReportControl::GetHeaderIndent() const { return GetIndent(GetReportHeader()->m_nIndentLevel); } CXTPReportRow* CXTPReportControl::CreateRow() { return new CXTPReportRow_Batch(); } CXTPReportGroupRow* CXTPReportControl::CreateGroupRow() { return new CXTPReportGroupRow_Batch(); } CXTPReportRow* CXTPReportControl::CreateHeaderFooterRow() { return new CXTPHeapObjectT; } void CXTPReportControl::ShowIconWhenEditing(BOOL bShow) { m_bShowIconWhenEditing = bShow; } BOOL CXTPReportControl::IsShowIconWhenEditing() { return m_bShowIconWhenEditing; } void CXTPReportControl::EditItem(XTP_REPORTRECORDITEM_ARGS *pItemArgs) { CXTPReportRecordItem *pItem = pItemArgs ? pItemArgs->pItem : NULL; if (NULL == m_pActiveItem && NULL == pItem) { // Nothing do to return; } if (m_pActiveItem != NULL) { m_pActiveItem->OnCancelEdit(this, TRUE); m_pActiveItem = NULL; if (!m_bFocusSubItems) SetFocusedColumn(NULL); } CMDTARGET_RELEASE(m_ptrVirtualEditingRow); if (pItem && pItemArgs && pItemArgs->pRow) { if (!HasFocus()) SetFocus(); if (!IsVirtualMode()) { AdjustScrollBars(); RedrawControl(); UpdateWindow(); } if (IsVirtualMode()) { int nRowIndex = pItemArgs->pRow->GetIndex(); //EnsureVisible(pItemArgs->pRow); RedrawControl(); UpdateWindow(); pItemArgs->pRow = NULL; // RedrawControl delete and re-create new screen rows BOOL bMapped = FALSE; CXTPReportScreenRows *pScreenRows = GetRows()->GetScreenRows(); for (int i = 0; i GetSize(); i++) { CXTPReportRow* pRow = pScreenRows->GetAt(i); if (pRow->GetIndex() == nRowIndex) { pItemArgs->pRow = pRow; bMapped = TRUE; ASSERT(m_ptrVirtualEditingRow == NULL); m_ptrVirtualEditingRow = pRow; CMDTARGET_ADDREF(m_ptrVirtualEditingRow); break; } } ASSERT(bMapped); if (!bMapped) return; } else if (GetFocusedRow() != pItemArgs->pRow) { SetFocusedRow(pItemArgs->pRow); UpdateWindow(); } pItemArgs->rcItem = pItemArgs->pRow->GetItemRect(pItem); pItemArgs->rcItem.left += (pItemArgs->rcItem.left == 0 ? GetHeaderIndent() : 0); if (m_bShowIconWhenEditing && pItemArgs->pColumn) { XTP_REPORTRECORDITEM_METRICS* pMetrics = new XTP_REPORTRECORDITEM_METRICS(); XTP_REPORTRECORDITEM_DRAWARGS drawArgs; drawArgs.pControl = this; drawArgs.pColumn = pItemArgs->pColumn; drawArgs.rcItem = pItemArgs->pColumn->GetRect(); drawArgs.nTextAlign = pItem->GetAlignment() == -1 ? 0 : pItem->GetAlignment(); drawArgs.pRow = pItemArgs->pRow; drawArgs.pItem = pItemArgs->pItem; pItemArgs->pRow->GetItemMetrics(&drawArgs, pMetrics); int nIcon = pMetrics->nItemIcon; nIcon = (nIcon != XTP_REPORT_NOICON) ? nIcon : pItem->GetIconIndex(); if (nIcon != XTP_REPORT_NOICON) { if ((drawArgs.nTextAlign & xtpColumnIconRight) != 0) pItemArgs->rcItem.right -= GetPaintManager()->DrawBitmap(NULL, this, pItemArgs->rcItem, nIcon); else pItemArgs->rcItem.left += GetPaintManager()->DrawBitmap(NULL, this, pItemArgs->rcItem, nIcon); } CMDTARGET_RELEASE(pMetrics); } if (pItem->GetHasCheckbox() && pItem->GetCanEditCheckboxItem()) pItemArgs->rcItem.left += 15; if (SetFocusedColumn(pItemArgs->pColumn)) { m_pActiveItem = pItem; pItem->OnBeginEdit(pItemArgs); if (!IsEditMode()) // Need to actually cancel the edit - old version (10) did not have this call EditItem(NULL); } // Fix selection if (GetInplaceEdit()->GetSafeHwnd() && GetInplaceEdit()->GetItem() == pItem) { CXTPReportRecordItemEditOptions* pEditOptions = pItem->GetEditOptions(pItemArgs->pColumn); if (pEditOptions && pEditOptions->m_bSelectTextOnEdit) { GetInplaceEdit()->SetSel(0, -1); } else { CString str; GetInplaceEdit()->GetWindowText(str); GetInplaceEdit()->SetSel(str.GetLength(), str.GetLength()); } } } RedrawControl(); } BOOL CXTPReportControl::HasFocus() const { const CWnd* pFocusWnd = GetFocus(); if (!pFocusWnd) return FALSE; return (pFocusWnd->GetSafeHwnd() == m_hWnd) || (pFocusWnd->GetParent()->GetSafeHwnd() == m_hWnd) || (pFocusWnd->GetOwner()->GetSafeHwnd() == m_hWnd); } void CXTPReportControl::ReleaseItem(int nIndex) { CXTPReportRecords *pRecords = GetRecords(); int i(0); if (IsVirtualMode() && pRecords->GetCount()) { CXTPReportRecord* pRecord = pRecords->GetAt(0); pRecord->m_arrItems[nIndex]->InternalRelease(); pRecord->m_arrItems.RemoveAt(nIndex); } else { for (i = 0; i < pRecords->GetCount(); i++) { CXTPReportRecord* pRecord = pRecords->GetAt(i); pRecord->m_arrItems[nIndex]->InternalRelease(); pRecord->m_arrItems.RemoveAt(nIndex); } } CXTPReportColumns* pColumns = GetColumns(); CXTPReportColumn* pColumnToRemove = NULL; int nColumnsCount = pColumns->GetCount(); for (i = 0; i < nColumnsCount; i++) { CXTPReportColumn* pColumn = pColumns->GetAt(i); if (pColumn->m_nItemIndex > nIndex) pColumn->m_nItemIndex--; else if (pColumn->m_nItemIndex == nIndex) pColumnToRemove = pColumn; } if (pColumnToRemove) pColumns->Remove(pColumnToRemove); } void CXTPReportControl::SetVirtualMode(CXTPReportRecord* pVirtualRecord, int nCount, int nFields) { CXTPReportRecords *pRecords = GetRecords(); if (pRecords) { if (pVirtualRecord) { int nItems = pVirtualRecord->GetItemCount(); if (nItems == 0 && nFields > 0) for (int i = 0; i < nFields; i++) pVirtualRecord->AddItem(new CXTPReportRecordItem()); } else { pVirtualRecord = new CXTPReportRecord(); if (nFields > 0) for (int i = 0; i < nFields; i++) pVirtualRecord->AddItem(new CXTPReportRecordItem()); } if (m_iIconViewColumn > -1) { int nItems = pVirtualRecord->GetItemCount(); CXTPReportRecordItem* pLastItem = pVirtualRecord->GetItem(nItems - 1); if (!pLastItem->IsKindOf(RUNTIME_CLASS(CXTPReportRecordItemIcon))) pVirtualRecord->AddItem(new CXTPReportRecordItemIcon()); } pRecords->SetVirtualMode(pVirtualRecord, nCount); } } BOOL CXTPReportControl::IsVirtualMode() const { CXTPReportRecords *pRecords = GetRecords(); return pRecords ? pRecords->IsVirtualMode() : FALSE; } CXTPReportRow* CXTPReportControl::GetFocusedRow() const { return m_pSections->GetFocusedRow(); } void CXTPReportControl::OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct) { CWnd::OnStyleChanged(nStyleType, lpStyleStruct); RedrawControl(); } CXTPToolTipContext* CXTPReportControl::GetToolTipContext() const { return m_pToolTipContext; } INT_PTR CXTPReportControl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const { ASSERT_VALID(this); ASSERT(::IsWindow(m_hWnd)); // check child windows first by calling CControlBar INT_PTR nHit = CWnd::OnToolHitTest(point, pTI); if (nHit != -1) return nHit; nHit = GetReportHeader()->OnToolHitTest(point, pTI); if (nHit != -1) return nHit; CXTPReportRow* pRow = HitTest(point); if (pRow) nHit = pRow->OnToolHitTest(point, pTI); return nHit; } void CXTPReportControl::SetLayoutRTL(BOOL bRightToLeft) { if (!XTPSystemVersion()->IsLayoutRTLSupported()) return; if (!m_hWnd) return; if (bRightToLeft) { ModifyStyleEx(0, WS_EX_LAYOUTRTL); } else { ModifyStyleEx(WS_EX_LAYOUTRTL, 0); } GetImageManager()->DrawReverted(bRightToLeft); GetInplaceEdit()->DestroyWindow(); AdjustLayout(); if (GetParent()) { CRect rc; GetParent()->GetClientRect(&rc); GetParent()->SetWindowPos(NULL, 0, 0, rc.Width() + 1, rc.Height(), SWP_NOMOVE | SWP_NOZORDER); } } BOOL CXTPReportControl::IsLayoutRTL() { if (!XTPSystemVersion()->IsLayoutRTLSupported()) return FALSE; if (!m_hWnd) return FALSE; return !!(GetWindowLong(m_hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL); } ////////////////////////////////////////////////////////////////////////// // Clipboard operations BOOL CXTPReportControl::CanCopy() { // Check whether are there any selected rows to be copied CXTPReportSelectedRows* pSelRows = GetSelectedRows(); if ((pSelRows != NULL) && (pSelRows->GetCount() > 0)) return TRUE; return FALSE; } BOOL CXTPReportControl::CanCut() { //Old VirtualMode if (IsVirtualMode()) return FALSE; return CanCopy(); } BOOL CXTPReportControl::CanPaste() { CLIPFORMAT uCF_Records = (CLIPFORMAT)::RegisterClipboardFormat(XTPREPORTCTRL_CF_RECORDS); BOOL bCan = FALSE; COleDataObject odj; if (odj.AttachClipboard()) { bCan = odj.IsDataAvailable(CF_TEXT) || odj.IsDataAvailable(CF_UNICODETEXT) || odj.IsDataAvailable(uCF_Records) ; } return bCan; } void CXTPReportControl::Cut() { CWaitCursor _WC; Copy(); if (IsVirtualMode()) return; // Delete selected rows CXTPInternalCollectionT arSelectedRows; _GetSelectedRows(NULL, &arSelectedRows); int nSelRowsCount = (int) arSelectedRows.GetSize(); int nFirstSelRow = INT_MAX; for (int i = nSelRowsCount - 1; i >= 0 ; i--) { CXTPReportRow* pRow = arSelectedRows.GetAt(i, FALSE); if (pRow) { nFirstSelRow = min(nFirstSelRow, pRow->GetIndex()); VERIFY(RemoveRowEx(pRow, FALSE)); } arSelectedRows.RemoveAt(i); } if (GetSelectedRows()) { GetSelectedRows()->Clear(); if (nFirstSelRow != INT_MAX) { GetRows()->m_nFocusedRow = min(nFirstSelRow, GetRows()->GetCount() - 1); if (GetFocusedRow()) { SetFocusedRow(GetFocusedRow()); GetSelectedRows()->Add(GetFocusedRow()); } } } AdjustScrollBars(); RedrawControl(); } // We support text format with \t dividers for record items and // \r\n dividers for records (simple tab-separated text). // Such format is also supported by Excel and some other applications. void CXTPReportControl::Copy() { CWaitCursor _WC; int nRowsCount = 1; if (GetSelectedRows()) nRowsCount = GetSelectedRows()->GetCount(); // minimize memory reallocs to improve performance UINT nAveRecordsSize = 1500; // bytes UINT nGrowBytes = ((nRowsCount * nAveRecordsSize) / 4096 + 1) * 4096; UINT nAllocFlags = GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT; CSharedFile fileRecords(nAllocFlags, nGrowBytes); BOOL bIsRecordsData = FALSE; //------------------------------------------------------------------------ const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; try { CArchive ar(&fileRecords, CArchive::store); CXTPPropExchangeArchive px(ar); bIsRecordsData = _WriteSelectedRowsData(&px); ar.Close(); // perform Flush() and detach from file } catch(CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - %s\n"), szErrText); } pE->Delete(); } catch(CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - %s\n"), szErrText); } pE->Delete(); } catch(...) { TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - Unhandled Exception!\n")); } CString strClipText = _GetSelectedRowsVisibleColsText(); CLIPFORMAT uCF_Records = (CLIPFORMAT)::RegisterClipboardFormat(XTPREPORTCTRL_CF_RECORDS); // Put prepared text into the clipboard if (OpenClipboard()) { ::EmptyClipboard(); // 1 - Text HGLOBAL hText = XTPAllocStrInGlobalMem(strClipText); if (hText != NULL) { ::SetClipboardData(XTP_CF_TEXT_T, hText); } // 2 - Blob data if (bIsRecordsData) { HGLOBAL hData = fileRecords.Detach(); ::GlobalUnlock(hData); // unlock data ::SetClipboardData(uCF_Records, hData); } ::CloseClipboard(); } } void CXTPReportControl::Paste() { CWaitCursor _WC; CLIPFORMAT uCF_Records = (CLIPFORMAT)::RegisterClipboardFormat(XTPREPORTCTRL_CF_RECORDS); CXTPReportRecords arRecords; BOOL bTryPasteFromText = TRUE; // Retrieve text from the clipboard if (!OpenClipboard()) return; if (::IsClipboardFormatAvailable(uCF_Records)) { HGLOBAL hPasteData = ::GetClipboardData(uCF_Records); if (hPasteData) { bTryPasteFromText = FALSE; const int cErrTextSize = 1024; TCHAR szErrText[cErrTextSize + 1]; CSharedFile fileSahred; fileSahred.SetHandle(hPasteData, FALSE); CArchive ar(&fileSahred, CArchive::load); try { CXTPPropExchangeArchive px(ar); if (!_ReadRecordsFromData(&px, arRecords)) { arRecords.RemoveAll(); } } catch(CArchiveException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText); } pE->Delete(); } catch(CFileException* pE) { if (pE->GetErrorMessage(szErrText, cErrTextSize)) { TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText); } pE->Delete(); } catch(...) { TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - Unhandled Exception!\n")); } //********* ar.Close(); // detach from file fileSahred.Detach(); //detach from data ::GlobalUnlock(hPasteData); // unlock data } } UINT uCF_TText = sizeof(TCHAR) == 2 ? CF_UNICODETEXT : CF_TEXT; if (bTryPasteFromText && ::IsClipboardFormatAvailable(uCF_TText)) { // Try to get text data from the clipboard HGLOBAL hglbPaste = ::GetClipboardData(uCF_TText); // Import Text data into the control if (hglbPaste != NULL) { TCHAR* lpszClipboard = (TCHAR*)GlobalLock(hglbPaste); if (!_ReadRecordsFromText(lpszClipboard, arRecords)) { arRecords.RemoveAll(); } ::GlobalUnlock(hglbPaste); } } ::CloseClipboard(); if (IsVirtualMode()) return; CUpdateContext updateContext(this); // Add and Populate records int nRecordsCount = arRecords.GetCount(); if (nRecordsCount > 0) { // Add for (int i = 0; i < nRecordsCount; i++) { CXTPReportRecord* pRecord = arRecords.GetAt(i); if (pRecord) { CMDTARGET_ADDREF(pRecord); AddRecord(pRecord); } } Populate(); // Select added records _SelectRows(&arRecords); } } // We support text format with \t dividers for record items and // \r\n dividers for records (simple tab-separated text). // Such format is also supported by Excel and some other applications. CString CXTPReportControl::_GetSelectedRowsVisibleColsText() { CString strSelText; CXTPReportColumns* pColumns = GetColumns(); if (NULL == pColumns) return _T(""); const int nColumnCount = pColumns->GetVisibleColumnsCount(); // Iterate over the selected rows and prepare corresponding records text CXTPReportSelectedRows* pSelectedRows = GetSelectedRows(); if ((pSelectedRows != NULL) && (pSelectedRows->GetCount() > 0)) { POSITION pos = pSelectedRows->GetFirstSelectedRowPosition(); while (pos) { CXTPReportRow* pRow = pSelectedRows->GetNextSelectedRow(pos); if (NULL == pRow) break; CXTPReportRecord* pRecord = pRow->GetRecord(); if (NULL == pRecord) continue; CStringArray arStrings; for (int nCol = 0; nCol < nColumnCount; nCol++) { CXTPReportColumn* pColumn = pColumns->GetVisibleAt(nCol); CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn); if (NULL == pItem) continue; arStrings.Add(pItem->GetCaption(pColumn)); } BOOL bCanceled = OnBeforeCopyToText(pRecord, arStrings); if (bCanceled) continue; strSelText += XTPStrMake(arStrings, _T("\t")); strSelText += _T("\r\n"); } } return strSelText; } BOOL CXTPReportControl::_ReadRecordsFromText(LPCTSTR pcszText, CXTPReportRecords& rarRecords) { ////////////////////////////////////////////////////////////////////////// // Insert retrieved text into the control CStringArray arRecordsStrings; XTPStrSplit(pcszText, _T("\r\n"), arRecordsStrings); int nCount = (int) arRecordsStrings.GetSize(); for (int i = 0; i < nCount; i++) { CString strRecord = arRecordsStrings[i]; if (strRecord.IsEmpty()) continue; CXTPReportRecord* pNewRec = _CreateRecodFromText(strRecord); // Case: pNewRec = NULL - paste was handled by the user if (pNewRec) rarRecords.Add(pNewRec); } return TRUE; } CXTPReportRecord* CXTPReportControl::_CreateRecodFromText(LPCTSTR pcszRecord) { if (!GetColumns()) { ASSERT(FALSE); return NULL; } CStringArray arStrings; // Read each field from the initial string and set visible field one by one XTPStrSplit(pcszRecord, _T("\t"), arStrings); CXTPReportRecord* pRecord = NULL; BOOL bHandled = OnBeforePasteFromText(arStrings, &pRecord); if (bHandled) return pRecord; #if _MFC_VER >= 0x0600 // Not supported by Visual Studio 5.0 if (!pRecord) { pRecord = new CXTPReportRecord(); if (!pRecord) { return NULL; } int nDataCount = (int) arStrings.GetSize(); // Fill record with all items int nCount = GetColumns()->GetCount(); for (int i = 0; i < nCount; i++) { COleVariant varItem(_T("")); CXTPReportRecordItem* pItem = new CXTPReportRecordItemVariant(varItem); if (!pItem) { CMDTARGET_RELEASE(pRecord); return NULL; } pRecord->AddItem(pItem); } // Iterate all visible columns and set text for each next const int nColumnCount = GetColumns()->GetVisibleColumnsCount(); for (int nCol = 0; nCol < nColumnCount; nCol++) { COleVariant varItem(nCol < nDataCount ? (LPCTSTR)arStrings[nCol] : _T("")); CXTPReportColumn* pColumn = GetColumns()->GetVisibleAt(nCol); CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn); ASSERT(pItem); if (NULL == pItem) continue; CXTPReportRecordItemVariant* pItemVar = DYNAMIC_DOWNCAST(CXTPReportRecordItemVariant, pItem); ASSERT(pItemVar); if (pItemVar) { pItemVar->m_oleValue = varItem; } } } #endif return pRecord; } BOOL CXTPReportControl::_WriteRecordsData(CXTPPropExchange* pPX, CXTPReportRecords* pRecords) { if (!pRecords) return FALSE; long nSchema = XTP_REPORT_CB_RECORDS_DATA_VER; PX_Long(pPX, _T("Version"), (long&)nSchema); pPX->ExchangeLocale(); CXTPPropExchangeSection secRecords(pPX->GetSection(_T("ReportRecords"))); int nRecordsCount = (int)pRecords->GetCount(); CXTPPropExchangeEnumeratorPtr pEnumRecords(secRecords->GetEnumerator(_T("Record"))); POSITION posRecord = pEnumRecords->GetPosition((DWORD)nRecordsCount); for (int i = 0; i < nRecordsCount; i++) { CXTPPropExchangeSection secRecord(pEnumRecords->GetNext(posRecord)); CXTPReportRecord* pRecord = pRecords->GetAt(i); PX_Object(&secRecord, pRecord, RUNTIME_CLASS(CXTPReportRecord)); } return TRUE; } void CXTPReportControl::_SelectChilds(CXTPReportRecords *pRecords) { ASSERT(NULL != pRecords); CXTPReportRows *pRows = GetRows(); CXTPReportSelectedRows *pSelRows = GetSelectedRows(); for (int nRecord=0; nRecordGetCount(); nRecord++) { CXTPReportRecord *pRecord = pRecords->GetAt(nRecord); ASSERT(NULL != pRecord); if (NULL != pRecord) { CXTPReportRow *pRow = pRows->Find(pRecord); if (NULL != pRow) { pSelRows->Add(pRow); // Recursion if (pRecord->HasChildren()) { CXTPReportRecords *pChilds = pRecord->GetChilds(); if (NULL != pChilds) { _SelectChilds(pChilds); } } } } } } void CXTPReportControl::_SelectRows(CXTPReportRecords *pRecords) { CXTPReportSelectedRows *pSelRows = GetSelectedRows(); pSelRows->Clear(); _SelectChilds(pRecords); if (pSelRows->IsChanged()) { OnSelectionChanged(); } } BOOL CXTPReportControl::_GetSelectedRows(CXTPReportRecords* pRecords, CXTPInternalCollectionT *pRows) { ASSERT(!pRecords || pRecords->m_bArray == TRUE); CXTPReportSelectedRows* pSelectedRows = GetSelectedRows(); if (!pSelectedRows || !pSelectedRows->GetCount() || (!pRecords && !pRows)) return FALSE; POSITION pos = pSelectedRows->GetFirstSelectedRowPosition(); while (pos) { CXTPReportRow* pRow = pSelectedRows->GetNextSelectedRow(pos); CXTPReportRecord* pRecord = pRow ? pRow->GetRecord() : NULL; if (NULL == pRow) break; if (pRecord && pRecords) pRecords->Add(pRecord); if (pRow && pRows) pRows->AddPtr(pRow, TRUE); } return TRUE; } BOOL CXTPReportControl::_WriteSelectedRowsData(CXTPPropExchange* pPX) { if (!pPX || !pPX->IsStoring()) { ASSERT(FALSE); return FALSE; } CXTPReportRecords* pSelectedRecords= new CXTPReportRecords(TRUE); if (!_GetSelectedRows(pSelectedRecords) || !_WriteRecordsData(pPX, pSelectedRecords)) { CMDTARGET_RELEASE(pSelectedRecords); return FALSE; } CMDTARGET_RELEASE(pSelectedRecords); return TRUE; } BOOL CXTPReportControl::_ReadRecordsFromData(CXTPPropExchange* pPX, CXTPReportRecords& rarRecords) { rarRecords.RemoveAll(); if (!pPX || !pPX->IsLoading()) { ASSERT(FALSE); return FALSE; } CXTPPropExchangeSection secRecords(pPX->GetSection(_T("ReportRecords"))); long nSchema = 0; PX_Long(pPX, _T("Version"), (long&)nSchema); pPX->ExchangeLocale(); if (nSchema != XTP_REPORT_CB_RECORDS_DATA_VER) { ASSERT(FALSE); return FALSE; } CXTPPropExchangeEnumeratorPtr pEnumRecords(secRecords->GetEnumerator(_T("Record"))); POSITION posRecord = pEnumRecords->GetPosition(); while (posRecord) { CXTPPropExchangeSection secRecord(pEnumRecords->GetNext(posRecord)); CXTPReportRecord* pRecord = NULL; PX_Object(&secRecord, pRecord, RUNTIME_CLASS(CXTPReportRecord)); if (!pRecord) AfxThrowArchiveException(CArchiveException::badClass); CXTPReportRecord* pRecord2 = pRecord; BOOL bCanceled = OnBeforePaste(&pRecord2); if (bCanceled || pRecord2 != pRecord) CMDTARGET_RELEASE(pRecord); if (bCanceled) continue; rarRecords.Add(pRecord2); } return TRUE; } BOOL CXTPReportControl::OnBeforeCopyToText(CXTPReportRecord* pRecord, CStringArray& rarStrings) { XTP_NM_REPORT_BEFORE_COPYPASTE nmParams; ::ZeroMemory(&nmParams, sizeof(nmParams)); CXTPReportRecord* pRecordTmp = pRecord; nmParams.ppRecord = &pRecordTmp; nmParams.parStrings = &rarStrings; LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_BEFORE_COPY_TOTEXT, (NMHDR*)&nmParams); return lResult != 0; } BOOL CXTPReportControl::OnBeforePasteFromText(CStringArray& arStrings, CXTPReportRecord** ppRecord) { XTP_NM_REPORT_BEFORE_COPYPASTE nmParams; ::ZeroMemory(&nmParams, sizeof(nmParams)); nmParams.parStrings = &arStrings; nmParams.ppRecord = ppRecord; LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_BEFORE_PASTE_FROMTEXT, (NMHDR*)&nmParams); return lResult != 0; } BOOL CXTPReportControl::OnBeforePaste(CXTPReportRecord** ppRecord) { XTP_NM_REPORT_BEFORE_COPYPASTE nmParams; ::ZeroMemory(&nmParams, sizeof(nmParams)); nmParams.ppRecord = ppRecord; LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_BEFORE_PASTE, (NMHDR*)&nmParams); return lResult != 0; } int CXTPReportControl::OnGetColumnDataBestFitWidth(CXTPReportColumn* pColumn) { CXTPReportPaintManager* pPaintManager = GetPaintManager(); if (!pColumn || !pPaintManager) { ASSERT(FALSE); return 0; } int nDataWidth = 0; int nDataWidth0 = 0; int nDataWidth1 = 0; CXTPClientRect rcClient(this); CBitmap bmp; { CClientDC dcClient(this); bmp.CreateCompatibleBitmap(&dcClient, rcClient.Width(), rcClient.Height()); } CXTPCompatibleDC dc(NULL, &bmp); CXTPFontDC autoFont(&dc, pPaintManager->GetTextFont()); // to reset selected font on exit if (pColumn->GetBestFitMode() == xtpColumnBestFitModeVisibleData || (pColumn->GetBestFitMode() == xtpColumnBestFitModeAllData && IsVirtualMode()) /* && pColumn->m_nMaxItemWidth == 0*/) { // calculate width for visible rows only int nVisibleRows = GetReportAreaRows(GetTopRowIndex(), TRUE); nDataWidth = OnGetItemsCaptionMaxWidth(&dc, GetRows(), pColumn, GetTopRowIndex(), nVisibleRows); } else if (pColumn->GetBestFitMode() == xtpColumnBestFitModeAllData && !IsVirtualMode()) nDataWidth = OnGetItemsCaptionMaxWidth(&dc, GetRows(), pColumn); else return 0; if (m_pSectionHeader->IsVisible() && GetHeaderRows()->GetCount() > 0) nDataWidth0 = OnGetItemsCaptionMaxWidth(&dc, GetHeaderRows(), pColumn); if (m_pSectionFooter->IsVisible() && GetFooterRows()->GetCount() > 0) nDataWidth1 = OnGetItemsCaptionMaxWidth(&dc, GetFooterRows(), pColumn); nDataWidth = max(nDataWidth, max(nDataWidth0, nDataWidth1)); return nDataWidth; } int CXTPReportControl::OnGetItemsCaptionMaxWidth(CDC* pDC, CXTPReportRows* pRows, CXTPReportColumn* pColumn, int nStartRow, int nRowsCount) { CXTPReportPaintManager* pPaintManager = GetPaintManager(); if (!pDC || !pRows || !pColumn || !pPaintManager) { ASSERT(FALSE); return 0; } XTP_REPORTRECORDITEM_DRAWARGS drawArgs; drawArgs.pDC = pDC; drawArgs.pControl = this; drawArgs.pColumn = pColumn; drawArgs.rcItem = pColumn->GetRect(); XTP_REPORTRECORDITEM_METRICS* pMetrics = new XTP_REPORTRECORDITEM_METRICS(); int nGroupIndent = 0; if (GetColumns()->GetVisibleAt(0) == pColumn) nGroupIndent = GetHeaderIndent(); CSize sizeBitmap(0, 0); int nMaxWidth = 0; int nItemIndex = pColumn->GetItemIndex(); int nEndRow = pRows->GetCount(); if (nRowsCount > 0) nEndRow = min(pRows->GetCount(), nStartRow + nRowsCount); for (int i = max(0, nStartRow); i < nEndRow; i++) { CXTPReportRow* pRow = pRows->GetAt(i); if (!pRow) continue; if (pRow && pRow->IsGroupRow()) continue; CXTPReportRecord* pRec = pRow ? pRow->GetRecord() : NULL; CXTPReportRecordItem* pItem = pRec ? pRec->GetItem(nItemIndex) : NULL; if (!pItem) continue; // 1. Calculate Text drawArgs.pRow = pRow; drawArgs.pItem = pItem; pMetrics->strText = pItem->GetCaption(pColumn); pRow->GetItemMetrics(&drawArgs, pMetrics); pDC->SelectObject(pMetrics->pFont); int nWidth = 0; if (pItem->GetMarkupUIElement()) { nWidth = XTPMarkupMeasureElement(pItem->GetMarkupUIElement(), INT_MAX, 0).cx + 4; } else { CString sFirst(pMetrics->strText); CString sLast; int jPos = sFirst.Find(_T('\n'), 0); int wd(0); while (jPos > -1) { sLast = sFirst.Mid(jPos + 1); sFirst = sFirst.Left(jPos - 1); wd = max(wd, pDC->GetTextExtent(sFirst).cx + 7); sFirst = sLast; jPos = sFirst.Find(_T('\n'), 0); } if (!sFirst.IsEmpty()) nWidth = max(wd, pDC->GetTextExtent(sFirst).cx + 7); // nWidth = pDC->GetTextExtent(pMetrics->strText).cx + 7; } // 2. Calculate Tree Indent if (pColumn->IsTreeColumn()) { int nTreeDepth = pRow->GetTreeDepth() - pRow->GetGroupLevel(); if (nTreeDepth > 0) nTreeDepth++; nWidth += GetIndent(nTreeDepth); if (sizeBitmap.cx == 0 && sizeBitmap.cy == 0) { CRect rcBmp(0, 0, 100, 100); sizeBitmap = pPaintManager->DrawCollapsedBitmap(NULL, pRow, rcBmp); } nWidth += sizeBitmap.cx + 2; } // 2.1 Calculate Group Indent nWidth += nGroupIndent; // 3. Calculate item Icon int nIcon = pMetrics->nItemIcon; nIcon = (nIcon != XTP_REPORT_NOICON) ? nIcon : pItem->GetIconIndex(); if (nIcon != XTP_REPORT_NOICON) { CXTPImageManagerIcon* pIcon = GetImageManager()->GetImage(nIcon, 0); if (pIcon) nWidth += pIcon->GetWidth() + 4; } if (pItem->GetHasCheckbox()) { nWidth += 16; } // 4. Calculate item Controls if (pItem->m_pItemControls) { int nControlsCount = pItem->m_pItemControls->GetSize(); for (int k = 0; k < nControlsCount; k++) { CXTPReportRecordItemControl* pCtrl = pItem->m_pItemControls->GetAt(k); int nControlWidth = 0; if (pCtrl) nControlWidth = pCtrl->GetSize().cx; if (nControlWidth < 0) nControlWidth = 20; nWidth += nControlWidth; } } nMaxWidth = max(nMaxWidth, nWidth); } CMDTARGET_RELEASE(pMetrics); return nMaxWidth; } BOOL CXTPReportControl::IsEditMode() { CXTPReportInplaceEdit* pEdit = GetInplaceEdit(); BOOL bEditMode = pEdit && pEdit->GetSafeHwnd() && pEdit->IsWindowVisible(); bEditMode |= GetInplaceList() && GetInplaceList()->GetSafeHwnd() && GetInplaceList()->IsWindowVisible(); return bEditMode; } int CXTPReportControl::GetRowsHeight(CXTPReportRows* pRows, int nTotalWidth, int nMaxHeight) { int nRowsHeight = 0; CWindowDC dc (this); for (int i = 0; i < pRows->GetCount(); ++i) { nRowsHeight += GetPaintManager()->GetRowHeight(&dc, pRows->GetAt(i), nTotalWidth); if (nMaxHeight >= 0 && nRowsHeight > nMaxHeight) return nRowsHeight; } return nRowsHeight; } void CXTPReportControl::DrawDefaultGrid(CDC* pDC, CRect rcClient, int nRowHeight, int nLeftOffset) { if (nRowHeight <= 0) return; int nFreezeCols = GetFreezeColumnsCount(); CRect rcClipBox = GetReportRectangle(); CRect rcRow; rcRow = rcClient; rcRow.left -= nLeftOffset; rcRow.right -= nLeftOffset; rcRow.bottom = rcClient.top + nRowHeight; int nIndentWidth = GetHeaderIndent(); CXTPReportPaintManager* pPaintManager = GetPaintManager(); CXTPReportColumns arrVisibleColumns(this); GetColumns()->GetVisibleColumns(arrVisibleColumns); int nVisColCount = arrVisibleColumns.GetCount(); nFreezeCols = min(nFreezeCols, nVisColCount); // fill the empty space while (rcRow.top < rcClient.bottom) { CRect rcItem(rcRow.left, rcRow.top, rcRow.right, rcRow.bottom); CRect rcIndent(nFreezeCols ? rcRow : rcRow); ///////////////////// rcIndent.right = rcIndent.left + nIndentWidth; int xMinCol_0 = rcRow.left + nIndentWidth; for (int nColumn = nVisColCount-1; nColumn >= 0; nColumn--) { BOOL bFreezeCol = nColumn < nFreezeCols; int nColIdx = bFreezeCol ? nFreezeCols - 1 - nColumn : nColumn; CXTPReportColumn* pColumn = arrVisibleColumns.GetAt(nColIdx); ASSERT(pColumn && pColumn->IsVisible()); if (pColumn) { rcItem.left = pColumn->GetRect().left; if (nColIdx == 0) rcItem.left = max(xMinCol_0, rcItem.left); rcItem.right = pColumn->GetRect().right; if (!CRect().IntersectRect(rcClipBox, rcItem)) continue; if (bFreezeCol) { CRect rcFreeze(rcItem); rcFreeze.top +=1; pDC->FillSolidRect(rcFreeze, pPaintManager->GetControlBackColor(this)); } CRect rcGridItem(rcItem); rcGridItem.left--; pPaintManager->DrawGrid(pDC, xtpReportOrientationHorizontal, rcGridItem); pPaintManager->DrawGrid(pDC, xtpReportOrientationVertical, rcGridItem); if (nColIdx == nFreezeCols - 1) pPaintManager->DrawFreezeColsDivider(pDC, rcGridItem, this); } } if (nIndentWidth > 0) // draw indent column pPaintManager->FillIndent(pDC, rcIndent); rcRow.top += nRowHeight; rcRow.bottom += nRowHeight; } } BOOL CXTPReportControl::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN) { if (!OnPreviewKeyDown((UINT&)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam)) ) { return TRUE; } } return CWnd::PreTranslateMessage(pMsg); } BOOL CXTPReportControl::OnConstraintSelecting(CXTPReportRow* pRow, CXTPReportRecordItem* pItem, CXTPReportColumn* pColumn, CXTPReportRecordItemConstraint* pConstraint) { XTP_NM_REPORTCONSTRAINTSELECTING nmConstraint; ::ZeroMemory(&nmConstraint, sizeof(nmConstraint)); nmConstraint.pRow = pRow; nmConstraint.pColumn = pColumn; nmConstraint.pItem = pItem; nmConstraint.pConstraint = pConstraint; LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_CONSTRAINT_SELECTING, (NMHDR*)&nmConstraint); return lResult != 0; } const XTP_NM_REPORTTOOLTIPINFO& CXTPReportControl::OnGetToolTipInfo(CXTPReportRow* pRow, CXTPReportRecordItem* pItem, CString& rstrToolTipText) { ::ZeroMemory(m_pCachedToolTipInfo, sizeof(XTP_NM_REPORTTOOLTIPINFO)); m_pCachedToolTipInfo->pRow = pRow; m_pCachedToolTipInfo->pItem = pItem; m_pCachedToolTipInfo->pstrText = &rstrToolTipText; SendNotifyMessage(XTP_NM_REPORT_GETTOOLTIPINFO, (NMHDR*)m_pCachedToolTipInfo); return *m_pCachedToolTipInfo; } CXTPReportDataManager* CXTPReportControl::GetDataManager() { if (!m_pDataManager) m_pDataManager = new CXTPReportDataManager(this); return m_pDataManager; } CRect CXTPReportControl::GetElementRect(int nElement) const { switch (nElement) { case xtpReportElementRectGroupByArea: return m_rcGroupByArea; case xtpReportElementRectHeaderArea: return m_rcHeaderArea; case xtpReportElementRectFooterArea: return m_rcFooterArea; case xtpReportElementRectHeaderRecordsArea: return m_pSectionHeader->m_rcSection; case xtpReportElementRectFooterRecordsArea: return m_pSectionFooter->m_rcSection; case xtpReportElementRectHeaderRecordsDividerArea: return m_pSectionHeader->GetDividerRect(); case xtpReportElementRectFooterRecordsDividerArea: return m_pSectionFooter->GetDividerRect(); default: return m_pSectionBody->m_rcSection; } } CXTPMarkupContext* CXTPReportControl::GetMarkupContext() const { return m_pMarkupContext; } void CXTPReportControl::EnableMarkup(BOOL bEnable) { if (m_bMarkupEnabled == bEnable) return; m_bMarkupEnabled = bEnable; XTPMarkupReleaseContext(m_pMarkupContext); m_pMarkupContext = NULL; if (bEnable) { m_pMarkupContext = XTPMarkupCreateContext(m_hWnd); } m_pSections->SetMarkupContext(m_pMarkupContext); } LRESULT CXTPReportControl::OnGetObject(WPARAM wParam, LPARAM lParam) { if (((LONG)lParam) != OBJID_CLIENT) return (LRESULT)Default(); LPUNKNOWN lpUnknown = GetInterface(&IID_IAccessible); if (!lpUnknown) return E_FAIL; return LresultFromObject(IID_IAccessible, wParam, lpUnknown); } BEGIN_INTERFACE_MAP(CXTPReportControl, CCmdTarget) INTERFACE_PART(CXTPReportControl, IID_IAccessible, ExternalAccessible) END_INTERFACE_MAP() CCmdTarget* CXTPReportControl::GetAccessible() { return this; } HRESULT CXTPReportControl::GetAccessibleParent(IDispatch* FAR* ppdispParent) { *ppdispParent = NULL; if (GetSafeHwnd()) { return AccessibleObjectFromWindow(GetSafeHwnd(), OBJID_WINDOW, IID_IDispatch, (void**)ppdispParent); } return E_FAIL; } HRESULT CXTPReportControl::GetAccessibleChildCount(long FAR* pChildCount) { if (pChildCount == 0) { return E_INVALIDARG; } *pChildCount = 1 + GetRows()->GetCount(); return S_OK; } HRESULT CXTPReportControl::GetAccessibleChild(VARIANT varChild, IDispatch* FAR* ppdispChild) { *ppdispChild = NULL; int nChild = GetChildIndex(&varChild); if (nChild <= 0) { return E_INVALIDARG; } if (nChild == 1) { *ppdispChild = GetReportHeader()->GetIDispatch(TRUE); return S_OK; } CXTPReportRow* pRow = GetRows()->GetAt(nChild - 2); if (!pRow) { return E_INVALIDARG; } *ppdispChild = pRow->GetIDispatch(TRUE); return S_OK; } HRESULT CXTPReportControl::GetAccessibleName(VARIANT varChild, BSTR* pszName) { int nChild = GetChildIndex(&varChild); if (nChild == CHILDID_SELF || nChild == -1) { CString strCaption; GetWindowText(strCaption); if (strCaption.IsEmpty()) strCaption = _T("Report"); *pszName = strCaption.AllocSysString(); return S_OK; } return E_INVALIDARG; } HRESULT CXTPReportControl::GetAccessibleRole(VARIANT varChild, VARIANT* pvarRole) { pvarRole->vt = VT_EMPTY; int nChild = GetChildIndex(&varChild); if (nChild == CHILDID_SELF) { pvarRole->vt = VT_I4; pvarRole->lVal = ROLE_SYSTEM_TABLE; return S_OK; } return E_INVALIDARG; } HRESULT CXTPReportControl::GetAccessibleState(VARIANT varChild, VARIANT* pvarState) { pvarState->vt = VT_I4; pvarState->lVal = 0; int nChild = GetChildIndex(&varChild); if (nChild == CHILDID_SELF) { pvarState->lVal = STATE_SYSTEM_FOCUSABLE; } return S_OK; } HRESULT CXTPReportControl::AccessibleLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild) { *pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0; if (!GetSafeHwnd()) return S_OK; CRect rc; GetWindowRect(&rc); int nChild = GetChildIndex(&varChild); if (nChild == 1) { rc = m_rcHeaderArea; ClientToScreen(&rc); } if (nChild > 1) { CXTPReportRow* pRow = GetRows()->GetAt(nChild - 2); if (pRow) { rc = pRow->GetRect(); ClientToScreen(&rc); } } *pxLeft = rc.left; *pyTop = rc.top; *pcxWidth = rc.Width(); *pcyHeight = rc.Height(); return S_OK; } HRESULT CXTPReportControl::AccessibleHitTest(long xLeft, long yTop, VARIANT* pvarID) { if (pvarID == NULL) return E_INVALIDARG; pvarID->vt = VT_EMPTY; if (!GetSafeHwnd()) return S_FALSE; if (!CXTPWindowRect(this).PtInRect(CPoint(xLeft, yTop))) return S_FALSE; pvarID->vt = VT_I4; pvarID->lVal = 0; CPoint pt(xLeft, yTop); ScreenToClient(&pt); if (m_rcHeaderArea.PtInRect(pt)) { pvarID->vt = VT_DISPATCH; pvarID->pdispVal = GetReportHeader()->GetIDispatch(TRUE); return S_OK; } CXTPReportRow* pRow = HitTest(pt); if (pRow) { pvarID->vt = VT_DISPATCH; pvarID->pdispVal = pRow->GetIDispatch(TRUE); return S_OK; } return S_FALSE; } void CXTPReportControl::EnsureStopLastRqstTimer() { if (m_uRqstEditTimer) { KillTimer(m_uRqstEditTimer); m_uRqstEditTimer = 0; m_iLastRqstEditRow = -1; m_iLastRqstEditCol = -1; } } // Information for delay editing. void CXTPReportControl::EnsureStopDelayEditTimer() { if (m_uiDelayEditTimer) { KillTimer(m_uiDelayEditTimer); m_uiDelayEditTimer = NULL; } } void CXTPReportControl::StartLastRqstTimer() { EnsureStopLastRqstTimer(); m_uRqstEditTimer = SetTimer(XTP_REPORT_DELAY_CLICK_TIMER_ID, 3000, NULL); // After 3 seconds, ignore this click. } // Information for delay editing. void CXTPReportControl::StartDelayEditTimer() { EnsureStopDelayEditTimer(); m_uiDelayEditTimer = SetTimer(XTP_REPORT_DELAYEDIT_CLICK_TIMER_ID, m_uiDelayEditMaxTime, NULL); // Begin edit after a full double click is possible. } void CXTPReportControl::SetSelectionState(int index, int state) { CXTPReportSelectedRows* pSelectedRows = GetSelectedRows(); if (!pSelectedRows) return; CXTPReportRecordItem* pItem = NULL; CXTPReportRecord* pRec = NULL; for (int i = 0; i < pSelectedRows->GetCount(); i++) { if (pSelectedRows->GetAt(i)) { pRec = pSelectedRows->GetAt(i)->GetRecord(); if (pRec) { if (index < pRec->GetItemCount()) { pItem = pRec->GetItem(index); if (pItem) { pItem->SetChecked(state == 1); pItem->SetCheckedState(state); } } } } } RedrawControl(); } void CXTPReportControl::Recalc(BOOL bAll) { EditItem(NULL); if (!bAll && GetFocusedRow()) { CXTPReportRecord* pRec = GetFocusedRow()->GetRecord(); if (pRec) { int N = pRec->GetItemCount(); CXTPReportRecordItem* pItem = NULL; for (int i = 0; i < N; i++) { pItem = pRec->GetItem(i); if (pItem) { if (!pItem->GetFormula().IsEmpty()) pItem->SetCaption(_T("x")); //it will call recalc for item } } RedrawControl(); } } else if (GetRecords()) { int n = GetRecords()->GetCount(); for (int j = 0; j < n; j++) { CXTPReportRecord* pRec = GetRecords()->GetAt(j); if (pRec) { int N = pRec->GetItemCount(); CXTPReportRecordItem* pItem = NULL; for (int i = 0; i < N; i++) { pItem = pRec->GetItem(i); if (pItem) { if (!pItem->GetFormula().IsEmpty()) pItem->SetCaption(_T("x")); } } RedrawControl(); } } int N = GetRows()->GetCount(); for (int I = 0; I < N; I++) { CXTPReportRow* pTRow = GetRows()->GetAt(I); if (pTRow && pTRow->IsGroupRow()) { CXTPReportGroupRow* pTgRow = (CXTPReportGroupRow*) pTRow; if (!pTgRow->GetFormula().IsEmpty()) pTgRow->SetCaption(_T("x")); } } RedrawControl(); } } BOOL CXTPReportControl::IsShowRowNumber() { if (m_iColumnForNum > -1) { if (m_bUseIconColumnForNum) { CXTPReportColumn* pIconCol = GetColumns()->Find(m_iColumnForNum); if (pIconCol) return pIconCol->IsVisible(); } } return FALSE; } void CXTPReportControl::ShowRowNumber(BOOL bSet) { if (bSet) { if (m_iColumnForNumPrev > -1) m_iColumnForNum = m_iColumnForNumPrev; if (m_iColumnForNum > -1) { if (m_bUseIconColumnForNum) { CXTPReportColumn* pIconCol = GetColumns()->Find(m_iColumnForNum); if (pIconCol) pIconCol->SetVisible(TRUE); } } } else { m_iColumnForNumPrev = m_iColumnForNum; if (m_iColumnForNum > -1) { if (m_bUseIconColumnForNum && !m_bIconView) { CXTPReportColumn* pIconCol = GetColumns()->Find(m_iColumnForNum); if (pIconCol) pIconCol->SetVisible(FALSE); } } m_iColumnForNum = -1; } RedrawControl(); } int CXTPReportControl::GetFreezeColumnsCount() const { int nCount = 0; BOOL bStop = FALSE; const CXTPReportColumns *pColumns = GetColumns(); for (int nColumn=0; nColumnGetCount(); nColumn++) { const CXTPReportColumn *pColumn = pColumns->GetAt(nColumn); ASSERT(NULL != pColumn); if (pColumn->IsVisible()) { if (pColumn->IsFrozen() && !bStop) { ++nCount; } else { bStop = TRUE; } } } return nCount; } int CXTPReportControl::GetFreezeColumnsIndex() const { int nCount = GetFreezeColumnsCount(); int nIndex = -1; for (int nColumn=0; nColumnGetCount(); nColumn++) { const CXTPReportColumn *pColumn = GetColumns()->GetAt(nColumn); ASSERT(NULL != pColumn); if (pColumn->IsVisible() && (nCount > 0)) { nCount--; nIndex = nColumn; } } return nIndex; } void CXTPReportControl::SetFreezeColumnsCount(int nCount, BOOL bAdjust) { UNREFERENCED_PARAMETER(bAdjust); for (int nColumn=0; nColumnGetCount(); nColumn++) { CXTPReportColumn *pColumn = GetColumns()->GetAt(nColumn); if (NULL != pColumn) { pColumn->SetFrozen(nColumn < nCount); } } RedrawControl(); #if 0 if (nCount >= 0 && nCount < m_pColumns->GetCount()) { BOOL bCallView = FALSE; if (GetPaintManager() != NULL && GetPaintManager()->m_bMoveScrollbarOnFixedColumnsIndent) bCallView = TRUE; m_nFreezeColumnsCount = nCount; if (IsFullColumnScrolling()) SetFullColumnScrolling(IsFullColumnScrolling()); else if (bCallView && m_hWnd != NULL) { CXTPReportControl::OnHScroll(SB_TOP, 0, NULL); RedrawControl(); UpdateWindow(); AdjustScrollBars(); } if (bCallView) { CWnd* pParent = GetParent(); if (pParent) { CRect rc; pParent->GetWindowRect(&rc); int w = rc.Width(); int h = rc.Height(); if (bAdjust) h -= 4; if (DYNAMIC_DOWNCAST(CView, pParent)) ((CView*) pParent)->SendMessage(WM_SIZE, 0, MAKELPARAM(w, h)); //pParent->SetWindowPos(NULL, 0, 0, rc.Width(), rc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); } } } else m_nFreezeColumnsCount = 0; #endif } void CXTPReportControl::SetDisableReorderColumnsCount(int nCount) { if (nCount >= 0 && nCount < m_pColumns->GetCount()) m_nDisableReorderColumnsCount = nCount; else m_nDisableReorderColumnsCount = 0; } CXTPReportRecordItem* CXTPReportControl::GetFocusedRecordItem() const { CXTPReportColumn* pCol = GetFocusedColumn(); CXTPReportRow* pRow = GetFocusedRow(); if (pCol && pRow && pRow->GetRecord()) return pRow->GetRecord()->GetItem(pCol); return NULL; } BOOL CXTPReportControl::SetCellText(int row, int col, CString sText) { CXTPReportRow* pRow = GetRows()->GetAt(row); if (pRow && pRow->GetRecord()) { CXTPReportRecordItem* pItem = pRow->GetRecord()->GetItem(col); if (pItem) { if (pItem->IsKindOf(RUNTIME_CLASS(CXTPReportRecordItemText))) ((CXTPReportRecordItemText*) pItem)->SetValue(sText); pItem->SetCaption(sText); return TRUE; } } return FALSE; } BOOL CXTPReportControl::SetCellFormula(int row, int col, CString sFormula) { CXTPReportRow* pRow = GetRows()->GetAt(row); if (pRow && pRow->GetRecord()) { CXTPReportRecordItem* pItem = pRow->GetRecord()->GetItem(col); if (pItem) { pItem->SetFormula(sFormula); //e.g. "SUM(R0*C2:R1*C5)" pItem->SetFormatString(_T("%d")); pItem->SetCaption(_T("x")); pItem->SetEditable(FALSE); return TRUE; } } return FALSE; } void CXTPReportControl::UnselectGroupRows() { if (IsSkipGroupsFocusEnabled() && !IsVirtualMode()) { for (int II = 0; II < GetRows()->GetCount(); II++) { CXTPReportRow* pRow = GetRows()->GetAt(II); if (pRow) { if (pRow->IsGroupRow()) pRow->SetSelected(FALSE); } } } } BOOL CXTPReportControl::IsFullColumnScrolling() const { if (GetReportHeader() && GetReportHeader()->IsAutoColumnSizing()) { return FALSE; } else { return (xtpReportScrollModeBlock == m_scrollModeH); } } //---------------------------------------------------------------------- IMPLEMENT_DYNAMIC(CXTPPromptDlg, CDialog) CXTPPromptDlg::CXTPPromptDlg(CWnd* pParent) : CDialog() { UNREFERENCED_PARAMETER(pParent); } CXTPPromptDlg::~CXTPPromptDlg() { } INT_PTR CXTPPromptDlg::DoModal() { BYTE DlgTempl[]= { 0X01, 0X00, 0XFF, 0XFF, 0X00, 0X00, 0X00, 0X00, 0X80, 0X00, 0X00, 0X00, 0X48, 0X00, 0XC8, 0X80, 0X02, 0X00, 0X00, 0X00, 0X00, 0X00, 0X06, 0X01, 0X19, 0X00, 0X00, 0X00, 0X00, 0X00, 0X41, 0X00, 0X73, 0X00, 0X73, 0X00, 0X69, 0X00, 0X67, 0X00, 0X6E, 0X00, 0X20, 0X00, 0X4D, 0X00, 0X61, 0X00, 0X72, 0X00, 0X6B, 0X00, 0X65, 0X00, 0X72, 0X00, 0X20, 0X00, 0X4E, 0X00, 0X61, 0X00, 0X6D, 0X00, 0X65, 0X00, 0X00, 0X00, 0X08, 0X00, 0X90, 0X01, 0X00, 0X01, 0X4D, 0X00, 0X53, 0X00, 0X20, 0X00, 0X53, 0X00, 0X68, 0X00, 0X65, 0X00, 0X6C, 0X00, 0X6C, 0X00, 0X20, 0X00, 0X44, 0X00, 0X6C, 0X00, 0X67, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X80, 0X10, 0X81, 0X50, 0X02, 0X00, 0X02, 0X00, 0XCA, 0X00, 0X15, 0X00, 0XF1, 0X03, 0X00, 0X00, 0XFF, 0XFF, 0X81, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X01, 0X00, 0X01, 0X50, 0XD0, 0X00, 0X04, 0X00, 0X32, 0X00, 0X0E, 0X00, 0X01, 0X00, 0X00, 0X00, 0XFF, 0XFF, 0X80, 0X00, 0X4F, 0X00, 0X4B, 0X00, 0X00, 0X00, 0X00, 0X00 }; InitModalIndirect((LPCDLGTEMPLATE)&DlgTempl, NULL); return CDialog::DoModal(); } void CXTPPromptDlg::OnOK() { if (GetDlgItem(1009)) GetDlgItem(1009)->GetWindowText(m_sName); CDialog::OnOK(); } BOOL CXTPPromptDlg::OnInitDialog() { CDialog::OnInitDialog(); if (GetDlgItem(1009)) GetDlgItem(1009)->SetWindowText(m_sName); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// XTPReportScrollMode CXTPReportControl::GetScrollMode(XTPReportOrientation orientation) const { XTPReportScrollMode scrollMode; switch(orientation) { case xtpReportOrientationHorizontal: scrollMode = m_scrollModeH; break; case xtpReportOrientationVertical: scrollMode = m_scrollModeV; break; default: scrollMode = xtpReportScrollModeNone; break; } return scrollMode; } void CXTPReportControl::SetScrollMode( XTPReportOrientation orientation, XTPReportScrollMode scrollMode) { switch(orientation) { case xtpReportOrientationHorizontal: m_scrollModeH = scrollMode; break; case xtpReportOrientationVertical: m_scrollModeV = scrollMode; break; case xtpReportOrientationAll: m_scrollModeH = scrollMode; m_scrollModeV = scrollMode; break; } AdjustScrollBars(); } void CXTPReportControl::SetGridStyle(BOOL bVertical, XTPReportGridStyle gridStyle) { m_pPaintManager->SetGridStyle(bVertical, gridStyle); AdjustScrollBars(); } XTPReportGridStyle CXTPReportControl::GetGridStyle(BOOL bVertical) const { return m_pPaintManager->GetGridStyle(bVertical); } COLORREF CXTPReportControl::SetGridColor(COLORREF clrGridLine) { return m_pPaintManager->SetGridColor(clrGridLine); } void CXTPReportControl::EnablePreviewMode(BOOL bIsPreviewMode) { m_pPaintManager->EnablePreviewMode(bIsPreviewMode); } BOOL CXTPReportControl::IsPreviewMode() const { return m_pPaintManager->IsPreviewMode(); } void CXTPReportControl::ShadeGroupHeadings(BOOL bEnable) { if (m_pPaintManager) m_pPaintManager->m_bShadeGroupHeadings = bEnable; AdjustScrollBars(); } BOOL CXTPReportControl::IsShadeGroupHeadingsEnabled() const { return m_pPaintManager ? m_pPaintManager->m_bShadeGroupHeadings : FALSE; } void CXTPReportControl::SetGroupRowsBold(BOOL bBold) { if (m_pPaintManager) m_pPaintManager->m_bGroupRowTextBold = bBold; } BOOL CXTPReportControl::IsGroupRowsBold() const { return m_pPaintManager ? m_pPaintManager->m_bGroupRowTextBold : FALSE; } ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// void CXTPReportControl::InitialSelectionEnable(BOOL bEnable) { m_bInitialSelectionEnable = bEnable; if (!m_bInitialSelectionEnable) m_pSelectedRows->Clear(); } CXTPReportSections *CXTPReportControl::GetSections() const { return m_pSections; }