// 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; nColumnIsVisible() && (!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; nColumnIsVisible() && !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; nColumnIsVisible()) { 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); } } }