5666 lines
132 KiB
C++
5666 lines
132 KiB
C++
|
|
// XTPReportControl.cpp : implementation of the CXTPReportControl 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/XTPSystemHelpers.h"
|
||
|
|
#include "Common/XTPImageManager.h"
|
||
|
|
#include "Common/XTPVC80Helpers.h"
|
||
|
|
#include "Common/XTPVC50Helpers.h"
|
||
|
|
#include "Common/XTPPropExchange.h"
|
||
|
|
#include "Common/XTPToolTipContext.h"
|
||
|
|
#include "Common/XTPResourceManager.h"
|
||
|
|
|
||
|
|
#include "XTPReportRecordItem.h"
|
||
|
|
#include "XTPReportRecordItemText.h"
|
||
|
|
#include "XTPReportRecord.h"
|
||
|
|
#include "XTPReportRecords.h"
|
||
|
|
#include "XTPReportHeader.h"
|
||
|
|
#include "XTPReportColumn.h"
|
||
|
|
#include "XTPReportColumns.h"
|
||
|
|
#include "XTPReportRow.h"
|
||
|
|
#include "XTPReportRows.h"
|
||
|
|
#include "XTPReportControl.h"
|
||
|
|
#include "XTPReportPaintManager.h"
|
||
|
|
#include "XTPReportNavigator.h"
|
||
|
|
#include "XTPReportFilterEditControl.h"
|
||
|
|
#include "XTPReportSubListControl.h"
|
||
|
|
#include "XTPReportGroupRow.h"
|
||
|
|
#include "XTPReportInplaceControls.h"
|
||
|
|
#include "XTPReportRecordItemControls.h"
|
||
|
|
|
||
|
|
#include <locale.h>
|
||
|
|
|
||
|
|
#ifdef _DEBUG
|
||
|
|
#define new DEBUG_NEW
|
||
|
|
#undef THIS_FILE
|
||
|
|
static char THIS_FILE[] = __FILE__;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define XTP_REPORT_HSCROLL_STEP 7
|
||
|
|
|
||
|
|
#define XTP_REPORT_AUTO_SCROLL_TIMER_ID 7
|
||
|
|
#define XTP_REPORT_AUTO_SCROLL_TIMER_RESOLUTION_MS 200
|
||
|
|
|
||
|
|
#define XTP_REPORT_CB_RECORDS_DATA_VER 1
|
||
|
|
|
||
|
|
#define ASSERT_DBG_REMOVE_RECORD_EX
|
||
|
|
//#define XTP_DBG_REMOVE_RECORD_EX_ASSERT ASSERT
|
||
|
|
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportDataAllocator, FALSE)
|
||
|
|
XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator, FALSE)
|
||
|
|
|
||
|
|
// to allocate in app default heap
|
||
|
|
XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportAllocatorDefault, FALSE)
|
||
|
|
|
||
|
|
|
||
|
|
class CXTPReportRow_Batch : public CXTPBatchAllocObjT<CXTPReportRow, CXTPReportRow_BatchData> {};
|
||
|
|
class CXTPReportGroupRow_Batch : public CXTPBatchAllocObjT<CXTPReportGroupRow, CXTPReportGroupRow_BatchData> {};
|
||
|
|
|
||
|
|
XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CXTPReportRow_BatchData, CXTPReportRow_Batch, FALSE)
|
||
|
|
XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CXTPReportGroupRow_BatchData, CXTPReportGroupRow_Batch, FALSE)
|
||
|
|
|
||
|
|
//===========================================================================
|
||
|
|
BOOL CXTPReportControl::UseReportCustomHeap()
|
||
|
|
{
|
||
|
|
ASSERT(CXTPReportDataAllocator::ms_dwRefs == 0 || CXTPReportDataAllocator::ms_bUseCustomHeap);
|
||
|
|
ASSERT(CXTPReportRowAllocator::ms_dwRefs == 0 || CXTPReportRowAllocator::ms_bUseCustomHeap);
|
||
|
|
|
||
|
|
if (CXTPReportDataAllocator::ms_dwRefs == 0)
|
||
|
|
CXTPReportDataAllocator::ms_bUseCustomHeap = TRUE;
|
||
|
|
|
||
|
|
if (CXTPReportRowAllocator::ms_dwRefs == 0)
|
||
|
|
CXTPReportRowAllocator::ms_bUseCustomHeap = TRUE;
|
||
|
|
|
||
|
|
return CXTPReportDataAllocator::ms_bUseCustomHeap &&
|
||
|
|
CXTPReportRowAllocator::ms_bUseCustomHeap;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::UseRowBatchAllocation()
|
||
|
|
{
|
||
|
|
ASSERT(CXTPReportRow_BatchData::IsDataEmpty() || CXTPReportRow_BatchData::m_bBatchAllocationEnabled);
|
||
|
|
ASSERT(CXTPReportGroupRow_BatchData::IsDataEmpty() || CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled);
|
||
|
|
|
||
|
|
if (CXTPReportRow_BatchData::IsDataEmpty())
|
||
|
|
CXTPReportRow_BatchData::m_bBatchAllocationEnabled = TRUE;
|
||
|
|
|
||
|
|
if (CXTPReportGroupRow_BatchData::IsDataEmpty())
|
||
|
|
CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled = TRUE;
|
||
|
|
|
||
|
|
return CXTPReportRow_BatchData::m_bBatchAllocationEnabled &&
|
||
|
|
CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::FreeRowBatchExtraData()
|
||
|
|
{
|
||
|
|
CXTPReportRow_Batch::FreeExtraData();
|
||
|
|
CXTPReportGroupRow_Batch::FreeExtraData();
|
||
|
|
}
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
BOOL CXTPReportControlLocale::s_bUseResourceFileLocale = FALSE;
|
||
|
|
|
||
|
|
CArray<CXTPReportControlLocale::XTP_TIMESPEC, CXTPReportControlLocale::XTP_TIMESPEC&>
|
||
|
|
CXTPReportControlLocale::s_arMappedSpecs;
|
||
|
|
|
||
|
|
//===========================================================================
|
||
|
|
BOOL CXTPReportControlLocale::IsUseResourceFileLocale()
|
||
|
|
{
|
||
|
|
return s_bUseResourceFileLocale;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::SetUseResourceFileLocale(BOOL bUseResourceFileLocale)
|
||
|
|
{
|
||
|
|
s_bUseResourceFileLocale = bUseResourceFileLocale;
|
||
|
|
}
|
||
|
|
|
||
|
|
LCID CXTPReportControlLocale::GetActiveLCID()
|
||
|
|
{
|
||
|
|
LCID lcidCurr = LOCALE_USER_DEFAULT;
|
||
|
|
|
||
|
|
if (s_bUseResourceFileLocale)
|
||
|
|
lcidCurr = MAKELCID(XTPResourceManager()->GetResourcesLangID(), SORT_DEFAULT);
|
||
|
|
|
||
|
|
return lcidCurr;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL AFX_CDECL CXTPReportControlLocale::VariantChangeTypeEx(VARIANT& rVarValue, VARTYPE vartype, BOOL bThrowError)
|
||
|
|
{
|
||
|
|
if (vartype != rVarValue.vt)
|
||
|
|
{
|
||
|
|
LCID lcID = GetActiveLCID();
|
||
|
|
|
||
|
|
HRESULT hr = ::VariantChangeTypeEx(&rVarValue, &rVarValue, lcID, 0, vartype);
|
||
|
|
|
||
|
|
if (bThrowError && FAILED(hr))
|
||
|
|
{
|
||
|
|
if (hr == E_OUTOFMEMORY)
|
||
|
|
AfxThrowMemoryException();
|
||
|
|
else
|
||
|
|
AfxThrowOleException(hr);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
return SUCCEEDED(hr);
|
||
|
|
}
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CString AFX_CDECL CXTPReportControlLocale::FormatDateTime(const COleDateTime& dt, LPCTSTR lpcszFormatString)
|
||
|
|
{
|
||
|
|
return _FormatDateTime(dt, lpcszFormatString, GetActiveLCID());
|
||
|
|
}
|
||
|
|
|
||
|
|
CString CXTPReportControlLocale::_FormatDateTime(const COleDateTime& dt, LPCTSTR lpcszFormatString, LCID lcLocaleID)
|
||
|
|
{
|
||
|
|
if (dt.GetStatus() != COleDateTime::valid)
|
||
|
|
{
|
||
|
|
ASSERT(dt.GetStatus() == COleDateTime::null);
|
||
|
|
return _T("");
|
||
|
|
}
|
||
|
|
|
||
|
|
CString strDT = lpcszFormatString;
|
||
|
|
|
||
|
|
SYSTEMTIME sysTime;
|
||
|
|
if (!GETASSYSTEMTIME_DT(dt, sysTime))
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return _T("");
|
||
|
|
}
|
||
|
|
|
||
|
|
// %% Percent sign
|
||
|
|
REPLACE_S(strDT, _T("%%"), _T("\0x1"));
|
||
|
|
|
||
|
|
_ProcessMappedSpecs(strDT, &sysTime, lcLocaleID);
|
||
|
|
_ProcessDateTimeSpecs(strDT, &sysTime, lcLocaleID);
|
||
|
|
|
||
|
|
// All locale dependent specifiers already processed
|
||
|
|
_ProcessOtherSpecs(strDT, dt);
|
||
|
|
|
||
|
|
REPLACE_S(strDT, _T("\0x1"), _T("%"));
|
||
|
|
|
||
|
|
return strDT;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::_ProcessMappedSpecs(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
|
||
|
|
{
|
||
|
|
_InitMappedSpecs();
|
||
|
|
|
||
|
|
const int cnBufferSize = 96;
|
||
|
|
TCHAR szBuffer[cnBufferSize];
|
||
|
|
|
||
|
|
int nCount = (int)s_arMappedSpecs.GetSize();
|
||
|
|
for (int i = 0; i < nCount; i++)
|
||
|
|
{
|
||
|
|
const XTP_TIMESPEC& specI = s_arMappedSpecs.ElementAt(i);
|
||
|
|
if (FIND_S(rstrFormat, specI.pcszSpec, 0) < 0)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
::ZeroMemory(szBuffer, sizeof(szBuffer));
|
||
|
|
|
||
|
|
int nResult;
|
||
|
|
if (specI.bTime)
|
||
|
|
{
|
||
|
|
nResult = ::GetTimeFormat(lcLocaleID, 0, pST, specI.pcszFormat, szBuffer, cnBufferSize);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
nResult = ::GetDateFormat(lcLocaleID, 0, pST, specI.pcszFormat, szBuffer, cnBufferSize);
|
||
|
|
}
|
||
|
|
ASSERT(nResult);
|
||
|
|
if (nResult)
|
||
|
|
{
|
||
|
|
REPLACE_S(rstrFormat, specI.pcszSpec, szBuffer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::_ProcessDateTimeSpecs(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
|
||
|
|
{
|
||
|
|
// %c Date and time representation appropriate for locale
|
||
|
|
// %#c Long date and time representation
|
||
|
|
|
||
|
|
// %x Date representation for current locale
|
||
|
|
// %#x Long date representation for current locale
|
||
|
|
|
||
|
|
// %X Time representation for current locale
|
||
|
|
|
||
|
|
REPLACE_S(rstrFormat, _T("%c"), _T("%x %X"));
|
||
|
|
REPLACE_S(rstrFormat, _T("%#c"), _T("%#x %X"));
|
||
|
|
|
||
|
|
__ProcessDate_x(rstrFormat, pST, lcLocaleID);
|
||
|
|
__ProcessTime_X(rstrFormat, pST, lcLocaleID);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::__ProcessDate_x(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
|
||
|
|
{
|
||
|
|
const int cnBufferSize = 96;
|
||
|
|
TCHAR szBuffer[cnBufferSize];
|
||
|
|
|
||
|
|
// %x Date representation for current locale
|
||
|
|
// %#x Long date representation for current locale
|
||
|
|
|
||
|
|
TCHAR* arSpec2[2] = {_T("%x"), _T("%#x")};
|
||
|
|
|
||
|
|
for (int i = 0; i < 2; i++)
|
||
|
|
{
|
||
|
|
if (FIND_S(rstrFormat, arSpec2[i], 0) >= 0)
|
||
|
|
{
|
||
|
|
::ZeroMemory(szBuffer, sizeof(szBuffer));
|
||
|
|
|
||
|
|
DWORD dwFlags = (i == 0) ? DATE_SHORTDATE : DATE_LONGDATE;
|
||
|
|
|
||
|
|
int nRes = ::GetDateFormat(lcLocaleID, dwFlags, pST, NULL, szBuffer, cnBufferSize);
|
||
|
|
|
||
|
|
ASSERT(nRes);
|
||
|
|
REPLACE_S(rstrFormat, arSpec2[i], szBuffer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::__ProcessTime_X(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
|
||
|
|
{
|
||
|
|
if (FIND_S(rstrFormat, _T("%X"), 0) >= 0)
|
||
|
|
{
|
||
|
|
const int cnBufferSize = 96;
|
||
|
|
TCHAR szBuffer[cnBufferSize];
|
||
|
|
|
||
|
|
::ZeroMemory(szBuffer, sizeof(szBuffer));
|
||
|
|
int nRes = ::GetTimeFormat(lcLocaleID, 0, pST, NULL, szBuffer, cnBufferSize);
|
||
|
|
|
||
|
|
ASSERT(nRes);
|
||
|
|
REPLACE_S(rstrFormat, _T("%X"), szBuffer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::_ProcessOtherSpecs(CString& rstrFormat, const COleDateTime& dt)
|
||
|
|
{
|
||
|
|
// %j Day of year as decimal number (001 - 366)
|
||
|
|
// %w Weekday as decimal number (0 - 6; Sunday is 0)
|
||
|
|
// %U Week of year as decimal number, with Sunday as first day of week (00 - 53)
|
||
|
|
// %W Week of year as decimal number, with Monday as first day of week (00 - 53)
|
||
|
|
// %z, %Z Either the time-zone name or time zone abbreviation, depending on registry settings; no characters if time zone is unknown
|
||
|
|
|
||
|
|
static LPCTSTR arszSpecs[] = { _T("%j"), _T("%#j"),
|
||
|
|
_T("%w"), _T("%#w"),
|
||
|
|
_T("%U"), _T("%#U"),
|
||
|
|
_T("%W"), _T("%#W"),
|
||
|
|
_T("%z"), _T("%Z") };
|
||
|
|
|
||
|
|
int nCount = _countof(arszSpecs);
|
||
|
|
for (int i = 0; i < nCount; i++)
|
||
|
|
{
|
||
|
|
if (FIND_S(rstrFormat, arszSpecs[i], 0) < 0)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
CString str = dt.Format(arszSpecs[i]);
|
||
|
|
|
||
|
|
REPLACE_S(rstrFormat, arszSpecs[i], str);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::_InitMappedSpecs()
|
||
|
|
{
|
||
|
|
if (s_arMappedSpecs.GetSize())
|
||
|
|
return;
|
||
|
|
|
||
|
|
// date
|
||
|
|
_AddsMappedSpec(_T("%a"), _T("ddd"), FALSE);
|
||
|
|
_AddsMappedSpec(_T("%A"), _T("dddd"), FALSE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%b"), _T("MMM"), FALSE);
|
||
|
|
_AddsMappedSpec(_T("%B"), _T("MMMM"), FALSE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%d"), _T("dd"), FALSE);
|
||
|
|
_AddsMappedSpec(_T("%#d"), _T("d"), FALSE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%m"), _T("MM"), FALSE);
|
||
|
|
_AddsMappedSpec(_T("%#m"), _T("M"), FALSE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%y"), _T("yy"), FALSE);
|
||
|
|
_AddsMappedSpec(_T("%#y"), _T("y"), FALSE);
|
||
|
|
_AddsMappedSpec(_T("%Y"), _T("yyyy"), FALSE);
|
||
|
|
|
||
|
|
// time
|
||
|
|
_AddsMappedSpec(_T("%H"), _T("HH"), TRUE);
|
||
|
|
_AddsMappedSpec(_T("%#H"), _T("H"), TRUE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%I"), _T("hh"), TRUE);
|
||
|
|
_AddsMappedSpec(_T("%#I"), _T("h"), TRUE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%M"), _T("mm"), TRUE);
|
||
|
|
_AddsMappedSpec(_T("%#M"), _T("m"), TRUE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%S"), _T("ss"), TRUE);
|
||
|
|
_AddsMappedSpec(_T("%#S"), _T("s"), TRUE);
|
||
|
|
|
||
|
|
_AddsMappedSpec(_T("%p"), _T("tt"), TRUE);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControlLocale::_AddsMappedSpec(LPCTSTR pcszSpec, LPCTSTR pcszFormat, BOOL bTime)
|
||
|
|
{
|
||
|
|
XTP_TIMESPEC tmpSpec = {pcszSpec, pcszFormat, bTime};
|
||
|
|
s_arMappedSpecs.Add(tmpSpec);
|
||
|
|
}
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
// CReportDropTarget
|
||
|
|
class CXTPReportControl::CReportDropTarget : public COleDropTarget
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
|
||
|
|
{
|
||
|
|
CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
|
||
|
|
if (!pReport)
|
||
|
|
return DROPEFFECT_NONE;
|
||
|
|
|
||
|
|
return pReport->OnDragOver(pDataObject, dwKeyState, point, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
|
||
|
|
{
|
||
|
|
CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
|
||
|
|
if (!pReport)
|
||
|
|
return DROPEFFECT_NONE;
|
||
|
|
|
||
|
|
return pReport->OnDragOver(pDataObject, dwKeyState, point, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
virtual void OnDragLeave(CWnd* pWnd)
|
||
|
|
{
|
||
|
|
CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
|
||
|
|
|
||
|
|
if (pReport)
|
||
|
|
{
|
||
|
|
pReport->OnDragOver(NULL, 0, CPoint(-1, -1), 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
|
||
|
|
DROPEFFECT dropEffect, CPoint point)
|
||
|
|
{
|
||
|
|
CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
|
||
|
|
|
||
|
|
if (pReport)
|
||
|
|
{
|
||
|
|
return pReport->OnDrop(pDataObject, dropEffect, point);
|
||
|
|
}
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
void XTPStrSplit(LPCTSTR pcszString, LPCTSTR pcszSeparator, CStringArray& rarStrings)
|
||
|
|
{
|
||
|
|
rarStrings.RemoveAll();
|
||
|
|
|
||
|
|
int nSeparatorLen = (int)_tcslen(pcszSeparator);
|
||
|
|
CString strString(pcszString);
|
||
|
|
CString strItem;
|
||
|
|
int nIndex_start = 0;
|
||
|
|
|
||
|
|
// parse data
|
||
|
|
BOOL bBreak = FALSE;
|
||
|
|
do
|
||
|
|
{
|
||
|
|
int nIndex = FIND_S(strString, pcszSeparator, nIndex_start);
|
||
|
|
if (nIndex >= 0)
|
||
|
|
{
|
||
|
|
strItem = strString.Mid(nIndex_start, nIndex - nIndex_start);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
strItem = strString.Mid(nIndex_start);
|
||
|
|
bBreak = TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
//---------------------------------------
|
||
|
|
rarStrings.Add(strItem);
|
||
|
|
|
||
|
|
nIndex_start = nIndex + nSeparatorLen;
|
||
|
|
}
|
||
|
|
while (!bBreak);
|
||
|
|
}
|
||
|
|
|
||
|
|
CString XTPStrMake(const CStringArray& arStrings, LPCTSTR pcszSeparator)
|
||
|
|
{
|
||
|
|
CString strString;
|
||
|
|
|
||
|
|
int nCount = (int)arStrings.GetSize();
|
||
|
|
for (int i = 0; i < nCount; i++)
|
||
|
|
{
|
||
|
|
if (i > 0)
|
||
|
|
{
|
||
|
|
strString += pcszSeparator;
|
||
|
|
}
|
||
|
|
strString += arStrings[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
return strString;
|
||
|
|
}
|
||
|
|
|
||
|
|
// CXTPReportControl
|
||
|
|
IMPLEMENT_DYNCREATE(CXTPReportControl, CWnd)
|
||
|
|
|
||
|
|
BEGIN_MESSAGE_MAP(CXTPReportControl, CWnd)
|
||
|
|
//{{AFX_MSG_MAP(CXTPReportControl)
|
||
|
|
ON_WM_PAINT()
|
||
|
|
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
|
||
|
|
ON_WM_ERASEBKGND()
|
||
|
|
ON_WM_SIZE()
|
||
|
|
ON_WM_LBUTTONDOWN()
|
||
|
|
ON_WM_NCHITTEST_EX()
|
||
|
|
ON_WM_LBUTTONUP()
|
||
|
|
ON_WM_RBUTTONDOWN()
|
||
|
|
ON_WM_RBUTTONUP()
|
||
|
|
ON_WM_CONTEXTMENU()
|
||
|
|
ON_WM_MOUSEMOVE()
|
||
|
|
ON_WM_SETCURSOR()
|
||
|
|
ON_WM_KEYDOWN()
|
||
|
|
ON_WM_VSCROLL()
|
||
|
|
ON_WM_HSCROLL()
|
||
|
|
ON_WM_MOUSEWHEEL()
|
||
|
|
ON_WM_SYSKEYDOWN()
|
||
|
|
ON_WM_CAPTURECHANGED()
|
||
|
|
ON_WM_SYSCOLORCHANGE()
|
||
|
|
ON_WM_SETFOCUS()
|
||
|
|
ON_WM_KILLFOCUS()
|
||
|
|
ON_WM_KEYUP()
|
||
|
|
ON_WM_SYSKEYUP()
|
||
|
|
ON_WM_LBUTTONDBLCLK()
|
||
|
|
ON_WM_GETDLGCODE()
|
||
|
|
ON_WM_CHAR()
|
||
|
|
ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave)
|
||
|
|
ON_WM_STYLECHANGED()
|
||
|
|
ON_WM_ENABLE()
|
||
|
|
ON_WM_TIMER()
|
||
|
|
//}}AFX_MSG_MAP
|
||
|
|
END_MESSAGE_MAP()
|
||
|
|
|
||
|
|
CXTPReportControl::CXTPReportControl()
|
||
|
|
{
|
||
|
|
RegisterWindowClass();
|
||
|
|
|
||
|
|
m_nLockUpdateCount = 0;
|
||
|
|
m_nRowsPerWheel = GetMouseScrollLines();
|
||
|
|
|
||
|
|
m_pRows = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
|
||
|
|
m_pPlainTree = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
|
||
|
|
m_pRecords = new CXTPHeapObjectT<CXTPReportRecords, CXTPReportAllocatorDefault>;
|
||
|
|
|
||
|
|
m_pColumns = new CXTPReportColumns(this);
|
||
|
|
m_pReportHeader = new CXTPReportHeader(this, m_pColumns);
|
||
|
|
|
||
|
|
m_pPaintManager = new CXTPReportPaintManager();
|
||
|
|
m_pNavigator = new CXTPReportNavigator(this);
|
||
|
|
m_nTopRow = 0;
|
||
|
|
|
||
|
|
m_nFocusedRow = -1;
|
||
|
|
m_nFocusedHeaderRow = -1;
|
||
|
|
m_nFocusedFooterRow = -1;
|
||
|
|
|
||
|
|
m_mouseMode = xtpReportMouseNothing;
|
||
|
|
|
||
|
|
m_pSelectedRows = new CXTPReportSelectedRows(this);
|
||
|
|
|
||
|
|
m_bChanged = TRUE;
|
||
|
|
m_bRefreshIndexes = FALSE;
|
||
|
|
|
||
|
|
m_bGroupByEnabled = FALSE;
|
||
|
|
m_bHeaderVisible = TRUE;
|
||
|
|
m_bFooterVisible = FALSE;
|
||
|
|
m_bHeaderRecordsVisible = FALSE;
|
||
|
|
m_bFooterRecordsVisible = FALSE;
|
||
|
|
|
||
|
|
m_bMultipleSelection = TRUE;
|
||
|
|
m_bMultiSelectionMode = FALSE;
|
||
|
|
|
||
|
|
m_bShowTooltips = TRUE;
|
||
|
|
|
||
|
|
m_bSkipGroupsFocus = TRUE;
|
||
|
|
|
||
|
|
m_pImageManager = new CXTPImageManager();
|
||
|
|
|
||
|
|
m_pFocusedColumn = NULL;
|
||
|
|
m_pActiveItem = NULL;
|
||
|
|
|
||
|
|
m_bFocusSubItems = FALSE;
|
||
|
|
m_bEditOnClick = TRUE;
|
||
|
|
m_bAllowEdit = FALSE;
|
||
|
|
m_bHeaderAllowEdit = FALSE;
|
||
|
|
m_bFooterAllowEdit = FALSE;
|
||
|
|
m_bSelectionEnable = TRUE;
|
||
|
|
m_bRowFocusVisible = TRUE;
|
||
|
|
|
||
|
|
m_bAutoCheckItems = TRUE;
|
||
|
|
|
||
|
|
m_pInplaceEdit = new CXTPReportInplaceEdit();
|
||
|
|
m_pInplaceButtons = new CXTPReportInplaceButtons();
|
||
|
|
m_pInplaceList = new CXTPReportInplaceList();
|
||
|
|
|
||
|
|
m_rcGroupByArea.SetRectEmpty();
|
||
|
|
m_rcHeaderArea.SetRectEmpty();
|
||
|
|
m_rcReportArea.SetRectEmpty();
|
||
|
|
m_rcFooterArea.SetRectEmpty();
|
||
|
|
|
||
|
|
m_nFreezeColumnsCount = 0;
|
||
|
|
m_nDisableReorderColumnsCount = 0;
|
||
|
|
m_nLeftOffset = 0;
|
||
|
|
m_pHotRow = 0;
|
||
|
|
m_nOLEDropMode = 0;
|
||
|
|
m_bFullColumnScrolling = FALSE;
|
||
|
|
m_nHScrollStep = XTP_REPORT_HSCROLL_STEP;
|
||
|
|
|
||
|
|
m_bVScrollBarVisible = FALSE;
|
||
|
|
m_bHScrollBarVisible = FALSE;
|
||
|
|
|
||
|
|
m_bPrepareDrag = FALSE;
|
||
|
|
m_pointDrag = CPoint(0, 0);
|
||
|
|
|
||
|
|
m_pToolTipContext = new CXTPToolTipContext;
|
||
|
|
m_pCachedToolTipInfo = new XTP_NM_REPORTTOOLTIPINFO;
|
||
|
|
|
||
|
|
m_nPopulatedRecordsCount = 0;
|
||
|
|
|
||
|
|
m_cfReport = NULL;
|
||
|
|
m_pDropTarget = new CReportDropTarget;
|
||
|
|
m_bDragMode = FALSE;
|
||
|
|
m_dwDragDropFlags = 0;
|
||
|
|
m_nDropPos = -1;
|
||
|
|
m_pDropRecords = NULL;
|
||
|
|
m_pSelectOnUpRow = NULL;
|
||
|
|
|
||
|
|
m_bOnSizeRunning = FALSE;
|
||
|
|
m_uAutoScrollTimerID = 0;
|
||
|
|
|
||
|
|
m_bSortRecordChilds = FALSE;
|
||
|
|
|
||
|
|
m_pRowsCompareFunc = NULL;
|
||
|
|
|
||
|
|
m_ptrVirtualEditingRow = NULL;
|
||
|
|
|
||
|
|
m_bFilterHiddenColumns = FALSE;
|
||
|
|
|
||
|
|
m_pHeaderRecords = new CXTPHeapObjectT<CXTPReportRecords, CXTPReportAllocatorDefault>;
|
||
|
|
m_pFooterRecords = new CXTPHeapObjectT<CXTPReportRecords, CXTPReportAllocatorDefault>;
|
||
|
|
m_pHeaderRows = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
|
||
|
|
m_pFooterRows = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
|
||
|
|
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
m_WatermarkTransparency = 100;
|
||
|
|
m_WatermarkAlignment = xtpReportWatermarkStretch;
|
||
|
|
|
||
|
|
m_bHeaderRowsAllowAccess = TRUE;
|
||
|
|
m_bFooterRowsAllowAccess = TRUE;
|
||
|
|
|
||
|
|
m_bHeaderRowsSelectionEnable = TRUE;
|
||
|
|
m_bFooterRowsSelectionEnable = TRUE;
|
||
|
|
|
||
|
|
m_nEnsureVisibleRowIdx = m_nEnsureVisibleColumnIdx = -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
|
||
|
|
{
|
||
|
|
return XTPDrawHelpers()->RegisterWndClass(hInstance, XTPREPORTCTRL_CLASSNAME, CS_DBLCLKS);
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportControl::~CXTPReportControl()
|
||
|
|
{
|
||
|
|
if (::IsWindow(m_wndTip.GetSafeHwnd()))
|
||
|
|
m_wndTip.DestroyWindow();
|
||
|
|
|
||
|
|
EditItem(0);
|
||
|
|
|
||
|
|
//m_arrScreenRows.Clear();
|
||
|
|
ResetContent(FALSE);
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pRows);
|
||
|
|
CMDTARGET_RELEASE(m_pPlainTree);
|
||
|
|
CMDTARGET_RELEASE(m_pSelectedRows);
|
||
|
|
CMDTARGET_RELEASE(m_pRecords);
|
||
|
|
CMDTARGET_RELEASE(m_pColumns);
|
||
|
|
CMDTARGET_RELEASE(m_pPaintManager);
|
||
|
|
CMDTARGET_RELEASE(m_pNavigator);
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pImageManager);
|
||
|
|
CMDTARGET_RELEASE(m_pReportHeader);
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pToolTipContext);
|
||
|
|
SAFE_DELETE(m_pCachedToolTipInfo);
|
||
|
|
|
||
|
|
SAFE_DELETE(m_pInplaceEdit);
|
||
|
|
SAFE_DELETE(m_pInplaceButtons);
|
||
|
|
SAFE_DELETE(m_pInplaceList);
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pDropTarget);
|
||
|
|
CMDTARGET_RELEASE(m_ptrVirtualEditingRow);
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pHeaderRecords);
|
||
|
|
CMDTARGET_RELEASE(m_pFooterRecords);
|
||
|
|
CMDTARGET_RELEASE(m_pHeaderRows);
|
||
|
|
CMDTARGET_RELEASE(m_pFooterRows);
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pDropRecords);
|
||
|
|
|
||
|
|
if(m_hbmpWatermark)
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::ResetContent(BOOL bUpdateControl)
|
||
|
|
{
|
||
|
|
EditItem(NULL);
|
||
|
|
|
||
|
|
m_arrScreenRows.Clear();
|
||
|
|
|
||
|
|
if (m_pRows) m_pRows->Clear();
|
||
|
|
if (m_pPlainTree) m_pPlainTree->Clear();
|
||
|
|
if (m_pSelectedRows) m_pSelectedRows->Clear();
|
||
|
|
|
||
|
|
// m_pHeaderRows->Clear();
|
||
|
|
// m_pFooterRows->Clear();
|
||
|
|
|
||
|
|
// m_pHeaderRecords->RemoveAll();
|
||
|
|
// m_pFooterRecords->RemoveAll();
|
||
|
|
|
||
|
|
if (m_pRecords) m_pRecords->RemoveAll();
|
||
|
|
|
||
|
|
if (bUpdateControl)
|
||
|
|
{
|
||
|
|
AdjustIndentation();
|
||
|
|
AdjustScrollBars();
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void CXTPReportControl::SetReportHeader(CXTPReportHeader* pReportHeader)
|
||
|
|
{
|
||
|
|
if (pReportHeader)
|
||
|
|
{
|
||
|
|
m_pReportHeader->InternalRelease();
|
||
|
|
m_pReportHeader = pReportHeader;
|
||
|
|
AdjustLayout();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetImageManager(CXTPImageManager* pImageManager)
|
||
|
|
{
|
||
|
|
if (pImageManager)
|
||
|
|
{
|
||
|
|
m_pImageManager->InternalRelease();
|
||
|
|
m_pImageManager = pImageManager;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetImageList(CImageList* pImageList)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < pImageList->GetImageCount(); i++)
|
||
|
|
{
|
||
|
|
HICON hIcon = pImageList->ExtractIcon(i);
|
||
|
|
m_pImageManager->SetIcon(hIcon, i);
|
||
|
|
|
||
|
|
DestroyIcon(hIcon);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetPaintManager(CXTPReportPaintManager* pPaintManager)
|
||
|
|
{
|
||
|
|
if (pPaintManager)
|
||
|
|
{
|
||
|
|
m_pPaintManager->InternalRelease();
|
||
|
|
m_pPaintManager = pPaintManager;
|
||
|
|
|
||
|
|
AdjustLayout();
|
||
|
|
AdjustScrollBars();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
|
||
|
|
{
|
||
|
|
if (!CWnd::Create(XTPREPORTCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext))
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::GetIndent(int nLevel) const
|
||
|
|
{
|
||
|
|
return max(0, (nLevel - 1) * m_pPaintManager->m_nTreeIndent);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetTreeIndent(int nIndent)
|
||
|
|
{
|
||
|
|
m_pPaintManager->m_nTreeIndent = nIndent;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void CXTPReportControl::BeginUpdate()
|
||
|
|
{
|
||
|
|
m_nLockUpdateCount++;
|
||
|
|
m_bRefreshIndexes = FALSE;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EndUpdate()
|
||
|
|
{
|
||
|
|
SetChanged();
|
||
|
|
m_nLockUpdateCount--;
|
||
|
|
|
||
|
|
if (m_nLockUpdateCount == 0)
|
||
|
|
{
|
||
|
|
if (m_bRefreshIndexes)
|
||
|
|
{
|
||
|
|
m_bRefreshIndexes = FALSE;
|
||
|
|
_RefreshIndexes();
|
||
|
|
}
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::RedrawControl()
|
||
|
|
{
|
||
|
|
SetChanged();
|
||
|
|
if (m_nLockUpdateCount == 0 && GetSafeHwnd())
|
||
|
|
{
|
||
|
|
Invalidate(FALSE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::UpdateSubList()
|
||
|
|
{
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
if (pHeader && pHeader->m_pSubList &&
|
||
|
|
(pHeader->m_pSubList->GetReportCtrl() == this))
|
||
|
|
{
|
||
|
|
pHeader->m_pSubList->UpdateList();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::_DoCollapse(CXTPReportRow* pRow)
|
||
|
|
{
|
||
|
|
int nIndex = pRow->GetIndex() + 1;
|
||
|
|
int nCount = 0;
|
||
|
|
|
||
|
|
while (nIndex < m_pRows->GetCount())
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRowChild = m_pRows->GetAt(nIndex);
|
||
|
|
if (!pRowChild->HasParent(pRow))
|
||
|
|
break;
|
||
|
|
|
||
|
|
pRowChild->m_bVisible = FALSE;
|
||
|
|
pRowChild->m_nIndex = -1;
|
||
|
|
m_pRows->RemoveAt(nIndex);
|
||
|
|
nCount++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nCount > 0)
|
||
|
|
{
|
||
|
|
m_pSelectedRows->_OnCollapsed(nIndex - 1, nCount);
|
||
|
|
|
||
|
|
if (m_nFocusedRow >= nIndex)
|
||
|
|
m_nFocusedRow = max(nIndex - 1, m_nFocusedRow - nCount);
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::_DoExpand(CXTPReportRow* pRow)
|
||
|
|
{
|
||
|
|
int nIndex = pRow->m_nIndex;
|
||
|
|
int nCount = _DoExpand(nIndex, pRow);
|
||
|
|
|
||
|
|
if (nCount > 0)
|
||
|
|
{
|
||
|
|
m_pSelectedRows->_OnExpanded(nIndex, nCount);
|
||
|
|
|
||
|
|
if (m_nFocusedRow > nIndex)
|
||
|
|
m_nFocusedRow += nCount;
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::_DoExpand(int nIndex, CXTPReportRow* pRow)
|
||
|
|
{
|
||
|
|
if (!pRow->HasChildren())
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
int nStartIndex = nIndex;
|
||
|
|
for (int i = 0; i < pRow->GetChilds()->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRowChild = pRow->GetChilds()->GetAt(i);
|
||
|
|
|
||
|
|
pRowChild->m_nRowLevel = pRow->m_nRowLevel + 1;
|
||
|
|
pRowChild->m_nGroupLevel = pRow->m_nGroupLevel + (pRow->IsGroupRow() ? 1 : 0);
|
||
|
|
|
||
|
|
nIndex += InsertRow(nIndex + 1, pRowChild);
|
||
|
|
}
|
||
|
|
return nIndex - nStartIndex;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::RefreshIndexes(BOOL bAdjustLayout, BOOL bReverseOrder)
|
||
|
|
{
|
||
|
|
int nRowCount = m_pRows->GetCount();
|
||
|
|
int nStartIdx = 0, nEndIdx = nRowCount, nStep = 1;
|
||
|
|
if(bReverseOrder)
|
||
|
|
{
|
||
|
|
nStartIdx = nRowCount - 1;
|
||
|
|
nEndIdx = nStep = -1;
|
||
|
|
}
|
||
|
|
for (int nIndex = nStartIdx; nIndex != nEndIdx; nIndex += nStep)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(nIndex);
|
||
|
|
|
||
|
|
BOOL bSelected = m_pSelectedRows->Contains(pRow);
|
||
|
|
if(bSelected)
|
||
|
|
m_pSelectedRows->Remove(pRow);
|
||
|
|
|
||
|
|
pRow->m_nIndex = nIndex;
|
||
|
|
ASSERT(pRow->m_bVisible);
|
||
|
|
|
||
|
|
if(bSelected)
|
||
|
|
m_pSelectedRows->Add(pRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bAdjustLayout)
|
||
|
|
AdjustScrollBars();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::_RefreshIndexes(BOOL bAdjustLayout, BOOL bReverseOrder)
|
||
|
|
{
|
||
|
|
if (m_nLockUpdateCount != 0)
|
||
|
|
{
|
||
|
|
m_bRefreshIndexes = TRUE;
|
||
|
|
return;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
RefreshIndexes(bAdjustLayout, bReverseOrder);
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::InsertRow(int nIndex, CXTPReportRow* pRow)
|
||
|
|
{
|
||
|
|
m_pRows->InsertAt(nIndex, pRow);
|
||
|
|
pRow->InternalAddRef();
|
||
|
|
pRow->m_bVisible = TRUE;
|
||
|
|
|
||
|
|
|
||
|
|
int nRowsInserted = 1;
|
||
|
|
|
||
|
|
if (pRow->IsExpanded() && pRow->HasChildren())
|
||
|
|
{
|
||
|
|
nRowsInserted += _DoExpand(nIndex, pRow);
|
||
|
|
}
|
||
|
|
return nRowsInserted;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::BuildTree(CXTPReportRows* pTree, CXTPReportRow* pParentRow, CXTPReportRecords* pRecords)
|
||
|
|
{
|
||
|
|
ASSERT(pTree->GetCount() == 0);
|
||
|
|
|
||
|
|
pTree->ReserveSize(pRecords->GetCount());
|
||
|
|
|
||
|
|
for (int i = 0; i < pRecords->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = pRecords->GetAt(i);
|
||
|
|
|
||
|
|
// add record if all conditions are met
|
||
|
|
if (pRecord->IsLocked() ||
|
||
|
|
(pRecord->IsVisible() && !ApplyFilter(pRecord, GetFilterText(), IsPreviewMode())))
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = CreateRow();
|
||
|
|
pRow->InitRow(this, pRecord);
|
||
|
|
|
||
|
|
pRow->m_pParentRow = pParentRow;
|
||
|
|
pTree->Add(pRow);
|
||
|
|
|
||
|
|
if (pRecord->HasChildren())
|
||
|
|
{
|
||
|
|
BuildTree(pRow->GetChilds(), pRow, pRecord->GetChilds());
|
||
|
|
if (pRow->GetChilds() && IsSortRecordChilds())
|
||
|
|
{
|
||
|
|
SortRows(pRow->GetChilds());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SortTree(CXTPReportRows* pTree)
|
||
|
|
{
|
||
|
|
ASSERT(pTree);
|
||
|
|
if (!pTree)
|
||
|
|
return;
|
||
|
|
|
||
|
|
SortRows(pTree);
|
||
|
|
|
||
|
|
for (int i = 0; i < pTree->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pTree->GetAt(i);
|
||
|
|
ASSERT(pRow);
|
||
|
|
if (!pRow)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
|
||
|
|
BOOL bRecordHasChildren = pRow->GetRecord() && pRow->GetRecord()->HasChildren();
|
||
|
|
|
||
|
|
if (pRow->HasChildren() && pRow->GetChilds() &&
|
||
|
|
(bRecordHasChildren && m_bSortRecordChilds || !bRecordHasChildren))
|
||
|
|
{
|
||
|
|
SortTree(pRow->GetChilds());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pTree->RefreshChildIndices(FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::ReSortRows()
|
||
|
|
{
|
||
|
|
if (IsVirtualMode())
|
||
|
|
{
|
||
|
|
Populate();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
SortTree(m_pPlainTree);
|
||
|
|
|
||
|
|
CXTPReportRecord* pFocusedRecord = GetFocusedRow() ? GetFocusedRow()->GetRecord() : NULL;
|
||
|
|
|
||
|
|
m_pRows->Clear();
|
||
|
|
m_arrScreenRows.Clear(FALSE);
|
||
|
|
|
||
|
|
for (int nGroupRow = 0; nGroupRow < m_pPlainTree->GetCount(); nGroupRow++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pPlainTree->GetAt(nGroupRow);
|
||
|
|
InsertRow(m_pRows->GetCount(), pRow);
|
||
|
|
pRow->m_nChildIndex = nGroupRow;
|
||
|
|
ASSERT(pRow->m_pParentRows == m_pPlainTree);
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------
|
||
|
|
m_nFocusedRow = -1;
|
||
|
|
// Update indexes on virtual rows
|
||
|
|
int nRowCount = m_pRows->GetCount();
|
||
|
|
for (int nRowIndex = 0; nRowIndex < nRowCount; nRowIndex++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(nRowIndex);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
pRow->SetIndex(nRowIndex);
|
||
|
|
pRow->m_bVisible = TRUE;
|
||
|
|
|
||
|
|
if (pFocusedRecord && pRow->GetRecord() == pFocusedRecord)
|
||
|
|
{
|
||
|
|
m_nFocusedRow = pRow->GetIndex();
|
||
|
|
if(IsSelectionEnabled())
|
||
|
|
m_pSelectedRows->Select(pRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
AdjustIndentation();
|
||
|
|
AdjustLayout();
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
CLIPFORMAT CXTPReportControl::EnableDragDrop(LPCTSTR lpszClipboardFormat, DWORD dwFlags)
|
||
|
|
{
|
||
|
|
if (m_dwDragDropFlags != 0)
|
||
|
|
{
|
||
|
|
if (m_pDropTarget)
|
||
|
|
m_pDropTarget->Revoke();
|
||
|
|
}
|
||
|
|
|
||
|
|
m_dwDragDropFlags = dwFlags;
|
||
|
|
m_cfReport = NULL;
|
||
|
|
|
||
|
|
if (m_dwDragDropFlags != 0)
|
||
|
|
{
|
||
|
|
if (m_pDropTarget)
|
||
|
|
{
|
||
|
|
m_cfReport = (CLIPFORMAT)::RegisterClipboardFormat(lpszClipboardFormat);
|
||
|
|
|
||
|
|
m_pDropTarget->Revoke(); // to ensure kill previous registration.
|
||
|
|
|
||
|
|
m_pDropTarget->Register(this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return m_cfReport;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::ApplyFilter(CXTPReportRecord* pRecord, CString strFilterText, BOOL bIncludePreview)
|
||
|
|
{
|
||
|
|
// not filtered if filter text is empty
|
||
|
|
if (!pRecord)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
if (pRecord->IsFiltered())
|
||
|
|
return TRUE;
|
||
|
|
|
||
|
|
if (strFilterText.IsEmpty())
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
BOOL bFilterHidden = IsFilterHiddenColumns();
|
||
|
|
|
||
|
|
// process each token in the filter string
|
||
|
|
TCHAR szSeps[] = _T(" \t");
|
||
|
|
TCHAR *szToken, *lpszContext = 0;
|
||
|
|
//int nCurPos = 0;
|
||
|
|
|
||
|
|
szToken = STRTOK_S(strFilterText.GetBuffer(strFilterText.GetLength()), szSeps, &lpszContext);
|
||
|
|
while (szToken != NULL)
|
||
|
|
{
|
||
|
|
CString strToken(szToken);
|
||
|
|
strToken.MakeLower();
|
||
|
|
BOOL bTokenFound = FALSE;
|
||
|
|
// enumerate all visible columns
|
||
|
|
int nColumnsCount = m_pColumns->GetCount();
|
||
|
|
for (int nCol = 0; nCol < nColumnsCount; nCol++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pCol = m_pColumns->GetAt(nCol);
|
||
|
|
if (pCol && (pCol->IsVisible() || bFilterHidden) && pCol->IsFiltrable())
|
||
|
|
{
|
||
|
|
CXTPReportRecordItem* pItem = pRecord->GetItem(pCol);
|
||
|
|
if (pItem)
|
||
|
|
{
|
||
|
|
CString sItemText = pItem->GetCaption(pCol);
|
||
|
|
// case-insensitive search
|
||
|
|
sItemText.MakeLower();
|
||
|
|
bTokenFound = sItemText.Find(strToken) != -1;
|
||
|
|
|
||
|
|
if (bTokenFound)
|
||
|
|
{
|
||
|
|
// stop search current token - passed
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// also check preview text
|
||
|
|
if (bIncludePreview && !bTokenFound && pRecord->GetItemPreview())
|
||
|
|
{
|
||
|
|
CString sItemText = pRecord->GetItemPreview()->GetCaption(NULL);
|
||
|
|
// case-insensitive search
|
||
|
|
sItemText.MakeLower();
|
||
|
|
bTokenFound = sItemText.Find(strToken) != -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Token not found - filter this record
|
||
|
|
if (!bTokenFound)
|
||
|
|
{
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get next token
|
||
|
|
szToken = STRTOK_S(NULL, szSeps, &lpszContext);
|
||
|
|
}
|
||
|
|
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::Populate()
|
||
|
|
{
|
||
|
|
EditItem(NULL);
|
||
|
|
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
m_nPopulatedRecordsCount = 0;
|
||
|
|
|
||
|
|
// save focused items
|
||
|
|
CXTPReportRecord* pFocusedRecord = GetFocusedRow() ? GetFocusedRow()->GetRecord() : NULL;
|
||
|
|
m_pSelectedRows->Clear();
|
||
|
|
m_nFocusedRow = -1;
|
||
|
|
m_nFocusedHeaderRow = -1;
|
||
|
|
m_nFocusedFooterRow = -1;
|
||
|
|
|
||
|
|
m_pRows->Clear();
|
||
|
|
m_pPlainTree->Clear();
|
||
|
|
m_arrScreenRows.Clear(FALSE);
|
||
|
|
m_pHeaderRows->Clear();
|
||
|
|
m_pFooterRows->Clear();
|
||
|
|
|
||
|
|
if (IsVirtualMode())
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = CreateRow();
|
||
|
|
pRow->InitRow(this, GetRecords()->m_pVirtualRecord);
|
||
|
|
pRow->m_bVisible = TRUE;
|
||
|
|
|
||
|
|
m_pRows->SetVirtualMode(pRow, GetRecords()->GetCount());
|
||
|
|
m_nPopulatedRecordsCount = GetRecords()->GetCount();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
BuildTree(m_pPlainTree, NULL, m_pRecords);
|
||
|
|
m_nPopulatedRecordsCount = m_pPlainTree->GetCount();
|
||
|
|
|
||
|
|
SortRows(m_pPlainTree);
|
||
|
|
|
||
|
|
int nGroupRowsCount = 0;
|
||
|
|
|
||
|
|
if (m_pColumns->GetGroupsOrder()->GetCount() > 0)
|
||
|
|
{
|
||
|
|
CXTPReportRows* pGroupTree = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
|
||
|
|
|
||
|
|
int nReserve = m_pRecords->GetCount() / (m_pColumns->GetGroupsOrder()->GetCount() + 1);
|
||
|
|
nReserve = max(nReserve, 300);
|
||
|
|
pGroupTree->ReserveSize(nReserve);
|
||
|
|
|
||
|
|
CXTPReportGroupRow* pLastGroup = NULL;
|
||
|
|
|
||
|
|
for (int nPlainRow = 0; nPlainRow < m_pPlainTree->GetCount(); nPlainRow++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pPlainTree->GetAt(nPlainRow);
|
||
|
|
CXTPReportGroupRow* pGroupToAdd = NULL;
|
||
|
|
|
||
|
|
for (int nColumn = 0; nColumn < m_pColumns->GetGroupsOrder()->GetCount(); nColumn++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = m_pColumns->GetGroupsOrder()->GetAt(nColumn);
|
||
|
|
CXTPReportRecordItem* pItem = pRow->GetRecord()->GetItem(pColumn);
|
||
|
|
CString strGroup = pItem ? pItem->GetGroupCaption(pColumn) : _T("");
|
||
|
|
|
||
|
|
if (pLastGroup && GetRecords()->Compare(pLastGroup->GetCaption(), strGroup) == 0)
|
||
|
|
{
|
||
|
|
pGroupToAdd = pLastGroup;
|
||
|
|
|
||
|
|
if (pGroupToAdd->HasChildren())
|
||
|
|
pLastGroup = (CXTPReportGroupRow*)pGroupToAdd->GetChilds()->GetAt(pGroupToAdd->GetChilds()->GetCount() - 1);
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CXTPReportGroupRow* pGroup = CreateGroupRow();
|
||
|
|
nGroupRowsCount++;
|
||
|
|
|
||
|
|
pGroup->InitRow(this, NULL);
|
||
|
|
pGroup->SetCaption(strGroup);
|
||
|
|
|
||
|
|
if (pGroupToAdd)
|
||
|
|
{
|
||
|
|
pGroupToAdd->AddChild(pGroup);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
pGroupTree->Add(pGroup);
|
||
|
|
}
|
||
|
|
|
||
|
|
pGroupToAdd = pGroup;
|
||
|
|
pLastGroup = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
if (pGroupToAdd) pGroupToAdd->AddChild(pRow);
|
||
|
|
pRow->InternalAddRef();
|
||
|
|
pLastGroup = (CXTPReportGroupRow*)pGroupTree->GetAt(pGroupTree->GetCount() - 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pPlainTree->InternalRelease();
|
||
|
|
m_pPlainTree = pGroupTree;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pRows->ReserveSize(m_pRecords->GetCount() + nGroupRowsCount + 10);
|
||
|
|
|
||
|
|
for (int nGroupRow = 0; nGroupRow < m_pPlainTree->GetCount(); nGroupRow++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pPlainTree->GetAt(nGroupRow);
|
||
|
|
InsertRow(m_pRows->GetCount(), pRow);
|
||
|
|
pRow->m_nChildIndex = nGroupRow;
|
||
|
|
ASSERT(pRow->m_pParentRows == m_pPlainTree);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
m_nFocusedRow = -1;
|
||
|
|
m_nFocusedHeaderRow = -1;
|
||
|
|
m_nFocusedFooterRow = -1;
|
||
|
|
|
||
|
|
// Update indexes on virtual rows
|
||
|
|
int nRowCount = m_pRows->GetCount();
|
||
|
|
for (int nRowIndex = 0; nRowIndex < nRowCount; nRowIndex++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(nRowIndex);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
pRow->SetIndex(nRowIndex);
|
||
|
|
pRow->m_bVisible = TRUE;
|
||
|
|
|
||
|
|
if (pFocusedRecord && pRow->GetRecord() == pFocusedRecord)
|
||
|
|
{
|
||
|
|
m_nFocusedRow = pRow->GetIndex();
|
||
|
|
if(IsSelectionEnabled())
|
||
|
|
m_pSelectedRows->Select(pRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int i;
|
||
|
|
// header record rows
|
||
|
|
for (i = 0; i < m_pHeaderRecords->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = m_pHeaderRecords->GetAt(i);
|
||
|
|
CXTPReportRow* pRow = CreateHeaderFooterRow();
|
||
|
|
|
||
|
|
pRow->InitRow(this, pRecord);
|
||
|
|
pRow->SetIndex(i);
|
||
|
|
pRow->m_nRowType = xtpRowTypeHeader;
|
||
|
|
pRow->m_pParentRow = NULL;
|
||
|
|
m_pHeaderRows->Add(pRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
// footer record rows
|
||
|
|
for (i = 0; i < m_pFooterRecords->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = m_pFooterRecords->GetAt(i);
|
||
|
|
CXTPReportRow* pRow = CreateHeaderFooterRow();
|
||
|
|
|
||
|
|
pRow->InitRow(this, pRecord);
|
||
|
|
pRow->SetIndex(i);
|
||
|
|
pRow->m_nRowType = xtpRowTypeFooter;
|
||
|
|
pRow->m_pParentRow = NULL;
|
||
|
|
m_pFooterRows->Add(pRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
AdjustIndentation();
|
||
|
|
AdjustLayout();
|
||
|
|
AdjustScrollBars();
|
||
|
|
|
||
|
|
UpdateSubList();
|
||
|
|
|
||
|
|
if (m_nFocusedRow == -1)
|
||
|
|
{
|
||
|
|
SetTopRow(0);
|
||
|
|
|
||
|
|
if (GetRows()->GetCount() > 0)
|
||
|
|
{
|
||
|
|
m_nFocusedRow = 0;
|
||
|
|
if(IsSelectionEnabled())
|
||
|
|
m_pSelectedRows->Select(m_pRows->GetAt(0));
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
EnsureVisible(GetFocusedRow());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pFocusedColumn == NULL && m_bFocusSubItems)
|
||
|
|
{
|
||
|
|
m_pFocusedColumn = m_pColumns->GetFirstVisibleColumn();
|
||
|
|
}
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::PopulateHeaderRows()
|
||
|
|
{
|
||
|
|
if(IsVirtualMode())
|
||
|
|
return;
|
||
|
|
|
||
|
|
EditItem(NULL);
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
m_pHeaderRows->Clear();
|
||
|
|
for (int i = 0; i < m_pHeaderRecords->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = m_pHeaderRecords->GetAt(i);
|
||
|
|
CXTPReportRow* pRow = CreateHeaderFooterRow();
|
||
|
|
|
||
|
|
pRow->InitRow(this, pRecord);
|
||
|
|
pRow->SetIndex(i);
|
||
|
|
pRow->m_nRowType = xtpRowTypeHeader;
|
||
|
|
pRow->m_pParentRow = NULL;
|
||
|
|
m_pHeaderRows->Add(pRow);
|
||
|
|
}
|
||
|
|
AdjustIndentation();
|
||
|
|
AdjustLayout();
|
||
|
|
AdjustScrollBars();
|
||
|
|
|
||
|
|
UpdateSubList();
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::PopulateFooterRows()
|
||
|
|
{
|
||
|
|
if(IsVirtualMode())
|
||
|
|
return;
|
||
|
|
|
||
|
|
EditItem(NULL);
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
m_pFooterRows->Clear();
|
||
|
|
for (int i = 0; i < m_pFooterRecords->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = m_pFooterRecords->GetAt(i);
|
||
|
|
CXTPReportRow* pRow = CreateHeaderFooterRow();
|
||
|
|
|
||
|
|
pRow->InitRow(this, pRecord);
|
||
|
|
pRow->SetIndex(i);
|
||
|
|
pRow->m_nRowType = xtpRowTypeFooter;
|
||
|
|
pRow->m_pParentRow = NULL;
|
||
|
|
m_pFooterRows->Add(pRow);
|
||
|
|
}
|
||
|
|
AdjustIndentation();
|
||
|
|
AdjustLayout();
|
||
|
|
AdjustScrollBars();
|
||
|
|
|
||
|
|
UpdateSubList();
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SortRows(CXTPReportRows* pRows)
|
||
|
|
{
|
||
|
|
if (pRows->GetCount() == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (m_pRowsCompareFunc && m_pRowsCompareFunc != CXTPReportRows::CompareRows)
|
||
|
|
{
|
||
|
|
pRows->SortEx(m_pRowsCompareFunc);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pColumns->GetSortOrder()->GetCount() == 0 &&
|
||
|
|
m_pColumns->GetGroupsOrder()->GetCount() == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
pRows->Sort();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::AdjustIndentation()
|
||
|
|
{
|
||
|
|
XTP_TRACE(_T("AdjustIndentation()\n"));
|
||
|
|
|
||
|
|
GetReportHeader()->m_nIndentLevel =
|
||
|
|
m_pColumns->GetGroupsOrder()->GetCount();
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportColumn* CXTPReportControl::AddColumn(CXTPReportColumn* pColumn)
|
||
|
|
{
|
||
|
|
ASSERT(pColumn);
|
||
|
|
m_pColumns->Add(pColumn);
|
||
|
|
|
||
|
|
return pColumn;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRecord* CXTPReportControl::AddRecord(CXTPReportRecord* pRecord)
|
||
|
|
{
|
||
|
|
ASSERT(pRecord);
|
||
|
|
if (!pRecord)
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
m_pRecords->Add(pRecord);
|
||
|
|
|
||
|
|
return pRecord;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::AddRecordEx(CXTPReportRecord* pRecord, CXTPReportRecord* pParentRecord, int nChildIndex)
|
||
|
|
{
|
||
|
|
ASSERT(pRecord);
|
||
|
|
if (!pRecord)
|
||
|
|
return;
|
||
|
|
|
||
|
|
// add record
|
||
|
|
BOOL bAddRecord = TRUE;
|
||
|
|
CXTPReportRecords* pParentRecords = pParentRecord ? pParentRecord->HasChildren() ? pParentRecord->GetChilds() : NULL : m_pRecords;
|
||
|
|
if(pParentRecords)
|
||
|
|
{
|
||
|
|
for(int nChild = 0; nChild < pParentRecords->GetCount(); nChild++)
|
||
|
|
{
|
||
|
|
if(pRecord == pParentRecords->GetAt(nChild))
|
||
|
|
{
|
||
|
|
bAddRecord = FALSE;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(bAddRecord)
|
||
|
|
{
|
||
|
|
if(pParentRecord)
|
||
|
|
pParentRecord->GetChilds()->Add(pRecord);
|
||
|
|
else
|
||
|
|
m_pRecords->Add(pRecord);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!pRecord->IsVisible())
|
||
|
|
return;
|
||
|
|
|
||
|
|
// find parent record rows
|
||
|
|
CXTPReportRows* pParentRows = m_pPlainTree;
|
||
|
|
CXTPReportRow* pParentRow = NULL;
|
||
|
|
if(pParentRecord)
|
||
|
|
{
|
||
|
|
pParentRow = m_pPlainTree->FindInTree(pParentRecord);
|
||
|
|
if(pParentRow)
|
||
|
|
pParentRows = pParentRow->GetChilds();
|
||
|
|
}
|
||
|
|
BOOL bRoot = pParentRows == m_pPlainTree;
|
||
|
|
|
||
|
|
// create new row
|
||
|
|
CXTPReportRow* pNewRow = CreateRow();
|
||
|
|
pNewRow->InitRow(this, pRecord);
|
||
|
|
pNewRow->m_pParentRow = NULL;
|
||
|
|
|
||
|
|
// add row to pParentRows
|
||
|
|
BOOL bInsertAfter = FALSE;
|
||
|
|
CXTPReportRow* pPlainTreeRow = NULL;
|
||
|
|
CXTPReportRow* pInsertRowPos = NULL;
|
||
|
|
int nNextSiblingIndex = m_pRows->GetCount();
|
||
|
|
if(bRoot)
|
||
|
|
{
|
||
|
|
pInsertRowPos = pParentRows->FindInsertionPos(pNewRow, bInsertAfter);
|
||
|
|
CXTPReportRow* pRow = pInsertRowPos;
|
||
|
|
while(pRow)
|
||
|
|
{
|
||
|
|
if(pRow->GetNextSiblingRow())
|
||
|
|
{
|
||
|
|
nNextSiblingIndex = pRow->GetNextSiblingRow()->GetIndex();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
pRow = pRow->GetParentRow();
|
||
|
|
}
|
||
|
|
if(m_pColumns->GetGroupsOrder()->GetCount() > 0)
|
||
|
|
{
|
||
|
|
CXTPReportGroupRow* pGroupToAdd = pInsertRowPos ? (CXTPReportGroupRow*)pInsertRowPos->GetParentRow() : NULL;
|
||
|
|
if(!pInsertRowPos || (pInsertRowPos && pInsertRowPos->IsGroupRow()))
|
||
|
|
{
|
||
|
|
for(int nColumn = pInsertRowPos ? pInsertRowPos->GetGroupLevel() : 0; nColumn < m_pColumns->GetGroupsOrder()->GetCount(); nColumn++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = m_pColumns->GetGroupsOrder()->GetAt(nColumn);
|
||
|
|
CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn);
|
||
|
|
CString strGroup = pItem ? pItem->GetGroupCaption(pColumn) : _T("");
|
||
|
|
|
||
|
|
CXTPReportGroupRow* pGroup = CreateGroupRow();
|
||
|
|
pGroup->InitRow(this, NULL);
|
||
|
|
pGroup->SetCaption(strGroup);
|
||
|
|
pGroup->m_nGroupLevel = pGroupToAdd ? pGroupToAdd->m_nRowLevel + 1 : 0;
|
||
|
|
pGroup->m_nRowLevel = nColumn;
|
||
|
|
if(pGroupToAdd)
|
||
|
|
{
|
||
|
|
if(!pPlainTreeRow)
|
||
|
|
{
|
||
|
|
pPlainTreeRow = pGroup;
|
||
|
|
pGroupToAdd->GetChilds()->InsertAt(bInsertAfter ? pInsertRowPos ? pInsertRowPos->m_nChildIndex + 1 : 0 : pInsertRowPos ? pInsertRowPos->m_nChildIndex : 0, pGroup);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
pGroupToAdd->AddChild(pGroup);
|
||
|
|
pGroup->m_pParentRows = pGroupToAdd->GetChilds();
|
||
|
|
pGroup->m_pParentRow = pGroupToAdd;
|
||
|
|
pGroup->m_bVisible = pGroupToAdd->IsExpanded();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
pPlainTreeRow = pGroup;
|
||
|
|
pParentRows->InsertAt(pInsertRowPos ? pInsertRowPos->m_nChildIndex : pParentRows->GetCount(), pGroup);
|
||
|
|
pGroup->m_pParentRows = pParentRows;
|
||
|
|
pGroup->m_pParentRow = NULL;
|
||
|
|
pGroup->m_bVisible = TRUE;
|
||
|
|
}
|
||
|
|
pGroupToAdd = pGroup;
|
||
|
|
}
|
||
|
|
// insert row
|
||
|
|
if(pGroupToAdd)
|
||
|
|
{
|
||
|
|
pGroupToAdd->AddChild(pNewRow);
|
||
|
|
pNewRow->m_pParentRows = pGroupToAdd->GetChilds();
|
||
|
|
// pNewRow->m_pParentRow = pGroupToAdd;
|
||
|
|
pNewRow->m_bVisible = pGroupToAdd->IsExpanded();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// insert row
|
||
|
|
if(pGroupToAdd)
|
||
|
|
{
|
||
|
|
pGroupToAdd->GetChilds()->InsertAt(bInsertAfter ? pInsertRowPos ? pInsertRowPos->m_nChildIndex + 1 : 0 : pInsertRowPos ? pInsertRowPos->m_nChildIndex : 0, pNewRow);
|
||
|
|
pNewRow->m_pParentRows = pGroupToAdd->GetChilds();
|
||
|
|
pNewRow->m_pParentRow = pGroupToAdd;
|
||
|
|
pNewRow->m_bVisible = pGroupToAdd->IsExpanded();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
pParentRows->InsertAt(pInsertRowPos ? pInsertRowPos->m_nChildIndex : pParentRows->GetCount(), pNewRow);
|
||
|
|
pNewRow->m_pParentRows = pParentRows;
|
||
|
|
pNewRow->m_pParentRow = NULL;
|
||
|
|
pNewRow->m_bVisible = TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(nChildIndex >= 0 && nChildIndex < pParentRows->GetCount())
|
||
|
|
pParentRows->InsertAt(nChildIndex, pNewRow);
|
||
|
|
else
|
||
|
|
pParentRows->Add(pNewRow);
|
||
|
|
pNewRow->m_pParentRows = pParentRows;
|
||
|
|
pNewRow->m_pParentRow = pParentRow;
|
||
|
|
pNewRow->m_bVisible = TRUE;
|
||
|
|
pNewRow->m_nRowLevel = pParentRow->m_nRowLevel + 1;
|
||
|
|
pNewRow->m_nGroupLevel = pParentRow->m_nGroupLevel;
|
||
|
|
pNewRow->m_nChildIndex = nChildIndex >= 0 ? nChildIndex : pParentRows->GetCount() - 1;
|
||
|
|
|
||
|
|
CXTPReportRow* pRow = pNewRow;
|
||
|
|
while(pRow)
|
||
|
|
{
|
||
|
|
if(pRow->GetNextSiblingRow())
|
||
|
|
{
|
||
|
|
nNextSiblingIndex = pRow->GetNextSiblingRow()->GetIndex();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
pRow = pRow->GetParentRow();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// refresh child indices
|
||
|
|
if(pInsertRowPos && pInsertRowPos->GetParentRows())
|
||
|
|
pInsertRowPos->GetParentRows()->RefreshChildIndices();
|
||
|
|
else
|
||
|
|
pParentRows->RefreshChildIndices();
|
||
|
|
|
||
|
|
// add row to m_pRows
|
||
|
|
if(bRoot)
|
||
|
|
{
|
||
|
|
if(pInsertRowPos)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pInsertRowPos->GetParentRow();
|
||
|
|
BOOL bIsExpanded = TRUE;
|
||
|
|
while(pRow && bIsExpanded)
|
||
|
|
{
|
||
|
|
bIsExpanded = bIsExpanded && pRow->IsExpanded();
|
||
|
|
pRow = pRow->GetParentRow();
|
||
|
|
}
|
||
|
|
|
||
|
|
if(bIsExpanded)
|
||
|
|
{
|
||
|
|
if(bInsertAfter)
|
||
|
|
InsertRow(nNextSiblingIndex, pPlainTreeRow ? pPlainTreeRow : pNewRow);
|
||
|
|
else
|
||
|
|
InsertRow(pInsertRowPos->GetIndex(), pPlainTreeRow ? pPlainTreeRow : pNewRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
InsertRow(m_pRows->GetCount(), pPlainTreeRow ? pPlainTreeRow : pNewRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pNewRow->GetParentRow();
|
||
|
|
BOOL bIsExpanded = TRUE;
|
||
|
|
while(pRow && bIsExpanded)
|
||
|
|
{
|
||
|
|
bIsExpanded = bIsExpanded && pRow->IsExpanded();
|
||
|
|
pRow = pRow->GetParentRow();
|
||
|
|
}
|
||
|
|
|
||
|
|
if(bIsExpanded)
|
||
|
|
InsertRow(nNextSiblingIndex, pNewRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
RefreshIndexes(FALSE, TRUE);
|
||
|
|
|
||
|
|
// add children
|
||
|
|
if(pRecord && pRecord->HasChildren())
|
||
|
|
{
|
||
|
|
for(int nChild = 0; nChild < pRecord->GetChilds()->GetCount(); nChild++)
|
||
|
|
{
|
||
|
|
AddRecordEx(pRecord->GetChilds()->GetAt(nChild), pRecord);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::RemoveRowEx(CXTPReportRow* pRow, BOOL bAdjustLayout)
|
||
|
|
{
|
||
|
|
ASSERT(pRow);
|
||
|
|
if (!pRow)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
//------------------------------------------------
|
||
|
|
if (!pRow->IsGroupRow())
|
||
|
|
{
|
||
|
|
ASSERT(pRow->GetRecord());
|
||
|
|
return RemoveRecordEx(pRow->GetRecord(), bAdjustLayout);
|
||
|
|
}
|
||
|
|
|
||
|
|
//------------------------------------------------
|
||
|
|
CWaitCursor _WC;
|
||
|
|
|
||
|
|
int nCount = pRow->GetChilds()->GetCount();
|
||
|
|
ASSERT(nCount);
|
||
|
|
|
||
|
|
for (int i = nCount - 1; i >= 0 ; i--)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRowI = pRow->GetChilds()->GetAt(i);
|
||
|
|
RemoveRowEx(pRowI, bAdjustLayout);
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::RemoveRecordEx(CXTPReportRecord* pRecord, BOOL bAdjustLayout, BOOL bRemoveFromParent)
|
||
|
|
{
|
||
|
|
ASSERT(pRecord && m_pRecords);
|
||
|
|
|
||
|
|
if (!pRecord || !m_pRecords)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
if (pRecord->HasChildren())
|
||
|
|
{
|
||
|
|
for (int i = pRecord->GetChilds()->GetCount() - 1; i >= 0 ; i--)
|
||
|
|
{
|
||
|
|
RemoveRecordEx(pRecord->GetChilds()->GetAt(i), bAdjustLayout, FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
// return RemoveRecordEx(pRecord, bAdjustLayout);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL bResult = FALSE;
|
||
|
|
|
||
|
|
//--------------------------------------------------------
|
||
|
|
CXTPReportRow* pRow0 = m_pPlainTree->FindInTree(pRecord);
|
||
|
|
|
||
|
|
ASSERT_DBG_REMOVE_RECORD_EX(pRow0);
|
||
|
|
|
||
|
|
if (pRow0)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pRow0;
|
||
|
|
pRow0 = NULL;
|
||
|
|
|
||
|
|
do
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow_parent = pRow->GetParentRow();
|
||
|
|
|
||
|
|
ASSERT(pRow->GetParentRows());
|
||
|
|
|
||
|
|
// 1. Remove from selected rows
|
||
|
|
if(m_pSelectedRows->Contains(pRow))
|
||
|
|
m_pSelectedRows->Remove(pRow);
|
||
|
|
|
||
|
|
// 2. remove from Rows Tree
|
||
|
|
if (pRow->GetParentRows())
|
||
|
|
VERIFY(pRow->GetParentRows()->RemoveRow(pRow) >= 0);
|
||
|
|
|
||
|
|
// 3. remove from Display Rows array
|
||
|
|
m_pRows->RemoveRow(pRow);
|
||
|
|
|
||
|
|
pRow = pRow_parent;
|
||
|
|
|
||
|
|
} while (pRow && pRow->IsGroupRow() && pRow->GetChilds()->GetCount() == 0);
|
||
|
|
|
||
|
|
// refresh child indices
|
||
|
|
if(pRow && pRow->HasChildren())
|
||
|
|
pRow->GetChilds()->RefreshChildIndices();
|
||
|
|
else
|
||
|
|
m_pPlainTree->RefreshChildIndices();
|
||
|
|
|
||
|
|
bResult = TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-------------------------------------------------------
|
||
|
|
//pRecord->Delete(); // the code below is more safe when record already removed!
|
||
|
|
|
||
|
|
ASSERT(pRecord->GetRecords());
|
||
|
|
|
||
|
|
if (bRemoveFromParent && pRecord->GetRecords())
|
||
|
|
{
|
||
|
|
BOOL bRecordRem = pRecord->GetRecords()->RemoveRecord(pRecord) >= 0;
|
||
|
|
pRecord = NULL;
|
||
|
|
ASSERT_DBG_REMOVE_RECORD_EX(bRecordRem);
|
||
|
|
|
||
|
|
bResult |= bRecordRem;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_nFocusedRow >= 0 && m_nFocusedRow >= m_pRows->GetCount())
|
||
|
|
m_nFocusedRow = m_pRows->GetCount() - 1;
|
||
|
|
|
||
|
|
//-------------------------------------------------------
|
||
|
|
if (bResult)
|
||
|
|
RefreshIndexes(bAdjustLayout);
|
||
|
|
|
||
|
|
return bResult;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::UpdateRecord(CXTPReportRecord* pRecord, BOOL bUpdateChildren)
|
||
|
|
{
|
||
|
|
// get parent record
|
||
|
|
CXTPReportRecord* pParentRecord = NULL;
|
||
|
|
if(pRecord->GetRecords())
|
||
|
|
pParentRecord = pRecord->GetRecords()->GetOwnerRecord();
|
||
|
|
// update record
|
||
|
|
if(!pParentRecord || bUpdateChildren)
|
||
|
|
{
|
||
|
|
// internal addref
|
||
|
|
pRecord->TreeAddRef();
|
||
|
|
// get record row child index
|
||
|
|
CXTPReportRow* pRow = m_pPlainTree->FindInTree(pRecord);
|
||
|
|
int nChildIndex = pRow->m_nChildIndex;
|
||
|
|
// remove record
|
||
|
|
RemoveRecordEx(pRecord, FALSE);
|
||
|
|
// add record
|
||
|
|
AddRecordEx(pRecord, pParentRecord, nChildIndex);
|
||
|
|
// internal release
|
||
|
|
pRecord->TreeRelease();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DrawNoItems(CDC* pDC, const CRect& rcClient)
|
||
|
|
{
|
||
|
|
pDC->SetTextColor(GetPaintManager()->m_clrWindowText);
|
||
|
|
CString strNoItems = GetPaintManager()->m_strNoItems;
|
||
|
|
|
||
|
|
if (!strNoItems.IsEmpty())
|
||
|
|
{
|
||
|
|
CRect rcText(rcClient);
|
||
|
|
rcText.DeflateRect(5, 5, 5, 5);
|
||
|
|
CXTPFontDC font(pDC, &GetPaintManager()->m_fontText);
|
||
|
|
UINT uFlags = DT_CENTER | DT_TOP | DT_NOPREFIX | DT_WORDBREAK |
|
||
|
|
DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_EDITCONTROL;
|
||
|
|
|
||
|
|
pDC->DrawText(strNoItems, rcText, uFlags);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DrawRows(CDC* pDC, CRect& rcClient)
|
||
|
|
{
|
||
|
|
m_arrScreenRows.Clear(FALSE);
|
||
|
|
|
||
|
|
pDC->SetBkMode(TRANSPARENT);
|
||
|
|
|
||
|
|
int y = rcClient.top;
|
||
|
|
|
||
|
|
int nRowCount = m_pRows->GetCount();
|
||
|
|
|
||
|
|
if (0 == nRowCount)
|
||
|
|
{
|
||
|
|
DrawNoItems(pDC, rcClient);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GetReportHeader()->GetNextVisibleColumn(-1, 1) == NULL)
|
||
|
|
return;
|
||
|
|
|
||
|
|
int nRowHeight = 0;
|
||
|
|
int nHeaderWidth = GetReportHeader()->GetWidth();
|
||
|
|
|
||
|
|
|
||
|
|
//m_arrScreenRows.ReserveSize(200);
|
||
|
|
m_arrScreenRows.SetSize(0, 200);
|
||
|
|
|
||
|
|
for (int i = m_nTopRow; i < nRowCount; i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(i);
|
||
|
|
ASSERT(pRow);
|
||
|
|
if (!pRow)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
if (y > rcClient.bottom)
|
||
|
|
break;
|
||
|
|
|
||
|
|
nRowHeight = pRow->GetHeight(pDC, nHeaderWidth);
|
||
|
|
|
||
|
|
CRect rcRow(rcClient.left, y, rcClient.left + nHeaderWidth,
|
||
|
|
y + pRow->GetHeight(pDC, nHeaderWidth));
|
||
|
|
|
||
|
|
pRow->Draw(pDC, rcRow, m_nLeftOffset);
|
||
|
|
|
||
|
|
y += rcRow.Height();
|
||
|
|
|
||
|
|
|
||
|
|
CXTPReportRow* pScreenRow = NULL;
|
||
|
|
if (IsVirtualMode())
|
||
|
|
{
|
||
|
|
pScreenRow = CreateRow();
|
||
|
|
pScreenRow->InitRow(pRow);
|
||
|
|
pScreenRow->m_bExpanded = pRow->m_bExpanded;
|
||
|
|
if(pScreenRow->m_nRowLevel == 0)
|
||
|
|
pScreenRow->m_rcCollapse = pRow->m_rcCollapse;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
pScreenRow = pRow;
|
||
|
|
pScreenRow->InternalAddRef();
|
||
|
|
|
||
|
|
}
|
||
|
|
m_arrScreenRows.InsertAt(m_arrScreenRows.GetCount(), pScreenRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
// fill the rest of space with the "fake" rows
|
||
|
|
if (GetPaintManager()->IsDrawGridForEmptySpace() && y < rcClient.bottom)
|
||
|
|
{
|
||
|
|
CRect rcEmpty(rcClient);
|
||
|
|
rcEmpty.top = y;
|
||
|
|
DrawDefaultGrid(pDC, rcEmpty, nRowHeight, m_nLeftOffset);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DrawFixedRows(CDC* pDC, CRect& rcClient, CXTPReportRows* pRows)
|
||
|
|
{
|
||
|
|
pDC->SetBkMode(TRANSPARENT);
|
||
|
|
|
||
|
|
int y = rcClient.top;
|
||
|
|
|
||
|
|
int nRowCount = pRows->GetCount();
|
||
|
|
|
||
|
|
if ( nRowCount > 0 )
|
||
|
|
{
|
||
|
|
if (GetReportHeader()->GetNextVisibleColumn(-1, 1) == NULL)
|
||
|
|
return;
|
||
|
|
|
||
|
|
int nHeaderWidth = GetReportHeader()->GetWidth();
|
||
|
|
|
||
|
|
for (int i = 0; i < nRowCount; i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pRows->GetAt(i);
|
||
|
|
|
||
|
|
if (y > rcClient.bottom)
|
||
|
|
break;
|
||
|
|
|
||
|
|
CRect rcRow(rcClient.left, y, rcClient.left + nHeaderWidth,
|
||
|
|
y + pRow->GetHeight(pDC, nHeaderWidth));
|
||
|
|
|
||
|
|
pRow->DrawFixed(pDC, rcRow, m_nLeftOffset, rcClient);
|
||
|
|
|
||
|
|
y += rcRow.Height();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DrawFixedRecordsDivider(CDC* pDC, CRect& rcClient, BOOL bHeaderRows)
|
||
|
|
{
|
||
|
|
GetPaintManager()->DrawFixedRowsDivider(pDC, rcClient, this, bHeaderRows, m_bVScrollBarVisible);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnSelectionChanged()
|
||
|
|
{
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_SELCHANGED);
|
||
|
|
if (m_pSelectedRows)
|
||
|
|
m_pSelectedRows->SetChanged(FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnFocusChanging(CXTPReportRow* pNewRow, CXTPReportColumn* pNewCol)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORTREQUESTEDIT nm;
|
||
|
|
::ZeroMemory(&nm, sizeof(nm));
|
||
|
|
|
||
|
|
nm.bCancel = FALSE;
|
||
|
|
nm.pRow = pNewRow ? pNewRow : GetFocusedRow();
|
||
|
|
nm.pColumn = pNewCol ? pNewCol : GetFocusedColumn();
|
||
|
|
nm.pItem = nm.pRow && nm.pColumn ? (nm.pRow->GetRecord() ? nm.pRow->GetRecord()->GetItem(nm.pColumn) : NULL) : NULL;
|
||
|
|
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_FOCUS_CHANGING, (NMHDR*)&nm);
|
||
|
|
|
||
|
|
return !nm.bCancel;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::GetItemMetrics(XTP_REPORTRECORDITEM_DRAWARGS* pDrawArgs,
|
||
|
|
XTP_REPORTRECORDITEM_METRICS* pMetrics)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORTITEMMETRICS nmData;
|
||
|
|
nmData.pDrawArgs = pDrawArgs;
|
||
|
|
nmData.pItemMetrics = pMetrics;
|
||
|
|
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_GETITEMMETRICS, (NMHDR*)&nmData);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::SetFocusedColumn(CXTPReportColumn* pColumn)
|
||
|
|
{
|
||
|
|
if (m_pFocusedColumn != pColumn)
|
||
|
|
{
|
||
|
|
if (m_bFocusSubItems && pColumn)
|
||
|
|
{
|
||
|
|
if(!OnFocusChanging(NULL, pColumn))
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pFocusedColumn = pColumn;
|
||
|
|
|
||
|
|
if (m_pFocusedColumn && m_bFocusSubItems)
|
||
|
|
{
|
||
|
|
CRect rc(m_pFocusedColumn->GetRect());
|
||
|
|
|
||
|
|
if (rc.right >= m_rcReportArea.Width())
|
||
|
|
{
|
||
|
|
SetLeftOffset(m_nLeftOffset + min(rc.left, rc.right - m_rcReportArea.Width()));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int nFreezeColumnWidth = 0;
|
||
|
|
if (m_nFreezeColumnsCount > 0)
|
||
|
|
{
|
||
|
|
int nFreezeColumnsCount = m_nFreezeColumnsCount;
|
||
|
|
for (int i = 0; (i < m_pColumns->GetCount()) && (nFreezeColumnsCount > 0); i++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumnCheck = m_pColumns->GetAt(i);
|
||
|
|
|
||
|
|
if (pColumnCheck == m_pFocusedColumn)
|
||
|
|
{
|
||
|
|
nFreezeColumnWidth = 0;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pColumnCheck && pColumnCheck->IsVisible())
|
||
|
|
{
|
||
|
|
nFreezeColumnsCount--;
|
||
|
|
nFreezeColumnWidth = pColumnCheck->GetRect().right;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (rc.left - nFreezeColumnWidth <= 0 && m_nLeftOffset != 0)
|
||
|
|
{
|
||
|
|
SetLeftOffset(m_nLeftOffset + rc.left - nFreezeColumnWidth);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bFocusSubItems)
|
||
|
|
{
|
||
|
|
OnSelectionChanged();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::SetFocusedRow(CXTPReportRow* pRow, BOOL bIgnoreSelection)
|
||
|
|
{
|
||
|
|
if(pRow)
|
||
|
|
{
|
||
|
|
int nFocusedRow = m_nFocusedRow != -1 ? m_nFocusedRow : m_nFocusedHeaderRow != -1 ? m_nFocusedHeaderRow : m_nFocusedFooterRow;
|
||
|
|
int nFocusedRowType = m_nFocusedRow != -1 ? xtpRowTypeBody : m_nFocusedHeaderRow != -1 ? xtpRowTypeHeader : xtpRowTypeFooter;
|
||
|
|
|
||
|
|
if (nFocusedRow != pRow->GetIndex() || pRow->GetType() != nFocusedRowType)
|
||
|
|
{
|
||
|
|
if (!OnFocusChanging(pRow, NULL))
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
EditItem(NULL);
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
BOOL bEnableSelection = (!bIgnoreSelection || !m_bMultipleSelection) && IsSelectionEnabled();
|
||
|
|
if (pRow && pRow->GetType() == xtpRowTypeHeader)
|
||
|
|
bEnableSelection &= IsHeaderRowsSelectionEnabled();
|
||
|
|
if (pRow && pRow->GetType() == xtpRowTypeFooter)
|
||
|
|
bEnableSelection &= IsFooterRowsSelectionEnabled();
|
||
|
|
|
||
|
|
if (bEnableSelection)
|
||
|
|
{
|
||
|
|
m_pSelectedRows->Select(pRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
m_nFocusedRow = m_nFocusedHeaderRow = m_nFocusedFooterRow = -1;
|
||
|
|
|
||
|
|
switch (pRow->GetType())
|
||
|
|
{
|
||
|
|
case xtpRowTypeBody: m_nFocusedRow = pRow->GetIndex(); break;
|
||
|
|
case xtpRowTypeHeader: m_nFocusedHeaderRow = pRow->GetIndex(); break;
|
||
|
|
case xtpRowTypeFooter: m_nFocusedFooterRow = pRow->GetIndex(); break;
|
||
|
|
}
|
||
|
|
|
||
|
|
GetNavigator()->SetMovePosition(pRow->GetType());
|
||
|
|
|
||
|
|
EnsureVisible(pRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
|
||
|
|
if (m_pSelectedRows->IsChanged())
|
||
|
|
OnSelectionChanged();
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::SetFocusedRow(CXTPReportRow* pRow, BOOL bSelectBlock, BOOL bIgnoreSelection)
|
||
|
|
{
|
||
|
|
if (!pRow)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
int nFocusedRow = m_nFocusedRow != -1 ? m_nFocusedRow : m_nFocusedHeaderRow != -1 ? m_nFocusedHeaderRow : m_nFocusedFooterRow;
|
||
|
|
int nFocusedRowType = m_nFocusedRow != -1 ? xtpRowTypeBody : m_nFocusedHeaderRow != -1 ? xtpRowTypeHeader : xtpRowTypeFooter;
|
||
|
|
|
||
|
|
if (nFocusedRow != pRow->GetIndex() || pRow->GetType() != nFocusedRowType)
|
||
|
|
{
|
||
|
|
if (!OnFocusChanging(pRow, NULL))
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
EditItem(NULL);
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
BOOL bEnableSelection = IsSelectionEnabled();
|
||
|
|
if(pRow && pRow->GetType() == xtpRowTypeHeader)
|
||
|
|
bEnableSelection &= IsHeaderRowsSelectionEnabled();
|
||
|
|
if(pRow && pRow->GetType() == xtpRowTypeFooter)
|
||
|
|
bEnableSelection &= IsFooterRowsSelectionEnabled();
|
||
|
|
|
||
|
|
if(bEnableSelection)
|
||
|
|
{
|
||
|
|
if (m_bMultipleSelection)
|
||
|
|
{
|
||
|
|
nFocusedRow = m_nFocusedRow != -1 ? m_nFocusedRow : m_nFocusedHeaderRow != -1 ? m_nFocusedHeaderRow : m_nFocusedFooterRow;
|
||
|
|
if (bSelectBlock && nFocusedRow != -1)
|
||
|
|
{
|
||
|
|
m_pSelectedRows->SelectBlock(nFocusedRow, pRow->GetIndex());
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (!bIgnoreSelection)
|
||
|
|
{
|
||
|
|
m_pSelectedRows->Select(pRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_pSelectedRows->Select(pRow);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
m_nFocusedRow = m_nFocusedHeaderRow = m_nFocusedFooterRow = -1;
|
||
|
|
|
||
|
|
switch(pRow->GetType())
|
||
|
|
{
|
||
|
|
case xtpRowTypeBody: m_nFocusedRow = pRow->GetIndex(); break;
|
||
|
|
case xtpRowTypeHeader: m_nFocusedHeaderRow = pRow->GetIndex(); break;
|
||
|
|
case xtpRowTypeFooter: m_nFocusedFooterRow = pRow->GetIndex(); break;
|
||
|
|
}
|
||
|
|
|
||
|
|
GetNavigator()->SetMovePosition(pRow->GetType());
|
||
|
|
|
||
|
|
EnsureVisible(pRow);
|
||
|
|
EndUpdate();
|
||
|
|
|
||
|
|
if (m_pSelectedRows->IsChanged())
|
||
|
|
OnSelectionChanged();
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void CXTPReportControl::SetLeftOffset(int nOffset)
|
||
|
|
{
|
||
|
|
if (nOffset < 0)
|
||
|
|
nOffset = 0;
|
||
|
|
|
||
|
|
if (nOffset == m_nLeftOffset)
|
||
|
|
return;
|
||
|
|
|
||
|
|
m_nLeftOffset = nOffset;
|
||
|
|
|
||
|
|
if (!m_bFullColumnScrolling)
|
||
|
|
SetScrollPos(SB_HORZ, nOffset);
|
||
|
|
|
||
|
|
AdjustScrollBars();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetTopRow(int nIndex)
|
||
|
|
{
|
||
|
|
if (nIndex == m_nTopRow)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ASSERT(nIndex >= 0);
|
||
|
|
|
||
|
|
if (nIndex < 0)
|
||
|
|
nIndex = 0;
|
||
|
|
|
||
|
|
m_nTopRow = nIndex;
|
||
|
|
SetScrollPos(SB_VERT, nIndex);
|
||
|
|
AdjustScrollBars();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EnsureVisible(CXTPReportRow* pCheckRow)
|
||
|
|
{
|
||
|
|
int nCheckIndex = pCheckRow ? pCheckRow->GetIndex() : -1;
|
||
|
|
|
||
|
|
if (nCheckIndex == -1 || !pCheckRow->m_bVisible || nCheckIndex >= m_pRows->GetCount())
|
||
|
|
return;
|
||
|
|
|
||
|
|
if(m_rcReportArea.Height() <= 0)
|
||
|
|
{
|
||
|
|
m_nEnsureVisibleRowIdx = nCheckIndex;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nCheckIndex < m_nTopRow)
|
||
|
|
{
|
||
|
|
SetTopRow(nCheckIndex);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
CClientDC dc (this);
|
||
|
|
|
||
|
|
int top = m_rcReportArea.top;
|
||
|
|
int nHeaderWidth = GetReportHeader()->GetWidth();
|
||
|
|
|
||
|
|
for (int i = m_nTopRow; i < m_pRows->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(i);
|
||
|
|
ASSERT(pRow);
|
||
|
|
if (!pRow)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
int nRowHeight = pRow->GetHeight(&dc, nHeaderWidth);
|
||
|
|
|
||
|
|
if (top + nRowHeight > m_rcReportArea.bottom)
|
||
|
|
break;
|
||
|
|
|
||
|
|
if (i == nCheckIndex)
|
||
|
|
return;
|
||
|
|
|
||
|
|
top += nRowHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
int nHeight = m_rcReportArea.Height();
|
||
|
|
for (top = nCheckIndex; top >= 0; top--)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(top);
|
||
|
|
int nRowHeight = pRow->GetHeight(&dc, nHeaderWidth);
|
||
|
|
|
||
|
|
if (nHeight - nRowHeight < 0)
|
||
|
|
{
|
||
|
|
if (top != nCheckIndex)
|
||
|
|
top++;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
nHeight -= nRowHeight;
|
||
|
|
}
|
||
|
|
SetTopRow(top);
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EnsureVisible(CXTPReportColumn* pCheckColumn)
|
||
|
|
{
|
||
|
|
int nCheckIndex = pCheckColumn ? pCheckColumn->GetIndex() : -1;
|
||
|
|
|
||
|
|
if (nCheckIndex == -1 || !pCheckColumn->m_bVisible || nCheckIndex >= m_pColumns->GetCount())
|
||
|
|
return;
|
||
|
|
|
||
|
|
if(m_rcReportArea.Height() <= 0)
|
||
|
|
{
|
||
|
|
m_nEnsureVisibleRowIdx = nCheckIndex;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
CRect rc(pCheckColumn->GetRect());
|
||
|
|
|
||
|
|
if (rc.right >= m_rcReportArea.Width())
|
||
|
|
{
|
||
|
|
SetLeftOffset(m_nLeftOffset + min(rc.left, rc.right - m_rcReportArea.Width()));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int nFreezeColumnWidth = 0;
|
||
|
|
if (m_nFreezeColumnsCount > 0)
|
||
|
|
{
|
||
|
|
int nFreezeColumnsCount = m_nFreezeColumnsCount;
|
||
|
|
for (int i = 0; (i < m_pColumns->GetCount()) && (nFreezeColumnsCount > 0); i++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = m_pColumns->GetAt(i);
|
||
|
|
|
||
|
|
if (pColumn == pCheckColumn)
|
||
|
|
{
|
||
|
|
nFreezeColumnWidth = 0;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pColumn && pColumn->IsVisible())
|
||
|
|
{
|
||
|
|
nFreezeColumnsCount--;
|
||
|
|
nFreezeColumnWidth = pColumn->GetRect().right;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (rc.left - nFreezeColumnWidth <= 0 && m_nLeftOffset != 0)
|
||
|
|
{
|
||
|
|
SetLeftOffset(m_nLeftOffset + rc.left - nFreezeColumnWidth);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRow* CXTPReportControl::HitTest(CPoint pt) const
|
||
|
|
{
|
||
|
|
if (m_rcReportArea.PtInRect(pt))
|
||
|
|
{
|
||
|
|
for (int i = 0; i < m_arrScreenRows.GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_arrScreenRows.GetAt(i);
|
||
|
|
|
||
|
|
CRect rc = pRow->GetRect();
|
||
|
|
|
||
|
|
if (rc.PtInRect(pt))
|
||
|
|
return pRow;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// header records
|
||
|
|
if (m_rcHeaderRecordsArea.PtInRect(pt))
|
||
|
|
{
|
||
|
|
for (int i = 0; i < m_pHeaderRows->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pHeaderRows->GetAt(i);
|
||
|
|
|
||
|
|
CRect rc = pRow->GetRect();
|
||
|
|
|
||
|
|
if (rc.PtInRect(pt))
|
||
|
|
return pRow;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// footer records
|
||
|
|
if (m_rcFooterRecordsArea.PtInRect(pt))
|
||
|
|
{
|
||
|
|
for (int i = 0; i < m_pFooterRows->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pFooterRows->GetAt(i);
|
||
|
|
|
||
|
|
CRect rc = pRow->GetRect();
|
||
|
|
|
||
|
|
if (rc.PtInRect(pt))
|
||
|
|
return pRow;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::GetReportAreaRows(int nStartRow, BOOL bMoveDown)
|
||
|
|
{
|
||
|
|
int nDirection = bMoveDown ? +1 : -1;
|
||
|
|
|
||
|
|
int top = m_rcReportArea.top;
|
||
|
|
|
||
|
|
CClientDC dc(this);
|
||
|
|
int nHeaderWidth = GetReportHeader()->GetWidth();
|
||
|
|
|
||
|
|
for (int i = nStartRow; (i < m_pRows->GetCount() && i >= 0); i += nDirection)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_pRows->GetAt(i);
|
||
|
|
ASSERT(pRow);
|
||
|
|
if (!pRow)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
int rowHeight = pRow->GetHeight(&dc, nHeaderWidth);
|
||
|
|
|
||
|
|
if (top + rowHeight > m_rcReportArea.bottom)
|
||
|
|
return bMoveDown ? i - nStartRow - 1 : nStartRow - i - 1;
|
||
|
|
|
||
|
|
top += rowHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
return bMoveDown ? m_pRows->GetCount() - nStartRow : nStartRow;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::AdjustLayout()
|
||
|
|
{
|
||
|
|
if (GetSafeHwnd() == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
CXTPClientRect rc(this);
|
||
|
|
|
||
|
|
int nHeaderWidth = m_rcHeaderArea.Width();
|
||
|
|
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
int nGroupByHeight = (m_bGroupByEnabled && pHeader) ? pHeader->GetGroupByHeight() : 0;
|
||
|
|
m_rcGroupByArea.SetRect(0, 0, rc.Width(), nGroupByHeight);
|
||
|
|
|
||
|
|
int nHeaderHeight = 0;
|
||
|
|
int nFooterHeight = 0;
|
||
|
|
int nHeaderRecordsHeight = 0;
|
||
|
|
int nFooterRecordsHeight = 0;
|
||
|
|
|
||
|
|
if (m_bHeaderVisible)
|
||
|
|
{
|
||
|
|
CWindowDC dc (this);
|
||
|
|
nHeaderHeight = GetPaintManager()->GetHeaderHeight(this, &dc);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bFooterVisible)
|
||
|
|
{
|
||
|
|
CWindowDC dc (this);
|
||
|
|
nFooterHeight = GetPaintManager()->GetFooterHeight(this, &dc);
|
||
|
|
}
|
||
|
|
|
||
|
|
// header records divider
|
||
|
|
int nHeaderDividerHeight = GetHeaderRowsDividerHeight();
|
||
|
|
int nFooterDividerHeight = GetFooterRowsDividerHeight();
|
||
|
|
|
||
|
|
// header records height
|
||
|
|
if (m_bHeaderRecordsVisible)
|
||
|
|
{
|
||
|
|
nHeaderRecordsHeight = GetRowsHeight(m_pHeaderRows, rc.Width());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
nHeaderDividerHeight = 0;
|
||
|
|
|
||
|
|
// footer records height
|
||
|
|
if (m_bFooterRecordsVisible)
|
||
|
|
{
|
||
|
|
nFooterRecordsHeight = GetRowsHeight(m_pFooterRows, rc.Width());
|
||
|
|
}
|
||
|
|
|
||
|
|
m_rcHeaderArea.SetRect(0, m_rcGroupByArea.bottom, rc.Width(), m_rcGroupByArea.bottom + nHeaderHeight);
|
||
|
|
m_rcHeaderRecordsArea.SetRect(0, m_rcHeaderArea.bottom, rc.Width(), m_rcHeaderArea.bottom + nHeaderRecordsHeight);
|
||
|
|
|
||
|
|
|
||
|
|
m_rcHeaderRecordsDividerArea.SetRect(0, m_rcHeaderRecordsArea.bottom, rc.Width(), m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight);
|
||
|
|
|
||
|
|
int nFreeHeight = rc.Height() - nGroupByHeight- nHeaderHeight - nFooterHeight - nHeaderRecordsHeight - nFooterRecordsHeight - nHeaderDividerHeight - nFooterDividerHeight;
|
||
|
|
BOOL bPinned = FALSE;
|
||
|
|
|
||
|
|
if (m_bFooterRecordsVisible && m_bPinFooterRecords)
|
||
|
|
{
|
||
|
|
int nBodyRowsHeight = GetRowsHeight(m_pRows, rc.Width(), nFreeHeight);
|
||
|
|
|
||
|
|
if (nBodyRowsHeight < nFreeHeight)
|
||
|
|
{
|
||
|
|
// footer records immediately after body records
|
||
|
|
m_rcFooterRecordsArea.SetRect(0, m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight + nFooterDividerHeight + nBodyRowsHeight, rc.Width(),
|
||
|
|
m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight + nFooterDividerHeight + nBodyRowsHeight + nFooterRecordsHeight);
|
||
|
|
|
||
|
|
m_rcFooterRecordsDividerArea.SetRect(0,m_rcFooterRecordsArea.top - nFooterDividerHeight,rc.Width(), m_rcFooterRecordsArea.top);
|
||
|
|
bPinned = TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!bPinned)
|
||
|
|
{
|
||
|
|
if (rc.Height() - nFooterHeight - nFooterRecordsHeight > m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight)
|
||
|
|
{
|
||
|
|
// there can be empty space between body rows and footer records rows
|
||
|
|
m_rcFooterRecordsArea.SetRect(0, rc.Height() - nFooterHeight - nFooterRecordsHeight, rc.Width(), rc.Height() - nFooterHeight);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// no place for body records (between header and footer records)
|
||
|
|
m_rcFooterRecordsArea.SetRect(0, m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight, rc.Width(), m_rcHeaderRecordsArea.bottom + nFooterRecordsHeight + nHeaderDividerHeight);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_rcFooterRecordsDividerArea.SetRect(0,m_rcFooterRecordsArea.top - nFooterDividerHeight -1,rc.Width(), m_rcFooterRecordsArea.top);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_rcFooterArea.SetRect(0, rc.Height() - nFooterHeight, rc.Width(), rc.Height());
|
||
|
|
m_rcReportArea.SetRect(0, m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight, rc.Width(), m_rcFooterRecordsArea.top - nFooterDividerHeight);
|
||
|
|
|
||
|
|
if (nHeaderWidth != m_rcHeaderArea.Width() && pHeader)
|
||
|
|
{
|
||
|
|
pHeader->AdjustColumnsWidth(m_rcHeaderArea.Width());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CScrollBar* CXTPReportControl::GetScrollBarCtrl(int nBar) const
|
||
|
|
{
|
||
|
|
if (DYNAMIC_DOWNCAST(CView, GetParent()))
|
||
|
|
return GetParent()->GetScrollBarCtrl(nBar);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::AdjustScrollBars()
|
||
|
|
{
|
||
|
|
if (GetSafeHwnd() == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
EditItem(NULL);
|
||
|
|
|
||
|
|
int nHeight = m_rcReportArea.Height();
|
||
|
|
|
||
|
|
if (nHeight <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
int nCount = m_pRows->GetCount() - 1;
|
||
|
|
int nLinesCount = nCount;
|
||
|
|
int nHeaderWidth = GetReportHeader()->GetWidth();
|
||
|
|
|
||
|
|
{
|
||
|
|
CClientDC dc(this);
|
||
|
|
|
||
|
|
for (; nLinesCount >= 0; nLinesCount--)
|
||
|
|
{
|
||
|
|
|
||
|
|
nHeight -= m_pRows->GetAt(nLinesCount)->GetHeight(&dc, nHeaderWidth);
|
||
|
|
|
||
|
|
if (nHeight < 0)
|
||
|
|
{
|
||
|
|
if (nLinesCount != nCount)
|
||
|
|
nLinesCount++;
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
nLinesCount = max(nLinesCount, 0);
|
||
|
|
|
||
|
|
if (m_nTopRow > nLinesCount)
|
||
|
|
{
|
||
|
|
m_nTopRow = nLinesCount;
|
||
|
|
SetScrollPos(SB_VERT, m_nTopRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL bEnabled = nLinesCount > 0;
|
||
|
|
|
||
|
|
if (bEnabled)
|
||
|
|
{
|
||
|
|
SCROLLINFO si ;
|
||
|
|
si.cbSize = sizeof(SCROLLINFO);
|
||
|
|
si.nPage = nCount - nLinesCount + 1;
|
||
|
|
si.nMax = nCount;
|
||
|
|
si.nMin = 0 ;
|
||
|
|
si.fMask = SIF_PAGE | SIF_RANGE ;
|
||
|
|
SetScrollInfo(SB_VERT, &si) ;
|
||
|
|
}
|
||
|
|
|
||
|
|
EnableScrollBarCtrl(SB_VERT, bEnabled);
|
||
|
|
|
||
|
|
::EnableScrollBar(m_hWnd, SB_VERT, (bEnabled && IsWindowEnabled()) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
|
||
|
|
|
||
|
|
m_bVScrollBarVisible = bEnabled;
|
||
|
|
|
||
|
|
|
||
|
|
if (!GetReportHeader()->m_bAutoColumnSizing)
|
||
|
|
{
|
||
|
|
if (m_bFullColumnScrolling)
|
||
|
|
{
|
||
|
|
CXTPReportColumn *pPrev = NULL, *pCurr = NULL, *pNext = NULL;
|
||
|
|
int nScrollPos, nScrollMax;
|
||
|
|
GetReportHeader()->GetFulColScrollInfo(pPrev, pCurr, pNext, nScrollPos, nScrollMax);
|
||
|
|
|
||
|
|
bEnabled = nScrollMax > 1;
|
||
|
|
|
||
|
|
if (bEnabled)
|
||
|
|
{
|
||
|
|
SCROLLINFO si ;
|
||
|
|
si.cbSize = sizeof(SCROLLINFO);
|
||
|
|
si.nPage = 1;
|
||
|
|
si.nMax = nScrollMax - 1;
|
||
|
|
si.nMin = 0;
|
||
|
|
si.nPos = nScrollPos;
|
||
|
|
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
||
|
|
SetScrollInfo(SB_HORZ, &si) ;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_nLeftOffset = 0;
|
||
|
|
SetScrollPos(SB_HORZ, m_nLeftOffset);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
nHeaderWidth = max(GetReportHeader()->GetWidth() - m_rcReportArea.Width(), 0);
|
||
|
|
|
||
|
|
if (m_nLeftOffset > nHeaderWidth)
|
||
|
|
{
|
||
|
|
m_nLeftOffset = nHeaderWidth;
|
||
|
|
SetScrollPos(SB_HORZ, m_nLeftOffset);
|
||
|
|
}
|
||
|
|
|
||
|
|
bEnabled = nHeaderWidth > 0;
|
||
|
|
|
||
|
|
if (bEnabled)
|
||
|
|
{
|
||
|
|
SCROLLINFO si ;
|
||
|
|
si.cbSize = sizeof(SCROLLINFO);
|
||
|
|
si.nPage = m_rcReportArea.Width();
|
||
|
|
si.nMax = si.nPage + nHeaderWidth;
|
||
|
|
si.nMin = 0 ;
|
||
|
|
si.fMask = SIF_PAGE | SIF_RANGE ;
|
||
|
|
SetScrollInfo(SB_HORZ, &si) ;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
EnableScrollBarCtrl(SB_HORZ, bEnabled);
|
||
|
|
m_bHScrollBarVisible = bEnabled;
|
||
|
|
::EnableScrollBar(m_hWnd, SB_HORZ, (bEnabled && IsWindowEnabled()) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
AdjustLayout();
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetFullColumnScrolling(BOOL bSet)
|
||
|
|
{
|
||
|
|
m_bFullColumnScrolling = bSet;
|
||
|
|
|
||
|
|
if (m_hWnd)
|
||
|
|
{
|
||
|
|
CXTPReportControl::OnHScroll(SB_TOP, 0, NULL);
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
UpdateWindow();
|
||
|
|
|
||
|
|
AdjustScrollBars();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::SetWatermarkBitmap(HBITMAP hBitmap, BYTE Transparency)
|
||
|
|
{
|
||
|
|
m_WatermarkTransparency = Transparency;
|
||
|
|
|
||
|
|
// if bitmap handle is NULL, remove watermark bitmap
|
||
|
|
if(!hBitmap)
|
||
|
|
{
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// remove old watermark bitmap if one is
|
||
|
|
if(m_hbmpWatermark)
|
||
|
|
{
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
}
|
||
|
|
// add new watermark bitmap
|
||
|
|
m_hbmpWatermark = CXTPImageManagerIcon::CopyAlphaBitmap(hBitmap);
|
||
|
|
if(!m_hbmpWatermark)
|
||
|
|
return FALSE;
|
||
|
|
if(!CBitmap::FromHandle(m_hbmpWatermark)->GetBitmap(&m_bmWatermark))
|
||
|
|
{
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
BOOL bAlphaBitmap = m_bmWatermark.bmBitsPixel == 32;
|
||
|
|
// create an alpha bitmap if the bitmap supplied isn't an alpha one
|
||
|
|
if(!bAlphaBitmap)
|
||
|
|
{
|
||
|
|
CXTPCompatibleDC memWatermarkDC(NULL, m_hbmpWatermark);
|
||
|
|
CXTPImageManagerIcon::DrawAlphaBitmap(&memWatermarkDC, m_hbmpWatermark, CPoint(0, 0), CSize(m_bmWatermark.bmWidth, m_bmWatermark.bmHeight));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::SetWatermarkBitmap(LPCTSTR szPath, BYTE Transparency)
|
||
|
|
{
|
||
|
|
m_WatermarkTransparency = Transparency;
|
||
|
|
|
||
|
|
// if path is empty, remove watermark bitmap
|
||
|
|
if(_tcslen(szPath) == 0)
|
||
|
|
{
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// remove old watermark bitmap if one is
|
||
|
|
if(m_hbmpWatermark)
|
||
|
|
{
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
}
|
||
|
|
// add new watermark bitmap
|
||
|
|
BOOL bAlphaBitmap = FALSE;
|
||
|
|
m_hbmpWatermark = CXTPImageManagerIcon::LoadBitmapFromFile(szPath, &bAlphaBitmap);
|
||
|
|
if(!m_hbmpWatermark)
|
||
|
|
return FALSE;
|
||
|
|
if(!CBitmap::FromHandle(m_hbmpWatermark)->GetBitmap(&m_bmWatermark))
|
||
|
|
{
|
||
|
|
::DeleteObject(m_hbmpWatermark);
|
||
|
|
m_hbmpWatermark = NULL;
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
// create an alpha bitmap if the bitmap supplied isn't an alpha one
|
||
|
|
if(!bAlphaBitmap)
|
||
|
|
{
|
||
|
|
CXTPCompatibleDC memWatermarkDC(NULL, m_hbmpWatermark);
|
||
|
|
CXTPImageManagerIcon::DrawAlphaBitmap(&memWatermarkDC, m_hbmpWatermark, CPoint(0, 0), CSize(m_bmWatermark.bmWidth, m_bmWatermark.bmHeight));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
// CXTPReportControl message handlers
|
||
|
|
|
||
|
|
void CXTPReportControl::OnPaint()
|
||
|
|
{
|
||
|
|
CPaintDC dc(this); // device context for painting
|
||
|
|
CXTPClientRect rc(this);
|
||
|
|
|
||
|
|
// ensure visible row and column if first started
|
||
|
|
if(m_nEnsureVisibleRowIdx >= 0)
|
||
|
|
{
|
||
|
|
EnsureVisible(GetRows()->GetAt(m_nEnsureVisibleRowIdx));
|
||
|
|
m_nEnsureVisibleRowIdx = -1;
|
||
|
|
}
|
||
|
|
if(m_nEnsureVisibleColumnIdx >= 0)
|
||
|
|
{
|
||
|
|
EnsureVisible(GetColumns()->GetAt(m_nEnsureVisibleColumnIdx));
|
||
|
|
m_nEnsureVisibleColumnIdx = -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// start counting drawing time
|
||
|
|
#ifdef XTP_DEBUG
|
||
|
|
LARGE_INTEGER iStartCount;
|
||
|
|
QueryPerformanceCounter(&iStartCount);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (m_nLockUpdateCount == 0 && (IsChanged() || m_bmpCache.GetSafeHandle() == 0))
|
||
|
|
{
|
||
|
|
CDC memDC;
|
||
|
|
memDC.CreateCompatibleDC(&dc);
|
||
|
|
|
||
|
|
m_bmpCache.DeleteObject();
|
||
|
|
m_bmpCache.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
|
||
|
|
|
||
|
|
|
||
|
|
CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
|
||
|
|
|
||
|
|
OnDraw(&memDC);
|
||
|
|
|
||
|
|
// update flag
|
||
|
|
SetChanged(FALSE);
|
||
|
|
|
||
|
|
if (!IsWindowEnabled())
|
||
|
|
{
|
||
|
|
XTPImageManager()->DisableBitmap(memDC, rc, RGB(250, 250, 250), RGB(128, 128, 128));
|
||
|
|
}
|
||
|
|
|
||
|
|
if(m_hbmpWatermark)
|
||
|
|
{
|
||
|
|
CRect rcDst(GetReportRectangle());
|
||
|
|
if(IsHeaderRowsVisible())
|
||
|
|
rcDst.top = m_rcHeaderArea.top;
|
||
|
|
if(IsFooterRowsVisible())
|
||
|
|
rcDst.bottom = m_rcFooterArea.bottom;
|
||
|
|
CRect rcAll(rcDst);
|
||
|
|
CRect rcSrc(0, 0, m_bmWatermark.bmWidth, m_bmWatermark.bmHeight);
|
||
|
|
// no stretch
|
||
|
|
if(!(GetWatermarkAlignment() & xtpReportWatermarkStretch))
|
||
|
|
{
|
||
|
|
if(rcSrc.Width() > rcDst.Width())
|
||
|
|
rcSrc.right = rcSrc.left + rcDst.Width();
|
||
|
|
else
|
||
|
|
rcDst.right = rcDst.left + rcSrc.Width();
|
||
|
|
if(rcSrc.Height() > rcDst.Height())
|
||
|
|
rcSrc.bottom = rcSrc.top + rcDst.Height();
|
||
|
|
else
|
||
|
|
rcDst.bottom = rcDst.top + rcSrc.Height();
|
||
|
|
}
|
||
|
|
// enlarge only
|
||
|
|
if((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkEnlargeOnly))
|
||
|
|
{
|
||
|
|
if(rcSrc.Width() > rcDst.Width())
|
||
|
|
rcSrc.right = rcSrc.left + rcDst.Width();
|
||
|
|
if(rcSrc.Height() > rcDst.Height())
|
||
|
|
rcSrc.bottom = rcSrc.top + rcDst.Height();
|
||
|
|
}
|
||
|
|
// shrink only
|
||
|
|
if((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkShrinkOnly))
|
||
|
|
{
|
||
|
|
if(rcSrc.Width() < rcDst.Width())
|
||
|
|
rcDst.right = rcDst.left + rcSrc.Width();
|
||
|
|
if(rcSrc.Height() < rcDst.Height())
|
||
|
|
rcDst.bottom = rcDst.top + rcSrc.Height();
|
||
|
|
}
|
||
|
|
// preserve aspect ratio
|
||
|
|
if((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkPreserveRatio))
|
||
|
|
{
|
||
|
|
if(rcDst.Width() > (rcDst.Height() * rcSrc.Width() / rcSrc.Height()))
|
||
|
|
rcDst.right = rcDst.left + rcDst.Height() * rcSrc.Width() / rcSrc.Height();
|
||
|
|
if(rcDst.Height() > (rcDst.Width() * rcSrc.Height() / rcSrc.Width()))
|
||
|
|
rcDst.bottom = rcDst.top + rcDst.Width() * rcSrc.Height() / rcSrc.Width();
|
||
|
|
}
|
||
|
|
// alignment
|
||
|
|
// if(!(GetWatermarkAlignment() & xtpReportWatermarkStretch))
|
||
|
|
{
|
||
|
|
// horizontal
|
||
|
|
switch(GetWatermarkAlignment() & xtpReportWatermarkHmask)
|
||
|
|
{
|
||
|
|
// center
|
||
|
|
case xtpReportWatermarkCenter :
|
||
|
|
rcDst.OffsetRect((rcAll.Width() - rcDst.Width()) / 2, 0);
|
||
|
|
break;
|
||
|
|
// right
|
||
|
|
case xtpReportWatermarkRight :
|
||
|
|
rcDst.OffsetRect(rcAll.Width() - rcDst.Width(), 0);
|
||
|
|
break;
|
||
|
|
// left
|
||
|
|
default :
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
// vertical
|
||
|
|
switch(GetWatermarkAlignment() & xtpReportWatermarkVmask)
|
||
|
|
{
|
||
|
|
// center
|
||
|
|
case xtpReportWatermarkVCenter :
|
||
|
|
rcDst.OffsetRect(0, (rcAll.Height() - rcDst.Height()) / 2);
|
||
|
|
break;
|
||
|
|
// bottom
|
||
|
|
case xtpReportWatermarkBottom:
|
||
|
|
rcDst.OffsetRect(0, rcAll.Height() - rcDst.Height());
|
||
|
|
break;
|
||
|
|
// top
|
||
|
|
default :
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPCompatibleDC memWatermarkDC(&dc, m_hbmpWatermark);
|
||
|
|
|
||
|
|
COLORREF clrBk = GetPaintManager()->m_clrControlBack;
|
||
|
|
CRect rcReport00(0, 0, rc.Width(), rc.Height());
|
||
|
|
|
||
|
|
CBitmap bmpTmp;
|
||
|
|
bmpTmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
|
||
|
|
|
||
|
|
CXTPCompatibleDC memDCtmp(&dc, &bmpTmp);
|
||
|
|
|
||
|
|
memDCtmp.FillSolidRect(&rcReport00, clrBk);
|
||
|
|
|
||
|
|
if(GetWatermarkAlignment() & xtpReportWatermarkStretch)
|
||
|
|
{
|
||
|
|
CBitmap bmpWatermarkTmp;
|
||
|
|
bmpWatermarkTmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
|
||
|
|
CXTPCompatibleDC memWatermarkDCtmp(&dc, &bmpWatermarkTmp);
|
||
|
|
memWatermarkDCtmp.FillSolidRect(&rc, RGB(255, 255, 255));
|
||
|
|
memWatermarkDCtmp.SetStretchBltMode(HALFTONE);
|
||
|
|
memWatermarkDCtmp.StretchBlt(rcDst.left, rcDst.top, rcDst.Width(), rcDst.Height(), &memWatermarkDC, 0, 0, rcSrc.Width(), rcSrc.Height(), SRCCOPY);
|
||
|
|
|
||
|
|
XTPImageManager()->AlphaBlend2(memDCtmp, rc, memWatermarkDCtmp, rc, m_WatermarkTransparency);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
XTPImageManager()->AlphaBlend2(memDCtmp, rcDst, memWatermarkDC, rcSrc, m_WatermarkTransparency);
|
||
|
|
}
|
||
|
|
|
||
|
|
XTPImageManager()->TransparentBlt(memDCtmp, rcReport00, memDC, rcReport00, clrBk);
|
||
|
|
|
||
|
|
memDC.BitBlt(0, 0, rc.right, rc.bottom, &memDCtmp, 0, 0, SRCCOPY);
|
||
|
|
}
|
||
|
|
|
||
|
|
dc.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
|
||
|
|
|
||
|
|
memDC.SelectObject(pOldBitmap);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CXTPCompatibleDC memDC(&dc, &m_bmpCache);
|
||
|
|
dc.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
|
||
|
|
}
|
||
|
|
|
||
|
|
// count drawing time
|
||
|
|
#ifdef XTP_DEBUG
|
||
|
|
LARGE_INTEGER iEndCount;
|
||
|
|
QueryPerformanceCounter(&iEndCount);
|
||
|
|
XTP_TRACE(_T("Draw counter ticks: %d\n"), iEndCount.LowPart-iStartCount.LowPart);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
LRESULT CXTPReportControl::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
|
||
|
|
{
|
||
|
|
CDC* pDC = CDC::FromHandle((HDC)wParam);
|
||
|
|
if (pDC)
|
||
|
|
{
|
||
|
|
if (m_bmpCache.GetSafeHandle() == 0)
|
||
|
|
OnDraw(pDC);
|
||
|
|
else
|
||
|
|
{
|
||
|
|
CXTPCompatibleDC memDC(pDC, &m_bmpCache);
|
||
|
|
CXTPClientRect rc(this);
|
||
|
|
pDC->BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnEraseBkgnd(CDC* /*pDC*/)
|
||
|
|
{
|
||
|
|
return TRUE; // Don't erase the background.
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnDraw(CDC* pDC)
|
||
|
|
{
|
||
|
|
if (GetExStyle() & WS_EX_RTLREADING)
|
||
|
|
{
|
||
|
|
pDC->SetTextAlign(TA_RTLREADING);
|
||
|
|
}
|
||
|
|
|
||
|
|
// draw new image
|
||
|
|
pDC->FillSolidRect(CXTPClientRect(this), GetPaintManager()->GetControlBackColor(this));
|
||
|
|
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
|
||
|
|
CRect rcHeader = m_rcHeaderArea;
|
||
|
|
rcHeader.right = rcHeader.left + pHeader->GetWidth();
|
||
|
|
|
||
|
|
// draw header
|
||
|
|
if (pHeader)
|
||
|
|
pHeader->Draw(pDC, rcHeader, m_nLeftOffset);
|
||
|
|
|
||
|
|
// draw group by box
|
||
|
|
if (pHeader)
|
||
|
|
pHeader->DrawGroupByControl(pDC, m_rcGroupByArea);
|
||
|
|
|
||
|
|
DrawRows(pDC, m_rcReportArea);
|
||
|
|
|
||
|
|
if (m_bHeaderRecordsVisible && m_pHeaderRows->GetCount() > 0)
|
||
|
|
{
|
||
|
|
DrawFixedRows(pDC, m_rcHeaderRecordsArea, m_pHeaderRows);
|
||
|
|
DrawFixedRecordsDivider(pDC, m_rcHeaderRecordsDividerArea, TRUE);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bFooterRecordsVisible && m_pFooterRows->GetCount() > 0)
|
||
|
|
{
|
||
|
|
DrawFixedRows(pDC, m_rcFooterRecordsArea, m_pFooterRows);
|
||
|
|
DrawFixedRecordsDivider(pDC, m_rcFooterRecordsDividerArea, FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
CRect rcFooter = m_rcFooterArea;
|
||
|
|
if (rcFooter.Height() > 0)
|
||
|
|
pHeader->DrawFooter(pDC, rcFooter, m_nLeftOffset);
|
||
|
|
|
||
|
|
if (m_nDropPos != -1)
|
||
|
|
{
|
||
|
|
DrawDropMarker(pDC);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// update flag
|
||
|
|
SetChanged(FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DrawDropMarker(CDC* pDC)
|
||
|
|
{
|
||
|
|
CRect rc(m_rcReportArea.left, m_nDropPos, m_rcReportArea.right, m_nDropPos + 1);
|
||
|
|
|
||
|
|
pDC->FillSolidRect(rc, GetPaintManager()->m_clrHotDivider);
|
||
|
|
|
||
|
|
CXTPPenDC pen (*pDC, GetPaintManager()->m_clrHotDivider);
|
||
|
|
CXTPBrushDC brush (*pDC, GetPaintManager()->m_clrHotDivider);
|
||
|
|
|
||
|
|
int x = rc.left;
|
||
|
|
int y = m_nDropPos;
|
||
|
|
|
||
|
|
POINT ptsLeftArrow[] =
|
||
|
|
{
|
||
|
|
{x, y - 2}, {x + 2, y - 2}, {x + 2, y - 5}, {x + 7, y},
|
||
|
|
{x + 2, y + 5}, {x + 2, y + 2}, {x, y + 2}
|
||
|
|
};
|
||
|
|
pDC->Polygon(ptsLeftArrow, 7);
|
||
|
|
|
||
|
|
x = rc.right - 1;
|
||
|
|
|
||
|
|
POINT ptsRightArrow[] =
|
||
|
|
{
|
||
|
|
{x, y - 2}, {x - 2, y - 2}, {x - 2, y - 5}, {x - 7, y},
|
||
|
|
{x - 2, y + 5}, {x - 2, y + 2}, {x, y + 2}
|
||
|
|
};
|
||
|
|
pDC->Polygon(ptsRightArrow, 7);
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnSize(UINT nType, int cx, int cy)
|
||
|
|
{
|
||
|
|
if (m_bOnSizeRunning)
|
||
|
|
return;
|
||
|
|
|
||
|
|
m_bOnSizeRunning = TRUE;
|
||
|
|
|
||
|
|
CWnd::OnSize(nType, cx, cy);
|
||
|
|
|
||
|
|
AdjustLayout();
|
||
|
|
AdjustScrollBars();
|
||
|
|
|
||
|
|
m_bOnSizeRunning = FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnRButtonDown(UINT nFlags, CPoint point)
|
||
|
|
{
|
||
|
|
CWnd::OnRButtonDown(nFlags, point);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnRButtonUp(UINT nFlags, CPoint point)
|
||
|
|
{
|
||
|
|
HWND hWnd = m_hWnd;
|
||
|
|
CWnd::OnRButtonUp(nFlags, point);
|
||
|
|
|
||
|
|
if (!IsWindow(hWnd)) // Can be destroyed in WM_CONTEXTMENU
|
||
|
|
return;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
LRESULT CXTPReportControl::OnNcHitTest(CPoint point)
|
||
|
|
{
|
||
|
|
LRESULT ht = CWnd::OnNcHitTest(point);
|
||
|
|
|
||
|
|
if (ht != HTCLIENT)
|
||
|
|
return ht;
|
||
|
|
|
||
|
|
DWORD dwStyle = GetStyle();
|
||
|
|
|
||
|
|
if ((dwStyle & (WS_VSCROLL | WS_HSCROLL)) == 0)
|
||
|
|
return ht;
|
||
|
|
|
||
|
|
CXTPWindowRect rcWindow(this);
|
||
|
|
|
||
|
|
if (dwStyle & WS_VSCROLL)
|
||
|
|
{
|
||
|
|
CRect rc(rcWindow.right- GetSystemMetrics(SM_CXVSCROLL), rcWindow.top,
|
||
|
|
rcWindow.right, rcWindow.bottom - (dwStyle & WS_HSCROLL ? GetSystemMetrics(SM_CYHSCROLL) : 0));
|
||
|
|
|
||
|
|
if (rc.PtInRect(point))
|
||
|
|
return HTVSCROLL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (dwStyle & WS_HSCROLL)
|
||
|
|
{
|
||
|
|
CRect rc(rcWindow.left, rcWindow.bottom - GetSystemMetrics(SM_CYHSCROLL),
|
||
|
|
rcWindow.right - (dwStyle & WS_VSCROLL ? GetSystemMetrics(SM_CXVSCROLL) : 0), rcWindow.bottom);
|
||
|
|
|
||
|
|
if (rc.PtInRect(point))
|
||
|
|
return HTHSCROLL;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ht;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnLButtonDown(UINT nFlags, CPoint point)
|
||
|
|
{
|
||
|
|
CWnd::OnLButtonDown(nFlags, point);
|
||
|
|
SetFocus();
|
||
|
|
EditItem(NULL);
|
||
|
|
|
||
|
|
// columns processing
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
if (pHeader)
|
||
|
|
{
|
||
|
|
pHeader->OnLButtonDown(point);
|
||
|
|
}
|
||
|
|
|
||
|
|
// rows selection
|
||
|
|
CXTPReportRow* pRow = HitTest(point);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
XTP_REPORTRECORDITEM_CLICKARGS clickArgs;
|
||
|
|
clickArgs.pControl = this;
|
||
|
|
clickArgs.pRow = pRow;
|
||
|
|
clickArgs.ptClient = point;
|
||
|
|
clickArgs.pColumn = NULL;
|
||
|
|
|
||
|
|
// find clicked item
|
||
|
|
clickArgs.pItem = pRow->HitTest(point, &clickArgs.rcItem, &clickArgs.pColumn);
|
||
|
|
|
||
|
|
if (pRow->OnLButtonDown(&clickArgs))
|
||
|
|
return;
|
||
|
|
|
||
|
|
// some rows may be unaccessible for end user
|
||
|
|
if (pRow->GetType() == xtpRowTypeHeader && !m_bHeaderRowsAllowAccess)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (pRow->GetType() == xtpRowTypeFooter && !m_bFooterRowsAllowAccess)
|
||
|
|
return;
|
||
|
|
|
||
|
|
bool bIgnoreSelection = GetKeyState(VK_CONTROL) < 0 || IsMultiSelectionMode();
|
||
|
|
bool bSelectBlock = GetKeyState(VK_SHIFT) < 0;
|
||
|
|
BOOL bFocusChanged = TRUE;
|
||
|
|
|
||
|
|
|
||
|
|
CXTPReportColumn* pFocusedColumn = clickArgs.pColumn;
|
||
|
|
|
||
|
|
|
||
|
|
CUpdateContext updateContext(this);
|
||
|
|
|
||
|
|
if (m_bFocusSubItems && pFocusedColumn && pRow->GetRecord() && pRow->GetRecord()->GetItem(pFocusedColumn)->IsFocusable())
|
||
|
|
{
|
||
|
|
SetFocusedColumn(pFocusedColumn);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pRow->IsSelected() && !bIgnoreSelection && !bSelectBlock)
|
||
|
|
{
|
||
|
|
m_pSelectOnUpRow = pRow;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
bFocusChanged = SetFocusedRow(pRow, bSelectBlock, bIgnoreSelection);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL bSelectionChanged = m_pSelectedRows->IsChanged();
|
||
|
|
if (bFocusChanged && bIgnoreSelection && IsSelectionEnabled())
|
||
|
|
{
|
||
|
|
m_pSelectedRows->Invert(pRow);
|
||
|
|
if(!bSelectionChanged && m_pSelectedRows->IsChanged())
|
||
|
|
OnSelectionChanged();
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pointDrag = point;
|
||
|
|
m_bPrepareDrag = TRUE;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnLButtonUp(UINT nFlags, CPoint point)
|
||
|
|
{
|
||
|
|
CWnd::OnLButtonUp(nFlags, point);
|
||
|
|
|
||
|
|
m_bPrepareDrag = FALSE;
|
||
|
|
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
|
||
|
|
// columns processing
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
if (pHeader)
|
||
|
|
{
|
||
|
|
pHeader->OnLButtonUp(nFlags, point);
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRow* pRow = HitTest(point);
|
||
|
|
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
if (pRow == m_pSelectOnUpRow)
|
||
|
|
{
|
||
|
|
SetFocusedRow(pRow, FALSE, FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
XTP_REPORTRECORDITEM_CLICKARGS clickArgs;
|
||
|
|
clickArgs.pControl = this;
|
||
|
|
clickArgs.pRow = pRow;
|
||
|
|
clickArgs.ptClient = point;
|
||
|
|
clickArgs.pColumn = NULL;
|
||
|
|
|
||
|
|
// find clicked item
|
||
|
|
clickArgs.pItem = pRow->HitTest(point, &clickArgs.rcItem, &clickArgs.pColumn);
|
||
|
|
|
||
|
|
pRow->OnLButtonUp(&clickArgs);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_pSelectOnUpRow = NULL;
|
||
|
|
|
||
|
|
if (!m_bMultipleSelection || (GetKeyState(VK_SHIFT) >= 0 && (GetKeyState(VK_CONTROL) >= 0 && !IsMultiSelectionMode())))
|
||
|
|
{
|
||
|
|
// rows processing
|
||
|
|
if (pRow && pRow->IsFocused())
|
||
|
|
{
|
||
|
|
pRow->OnClick(point);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnLButtonDblClk(UINT nFlags, CPoint ptDblClick)
|
||
|
|
{
|
||
|
|
CWnd::OnLButtonDblClk(nFlags, ptDblClick);
|
||
|
|
|
||
|
|
// columns processing
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
if (pHeader)
|
||
|
|
{
|
||
|
|
pHeader->OnLButtonDblClk(ptDblClick);
|
||
|
|
}
|
||
|
|
|
||
|
|
// rows processing
|
||
|
|
CXTPReportRow* pRow = HitTest(ptDblClick);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
pRow->OnDblClick(ptDblClick);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// just notify parent
|
||
|
|
SendMessageToParent(NULL, NULL, NULL, NM_DBLCLK, &ptDblClick);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
void CXTPReportControl::OnContextMenu(CWnd* /*pWnd*/, CPoint pos)
|
||
|
|
{
|
||
|
|
if (GetMouseMode() != xtpReportMouseNothing)
|
||
|
|
return;
|
||
|
|
|
||
|
|
CPoint ptClient = pos;
|
||
|
|
ScreenToClient(&ptClient);
|
||
|
|
|
||
|
|
// call context menu handler for report header if clicked inside
|
||
|
|
if (m_rcHeaderArea.PtInRect(ptClient) ||
|
||
|
|
m_rcGroupByArea.PtInRect(ptClient))
|
||
|
|
{
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
if (pHeader)
|
||
|
|
pHeader->OnContextMenu(ptClient);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// call context menu handler for report area if clicked inside
|
||
|
|
if (m_rcReportArea.PtInRect(ptClient) ||
|
||
|
|
m_rcHeaderRecordsArea.PtInRect(ptClient) ||
|
||
|
|
m_rcFooterRecordsArea.PtInRect(ptClient))
|
||
|
|
{
|
||
|
|
// rows processing
|
||
|
|
CXTPReportRow* pRow = HitTest(ptClient);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
SetFocusedRow(pRow, pRow->IsSelected());
|
||
|
|
pRow->OnContextMenu(ptClient);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SendMessageToParent(NULL, NULL, NULL, NM_RCLICK, &pos);
|
||
|
|
}
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pos == CPoint(-1, -1))
|
||
|
|
{
|
||
|
|
CXTPReportRow* pFocusedRow = GetFocusedRow();
|
||
|
|
if (pFocusedRow)
|
||
|
|
{
|
||
|
|
ptClient = CPoint(pFocusedRow->GetRect().left, pFocusedRow->GetRect().bottom);
|
||
|
|
pFocusedRow->OnContextMenu(ptClient);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
pos = m_rcReportArea.TopLeft();
|
||
|
|
ClientToScreen(&pos);
|
||
|
|
SendMessageToParent(NULL, NULL, NULL, NM_RCLICK, &pos);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportColumn* CXTPReportControl::GetNextFocusableColumn(CXTPReportRow* pRow, int nColumnIndex, int nDirection)
|
||
|
|
{
|
||
|
|
if (!pRow->GetRecord())
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
for (;;)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = GetReportHeader()->GetNextVisibleColumn(nColumnIndex, nDirection);
|
||
|
|
if (!pColumn)
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
CXTPReportRecordItem* pItem = pRow->GetRecord()->GetItem(pColumn);
|
||
|
|
|
||
|
|
if (pItem && pItem->IsFocusable())
|
||
|
|
return pColumn;
|
||
|
|
|
||
|
|
nColumnIndex = pColumn->GetIndex();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnPreviewKeyDown(UINT& rnChar, UINT nRepCnt, UINT nFlags)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORTPREVIEWKEYDOWN nmParams;
|
||
|
|
::ZeroMemory(&nmParams, sizeof(nmParams));
|
||
|
|
|
||
|
|
nmParams.nChar = rnChar;
|
||
|
|
nmParams.nRepCnt = nRepCnt;
|
||
|
|
nmParams.nFlags = nFlags;
|
||
|
|
nmParams.bCancel = FALSE;
|
||
|
|
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_PREVIEWKEYDOWN, (NMHDR*)&nmParams);
|
||
|
|
rnChar = nmParams.nChar;
|
||
|
|
|
||
|
|
return !nmParams.bCancel;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
|
{
|
||
|
|
// TRACE(_T("ReportControl, OnKeyDown('%d') \n"), nChar);
|
||
|
|
|
||
|
|
// Moved to PreTranslateMessage
|
||
|
|
// if (!OnPreviewKeyDown(nChar, nRepCnt, nFlags))
|
||
|
|
// {
|
||
|
|
// return;
|
||
|
|
// }
|
||
|
|
|
||
|
|
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
|
||
|
|
|
||
|
|
BOOL bSelectBlock = GetKeyState(VK_SHIFT) < 0;
|
||
|
|
BOOL bSignoreSelection = GetKeyState(VK_CONTROL) < 0 || IsMultiSelectionMode();
|
||
|
|
|
||
|
|
CXTPReportRow* pFocusedRow = GetFocusedRow();
|
||
|
|
|
||
|
|
CXTPDrawHelpers::KeyToLayout(this, nChar);
|
||
|
|
|
||
|
|
if (m_pRows->GetCount() != 0)
|
||
|
|
switch (nChar)
|
||
|
|
{
|
||
|
|
case VK_ADD:
|
||
|
|
if (bSignoreSelection)
|
||
|
|
ExpandAll();
|
||
|
|
else if (pFocusedRow && pFocusedRow->HasChildren() && !pFocusedRow->IsExpanded())
|
||
|
|
{
|
||
|
|
pFocusedRow->SetExpanded(TRUE);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_SUBTRACT:
|
||
|
|
if (bSignoreSelection)
|
||
|
|
CollapseAll();
|
||
|
|
else if (pFocusedRow && pFocusedRow->HasChildren() && pFocusedRow->IsExpanded())
|
||
|
|
{
|
||
|
|
pFocusedRow->SetExpanded(FALSE);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_RIGHT:
|
||
|
|
if (pFocusedRow && pFocusedRow->HasChildren() && !pFocusedRow->IsExpanded())
|
||
|
|
{
|
||
|
|
pFocusedRow->SetExpanded(TRUE);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (pFocusedRow && m_bFocusSubItems && m_pFocusedColumn)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = GetNextFocusableColumn(pFocusedRow, m_pFocusedColumn->GetIndex(), +1);
|
||
|
|
if (pColumn)
|
||
|
|
{
|
||
|
|
SetFocusedColumn(pColumn);
|
||
|
|
SetFocusedRow(GetFocusedRow());
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case VK_DOWN:
|
||
|
|
GetNavigator()->MoveDown(bSelectBlock, bSignoreSelection);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_LEFT:
|
||
|
|
if (pFocusedRow && pFocusedRow->HasChildren() && pFocusedRow->IsExpanded())
|
||
|
|
{
|
||
|
|
pFocusedRow->SetExpanded(FALSE);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (pFocusedRow && m_bFocusSubItems && m_pFocusedColumn)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = GetNextFocusableColumn(pFocusedRow, m_pFocusedColumn->GetIndex(), -1);
|
||
|
|
if (pColumn)
|
||
|
|
{
|
||
|
|
SetFocusedColumn(pColumn);
|
||
|
|
SetFocusedRow(GetFocusedRow());
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (pFocusedRow && !pFocusedRow->HasChildren() && pFocusedRow->GetParentRow() && !bSelectBlock)
|
||
|
|
{
|
||
|
|
SetFocusedRow(pFocusedRow->GetParentRow());
|
||
|
|
pFocusedRow->SetExpanded(FALSE);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case VK_UP:
|
||
|
|
GetNavigator()->MoveUp(bSelectBlock, bSignoreSelection);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_HOME:
|
||
|
|
GetNavigator()->MoveFirstRow(bSelectBlock, FALSE);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_END:
|
||
|
|
GetNavigator()->MoveLastRow(bSelectBlock, FALSE);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_NEXT:
|
||
|
|
GetNavigator()->MovePageDown(bSelectBlock, FALSE);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_PRIOR:
|
||
|
|
GetNavigator()->MovePageUp(bSelectBlock, FALSE);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_RETURN:
|
||
|
|
if (pFocusedRow && pFocusedRow->HasChildren())
|
||
|
|
{
|
||
|
|
pFocusedRow->SetExpanded(!pFocusedRow->IsExpanded());
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_ESCAPE:
|
||
|
|
if (m_mouseMode != xtpReportMouseNothing)
|
||
|
|
{
|
||
|
|
GetReportHeader()->CancelMouseMode();
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VK_F2:
|
||
|
|
GetNavigator()->BeginEdit();
|
||
|
|
break;
|
||
|
|
case VK_SPACE:
|
||
|
|
if(IsSelectionEnabled() && bSignoreSelection && pFocusedRow)
|
||
|
|
{
|
||
|
|
// m_pSelectedRows->Invert(pFocusedRow);
|
||
|
|
if(pFocusedRow->IsSelected())
|
||
|
|
m_pSelectedRows->Remove(pFocusedRow);
|
||
|
|
else
|
||
|
|
m_pSelectedRows->Add(pFocusedRow);
|
||
|
|
OnSelectionChanged();
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
NMKEY nmgv;
|
||
|
|
nmgv.nVKey = nChar;
|
||
|
|
nmgv.uFlags = nFlags;
|
||
|
|
SendNotifyMessage(NM_KEYDOWN, (NMHDR*)&nmgv);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
|
{
|
||
|
|
CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
|
{
|
||
|
|
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
|
{
|
||
|
|
CWnd::OnSysKeyUp(nChar, nRepCnt, nFlags);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnChar(UINT nChar, UINT nRepCntr, UINT nFlags)
|
||
|
|
{
|
||
|
|
// TRACE(_T("ReportControl, OnChar('%d') \n"), nChar);
|
||
|
|
|
||
|
|
// Moved to PreTranslateMessage
|
||
|
|
// if (!OnPreviewKeyDown(nChar, nRepCntr, nFlags))
|
||
|
|
// {
|
||
|
|
// return;
|
||
|
|
// }
|
||
|
|
|
||
|
|
NMCHAR nmgv;
|
||
|
|
ZeroMemory(&nmgv, sizeof(NMCHAR));
|
||
|
|
nmgv.ch = nChar;
|
||
|
|
SendNotifyMessage(NM_CHAR, (NMHDR*)&nmgv);
|
||
|
|
|
||
|
|
|
||
|
|
CXTPReportRow* pFocusedRow = GetFocusedRow();
|
||
|
|
|
||
|
|
if (m_bFocusSubItems && pFocusedRow && (nChar == VK_TAB))
|
||
|
|
{
|
||
|
|
EditItem(NULL);
|
||
|
|
|
||
|
|
BOOL bBack = GetKeyState(VK_SHIFT) < 0;
|
||
|
|
|
||
|
|
GetNavigator()->MoveLeftRight(bBack);
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pFocusedColumn && pFocusedRow && pFocusedRow->GetRecord() && (nChar != VK_RETURN) && (nChar != VK_ESCAPE))
|
||
|
|
{
|
||
|
|
XTP_REPORTRECORDITEM_ARGS itemArgs(this, pFocusedRow, m_pFocusedColumn) ;
|
||
|
|
|
||
|
|
if (itemArgs.pItem && itemArgs.pItem->OnChar(&itemArgs, nChar))
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
CWnd::OnChar(nChar, nRepCntr, nFlags);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnCaptureChanged(CWnd* pWnd)
|
||
|
|
{
|
||
|
|
if (m_mouseMode != xtpReportMouseNothing)
|
||
|
|
{
|
||
|
|
GetReportHeader()->CancelMouseMode();
|
||
|
|
}
|
||
|
|
CWnd::OnCaptureChanged(pWnd);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnEnable(BOOL bEnable)
|
||
|
|
{
|
||
|
|
UNREFERENCED_PARAMETER(bEnable);
|
||
|
|
|
||
|
|
AdjustScrollBars();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
||
|
|
{
|
||
|
|
if (pScrollBar != NULL)
|
||
|
|
{
|
||
|
|
CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
int nCurPos = m_nTopRow;
|
||
|
|
|
||
|
|
// decide what to do for each diffrent scroll event
|
||
|
|
switch (nSBCode)
|
||
|
|
{
|
||
|
|
case SB_TOP: nCurPos = 0; break;
|
||
|
|
case SB_BOTTOM: nCurPos = GetScrollLimit(SB_VERT); break;
|
||
|
|
case SB_LINEUP: nCurPos = max(nCurPos - 1, 0); break;
|
||
|
|
case SB_LINEDOWN: nCurPos = min(nCurPos + 1, GetScrollLimit(SB_VERT)); break;
|
||
|
|
|
||
|
|
case SB_PAGEUP: nCurPos = max(nCurPos - GetReportAreaRows(nCurPos, false), 0); break;
|
||
|
|
case SB_PAGEDOWN: nCurPos = min(nCurPos + GetReportAreaRows(nCurPos, true), GetScrollLimit(SB_VERT)); break;
|
||
|
|
|
||
|
|
case SB_THUMBTRACK:
|
||
|
|
case SB_THUMBPOSITION:
|
||
|
|
{
|
||
|
|
SCROLLINFO si;
|
||
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
||
|
|
si.cbSize = sizeof(SCROLLINFO);
|
||
|
|
si.fMask = SIF_TRACKPOS;
|
||
|
|
|
||
|
|
if (!GetScrollInfo(SB_VERT, &si))
|
||
|
|
return;
|
||
|
|
nCurPos = si.nTrackPos;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
SetTopRow(nCurPos);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
||
|
|
{
|
||
|
|
if (pScrollBar != NULL)
|
||
|
|
{
|
||
|
|
CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
int nCurPos = m_nLeftOffset;
|
||
|
|
|
||
|
|
// FCS - full column scrolling
|
||
|
|
int nLeftOffset_new = m_nLeftOffset;
|
||
|
|
|
||
|
|
CXTPReportColumn *pPrev = NULL, *pCurr = NULL, *pNext = NULL;
|
||
|
|
int nScrollPos = 0, nScrollMax = 0;
|
||
|
|
int nFreezOffset = 0;
|
||
|
|
if (m_bFullColumnScrolling)
|
||
|
|
nFreezOffset = GetReportHeader()->GetFulColScrollInfo(pPrev, pCurr, pNext, nScrollPos, nScrollMax);
|
||
|
|
|
||
|
|
// decide what to do for each different scroll event
|
||
|
|
switch (nSBCode)
|
||
|
|
{
|
||
|
|
case SB_TOP:
|
||
|
|
nCurPos = 0;
|
||
|
|
nLeftOffset_new = 0;
|
||
|
|
nScrollPos = 0;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SB_BOTTOM:
|
||
|
|
nCurPos = GetScrollLimit(SB_HORZ);
|
||
|
|
if (m_bFullColumnScrolling)
|
||
|
|
{
|
||
|
|
int nVisColCount = GetColumns()->GetVisibleColumnsCount();
|
||
|
|
CXTPReportColumn *pLast = GetColumns()->GetVisibleAt(max(nVisColCount-1, 0));
|
||
|
|
ASSERT(pLast);
|
||
|
|
if (!pLast)
|
||
|
|
return;
|
||
|
|
|
||
|
|
nLeftOffset_new = labs(GetReportHeader()->m_rcHeader.left - pLast->GetRect().left) - nFreezOffset;
|
||
|
|
nScrollPos = max(nScrollMax - 1, 0);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SB_LINEUP:
|
||
|
|
nCurPos = max(nCurPos - m_nHScrollStep, 0);
|
||
|
|
if (m_bFullColumnScrolling && pPrev)
|
||
|
|
{
|
||
|
|
nLeftOffset_new = labs(GetReportHeader()->m_rcHeader.left - pPrev->GetRect().left) - nFreezOffset;
|
||
|
|
nScrollPos = max(nScrollPos - 1, 0);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SB_LINEDOWN:
|
||
|
|
nCurPos = min(nCurPos + m_nHScrollStep, GetScrollLimit(SB_HORZ));
|
||
|
|
if (m_bFullColumnScrolling && pNext)
|
||
|
|
{
|
||
|
|
nLeftOffset_new = labs(GetReportHeader()->m_rcHeader.left - pNext->GetRect().left) - nFreezOffset;
|
||
|
|
nScrollPos = nScrollPos + 1;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SB_PAGEUP:
|
||
|
|
nCurPos = max(nCurPos - m_rcReportArea.Width(), 0);
|
||
|
|
if (m_bFullColumnScrolling && pPrev)
|
||
|
|
{
|
||
|
|
nLeftOffset_new = labs(GetReportHeader()->m_rcHeader.left - pPrev->GetRect().left) - nFreezOffset;
|
||
|
|
nScrollPos = max(nScrollPos - 1, 0);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SB_PAGEDOWN:
|
||
|
|
nCurPos = min(nCurPos + m_rcReportArea.Width(), GetScrollLimit(SB_HORZ));
|
||
|
|
if (m_bFullColumnScrolling && pNext)
|
||
|
|
{
|
||
|
|
nLeftOffset_new = labs(GetReportHeader()->m_rcHeader.left - pNext->GetRect().left) - nFreezOffset;
|
||
|
|
nScrollPos = nScrollPos + 1;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SB_THUMBTRACK:
|
||
|
|
case SB_THUMBPOSITION:
|
||
|
|
nCurPos = nPos;
|
||
|
|
if (m_bFullColumnScrolling)
|
||
|
|
{
|
||
|
|
int nVisColCount = GetColumns()->GetVisibleColumnsCount();
|
||
|
|
|
||
|
|
int nCurrCol = nVisColCount - nScrollMax + nPos;
|
||
|
|
CXTPReportColumn *pCurrScroll = GetColumns()->GetVisibleAt(nCurrCol);
|
||
|
|
|
||
|
|
ASSERT(pCurrScroll);
|
||
|
|
if (!pCurrScroll)
|
||
|
|
return;
|
||
|
|
|
||
|
|
nLeftOffset_new = labs(GetReportHeader()->m_rcHeader.left - pCurrScroll->GetRect().left) - nFreezOffset;
|
||
|
|
nScrollPos = nPos;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bFullColumnScrolling)
|
||
|
|
{
|
||
|
|
SetLeftOffset(nLeftOffset_new);
|
||
|
|
SetScrollPos(SB_HORZ, nScrollPos);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SetLeftOffset(nCurPos);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UINT CXTPReportControl::GetMouseScrollLines()
|
||
|
|
{
|
||
|
|
int nScrollLines = 3; // default value
|
||
|
|
|
||
|
|
if (XTPSystemVersion()->IsWin95())
|
||
|
|
{
|
||
|
|
|
||
|
|
HKEY hKey;
|
||
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(
|
||
|
|
HKEY_CURRENT_USER, _T("Control Panel\\Desktop"), 0, KEY_QUERY_VALUE, &hKey))
|
||
|
|
{
|
||
|
|
TCHAR szData[128];
|
||
|
|
DWORD dwKeyDataType;
|
||
|
|
DWORD dwDataBufSize = sizeof(szData);
|
||
|
|
|
||
|
|
if (ERROR_SUCCESS == RegQueryValueEx(
|
||
|
|
hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType, (LPBYTE) &szData, &dwDataBufSize))
|
||
|
|
{
|
||
|
|
nScrollLines = _tcstoul(szData, NULL, 10);
|
||
|
|
}
|
||
|
|
RegCloseKey(hKey);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// win98 or greater
|
||
|
|
else
|
||
|
|
SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
|
||
|
|
|
||
|
|
return nScrollLines;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
|
||
|
|
{
|
||
|
|
if (!m_bVScrollBarVisible)
|
||
|
|
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
|
||
|
|
|
||
|
|
UINT uiMsg;
|
||
|
|
int nScrollsCount = 0;
|
||
|
|
// calculate what should be sent
|
||
|
|
if (m_nRowsPerWheel == -1)
|
||
|
|
{
|
||
|
|
// A m_nRowsPerWheel value less than 0 indicates that the mouse wheel scrolls whole pages, not just lines.
|
||
|
|
int nPagesScrolled = zDelta / 120;
|
||
|
|
uiMsg = nPagesScrolled > 0 ? SB_PAGEUP : SB_PAGEDOWN;
|
||
|
|
nScrollsCount = nPagesScrolled > 0 ? nPagesScrolled : -nPagesScrolled;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int nRowsScrolled = m_nRowsPerWheel * zDelta / 120;
|
||
|
|
uiMsg = nRowsScrolled > 0 ? SB_LINEUP : SB_LINEDOWN;
|
||
|
|
nScrollsCount = nRowsScrolled > 0 ? nRowsScrolled : -nRowsScrolled;
|
||
|
|
}
|
||
|
|
|
||
|
|
BeginUpdate();
|
||
|
|
|
||
|
|
// send scroll messages
|
||
|
|
for (int i = 0; i < nScrollsCount; i++)
|
||
|
|
{
|
||
|
|
OnVScroll(uiMsg, 0, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
UpdateWindow();
|
||
|
|
|
||
|
|
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnMouseLeave()
|
||
|
|
{
|
||
|
|
OnMouseMove(0, CPoint(-1, -1));
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnMouseMove(UINT nFlags, CPoint point)
|
||
|
|
{
|
||
|
|
CWnd::OnMouseMove(nFlags, point);
|
||
|
|
|
||
|
|
CXTPReportHeader* pHeader = GetReportHeader();
|
||
|
|
if (pHeader)
|
||
|
|
{
|
||
|
|
pHeader->OnMouseMove(nFlags, point);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GetMouseMode() == xtpReportMouseNothing)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = HitTest(point);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
pRow->OnMouseMove(nFlags, point);
|
||
|
|
|
||
|
|
if (m_bShowTooltips && nFlags == 0)
|
||
|
|
{
|
||
|
|
pRow->ShowToolTip(point, &m_wndTip);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pHotRow != pRow)
|
||
|
|
{
|
||
|
|
TRACKMOUSEEVENT tme =
|
||
|
|
{
|
||
|
|
sizeof(TRACKMOUSEEVENT), TME_LEAVE, GetSafeHwnd(), 0
|
||
|
|
};
|
||
|
|
_TrackMouseEvent (&tme);
|
||
|
|
|
||
|
|
m_pHotRow = pRow;
|
||
|
|
}
|
||
|
|
|
||
|
|
// If mouse moved some since down...
|
||
|
|
if (m_bPrepareDrag && (labs (point.x - m_pointDrag.x) > 3 ||
|
||
|
|
labs (point.y - m_pointDrag.y) > 3))
|
||
|
|
{
|
||
|
|
// Prevent duplicate
|
||
|
|
m_bPrepareDrag = FALSE;
|
||
|
|
|
||
|
|
m_pSelectOnUpRow = NULL;
|
||
|
|
|
||
|
|
// Begin a drag operation
|
||
|
|
OnBeginDrag(m_pointDrag);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnBeginDrag(CPoint point)
|
||
|
|
{
|
||
|
|
if (SendMessageToParent(NULL, NULL, NULL, LVN_BEGINDRAG, &point))
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (m_cfReport == NULL)
|
||
|
|
return;
|
||
|
|
|
||
|
|
CXTPReportSelectedRows* pSelectedRows = GetSelectedRows();
|
||
|
|
if (!pSelectedRows)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if ((m_dwDragDropFlags & xtpReportAllowDrag) == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
int nCount = pSelectedRows->GetCount();
|
||
|
|
for (int i = nCount - 1; i >= 0; i--)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pSelectedRows->GetAt(i);
|
||
|
|
if (pRow->IsGroupRow())
|
||
|
|
{
|
||
|
|
pRow->SetExpanded(TRUE);
|
||
|
|
pRow->SelectChilds();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
COleDataSource ds;
|
||
|
|
|
||
|
|
int nRowsCount = pSelectedRows->GetCount();
|
||
|
|
if (nRowsCount < 1)
|
||
|
|
return;
|
||
|
|
|
||
|
|
// minimize memory reallocs to improve performance
|
||
|
|
UINT nAveRecordsSize = 1500; // bytes
|
||
|
|
UINT nGrowBytes = ((nRowsCount * nAveRecordsSize) / 4096 + 1) * 4096;
|
||
|
|
|
||
|
|
UINT nAllocFlags = GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT;
|
||
|
|
|
||
|
|
CSharedFile fileRecords(nAllocFlags, nGrowBytes);
|
||
|
|
|
||
|
|
BOOL bSucceed = FALSE;
|
||
|
|
|
||
|
|
//------------------------------------------------------------------------
|
||
|
|
const int cErrTextSize = 1024;
|
||
|
|
TCHAR szErrText[cErrTextSize + 1];
|
||
|
|
|
||
|
|
CXTPReportRecords* pDragRecords = new CXTPReportRecords(TRUE);
|
||
|
|
|
||
|
|
if (!_GetSelectedRows(pDragRecords))
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pDragRecords);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
CArchive ar(&fileRecords, CArchive::store);
|
||
|
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
|
||
|
|
bSucceed = _WriteRecordsData(&px, pDragRecords);
|
||
|
|
|
||
|
|
ar.Close(); // perform Flush() and detach from file
|
||
|
|
}
|
||
|
|
catch(CArchiveException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(CFileException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(...)
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - Unhandled Exception!\n"));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!bSucceed)
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pDragRecords);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
HGLOBAL hGlobal = fileRecords.Detach();
|
||
|
|
|
||
|
|
m_bDragMode = TRUE;
|
||
|
|
|
||
|
|
DROPEFFECT dropEffectMask =
|
||
|
|
((m_dwDragDropFlags & xtpReportAllowDragCopy) ? DROPEFFECT_COPY : 0) +
|
||
|
|
((m_dwDragDropFlags & xtpReportAllowDragMove) ? DROPEFFECT_MOVE : 0);
|
||
|
|
|
||
|
|
XTP_NM_REPORTDRAGDROP nmData;
|
||
|
|
ZeroMemory(&nmData, sizeof(nmData));
|
||
|
|
nmData.pRecords = pDragRecords;
|
||
|
|
|
||
|
|
if (SendNotifyMessage(XTP_NM_REPORT_BEGINDRAG, (NMHDR*)&nmData) == -1)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ds.CacheGlobalData (m_cfReport, hGlobal);
|
||
|
|
DROPEFFECT dropEffect = ds.DoDragDrop(dropEffectMask);
|
||
|
|
|
||
|
|
m_bDragMode = FALSE;
|
||
|
|
|
||
|
|
nmData.dropEffect = dropEffect;
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_DRAGDROP_COMPLETED, (NMHDR*)&nmData);
|
||
|
|
|
||
|
|
if ((dropEffect == DROPEFFECT_MOVE) && (dropEffectMask & DROPEFFECT_MOVE))
|
||
|
|
{
|
||
|
|
Cut();
|
||
|
|
}
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(pDragRecords);
|
||
|
|
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
}
|
||
|
|
|
||
|
|
DROPEFFECT CXTPReportControl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point, int nState)
|
||
|
|
{
|
||
|
|
DROPEFFECT dropEffect = DROPEFFECT_MOVE;
|
||
|
|
BOOL bAbove = TRUE;
|
||
|
|
CXTPReportRecord* pTargetRecord = NULL;
|
||
|
|
|
||
|
|
if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
|
||
|
|
dropEffect = DROPEFFECT_COPY;
|
||
|
|
|
||
|
|
if (!m_nOLEDropMode)
|
||
|
|
{
|
||
|
|
if (m_cfReport == NULL)
|
||
|
|
dropEffect = DROPEFFECT_NONE;
|
||
|
|
|
||
|
|
if ((m_dwDragDropFlags & xtpReportAllowDrop) == 0)
|
||
|
|
dropEffect = DROPEFFECT_NONE;
|
||
|
|
|
||
|
|
if ((dropEffect != DROPEFFECT_NONE) && (!pDataObject || !pDataObject->IsDataAvailable(m_cfReport)))
|
||
|
|
dropEffect = DROPEFFECT_NONE;
|
||
|
|
}
|
||
|
|
|
||
|
|
int nDropPos = m_nDropPos;
|
||
|
|
m_nDropPos = -1;
|
||
|
|
|
||
|
|
if (dropEffect != DROPEFFECT_NONE)
|
||
|
|
{
|
||
|
|
DoAutoVertScrollIfNeed(m_pointDrag, point);
|
||
|
|
|
||
|
|
if (GetColumns()->GetSortOrder()->GetCount() == 0 && GetColumns()->GetGroupsOrder()->GetCount() == 0)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = HitTest(point);
|
||
|
|
if (pRow && pRow->GetRecord())
|
||
|
|
{
|
||
|
|
bAbove = pRow->GetRect().CenterPoint().y < point.y ? FALSE : TRUE;
|
||
|
|
pTargetRecord = pRow->GetRecord();
|
||
|
|
m_nDropPos = (pRow->GetRect().CenterPoint().y < point.y ? pRow->GetRect().bottom - 1: pRow->GetRect().top - 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if(nState == 0)
|
||
|
|
{
|
||
|
|
// entering, get report records
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(m_pDropRecords);
|
||
|
|
|
||
|
|
CFile* pFile = m_cfReport ? pDataObject->GetFileData(m_cfReport) : NULL;
|
||
|
|
if (pFile)
|
||
|
|
{
|
||
|
|
m_pDropRecords = new CXTPReportRecords();
|
||
|
|
|
||
|
|
const int cErrTextSize = 1024;
|
||
|
|
TCHAR szErrText[cErrTextSize + 1];
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
CArchive ar(pFile, CArchive::load);
|
||
|
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
|
||
|
|
if (!_ReadRecordsFromData(&px, *m_pDropRecords))
|
||
|
|
{
|
||
|
|
m_pDropRecords->RemoveAll();
|
||
|
|
}
|
||
|
|
ar.Close(); // detach from file
|
||
|
|
}
|
||
|
|
catch(CArchiveException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(CFileException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(...)
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - Unhandled Exception!\n"));
|
||
|
|
}
|
||
|
|
|
||
|
|
delete pFile;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(nState == 1)
|
||
|
|
{
|
||
|
|
// leaving, release drop records
|
||
|
|
CMDTARGET_RELEASE(m_pDropRecords);
|
||
|
|
}
|
||
|
|
|
||
|
|
XTP_NM_REPORTDRAGDROP nmData;
|
||
|
|
nmData.pRecords = m_pDropRecords;
|
||
|
|
nmData.pTargetRecord = pTargetRecord;
|
||
|
|
nmData.bAbove = bAbove;
|
||
|
|
nmData.dropEffect = dropEffect;
|
||
|
|
nmData.pt = point;
|
||
|
|
nmData.nState = nState;
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_DRAGOVER, (NMHDR*)&nmData);
|
||
|
|
|
||
|
|
if (m_nDropPos != nDropPos)
|
||
|
|
{
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
return dropEffect;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnTimer(UINT_PTR uTimerID)
|
||
|
|
{
|
||
|
|
if (m_uAutoScrollTimerID == uTimerID)
|
||
|
|
{
|
||
|
|
CPoint ptMouse;
|
||
|
|
if (::GetCursorPos(&ptMouse))
|
||
|
|
{
|
||
|
|
ScreenToClient(&ptMouse);
|
||
|
|
DoAutoVertScrollIfNeed(m_pointDrag, ptMouse);
|
||
|
|
}
|
||
|
|
//TRACE(_T("AutoScrollTimer \n"));
|
||
|
|
}
|
||
|
|
|
||
|
|
CWnd::OnTimer(uTimerID);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EnsureStopAutoVertScroll()
|
||
|
|
{
|
||
|
|
if (m_uAutoScrollTimerID)
|
||
|
|
{
|
||
|
|
KillTimer(m_uAutoScrollTimerID);
|
||
|
|
m_uAutoScrollTimerID = 0;
|
||
|
|
|
||
|
|
//TRACE(_T("AutoScroll STOP \n"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EnsureStartAutoVertScroll()
|
||
|
|
{
|
||
|
|
if (!m_uAutoScrollTimerID)
|
||
|
|
{
|
||
|
|
m_uAutoScrollTimerID = SetTimer(XTP_REPORT_AUTO_SCROLL_TIMER_ID, XTP_REPORT_AUTO_SCROLL_TIMER_RESOLUTION_MS, NULL);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DoAutoVertScrollIfNeed(CPoint ptClick, CPoint pt)
|
||
|
|
{
|
||
|
|
if (!m_arrScreenRows.GetCount())
|
||
|
|
{
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRow* pRow0 = m_arrScreenRows.GetAt(0);
|
||
|
|
CXTPReportRow* pRow1 = m_arrScreenRows.GetAt(m_arrScreenRows.GetCount() - 1);
|
||
|
|
|
||
|
|
if (!pRow0 || !pRow1)
|
||
|
|
{
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int nDirection = 0;
|
||
|
|
|
||
|
|
CRect rc0 = m_rcReportArea; //pRow0->GetRect();
|
||
|
|
CRect rc1 = m_rcReportArea; //pRow1->GetRect();
|
||
|
|
rc0.bottom = m_rcReportArea.top + 20;
|
||
|
|
rc1.top = m_rcReportArea.bottom - 20;
|
||
|
|
|
||
|
|
if (rc0.PtInRect(pt))
|
||
|
|
nDirection = -1;
|
||
|
|
else if (rc1.PtInRect(pt))
|
||
|
|
nDirection = 1;
|
||
|
|
|
||
|
|
if (!nDirection ||
|
||
|
|
m_bDragMode &&
|
||
|
|
(nDirection == 1 && pt.y - ptClick.y < 3 ||
|
||
|
|
nDirection == -1 && ptClick.y - pt.y < 3)
|
||
|
|
)
|
||
|
|
{
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------
|
||
|
|
int nTopRow = GetTopRowIndex();
|
||
|
|
int nRowsCount = m_pRows->GetCount();
|
||
|
|
|
||
|
|
if (nDirection == -1 && nTopRow > 0 ||
|
||
|
|
nDirection == 1 &&
|
||
|
|
(pRow1->GetIndex() < nRowsCount ||
|
||
|
|
pRow1->GetRect().bottom > m_rcReportArea.bottom)
|
||
|
|
)
|
||
|
|
{
|
||
|
|
//TRACE(_T("AutoScroll direction=%d, nextRow=%d\n"), nDirection, nTopRow+nDirection);
|
||
|
|
SetTopRow(nTopRow + nDirection);
|
||
|
|
|
||
|
|
EnsureStartAutoVertScroll();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(m_pDropRecords);
|
||
|
|
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
|
||
|
|
CUpdateContext updateContext(this);
|
||
|
|
int nDropPos = m_nDropPos;
|
||
|
|
m_nDropPos = -1;
|
||
|
|
|
||
|
|
if (dropEffect != DROPEFFECT_COPY && dropEffect != DROPEFFECT_MOVE)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
|
||
|
|
if (IsVirtualMode())
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
if (!pDataObject || !pDataObject->IsDataAvailable(m_cfReport))
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
if ((m_dwDragDropFlags & xtpReportAllowDrop) == 0)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
int nInsert = GetRecords()->GetCount();
|
||
|
|
|
||
|
|
BOOL bAbove = TRUE;
|
||
|
|
CXTPReportRecord* pTargetRecord = NULL;
|
||
|
|
|
||
|
|
CXTPReportRow* pRow = HitTest(point);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
bAbove = pRow->GetRect().CenterPoint().y < point.y ? FALSE : TRUE;
|
||
|
|
|
||
|
|
pTargetRecord = pRow->GetRecord();
|
||
|
|
if(pTargetRecord)
|
||
|
|
nInsert = pTargetRecord->GetIndex() + (bAbove ? 0 : 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bDragMode && dropEffect == DROPEFFECT_MOVE)
|
||
|
|
{
|
||
|
|
if (nDropPos == -1)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
CXTPReportRecords* pDropRecords = new CXTPReportRecords(TRUE);
|
||
|
|
|
||
|
|
if (!_GetSelectedRows(pDropRecords))
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pDropRecords);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
XTP_NM_REPORTDRAGDROP nmData;
|
||
|
|
nmData.pRecords = pDropRecords;
|
||
|
|
nmData.pTargetRecord = pTargetRecord;
|
||
|
|
nmData.bAbove = bAbove;
|
||
|
|
nmData.dropEffect = dropEffect;
|
||
|
|
|
||
|
|
CMDTARGET_ADDREF(pTargetRecord);
|
||
|
|
|
||
|
|
if (SendNotifyMessage(XTP_NM_REPORT_DROP, (NMHDR*)&nmData) == -1)
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pDropRecords);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
GetRecords()->Move(nInsert, pDropRecords);
|
||
|
|
|
||
|
|
Populate();
|
||
|
|
|
||
|
|
_SelectRows(pDropRecords);
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_RECORDS_DROPPED, (NMHDR*)&nmData);
|
||
|
|
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(pDropRecords);
|
||
|
|
CMDTARGET_RELEASE(pTargetRecord);
|
||
|
|
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CFile* pFile = pDataObject->GetFileData(m_cfReport);
|
||
|
|
if (!pFile)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
CXTPReportRecords* pDropRecords = new CXTPReportRecords();
|
||
|
|
|
||
|
|
const int cErrTextSize = 1024;
|
||
|
|
TCHAR szErrText[cErrTextSize + 1];
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
CArchive ar(pFile, CArchive::load);
|
||
|
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
|
||
|
|
if (!_ReadRecordsFromData(&px, *pDropRecords))
|
||
|
|
{
|
||
|
|
pDropRecords->RemoveAll();
|
||
|
|
}
|
||
|
|
ar.Close(); // detach from file
|
||
|
|
}
|
||
|
|
catch(CArchiveException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(CFileException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(...)
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - Unhandled Exception!\n"));
|
||
|
|
}
|
||
|
|
|
||
|
|
delete pFile;
|
||
|
|
|
||
|
|
XTP_NM_REPORTDRAGDROP nmData;
|
||
|
|
nmData.pRecords = pDropRecords;
|
||
|
|
nmData.pTargetRecord = pTargetRecord;
|
||
|
|
nmData.bAbove = bAbove;
|
||
|
|
nmData.dropEffect = dropEffect;
|
||
|
|
|
||
|
|
if (SendNotifyMessage(XTP_NM_REPORT_DROP, (NMHDR*)&nmData) == -1)
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pDropRecords);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add and Populate records
|
||
|
|
int nRecordsCount = pDropRecords->GetCount();
|
||
|
|
if (nRecordsCount > 0)
|
||
|
|
{
|
||
|
|
// Add
|
||
|
|
for (int i = 0; i < nRecordsCount; i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = pDropRecords->GetAt(i);
|
||
|
|
if (pRecord)
|
||
|
|
{
|
||
|
|
CMDTARGET_ADDREF(pRecord);
|
||
|
|
|
||
|
|
m_pRecords->InsertAt(nInsert, pRecord);
|
||
|
|
nInsert++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Populate();
|
||
|
|
|
||
|
|
_SelectRows(pDropRecords);
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_RECORDS_DROPPED, (NMHDR*)&nmData);
|
||
|
|
}
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(pDropRecords);
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
||
|
|
{
|
||
|
|
if (nHitTest == HTCLIENT)
|
||
|
|
{
|
||
|
|
switch (m_mouseMode)
|
||
|
|
{
|
||
|
|
case xtpReportMouseOverColumnDivide:
|
||
|
|
SetCursor(GetReportHeader()->m_hResizeCursor);
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return CWnd::OnSetCursor(pWnd, nHitTest, message);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
LRESULT CXTPReportControl::SendNotifyMessage(UINT nMessage, NMHDR* pNMHDR) const
|
||
|
|
{
|
||
|
|
if (!IsWindow(m_hWnd))
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
NMHDR nmhdr;
|
||
|
|
if (pNMHDR == NULL)
|
||
|
|
pNMHDR = &nmhdr;
|
||
|
|
|
||
|
|
pNMHDR->hwndFrom = GetSafeHwnd();
|
||
|
|
pNMHDR->idFrom = GetDlgCtrlID();
|
||
|
|
pNMHDR->code = nMessage;
|
||
|
|
|
||
|
|
CWnd *pOwner = GetOwner();
|
||
|
|
if (pOwner && IsWindow(pOwner->m_hWnd))
|
||
|
|
return pOwner->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM)pNMHDR);
|
||
|
|
else
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
LRESULT CXTPReportControl::SendMessageToParent(CXTPReportRow* pRow, CXTPReportRecordItem* pItem, CXTPReportColumn* pColumn, UINT nMessage, CPoint* pPoint, int nHyperlink) const
|
||
|
|
{
|
||
|
|
if (!IsWindow(m_hWnd))
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
XTP_NM_REPORTRECORDITEM nmgv;
|
||
|
|
nmgv.pItem = pItem;
|
||
|
|
nmgv.pColumn = pColumn;
|
||
|
|
nmgv.pRow = pRow;
|
||
|
|
nmgv.nHyperlink = nHyperlink;
|
||
|
|
nmgv.pt.x = 0;
|
||
|
|
nmgv.pt.y = 0;
|
||
|
|
if (pPoint)
|
||
|
|
{
|
||
|
|
nmgv.pt = *pPoint;
|
||
|
|
}
|
||
|
|
|
||
|
|
return SendNotifyMessage(nMessage, (NMHDR*)&nmgv);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DoPropExchange(CXTPPropExchange* pPX)
|
||
|
|
{
|
||
|
|
TRY
|
||
|
|
{
|
||
|
|
pPX->ExchangeSchemaSafe();
|
||
|
|
|
||
|
|
CXTPPropExchangeSection secColumns(pPX->GetSection(_T("Columns")));
|
||
|
|
m_pColumns->DoPropExchange(&secColumns);
|
||
|
|
|
||
|
|
PX_Bool(pPX, _T("ShowGroupBox"), m_bGroupByEnabled, FALSE);
|
||
|
|
PX_Int(pPX, _T("FreezeColumnsCount"), m_nFreezeColumnsCount, 0);
|
||
|
|
|
||
|
|
if (pPX->GetSchema() >= _XTP_SCHEMA_110)
|
||
|
|
{
|
||
|
|
PX_Bool(pPX, _T("FullColumnScrolling"), m_bFullColumnScrolling, FALSE);
|
||
|
|
PX_Int(pPX, _T("HScrollStep"), m_nHScrollStep, XTP_REPORT_HSCROLL_STEP);
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPPropExchangeSection secHeader(pPX->GetSection(_T("Header")));
|
||
|
|
GetReportHeader()->DoPropExchange(&secHeader);
|
||
|
|
|
||
|
|
if (pPX->IsLoading())
|
||
|
|
{
|
||
|
|
GetReportHeader()->OnColumnsChanged();
|
||
|
|
Populate();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CATCH(CArchiveException, e)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
END_CATCH
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SerializeState(CArchive& ar)
|
||
|
|
{
|
||
|
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
DoPropExchange(&px);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::CollapseAll()
|
||
|
|
{
|
||
|
|
BeginUpdate();
|
||
|
|
for (int i = m_pRows->GetCount() - 1; i >= 0; i--)
|
||
|
|
m_pRows->GetAt(i)->SetExpanded(FALSE);
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
EnsureVisible(GetFocusedRow());
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::ExpandAll()
|
||
|
|
{
|
||
|
|
BeginUpdate();
|
||
|
|
for (int i = m_pRows->GetCount() - 1; i >= 0; i--)
|
||
|
|
m_pRows->GetAt(i)->SetExpanded(TRUE);
|
||
|
|
|
||
|
|
EndUpdate();
|
||
|
|
EnsureVisible(GetFocusedRow());
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetMouseMode(XTPReportMouseMode nMode)
|
||
|
|
{
|
||
|
|
XTP_TRACE(_T("SetMouseMode: Switching from %d to %d\n"), m_mouseMode, nMode);
|
||
|
|
m_mouseMode = nMode;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::RelayToolTipEvent(UINT message)
|
||
|
|
{
|
||
|
|
if (m_wndTip.GetSafeHwnd() && m_wndTip.IsWindowVisible())
|
||
|
|
{
|
||
|
|
CPoint pt;
|
||
|
|
GetCursorPos(&pt);
|
||
|
|
|
||
|
|
if (!m_wndTip.GetHoverRect().PtInRect(pt))
|
||
|
|
{
|
||
|
|
m_wndTip.SetTooltipText(NULL);
|
||
|
|
m_wndTip.Activate(FALSE, FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (message)
|
||
|
|
{
|
||
|
|
case WM_MOUSEWHEEL:
|
||
|
|
case WM_KEYDOWN:
|
||
|
|
case WM_SYSKEYDOWN:
|
||
|
|
case WM_LBUTTONDOWN:
|
||
|
|
case WM_RBUTTONDOWN:
|
||
|
|
case WM_MBUTTONDOWN:
|
||
|
|
case WM_LBUTTONUP:
|
||
|
|
case WM_RBUTTONUP:
|
||
|
|
case WM_MBUTTONUP:
|
||
|
|
case WM_MOUSELEAVE:
|
||
|
|
m_wndTip.Activate(FALSE, FALSE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
||
|
|
{
|
||
|
|
static BOOL bRelay = FALSE;
|
||
|
|
if (m_wndTip.GetSafeHwnd() && m_wndTip.IsWindowVisible() && !bRelay)
|
||
|
|
{
|
||
|
|
bRelay = TRUE;
|
||
|
|
RelayToolTipEvent(message);
|
||
|
|
bRelay = FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_pToolTipContext && m_bShowTooltips)
|
||
|
|
{
|
||
|
|
m_pToolTipContext->FilterToolTipMessage(this, message, wParam, lParam);
|
||
|
|
}
|
||
|
|
|
||
|
|
return CWnd::OnWndMsg(message, wParam, lParam, pResult);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnSysColorChange()
|
||
|
|
{
|
||
|
|
CWnd::OnSysColorChange();
|
||
|
|
m_pPaintManager->RefreshMetrics();
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
UINT CXTPReportControl::OnGetDlgCode()
|
||
|
|
{
|
||
|
|
return (m_bFocusSubItems ? DLGC_WANTTAB :0) | DLGC_WANTARROWS | DLGC_WANTCHARS;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnSetFocus(CWnd* pOldWnd)
|
||
|
|
{
|
||
|
|
CWnd::OnSetFocus(pOldWnd);
|
||
|
|
RedrawControl();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnKillFocus (CWnd* pNewWnd)
|
||
|
|
{
|
||
|
|
CWnd::OnKillFocus(pNewWnd);
|
||
|
|
|
||
|
|
EnsureStopAutoVertScroll();
|
||
|
|
RedrawControl();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::GetHeaderIndent() const
|
||
|
|
{
|
||
|
|
return GetIndent(GetReportHeader()->m_nIndentLevel);
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRow* CXTPReportControl::CreateRow()
|
||
|
|
{
|
||
|
|
return new CXTPReportRow_Batch();
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportGroupRow* CXTPReportControl::CreateGroupRow()
|
||
|
|
{
|
||
|
|
return new CXTPReportGroupRow_Batch();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRow* CXTPReportControl::CreateHeaderFooterRow()
|
||
|
|
{
|
||
|
|
return new CXTPHeapObjectT<CXTPReportRow, CXTPReportAllocatorDefault>;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EditItem(XTP_REPORTRECORDITEM_ARGS* pItemArgs)
|
||
|
|
{
|
||
|
|
CXTPReportRecordItem* pItem = pItemArgs ? pItemArgs->pItem : NULL;
|
||
|
|
|
||
|
|
if (m_pActiveItem != NULL)
|
||
|
|
{
|
||
|
|
m_pActiveItem->OnCancelEdit(this, TRUE);
|
||
|
|
m_pActiveItem = NULL;
|
||
|
|
|
||
|
|
if (!m_bFocusSubItems)
|
||
|
|
{
|
||
|
|
SetFocusedColumn(NULL);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CMDTARGET_RELEASE(m_ptrVirtualEditingRow);
|
||
|
|
|
||
|
|
if (pItem && pItemArgs && pItemArgs->pRow)
|
||
|
|
{
|
||
|
|
if (!HasFocus())
|
||
|
|
SetFocus();
|
||
|
|
|
||
|
|
if (!IsVirtualMode())
|
||
|
|
{
|
||
|
|
AdjustScrollBars();
|
||
|
|
RedrawControl();
|
||
|
|
UpdateWindow();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsVirtualMode())
|
||
|
|
{
|
||
|
|
int nRowIndex = pItemArgs->pRow->GetIndex();
|
||
|
|
|
||
|
|
EnsureVisible(pItemArgs->pRow);
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
UpdateWindow();
|
||
|
|
pItemArgs->pRow = NULL; // RedrawControl delete and re-create new screen rows
|
||
|
|
|
||
|
|
BOOL bMapped = FALSE;
|
||
|
|
int nScrCount = m_arrScreenRows.GetCount();
|
||
|
|
for (int i = 0; i < nScrCount; i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = m_arrScreenRows.GetAt(i);
|
||
|
|
if (pRow->GetIndex() == nRowIndex)
|
||
|
|
{
|
||
|
|
pItemArgs->pRow = pRow;
|
||
|
|
bMapped = TRUE;
|
||
|
|
|
||
|
|
ASSERT(m_ptrVirtualEditingRow == NULL);
|
||
|
|
|
||
|
|
m_ptrVirtualEditingRow = pRow;
|
||
|
|
CMDTARGET_ADDREF(m_ptrVirtualEditingRow);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ASSERT(bMapped);
|
||
|
|
if (!bMapped)
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
else if (GetFocusedRow() != pItemArgs->pRow)
|
||
|
|
{
|
||
|
|
SetFocusedRow(pItemArgs->pRow);
|
||
|
|
UpdateWindow();
|
||
|
|
}
|
||
|
|
|
||
|
|
pItemArgs->rcItem = pItemArgs->pRow->GetItemRect(pItem);
|
||
|
|
|
||
|
|
if(SetFocusedColumn(pItemArgs->pColumn))
|
||
|
|
{
|
||
|
|
m_pActiveItem = pItem;
|
||
|
|
pItem->OnBeginEdit(pItemArgs);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::HasFocus() const
|
||
|
|
{
|
||
|
|
const CWnd* pFocusWnd = GetFocus();
|
||
|
|
if (!pFocusWnd)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
return (pFocusWnd->GetSafeHwnd() == m_hWnd) || (pFocusWnd->GetParent()->GetSafeHwnd() == m_hWnd) || (pFocusWnd->GetOwner()->GetSafeHwnd() == m_hWnd);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void CXTPReportControl::ReleaseItem(int nIndex)
|
||
|
|
{
|
||
|
|
int i;
|
||
|
|
|
||
|
|
for (i = 0; i < m_pRecords->GetCount(); i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = m_pRecords->GetAt(i);
|
||
|
|
|
||
|
|
pRecord->m_arrItems[nIndex]->InternalRelease();
|
||
|
|
pRecord->m_arrItems.RemoveAt(nIndex);
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportColumns* pColumns = GetColumns();
|
||
|
|
|
||
|
|
CXTPReportColumn* pColumnToRemove = NULL;
|
||
|
|
|
||
|
|
int nColumnsCount = pColumns->GetCount();
|
||
|
|
for (i = 0; i < nColumnsCount; i++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = pColumns->GetAt(i);
|
||
|
|
|
||
|
|
if (pColumn->m_nItemIndex > nIndex)
|
||
|
|
{
|
||
|
|
pColumn->m_nItemIndex--;
|
||
|
|
}
|
||
|
|
else if (pColumn->m_nItemIndex == nIndex)
|
||
|
|
{
|
||
|
|
pColumnToRemove = pColumn;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pColumnToRemove)
|
||
|
|
pColumns->Remove(pColumnToRemove);
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetVirtualMode(CXTPReportRecord* pVirtualRecord, int nCount)
|
||
|
|
{
|
||
|
|
if (m_pRecords)
|
||
|
|
m_pRecords->SetVirtualMode(pVirtualRecord, nCount);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::IsVirtualMode() const
|
||
|
|
{
|
||
|
|
return m_pRecords ? m_pRecords->IsVirtualMode() : FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRow* CXTPReportControl::GetFocusedRow() const
|
||
|
|
{
|
||
|
|
if (m_nFocusedRow != -1)
|
||
|
|
return m_pRows ? m_pRows->GetAt(m_nFocusedRow) : NULL;
|
||
|
|
|
||
|
|
if (m_nFocusedHeaderRow != -1)
|
||
|
|
return m_pHeaderRows ? m_pHeaderRows->GetAt(m_nFocusedHeaderRow) : NULL;
|
||
|
|
|
||
|
|
if (m_nFocusedFooterRow != -1)
|
||
|
|
return m_pFooterRows ? m_pFooterRows->GetAt(m_nFocusedFooterRow) : NULL;
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
|
||
|
|
{
|
||
|
|
CWnd::OnStyleChanged(nStyleType, lpStyleStruct);
|
||
|
|
|
||
|
|
RedrawControl();
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPToolTipContext* CXTPReportControl::GetToolTipContext() const
|
||
|
|
{
|
||
|
|
return m_pToolTipContext;
|
||
|
|
}
|
||
|
|
|
||
|
|
INT_PTR CXTPReportControl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
|
||
|
|
{
|
||
|
|
ASSERT_VALID(this);
|
||
|
|
ASSERT(::IsWindow(m_hWnd));
|
||
|
|
|
||
|
|
// check child windows first by calling CControlBar
|
||
|
|
INT_PTR nHit = CWnd::OnToolHitTest(point, pTI);
|
||
|
|
if (nHit != -1)
|
||
|
|
return nHit;
|
||
|
|
|
||
|
|
nHit = GetReportHeader()->OnToolHitTest(point, pTI);
|
||
|
|
if (nHit != -1)
|
||
|
|
return nHit;
|
||
|
|
|
||
|
|
CXTPReportRow* pRow = HitTest(point);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
nHit = pRow->OnToolHitTest(point, pTI);
|
||
|
|
}
|
||
|
|
|
||
|
|
return nHit;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::SetLayoutRTL(BOOL bRightToLeft)
|
||
|
|
{
|
||
|
|
if (!XTPSystemVersion()->IsLayoutRTLSupported())
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (!m_hWnd)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ModifyStyleEx(bRightToLeft ? 0 : WS_EX_LAYOUTRTL, !bRightToLeft ? 0 : WS_EX_LAYOUTRTL);
|
||
|
|
GetImageManager()->DrawReverted(bRightToLeft);
|
||
|
|
|
||
|
|
GetInplaceEdit()->DestroyWindow();
|
||
|
|
|
||
|
|
AdjustLayout();
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::IsLayoutRTL()
|
||
|
|
{
|
||
|
|
if (!XTPSystemVersion()->IsLayoutRTLSupported())
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
if (!m_hWnd)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
return !!(GetWindowLong(m_hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL);
|
||
|
|
}
|
||
|
|
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
// Clipboard operations
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::CanCopy()
|
||
|
|
{
|
||
|
|
// Check whether are there any selected rows to be copied
|
||
|
|
CXTPReportSelectedRows* pSelRows = GetSelectedRows();
|
||
|
|
|
||
|
|
if ((pSelRows != NULL) && (pSelRows->GetCount() > 0))
|
||
|
|
{
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::CanCut()
|
||
|
|
{
|
||
|
|
if (IsVirtualMode())
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
return CanCopy();
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::CanPaste()
|
||
|
|
{
|
||
|
|
if (IsVirtualMode())
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
CLIPFORMAT uCF_Records = (CLIPFORMAT)::RegisterClipboardFormat(XTPREPORTCTRL_CF_RECORDS);
|
||
|
|
|
||
|
|
BOOL bCan = FALSE;
|
||
|
|
COleDataObject odj;
|
||
|
|
if (odj.AttachClipboard())
|
||
|
|
{
|
||
|
|
bCan = odj.IsDataAvailable(CF_TEXT)
|
||
|
|
|| odj.IsDataAvailable(CF_UNICODETEXT)
|
||
|
|
|| odj.IsDataAvailable(uCF_Records) ;
|
||
|
|
}
|
||
|
|
return bCan;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::Cut()
|
||
|
|
{
|
||
|
|
CWaitCursor _WC;
|
||
|
|
|
||
|
|
// Copy selected data into the clipboard
|
||
|
|
Copy();
|
||
|
|
|
||
|
|
if (IsVirtualMode())
|
||
|
|
return;
|
||
|
|
|
||
|
|
// Delete selected rows
|
||
|
|
CXTPInternalCollectionT<CXTPReportRow> arSelectedRows;
|
||
|
|
_GetSelectedRows(NULL, &arSelectedRows);
|
||
|
|
int nSelRowsCount = (int)arSelectedRows.GetSize();
|
||
|
|
int nFirstSelRow = INT_MAX;
|
||
|
|
for (int i = nSelRowsCount - 1; i >= 0 ; i--)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = arSelectedRows.GetAt(i, FALSE);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
nFirstSelRow = min(nFirstSelRow, pRow->GetIndex());
|
||
|
|
VERIFY(RemoveRowEx(pRow, FALSE));
|
||
|
|
}
|
||
|
|
|
||
|
|
arSelectedRows.RemoveAt(i);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GetSelectedRows())
|
||
|
|
{
|
||
|
|
GetSelectedRows()->Clear();
|
||
|
|
|
||
|
|
if (nFirstSelRow != INT_MAX)
|
||
|
|
{
|
||
|
|
m_nFocusedRow = min(nFirstSelRow, GetRows()->GetCount() - 1);
|
||
|
|
|
||
|
|
if (GetFocusedRow())
|
||
|
|
{
|
||
|
|
SetFocusedRow(GetFocusedRow());
|
||
|
|
GetSelectedRows()->Add(GetFocusedRow());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
AdjustScrollBars();
|
||
|
|
RedrawControl();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// We support text format with \t dividers for record items and
|
||
|
|
// \r\n dividers for records (simple tab-separated text).
|
||
|
|
// Such format is also supported by Excel and some other applications.
|
||
|
|
void CXTPReportControl::Copy()
|
||
|
|
{
|
||
|
|
CWaitCursor _WC;
|
||
|
|
|
||
|
|
int nRowsCount = GetSelectedRows() ? GetSelectedRows()->GetCount() : 1;
|
||
|
|
|
||
|
|
// minimize memory reallocs to improve performance
|
||
|
|
UINT nAveRecordsSize = 1500; // bytes
|
||
|
|
UINT nGrowBytes = ((nRowsCount * nAveRecordsSize) / 4096 + 1) * 4096;
|
||
|
|
|
||
|
|
UINT nAllocFlags = GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT;
|
||
|
|
|
||
|
|
CSharedFile fileRecords(nAllocFlags, nGrowBytes);
|
||
|
|
|
||
|
|
BOOL bIsRecordsData = FALSE;
|
||
|
|
|
||
|
|
//------------------------------------------------------------------------
|
||
|
|
const int cErrTextSize = 1024;
|
||
|
|
TCHAR szErrText[cErrTextSize + 1];
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
CArchive ar(&fileRecords, CArchive::store);
|
||
|
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
|
||
|
|
bIsRecordsData = _WriteSelectedRowsData(&px);
|
||
|
|
|
||
|
|
ar.Close(); // perform Flush() and detach from file
|
||
|
|
}
|
||
|
|
catch(CArchiveException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(CFileException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(...)
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Copy() - Unhandled Exception!\n"));
|
||
|
|
}
|
||
|
|
|
||
|
|
//*****
|
||
|
|
CString strClipText = _GetSelectedRowsVisibleColsText();
|
||
|
|
|
||
|
|
CLIPFORMAT uCF_Records = (CLIPFORMAT)::RegisterClipboardFormat(XTPREPORTCTRL_CF_RECORDS);
|
||
|
|
|
||
|
|
// Put prepared text into the clipboard
|
||
|
|
if (OpenClipboard())
|
||
|
|
{
|
||
|
|
::EmptyClipboard();
|
||
|
|
|
||
|
|
// 1 - Text
|
||
|
|
int nLen = (strClipText.GetLength() + 1) * sizeof(TCHAR);
|
||
|
|
HGLOBAL hText = ::GlobalAlloc(nAllocFlags, nLen);
|
||
|
|
|
||
|
|
if (hText != NULL)
|
||
|
|
{
|
||
|
|
LPTSTR lptstrCopy = (TCHAR*)GlobalLock(hText);
|
||
|
|
STRCPY_S(lptstrCopy, strClipText.GetLength() + 1, (LPCTSTR)strClipText);
|
||
|
|
GlobalUnlock(hText);
|
||
|
|
|
||
|
|
#ifndef _UNICODE
|
||
|
|
::SetClipboardData(CF_TEXT, hText);
|
||
|
|
#else
|
||
|
|
::SetClipboardData(CF_UNICODETEXT, hText);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2 - Blob data
|
||
|
|
if (bIsRecordsData)
|
||
|
|
{
|
||
|
|
HGLOBAL hData = fileRecords.Detach();
|
||
|
|
::GlobalUnlock(hData); // unlock data
|
||
|
|
::SetClipboardData(uCF_Records, hData);
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------
|
||
|
|
::CloseClipboard();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::Paste()
|
||
|
|
{
|
||
|
|
if (IsVirtualMode())
|
||
|
|
return;
|
||
|
|
|
||
|
|
CWaitCursor _WC;
|
||
|
|
|
||
|
|
CLIPFORMAT uCF_Records = (CLIPFORMAT)::RegisterClipboardFormat(XTPREPORTCTRL_CF_RECORDS);
|
||
|
|
|
||
|
|
CXTPReportRecords arRecords;
|
||
|
|
BOOL bTryPasteFromText = TRUE;
|
||
|
|
|
||
|
|
// Retrieve text from the clipboard
|
||
|
|
if (!OpenClipboard())
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (::IsClipboardFormatAvailable(uCF_Records))
|
||
|
|
{
|
||
|
|
HGLOBAL hPasteData = ::GetClipboardData(uCF_Records);
|
||
|
|
|
||
|
|
if (hPasteData)
|
||
|
|
{
|
||
|
|
bTryPasteFromText = FALSE;
|
||
|
|
|
||
|
|
const int cErrTextSize = 1024;
|
||
|
|
TCHAR szErrText[cErrTextSize + 1];
|
||
|
|
|
||
|
|
CSharedFile fileSahred;
|
||
|
|
fileSahred.SetHandle(hPasteData, FALSE);
|
||
|
|
CArchive ar(&fileSahred, CArchive::load);
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
|
||
|
|
if (!_ReadRecordsFromData(&px, arRecords))
|
||
|
|
{
|
||
|
|
arRecords.RemoveAll();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch(CArchiveException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(CFileException* pE)
|
||
|
|
{
|
||
|
|
if (pE->GetErrorMessage(szErrText, cErrTextSize))
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - %s\n"), szErrText);
|
||
|
|
}
|
||
|
|
pE->Delete();
|
||
|
|
}
|
||
|
|
catch(...)
|
||
|
|
{
|
||
|
|
TRACE(_T("EXCEPTION: CXTPReportControl::Paste() - Unhandled Exception!\n"));
|
||
|
|
}
|
||
|
|
|
||
|
|
//*********
|
||
|
|
ar.Close(); // detach from file
|
||
|
|
fileSahred.Detach(); //detach from data
|
||
|
|
::GlobalUnlock(hPasteData); // unlock data
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UINT uCF_TText = sizeof(TCHAR) == 2 ? CF_UNICODETEXT : CF_TEXT;
|
||
|
|
|
||
|
|
if (bTryPasteFromText && ::IsClipboardFormatAvailable(uCF_TText))
|
||
|
|
{
|
||
|
|
// Try to get text data from the clipboard
|
||
|
|
HGLOBAL hglbPaste = ::GetClipboardData(uCF_TText);
|
||
|
|
|
||
|
|
// Import Text data into the control
|
||
|
|
if (hglbPaste != NULL)
|
||
|
|
{
|
||
|
|
TCHAR* lpszClipboard = (TCHAR*)GlobalLock(hglbPaste);
|
||
|
|
|
||
|
|
if (!_ReadRecordsFromText(lpszClipboard, arRecords))
|
||
|
|
{
|
||
|
|
arRecords.RemoveAll();
|
||
|
|
}
|
||
|
|
::GlobalUnlock(hglbPaste);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
::CloseClipboard();
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
CUpdateContext updateContext(this);
|
||
|
|
|
||
|
|
// Add and Populate records
|
||
|
|
int nRecordsCount = arRecords.GetCount();
|
||
|
|
if (nRecordsCount > 0)
|
||
|
|
{
|
||
|
|
// Add
|
||
|
|
for (int i = 0; i < nRecordsCount; i++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRecord = arRecords.GetAt(i);
|
||
|
|
if (pRecord)
|
||
|
|
{
|
||
|
|
CMDTARGET_ADDREF(pRecord);
|
||
|
|
AddRecord(pRecord);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Populate();
|
||
|
|
|
||
|
|
// Select added records
|
||
|
|
_SelectRows(&arRecords);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// We support text format with \t dividers for record items and
|
||
|
|
// \r\n dividers for records (simple tab-separated text).
|
||
|
|
// Such format is also supported by Excel and some other applications.
|
||
|
|
CString CXTPReportControl::_GetSelectedRowsVisibleColsText()
|
||
|
|
{
|
||
|
|
CString strSelText;
|
||
|
|
|
||
|
|
CXTPReportColumns* pColumns = GetColumns();
|
||
|
|
if (NULL == pColumns)
|
||
|
|
return _T("");
|
||
|
|
|
||
|
|
const int nColumnCount = pColumns->GetVisibleColumnsCount();
|
||
|
|
|
||
|
|
// Iterate over the selected rows and prepare corresponding records text
|
||
|
|
CXTPReportSelectedRows* pSelectedRows = GetSelectedRows();
|
||
|
|
if ((pSelectedRows != NULL) && (pSelectedRows->GetCount() > 0))
|
||
|
|
{
|
||
|
|
POSITION pos = pSelectedRows->GetFirstSelectedRowPosition();
|
||
|
|
while (pos)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pSelectedRows->GetNextSelectedRow(pos);
|
||
|
|
if (NULL == pRow)
|
||
|
|
break;
|
||
|
|
|
||
|
|
CXTPReportRecord* pRecord = pRow->GetRecord();
|
||
|
|
if (NULL == pRecord)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
CStringArray arStrings;
|
||
|
|
for (int nCol = 0; nCol < nColumnCount; nCol++)
|
||
|
|
{
|
||
|
|
CXTPReportColumn* pColumn = pColumns->GetVisibleAt(nCol);
|
||
|
|
CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn);
|
||
|
|
if (NULL == pItem)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
arStrings.Add(pItem->GetCaption(pColumn));
|
||
|
|
}
|
||
|
|
|
||
|
|
//===============================================================
|
||
|
|
BOOL bCanceled = OnBeforeCopyToText(pRecord, arStrings);
|
||
|
|
if (bCanceled)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
strSelText += XTPStrMake(arStrings, _T("\t"));
|
||
|
|
strSelText += _T("\r\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return strSelText;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::_ReadRecordsFromText(LPCTSTR pcszText,
|
||
|
|
CXTPReportRecords& rarRecords)
|
||
|
|
{
|
||
|
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
// Insert retrieved text into the control
|
||
|
|
|
||
|
|
CStringArray arRecordsStrings;
|
||
|
|
XTPStrSplit(pcszText, _T("\r\n"), arRecordsStrings);
|
||
|
|
|
||
|
|
int nCount = (int)arRecordsStrings.GetSize();
|
||
|
|
for (int i = 0; i < nCount; i++)
|
||
|
|
{
|
||
|
|
CString strRecord = arRecordsStrings[i];
|
||
|
|
if (strRecord.IsEmpty())
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRecord* pNewRec = _CreateRecodFromText(strRecord);
|
||
|
|
// pNewRec = NULL - paste was handled by the user
|
||
|
|
|
||
|
|
if (pNewRec)
|
||
|
|
{
|
||
|
|
rarRecords.Add(pNewRec);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRecord* CXTPReportControl::_CreateRecodFromText(LPCTSTR pcszRecord)
|
||
|
|
{
|
||
|
|
if (!GetColumns())
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
CStringArray arStrings;
|
||
|
|
|
||
|
|
// Read each field from the initial string and set visible field one by one
|
||
|
|
XTPStrSplit(pcszRecord, _T("\t"), arStrings);
|
||
|
|
|
||
|
|
//=======================================================================
|
||
|
|
CXTPReportRecord* pRecord = NULL;
|
||
|
|
BOOL bHandled = OnBeforePasteFromText(arStrings, &pRecord);
|
||
|
|
if (bHandled)
|
||
|
|
{
|
||
|
|
return pRecord;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if _MFC_VER >= 0x0600 // Not supported by Visual Studio 5.0
|
||
|
|
|
||
|
|
if (!pRecord)
|
||
|
|
{
|
||
|
|
pRecord = new CXTPReportRecord();
|
||
|
|
if (!pRecord)
|
||
|
|
{
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
int nDataCount = (int)arStrings.GetSize();
|
||
|
|
|
||
|
|
// Fill record with all items
|
||
|
|
int nCount = GetColumns()->GetCount();
|
||
|
|
for (int i = 0; i < nCount; i++)
|
||
|
|
{
|
||
|
|
COleVariant varItem(_T(""));
|
||
|
|
|
||
|
|
CXTPReportRecordItem* pItem = new CXTPReportRecordItemVariant(varItem);
|
||
|
|
if (!pItem)
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pRecord);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
pRecord->AddItem(pItem);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Iterate all visible columns and set text for each next
|
||
|
|
const int nColumnCount = GetColumns()->GetVisibleColumnsCount();
|
||
|
|
for (int nCol = 0; nCol < nColumnCount; nCol++)
|
||
|
|
{
|
||
|
|
COleVariant varItem(nCol < nDataCount ? (LPCTSTR)arStrings[nCol] : _T(""));
|
||
|
|
|
||
|
|
CXTPReportColumn* pColumn = GetColumns()->GetVisibleAt(nCol);
|
||
|
|
CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn);
|
||
|
|
ASSERT(pItem);
|
||
|
|
if (NULL == pItem)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
CXTPReportRecordItemVariant* pItemVar = DYNAMIC_DOWNCAST(CXTPReportRecordItemVariant, pItem);
|
||
|
|
ASSERT(pItemVar);
|
||
|
|
|
||
|
|
if (pItemVar)
|
||
|
|
{
|
||
|
|
pItemVar->m_oleValue = varItem;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return pRecord;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::_WriteRecordsData(CXTPPropExchange* pPX, CXTPReportRecords* pRecords)
|
||
|
|
{
|
||
|
|
if (!pRecords)
|
||
|
|
return FALSE;
|
||
|
|
|
||
|
|
|
||
|
|
long nSchema = XTP_REPORT_CB_RECORDS_DATA_VER;
|
||
|
|
|
||
|
|
PX_Long(pPX, _T("Version"), (long&)nSchema);
|
||
|
|
pPX->ExchangeLocale();
|
||
|
|
|
||
|
|
|
||
|
|
CXTPPropExchangeSection secRecords(pPX->GetSection(_T("ReportRecords")));
|
||
|
|
|
||
|
|
int nRecordsCount = (int)pRecords->GetCount();
|
||
|
|
CXTPPropExchangeEnumeratorPtr pEnumRecords(secRecords->GetEnumerator(_T("Record")));
|
||
|
|
POSITION posRecord = pEnumRecords->GetPosition((DWORD)nRecordsCount);
|
||
|
|
|
||
|
|
for (int i = 0; i < nRecordsCount; i++)
|
||
|
|
{
|
||
|
|
CXTPPropExchangeSection secRecord(pEnumRecords->GetNext(posRecord));
|
||
|
|
|
||
|
|
CXTPReportRecord* pRecord = pRecords->GetAt(i);
|
||
|
|
PX_Object(&secRecord, pRecord, RUNTIME_CLASS(CXTPReportRecord));
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::_SelectRows(CXTPReportRecords* pRecords)
|
||
|
|
{
|
||
|
|
CXTPReportRows* pRows = GetRows();
|
||
|
|
CXTPReportSelectedRows* pSelRows = GetSelectedRows();
|
||
|
|
if (!pRows || !pSelRows)
|
||
|
|
return;
|
||
|
|
|
||
|
|
pSelRows->Clear();
|
||
|
|
int nRecordsCount = pRecords->GetCount();
|
||
|
|
|
||
|
|
for (int nNewRecNr = 0; nNewRecNr < nRecordsCount; nNewRecNr++)
|
||
|
|
{
|
||
|
|
CXTPReportRecord* pRec = pRecords->GetAt(nNewRecNr);
|
||
|
|
CXTPReportRow* pRow = pRows->Find(pRec);
|
||
|
|
if (pRow)
|
||
|
|
{
|
||
|
|
pSelRows->Add(pRow);
|
||
|
|
|
||
|
|
if (nNewRecNr == nRecordsCount - 1)
|
||
|
|
SetFocusedRow(pRow, TRUE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::_GetSelectedRows(CXTPReportRecords* pRecords,
|
||
|
|
CXTPInternalCollectionT<CXTPReportRow> *pRows)
|
||
|
|
{
|
||
|
|
ASSERT(!pRecords || pRecords->m_bArray == TRUE);
|
||
|
|
|
||
|
|
CXTPReportSelectedRows* pSelectedRows = GetSelectedRows();
|
||
|
|
if (!pSelectedRows || !pSelectedRows->GetCount() || (!pRecords && !pRows))
|
||
|
|
{
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
POSITION pos = pSelectedRows->GetFirstSelectedRowPosition();
|
||
|
|
while (pos)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pSelectedRows->GetNextSelectedRow(pos);
|
||
|
|
CXTPReportRecord* pRecord = pRow ? pRow->GetRecord() : NULL;
|
||
|
|
if (NULL == pRow)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (pRecord && pRecords)
|
||
|
|
{
|
||
|
|
pRecords->Add(pRecord);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pRow && pRows)
|
||
|
|
{
|
||
|
|
pRows->AddPtr(pRow, TRUE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::_WriteSelectedRowsData(CXTPPropExchange* pPX)
|
||
|
|
{
|
||
|
|
if (!pPX || !pPX->IsStoring())
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPReportRecords* pSelectedRecords= new CXTPReportRecords(TRUE);
|
||
|
|
|
||
|
|
if (!_GetSelectedRows(pSelectedRecords) || !_WriteRecordsData(pPX, pSelectedRecords))
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pSelectedRecords);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(pSelectedRecords);
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::_ReadRecordsFromData(CXTPPropExchange* pPX,
|
||
|
|
CXTPReportRecords& rarRecords)
|
||
|
|
{
|
||
|
|
rarRecords.RemoveAll();
|
||
|
|
|
||
|
|
if (!pPX || !pPX->IsLoading())
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPPropExchangeSection secRecords(pPX->GetSection(_T("ReportRecords")));
|
||
|
|
|
||
|
|
long nSchema = 0;
|
||
|
|
|
||
|
|
PX_Long(pPX, _T("Version"), (long&)nSchema);
|
||
|
|
pPX->ExchangeLocale();
|
||
|
|
|
||
|
|
if (nSchema != XTP_REPORT_CB_RECORDS_DATA_VER)
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return FALSE;
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPPropExchangeEnumeratorPtr pEnumRecords(secRecords->GetEnumerator(_T("Record")));
|
||
|
|
POSITION posRecord = pEnumRecords->GetPosition();
|
||
|
|
|
||
|
|
while (posRecord)
|
||
|
|
{
|
||
|
|
CXTPPropExchangeSection secRecord(pEnumRecords->GetNext(posRecord));
|
||
|
|
|
||
|
|
CXTPReportRecord* pRecord = NULL;
|
||
|
|
PX_Object(&secRecord, pRecord, RUNTIME_CLASS(CXTPReportRecord));
|
||
|
|
|
||
|
|
if (!pRecord)
|
||
|
|
{
|
||
|
|
AfxThrowArchiveException(CArchiveException::badClass);
|
||
|
|
}
|
||
|
|
CXTPReportRecord* pRecord2 = pRecord;
|
||
|
|
BOOL bCanceled = OnBeforePaste(&pRecord2);
|
||
|
|
|
||
|
|
if (bCanceled || pRecord2 != pRecord)
|
||
|
|
{
|
||
|
|
CMDTARGET_RELEASE(pRecord);
|
||
|
|
}
|
||
|
|
if (bCanceled)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
rarRecords.Add(pRecord2);
|
||
|
|
}
|
||
|
|
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnBeforeCopyToText(CXTPReportRecord* pRecord, CStringArray& rarStrings)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORT_BEFORE_COPYPASTE nmParams;
|
||
|
|
::ZeroMemory(&nmParams, sizeof(nmParams));
|
||
|
|
|
||
|
|
CXTPReportRecord* pRecordTmp = pRecord;
|
||
|
|
nmParams.ppRecord = &pRecordTmp;
|
||
|
|
nmParams.parStrings = &rarStrings;
|
||
|
|
|
||
|
|
LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_BEFORE_COPY_TOTEXT, (NMHDR*)&nmParams);
|
||
|
|
|
||
|
|
return lResult != 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnBeforePasteFromText(CStringArray& arStrings,
|
||
|
|
CXTPReportRecord** ppRecord)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORT_BEFORE_COPYPASTE nmParams;
|
||
|
|
::ZeroMemory(&nmParams, sizeof(nmParams));
|
||
|
|
|
||
|
|
nmParams.parStrings = &arStrings;
|
||
|
|
nmParams.ppRecord = ppRecord;
|
||
|
|
|
||
|
|
LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_BEFORE_PASTE_FROMTEXT, (NMHDR*)&nmParams);
|
||
|
|
|
||
|
|
return lResult != 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnBeforePaste(CXTPReportRecord** ppRecord)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORT_BEFORE_COPYPASTE nmParams;
|
||
|
|
::ZeroMemory(&nmParams, sizeof(nmParams));
|
||
|
|
|
||
|
|
nmParams.ppRecord = ppRecord;
|
||
|
|
|
||
|
|
LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_BEFORE_PASTE, (NMHDR*)&nmParams);
|
||
|
|
|
||
|
|
return lResult != 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::OnGetColumnDataBestFitWidth(CXTPReportColumn* pColumn)
|
||
|
|
{
|
||
|
|
CXTPReportPaintManager* pPaintManager = GetPaintManager();
|
||
|
|
if (!pColumn || !pPaintManager)
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
int nDataWidth = 0;
|
||
|
|
int nDataWidth0 = 0;
|
||
|
|
int nDataWidth1 = 0;
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------
|
||
|
|
CXTPClientRect rcClient(this);
|
||
|
|
|
||
|
|
CBitmap bmp;
|
||
|
|
|
||
|
|
{
|
||
|
|
CClientDC dcClient(this);
|
||
|
|
bmp.CreateCompatibleBitmap(&dcClient, rcClient.Width(), rcClient.Height());
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPCompatibleDC dc(NULL, &bmp);
|
||
|
|
|
||
|
|
CXTPFontDC autoFont(&dc, pPaintManager->GetTextFont()); // to reset selected font on exit
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------
|
||
|
|
if(pColumn->GetBestFitMode() == xtpColumnBestFitModeVisibleData
|
||
|
|
/* && pColumn->m_nMaxItemWidth == 0*/)
|
||
|
|
{
|
||
|
|
// calculate width for visible rows only
|
||
|
|
int nVisibleRows = GetReportAreaRows(GetTopRowIndex(), TRUE);
|
||
|
|
|
||
|
|
nDataWidth = OnGetItemsCaptionMaxWidth(&dc, GetRows(), pColumn,
|
||
|
|
GetTopRowIndex(), nVisibleRows);
|
||
|
|
}
|
||
|
|
else if(pColumn->GetBestFitMode() == xtpColumnBestFitModeAllData)
|
||
|
|
{
|
||
|
|
nDataWidth = OnGetItemsCaptionMaxWidth(&dc, GetRows(), pColumn);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_bHeaderRecordsVisible && m_pHeaderRows->GetCount() > 0)
|
||
|
|
nDataWidth0 = OnGetItemsCaptionMaxWidth(&dc, m_pHeaderRows, pColumn);
|
||
|
|
|
||
|
|
if (m_bFooterRecordsVisible && m_pFooterRows->GetCount() > 0)
|
||
|
|
nDataWidth1 = OnGetItemsCaptionMaxWidth(&dc, m_pFooterRows, pColumn);
|
||
|
|
|
||
|
|
nDataWidth = max(nDataWidth, max(nDataWidth0, nDataWidth1));
|
||
|
|
|
||
|
|
return nDataWidth;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::OnGetItemsCaptionMaxWidth(CDC* pDC, CXTPReportRows* pRows,
|
||
|
|
CXTPReportColumn* pColumn, int nStartRow, int nRowsCount)
|
||
|
|
{
|
||
|
|
CXTPReportPaintManager* pPaintManager = GetPaintManager();
|
||
|
|
if(!pDC || !pRows || !pColumn || !pPaintManager)
|
||
|
|
{
|
||
|
|
ASSERT(FALSE);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
XTP_REPORTRECORDITEM_DRAWARGS drawArgs;
|
||
|
|
drawArgs.pDC = pDC;
|
||
|
|
drawArgs.pControl = this;
|
||
|
|
drawArgs.pColumn = pColumn;
|
||
|
|
drawArgs.rcItem = pColumn->GetRect();
|
||
|
|
|
||
|
|
XTP_REPORTRECORDITEM_METRICS* pMetrics = new XTP_REPORTRECORDITEM_METRICS();
|
||
|
|
|
||
|
|
CSize sizeBitmap(0, 0);
|
||
|
|
int nMaxWidth = 0;
|
||
|
|
int nItemIndex = pColumn->GetItemIndex();
|
||
|
|
|
||
|
|
int nEndRow = pRows->GetCount();
|
||
|
|
if (nRowsCount > 0)
|
||
|
|
nEndRow = min(pRows->GetCount(), nStartRow + nRowsCount);
|
||
|
|
|
||
|
|
for (int i = max(0, nStartRow); i < nEndRow; i++)
|
||
|
|
{
|
||
|
|
CXTPReportRow* pRow = pRows->GetAt(i);
|
||
|
|
ASSERT(pRow);
|
||
|
|
if (pRow && pRow->IsGroupRow())
|
||
|
|
continue;
|
||
|
|
|
||
|
|
CXTPReportRecord* pRec = pRow ? pRow->GetRecord() : NULL;
|
||
|
|
CXTPReportRecordItem* pItem = pRec ? pRec->GetItem(nItemIndex) : NULL;
|
||
|
|
ASSERT(pItem);
|
||
|
|
|
||
|
|
if (!pItem)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
// 1. Calculate Text
|
||
|
|
drawArgs.pRow = pRow;
|
||
|
|
drawArgs.pItem = pItem;
|
||
|
|
|
||
|
|
pMetrics->strText = pItem->GetCaption(pColumn);
|
||
|
|
|
||
|
|
pRow->GetItemMetrics(&drawArgs, pMetrics);
|
||
|
|
|
||
|
|
pDC->SelectObject(pMetrics->pFont);
|
||
|
|
|
||
|
|
int nWidth = pDC->GetTextExtent(pMetrics->strText).cx + 7;
|
||
|
|
|
||
|
|
// 2. Calculate Tree Indent
|
||
|
|
if (pColumn->IsTreeColumn())
|
||
|
|
{
|
||
|
|
int nTreeDepth = pRow->GetTreeDepth() - pRow->GetGroupLevel();
|
||
|
|
if (nTreeDepth > 0)
|
||
|
|
nTreeDepth++;
|
||
|
|
nWidth += GetIndent(nTreeDepth);
|
||
|
|
|
||
|
|
if (sizeBitmap.cx == 0 && sizeBitmap.cy == 0)
|
||
|
|
{
|
||
|
|
CRect rcBmp(0, 0, 100, 100);
|
||
|
|
sizeBitmap = pPaintManager->DrawCollapsedBitmap(NULL, pRow, rcBmp);
|
||
|
|
}
|
||
|
|
|
||
|
|
nWidth += sizeBitmap.cx + 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// 3. Calculate item Icon
|
||
|
|
int nIcon = pMetrics->nItemIcon;
|
||
|
|
nIcon = (nIcon != XTP_REPORT_NOICON) ? nIcon : pItem->GetIconIndex();
|
||
|
|
if (nIcon != XTP_REPORT_NOICON)
|
||
|
|
{
|
||
|
|
CXTPImageManagerIcon* pIcon = GetImageManager()->GetImage(nIcon, 0);
|
||
|
|
if (pIcon)
|
||
|
|
nWidth += pIcon->GetWidth() + 4;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// 4. Calculate item Controls
|
||
|
|
if (pItem->m_pItemControls)
|
||
|
|
{
|
||
|
|
int nControlsCount = pItem->m_pItemControls->GetSize();
|
||
|
|
for (int k = 0; k < nControlsCount; k++)
|
||
|
|
{
|
||
|
|
CXTPReportRecordItemControl* pCtrl = pItem->m_pItemControls->GetAt(k);
|
||
|
|
int nControlWidth = 0;
|
||
|
|
if (pCtrl)
|
||
|
|
nControlWidth = pCtrl->GetSize().cx;
|
||
|
|
if(nControlWidth < 0)
|
||
|
|
nControlWidth = 20;
|
||
|
|
|
||
|
|
nWidth += nControlWidth;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
nMaxWidth = max(nMaxWidth, nWidth);
|
||
|
|
}
|
||
|
|
|
||
|
|
CMDTARGET_RELEASE(pMetrics);
|
||
|
|
|
||
|
|
return nMaxWidth;
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::IsEditMode()
|
||
|
|
{
|
||
|
|
CXTPReportInplaceEdit* pEdit = GetInplaceEdit();
|
||
|
|
|
||
|
|
BOOL bEditMode = pEdit && pEdit->GetSafeHwnd() && pEdit->IsWindowVisible();
|
||
|
|
bEditMode |= GetInplaceList() && GetInplaceList()->GetSafeHwnd() && GetInplaceList()->IsWindowVisible();
|
||
|
|
|
||
|
|
return bEditMode;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int CXTPReportControl::GetRowsHeight(CXTPReportRows* pRows, int nTotalWidth, int nMaxHeight)
|
||
|
|
{
|
||
|
|
int nRowsHeight = 0;
|
||
|
|
|
||
|
|
CWindowDC dc (this);
|
||
|
|
|
||
|
|
for(int i = 0; i < pRows->GetCount(); ++i)
|
||
|
|
{
|
||
|
|
nRowsHeight += GetPaintManager()->GetRowHeight(&dc, pRows->GetAt(i), nTotalWidth);
|
||
|
|
|
||
|
|
if (nMaxHeight >= 0 && nRowsHeight > nMaxHeight)
|
||
|
|
return nRowsHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
return nRowsHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::GetHeaderRowsDividerHeight()
|
||
|
|
{
|
||
|
|
return GetPaintManager()->GetHeaderRowsDividerHeight();
|
||
|
|
}
|
||
|
|
|
||
|
|
int CXTPReportControl::GetFooterRowsDividerHeight()
|
||
|
|
{
|
||
|
|
return GetPaintManager()->GetFooterRowsDividerHeight();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::DrawDefaultGrid(CDC* pDC, CRect rcClient, int nRowHeight, int nLeftOffset)
|
||
|
|
{
|
||
|
|
if (nRowHeight <= 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
// int y = rcClient.top;
|
||
|
|
int nFreezeCols = m_nFreezeColumnsCount;
|
||
|
|
CRect rcClipBox = GetReportRectangle();
|
||
|
|
|
||
|
|
CRect rcRow;
|
||
|
|
rcRow = rcClient;
|
||
|
|
rcRow.left -= nLeftOffset;
|
||
|
|
rcRow.right -= nLeftOffset;
|
||
|
|
rcRow.bottom = rcClient.top + nRowHeight;
|
||
|
|
|
||
|
|
int nIndentWidth = GetHeaderIndent();
|
||
|
|
CXTPReportPaintManager* pPaintManager = GetPaintManager();
|
||
|
|
|
||
|
|
CXTPReportColumns arrVisibleColumns(this);
|
||
|
|
GetColumns()->GetVisibleColumns(arrVisibleColumns);
|
||
|
|
int nVisColCount = arrVisibleColumns.GetCount();
|
||
|
|
nFreezeCols = min(nFreezeCols, nVisColCount);
|
||
|
|
|
||
|
|
// fill the empty space
|
||
|
|
while(rcRow.top < rcClient.bottom)
|
||
|
|
{
|
||
|
|
CRect rcItem(rcRow.left, rcRow.top, rcRow.right, rcRow.bottom);
|
||
|
|
|
||
|
|
CRect rcIndent(nFreezeCols ? rcRow : rcRow); /////////////////////
|
||
|
|
rcIndent.right = rcIndent.left + nIndentWidth;
|
||
|
|
|
||
|
|
int xMinCol_0 = rcRow.left + nIndentWidth;
|
||
|
|
|
||
|
|
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)
|
||
|
|
{
|
||
|
|
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)
|
||
|
|
{
|
||
|
|
CRect rcFreeze(rcItem);
|
||
|
|
rcFreeze.top +=1;
|
||
|
|
pDC->FillSolidRect(rcFreeze, pPaintManager->GetControlBackColor(this));
|
||
|
|
}
|
||
|
|
|
||
|
|
CRect rcGridItem(rcItem);
|
||
|
|
rcGridItem.left--;
|
||
|
|
|
||
|
|
pPaintManager->DrawGrid(pDC, FALSE, rcGridItem);
|
||
|
|
pPaintManager->DrawGrid(pDC, TRUE, rcGridItem);
|
||
|
|
|
||
|
|
if (nColIdx == nFreezeCols - 1)
|
||
|
|
pPaintManager->DrawFreezeColsDivider(pDC, rcGridItem, this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nIndentWidth > 0)
|
||
|
|
{
|
||
|
|
// draw indent column
|
||
|
|
pPaintManager->FillIndent(pDC, rcIndent);
|
||
|
|
}
|
||
|
|
|
||
|
|
rcRow.top += nRowHeight;
|
||
|
|
rcRow.bottom += nRowHeight;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::PreTranslateMessage(MSG* pMsg)
|
||
|
|
{
|
||
|
|
if (pMsg->message == WM_KEYDOWN)
|
||
|
|
{
|
||
|
|
if (!OnPreviewKeyDown((UINT&)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam)) )
|
||
|
|
{
|
||
|
|
TRACE(_T("ReportControl, PreTranslateMessagem-OnPreviewKeyDown('%d') = CANCEL \n"), pMsg->wParam);
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return CWnd::PreTranslateMessage(pMsg);
|
||
|
|
}
|
||
|
|
|
||
|
|
BOOL CXTPReportControl::OnConstraintSelecting(CXTPReportRow* pRow, CXTPReportRecordItem* pItem, CXTPReportColumn* pColumn,
|
||
|
|
CXTPReportRecordItemConstraint* pConstraint)
|
||
|
|
{
|
||
|
|
XTP_NM_REPORTCONSTRAINTSELECTING nmConstraint;
|
||
|
|
::ZeroMemory(&nmConstraint, sizeof(nmConstraint));
|
||
|
|
|
||
|
|
nmConstraint.pRow = pRow;
|
||
|
|
nmConstraint.pColumn = pColumn;
|
||
|
|
nmConstraint.pItem = pItem;
|
||
|
|
nmConstraint.pConstraint = pConstraint;
|
||
|
|
|
||
|
|
LRESULT lResult = SendNotifyMessage(XTP_NM_REPORT_CONSTRAINT_SELECTING, (NMHDR*)&nmConstraint);
|
||
|
|
|
||
|
|
return lResult != 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
const XTP_NM_REPORTTOOLTIPINFO& CXTPReportControl::OnGetToolTipInfo(CXTPReportRow* pRow, CXTPReportRecordItem* pItem, CString& rstrToolTipText)
|
||
|
|
{
|
||
|
|
::ZeroMemory(m_pCachedToolTipInfo, sizeof(XTP_NM_REPORTTOOLTIPINFO));
|
||
|
|
|
||
|
|
m_pCachedToolTipInfo->pRow = pRow;
|
||
|
|
m_pCachedToolTipInfo->pItem = pItem;
|
||
|
|
m_pCachedToolTipInfo->pstrText = &rstrToolTipText;
|
||
|
|
|
||
|
|
SendNotifyMessage(XTP_NM_REPORT_GETTOOLTIPINFO, (NMHDR*)m_pCachedToolTipInfo);
|
||
|
|
|
||
|
|
return *m_pCachedToolTipInfo;
|
||
|
|
}
|
||
|
|
|
||
|
|
CRect CXTPReportControl::GetElementRect(int nElement) const
|
||
|
|
{
|
||
|
|
switch(nElement)
|
||
|
|
{
|
||
|
|
case xtpReportElementRectGroupByArea : return m_rcGroupByArea; break;
|
||
|
|
case xtpReportElementRectHeaderArea : return m_rcHeaderArea; break;
|
||
|
|
case xtpReportElementRectFooterArea : return m_rcFooterArea; break;
|
||
|
|
case xtpReportElementRectHeaderRecordsArea : return m_rcHeaderRecordsArea; break;
|
||
|
|
case xtpReportElementRectFooterRecordsArea : return m_rcFooterRecordsArea; break;
|
||
|
|
case xtpReportElementRectHeaderRecordsDividerArea : return m_rcHeaderRecordsDividerArea; break;
|
||
|
|
case xtpReportElementRectFooterRecordsDividerArea : return m_rcFooterRecordsDividerArea; break;
|
||
|
|
default : return m_rcReportArea; break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CXTPReportControl::EnableMarkup(BOOL bEnable)
|
||
|
|
{
|
||
|
|
m_pRecords->EnableMarkup(bEnable);
|
||
|
|
}
|
||
|
|
|
||
|
|
CXTPMarkupContext* CXTPReportControl::GetMarkupContext() const
|
||
|
|
{
|
||
|
|
return m_pRecords->GetMarkupContext();
|
||
|
|
}
|