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++

// 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);
}
}
}