DragonNest/Third/XTToolkitPro/Source/ReportControl/XTPReportRows.cpp

926 lines
21 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
// 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);
}