// XTPReportRows.cpp : implementation of the CXTPReportRows class. // // This file is a part of the XTREME REPORTCONTROL MFC class library. // (c)1998-2008 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/XTPVc50Helpers.h" #include "XTPReportRow.h" #include "XTPReportGroupRow.h" #include "XTPReportRecord.h" #include "XTPReportRecords.h" #include "XTPReportRecordItem.h" #include "XTPReportRecordItemText.h" #include "XTPReportControl.h" #include "XTPReportColumns.h" #include "XTPReportColumn.h" #include "XTPReportInplaceControls.h" #include "XTPReportRows.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ////////////////////////////////////////////////////////////////////////// // CXTPReportRows CXTPReportRows::CXTPReportRows() { m_pVirtualRow = 0; m_nVirtualRowsCount = 0; } CXTPReportRows::~CXTPReportRows() { Clear(); } ////////////////////////////////////////////////////////////////////////// // CXTPReportRows member functions void CXTPReportRows::Clear(BOOL bResetRow) { // array cleanup for (int nRow = (int)m_arrRows.GetSize() - 1; nRow >= 0; nRow--) { CXTPReportRow* pRow = m_arrRows.GetAt(nRow); if (bResetRow) { pRow->m_bVisible = FALSE; pRow->m_nIndex = -1; } pRow->InternalRelease(); } m_arrRows.RemoveAll(); if (m_pVirtualRow) { m_pVirtualRow->InternalRelease(); m_pVirtualRow = 0; } } CXTPReportRow* CXTPReportRows::GetNext(CXTPReportRow* pRow, BOOL bSkipGroupFocus) { if (pRow) { int index = pRow->GetIndex(); while (index < GetCount() - 1) { index++; pRow = GetAt(index); if (!bSkipGroupFocus || !pRow->IsGroupRow() || !pRow->IsExpanded()) return pRow; } } else if (GetCount() > 0) { return GetAt(0); } return pRow; } CXTPReportRow* CXTPReportRows::GetPrev(CXTPReportRow* pRow, BOOL bSkipGroupFocus) { if (pRow) { int index = pRow->GetIndex(); while (index > 0) { index--; pRow = GetAt(index); if (!bSkipGroupFocus || !pRow->IsGroupRow() || !pRow->IsExpanded()) return pRow; } } else if (GetCount() > 0) { return GetAt(0); } return pRow; } void CXTPReportRows::InsertAt(int nIndex, CXTPReportRow* pRow) { m_arrRows.InsertAt(nIndex, pRow); } int CXTPReportRows::Add(CXTPReportRow* pRow) { int nIndex = (int)m_arrRows.Add(pRow); pRow->m_nChildIndex = nIndex; pRow->m_pParentRows = this; return nIndex; } void CXTPReportRows::RemoveAt(int nIndex) { m_arrRows.GetAt(nIndex)->InternalRelease(); m_arrRows.RemoveAt(nIndex); } int CXTPReportRows::RemoveRow(CXTPReportRow* pRow) { for (int i = 0; i < (int)m_arrRows.GetSize(); i++) { if (m_arrRows.GetAt(i) == pRow) { RemoveAt(i); return i; } } return -1; } void CXTPReportRows::SetVirtualMode(CXTPReportRow* pRow, int nCount) { ASSERT(m_pVirtualRow == NULL); m_pVirtualRow = pRow; m_nVirtualRowsCount = nCount; } int _cdecl CXTPReportRows::CompareRows(const CXTPReportRow** ppRow1, const CXTPReportRow** ppRow2) { CXTPReportColumns* pColumns = (**ppRow1).GetControl()->GetColumns(); CXTPReportRecord* pRecord1 = (**ppRow1).GetRecord(); CXTPReportRecord* pRecord2 = (**ppRow2).GetRecord(); ASSERT(pColumns); ASSERT(pRecord1 && pRecord2 || !pRecord1 && !pRecord2); if (pRecord1 == pRecord2 && pRecord1) return 0; if (!pRecord1 && !pRecord2) { // compare groupRows by its first not group child rows if ((*ppRow1)->HasChildren() && (*ppRow2)->HasChildren()) { CXTPReportRow* pRow1a = (CXTPReportRow*)(*ppRow1); CXTPReportRow* pRow2a = (CXTPReportRow*)(*ppRow2); if (pRow1a->GetChilds() && pRow1a->GetChilds()->GetCount() && pRow2a->GetChilds() && pRow2a->GetChilds()->GetCount()) { pRow1a = pRow1a->GetChilds()->GetAt(0); pRow2a = pRow2a->GetChilds()->GetAt(0); return CompareRows((const CXTPReportRow**)&pRow1a, (const CXTPReportRow**)&pRow2a); } } } if (!pRecord1 || !pRecord2) { ASSERT(FALSE); return 0; } for (int nGroupOrder = 0; nGroupOrder < pColumns->GetGroupsOrder()->GetCount(); nGroupOrder++) { CXTPReportColumn* pColumn = pColumns->GetGroupsOrder()->GetAt(nGroupOrder); if (!pColumn->m_bAutoSortWhenGrouped) continue; BOOL bIncreasing = pColumn->m_bSortIncreasing; CXTPReportRecordItem* pItem1 = pRecord1->GetItem(pColumn); CXTPReportRecordItem* pItem2 = pRecord2->GetItem(pColumn); if (!pItem1 || !pItem2) continue; int nCompareResult = pItem1->CompareGroupCaption(pColumn, pItem2); if (nCompareResult != 0) return nCompareResult * (bIncreasing ? 1 : -1); } for (int nSortOrder = 0; nSortOrder < pColumns->GetSortOrder()->GetCount(); nSortOrder++) { CXTPReportColumn* pColumn = pColumns->GetSortOrder()->GetAt(nSortOrder); BOOL bIncreasing = pColumn->IsSortedIncreasing(); CXTPReportRecordItem* pItem1 = pRecord1->GetItem(pColumn); CXTPReportRecordItem* pItem2 = pRecord2->GetItem(pColumn); if (!pItem1 || !pItem2) continue; int nCompareResult = pItem1->Compare(pColumn, pItem2); if (nCompareResult != 0) return nCompareResult * (bIncreasing ? 1 : -1); } return pRecord1->GetIndex() > pRecord2->GetIndex() ? 1 : -1; } int _cdecl CXTPReportRows::CompareRows2(const CXTPReportRow** ppRow1, const CXTPReportRow** ppRow2) { CXTPReportColumns* pColumns = (**ppRow1).GetControl()->GetColumns(); CXTPReportRecord* pRecord1 = (**ppRow1).GetRecord(); CXTPReportRecord* pRecord2 = (**ppRow2).GetRecord(); ASSERT(pColumns); ASSERT(pRecord1 && pRecord2 || !pRecord1 && !pRecord2); if (pRecord1 == pRecord2 && pRecord1) return 0; if (!pRecord1 && !pRecord2) { // compare groupRows by its first not group child rows if ((*ppRow1)->HasChildren() && (*ppRow2)->HasChildren()) { CXTPReportRow* pRow1a = (CXTPReportRow*)(*ppRow1); CXTPReportRow* pRow2a = (CXTPReportRow*)(*ppRow2); if (pRow1a->GetChilds() && pRow1a->GetChilds()->GetCount() && pRow2a->GetChilds() && pRow2a->GetChilds()->GetCount()) { pRow1a = pRow1a->GetChilds()->GetAt(0); pRow2a = pRow2a->GetChilds()->GetAt(0); return CompareRows((const CXTPReportRow**)&pRow1a, (const CXTPReportRow**)&pRow2a); } } } if (!pRecord1 || !pRecord2) { ASSERT(FALSE); return 0; } for (int nGroupOrder = 0; nGroupOrder < pColumns->GetGroupsOrder()->GetCount(); nGroupOrder++) { CXTPReportColumn* pColumn = pColumns->GetGroupsOrder()->GetAt(nGroupOrder); if (!pColumn->m_bAutoSortWhenGrouped) continue; BOOL bIncreasing = pColumn->m_bSortIncreasing; CXTPReportRecordItem* pItem1 = pRecord1->GetItem(pColumn); CXTPReportRecordItem* pItem2 = pRecord2->GetItem(pColumn); if (!pItem1 || !pItem2) continue; int nCompareResult = pItem1->CompareGroupCaption(pColumn, pItem2); if (nCompareResult != 0) { if(nGroupOrder > 0) nCompareResult = bIncreasing ? -1 : 1; return nCompareResult * (bIncreasing ? 1 : -1); } } for (int nSortOrder = 0; nSortOrder < pColumns->GetSortOrder()->GetCount(); nSortOrder++) { CXTPReportColumn* pColumn = pColumns->GetSortOrder()->GetAt(nSortOrder); BOOL bIncreasing = pColumn->IsSortedIncreasing(); CXTPReportRecordItem* pItem1 = pRecord1->GetItem(pColumn); CXTPReportRecordItem* pItem2 = pRecord2->GetItem(pColumn); if (!pItem1 || !pItem2) continue; int nCompareResult = pItem1->Compare(pColumn, pItem2); if (nCompareResult != 0) return nCompareResult * (bIncreasing ? 1 : -1); } return 0; } void CXTPReportRows::SortEx(T_CompareFunc pCompareFunc) { typedef int (_cdecl *GENERICCOMPAREFUNC)(const void *, const void*); qsort(m_arrRows.GetData(), (size_t)m_arrRows.GetSize(), sizeof(CXTPReportRow*), (GENERICCOMPAREFUNC)pCompareFunc); } void CXTPReportRows::Sort() { SortEx(CompareRows); } int CXTPReportRows::GetCount() const { if (m_pVirtualRow) return m_nVirtualRowsCount; return (int)m_arrRows.GetSize(); } CXTPReportRow* CXTPReportRows::GetAt(int nIndex) const { if (m_pVirtualRow) { m_pVirtualRow->m_nIndex = nIndex; return m_pVirtualRow; } return (nIndex >= 0) && (nIndex < GetCount()) ? m_arrRows.GetAt(nIndex) : NULL; } CXTPReportRow* CXTPReportRows::Find(CXTPReportRecord* pRecord) { for (int i = 0; i < (int)m_arrRows.GetSize(); i++) { if (m_arrRows.GetAt(i)->GetRecord() == pRecord) return m_arrRows.GetAt(i); } return 0; } CXTPReportRow* CXTPReportRows::FindInTree(CXTPReportRecord* pRecord) { for (int i = 0; i < (int)m_arrRows.GetSize(); i++) { if (m_arrRows.GetAt(i)->GetRecord() == pRecord) return m_arrRows.GetAt(i); if (m_arrRows.GetAt(i)->HasChildren()) { CXTPReportRow* pRow = m_arrRows.GetAt(i)->GetChilds()->FindInTree(pRecord); if (pRow) return pRow; } } return 0; } CXTPReportRow* CXTPReportRows::FindInsertionPos(CXTPReportRow* pRow, BOOL& bInsertAfter) { CXTPReportRow* pInsertionRowPos = NULL; bInsertAfter = FALSE; for(int i = 0; i < (int)m_arrRows.GetSize(); i++) { CXTPReportRow* pCurRow = m_arrRows.GetAt(i); if(pCurRow->IsGroupRow()) { // compare group caption CXTPReportRecord* pRecord = pRow->GetRecord(); CXTPReportColumns* pColumns = pRow->GetControl()->GetColumns(); if(!(pRecord && pColumns)) continue; CXTPReportColumn* pColumn = pColumns->GetGroupsOrder()->GetAt(pCurRow->GetGroupLevel()); CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn); COleVariant varGroup(pItem ? (LPCTSTR)pItem->GetGroupCaption(pColumn) : _T("")); COleVariant varGroupRowCaption((LPCTSTR)((CXTPReportGroupRow*)pCurRow)->GetCaption()); ULONG dwFlags = pRecord->GetRecords()->IsCaseSensitive() ? 0 : NORM_IGNORECASE; LCID lcidnSortLocale = CXTPReportRecordItemVariant::m_nSortLocale; if (lcidnSortLocale == LOCALE_USER_DEFAULT) { lcidnSortLocale = CXTPReportControlLocale::GetActiveLCID(); } int nCompareResult = VARCMP_S(varGroup, varGroupRowCaption, lcidnSortLocale, dwFlags) - VARCMP_EQ; if(pColumn->m_bSortIncreasing && nCompareResult > 0 || !pColumn->m_bSortIncreasing && nCompareResult < 0) continue; // find in children if(!pCurRow->GetChilds()) continue; if(nCompareResult == 0) pInsertionRowPos = pCurRow->GetChilds()->FindInsertionPos(pRow, bInsertAfter); if(!pInsertionRowPos) { if(nCompareResult != 0) pInsertionRowPos = pCurRow; else { pInsertionRowPos = pCurRow->GetChilds()->GetAt(pCurRow->GetChilds()->GetCount() - 1); bInsertAfter = TRUE; } } break; } if(CompareRows2((const CXTPReportRow**)&pRow, (const CXTPReportRow**)&pCurRow) <= 0) { pInsertionRowPos = pCurRow; break; } } return pInsertionRowPos; } void CXTPReportRows::RefreshChildIndices(BOOL bRunInChildren) { for(int nIndex = 0; nIndex < GetCount(); nIndex++) { CXTPReportRow* pRow = GetAt(nIndex); pRow->m_nChildIndex = nIndex; ASSERT(pRow->m_pParentRows == this); if(bRunInChildren && pRow->HasChildren() && pRow->GetChilds()) pRow->GetChilds()->RefreshChildIndices(bRunInChildren); } } void CXTPReportRows::SetSize(INT_PTR nNewSize, INT_PTR nGrowBy) { int nSize = GetCount(); if (nNewSize < nSize) { for (int i = (int)nNewSize; i < nSize; i++) { CXTPReportRow* pRow = GetAt(i); if (pRow) pRow->InternalRelease(); } } m_arrRows.SetSize(nNewSize, nGrowBy); } void CXTPReportRows::ReserveSize(INT_PTR nNewSize, INT_PTR nGrowBy) { m_arrRows.ReserveSize(nNewSize, nGrowBy); } void CXTPReportRows::SetAt(INT_PTR nIndex, CXTPReportRow* pRow) { ASSERT(pRow); ASSERT(nIndex >= 0 && nIndex < GetCount()); if (!pRow || nIndex < 0 || nIndex >= GetCount()) return; CXTPReportRow* pRow_prev = GetAt((int)nIndex); if (pRow_prev) pRow_prev->InternalRelease(); pRow->m_nChildIndex = (int)nIndex; pRow->m_pParentRows = this; m_arrRows.SetAt(nIndex, pRow); } ////////////////////////////////////////////////////////////////////////// // CXTPReportSelectedRows CXTPReportSelectedRows::CXTPReportSelectedRows(CXTPReportControl* pControl) : m_pControl(pControl) { m_nRowBlockBegin = -1; m_nPosSelected = 0; m_bChanged = FALSE; m_nRowType = xtpRowTypeBody; } void CXTPReportSelectedRows::Clear() { if (m_arrSelectedBlocks.GetSize() > 0) { m_bChanged = TRUE; _NotifySelChanging(xtpReportSelectionClear); } m_arrSelectedBlocks.RemoveAll(); m_nRowBlockBegin = -1; m_nRowType = xtpRowTypeBody; m_pControl->RedrawControl(); } void CXTPReportSelectedRows::_InsertBlock(int nIndexInsert, int nIndexBegin, int nIndexEnd) { SELECTED_BLOCK block; block.nIndexBegin = nIndexBegin; block.nIndexEnd = nIndexEnd; m_arrSelectedBlocks.InsertAt(nIndexInsert, block); } void CXTPReportSelectedRows::_OnCollapsed(int nIndex, int nCount) { ASSERT(nCount > 0); for (int i = (int)m_arrSelectedBlocks.GetSize() - 1; i >= 0 ; i--) { int& nIndexBegin = m_arrSelectedBlocks[i].nIndexBegin; int& nIndexEnd = m_arrSelectedBlocks[i].nIndexEnd; if (nIndexBegin <= nIndex && nIndexEnd > nIndex + 1) { nIndexEnd = max(nIndexBegin + 1, nIndexEnd - nCount); } else if (nIndexBegin > nIndex + nCount) { nIndexBegin -= nCount; nIndexEnd -= nCount; } else if (nIndexEnd < nIndex) break; else if (nIndexBegin > nIndex) { nIndexBegin = nIndex; nIndexEnd = max(nIndexBegin + 1, nIndexEnd - nCount); } } } void CXTPReportSelectedRows::_OnExpanded(int nIndex, int nCount) { ASSERT(nCount > 0); for (int i = (int)m_arrSelectedBlocks.GetSize() - 1; i >= 0 ; i--) { int& nIndexBegin = m_arrSelectedBlocks[i].nIndexBegin; int& nIndexEnd = m_arrSelectedBlocks[i].nIndexEnd; if (nIndexBegin <= nIndex && nIndexEnd > nIndex + 1) { _InsertBlock(i + 1, nIndex + 1 + nCount, nIndexEnd + nCount); m_arrSelectedBlocks[i].nIndexEnd = nIndex + 1; } else if (nIndexBegin > nIndex) { nIndexBegin += nCount; nIndexEnd += nCount; } else if (nIndexEnd < nIndex) break; } } void CXTPReportSelectedRows::AddBlock(int ib, int ie) { int i = 0; int nCount = (int)m_arrSelectedBlocks.GetSize(); if (nCount > 0) { int& nIndexEnd = m_arrSelectedBlocks[nCount - 1].nIndexEnd; if (nIndexEnd == ib) { nIndexEnd = ie + 1; m_pControl->RedrawControl(); return; } if (nIndexEnd < ib) { i = nCount; } } for (; i < nCount; i++) { int& nIndexBegin = m_arrSelectedBlocks[i].nIndexBegin; int& nIndexEnd = m_arrSelectedBlocks[i].nIndexEnd; if ((nIndexBegin <= ib) && (nIndexEnd > ie)) { return; } if (nIndexEnd == ib) { nIndexEnd = ie + 1; if (i + 1 < nCount && m_arrSelectedBlocks[i + 1].nIndexBegin == nIndexEnd) { nIndexEnd = m_arrSelectedBlocks[i + 1].nIndexEnd; m_arrSelectedBlocks.RemoveAt(i + 1); } m_pControl->RedrawControl(); return; } if (nIndexBegin == ie + 1) { nIndexBegin = ib; m_pControl->RedrawControl(); return; } if (nIndexBegin > ie) break; } _InsertBlock(i, ib, ie + 1); m_pControl->RedrawControl(); } void CXTPReportSelectedRows::Add(CXTPReportRow* pRow) { if (!pRow) return; _NotifySelChanging(xtpReportSelectionAdd, pRow); int nIndex = pRow->GetIndex(); if (nIndex != -1) { AddBlock(nIndex, nIndex); } } void CXTPReportSelectedRows::Remove(CXTPReportRow* pRow) { if (!pRow) return; _NotifySelChanging(xtpReportSelectionRemove, pRow); int nIndex = pRow->GetIndex(); for (int i = 0; i < (int)m_arrSelectedBlocks.GetSize(); i++) { int nIndexBegin = m_arrSelectedBlocks[i].nIndexBegin; int nIndexEnd = m_arrSelectedBlocks[i].nIndexEnd; if ((nIndexBegin <= nIndex) && (nIndexEnd > nIndex)) { if (nIndexBegin != nIndex) { _InsertBlock(i, nIndexBegin, nIndex); i++; } if (nIndexEnd - 1 != nIndex) { _InsertBlock(i + 1, nIndex + 1, nIndexEnd); } m_arrSelectedBlocks.RemoveAt(i); m_pControl->RedrawControl(); return; } } } void CXTPReportSelectedRows::Select(CXTPReportRow* pRow) { if (!pRow) return; // If new selected row belongs to the other type - clear previous selection. if (m_nRowType != pRow->GetType()) Clear(); if (m_arrSelectedBlocks.GetSize() == 1 && m_arrSelectedBlocks[0].nIndexBegin == m_arrSelectedBlocks[0].nIndexEnd - 1 && m_arrSelectedBlocks[0].nIndexBegin == pRow->GetIndex()) { } else { Clear(); Add(pRow); m_bChanged = TRUE; m_nRowType = pRow->GetType(); } } void CXTPReportSelectedRows::SelectBlock(int nBlockBegin, int nEnd) { CXTPReportRows* pRows; switch(m_nRowType) { case xtpRowTypeHeader : pRows = m_pControl->GetHeaderRows(); break; case xtpRowTypeFooter : pRows = m_pControl->GetFooterRows(); break; default : pRows = m_pControl->GetRows(); break; } ASSERT(nBlockBegin >= 0 && nBlockBegin < pRows->GetCount() && nEnd < pRows->GetCount() ); nBlockBegin = m_nRowBlockBegin != -1 ? m_nRowBlockBegin : nBlockBegin; int nBegin = nBlockBegin; if (nBegin == -1 || nEnd == -1) return; if (nBegin > nEnd) { nBegin = nEnd; nEnd = nBlockBegin; } if (m_arrSelectedBlocks.GetSize() == 1 && m_arrSelectedBlocks[0].nIndexBegin == nBegin && m_arrSelectedBlocks[0].nIndexEnd == nEnd + 1) { return; } XTPReportRowType nRowType = m_nRowType; Clear(); m_nRowType = nRowType; if (m_nRowBlockBegin == -1) m_nRowBlockBegin = nBlockBegin; BOOL bSkipGroupFocus = m_pControl->IsSkipGroupsFocusEnabled(); BOOL bHasGroups = m_pControl->GetColumns()->GetGroupsOrder()->GetCount() != 0; if (!bHasGroups || !bSkipGroupFocus) { _InsertBlock(0, nBegin, nEnd + 1); } else { for (int i = nBegin; i <= nEnd; i++) { CXTPReportRow* pRow = pRows->GetAt(i); if (!pRow) continue; if (!bSkipGroupFocus || !pRow->IsGroupRow() || !pRow->IsExpanded() || (i == nBegin) || (i == nEnd)) { Add(pRow); } } } } BOOL CXTPReportSelectedRows::Contains(const CXTPReportRow* pRow) { if (!pRow) return FALSE; if (m_nRowType != pRow->GetType()) return FALSE; int nIndex = pRow->GetIndex(); int nCount = (int)m_arrSelectedBlocks.GetSize(); if (nCount == 0) return FALSE; if (m_arrSelectedBlocks[0].nIndexBegin > nIndex) return FALSE; if (m_arrSelectedBlocks[nCount - 1].nIndexEnd <= nIndex) return FALSE; for (int i = 0; i < nCount; i++) { if ((m_arrSelectedBlocks[i].nIndexBegin <= nIndex) && (m_arrSelectedBlocks[i].nIndexEnd > nIndex)) { return TRUE; } } return FALSE; } void CXTPReportSelectedRows::Invert(CXTPReportRow* pRow) { if(pRow->GetType() != m_nRowType) return; if (Contains(pRow)) Remove (pRow); else Add(pRow); m_nRowBlockBegin = -1; m_bChanged = TRUE; } int CXTPReportSelectedRows::GetCount() { int nCount = 0; for (int i = 0; i < (int)m_arrSelectedBlocks.GetSize(); i++) { nCount += m_arrSelectedBlocks[i].nIndexEnd - m_arrSelectedBlocks[i].nIndexBegin; } return nCount; } POSITION CXTPReportSelectedRows::GetFirstSelectedRowPosition() { if (m_arrSelectedBlocks.GetSize() == 0) return 0; m_nPosSelected = 0; POSITION pos = 0; pos = (POSITION)(DWORD_PTR)(m_arrSelectedBlocks[0].nIndexBegin + 1); return pos; } CXTPReportRow* CXTPReportSelectedRows::GetNextSelectedRow(POSITION& pos) { ASSERT(m_nPosSelected < m_arrSelectedBlocks.GetSize()); int nIndex = (int)(DWORD_PTR)pos - 1; CXTPReportRow* pRow; switch(m_nRowType) { case xtpRowTypeHeader : pRow = m_pControl->GetHeaderRows()->GetAt(nIndex); break; case xtpRowTypeFooter : pRow = m_pControl->GetFooterRows()->GetAt(nIndex); break; default : pRow = m_pControl->GetRows()->GetAt(nIndex); break; } if (nIndex < m_arrSelectedBlocks[m_nPosSelected].nIndexEnd - 1) { (int)(DWORD_PTR)pos++; } else { if (m_nPosSelected >= m_arrSelectedBlocks.GetSize() - 1) { pos = NULL; } else { m_nPosSelected++; pos = (POSITION)(DWORD_PTR)(m_arrSelectedBlocks[m_nPosSelected].nIndexBegin + 1); } } return pRow; } CXTPReportRow* CXTPReportSelectedRows::GetAt (int nIndex) { for (int i = 0; i < (int)m_arrSelectedBlocks.GetSize(); i++) { int nCount = m_arrSelectedBlocks[i].nIndexEnd - m_arrSelectedBlocks[i].nIndexBegin; if (nCount <= nIndex) { nIndex -= nCount; continue; } CXTPReportRow* pRow; switch(m_nRowType) { case xtpRowTypeHeader : pRow = m_pControl->GetHeaderRows()->GetAt(m_arrSelectedBlocks[i].nIndexBegin + nIndex); break; case xtpRowTypeFooter : pRow = m_pControl->GetFooterRows()->GetAt(m_arrSelectedBlocks[i].nIndexBegin + nIndex); break; default : pRow = m_pControl->GetRows()->GetAt(m_arrSelectedBlocks[i].nIndexBegin + nIndex); break; } return pRow; } return 0; } void CXTPReportSelectedRows::_NotifySelChanging(XTPReportSelectionChangeType nType, CXTPReportRow* pRow) { ASSERT(m_pControl); if (!m_pControl) return; XTP_NM_SELECTION_CHANGING nm; ::ZeroMemory(&nm, sizeof(nm)); nm.pRow = pRow; nm.nType = nType; m_pControl->SendNotifyMessage(XTP_NM_REPORT_SELCHANGING,(NMHDR*)&nm); }