DragonNest/Third/XTToolkitPro/Source/ReportControl/XTPReportRow.cpp
2024-12-19 09:48:26 +08:00

1034 lines
25 KiB
C++

// XTPReportRow.cpp : implementation of the CXTPReportRow 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 "Resource.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPToolTipContext.h"
#include "XTPReportRecord.h"
#include "XTPReportControl.h"
#include "XTPReportPaintManager.h"
#include "XTPReportRow.h"
#include "XTPReportColumns.h"
#include "XTPReportColumn.h"
#include "XTPReportRecordItem.h"
#include "XTPReportRecordItemText.h"
#include "XTPReportTip.h"
#include "XTPReportInplaceControls.h"
#include "XTPReportHeader.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CXTPReportRow, CCmdTarget)
/////////////////////////////////////////////////////////////////////////////
// CXTPReportRow
CXTPReportRow::CXTPReportRow()
: m_pParentRow(NULL), m_pRecord(NULL), m_pControl(NULL), m_pParentRows(NULL)
{
m_nGroupLevel = m_nRowLevel = 0;
m_bVisible = FALSE;
m_pChilds = NULL;
m_bExpanded = TRUE;
m_rcRow.SetRectEmpty();
m_rcCollapse.SetRectEmpty();
m_nChildIndex = m_nIndex = -1;
m_nPreviewHeight = 0;
m_nRowType = xtpRowTypeBody;
}
void CXTPReportRow::InitRow(CXTPReportControl* pControl, CXTPReportRecord* pRecord)
{
ASSERT(pRecord || IsGroupRow());
m_pControl = pControl;
if (pRecord)
{
m_pRecord = pRecord;
m_bExpanded = pRecord->m_bExpanded;
m_pRecord->InternalAddRef();
}
}
void CXTPReportRow::InitRow(CXTPReportRow* pRow)
{
ASSERT(pRow->m_pRecord);
ASSERT(pRow->m_pParentRow == NULL);
m_pControl = pRow->m_pControl;
m_pRecord = pRow->m_pRecord;
if (m_pRecord) m_pRecord->InternalAddRef();
m_rcRow = pRow->m_rcRow;
m_nIndex = pRow->m_nIndex;
m_nPreviewHeight = pRow->m_nPreviewHeight;
m_nRowLevel = pRow->m_nRowLevel;
m_nGroupLevel = pRow->m_nGroupLevel;
}
CXTPReportRows* CXTPReportRow::GetChilds()
{
if (!m_pChilds)
{
m_pChilds = new CXTPReportRows();
}
return m_pChilds;
}
CXTPReportRow::~CXTPReportRow()
{
if (m_pChilds)
{
m_pChilds->InternalRelease();
}
if (m_pRecord)
{
m_pRecord->InternalRelease();
}
}
int CXTPReportRow::GetHeight(CDC* pDC, int nWidth)
{
ASSERT(m_pControl);
if (!m_pControl)
return 0;
int nHeight = m_pControl->GetPaintManager()->GetRowHeight(pDC, this, nWidth);
if (!IsGroupRow() && !IsItemsVisible())
nHeight = 0;
if (pDC->IsPrinting())
return nHeight;
m_nPreviewHeight = 0;
if (IsPreviewVisible())
{
CXTPReportRecordItemPreview* pItem = GetRecord()->GetItemPreview();
m_nPreviewHeight = pItem->GetPreviewHeight(pDC, this, m_pControl->GetReportHeader()->GetWidth());
m_nPreviewHeight = m_pControl->GetPaintManager()->GetPreviewItemHeight(pDC, this, m_pControl->GetReportHeader()->GetWidth(), m_nPreviewHeight);
return nHeight + m_nPreviewHeight;
}
return nHeight;
}
BOOL CXTPReportRow::IsFocused() const
{
switch(m_nRowType)
{
case xtpRowTypeBody:
return m_pControl->m_nFocusedRow == m_nIndex;
case xtpRowTypeHeader:
return m_pControl->m_nFocusedHeaderRow == m_nIndex;
case xtpRowTypeFooter:
return m_pControl->m_nFocusedFooterRow == m_nIndex;
}
return FALSE;
}
BOOL CXTPReportRow::IsSelected() const
{
return m_pControl->GetSelectedRows()->Contains(this);
}
void CXTPReportRow::SetSelected(BOOL bSelected)
{
if (bSelected)
{
if (!m_pControl->IsMultipleSelection())
m_pControl->GetSelectedRows()->Clear();
m_pControl->GetSelectedRows()->Add(this);
}
else
{
m_pControl->GetSelectedRows()->Remove(this);
}
m_pControl->RedrawControl();
}
int CXTPReportRow::GetLastChildRow(CXTPReportRows* pChilds) const
{
CXTPReportRow* pRow = pChilds->GetAt(pChilds->GetCount() - 1);
return pRow->HasChildren() && pRow->IsExpanded() ? GetLastChildRow(pRow->GetChilds()) : pRow->GetIndex();
}
void CXTPReportRow::SelectChilds()
{
if (!(m_pControl->IsMultipleSelection() && HasChildren() && IsExpanded() && m_nIndex != -1))
return;
m_pControl->BeginUpdate();
int nIndexBegin = m_nIndex + 1;
int nIndexEnd = GetLastChildRow(GetChilds());
m_pControl->GetSelectedRows()->AddBlock(nIndexBegin, nIndexEnd);
m_pControl->EndUpdate();
}
BOOL CXTPReportRow::IsItemsVisible() const
{
return TRUE;
}
BOOL CXTPReportRow::IsPreviewVisible() const
{
return !IsGroupRow() && m_pRecord && m_pControl->IsPreviewMode() && m_pRecord->GetItemPreview() != NULL;
}
void CXTPReportRow::Draw(CDC* pDC, CRect rcRow, int nLeftOffset)
{
ASSERT(m_pControl);
if (!m_pControl)
return;
BOOL bControlFocused = m_pControl->HasFocus();
int nFreezeCols = m_pControl->m_nFreezeColumnsCount;
CRect rcClipBox = m_pControl->GetReportRectangle();
m_rcRow = rcRow;
m_rcRow.left -= nLeftOffset;
m_rcRow.right -= nLeftOffset;
if (nFreezeCols == 0)
{
rcRow = m_rcRow;
}
XTP_REPORTRECORDITEM_DRAWARGS drawArgs;
drawArgs.pDC = pDC;
drawArgs.pControl = m_pControl;
drawArgs.pRow = this;
int nIndentWidth = m_pControl->GetHeaderIndent();
CXTPReportPaintManager* pPaintManager = m_pControl->GetPaintManager();
CXTPReportColumns arrVisibleColumns(m_pControl);
m_pControl->GetColumns()->GetVisibleColumns(arrVisibleColumns);
int nVisColCount = arrVisibleColumns.GetCount();
nFreezeCols = min(nFreezeCols, nVisColCount);
// paint row background
pPaintManager->FillRow(pDC, this, m_rcRow);
CRect rcItem(m_rcRow.left, m_rcRow.top, m_rcRow.right, m_rcRow.bottom - m_nPreviewHeight);
CRect rcIndent(nFreezeCols ? rcRow : m_rcRow);
rcIndent.right = rcIndent.left + nIndentWidth;
if (m_pRecord) // if drawing record, not group
{
int xMinCol_0 = rcRow.left + nIndentWidth;
// paint record items
for (int nColumn = nVisColCount-1; nColumn >= 0; nColumn--)
{
BOOL bFreezeCol = nColumn < nFreezeCols;
int nColIdx = bFreezeCol ? nFreezeCols - 1 - nColumn : nColumn;
CXTPReportColumn* pColumn = arrVisibleColumns.GetAt(nColIdx);
ASSERT(pColumn && pColumn->IsVisible());
if (pColumn && IsItemsVisible())
{
rcItem.left = pColumn->GetRect().left;
if (nColIdx == 0)
{
rcItem.left = max(xMinCol_0, rcItem.left);
}
rcItem.right = pColumn->GetRect().right;
if (!CRect().IntersectRect(rcClipBox, rcItem))
continue;
if (bFreezeCol)
{
pDC->FillSolidRect(rcItem, pPaintManager->GetControlBackColor(GetControl()));
pPaintManager->FillRow(pDC, this, rcItem);
}
CRect rcGridItem(rcItem);
rcGridItem.left--;
// draw shade background if sorted by this row
if (pColumn->IsSorted())
{
pPaintManager->FillItemShade(pDC, rcItem);
}
CXTPReportRecordItem* pItem = m_pRecord->GetItem(pColumn);
if (pItem)
{
// draw item
drawArgs.pColumn = pColumn;
drawArgs.rcItem = rcItem;
drawArgs.nTextAlign = pColumn->GetAlignment();
drawArgs.pItem = pItem;
// draw item
int nItemTextWidth = pItem->Draw(&drawArgs);
pColumn->m_nMaxItemWidth = max(pColumn->m_nMaxItemWidth, nItemTextWidth);
}
pPaintManager->DrawGrid(pDC, TRUE, rcGridItem);
if (nColIdx == nFreezeCols - 1)
pPaintManager->DrawFreezeColsDivider(pDC, rcGridItem, GetControl(), this);
}
}
if (IsPreviewVisible())
{
CRect rcPreviewItem(m_rcRow);
rcPreviewItem.DeflateRect(nIndentWidth, rcPreviewItem.Height() - m_nPreviewHeight, 0, 0);
drawArgs.rcItem = rcPreviewItem;
drawArgs.nTextAlign = DT_LEFT;
drawArgs.pItem = m_pRecord->GetItemPreview();
drawArgs.pColumn = NULL;
drawArgs.pItem->Draw(&drawArgs);
}
if (nIndentWidth > 0)
{
// draw indent column
pPaintManager->FillIndent(pDC, rcIndent);
}
}
BOOL bGridVisible = pPaintManager->IsGridVisible(FALSE);
//CRect rcFocus(m_rcRow.left + nIndentWidth, m_rcRow.top, m_rcRow.right, m_rcRow.bottom - (bGridVisible ? 1 : 0));
CRect rcFocus(rcIndent.right, m_rcRow.top, m_rcRow.right, m_rcRow.bottom - (bGridVisible ? 1 : 0));
if (IsFocused() && bControlFocused && m_pControl->IsRowFocusVisible())
pPaintManager->DrawFocusedRow(pDC, rcFocus);
if (m_nIndex < m_pControl->GetRows()->GetCount() - 1 && nIndentWidth > 0)
{
CXTPReportRow* pNextRow = m_pControl->GetRows()->GetAt(m_nIndex + 1);
ASSERT(pNextRow);
if (pNextRow) rcFocus.left = rcIndent.left + min(nIndentWidth, pPaintManager->m_nTreeIndent * pNextRow->GetTreeDepth());
}
else
{
rcFocus.left = m_rcRow.left;
}
pPaintManager->DrawGrid(pDC, FALSE, rcFocus);
}
int CXTPReportRow::GetTreeDepth() const
{
return m_nRowLevel;
}
INT_PTR CXTPReportRow::OnToolHitTest(CPoint point, TOOLINFO* pTI)
{
CRect rcItem;
CXTPReportRecordItem* pItem = HitTest(point, &rcItem);
if (!pItem)
return -1;
INT_PTR nHit = (INT_PTR)pItem;
CString strTip = pItem->GetTooltip();
m_pControl->OnGetToolTipInfo(this, pItem, strTip);
if (strTip.IsEmpty() || strTip == _T(" "))
return -1;
CXTPToolTipContext::FillInToolInfo(pTI, m_pControl->m_hWnd, rcItem,
nHit, strTip);
return nHit;
}
BOOL CXTPReportRow::OnLButtonDown(XTP_REPORTRECORDITEM_CLICKARGS* pClickArgs)
{
if(pClickArgs->pItem && pClickArgs->pItem->OnLButtonDown(pClickArgs))
return TRUE;
return (BOOL)m_pControl->SendMessageToParent(this, pClickArgs->pItem, pClickArgs->pColumn, XTP_NM_REPORT_LBUTTONDOWN, &pClickArgs->ptClient);
}
BOOL CXTPReportRow::OnLButtonUp(XTP_REPORTRECORDITEM_CLICKARGS* pClickArgs)
{
if(pClickArgs->pItem)
pClickArgs->pItem->OnLButtonUp(pClickArgs);
return TRUE;
}
void CXTPReportRow::OnClick(CPoint ptClicked)
{
XTP_REPORTRECORDITEM_CLICKARGS clickArgs;
clickArgs.pControl = m_pControl;
clickArgs.pRow = this;
clickArgs.ptClient = ptClicked;
clickArgs.pColumn = NULL;
// find clicked item
clickArgs.pItem = HitTest(ptClicked, &clickArgs.rcItem, &clickArgs.pColumn);
if(m_pControl->IsVirtualMode())
{
if (m_nRowLevel == 0 && m_rcCollapse.PtInRect(ptClicked)
&& clickArgs.pColumn && clickArgs.pColumn->IsTreeColumn())
{
m_pControl->SendMessageToParent(this, NULL, NULL, XTP_NM_REPORT_ROWEXPANDED, NULL);
return;
}
}
if (HasChildren() && m_rcCollapse.PtInRect(ptClicked)
&& clickArgs.pColumn && clickArgs.pColumn->IsTreeColumn())
{
SetExpanded(!IsExpanded());
return;
}
// notify item if found
if (!clickArgs.pItem)
return;
clickArgs.pItem->OnClick(&clickArgs);
}
void CXTPReportRow::OnDblClick(CPoint ptClicked)
{
XTP_REPORTRECORDITEM_CLICKARGS clickArgs;
clickArgs.pControl = m_pControl;
clickArgs.pRow = this;
clickArgs.ptClient = ptClicked;
clickArgs.pColumn = NULL;
// find clicked item
clickArgs.pItem = HitTest(ptClicked, &clickArgs.rcItem, &clickArgs.pColumn);
// notify item if found
if (clickArgs.pItem != NULL)
{
clickArgs.pItem->OnDblClick(&clickArgs);
}
else
{
// just notify parent
m_pControl->SendMessageToParent(this, NULL, clickArgs.pColumn, NM_DBLCLK, &ptClicked, -1);
}
}
CRect CXTPReportRow::GetItemRect(CXTPReportRecordItem* pItem)
{
if (!IsItemsVisible() || !pItem || !m_pRecord)
return CRect(0, 0, 0, 0);
if (IsPreviewVisible() && pItem == GetRecord()->GetItemPreview())
{
return CRect(m_rcRow.left + m_pControl->GetHeaderIndent(),
m_rcRow.bottom - m_nPreviewHeight, m_rcRow.right, m_rcRow.bottom);
}
CXTPReportColumns* pColumns = m_pControl->GetColumns();
int nColumnCount = pColumns->GetCount();
CRect rcItem(0, m_rcRow.top, 0, m_rcRow.bottom - m_nPreviewHeight);
int nFreezeColCount = m_pControl->GetFreezeColumnsCount();
int nLeft = nFreezeColCount ? pColumns->GetAt(nFreezeColCount - 1)->GetRect().right : 0;
for (int nColumn = 0; nColumn < nColumnCount; nColumn++)
{
CXTPReportColumn* pColumn = pColumns->GetAt(nColumn);
if (pColumn && pColumn->IsVisible())
{
if (m_pRecord->GetItem(pColumn) != pItem)
continue;
rcItem.left = pColumn->GetRect().left;
rcItem.right = pColumn->GetRect().right;
if(pColumn->GetIndex() >= nFreezeColCount)
{
rcItem.left = max(rcItem.left, nLeft);
rcItem.right = max(rcItem.right, nLeft);
}
if(rcItem.Width() <= 0)
return CRect(0, 0, 0, 0);
ShiftTreeIndent(rcItem, pColumn);
return rcItem;
}
}
return CRect(0, 0, 0, 0);
}
void CXTPReportRow::ShiftTreeIndent(CRect& rcItem, CXTPReportColumn* pColumn) const
{
if (pColumn->IsTreeColumn())
{
int nTreeDepth = GetTreeDepth() - m_nGroupLevel;
if (nTreeDepth > 0)
nTreeDepth++;
rcItem.left += m_pControl->GetIndent(nTreeDepth);
CRect rcBitmap(rcItem);
int nIndent = m_pControl->GetPaintManager()->DrawCollapsedBitmap(NULL, this, rcBitmap).cx;
rcItem.left += nIndent + 1;
}
}
CXTPReportRecordItem* CXTPReportRow::HitTest(CPoint ptPoint, CRect* pRectItem, CXTPReportColumn** ppColumn) const
{
if (!m_pRecord)
return NULL;
// find record item
int x = m_rcRow.left + m_pControl->GetHeaderIndent();
CXTPReportColumns* pColumns = m_pControl->GetColumns();
int nColumnCount = pColumns->GetCount();
// if hittes for Preview item
if (IsPreviewVisible())
{
CXTPReportRecordItemPreview* pPreviewItem = GetRecord()->GetItemPreview();
if (pPreviewItem)
{
CRect rcItem(x, m_rcRow.bottom - m_nPreviewHeight, m_rcRow.right, m_rcRow.bottom);
if (rcItem.PtInRect(ptPoint))
{
if (pRectItem)
{
*pRectItem = rcItem;
}
return pPreviewItem;
}
}
}
CRect rcItem(0, m_rcRow.top, 0, m_rcRow.bottom - m_nPreviewHeight);
if (!IsItemsVisible())
return NULL;
int nFreezeColCount = m_pControl->GetFreezeColumnsCount();
int nLeft = nFreezeColCount ? pColumns->GetAt(nFreezeColCount - 1)->GetRect().right : 0;
for (int nColumn = 0; nColumn < nColumnCount; nColumn++)
{
CXTPReportColumn* pColumn = pColumns->GetAt(nColumn);
if (pColumn && pColumn->IsVisible())
{
rcItem.left = pColumn->GetRect().left;
rcItem.right = pColumn->GetRect().right;
if(pColumn->GetIndex() >= nFreezeColCount)
{
rcItem.left = max(rcItem.left, nLeft);
rcItem.right = max(rcItem.right, nLeft);
}
if(!rcItem.Width())
continue;
if (rcItem.PtInRect(ptPoint) && ppColumn)
{
*ppColumn = pColumn;
}
// make tooltip shift if tree view (see also Draw function)
ShiftTreeIndent(rcItem, pColumn);
// check point
if (rcItem.PtInRect(ptPoint))
{
if (pRectItem)
{
*pRectItem = rcItem;
}
return m_pRecord->GetItem(pColumn);
}
}
}
return NULL;
}
void CXTPReportRow::OnMouseMove(UINT nFlags, CPoint point)
{
// find clicked item
CRect rcItem;
CXTPReportRecordItem* pItem = HitTest(point, &rcItem);
// notify item if found
if (pItem != NULL)
{
pItem->OnMouseMove(nFlags, point, m_pControl);
}
}
void CXTPReportRow::FillMetrics(CXTPReportColumn* pColumn, CXTPReportRecordItem* pItem, XTP_REPORTRECORDITEM_METRICS* pMetrics)
{
m_pControl->m_nLockUpdateCount++;
XTP_REPORTRECORDITEM_DRAWARGS drawArgs;
drawArgs.pDC = NULL;
drawArgs.pColumn = pColumn;
drawArgs.pControl = m_pControl;
drawArgs.pRow = this;
drawArgs.rcItem.SetRectEmpty();
drawArgs.pItem = pItem;
drawArgs.nTextAlign = pColumn ? pColumn->GetAlignment() : DT_LEFT;
GetItemMetrics(&drawArgs, pMetrics);
m_pControl->m_nLockUpdateCount--;
}
void CXTPReportRow::ShowToolTip(CPoint ptTip, CXTPReportTip* pTipWnd)
{
CRect rcItem(0, 0, 0, 0);
CXTPReportColumn* pColumn = NULL;
CXTPReportRecordItem* pItem = HitTest(ptTip, &rcItem, &pColumn);
// show tooltip
if (!(pItem && (pItem->IsPreviewItem() || !pItem->IsPreviewItem() && pColumn)))
{
pTipWnd->m_pItem = NULL;
pTipWnd->m_nRowIndex = -1;
return;
}
if (!CXTPDrawHelpers::IsTopParentActive(m_pControl->GetSafeHwnd()) || m_pControl->GetActiveItem())
{
return;
}
if ((pItem != pTipWnd->m_pItem) || (m_nIndex != pTipWnd->m_nRowIndex))
{
pTipWnd->m_pItem = pItem;
pTipWnd->m_nRowIndex = m_nIndex;
CString strTip = pItem->GetTooltip();
m_pControl->OnGetToolTipInfo(this, pItem, strTip);
if (!strTip.IsEmpty() || strTip == _T(" ") || pColumn && (pColumn->GetAlignment() & DT_WORDBREAK))
return;
if (pItem->GetMarkupUIElement() != 0)
return;
XTP_REPORTRECORDITEM_METRICS* pMetrics = new XTP_REPORTRECORDITEM_METRICS();
pMetrics->strText = pItem->GetCaption(pColumn);
FillMetrics(pColumn, pItem, pMetrics);
CString strText(pMetrics->strText);
strText.TrimRight();
if (strText.IsEmpty())
{
pMetrics->InternalRelease();
return;
}
XTP_REPORTRECORDITEM_ARGS itemArgs;
itemArgs.pControl = m_pControl;
itemArgs.pRow = this;
pItem->GetCaptionRect(&itemArgs, rcItem);
m_pControl->ClientToScreen(&rcItem);
if (!pTipWnd->GetSafeHwnd())
{
pTipWnd->Create(m_pControl);
}
CWindowDC dc(m_pControl);
CXTPFontDC font(&dc, pMetrics->pFont);
CRect rcTooltip(rcItem);
BOOL bActivate = FALSE;
if (pItem->IsPreviewItem())
{
CRect rcCalc(rcTooltip.left, 0, rcTooltip.right, 0);
dc.DrawText(strText, rcCalc, DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
bActivate = (rcCalc.Height() / dc.GetTextExtent(_T(" "), 1).cy) > m_pControl->GetPaintManager()->GetMaxPreviewLines();
rcTooltip.bottom = rcTooltip.top + rcCalc.Height();
rcTooltip.right++;
}
else
{
CSize sz = dc.GetTextExtent(strText);
bActivate = sz.cx > (rcTooltip.Width() - 4);
}
if (bActivate)
{
rcTooltip.InflateRect(1, 1, 0, 0);
pTipWnd->SetFont(pMetrics->pFont);
pTipWnd->SetTooltipText(strText);
pTipWnd->SetHoverRect(rcTooltip);
pTipWnd->Activate(TRUE, pItem->IsPreviewItem());
TRACKMOUSEEVENT tme =
{
sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_pControl->GetSafeHwnd(), 0
};
_TrackMouseEvent (&tme);
}
pMetrics->InternalRelease();
}
}
BOOL CXTPReportRow::HasParent(CXTPReportRow* pRow)
{
if (m_pParentRow == NULL)
return FALSE;
if (pRow == m_pParentRow)
return TRUE;
return m_pParentRow->HasParent(pRow);
}
void CXTPReportRow::SetExpanded(BOOL bExpanded)
{
if (bExpanded != m_bExpanded && HasChildren())
{
if (bExpanded)
{
m_pControl->_DoExpand(this);
}
else
{
m_pControl->_DoCollapse(this);
}
if (m_pRecord)
{
m_pRecord->m_bExpanded = bExpanded;
}
m_bExpanded = bExpanded;
m_pControl->_RefreshIndexes();
m_pControl->SendMessageToParent(this, NULL, NULL, XTP_NM_REPORT_ROWEXPANDED, NULL);
}
else
{
m_bExpanded = bExpanded;
}
}
CXTPReportRow* CXTPReportRow::AddChild(CXTPReportRow* pRow)
{
GetChilds()->Add(pRow);
pRow->m_pParentRow = this;
return pRow;
}
void CXTPReportRow::OnContextMenu(CPoint ptClick)
{
CXTPReportColumn* pColumn = NULL;
CXTPReportRecordItem* pItem = HitTest(ptClick, NULL, &pColumn);
m_pControl->ClientToScreen(&ptClick);
// send process notification to the user and wait for the reaction
m_pControl->SendMessageToParent(this, pItem, pColumn, NM_RCLICK, &ptClick);
}
void CXTPReportRow::GetItemMetrics(XTP_REPORTRECORDITEM_DRAWARGS* pDrawArgs, XTP_REPORTRECORDITEM_METRICS* pItemMetrics)
{
ASSERT(m_pRecord);
ASSERT(pDrawArgs->pRow == this);
ASSERT(pDrawArgs->pItem != NULL);
if (!m_pRecord || !pDrawArgs->pItem)
return;
CXTPReportPaintManager* pPaintManager = pDrawArgs->pControl->GetPaintManager();
pItemMetrics->pFont = &pPaintManager->m_fontText;
pItemMetrics->clrForeground = pPaintManager->m_clrWindowText;
pItemMetrics->clrBackground = XTP_REPORT_COLOR_DEFAULT;
pItemMetrics->nColumnAlignment = pDrawArgs->nTextAlign;
pItemMetrics->nItemIcon = XTP_REPORT_NOICON;
m_pRecord->GetItemMetrics(pDrawArgs, pItemMetrics);
pDrawArgs->pItem->GetItemMetrics(pDrawArgs, pItemMetrics);
m_pControl->GetItemMetrics(pDrawArgs, pItemMetrics);
pDrawArgs->nTextAlign = pItemMetrics->nColumnAlignment;
if (IsSelected() && (pDrawArgs->pDC && !pDrawArgs->pDC->IsPrinting()))
{
if (pDrawArgs->pColumn && IsFocused() && m_pControl->m_pFocusedColumn == pDrawArgs->pColumn)
return;
if (GetControl()->HasFocus())
{
pItemMetrics->clrForeground = pPaintManager->m_clrHighlightText;
pItemMetrics->clrBackground = pPaintManager->m_clrHighlight;
}
else if (!pPaintManager->m_bHideSelection)
{
pItemMetrics->clrForeground = pPaintManager->m_clrSelectedRowText;
pItemMetrics->clrBackground = pPaintManager->m_clrSelectedRow;
}
}
}
BOOL CXTPReportRow::HasChildren() const
{
return m_pChilds && m_pChilds->GetCount() > 0;
}
int CXTPReportRow::GetIndex() const
{
return m_nIndex;
}
BOOL CXTPReportRow::IsGroupRow() const
{
return FALSE;
}
BOOL CXTPReportRow::IsExpanded() const
{
return m_bExpanded;
}
BOOL CXTPReportRow::IsLastTreeRow() const
{
if (!m_pParentRow)
return FALSE;
CXTPReportRows* pRows = m_pParentRow->GetChilds();
return pRows->GetCount() > 0 && pRows->GetAt(pRows->GetCount() - 1) == this;
}
void CXTPReportRow::EnsureVisible()
{
m_pControl->EnsureVisible(this);
}
CXTPReportRow* CXTPReportRow::GetNextSiblingRow() const
{
if (!m_pParentRows)
return 0;
if (m_nChildIndex == -1)
return 0;
ASSERT(m_pParentRows->GetAt(m_nChildIndex) == this);
if (m_nChildIndex < m_pParentRows->GetCount() - 1)
return m_pParentRows->GetAt(m_nChildIndex + 1);
return 0;
}
void CXTPReportRow::DrawFixed(CDC* pDC, CRect rcRow, int nLeftOffset, CRect rcArea)
{
ASSERT(m_pControl);
if (!m_pControl)
return;
// BOOL bControlFocused = m_pControl->HasFocus();
int nFreezeCols = m_pControl->m_nFreezeColumnsCount;
CRect rcClipBox = rcArea ;
m_rcRow = rcRow;
m_rcRow.left -= nLeftOffset;
m_rcRow.right -= nLeftOffset;
if (nFreezeCols == 0)
{
rcRow = m_rcRow;
}
XTP_REPORTRECORDITEM_DRAWARGS drawArgs;
drawArgs.pDC = pDC;
drawArgs.pControl = m_pControl;
drawArgs.pRow = this;
int nIndentWidth = m_pControl->GetHeaderIndent();
CXTPReportPaintManager* pPaintManager = m_pControl->GetPaintManager();
// whether to draw header's last horizontal grid depends on header divider style.
BOOL bDrawLastHeaderGrid = TRUE;
if (GetType() == xtpRowTypeHeader)
{
bDrawLastHeaderGrid = xtpReportFixedRowsDividerNone == (pPaintManager->GetHeaderRowsDividerStyle() & ~xtpReportFixedRowsDividerShade);
}
// whether to draw footer's first horizontal grid depends on footer divider style.
BOOL bDrawFirstFooterGrid = TRUE;
if (GetType() == xtpRowTypeFooter)
{
bDrawFirstFooterGrid = xtpReportFixedRowsDividerNone == (pPaintManager->GetFooterRowsDividerStyle() & ~xtpReportFixedRowsDividerShade);
}
CXTPReportColumns arrVisibleColumns(m_pControl);
m_pControl->GetColumns()->GetVisibleColumns(arrVisibleColumns);
int nVisColCount = arrVisibleColumns.GetCount();
nFreezeCols = min(nFreezeCols, nVisColCount);
// paint row background
pDC->FillSolidRect(m_rcRow, pPaintManager->GetControlBackColor(GetControl()));
CRect rcItem(m_rcRow.left, m_rcRow.top, m_rcRow.right, m_rcRow.bottom - m_nPreviewHeight);
CRect rcIndent(nFreezeCols ? rcRow : m_rcRow);
rcIndent.right = rcIndent.left + nIndentWidth;
if (m_pRecord) // if drawing record, not group
{
int xMinCol_0 = rcRow.left + nIndentWidth;
// paint record items
for (int nColumn = nVisColCount-1; nColumn >= 0; nColumn--)
{
BOOL bFreezeCol = nColumn < nFreezeCols;
int nColIdx = bFreezeCol ? nFreezeCols - 1 - nColumn : nColumn;
CXTPReportColumn* pColumn = arrVisibleColumns.GetAt(nColIdx);
ASSERT(pColumn && pColumn->IsVisible());
if (pColumn && IsItemsVisible())
{
rcItem.left = pColumn->GetRect().left;
if (nColIdx == 0)
{
rcItem.left = max(xMinCol_0, rcItem.left);
}
rcItem.right = pColumn->GetRect().right;
if (!CRect().IntersectRect(rcClipBox, rcItem))
continue;
if (bFreezeCol)
{
pDC->FillSolidRect(rcItem, pPaintManager->GetControlBackColor(GetControl()));
pPaintManager->FillRow(pDC, this, rcItem);
}
CRect rcGridItem(rcItem);
rcGridItem.left--;
// draw shade background if sorted by this row
if (pColumn->IsSorted())
{
pPaintManager->FillItemShade(pDC, rcItem);
}
CXTPReportRecordItem* pItem = m_pRecord->GetItem(pColumn);
if (pItem)
{
// draw item
drawArgs.pColumn = pColumn;
drawArgs.rcItem = rcItem;
drawArgs.nTextAlign = pColumn->GetAlignment();
drawArgs.pItem = pItem;
// draw item
int nItemTextWidth = pItem->Draw(&drawArgs);
pColumn->m_nMaxItemWidth = max(pColumn->m_nMaxItemWidth, nItemTextWidth);
}
// is vertical grid required
if (GetType() == xtpRowTypeHeader)
{
if (pColumn->GetDrawHeaderRowsVGrid())
pPaintManager->DrawGrid(pDC, TRUE, rcGridItem);
}
else
if (GetType() == xtpRowTypeFooter)
{
if (pColumn->GetDrawFooterRowsVGrid())
pPaintManager->DrawGrid(pDC, TRUE, rcGridItem);
}
if (bDrawFirstFooterGrid)
{
// horizontal grid above
CRect rcTop(rcGridItem);
rcTop.bottom = --rcGridItem.top;
pPaintManager->DrawGrid(pDC, FALSE, rcTop);
}
bDrawFirstFooterGrid = TRUE;
if (nColIdx == nFreezeCols - 1)
pPaintManager->DrawFreezeColsDivider(pDC, rcGridItem, GetControl(), this);
}
}
if (nIndentWidth > 0)
{
// draw indent column
pPaintManager->FillIndent(pDC, rcIndent);
}
}
// draw focus
BOOL bControlFocused = m_pControl->HasFocus();
BOOL bGridVisible = pPaintManager->IsGridVisible(FALSE);
CRect rcFocus(rcIndent.right, m_rcRow.top, m_rcRow.right, m_rcRow.bottom - (bGridVisible ? 1 : 0));
if (IsFocused() && bControlFocused && m_pControl->IsRowFocusVisible())
pPaintManager->DrawFocusedRow(pDC, rcFocus);
// last header grid line
if (bDrawLastHeaderGrid)
{
pPaintManager->DrawGrid(pDC, FALSE, rcFocus);
}
}