You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
548 lines
12 KiB
C++
548 lines
12 KiB
C++
// XTPReportColumns.cpp : implementation of the CXTPReportColumns 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/XTPPropExchange.h"
|
|
#include "Common/XTPCustomHeap.h"
|
|
#include "Common/XTPSystemHelpers.h"
|
|
#include "Common/XTPSmartPtrInternalT.h"
|
|
|
|
#include "XTPReportDefines.h"
|
|
#include "XTPReportControl.h"
|
|
#include "XTPReportHeader.h"
|
|
#include "XTPReportColumn.h"
|
|
#include "XTPReportColumns.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTPReportColumns
|
|
|
|
CXTPReportColumns::CXTPReportColumns(CXTPReportControl* pControl)
|
|
: m_pControl(pControl)
|
|
{
|
|
m_pGroupsOrder = new CXTPReportColumnOrder(this);
|
|
m_pSortOrder = new CXTPReportColumnOrder(this);
|
|
|
|
m_pTreeColumn = NULL;
|
|
|
|
}
|
|
|
|
CXTPReportColumns::~CXTPReportColumns()
|
|
{
|
|
Clear();
|
|
|
|
if (m_pGroupsOrder)
|
|
m_pGroupsOrder->InternalRelease();
|
|
if (m_pSortOrder)
|
|
m_pSortOrder->InternalRelease();
|
|
|
|
}
|
|
|
|
int CXTPReportColumns::GetAtOffset(int nOffset, BOOL bFrozen) const
|
|
{
|
|
int nIndex = -1;
|
|
int nLeft = 0;
|
|
|
|
for (int nColumn=0; nColumn<GetCount(); nColumn++)
|
|
{
|
|
const CXTPReportColumn *pColumn = GetAt(nColumn);
|
|
|
|
if (pColumn->IsVisible() && (!pColumn->IsFrozen() || bFrozen))
|
|
{
|
|
if (nOffset >= nLeft &&
|
|
nOffset <= nLeft+pColumn->GetWidth())
|
|
{
|
|
nIndex = nColumn;
|
|
}
|
|
|
|
nLeft += pColumn->GetWidth();
|
|
}
|
|
}
|
|
|
|
return nIndex;
|
|
}
|
|
|
|
int CXTPReportColumns::GetOffset(int nIndex) const
|
|
{
|
|
int nOffset = 0;
|
|
|
|
for (int nColumn=0; nColumn<GetCount(); nColumn++)
|
|
{
|
|
const CXTPReportColumn *pColumn = GetAt(nColumn);
|
|
|
|
if (pColumn->IsVisible() && !pColumn->IsFrozen() && (nIndex > 0))
|
|
{
|
|
nIndex -= 1;
|
|
nOffset += pColumn->GetWidth();
|
|
}
|
|
}
|
|
|
|
return nOffset;
|
|
}
|
|
|
|
|
|
void CXTPReportColumns::Clear()
|
|
{
|
|
// array cleanup
|
|
for (int nColumn = GetCount() - 1; nColumn >= 0; nColumn--)
|
|
{
|
|
CXTPReportColumn* pColumn = m_arrColumns.GetAt(nColumn);
|
|
if (pColumn)
|
|
pColumn->InternalRelease();
|
|
}
|
|
m_arrColumns.RemoveAll();
|
|
|
|
m_pSortOrder->Clear();
|
|
m_pGroupsOrder->Clear();
|
|
|
|
// clear variables which could be references to those values
|
|
if (m_pControl && (m_pControl->GetColumns() == this))
|
|
m_pControl->SetFocusedColumn(NULL);
|
|
}
|
|
|
|
int CXTPReportColumnOrder::GetCount() const
|
|
{
|
|
return (int) m_arrColumns.GetSize();
|
|
}
|
|
|
|
|
|
void CXTPReportColumns::Add(CXTPReportColumn* pColumn)
|
|
{
|
|
pColumn->m_pColumns = this;
|
|
m_arrColumns.Add(pColumn);
|
|
|
|
GetReportHeader()->OnColumnsChanged(xtpReportColumnOrderChanged | xtpReportColumnAdded, pColumn);
|
|
}
|
|
|
|
CXTPReportHeader* CXTPReportColumns::GetReportHeader() const
|
|
{
|
|
return m_pControl->GetReportHeader();
|
|
}
|
|
|
|
|
|
void CXTPReportColumns::Remove(CXTPReportColumn* pColumn)
|
|
{
|
|
m_pGroupsOrder->Remove(pColumn);
|
|
m_pSortOrder->Remove(pColumn);
|
|
|
|
int nIndex = IndexOf(pColumn);
|
|
if (nIndex != -1)
|
|
{
|
|
m_arrColumns.RemoveAt(nIndex);
|
|
pColumn->InternalRelease();
|
|
|
|
GetReportHeader()->OnColumnsChanged(xtpReportColumnOrderChanged | xtpReportColumnRemoved, pColumn);
|
|
}
|
|
}
|
|
|
|
int CXTPReportColumns::IndexOf(const CXTPReportColumn* pColumn) const
|
|
{
|
|
// array cleanup
|
|
for (int nColumn = GetCount() - 1; nColumn >= 0; nColumn--)
|
|
{
|
|
if (m_arrColumns.GetAt(nColumn) == pColumn)
|
|
return nColumn;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void CXTPReportColumns::ResetSortOrder()
|
|
{
|
|
m_pSortOrder->Clear();
|
|
}
|
|
|
|
void CXTPReportColumns::SetSortColumn(CXTPReportColumn* pColumn, BOOL bIncreasing)
|
|
{
|
|
ResetSortOrder();
|
|
m_pSortOrder->Add(pColumn, bIncreasing);
|
|
}
|
|
|
|
int CXTPReportColumns::ChangeColumnOrder(int nNewOrder, int nItemIndex)
|
|
{
|
|
if (nNewOrder < 0 || nItemIndex < 0)
|
|
return -1;
|
|
|
|
CXTPReportColumn* pColumn = GetAt(nItemIndex);
|
|
|
|
if (pColumn)
|
|
{
|
|
if (nNewOrder == nItemIndex)
|
|
return nNewOrder;
|
|
|
|
if (nNewOrder > nItemIndex)
|
|
nNewOrder--;
|
|
|
|
m_arrColumns.RemoveAt(nItemIndex);
|
|
m_arrColumns.InsertAt(nNewOrder, pColumn);
|
|
}
|
|
|
|
return nNewOrder;
|
|
}
|
|
|
|
int CXTPReportColumns::GetVisibleColumnsCount() const
|
|
{
|
|
int nCount = 0;
|
|
|
|
for (int nColumn=0; nColumn<GetCount(); nColumn++)
|
|
{
|
|
const CXTPReportColumn *pColumn = GetAt(nColumn);
|
|
|
|
if (NULL != pColumn && pColumn->IsVisible())
|
|
{
|
|
nCount++;
|
|
}
|
|
}
|
|
|
|
return nCount;
|
|
}
|
|
|
|
void CXTPReportColumns::GetVisibleColumns(CXTPReportColumns& arrColumns) const
|
|
{
|
|
int nCount = GetCount();
|
|
for (int nColumn = 0; nColumn < nCount; nColumn++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
if (pColumn && pColumn->IsVisible())
|
|
{
|
|
arrColumns.m_arrColumns.Add(pColumn);
|
|
pColumn->InternalAddRef();
|
|
}
|
|
}
|
|
}
|
|
|
|
CXTPReportColumn* CXTPReportColumns::Find(int nItemIndex) const
|
|
{
|
|
for (int nColumn = 0; nColumn < GetCount(); nColumn++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
if (pColumn->GetItemIndex() == nItemIndex)
|
|
return pColumn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CXTPReportColumn* CXTPReportColumns::Find(const CString& strInternalName) const
|
|
{
|
|
for (int nColumn = 0; nColumn < GetCount(); nColumn++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
if (pColumn->GetInternalName() == strInternalName)
|
|
return pColumn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CXTPReportColumns::InsertSortColumn(CXTPReportColumn* pColumn)
|
|
{
|
|
if (m_pSortOrder->IndexOf(pColumn) == -1)
|
|
m_pSortOrder->Add(pColumn);
|
|
}
|
|
|
|
CXTPReportColumn* CXTPReportColumns::GetVisibleAt(int nIndex) const
|
|
{
|
|
for (int nColumn = 0; nColumn < GetCount(); nColumn++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
if (!pColumn->IsVisible())
|
|
continue;
|
|
|
|
if (nIndex == 0)
|
|
return pColumn;
|
|
|
|
nIndex--;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CXTPReportColumn* CXTPReportColumns::GetFirstVisibleColumn() const
|
|
{
|
|
for (int nColumn = 0; nColumn < GetCount(); nColumn++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
if (pColumn->IsVisible())
|
|
return pColumn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CXTPReportColumn* CXTPReportColumns::GetLastVisibleColumn() const
|
|
{
|
|
for (int nColumn = GetCount() - 1; nColumn >= 0; nColumn--)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
if (pColumn->IsVisible())
|
|
return pColumn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void CXTPReportColumns::DoPropExchange(CXTPPropExchange* pPX)
|
|
{
|
|
int nItemIndex;
|
|
CString strInternalName;
|
|
|
|
if (pPX->IsStoring())
|
|
{
|
|
int nCount = GetCount();
|
|
|
|
CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Column")));
|
|
POSITION pos = pEnumerator->GetPosition(nCount, FALSE);
|
|
|
|
for (int nColumn = 0; nColumn < nCount; nColumn++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(nColumn);
|
|
CXTPPropExchangeSection secColumn(pEnumerator->GetNext(pos));
|
|
|
|
nItemIndex = pColumn->GetItemIndex();
|
|
strInternalName = pColumn->GetInternalName();
|
|
|
|
PX_Int(&secColumn, _T("ItemIndex"), nItemIndex);
|
|
PX_String(&secColumn, _T("InternalName"), strInternalName);
|
|
|
|
pColumn->DoPropExchange(&secColumn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Column")));
|
|
POSITION pos = pEnumerator->GetPosition(0, FALSE);
|
|
|
|
CXTPReportColumn tmpColumn(0, _T(""), 0);
|
|
int i = 0;
|
|
while (pos)
|
|
{
|
|
CXTPPropExchangeSection secColumn(pEnumerator->GetNext(pos));
|
|
|
|
CXTPReportColumn* pColumn = NULL;
|
|
PX_Int(&secColumn, _T("ItemIndex"), nItemIndex, -1);
|
|
|
|
if (pPX->GetSchema() > _XTP_SCHEMA_1100)
|
|
{
|
|
PX_String(&secColumn, _T("InternalName"), strInternalName);
|
|
|
|
if (!strInternalName.IsEmpty())
|
|
{
|
|
pColumn = Find(strInternalName);
|
|
|
|
if (!pColumn && pPX->GetSchema() < _XTP_SCHEMA_1500) // before 15.0 release internal name was equal to caption
|
|
{
|
|
for (int nColumn = 0; nColumn < GetCount(); nColumn++)
|
|
{
|
|
CXTPReportColumn* p = GetAt(nColumn);
|
|
if (p->GetCaption() == strInternalName)
|
|
{
|
|
pColumn = p;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// column data is exists but column is not in the collection.
|
|
if (!pColumn)
|
|
{
|
|
// just read data to skeep (to be safe for array serialization)
|
|
tmpColumn.DoPropExchange(&secColumn);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pColumn)
|
|
pColumn = Find(nItemIndex);
|
|
|
|
if (!pColumn)
|
|
AfxThrowArchiveException(CArchiveException::badIndex);
|
|
|
|
pColumn->DoPropExchange(&secColumn);
|
|
ChangeColumnOrder(i, IndexOf(pColumn));
|
|
i++;
|
|
}
|
|
}
|
|
|
|
CXTPPropExchangeSection secGroupsOrder(pPX->GetSection(_T("GroupsOrder")));
|
|
m_pGroupsOrder->DoPropExchange(&secGroupsOrder);
|
|
|
|
CXTPPropExchangeSection secSortOrder(pPX->GetSection(_T("SortOrder")));
|
|
m_pSortOrder->DoPropExchange(&secSortOrder);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CXTPReportColumnOrder
|
|
|
|
CXTPReportColumnOrder::CXTPReportColumnOrder(CXTPReportColumns* pColumns) :
|
|
m_pColumns(pColumns)
|
|
{
|
|
}
|
|
|
|
|
|
CXTPReportColumn* CXTPReportColumnOrder::GetAt(int nIndex)
|
|
{
|
|
if (nIndex >= 0 && nIndex < GetCount())
|
|
return m_arrColumns.GetAt(nIndex);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
int CXTPReportColumnOrder::InsertAt(int nIndex, CXTPReportColumn* pColumn)
|
|
{
|
|
if (nIndex < 0)
|
|
return -1;
|
|
|
|
if (nIndex >= GetCount())
|
|
nIndex = GetCount();
|
|
|
|
int nPrevIndex = IndexOf(pColumn);
|
|
|
|
if (nPrevIndex != -1)
|
|
{
|
|
if (nPrevIndex == nIndex)
|
|
return nIndex;
|
|
|
|
if (nIndex > nPrevIndex)
|
|
nIndex--;
|
|
|
|
if (nIndex == nPrevIndex)
|
|
return nIndex;
|
|
|
|
// change order
|
|
m_arrColumns.RemoveAt(nPrevIndex);
|
|
|
|
}
|
|
m_arrColumns.InsertAt(nIndex, pColumn);
|
|
return nIndex;
|
|
}
|
|
|
|
int CXTPReportColumnOrder::Add(CXTPReportColumn* pColumn, BOOL bSortIncreasing)
|
|
{
|
|
pColumn->m_bSortIncreasing = bSortIncreasing;
|
|
return (int) m_arrColumns.Add(pColumn);
|
|
}
|
|
|
|
int CXTPReportColumnOrder::Add(CXTPReportColumn* pColumn)
|
|
{
|
|
return (int) m_arrColumns.Add(pColumn);
|
|
}
|
|
|
|
void CXTPReportColumnOrder::Clear()
|
|
{
|
|
m_arrColumns.RemoveAll();
|
|
}
|
|
|
|
int CXTPReportColumnOrder::IndexOf(const CXTPReportColumn* pColumn)
|
|
{
|
|
int nCount = GetCount();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
if (GetAt(i) == pColumn)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void CXTPReportColumnOrder::RemoveAt(int nIndex)
|
|
{
|
|
if (nIndex >= 0 && nIndex < GetCount())
|
|
m_arrColumns.RemoveAt(nIndex);
|
|
}
|
|
|
|
void CXTPReportColumnOrder::Remove(CXTPReportColumn* pColumn)
|
|
{
|
|
int nCount = GetCount();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
if (GetAt(i) == pColumn)
|
|
{
|
|
m_arrColumns.RemoveAt(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXTPReportColumnOrder::DoPropExchange(CXTPPropExchange* pPX)
|
|
{
|
|
if (pPX->IsStoring())
|
|
{
|
|
int nCount = GetCount();
|
|
PX_Int(pPX, _T("Count"), nCount, 0);
|
|
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
CXTPReportColumn* pColumn = GetAt(i);
|
|
if (pColumn)
|
|
{
|
|
int nItemIndex = pColumn->GetItemIndex();
|
|
CString strInternalName = pColumn->GetInternalName();
|
|
CString strParamName;
|
|
|
|
strParamName.Format(_T("Column%i"), i);
|
|
PX_Int(pPX, strParamName, nItemIndex, 0);
|
|
|
|
strParamName.Format(_T("InternalName%i"), i);
|
|
PX_String(pPX, strParamName, strInternalName);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
|
|
int nCount = 0;
|
|
PX_Int(pPX, _T("Count"), nCount, 0);
|
|
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
int nItemIndex = 0;
|
|
CString strParamName;
|
|
strParamName.Format(_T("Column%i"), i);
|
|
PX_Int(pPX, strParamName, nItemIndex, 0);
|
|
|
|
CXTPReportColumn* pColumn = NULL;
|
|
if (pPX->GetSchema() > _XTP_SCHEMA_1100)
|
|
{
|
|
strParamName.Format(_T("InternalName%i"), i);
|
|
CString strInternalName;
|
|
PX_String(pPX, strParamName, strInternalName);
|
|
|
|
if (!strInternalName.IsEmpty())
|
|
pColumn = m_pColumns->Find(strInternalName);
|
|
}
|
|
if (!pColumn)
|
|
pColumn = m_pColumns->Find(nItemIndex);
|
|
|
|
if (pColumn)
|
|
Add(pColumn);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|