XTPReportControl.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:134k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTPReportControl.cpp : implementation of the CXTPReportControl class.
  2. //
  3. // This file is a part of the XTREME REPORTCONTROL MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Resource.h"
  22. #include "Common/XTPDrawHelpers.h"
  23. #include "Common/XTPSystemHelpers.h"
  24. #include "Common/XTPImageManager.h"
  25. #include "Common/XTPVC80Helpers.h"
  26. #include "Common/XTPVC50Helpers.h"
  27. #include "Common/XTPPropExchange.h"
  28. #include "Common/XTPToolTipContext.h"
  29. #include "Common/XTPResourceManager.h"
  30. #include "XTPReportRecordItem.h"
  31. #include "XTPReportRecordItemText.h"
  32. #include "XTPReportRecord.h"
  33. #include "XTPReportRecords.h"
  34. #include "XTPReportHeader.h"
  35. #include "XTPReportColumn.h"
  36. #include "XTPReportColumns.h"
  37. #include "XTPReportRow.h"
  38. #include "XTPReportRows.h"
  39. #include "XTPReportControl.h"
  40. #include "XTPReportPaintManager.h"
  41. #include "XTPReportNavigator.h"
  42. #include "XTPReportFilterEditControl.h"
  43. #include "XTPReportSubListControl.h"
  44. #include "XTPReportGroupRow.h"
  45. #include "XTPReportInplaceControls.h"
  46. #include <locale.h>
  47. #ifdef _DEBUG
  48. #define new DEBUG_NEW
  49. #undef THIS_FILE
  50. static char THIS_FILE[] = __FILE__;
  51. #endif
  52. #define XTP_REPORT_HSCROLL_STEP 7
  53. #define XTP_REPORT_AUTO_SCROLL_TIMER_ID 7
  54. #define XTP_REPORT_AUTO_SCROLL_TIMER_RESOLUTION_MS  200
  55. #define XTP_REPORT_CB_RECORDS_DATA_VER 1
  56. #define ASSERT_DBG_REMOVE_RECORD_EX
  57. //#define XTP_DBG_REMOVE_RECORD_EX_ASSERT ASSERT
  58. //////////////////////////////////////////////////////////////////////////
  59. XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportDataAllocator, FALSE)
  60. XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportRowAllocator, FALSE)
  61. // to allocate in app default heap
  62. XTP_IMPLEMENT_HEAP_ALLOCATOR(CXTPReportAllocatorDefault, FALSE)
  63. class CXTPReportRow_Batch : public CXTPBatchAllocObjT<CXTPReportRow, CXTPReportRow_BatchData> {};
  64. class CXTPReportGroupRow_Batch : public CXTPBatchAllocObjT<CXTPReportGroupRow, CXTPReportGroupRow_BatchData> {};
  65. XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CXTPReportRow_BatchData, CXTPReportRow_Batch, FALSE)
  66. XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CXTPReportGroupRow_BatchData, CXTPReportGroupRow_Batch, FALSE)
  67. //===========================================================================
  68. BOOL CXTPReportControl::UseReportCustomHeap()
  69. {
  70. ASSERT(CXTPReportDataAllocator::ms_dwRefs == 0 || CXTPReportDataAllocator::ms_bUseCustomHeap);
  71. ASSERT(CXTPReportRowAllocator::ms_dwRefs == 0 || CXTPReportRowAllocator::ms_bUseCustomHeap);
  72. if (CXTPReportDataAllocator::ms_dwRefs == 0)
  73. CXTPReportDataAllocator::ms_bUseCustomHeap = TRUE;
  74. if (CXTPReportRowAllocator::ms_dwRefs == 0)
  75. CXTPReportRowAllocator::ms_bUseCustomHeap = TRUE;
  76. return CXTPReportDataAllocator::ms_bUseCustomHeap &&
  77. CXTPReportRowAllocator::ms_bUseCustomHeap;
  78. }
  79. BOOL CXTPReportControl::UseRowBatchAllocation()
  80. {
  81. ASSERT(CXTPReportRow_BatchData::IsDataEmpty() || CXTPReportRow_BatchData::m_bBatchAllocationEnabled);
  82. ASSERT(CXTPReportGroupRow_BatchData::IsDataEmpty() || CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled);
  83. if (CXTPReportRow_BatchData::IsDataEmpty())
  84. CXTPReportRow_BatchData::m_bBatchAllocationEnabled = TRUE;
  85. if (CXTPReportGroupRow_BatchData::IsDataEmpty())
  86. CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled = TRUE;
  87. return CXTPReportRow_BatchData::m_bBatchAllocationEnabled &&
  88. CXTPReportGroupRow_BatchData::m_bBatchAllocationEnabled;
  89. }
  90. void CXTPReportControl::FreeRowBatchExtraData()
  91. {
  92. CXTPReportRow_Batch::FreeExtraData();
  93. CXTPReportGroupRow_Batch::FreeExtraData();
  94. }
  95. //////////////////////////////////////////////////////////////////////////
  96. BOOL CXTPReportControlLocale::s_bUseResourceFileLocale = FALSE;
  97. CArray<CXTPReportControlLocale::XTP_TIMESPEC, CXTPReportControlLocale::XTP_TIMESPEC&>
  98. CXTPReportControlLocale::s_arMappedSpecs;
  99. //===========================================================================
  100. BOOL CXTPReportControlLocale::IsUseResourceFileLocale()
  101. {
  102. return s_bUseResourceFileLocale;
  103. }
  104. void CXTPReportControlLocale::SetUseResourceFileLocale(BOOL bUseResourceFileLocale)
  105. {
  106. s_bUseResourceFileLocale = bUseResourceFileLocale;
  107. }
  108. LCID CXTPReportControlLocale::GetActiveLCID()
  109. {
  110. LCID lcidCurr = LOCALE_USER_DEFAULT;
  111. if (s_bUseResourceFileLocale)
  112. lcidCurr = MAKELCID(XTPResourceManager()->GetResourcesLangID(), SORT_DEFAULT);
  113. return lcidCurr;
  114. }
  115. BOOL AFX_CDECL CXTPReportControlLocale::VariantChangeTypeEx(VARIANT& rVarValue, VARTYPE vartype, BOOL bThrowError)
  116. {
  117. if (vartype != rVarValue.vt)
  118. {
  119. LCID lcID = GetActiveLCID();
  120. HRESULT hr = ::VariantChangeTypeEx(&rVarValue, &rVarValue, lcID, 0, vartype);
  121. if (bThrowError && FAILED(hr))
  122. {
  123. if (hr == E_OUTOFMEMORY)
  124. AfxThrowMemoryException();
  125. else
  126. AfxThrowOleException(hr);
  127. }
  128. return SUCCEEDED(hr);
  129. }
  130. return TRUE;
  131. }
  132. CString AFX_CDECL CXTPReportControlLocale::FormatDateTime(const COleDateTime& dt, LPCTSTR lpcszFormatString)
  133. {
  134. return _FormatDateTime(dt, lpcszFormatString, GetActiveLCID());
  135. }
  136. CString CXTPReportControlLocale::_FormatDateTime(const COleDateTime& dt, LPCTSTR lpcszFormatString, LCID lcLocaleID)
  137. {
  138. if (dt.GetStatus() != COleDateTime::valid)
  139. {
  140. ASSERT(dt.GetStatus() == COleDateTime::null);
  141. return _T("");
  142. }
  143. CString strDT = lpcszFormatString;
  144. SYSTEMTIME sysTime;
  145. if (!GETASSYSTEMTIME_DT(dt, sysTime))
  146. {
  147. ASSERT(FALSE);
  148. return _T("");
  149. }
  150. //  %% Percent sign
  151. REPLACE_S(strDT, _T("%%"), _T("x1"));
  152. _ProcessMappedSpecs(strDT, &sysTime, lcLocaleID);
  153. _ProcessDateTimeSpecs(strDT, &sysTime, lcLocaleID);
  154. // All locale dependent specifiers already processed
  155. _ProcessOtherSpecs(strDT, dt);
  156. REPLACE_S(strDT, _T("x1"), _T("%"));
  157. return strDT;
  158. }
  159. void CXTPReportControlLocale::_ProcessMappedSpecs(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
  160. {
  161. _InitMappedSpecs();
  162. const int cnBufferSize = 96;
  163. TCHAR szBuffer[cnBufferSize];
  164. int nCount = (int)s_arMappedSpecs.GetSize();
  165. for (int i = 0; i < nCount; i++)
  166. {
  167. const XTP_TIMESPEC& specI = s_arMappedSpecs.ElementAt(i);
  168. if (FIND_S(rstrFormat, specI.pcszSpec, 0) < 0)
  169. continue;
  170. ::ZeroMemory(szBuffer, sizeof(szBuffer));
  171. int nResult;
  172. if (specI.bTime)
  173. {
  174. nResult = ::GetTimeFormat(lcLocaleID, 0, pST, specI.pcszFormat, szBuffer, cnBufferSize);
  175. }
  176. else
  177. {
  178. nResult = ::GetDateFormat(lcLocaleID, 0, pST, specI.pcszFormat, szBuffer, cnBufferSize);
  179. }
  180. ASSERT(nResult);
  181. if (nResult)
  182. {
  183. REPLACE_S(rstrFormat, specI.pcszSpec, szBuffer);
  184. }
  185. }
  186. }
  187. void CXTPReportControlLocale::_ProcessDateTimeSpecs(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
  188. {
  189. //  %c  Date and time representation appropriate for locale
  190. //  %#c Long date and time representation
  191. //  %x Date representation for current locale
  192. //  %#x Long date representation for current locale
  193. //  %X Time representation for current locale
  194. REPLACE_S(rstrFormat, _T("%c"), _T("%x %X"));
  195. REPLACE_S(rstrFormat, _T("%#c"), _T("%#x %X"));
  196. __ProcessDate_x(rstrFormat, pST, lcLocaleID);
  197. __ProcessTime_X(rstrFormat, pST, lcLocaleID);
  198. }
  199. void CXTPReportControlLocale::__ProcessDate_x(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
  200. {
  201. const int cnBufferSize = 96;
  202. TCHAR szBuffer[cnBufferSize];
  203. //  %x Date representation for current locale
  204. //  %#x Long date representation for current locale
  205. TCHAR* arSpec2[2] = {_T("%x"), _T("%#x")};
  206. for (int i = 0; i < 2; i++)
  207. {
  208. if (FIND_S(rstrFormat, arSpec2[i], 0) >= 0)
  209. {
  210. ::ZeroMemory(szBuffer, sizeof(szBuffer));
  211. DWORD dwFlags = (i == 0) ? DATE_SHORTDATE : DATE_LONGDATE;
  212. int nRes = ::GetDateFormat(lcLocaleID, dwFlags, pST, NULL, szBuffer, cnBufferSize);
  213. ASSERT(nRes);
  214. REPLACE_S(rstrFormat, arSpec2[i], szBuffer);
  215. }
  216. }
  217. }
  218. void CXTPReportControlLocale::__ProcessTime_X(CString& rstrFormat, const SYSTEMTIME* pST, LCID lcLocaleID)
  219. {
  220. if (FIND_S(rstrFormat, _T("%X"), 0) >= 0)
  221. {
  222. const int cnBufferSize = 96;
  223. TCHAR szBuffer[cnBufferSize];
  224. ::ZeroMemory(szBuffer, sizeof(szBuffer));
  225. int nRes = ::GetTimeFormat(lcLocaleID, 0, pST, NULL, szBuffer, cnBufferSize);
  226. ASSERT(nRes);
  227. REPLACE_S(rstrFormat, _T("%X"), szBuffer);
  228. }
  229. }
  230. void CXTPReportControlLocale::_ProcessOtherSpecs(CString& rstrFormat, const COleDateTime& dt)
  231. {
  232. //  %j Day of year as decimal number (001 - 366)
  233. //  %w Weekday as decimal number (0 - 6; Sunday is 0)
  234. //  %U Week of year as decimal number, with Sunday as first day of week (00 - 53)
  235. //  %W Week of year as decimal number, with Monday as first day of week (00 - 53)
  236. //  %z, %Z  Either the time-zone name or time zone abbreviation, depending on registry settings; no characters if time zone is unknown
  237. static LPCTSTR arszSpecs[] = {  _T("%j"), _T("%#j"),
  238. _T("%w"), _T("%#w"),
  239. _T("%U"), _T("%#U"),
  240. _T("%W"), _T("%#W"),
  241. _T("%z"), _T("%Z") };
  242. int nCount = _countof(arszSpecs);
  243. for (int i = 0; i < nCount; i++)
  244. {
  245. if (FIND_S(rstrFormat, arszSpecs[i], 0) < 0)
  246. continue;
  247. CString str = dt.Format(arszSpecs[i]);
  248. REPLACE_S(rstrFormat, arszSpecs[i], str);
  249. }
  250. }
  251. void CXTPReportControlLocale::_InitMappedSpecs()
  252. {
  253. if (s_arMappedSpecs.GetSize())
  254. return;
  255. // date
  256. _AddsMappedSpec(_T("%a"), _T("ddd"),    FALSE);
  257. _AddsMappedSpec(_T("%A"), _T("dddd"),   FALSE);
  258. _AddsMappedSpec(_T("%b"), _T("MMM"),    FALSE);
  259. _AddsMappedSpec(_T("%B"), _T("MMMM"),   FALSE);
  260. _AddsMappedSpec(_T("%d"),  _T("dd"),    FALSE);
  261. _AddsMappedSpec(_T("%#d"), _T("d"),     FALSE);
  262. _AddsMappedSpec(_T("%m"),  _T("MM"),    FALSE);
  263. _AddsMappedSpec(_T("%#m"), _T("M"),     FALSE);
  264. _AddsMappedSpec(_T("%y"),  _T("yy"),    FALSE);
  265. _AddsMappedSpec(_T("%#y"), _T("y"),     FALSE);
  266. _AddsMappedSpec(_T("%Y"), _T("yyyy"),   FALSE);
  267. // time
  268. _AddsMappedSpec(_T("%H"),  _T("HH"),    TRUE);
  269. _AddsMappedSpec(_T("%#H"), _T("H"),     TRUE);
  270. _AddsMappedSpec(_T("%I"),  _T("hh"),    TRUE);
  271. _AddsMappedSpec(_T("%#I"), _T("h"),     TRUE);
  272. _AddsMappedSpec(_T("%M"),  _T("mm"),    TRUE);
  273. _AddsMappedSpec(_T("%#M"), _T("m"),     TRUE);
  274. _AddsMappedSpec(_T("%S"),  _T("ss"),    TRUE);
  275. _AddsMappedSpec(_T("%#S"), _T("s"),     TRUE);
  276. _AddsMappedSpec(_T("%p"), _T("tt"),     TRUE);
  277. }
  278. void CXTPReportControlLocale::_AddsMappedSpec(LPCTSTR pcszSpec, LPCTSTR pcszFormat, BOOL bTime)
  279. {
  280. XTP_TIMESPEC tmpSpec = {pcszSpec, pcszFormat, bTime};
  281. s_arMappedSpecs.Add(tmpSpec);
  282. }
  283. //////////////////////////////////////////////////////////////////////////
  284. // CReportDropTarget
  285. class CXTPReportControl::CReportDropTarget : public COleDropTarget
  286. {
  287. public:
  288. virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  289. {
  290. CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
  291. if (!pReport)
  292. return DROPEFFECT_NONE;
  293. return pReport->OnDragOver(pDataObject, dwKeyState, point, 0);
  294. }
  295. virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
  296. {
  297. CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
  298. if (!pReport)
  299. return DROPEFFECT_NONE;
  300. return pReport->OnDragOver(pDataObject, dwKeyState, point, 2);
  301. }
  302. virtual void OnDragLeave(CWnd* pWnd)
  303. {
  304. CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
  305. if (pReport)
  306. {
  307. pReport->OnDragOver(NULL, 0, CPoint(-1, -1), 1);
  308. }
  309. }
  310. virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
  311. DROPEFFECT dropEffect, CPoint point)
  312. {
  313. CXTPReportControl* pReport = DYNAMIC_DOWNCAST(CXTPReportControl, pWnd);
  314. if (pReport)
  315. {
  316. return pReport->OnDrop(pDataObject, dropEffect, point);
  317. }
  318. return FALSE;
  319. }
  320. };
  321. /////////////////////////////////////////////////////////////////////////////
  322. void XTPStrSplit(LPCTSTR pcszString, LPCTSTR pcszSeparator, CStringArray& rarStrings)
  323. {
  324. rarStrings.RemoveAll();
  325. int nSeparatorLen = (int)_tcslen(pcszSeparator);
  326. CString strString(pcszString);
  327. CString strItem;
  328. int nIndex_start = 0;
  329. // parse data
  330. BOOL bBreak = FALSE;
  331. do
  332. {
  333. int nIndex = FIND_S(strString, pcszSeparator, nIndex_start);
  334. if (nIndex >= 0)
  335. {
  336. strItem = strString.Mid(nIndex_start, nIndex - nIndex_start);
  337. }
  338. else
  339. {
  340. strItem = strString.Mid(nIndex_start);
  341. bBreak = TRUE;
  342. }
  343. //---------------------------------------
  344. rarStrings.Add(strItem);
  345. nIndex_start = nIndex + nSeparatorLen;
  346. }
  347. while (!bBreak);
  348. }
  349. CString XTPStrMake(const CStringArray& arStrings, LPCTSTR pcszSeparator)
  350. {
  351. CString strString;
  352. int nCount = (int)arStrings.GetSize();
  353. for (int i = 0; i < nCount; i++)
  354. {
  355. if (i > 0)
  356. {
  357. strString += pcszSeparator;
  358. }
  359. strString += arStrings[i];
  360. }
  361. return strString;
  362. }
  363. // CXTPReportControl
  364. IMPLEMENT_DYNCREATE(CXTPReportControl, CWnd)
  365. BEGIN_MESSAGE_MAP(CXTPReportControl, CWnd)
  366. //{{AFX_MSG_MAP(CXTPReportControl)
  367. ON_WM_PAINT()
  368. ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
  369. ON_WM_ERASEBKGND()
  370. ON_WM_SIZE()
  371. ON_WM_LBUTTONDOWN()
  372. ON_WM_LBUTTONUP()
  373. ON_WM_RBUTTONDOWN()
  374. ON_WM_RBUTTONUP()
  375. ON_WM_CONTEXTMENU()
  376. ON_WM_MOUSEMOVE()
  377. ON_WM_SETCURSOR()
  378. ON_WM_KEYDOWN()
  379. ON_WM_VSCROLL()
  380. ON_WM_HSCROLL()
  381. ON_WM_MOUSEWHEEL()
  382. ON_WM_SYSKEYDOWN()
  383. ON_WM_CAPTURECHANGED()
  384. ON_WM_SYSCOLORCHANGE()
  385. ON_WM_SETFOCUS()
  386. ON_WM_KILLFOCUS()
  387. ON_WM_KEYUP()
  388. ON_WM_SYSKEYUP()
  389. ON_WM_LBUTTONDBLCLK()
  390. ON_WM_GETDLGCODE()
  391. ON_WM_CHAR()
  392. ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave)
  393. ON_WM_STYLECHANGED()
  394. ON_WM_ENABLE()
  395. ON_WM_TIMER()
  396. //}}AFX_MSG_MAP
  397. END_MESSAGE_MAP()
  398. CXTPReportControl::CXTPReportControl()
  399. {
  400. RegisterWindowClass();
  401. m_nLockUpdateCount = 0;
  402. m_nRowsPerWheel = GetMouseScrollLines();
  403. m_pRows = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
  404. m_pPlainTree = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
  405. m_pRecords = new CXTPHeapObjectT<CXTPReportRecords, CXTPReportAllocatorDefault>;
  406. m_pColumns = new CXTPReportColumns(this);
  407. m_pReportHeader = new CXTPReportHeader(this, m_pColumns);
  408. m_pPaintManager = new CXTPReportPaintManager();
  409. m_pNavigator = new CXTPReportNavigator(this);
  410. m_nTopRow = 0;
  411. m_nFocusedRow = -1;
  412. m_nFocusedHeaderRow = -1;
  413. m_nFocusedFooterRow = -1;
  414. m_mouseMode = xtpReportMouseNothing;
  415. m_pSelectedRows = new CXTPReportSelectedRows(this);
  416. m_bChanged = TRUE;
  417. m_bRefreshIndexes = FALSE;
  418. m_bGroupByEnabled = FALSE;
  419. m_bHeaderVisible = TRUE;
  420. m_bFooterVisible = FALSE;
  421. m_bHeaderRecordsVisible = FALSE;
  422. m_bFooterRecordsVisible = FALSE;
  423. m_bMultipleSelection = TRUE;
  424. m_bMultiSelectionMode = FALSE;
  425. m_bShowTooltips = TRUE;
  426. m_bSkipGroupsFocus = TRUE;
  427. m_pImageManager = new CXTPImageManager();
  428. m_pFocusedColumn = NULL;
  429. m_pActiveItem = NULL;
  430. m_bFocusSubItems = FALSE;
  431. m_bEditOnClick = TRUE;
  432. m_bAllowEdit = FALSE;
  433. m_bHeaderAllowEdit = FALSE;
  434. m_bFooterAllowEdit = FALSE;
  435. m_bSelectionEnable = TRUE;
  436. m_bRowFocusVisible = TRUE;
  437. m_bAutoCheckItems = TRUE;
  438. m_pInplaceEdit = new CXTPReportInplaceEdit();
  439. m_pInplaceButtons = new CXTPReportInplaceButtons();
  440. m_pInplaceList = new CXTPReportInplaceList();
  441. m_rcGroupByArea.SetRectEmpty();
  442. m_rcHeaderArea.SetRectEmpty();
  443. m_rcReportArea.SetRectEmpty();
  444. m_rcFooterArea.SetRectEmpty();
  445. m_nFreezeColumnsCount = 0;
  446. m_nDisableReorderColumnsCount = 0;
  447. m_nLeftOffset = 0;
  448. m_pHotRow = 0;
  449. m_nOLEDropMode = 0;
  450. m_bFullColumnScrolling = FALSE;
  451. m_nHScrollStep = XTP_REPORT_HSCROLL_STEP;
  452. m_bVScrollBarVisible = FALSE;
  453. m_bHScrollBarVisible = FALSE;
  454. m_bPrepareDrag = FALSE;
  455. m_pointDrag = CPoint(0, 0);
  456. m_pToolTipContext = new CXTPToolTipContext;
  457. m_pCachedToolTipInfo = new XTP_NM_REPORTTOOLTIPINFO;
  458. m_nPopulatedRecordsCount = 0;
  459. m_cfReport = NULL;
  460. m_pDropTarget = new CReportDropTarget;
  461. m_bDragMode = FALSE;
  462. m_dwDragDropFlags = 0;
  463. m_nDropPos = -1;
  464. m_pDropRecords = NULL;
  465. m_pSelectOnUpRow = NULL;
  466. m_bOnSizeRunning = FALSE;
  467. m_uAutoScrollTimerID = 0;
  468. m_bSortRecordChilds = FALSE;
  469. m_pRowsCompareFunc = NULL;
  470. m_ptrVirtualEditingRow = NULL;
  471. m_bFilterHiddenColumns = FALSE;
  472. m_pHeaderRecords = new CXTPHeapObjectT<CXTPReportRecords, CXTPReportAllocatorDefault>;
  473. m_pFooterRecords = new CXTPHeapObjectT<CXTPReportRecords, CXTPReportAllocatorDefault>;
  474. m_pHeaderRows = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
  475. m_pFooterRows = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
  476. m_hbmpWatermark = NULL;
  477. m_WatermarkTransparency = 100;
  478. m_WatermarkAlignment = xtpReportWatermarkStretch;
  479. m_bHeaderRowsAllowAccess = TRUE;
  480. m_bFooterRowsAllowAccess = TRUE;
  481. m_bHeaderRowsSelectionEnable = TRUE;
  482. m_bFooterRowsSelectionEnable = TRUE;
  483. m_nEnsureVisibleRowIdx = m_nEnsureVisibleColumnIdx = -1;
  484. }
  485. BOOL CXTPReportControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
  486. {
  487. return XTPDrawHelpers()->RegisterWndClass(hInstance, XTPREPORTCTRL_CLASSNAME, CS_DBLCLKS);
  488. }
  489. CXTPReportControl::~CXTPReportControl()
  490. {
  491. if (::IsWindow(m_wndTip.GetSafeHwnd()))
  492. m_wndTip.DestroyWindow();
  493. EditItem(0);
  494. //m_arrScreenRows.Clear();
  495. ResetContent(FALSE);
  496. CMDTARGET_RELEASE(m_pRows);
  497. CMDTARGET_RELEASE(m_pPlainTree);
  498. CMDTARGET_RELEASE(m_pSelectedRows);
  499. CMDTARGET_RELEASE(m_pRecords);
  500. CMDTARGET_RELEASE(m_pColumns);
  501. CMDTARGET_RELEASE(m_pPaintManager);
  502. CMDTARGET_RELEASE(m_pNavigator);
  503. CMDTARGET_RELEASE(m_pImageManager);
  504. CMDTARGET_RELEASE(m_pReportHeader);
  505. CMDTARGET_RELEASE(m_pToolTipContext);
  506. SAFE_DELETE(m_pCachedToolTipInfo);
  507. SAFE_DELETE(m_pInplaceEdit);
  508. SAFE_DELETE(m_pInplaceButtons);
  509. SAFE_DELETE(m_pInplaceList);
  510. CMDTARGET_RELEASE(m_pDropTarget);
  511. CMDTARGET_RELEASE(m_ptrVirtualEditingRow);
  512. CMDTARGET_RELEASE(m_pHeaderRecords);
  513. CMDTARGET_RELEASE(m_pFooterRecords);
  514. CMDTARGET_RELEASE(m_pHeaderRows);
  515. CMDTARGET_RELEASE(m_pFooterRows);
  516. CMDTARGET_RELEASE(m_pDropRecords);
  517. if(m_hbmpWatermark)
  518. ::DeleteObject(m_hbmpWatermark);
  519. }
  520. void CXTPReportControl::ResetContent(BOOL bUpdateControl)
  521. {
  522. EditItem(NULL);
  523. m_arrScreenRows.Clear();
  524. if (m_pRows) m_pRows->Clear();
  525. if (m_pPlainTree) m_pPlainTree->Clear();
  526. if (m_pSelectedRows) m_pSelectedRows->Clear();
  527. //  m_pHeaderRows->Clear();
  528. //  m_pFooterRows->Clear();
  529. //  m_pHeaderRecords->RemoveAll();
  530. //  m_pFooterRecords->RemoveAll();
  531. if (m_pRecords) m_pRecords->RemoveAll();
  532. if (bUpdateControl)
  533. {
  534. AdjustIndentation();
  535. AdjustScrollBars();
  536. RedrawControl();
  537. }
  538. }
  539. void CXTPReportControl::SetReportHeader(CXTPReportHeader* pReportHeader)
  540. {
  541. if (pReportHeader)
  542. {
  543. m_pReportHeader->InternalRelease();
  544. m_pReportHeader = pReportHeader;
  545. AdjustLayout();
  546. }
  547. }
  548. void CXTPReportControl::SetImageManager(CXTPImageManager* pImageManager)
  549. {
  550. if (pImageManager)
  551. {
  552. m_pImageManager->InternalRelease();
  553. m_pImageManager = pImageManager;
  554. }
  555. }
  556. void CXTPReportControl::SetImageList(CImageList* pImageList)
  557. {
  558. for (int i = 0; i < pImageList->GetImageCount(); i++)
  559. {
  560. HICON hIcon = pImageList->ExtractIcon(i);
  561. m_pImageManager->SetIcon(hIcon, i);
  562. DestroyIcon(hIcon);
  563. }
  564. }
  565. void CXTPReportControl::SetPaintManager(CXTPReportPaintManager* pPaintManager)
  566. {
  567. if (pPaintManager)
  568. {
  569. m_pPaintManager->InternalRelease();
  570. m_pPaintManager = pPaintManager;
  571. AdjustLayout();
  572. AdjustScrollBars();
  573. }
  574. }
  575. BOOL CXTPReportControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
  576. {
  577. if (!CWnd::Create(XTPREPORTCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext))
  578. return FALSE;
  579. return TRUE;
  580. }
  581. int CXTPReportControl::GetIndent(int nLevel) const
  582. {
  583. return max(0, (nLevel - 1) * m_pPaintManager->m_nTreeIndent);
  584. }
  585. void CXTPReportControl::SetTreeIndent(int nIndent)
  586. {
  587. m_pPaintManager->m_nTreeIndent = nIndent;
  588. }
  589. void CXTPReportControl::BeginUpdate()
  590. {
  591. m_nLockUpdateCount++;
  592. m_bRefreshIndexes = FALSE;
  593. }
  594. void CXTPReportControl::EndUpdate()
  595. {
  596. SetChanged();
  597. m_nLockUpdateCount--;
  598. if (m_nLockUpdateCount == 0)
  599. {
  600. if (m_bRefreshIndexes)
  601. {
  602. m_bRefreshIndexes = FALSE;
  603. _RefreshIndexes();
  604. }
  605. RedrawControl();
  606. }
  607. }
  608. void CXTPReportControl::RedrawControl()
  609. {
  610. SetChanged();
  611. if (m_nLockUpdateCount == 0 && GetSafeHwnd())
  612. {
  613. Invalidate(FALSE);
  614. }
  615. }
  616. void CXTPReportControl::UpdateSubList()
  617. {
  618. CXTPReportHeader* pHeader = GetReportHeader();
  619. if (pHeader && pHeader->m_pSubList &&
  620. (pHeader->m_pSubList->GetReportCtrl() == this))
  621. {
  622. pHeader->m_pSubList->UpdateList();
  623. }
  624. }
  625. void CXTPReportControl::_DoCollapse(CXTPReportRow* pRow)
  626. {
  627. int nIndex = pRow->GetIndex() + 1;
  628. int nCount = 0;
  629. while (nIndex < m_pRows->GetCount())
  630. {
  631. CXTPReportRow* pRowChild = m_pRows->GetAt(nIndex);
  632. if (!pRowChild->HasParent(pRow))
  633. break;
  634. pRowChild->m_bVisible = FALSE;
  635. pRowChild->m_nIndex = -1;
  636. m_pRows->RemoveAt(nIndex);
  637. nCount++;
  638. }
  639. if (nCount > 0)
  640. {
  641. m_pSelectedRows->_OnCollapsed(nIndex - 1, nCount);
  642. if (m_nFocusedRow >= nIndex)
  643. m_nFocusedRow = max(nIndex - 1, m_nFocusedRow - nCount);
  644. }
  645. }
  646. void CXTPReportControl::_DoExpand(CXTPReportRow* pRow)
  647. {
  648. int nIndex = pRow->m_nIndex;
  649. int nCount = _DoExpand(nIndex, pRow);
  650. if (nCount > 0)
  651. {
  652. m_pSelectedRows->_OnExpanded(nIndex, nCount);
  653. if (m_nFocusedRow > nIndex)
  654. m_nFocusedRow += nCount;
  655. }
  656. }
  657. int CXTPReportControl::_DoExpand(int nIndex, CXTPReportRow* pRow)
  658. {
  659. if (!pRow->HasChildren())
  660. return 0;
  661. int nStartIndex = nIndex;
  662. for (int i = 0; i < pRow->GetChilds()->GetCount(); i++)
  663. {
  664. CXTPReportRow* pRowChild = pRow->GetChilds()->GetAt(i);
  665. pRowChild->m_nRowLevel = pRow->m_nRowLevel + 1;
  666. pRowChild->m_nGroupLevel = pRow->m_nGroupLevel + (pRow->IsGroupRow() ? 1 : 0);
  667. nIndex += InsertRow(nIndex + 1, pRowChild);
  668. }
  669. return nIndex - nStartIndex;
  670. }
  671. void CXTPReportControl::RefreshIndexes(BOOL bAdjustLayout, BOOL bReverseOrder)
  672. {
  673. int nRowCount = m_pRows->GetCount();
  674. int nStartIdx = 0, nEndIdx = nRowCount, nStep = 1;
  675. if(bReverseOrder)
  676. {
  677. nStartIdx = nRowCount - 1;
  678. nEndIdx = nStep = -1;
  679. }
  680. for (int nIndex = nStartIdx; nIndex != nEndIdx; nIndex += nStep)
  681. {
  682. CXTPReportRow* pRow = m_pRows->GetAt(nIndex);
  683. BOOL bSelected = m_pSelectedRows->Contains(pRow);
  684. if(bSelected)
  685. m_pSelectedRows->Remove(pRow);
  686. pRow->m_nIndex = nIndex;
  687. ASSERT(pRow->m_bVisible);
  688. if(bSelected)
  689. m_pSelectedRows->Add(pRow);
  690. }
  691. if (bAdjustLayout)
  692. AdjustScrollBars();
  693. }
  694. void CXTPReportControl::_RefreshIndexes(BOOL bAdjustLayout, BOOL bReverseOrder)
  695. {
  696. if (m_nLockUpdateCount != 0)
  697. {
  698. m_bRefreshIndexes = TRUE;
  699. return;
  700. }
  701. RefreshIndexes(bAdjustLayout, bReverseOrder);
  702. }
  703. int CXTPReportControl::InsertRow(int nIndex, CXTPReportRow* pRow)
  704. {
  705. m_pRows->InsertAt(nIndex, pRow);
  706. pRow->InternalAddRef();
  707. pRow->m_bVisible = TRUE;
  708. int nRowsInserted = 1;
  709. if (pRow->IsExpanded() && pRow->HasChildren())
  710. {
  711. nRowsInserted += _DoExpand(nIndex, pRow);
  712. }
  713. return nRowsInserted;
  714. }
  715. void CXTPReportControl::BuildTree(CXTPReportRows* pTree, CXTPReportRow* pParentRow, CXTPReportRecords* pRecords)
  716. {
  717. ASSERT(pTree->GetCount() == 0);
  718. pTree->ReserveSize(pRecords->GetCount());
  719. for (int i = 0; i < pRecords->GetCount(); i++)
  720. {
  721. CXTPReportRecord* pRecord = pRecords->GetAt(i);
  722. // add record if all conditions are met
  723. if (pRecord->IsLocked() ||
  724. (pRecord->IsVisible() && !ApplyFilter(pRecord, GetFilterText(), IsPreviewMode())))
  725. {
  726. CXTPReportRow* pRow = CreateRow();
  727. pRow->InitRow(this, pRecord);
  728. pRow->m_pParentRow = pParentRow;
  729. pTree->Add(pRow);
  730. if (pRecord->HasChildren())
  731. {
  732. BuildTree(pRow->GetChilds(), pRow, pRecord->GetChilds());
  733. if (pRow->GetChilds() && IsSortRecordChilds())
  734. {
  735. SortRows(pRow->GetChilds());
  736. }
  737. }
  738. }
  739. }
  740. }
  741. void CXTPReportControl::SortTree(CXTPReportRows* pTree)
  742. {
  743. ASSERT(pTree);
  744. if (!pTree)
  745. return;
  746. SortRows(pTree);
  747. for (int i = 0; i < pTree->GetCount(); i++)
  748. {
  749. CXTPReportRow* pRow = pTree->GetAt(i);
  750. ASSERT(pRow);
  751. if (!pRow)
  752. continue;
  753. BOOL bRecordHasChildren = pRow->GetRecord() && pRow->GetRecord()->HasChildren();
  754. if (pRow->HasChildren() && pRow->GetChilds() &&
  755. (bRecordHasChildren && m_bSortRecordChilds || !bRecordHasChildren))
  756. {
  757. SortTree(pRow->GetChilds());
  758. }
  759. }
  760. pTree->RefreshChildIndices(FALSE);
  761. }
  762. void CXTPReportControl::ReSortRows()
  763. {
  764. if (IsVirtualMode())
  765. {
  766. Populate();
  767. return;
  768. }
  769. SortTree(m_pPlainTree);
  770. CXTPReportRecord* pFocusedRecord = GetFocusedRow() ? GetFocusedRow()->GetRecord() : NULL;
  771. m_pRows->Clear();
  772. m_arrScreenRows.Clear(FALSE);
  773. for (int nGroupRow = 0; nGroupRow < m_pPlainTree->GetCount(); nGroupRow++)
  774. {
  775. CXTPReportRow* pRow = m_pPlainTree->GetAt(nGroupRow);
  776. InsertRow(m_pRows->GetCount(), pRow);
  777. pRow->m_nChildIndex = nGroupRow;
  778. ASSERT(pRow->m_pParentRows == m_pPlainTree);
  779. }
  780. //-----------------------------------------------------------------------
  781. m_nFocusedRow = -1;
  782. // Update indexes on virtual rows
  783. int nRowCount = m_pRows->GetCount();
  784. for (int nRowIndex = 0; nRowIndex < nRowCount; nRowIndex++)
  785. {
  786. CXTPReportRow* pRow = m_pRows->GetAt(nRowIndex);
  787. if (pRow)
  788. {
  789. pRow->SetIndex(nRowIndex);
  790. pRow->m_bVisible = TRUE;
  791. if (pFocusedRecord && pRow->GetRecord() == pFocusedRecord)
  792. {
  793. m_nFocusedRow = pRow->GetIndex();
  794. if(IsSelectionEnabled())
  795. m_pSelectedRows->Select(pRow);
  796. }
  797. }
  798. }
  799. AdjustIndentation();
  800. AdjustLayout();
  801. RedrawControl();
  802. }
  803. CLIPFORMAT CXTPReportControl::EnableDragDrop(LPCTSTR lpszClipboardFormat, DWORD dwFlags)
  804. {
  805. if (m_dwDragDropFlags != 0)
  806. {
  807. if (m_pDropTarget)
  808. m_pDropTarget->Revoke();
  809. }
  810. m_dwDragDropFlags = dwFlags;
  811. m_cfReport = NULL;
  812. if (m_dwDragDropFlags != 0)
  813. {
  814. if (m_pDropTarget)
  815. {
  816. m_cfReport = (CLIPFORMAT)::RegisterClipboardFormat(lpszClipboardFormat);
  817. m_pDropTarget->Revoke(); // to ensure kill previous registration.
  818. m_pDropTarget->Register(this);
  819. }
  820. }
  821. return m_cfReport;
  822. }
  823. BOOL CXTPReportControl::ApplyFilter(CXTPReportRecord* pRecord, CString strFilterText, BOOL bIncludePreview)
  824. {
  825. // not filtered if filter text is empty
  826. if (!pRecord)
  827. return FALSE;
  828. if (pRecord->IsFiltered())
  829. return TRUE;
  830. if (strFilterText.IsEmpty())
  831. return FALSE;
  832. BOOL bFilterHidden = IsFilterHiddenColumns();
  833. // process each token in the filter string
  834. TCHAR szSeps[] = _T(" t");
  835. TCHAR *szToken, *lpszContext = 0;
  836. //int nCurPos = 0;
  837. szToken = STRTOK_S(strFilterText.GetBuffer(strFilterText.GetLength()), szSeps, &lpszContext);
  838. while (szToken != NULL)
  839. {
  840. CString strToken(szToken);
  841. strToken.MakeLower();
  842. BOOL bTokenFound = FALSE;
  843. // enumerate all visible columns
  844. int nColumnsCount = m_pColumns->GetCount();
  845. for (int nCol = 0; nCol < nColumnsCount; nCol++)
  846. {
  847. CXTPReportColumn* pCol = m_pColumns->GetAt(nCol);
  848. if (pCol && (pCol->IsVisible() || bFilterHidden) && pCol->IsFiltrable())
  849. {
  850. CXTPReportRecordItem* pItem = pRecord->GetItem(pCol);
  851. if (pItem)
  852. {
  853. CString sItemText = pItem->GetCaption(pCol);
  854. // case-insensitive search
  855. sItemText.MakeLower();
  856. bTokenFound = sItemText.Find(strToken) != -1;
  857. if (bTokenFound)
  858. {
  859. // stop search current token - passed
  860. break;
  861. }
  862. }
  863. }
  864. }
  865. // also check preview text
  866. if (bIncludePreview && !bTokenFound && pRecord->GetItemPreview())
  867. {
  868. CString sItemText = pRecord->GetItemPreview()->GetCaption(NULL);
  869. // case-insensitive search
  870. sItemText.MakeLower();
  871. bTokenFound = sItemText.Find(strToken) != -1;
  872. }
  873. // Token not found - filter this record
  874. if (!bTokenFound)
  875. {
  876. return TRUE;
  877. }
  878. // get next token
  879. szToken = STRTOK_S(NULL, szSeps, &lpszContext);
  880. }
  881. return FALSE;
  882. }
  883. void CXTPReportControl::Populate()
  884. {
  885. EditItem(NULL);
  886. BeginUpdate();
  887. m_nPopulatedRecordsCount = 0;
  888. // save focused items
  889. CXTPReportRecord* pFocusedRecord = GetFocusedRow() ? GetFocusedRow()->GetRecord() : NULL;
  890. m_pSelectedRows->Clear();
  891. m_nFocusedRow = -1;
  892. m_nFocusedHeaderRow = -1;
  893. m_nFocusedFooterRow = -1;
  894. m_pRows->Clear();
  895. m_pPlainTree->Clear();
  896. m_arrScreenRows.Clear(FALSE);
  897. m_pHeaderRows->Clear();
  898. m_pFooterRows->Clear();
  899. if (IsVirtualMode())
  900. {
  901. CXTPReportRow* pRow = CreateRow();
  902. pRow->InitRow(this, GetRecords()->m_pVirtualRecord);
  903. pRow->m_bVisible = TRUE;
  904. m_pRows->SetVirtualMode(pRow, GetRecords()->GetCount());
  905. m_nPopulatedRecordsCount = GetRecords()->GetCount();
  906. }
  907. else
  908. {
  909. BuildTree(m_pPlainTree, NULL, m_pRecords);
  910. m_nPopulatedRecordsCount = m_pPlainTree->GetCount();
  911. SortRows(m_pPlainTree);
  912. int nGroupRowsCount = 0;
  913. if (m_pColumns->GetGroupsOrder()->GetCount() > 0)
  914. {
  915. CXTPReportRows* pGroupTree = new CXTPHeapObjectT<CXTPReportRows, CXTPReportAllocatorDefault>;
  916. int nReserve = m_pRecords->GetCount() / (m_pColumns->GetGroupsOrder()->GetCount() + 1);
  917. nReserve = max(nReserve, 300);
  918. pGroupTree->ReserveSize(nReserve);
  919. CXTPReportGroupRow* pLastGroup = NULL;
  920. for (int nPlainRow = 0; nPlainRow < m_pPlainTree->GetCount(); nPlainRow++)
  921. {
  922. CXTPReportRow* pRow = m_pPlainTree->GetAt(nPlainRow);
  923. CXTPReportGroupRow* pGroupToAdd = NULL;
  924. for (int nColumn = 0; nColumn < m_pColumns->GetGroupsOrder()->GetCount(); nColumn++)
  925. {
  926. CXTPReportColumn* pColumn = m_pColumns->GetGroupsOrder()->GetAt(nColumn);
  927. CXTPReportRecordItem* pItem = pRow->GetRecord()->GetItem(pColumn);
  928. CString strGroup = pItem ? pItem->GetGroupCaption(pColumn) : _T("");
  929. if (pLastGroup && GetRecords()->Compare(pLastGroup->GetCaption(), strGroup) == 0)
  930. {
  931. pGroupToAdd = pLastGroup;
  932. if (pGroupToAdd->HasChildren())
  933. pLastGroup = (CXTPReportGroupRow*)pGroupToAdd->GetChilds()->GetAt(pGroupToAdd->GetChilds()->GetCount() - 1);
  934. }
  935. else
  936. {
  937. CXTPReportGroupRow* pGroup = CreateGroupRow();
  938. nGroupRowsCount++;
  939. pGroup->InitRow(this, NULL);
  940. pGroup->SetCaption(strGroup);
  941. if (pGroupToAdd)
  942. {
  943. pGroupToAdd->AddChild(pGroup);
  944. }
  945. else
  946. {
  947. pGroupTree->Add(pGroup);
  948. }
  949. pGroupToAdd = pGroup;
  950. pLastGroup = NULL;
  951. }
  952. }
  953. if (pGroupToAdd) pGroupToAdd->AddChild(pRow);
  954. pRow->InternalAddRef();
  955. pLastGroup = (CXTPReportGroupRow*)pGroupTree->GetAt(pGroupTree->GetCount() - 1);
  956. }
  957. m_pPlainTree->InternalRelease();
  958. m_pPlainTree = pGroupTree;
  959. }
  960. m_pRows->ReserveSize(m_pRecords->GetCount() + nGroupRowsCount + 10);
  961. for (int nGroupRow = 0; nGroupRow < m_pPlainTree->GetCount(); nGroupRow++)
  962. {
  963. CXTPReportRow* pRow = m_pPlainTree->GetAt(nGroupRow);
  964. InsertRow(m_pRows->GetCount(), pRow);
  965. pRow->m_nChildIndex = nGroupRow;
  966. ASSERT(pRow->m_pParentRows == m_pPlainTree);
  967. }
  968. m_nFocusedRow = -1;
  969. m_nFocusedHeaderRow = -1;
  970. m_nFocusedFooterRow = -1;
  971. // Update indexes on virtual rows
  972. int nRowCount = m_pRows->GetCount();
  973. for (int nRowIndex = 0; nRowIndex < nRowCount; nRowIndex++)
  974. {
  975. CXTPReportRow* pRow = m_pRows->GetAt(nRowIndex);
  976. if (pRow)
  977. {
  978. pRow->SetIndex(nRowIndex);
  979. pRow->m_bVisible = TRUE;
  980. if (pFocusedRecord && pRow->GetRecord() == pFocusedRecord)
  981. {
  982. m_nFocusedRow = pRow->GetIndex();
  983. if(IsSelectionEnabled())
  984. m_pSelectedRows->Select(pRow);
  985. }
  986. }
  987. }
  988. int i;
  989. // header record rows
  990. for (i = 0; i < m_pHeaderRecords->GetCount(); i++)
  991. {
  992. CXTPReportRecord* pRecord = m_pHeaderRecords->GetAt(i);
  993. CXTPReportRow* pRow = CreateHeaderFooterRow();
  994. pRow->InitRow(this, pRecord);
  995. pRow->SetIndex(i);
  996. pRow->m_nRowType = xtpRowTypeHeader;
  997. pRow->m_pParentRow = NULL;
  998. m_pHeaderRows->Add(pRow);
  999. }
  1000. // footer record rows
  1001. for (i = 0; i < m_pFooterRecords->GetCount(); i++)
  1002. {
  1003. CXTPReportRecord* pRecord = m_pFooterRecords->GetAt(i);
  1004. CXTPReportRow* pRow = CreateHeaderFooterRow();
  1005. pRow->InitRow(this, pRecord);
  1006. pRow->SetIndex(i);
  1007. pRow->m_nRowType = xtpRowTypeFooter;
  1008. pRow->m_pParentRow = NULL;
  1009. m_pFooterRows->Add(pRow);
  1010. }
  1011. }
  1012. AdjustIndentation();
  1013. AdjustLayout();
  1014. AdjustScrollBars();
  1015. UpdateSubList();
  1016. if (m_nFocusedRow == -1)
  1017. {
  1018. SetTopRow(0);
  1019. if (GetRows()->GetCount() > 0)
  1020. {
  1021. m_nFocusedRow = 0;
  1022. if(IsSelectionEnabled())
  1023. m_pSelectedRows->Select(m_pRows->GetAt(0));
  1024. }
  1025. }
  1026. else
  1027. {
  1028. EnsureVisible(GetFocusedRow());
  1029. }
  1030. if (m_pFocusedColumn == NULL && m_bFocusSubItems)
  1031. {
  1032. m_pFocusedColumn = m_pColumns->GetFirstVisibleColumn();
  1033. }
  1034. EndUpdate();
  1035. }
  1036. void CXTPReportControl::PopulateHeaderRows()
  1037. {
  1038. if(IsVirtualMode())
  1039. return;
  1040. EditItem(NULL);
  1041. BeginUpdate();
  1042. m_pHeaderRows->Clear();
  1043. for (int i = 0; i < m_pHeaderRecords->GetCount(); i++)
  1044. {
  1045. CXTPReportRecord* pRecord = m_pHeaderRecords->GetAt(i);
  1046. CXTPReportRow* pRow = CreateHeaderFooterRow();
  1047. pRow->InitRow(this, pRecord);
  1048. pRow->SetIndex(i);
  1049. pRow->m_nRowType = xtpRowTypeHeader;
  1050. pRow->m_pParentRow = NULL;
  1051. m_pHeaderRows->Add(pRow);
  1052. }
  1053. AdjustIndentation();
  1054. AdjustLayout();
  1055. AdjustScrollBars();
  1056. UpdateSubList();
  1057. EndUpdate();
  1058. }
  1059. void CXTPReportControl::PopulateFooterRows()
  1060. {
  1061. if(IsVirtualMode())
  1062. return;
  1063. EditItem(NULL);
  1064. BeginUpdate();
  1065. m_pFooterRows->Clear();
  1066. for (int i = 0; i < m_pFooterRecords->GetCount(); i++)
  1067. {
  1068. CXTPReportRecord* pRecord = m_pFooterRecords->GetAt(i);
  1069. CXTPReportRow* pRow = CreateHeaderFooterRow();
  1070. pRow->InitRow(this, pRecord);
  1071. pRow->SetIndex(i);
  1072. pRow->m_nRowType = xtpRowTypeFooter;
  1073. pRow->m_pParentRow = NULL;
  1074. m_pFooterRows->Add(pRow);
  1075. }
  1076. AdjustIndentation();
  1077. AdjustLayout();
  1078. AdjustScrollBars();
  1079. UpdateSubList();
  1080. EndUpdate();
  1081. }
  1082. void CXTPReportControl::SortRows(CXTPReportRows* pRows)
  1083. {
  1084. if (pRows->GetCount() == 0)
  1085. return;
  1086. if (m_pRowsCompareFunc && m_pRowsCompareFunc != CXTPReportRows::CompareRows)
  1087. {
  1088. pRows->SortEx(m_pRowsCompareFunc);
  1089. return;
  1090. }
  1091. if (m_pColumns->GetSortOrder()->GetCount() == 0 &&
  1092. m_pColumns->GetGroupsOrder()->GetCount() == 0)
  1093. return;
  1094. pRows->Sort();
  1095. }
  1096. void CXTPReportControl::AdjustIndentation()
  1097. {
  1098. XTP_TRACE(_T("AdjustIndentation()n"));
  1099. GetReportHeader()->m_nIndentLevel =
  1100. m_pColumns->GetGroupsOrder()->GetCount();
  1101. }
  1102. CXTPReportColumn* CXTPReportControl::AddColumn(CXTPReportColumn* pColumn)
  1103. {
  1104. ASSERT(pColumn);
  1105. m_pColumns->Add(pColumn);
  1106. return pColumn;
  1107. }
  1108. CXTPReportRecord* CXTPReportControl::AddRecord(CXTPReportRecord* pRecord)
  1109. {
  1110. ASSERT(pRecord);
  1111. if (!pRecord)
  1112. return NULL;
  1113. m_pRecords->Add(pRecord);
  1114. return pRecord;
  1115. }
  1116. void CXTPReportControl::AddRecordEx(CXTPReportRecord* pRecord, CXTPReportRecord* pParentRecord, int nChildIndex)
  1117. {
  1118. ASSERT(pRecord);
  1119. if (!pRecord)
  1120. return;
  1121. // add record
  1122. BOOL bAddRecord = TRUE;
  1123. CXTPReportRecords* pParentRecords = pParentRecord ? pParentRecord->HasChildren() ? pParentRecord->GetChilds() : NULL : m_pRecords;
  1124. if(pParentRecords)
  1125. {
  1126. for(int nChild = 0; nChild < pParentRecords->GetCount(); nChild++)
  1127. {
  1128. if(pRecord == pParentRecords->GetAt(nChild))
  1129. {
  1130. bAddRecord = FALSE;
  1131. break;
  1132. }
  1133. }
  1134. }
  1135. if(bAddRecord)
  1136. {
  1137. if(pParentRecord)
  1138. pParentRecord->GetChilds()->Add(pRecord);
  1139. else
  1140. m_pRecords->Add(pRecord);
  1141. }
  1142. if(!pRecord->IsVisible())
  1143. return;
  1144. // find parent record rows
  1145. CXTPReportRows* pParentRows = m_pPlainTree;
  1146. CXTPReportRow* pParentRow = NULL;
  1147. if(pParentRecord)
  1148. {
  1149. pParentRow = m_pPlainTree->FindInTree(pParentRecord);
  1150. if(pParentRow)
  1151. pParentRows = pParentRow->GetChilds();
  1152. }
  1153. BOOL bRoot = pParentRows == m_pPlainTree;
  1154. // create new row
  1155. CXTPReportRow* pNewRow = CreateRow();
  1156. pNewRow->InitRow(this, pRecord);
  1157. pNewRow->m_pParentRow = NULL;
  1158. // add row to pParentRows
  1159. BOOL bInsertAfter = FALSE;
  1160. CXTPReportRow* pPlainTreeRow = NULL;
  1161. CXTPReportRow* pInsertRowPos = NULL;
  1162. int nNextSiblingIndex = m_pRows->GetCount();
  1163. if(bRoot)
  1164. {
  1165. pInsertRowPos = pParentRows->FindInsertionPos(pNewRow, bInsertAfter);
  1166. CXTPReportRow* pRow = pInsertRowPos;
  1167. while(pRow)
  1168. {
  1169. if(pRow->GetNextSiblingRow())
  1170. {
  1171. nNextSiblingIndex = pRow->GetNextSiblingRow()->GetIndex();
  1172. break;
  1173. }
  1174. else
  1175. pRow = pRow->GetParentRow();
  1176. }
  1177. if(m_pColumns->GetGroupsOrder()->GetCount() > 0)
  1178. {
  1179. CXTPReportGroupRow* pGroupToAdd = pInsertRowPos ? (CXTPReportGroupRow*)pInsertRowPos->GetParentRow() : NULL;
  1180. if(!pInsertRowPos || (pInsertRowPos && pInsertRowPos->IsGroupRow()))
  1181. {
  1182. for(int nColumn = pInsertRowPos ? pInsertRowPos->GetGroupLevel() : 0; nColumn < m_pColumns->GetGroupsOrder()->GetCount(); nColumn++)
  1183. {
  1184. CXTPReportColumn* pColumn = m_pColumns->GetGroupsOrder()->GetAt(nColumn);
  1185. CXTPReportRecordItem* pItem = pRecord->GetItem(pColumn);
  1186. CString strGroup = pItem ? pItem->GetGroupCaption(pColumn) : _T("");
  1187. CXTPReportGroupRow* pGroup = CreateGroupRow();
  1188. pGroup->InitRow(this, NULL);
  1189. pGroup->SetCaption(strGroup);
  1190. pGroup->m_nGroupLevel = pGroupToAdd ? pGroupToAdd->m_nRowLevel + 1 : 0;
  1191. pGroup->m_nRowLevel = nColumn;
  1192. if(pGroupToAdd)
  1193. {
  1194. if(!pPlainTreeRow)
  1195. {
  1196. pPlainTreeRow = pGroup;
  1197. pGroupToAdd->GetChilds()->InsertAt(bInsertAfter ? pInsertRowPos ? pInsertRowPos->m_nChildIndex + 1 : 0 : pInsertRowPos ? pInsertRowPos->m_nChildIndex : 0, pGroup);
  1198. }
  1199. else
  1200. pGroupToAdd->AddChild(pGroup);
  1201. pGroup->m_pParentRows = pGroupToAdd->GetChilds();
  1202. pGroup->m_pParentRow = pGroupToAdd;
  1203. pGroup->m_bVisible = pGroupToAdd->IsExpanded();
  1204. }
  1205. else
  1206. {
  1207. pPlainTreeRow = pGroup;
  1208. pParentRows->InsertAt(pInsertRowPos ? pInsertRowPos->m_nChildIndex : pParentRows->GetCount(), pGroup);
  1209. pGroup->m_pParentRows = pParentRows;
  1210. pGroup->m_pParentRow = NULL;
  1211. pGroup->m_bVisible = TRUE;
  1212. }
  1213. pGroupToAdd = pGroup;
  1214. }
  1215. // insert row
  1216. if(pGroupToAdd)
  1217. {
  1218. pGroupToAdd->AddChild(pNewRow);
  1219. pNewRow->m_pParentRows = pGroupToAdd->GetChilds();
  1220. //              pNewRow->m_pParentRow = pGroupToAdd;
  1221. pNewRow->m_bVisible = pGroupToAdd->IsExpanded();
  1222. }
  1223. }
  1224. else
  1225. {
  1226. // insert row
  1227. if(pGroupToAdd)
  1228. {
  1229. pGroupToAdd->GetChilds()->InsertAt(bInsertAfter ? pInsertRowPos ? pInsertRowPos->m_nChildIndex + 1 : 0 : pInsertRowPos ? pInsertRowPos->m_nChildIndex : 0, pNewRow);
  1230. pNewRow->m_pParentRows = pGroupToAdd->GetChilds();
  1231. pNewRow->m_pParentRow = pGroupToAdd;
  1232. pNewRow->m_bVisible = pGroupToAdd->IsExpanded();
  1233. }
  1234. }
  1235. }
  1236. else
  1237. {
  1238. pParentRows->InsertAt(pInsertRowPos ? pInsertRowPos->m_nChildIndex : pParentRows->GetCount(), pNewRow);
  1239. pNewRow->m_pParentRows = pParentRows;
  1240. pNewRow->m_pParentRow = NULL;
  1241. pNewRow->m_bVisible = TRUE;
  1242. }
  1243. }
  1244. else
  1245. {
  1246. if(nChildIndex >= 0 && nChildIndex < pParentRows->GetCount())
  1247. pParentRows->InsertAt(nChildIndex, pNewRow);
  1248. else
  1249. pParentRows->Add(pNewRow);
  1250. pNewRow->m_pParentRows = pParentRows;
  1251. pNewRow->m_pParentRow = pParentRow;
  1252. pNewRow->m_bVisible = TRUE;
  1253. pNewRow->m_nRowLevel = pParentRow->m_nRowLevel + 1;
  1254. pNewRow->m_nGroupLevel = pParentRow->m_nGroupLevel;
  1255. pNewRow->m_nChildIndex = nChildIndex >= 0 ? nChildIndex : pParentRows->GetCount() - 1;
  1256. CXTPReportRow* pRow = pNewRow;
  1257. while(pRow)
  1258. {
  1259. if(pRow->GetNextSiblingRow())
  1260. {
  1261. nNextSiblingIndex = pRow->GetNextSiblingRow()->GetIndex();
  1262. break;
  1263. }
  1264. else
  1265. pRow = pRow->GetParentRow();
  1266. }
  1267. }
  1268. // refresh child indices
  1269. if(pInsertRowPos && pInsertRowPos->GetParentRows())
  1270. pInsertRowPos->GetParentRows()->RefreshChildIndices();
  1271. else
  1272. pParentRows->RefreshChildIndices();
  1273. // add row to m_pRows
  1274. if(bRoot)
  1275. {
  1276. if(pInsertRowPos)
  1277. {
  1278. CXTPReportRow* pRow = pInsertRowPos->GetParentRow();
  1279. BOOL bIsExpanded = TRUE;
  1280. while(pRow && bIsExpanded)
  1281. {
  1282. bIsExpanded = bIsExpanded && pRow->IsExpanded();
  1283. pRow = pRow->GetParentRow();
  1284. }
  1285. if(bIsExpanded)
  1286. {
  1287. if(bInsertAfter)
  1288. InsertRow(nNextSiblingIndex, pPlainTreeRow ? pPlainTreeRow : pNewRow);
  1289. else
  1290. InsertRow(pInsertRowPos->GetIndex(), pPlainTreeRow ? pPlainTreeRow : pNewRow);
  1291. }
  1292. }
  1293. else
  1294. {
  1295. InsertRow(m_pRows->GetCount(), pPlainTreeRow ? pPlainTreeRow : pNewRow);
  1296. }
  1297. }
  1298. else
  1299. {
  1300. CXTPReportRow* pRow = pNewRow->GetParentRow();
  1301. BOOL bIsExpanded = TRUE;
  1302. while(pRow && bIsExpanded)
  1303. {
  1304. bIsExpanded = bIsExpanded && pRow->IsExpanded();
  1305. pRow = pRow->GetParentRow();
  1306. }
  1307. if(bIsExpanded)
  1308. InsertRow(nNextSiblingIndex, pNewRow);
  1309. }
  1310. RefreshIndexes(FALSE, TRUE);
  1311. // add children
  1312. if(pRecord && pRecord->HasChildren())
  1313. {
  1314. for(int nChild = 0; nChild < pRecord->GetChilds()->GetCount(); nChild++)
  1315. {
  1316. AddRecordEx(pRecord->GetChilds()->GetAt(nChild), pRecord);
  1317. }
  1318. }
  1319. }
  1320. BOOL CXTPReportControl::RemoveRowEx(CXTPReportRow* pRow, BOOL bAdjustLayout)
  1321. {
  1322. ASSERT(pRow);
  1323. if (!pRow)
  1324. return FALSE;
  1325. //------------------------------------------------
  1326. if (!pRow->IsGroupRow())
  1327. {
  1328. ASSERT(pRow->GetRecord());
  1329. return RemoveRecordEx(pRow->GetRecord(), bAdjustLayout);
  1330. }
  1331. //------------------------------------------------
  1332. CWaitCursor _WC;
  1333. int nCount = pRow->GetChilds()->GetCount();
  1334. ASSERT(nCount);
  1335. for (int i = nCount - 1; i >= 0 ; i--)
  1336. {
  1337. CXTPReportRow* pRowI = pRow->GetChilds()->GetAt(i);
  1338. RemoveRowEx(pRowI, bAdjustLayout);
  1339. }
  1340. return TRUE;
  1341. }
  1342. BOOL CXTPReportControl::RemoveRecordEx(CXTPReportRecord* pRecord, BOOL bAdjustLayout, BOOL bRemoveFromParent)
  1343. {
  1344. ASSERT(pRecord && m_pRecords);
  1345. if (!pRecord || !m_pRecords)
  1346. return FALSE;
  1347. if (pRecord->HasChildren())
  1348. {
  1349. for (int i = pRecord->GetChilds()->GetCount() - 1; i >= 0 ; i--)
  1350. {
  1351. RemoveRecordEx(pRecord->GetChilds()->GetAt(i), bAdjustLayout, FALSE);
  1352. }
  1353. //      return RemoveRecordEx(pRecord, bAdjustLayout);
  1354. }
  1355. BOOL bResult = FALSE;
  1356. //--------------------------------------------------------
  1357. CXTPReportRow* pRow0 = m_pPlainTree->FindInTree(pRecord);
  1358. ASSERT_DBG_REMOVE_RECORD_EX(pRow0);
  1359. if (pRow0)
  1360. {
  1361. CXTPReportRow* pRow = pRow0;
  1362. pRow0 = NULL;
  1363. do
  1364. {
  1365. CXTPReportRow* pRow_parent = pRow->GetParentRow();
  1366. ASSERT(pRow->GetParentRows());
  1367. // 1. Remove from selected rows
  1368. if(m_pSelectedRows->Contains(pRow))
  1369. m_pSelectedRows->Remove(pRow);
  1370. // 2. remove from Rows Tree
  1371. if (pRow->GetParentRows())
  1372. VERIFY(pRow->GetParentRows()->RemoveRow(pRow) >= 0);
  1373. // 3. remove from Display Rows array
  1374. m_pRows->RemoveRow(pRow);
  1375. pRow = pRow_parent;
  1376. } while (pRow && pRow->IsGroupRow() && pRow->GetChilds()->GetCount() == 0);
  1377. // refresh child indices
  1378. if(pRow && pRow->HasChildren())
  1379. pRow->GetChilds()->RefreshChildIndices();
  1380. else
  1381. m_pPlainTree->RefreshChildIndices();
  1382. bResult = TRUE;
  1383. }
  1384. //-------------------------------------------------------
  1385. //pRecord->Delete(); // the code below is more safe when record already removed!
  1386. ASSERT(pRecord->GetRecords());
  1387. if (bRemoveFromParent && pRecord->GetRecords())
  1388. {
  1389. BOOL bRecordRem = pRecord->GetRecords()->RemoveRecord(pRecord) >= 0;
  1390. pRecord = NULL;
  1391. ASSERT_DBG_REMOVE_RECORD_EX(bRecordRem);
  1392. bResult |= bRecordRem;
  1393. }
  1394. if (m_nFocusedRow >= 0 && m_nFocusedRow >= m_pRows->GetCount())
  1395. m_nFocusedRow = m_pRows->GetCount() - 1;
  1396. //-------------------------------------------------------
  1397. if (bResult)
  1398. RefreshIndexes(bAdjustLayout);
  1399. return bResult;
  1400. }
  1401. void CXTPReportControl::UpdateRecord(CXTPReportRecord* pRecord, BOOL bUpdateChildren)
  1402. {
  1403. // get parent record
  1404. CXTPReportRecord* pParentRecord = NULL;
  1405. if(pRecord->GetRecords())
  1406. pParentRecord = pRecord->GetRecords()->GetOwnerRecord();
  1407. // update record
  1408. if(!pParentRecord || bUpdateChildren)
  1409. {
  1410. // internal addref
  1411. pRecord->TreeAddRef();
  1412. // get record row child index
  1413. CXTPReportRow* pRow = m_pPlainTree->FindInTree(pRecord);
  1414. int nChildIndex = pRow->m_nChildIndex;
  1415. // remove record
  1416. RemoveRecordEx(pRecord, FALSE);
  1417. // add record
  1418. AddRecordEx(pRecord, pParentRecord, nChildIndex);
  1419. // internal release
  1420. pRecord->TreeRelease();
  1421. }
  1422. else
  1423. RedrawControl();
  1424. }
  1425. void CXTPReportControl::DrawNoItems(CDC* pDC, const CRect& rcClient)
  1426. {
  1427. pDC->SetTextColor(GetPaintManager()->m_clrWindowText);
  1428. CString strNoItems = GetPaintManager()->m_strNoItems;
  1429. if (!strNoItems.IsEmpty())
  1430. {
  1431. CRect rcText(rcClient);
  1432. rcText.DeflateRect(5, 5, 5, 5);
  1433. CXTPFontDC font(pDC, &GetPaintManager()->m_fontText);
  1434. UINT uFlags = DT_CENTER | DT_TOP | DT_NOPREFIX | DT_WORDBREAK |
  1435.   DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_EDITCONTROL;
  1436. pDC->DrawText(strNoItems, rcText, uFlags);
  1437. }
  1438. }
  1439. void CXTPReportControl::DrawRows(CDC* pDC, CRect& rcClient)
  1440. {
  1441. m_arrScreenRows.Clear(FALSE);
  1442. pDC->SetBkMode(TRANSPARENT);
  1443. int y = rcClient.top;
  1444. int nRowCount = m_pRows->GetCount();
  1445. if (0 == nRowCount)
  1446. {
  1447. DrawNoItems(pDC, rcClient);
  1448. }
  1449. if (GetReportHeader()->GetNextVisibleColumn(-1, 1) == NULL)
  1450. return;
  1451. int nRowHeight = 0;
  1452. int nHeaderWidth = GetReportHeader()->GetWidth();
  1453. //m_arrScreenRows.ReserveSize(200);
  1454. m_arrScreenRows.SetSize(0, 200);
  1455. for (int i = m_nTopRow; i < nRowCount; i++)
  1456. {
  1457. CXTPReportRow* pRow = m_pRows->GetAt(i);
  1458. ASSERT(pRow);
  1459. if (!pRow)
  1460. continue;
  1461. if (y > rcClient.bottom)
  1462. break;
  1463. nRowHeight = pRow->GetHeight(pDC, nHeaderWidth);
  1464. CRect rcRow(rcClient.left, y, rcClient.left + nHeaderWidth,
  1465. y + pRow->GetHeight(pDC, nHeaderWidth));
  1466. pRow->Draw(pDC, rcRow, m_nLeftOffset);
  1467. y += rcRow.Height();
  1468. CXTPReportRow* pScreenRow = NULL;
  1469. if (IsVirtualMode())
  1470. {
  1471. pScreenRow = CreateRow();
  1472. pScreenRow->InitRow(pRow);
  1473. pScreenRow->m_bExpanded = pRow->m_bExpanded;
  1474. if(pScreenRow->m_nRowLevel == 0)
  1475. pScreenRow->m_rcCollapse = pRow->m_rcCollapse;
  1476. }
  1477. else
  1478. {
  1479. pScreenRow = pRow;
  1480. pScreenRow->InternalAddRef();
  1481. }
  1482. m_arrScreenRows.InsertAt(m_arrScreenRows.GetCount(), pScreenRow);
  1483. }
  1484. // fill the rest of space with the "fake" rows
  1485. if (GetPaintManager()->IsDrawGridForEmptySpace() && y < rcClient.bottom)
  1486. {
  1487. CRect rcEmpty(rcClient);
  1488. rcEmpty.top = y;
  1489. DrawDefaultGrid(pDC, rcEmpty, nRowHeight, m_nLeftOffset);
  1490. }
  1491. }
  1492. void CXTPReportControl::DrawFixedRows(CDC* pDC, CRect& rcClient, CXTPReportRows* pRows)
  1493. {
  1494. pDC->SetBkMode(TRANSPARENT);
  1495. int y = rcClient.top;
  1496. int nRowCount = pRows->GetCount();
  1497. if ( nRowCount > 0 )
  1498. {
  1499. if (GetReportHeader()->GetNextVisibleColumn(-1, 1) == NULL)
  1500. return;
  1501. int nHeaderWidth = GetReportHeader()->GetWidth();
  1502. for (int i = 0; i < nRowCount; i++)
  1503. {
  1504. CXTPReportRow* pRow = pRows->GetAt(i);
  1505. if (y > rcClient.bottom)
  1506. break;
  1507. CRect rcRow(rcClient.left, y, rcClient.left + nHeaderWidth,
  1508. y + pRow->GetHeight(pDC, nHeaderWidth));
  1509. pRow->DrawFixed(pDC, rcRow, m_nLeftOffset, rcClient);
  1510. y += rcRow.Height();
  1511. }
  1512. }
  1513. }
  1514. void CXTPReportControl::DrawFixedRecordsDivider(CDC* pDC, CRect& rcClient, BOOL bHeaderRows)
  1515. {
  1516. GetPaintManager()->DrawFixedRowsDivider(pDC, rcClient, this, bHeaderRows, m_bVScrollBarVisible);
  1517. }
  1518. void CXTPReportControl::OnSelectionChanged()
  1519. {
  1520. SendNotifyMessage(XTP_NM_REPORT_SELCHANGED);
  1521. if (m_pSelectedRows)
  1522. m_pSelectedRows->SetChanged(FALSE);
  1523. }
  1524. BOOL CXTPReportControl::OnFocusChanging(CXTPReportRow* pNewRow, CXTPReportColumn* pNewCol)
  1525. {
  1526. XTP_NM_REPORTREQUESTEDIT nm;
  1527. ::ZeroMemory(&nm, sizeof(nm));
  1528. nm.bCancel = FALSE;
  1529. nm.pRow = pNewRow ? pNewRow : GetFocusedRow();
  1530. nm.pColumn = pNewCol ? pNewCol : GetFocusedColumn();
  1531. nm.pItem = nm.pRow && nm.pColumn ? (nm.pRow->GetRecord() ? nm.pRow->GetRecord()->GetItem(nm.pColumn) : NULL) : NULL;
  1532. SendNotifyMessage(XTP_NM_REPORT_FOCUS_CHANGING, (NMHDR*)&nm);
  1533. return !nm.bCancel;
  1534. }
  1535. void CXTPReportControl::GetItemMetrics(XTP_REPORTRECORDITEM_DRAWARGS* pDrawArgs,
  1536. XTP_REPORTRECORDITEM_METRICS* pMetrics)
  1537. {
  1538. XTP_NM_REPORTITEMMETRICS nmData;
  1539. nmData.pDrawArgs = pDrawArgs;
  1540. nmData.pItemMetrics = pMetrics;
  1541. SendNotifyMessage(XTP_NM_REPORT_GETITEMMETRICS, (NMHDR*)&nmData);
  1542. }
  1543. BOOL CXTPReportControl::SetFocusedColumn(CXTPReportColumn* pColumn)
  1544. {
  1545. if (m_pFocusedColumn != pColumn)
  1546. {
  1547. if (m_bFocusSubItems && pColumn)
  1548. {
  1549. if(!OnFocusChanging(NULL, pColumn))
  1550. return FALSE;
  1551. }
  1552. m_pFocusedColumn = pColumn;
  1553. if (m_pFocusedColumn && m_bFocusSubItems)
  1554. {
  1555. CRect rc(m_pFocusedColumn->GetRect());
  1556. if (rc.right >= m_rcReportArea.Width())
  1557. {
  1558. SetLeftOffset(m_nLeftOffset + min(rc.left, rc.right - m_rcReportArea.Width()));
  1559. }
  1560. else
  1561. {
  1562. int nFreezeColumnWidth = 0;
  1563. if (m_nFreezeColumnsCount > 0)
  1564. {
  1565. int nFreezeColumnsCount = m_nFreezeColumnsCount;
  1566. for (int i = 0; (i < m_pColumns->GetCount()) && (nFreezeColumnsCount > 0); i++)
  1567. {
  1568. CXTPReportColumn* pColumnCheck = m_pColumns->GetAt(i);
  1569. if (pColumnCheck == m_pFocusedColumn)
  1570. {
  1571. nFreezeColumnWidth = 0;
  1572. break;
  1573. }
  1574. if (pColumnCheck && pColumnCheck->IsVisible())
  1575. {
  1576. nFreezeColumnsCount--;
  1577. nFreezeColumnWidth = pColumnCheck->GetRect().right;
  1578. }
  1579. }
  1580. }
  1581. if (rc.left - nFreezeColumnWidth <= 0 && m_nLeftOffset != 0)
  1582. {
  1583. SetLeftOffset(m_nLeftOffset + rc.left - nFreezeColumnWidth);
  1584. }
  1585. }
  1586. }
  1587. if (m_bFocusSubItems)
  1588. {
  1589. OnSelectionChanged();
  1590. }
  1591. }
  1592. return TRUE;
  1593. }
  1594. BOOL CXTPReportControl::SetFocusedRow(CXTPReportRow* pRow, BOOL bIgnoreSelection)
  1595. {
  1596. if(pRow)
  1597. {
  1598. int nFocusedRow = m_nFocusedRow != -1 ? m_nFocusedRow : m_nFocusedHeaderRow != -1 ? m_nFocusedHeaderRow : m_nFocusedFooterRow;
  1599. int nFocusedRowType = m_nFocusedRow != -1 ? xtpRowTypeBody : m_nFocusedHeaderRow != -1 ? xtpRowTypeHeader : xtpRowTypeFooter;
  1600. if (nFocusedRow != pRow->GetIndex() || pRow->GetType() != nFocusedRowType)
  1601. {
  1602. if (!OnFocusChanging(pRow, NULL))
  1603. return FALSE;
  1604. }
  1605. }
  1606. EditItem(NULL);
  1607. BeginUpdate();
  1608. BOOL bEnableSelection = (!bIgnoreSelection || !m_bMultipleSelection) && IsSelectionEnabled();
  1609. if (pRow && pRow->GetType() == xtpRowTypeHeader)
  1610. bEnableSelection &= IsHeaderRowsSelectionEnabled();
  1611. if (pRow && pRow->GetType() == xtpRowTypeFooter)
  1612. bEnableSelection &= IsFooterRowsSelectionEnabled();
  1613. if (bEnableSelection)
  1614. {
  1615. m_pSelectedRows->Select(pRow);
  1616. }
  1617. if (pRow)
  1618. {
  1619. m_nFocusedRow = m_nFocusedHeaderRow = m_nFocusedFooterRow = -1;
  1620. switch (pRow->GetType())
  1621. {
  1622. case xtpRowTypeBody:    m_nFocusedRow = pRow->GetIndex(); break;
  1623. case xtpRowTypeHeader:  m_nFocusedHeaderRow = pRow->GetIndex();  break;
  1624. case xtpRowTypeFooter:  m_nFocusedFooterRow = pRow->GetIndex(); break;
  1625. }
  1626. GetNavigator()->SetMovePosition(pRow->GetType());
  1627. EnsureVisible(pRow);
  1628. }
  1629. EndUpdate();
  1630. if (m_pSelectedRows->IsChanged())
  1631. OnSelectionChanged();
  1632. return TRUE;
  1633. }
  1634. BOOL CXTPReportControl::SetFocusedRow(CXTPReportRow* pRow, BOOL bSelectBlock, BOOL bIgnoreSelection)
  1635. {
  1636. if (!pRow)
  1637. return FALSE;
  1638. int nFocusedRow = m_nFocusedRow != -1 ? m_nFocusedRow : m_nFocusedHeaderRow != -1 ? m_nFocusedHeaderRow : m_nFocusedFooterRow;
  1639. int nFocusedRowType = m_nFocusedRow != -1 ? xtpRowTypeBody : m_nFocusedHeaderRow != -1 ? xtpRowTypeHeader : xtpRowTypeFooter;
  1640. if (nFocusedRow != pRow->GetIndex() || pRow->GetType() != nFocusedRowType)
  1641. {
  1642. if (!OnFocusChanging(pRow, NULL))
  1643. return FALSE;
  1644. }
  1645. EditItem(NULL);
  1646. BeginUpdate();
  1647. BOOL bEnableSelection = IsSelectionEnabled();
  1648. if(pRow && pRow->GetType() == xtpRowTypeHeader)
  1649. bEnableSelection &= IsHeaderRowsSelectionEnabled();
  1650. if(pRow && pRow->GetType() == xtpRowTypeFooter)
  1651. bEnableSelection &= IsFooterRowsSelectionEnabled();
  1652. if(bEnableSelection)
  1653. {
  1654. if (m_bMultipleSelection)
  1655. {
  1656. int nFocusedRow = m_nFocusedRow != -1 ? m_nFocusedRow : m_nFocusedHeaderRow != -1 ? m_nFocusedHeaderRow : m_nFocusedFooterRow;
  1657. if (bSelectBlock && nFocusedRow != -1)
  1658. {
  1659. m_pSelectedRows->SelectBlock(nFocusedRow, pRow->GetIndex());
  1660. }
  1661. else if (!bIgnoreSelection)
  1662. {
  1663. m_pSelectedRows->Select(pRow);
  1664. }
  1665. }
  1666. else
  1667. {
  1668. m_pSelectedRows->Select(pRow);
  1669. }
  1670. }
  1671. m_nFocusedRow = m_nFocusedHeaderRow = m_nFocusedFooterRow = -1;
  1672. switch(pRow->GetType())
  1673. {
  1674. case xtpRowTypeBody:    m_nFocusedRow       = pRow->GetIndex(); break;
  1675. case xtpRowTypeHeader:  m_nFocusedHeaderRow = pRow->GetIndex(); break;
  1676. case xtpRowTypeFooter:  m_nFocusedFooterRow = pRow->GetIndex(); break;
  1677. }
  1678. GetNavigator()->SetMovePosition(pRow->GetType());
  1679. EnsureVisible(pRow);
  1680. EndUpdate();
  1681. if (m_pSelectedRows->IsChanged())
  1682. OnSelectionChanged();
  1683. return TRUE;
  1684. }
  1685. void CXTPReportControl::SetLeftOffset(int nOffset)
  1686. {
  1687. if (nOffset < 0)
  1688. nOffset = 0;
  1689. if (nOffset == m_nLeftOffset)
  1690. return;
  1691. m_nLeftOffset = nOffset;
  1692. if (!m_bFullColumnScrolling)
  1693. SetScrollPos(SB_HORZ, nOffset);
  1694. AdjustScrollBars();
  1695. }
  1696. void CXTPReportControl::SetTopRow(int nIndex)
  1697. {
  1698. if (nIndex == m_nTopRow)
  1699. return;
  1700. ASSERT(nIndex >= 0);
  1701. if (nIndex < 0)
  1702. nIndex = 0;
  1703. m_nTopRow = nIndex;
  1704. SetScrollPos(SB_VERT, nIndex);
  1705. AdjustScrollBars();
  1706. }
  1707. void CXTPReportControl::EnsureVisible(CXTPReportRow* pCheckRow)
  1708. {
  1709. int nCheckIndex = pCheckRow ? pCheckRow->GetIndex() : -1;
  1710. if (nCheckIndex == -1 || !pCheckRow->m_bVisible || nCheckIndex >= m_pRows->GetCount())
  1711. return;
  1712. if(m_rcReportArea.Height() <= 0)
  1713. {
  1714. m_nEnsureVisibleRowIdx = nCheckIndex;
  1715. return;
  1716. }
  1717. if (nCheckIndex < m_nTopRow)
  1718. {
  1719. SetTopRow(nCheckIndex);
  1720. return;
  1721. }
  1722. CClientDC dc (this);
  1723. int top = m_rcReportArea.top;
  1724. int nHeaderWidth = GetReportHeader()->GetWidth();
  1725. for (int i = m_nTopRow; i < m_pRows->GetCount(); i++)
  1726. {
  1727. CXTPReportRow* pRow = m_pRows->GetAt(i);
  1728. ASSERT(pRow);
  1729. if (!pRow)
  1730. continue;
  1731. int nRowHeight = pRow->GetHeight(&dc, nHeaderWidth);
  1732. if (top + nRowHeight > m_rcReportArea.bottom)
  1733. break;
  1734. if (i == nCheckIndex)
  1735. return;
  1736. top += nRowHeight;
  1737. }
  1738. int nHeight = m_rcReportArea.Height();
  1739. for (top = nCheckIndex; top >= 0; top--)
  1740. {
  1741. CXTPReportRow* pRow = m_pRows->GetAt(top);
  1742. int nRowHeight = pRow->GetHeight(&dc, nHeaderWidth);
  1743. if (nHeight - nRowHeight < 0)
  1744. {
  1745. if (top != nCheckIndex)
  1746. top++;
  1747. break;
  1748. }
  1749. nHeight -= nRowHeight;
  1750. }
  1751. SetTopRow(top);
  1752. RedrawControl();
  1753. }
  1754. void CXTPReportControl::EnsureVisible(CXTPReportColumn* pCheckColumn)
  1755. {
  1756. int nCheckIndex = pCheckColumn ? pCheckColumn->GetIndex() : -1;
  1757. if (nCheckIndex == -1 || !pCheckColumn->m_bVisible || nCheckIndex >= m_pColumns->GetCount())
  1758. return;
  1759. if(m_rcReportArea.Height() <= 0)
  1760. {
  1761. m_nEnsureVisibleRowIdx = nCheckIndex;
  1762. return;
  1763. }
  1764. CRect rc(pCheckColumn->GetRect());
  1765. if (rc.right >= m_rcReportArea.Width())
  1766. {
  1767. SetLeftOffset(m_nLeftOffset + min(rc.left, rc.right - m_rcReportArea.Width()));
  1768. }
  1769. else
  1770. {
  1771. int nFreezeColumnWidth = 0;
  1772. if (m_nFreezeColumnsCount > 0)
  1773. {
  1774. int nFreezeColumnsCount = m_nFreezeColumnsCount;
  1775. for (int i = 0; (i < m_pColumns->GetCount()) && (nFreezeColumnsCount > 0); i++)
  1776. {
  1777. CXTPReportColumn* pColumn = m_pColumns->GetAt(i);
  1778. if (pColumn == pCheckColumn)
  1779. {
  1780. nFreezeColumnWidth = 0;
  1781. break;
  1782. }
  1783. if (pColumn && pColumn->IsVisible())
  1784. {
  1785. nFreezeColumnsCount--;
  1786. nFreezeColumnWidth = pColumn->GetRect().right;
  1787. }
  1788. }
  1789. }
  1790. if (rc.left - nFreezeColumnWidth <= 0 && m_nLeftOffset != 0)
  1791. {
  1792. SetLeftOffset(m_nLeftOffset + rc.left - nFreezeColumnWidth);
  1793. }
  1794. }
  1795. }
  1796. CXTPReportRow* CXTPReportControl::HitTest(CPoint pt) const
  1797. {
  1798. if (m_rcReportArea.PtInRect(pt))
  1799. {
  1800. for (int i = 0; i < m_arrScreenRows.GetCount(); i++)
  1801. {
  1802. CXTPReportRow* pRow = m_arrScreenRows.GetAt(i);
  1803. CRect rc = pRow->GetRect();
  1804. if (rc.PtInRect(pt))
  1805. return pRow;
  1806. }
  1807. }
  1808. // header records
  1809. if (m_rcHeaderRecordsArea.PtInRect(pt))
  1810. {
  1811. for (int i = 0; i < m_pHeaderRows->GetCount(); i++)
  1812. {
  1813. CXTPReportRow* pRow = m_pHeaderRows->GetAt(i);
  1814. CRect rc = pRow->GetRect();
  1815. if (rc.PtInRect(pt))
  1816. return pRow;
  1817. }
  1818. }
  1819. // footer records
  1820. if (m_rcFooterRecordsArea.PtInRect(pt))
  1821. {
  1822. for (int i = 0; i < m_pFooterRows->GetCount(); i++)
  1823. {
  1824. CXTPReportRow* pRow = m_pFooterRows->GetAt(i);
  1825. CRect rc = pRow->GetRect();
  1826. if (rc.PtInRect(pt))
  1827. return pRow;
  1828. }
  1829. }
  1830. return NULL;
  1831. }
  1832. int CXTPReportControl::GetReportAreaRows(int nStartRow, BOOL bMoveDown)
  1833. {
  1834. int nDirection = bMoveDown ? +1 : -1;
  1835. int top = m_rcReportArea.top;
  1836. CClientDC dc(this);
  1837. int nHeaderWidth = GetReportHeader()->GetWidth();
  1838. for (int i = nStartRow; (i < m_pRows->GetCount() && i >= 0); i += nDirection)
  1839. {
  1840. CXTPReportRow* pRow = m_pRows->GetAt(i);
  1841. ASSERT(pRow);
  1842. if (!pRow)
  1843. continue;
  1844. int rowHeight = pRow->GetHeight(&dc, nHeaderWidth);
  1845. if (top + rowHeight > m_rcReportArea.bottom)
  1846. return bMoveDown ? i - nStartRow - 1 : nStartRow - i - 1;
  1847. top += rowHeight;
  1848. }
  1849. return bMoveDown ? m_pRows->GetCount() - nStartRow : nStartRow;
  1850. }
  1851. void CXTPReportControl::AdjustLayout()
  1852. {
  1853. if (GetSafeHwnd() == 0)
  1854. return;
  1855. CXTPClientRect rc(this);
  1856. int nHeaderWidth = m_rcHeaderArea.Width();
  1857. CXTPReportHeader* pHeader = GetReportHeader();
  1858. int nGroupByHeight = (m_bGroupByEnabled && pHeader) ? pHeader->GetGroupByHeight() : 0;
  1859. m_rcGroupByArea.SetRect(0, 0, rc.Width(), nGroupByHeight);
  1860. int nHeaderHeight = 0;
  1861. int nFooterHeight = 0;
  1862. int nHeaderRecordsHeight = 0;
  1863. int nFooterRecordsHeight = 0;
  1864. if (m_bHeaderVisible)
  1865. {
  1866. CWindowDC dc (this);
  1867. nHeaderHeight = GetPaintManager()->GetHeaderHeight(this, &dc);
  1868. }
  1869. if (m_bFooterVisible)
  1870. {
  1871. CWindowDC dc (this);
  1872. nFooterHeight = GetPaintManager()->GetFooterHeight(this, &dc);
  1873. }
  1874. // header records divider
  1875. int nHeaderDividerHeight = GetHeaderRowsDividerHeight();
  1876. int nFooterDividerHeight = GetFooterRowsDividerHeight();
  1877. // header records height
  1878. if (m_bHeaderRecordsVisible)
  1879. {
  1880. nHeaderRecordsHeight = GetRowsHeight(m_pHeaderRows, rc.Width());
  1881. }
  1882. else
  1883. nHeaderDividerHeight = 0;
  1884. // footer records height
  1885. if (m_bFooterRecordsVisible)
  1886. {
  1887. nFooterRecordsHeight = GetRowsHeight(m_pFooterRows, rc.Width());
  1888. }
  1889. m_rcHeaderArea.SetRect(0, m_rcGroupByArea.bottom, rc.Width(), m_rcGroupByArea.bottom + nHeaderHeight);
  1890. m_rcHeaderRecordsArea.SetRect(0, m_rcHeaderArea.bottom, rc.Width(), m_rcHeaderArea.bottom + nHeaderRecordsHeight);
  1891. m_rcHeaderRecordsDividerArea.SetRect(0, m_rcHeaderRecordsArea.bottom, rc.Width(), m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight);
  1892. int nFreeHeight = rc.Height() - nGroupByHeight- nHeaderHeight - nFooterHeight - nHeaderRecordsHeight - nFooterRecordsHeight - nHeaderDividerHeight - nFooterDividerHeight;
  1893. BOOL bPinned = FALSE;
  1894. if (m_bFooterRecordsVisible && m_bPinFooterRecords)
  1895. {
  1896. int nBodyRowsHeight = GetRowsHeight(m_pRows, rc.Width(), nFreeHeight);
  1897. if (nBodyRowsHeight < nFreeHeight)
  1898. {
  1899. // footer records immediately after body records
  1900. m_rcFooterRecordsArea.SetRect(0, m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight + nFooterDividerHeight + nBodyRowsHeight, rc.Width(),
  1901. m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight + nFooterDividerHeight + nBodyRowsHeight + nFooterRecordsHeight);
  1902. m_rcFooterRecordsDividerArea.SetRect(0,m_rcFooterRecordsArea.top - nFooterDividerHeight,rc.Width(), m_rcFooterRecordsArea.top);
  1903. bPinned = TRUE;
  1904. }
  1905. }
  1906. if (!bPinned)
  1907. {
  1908. if (rc.Height() - nFooterHeight - nFooterRecordsHeight > m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight)
  1909. {
  1910. // there can be empty space between body rows and footer records rows
  1911. m_rcFooterRecordsArea.SetRect(0, rc.Height() - nFooterHeight - nFooterRecordsHeight, rc.Width(), rc.Height() - nFooterHeight);
  1912. }
  1913. else
  1914. {
  1915. // no place for body records (between header and footer records)
  1916. m_rcFooterRecordsArea.SetRect(0, m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight, rc.Width(), m_rcHeaderRecordsArea.bottom + nFooterRecordsHeight + nHeaderDividerHeight);
  1917. }
  1918. m_rcFooterRecordsDividerArea.SetRect(0,m_rcFooterRecordsArea.top - nFooterDividerHeight -1,rc.Width(), m_rcFooterRecordsArea.top);
  1919. }
  1920. m_rcFooterArea.SetRect(0, rc.Height() - nFooterHeight, rc.Width(), rc.Height());
  1921. m_rcReportArea.SetRect(0, m_rcHeaderRecordsArea.bottom + nHeaderDividerHeight, rc.Width(), m_rcFooterRecordsArea.top - nFooterDividerHeight);
  1922. if (nHeaderWidth != m_rcHeaderArea.Width() && pHeader)
  1923. {
  1924. pHeader->AdjustColumnsWidth(m_rcHeaderArea.Width());
  1925. }
  1926. }
  1927. CScrollBar* CXTPReportControl::GetScrollBarCtrl(int nBar) const
  1928. {
  1929. if (DYNAMIC_DOWNCAST(CView, GetParent()))
  1930. return GetParent()->GetScrollBarCtrl(nBar);
  1931. return 0;
  1932. }
  1933. void CXTPReportControl::AdjustScrollBars()
  1934. {
  1935. if (GetSafeHwnd() == 0)
  1936. return;
  1937. EditItem(NULL);
  1938. int nHeight = m_rcReportArea.Height();
  1939. if (nHeight <= 0)
  1940. return;
  1941. BeginUpdate();
  1942. int nCount = m_pRows->GetCount() - 1;
  1943. int nLinesCount = nCount;
  1944. int nHeaderWidth = GetReportHeader()->GetWidth();
  1945. {
  1946. CClientDC dc(this);
  1947. for (; nLinesCount >= 0; nLinesCount--)
  1948. {
  1949. nHeight -= m_pRows->GetAt(nLinesCount)->GetHeight(&dc, nHeaderWidth);
  1950. if (nHeight < 0)
  1951. {
  1952. if (nLinesCount != nCount)
  1953. nLinesCount++;
  1954. break;
  1955. }
  1956. }
  1957. }
  1958. nLinesCount = max(nLinesCount, 0);
  1959. if (m_nTopRow > nLinesCount)
  1960. {
  1961. m_nTopRow = nLinesCount;
  1962. SetScrollPos(SB_VERT, m_nTopRow);
  1963. }
  1964. BOOL bEnabled = nLinesCount > 0;
  1965. if (bEnabled)
  1966. {
  1967. SCROLLINFO  si ;
  1968. si.cbSize = sizeof(SCROLLINFO);
  1969. si.nPage = nCount - nLinesCount + 1;
  1970. si.nMax = nCount;
  1971. si.nMin = 0 ;
  1972. si.fMask = SIF_PAGE | SIF_RANGE ;
  1973. SetScrollInfo(SB_VERT, &si) ;
  1974. }
  1975. EnableScrollBarCtrl(SB_VERT, bEnabled);
  1976. ::EnableScrollBar(m_hWnd, SB_VERT, (bEnabled && IsWindowEnabled()) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
  1977. m_bVScrollBarVisible = bEnabled;
  1978. if (!GetReportHeader()->m_bAutoColumnSizing)
  1979. {
  1980. if (m_bFullColumnScrolling)
  1981. {
  1982. CXTPReportColumn *pPrev = NULL, *pCurr = NULL, *pNext = NULL;
  1983. int nScrollPos, nScrollMax;
  1984. GetReportHeader()->GetFulColScrollInfo(pPrev, pCurr, pNext, nScrollPos, nScrollMax);
  1985. bEnabled = nScrollMax > 1;
  1986. if (bEnabled)
  1987. {
  1988. SCROLLINFO  si ;
  1989. si.cbSize = sizeof(SCROLLINFO);
  1990. si.nPage = 1;
  1991. si.nMax = nScrollMax - 1;
  1992. si.nMin = 0;
  1993. si.nPos = nScrollPos;
  1994. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  1995. SetScrollInfo(SB_HORZ, &si) ;
  1996. }
  1997. else
  1998. {
  1999. m_nLeftOffset = 0;
  2000. SetScrollPos(SB_HORZ, m_nLeftOffset);
  2001. }
  2002. }
  2003. else
  2004. {
  2005. nHeaderWidth = max(GetReportHeader()->GetWidth() - m_rcReportArea.Width(), 0);
  2006. if (m_nLeftOffset > nHeaderWidth)
  2007. {
  2008. m_nLeftOffset = nHeaderWidth;
  2009. SetScrollPos(SB_HORZ, m_nLeftOffset);
  2010. }
  2011. bEnabled = nHeaderWidth > 0;
  2012. if (bEnabled)
  2013. {
  2014. SCROLLINFO  si ;
  2015. si.cbSize = sizeof(SCROLLINFO);
  2016. si.nPage = m_rcReportArea.Width();
  2017. si.nMax = si.nPage + nHeaderWidth;
  2018. si.nMin = 0 ;
  2019. si.fMask = SIF_PAGE | SIF_RANGE ;
  2020. SetScrollInfo(SB_HORZ, &si) ;
  2021. }
  2022. }
  2023. EnableScrollBarCtrl(SB_HORZ, bEnabled);
  2024. m_bHScrollBarVisible = bEnabled;
  2025. ::EnableScrollBar(m_hWnd, SB_HORZ, (bEnabled && IsWindowEnabled()) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
  2026. }
  2027. AdjustLayout();
  2028. EndUpdate();
  2029. }
  2030. void CXTPReportControl::SetFullColumnScrolling(BOOL bSet)
  2031. {
  2032. m_bFullColumnScrolling = bSet;
  2033. if (m_hWnd)
  2034. {
  2035. CXTPReportControl::OnHScroll(SB_TOP, 0, NULL);
  2036. RedrawControl();
  2037. UpdateWindow();
  2038. AdjustScrollBars();
  2039. }
  2040. }
  2041. BOOL CXTPReportControl::SetWatermarkBitmap(HBITMAP hBitmap, BYTE Transparency)
  2042. {
  2043. m_WatermarkTransparency = Transparency;
  2044. // if bitmap handle is NULL, remove watermark bitmap
  2045. if(!hBitmap)
  2046. {
  2047. ::DeleteObject(m_hbmpWatermark);
  2048. m_hbmpWatermark = NULL;
  2049. }
  2050. else
  2051. {
  2052. // remove old watermark bitmap if one is
  2053. if(m_hbmpWatermark)
  2054. {
  2055. ::DeleteObject(m_hbmpWatermark);
  2056. m_hbmpWatermark = NULL;
  2057. }
  2058. // add new watermark bitmap
  2059. m_hbmpWatermark = CXTPImageManagerIcon::CopyAlphaBitmap(hBitmap);
  2060. if(!m_hbmpWatermark)
  2061. return FALSE;
  2062. if(!CBitmap::FromHandle(m_hbmpWatermark)->GetBitmap(&m_bmWatermark))
  2063. {
  2064. ::DeleteObject(m_hbmpWatermark);
  2065. m_hbmpWatermark = NULL;
  2066. return FALSE;
  2067. }
  2068. BOOL bAlphaBitmap = m_bmWatermark.bmBitsPixel == 32;
  2069. // create an alpha bitmap if the bitmap supplied isn't an alpha one
  2070. if(!bAlphaBitmap)
  2071. {
  2072. CXTPCompatibleDC memWatermarkDC(NULL, m_hbmpWatermark);
  2073. CXTPImageManagerIcon::DrawAlphaBitmap(&memWatermarkDC, m_hbmpWatermark, CPoint(0, 0), CSize(m_bmWatermark.bmWidth, m_bmWatermark.bmHeight));
  2074. }
  2075. }
  2076. return TRUE;
  2077. }
  2078. BOOL CXTPReportControl::SetWatermarkBitmap(LPCTSTR szPath, BYTE Transparency)
  2079. {
  2080. m_WatermarkTransparency = Transparency;
  2081. // if path is empty, remove watermark bitmap
  2082. if(_tcslen(szPath) == 0)
  2083. {
  2084. ::DeleteObject(m_hbmpWatermark);
  2085. m_hbmpWatermark = NULL;
  2086. }
  2087. else
  2088. {
  2089. // remove old watermark bitmap if one is
  2090. if(m_hbmpWatermark)
  2091. {
  2092. ::DeleteObject(m_hbmpWatermark);
  2093. m_hbmpWatermark = NULL;
  2094. }
  2095. // add new watermark bitmap
  2096. BOOL bAlphaBitmap = FALSE;
  2097. m_hbmpWatermark = CXTPImageManagerIcon::LoadBitmapFromFile(szPath, &bAlphaBitmap);
  2098. if(!m_hbmpWatermark)
  2099. return FALSE;
  2100. if(!CBitmap::FromHandle(m_hbmpWatermark)->GetBitmap(&m_bmWatermark))
  2101. {
  2102. ::DeleteObject(m_hbmpWatermark);
  2103. m_hbmpWatermark = NULL;
  2104. return FALSE;
  2105. }
  2106. // create an alpha bitmap if the bitmap supplied isn't an alpha one
  2107. if(!bAlphaBitmap)
  2108. {
  2109. CXTPCompatibleDC memWatermarkDC(NULL, m_hbmpWatermark);
  2110. CXTPImageManagerIcon::DrawAlphaBitmap(&memWatermarkDC, m_hbmpWatermark, CPoint(0, 0), CSize(m_bmWatermark.bmWidth, m_bmWatermark.bmHeight));
  2111. }
  2112. }
  2113. return TRUE;
  2114. }
  2115. //////////////////////////////////////////////////////////////////////////
  2116. // CXTPReportControl message handlers
  2117. void CXTPReportControl::OnPaint()
  2118. {
  2119. CPaintDC dc(this);      // device context for painting
  2120. CXTPClientRect rc(this);
  2121. // ensure visible row and column if first started
  2122. if(m_nEnsureVisibleRowIdx >= 0)
  2123. {
  2124. EnsureVisible(GetRows()->GetAt(m_nEnsureVisibleRowIdx));
  2125. m_nEnsureVisibleRowIdx = -1;
  2126. }
  2127. if(m_nEnsureVisibleColumnIdx >= 0)
  2128. {
  2129. EnsureVisible(GetColumns()->GetAt(m_nEnsureVisibleColumnIdx));
  2130. m_nEnsureVisibleColumnIdx = -1;
  2131. }
  2132. // start counting drawing time
  2133. #ifdef XTP_DEBUG
  2134. LARGE_INTEGER iStartCount;
  2135. QueryPerformanceCounter(&iStartCount);
  2136. #endif
  2137. if (m_nLockUpdateCount == 0 && (IsChanged() || m_bmpCache.GetSafeHandle() == 0))
  2138. {
  2139. CDC memDC;
  2140. memDC.CreateCompatibleDC(&dc);
  2141. m_bmpCache.DeleteObject();
  2142. m_bmpCache.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
  2143. CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
  2144. OnDraw(&memDC);
  2145. // update flag
  2146. SetChanged(FALSE);
  2147. if (!IsWindowEnabled())
  2148. {
  2149. XTPImageManager()->DisableBitmap(memDC, rc, RGB(250, 250, 250), RGB(128, 128, 128));
  2150. }
  2151. if(m_hbmpWatermark)
  2152. {
  2153. CRect rcDst(GetReportRectangle());
  2154. if(IsHeaderRowsVisible())
  2155. rcDst.top = m_rcHeaderArea.top;
  2156. if(IsFooterRowsVisible())
  2157. rcDst.bottom = m_rcFooterArea.bottom;
  2158. CRect rcAll(rcDst);
  2159. CRect rcSrc(0, 0, m_bmWatermark.bmWidth, m_bmWatermark.bmHeight);
  2160. // no stretch
  2161. if(!(GetWatermarkAlignment() & xtpReportWatermarkStretch))
  2162. {
  2163. if(rcSrc.Width() > rcDst.Width())
  2164. rcSrc.right = rcSrc.left + rcDst.Width();
  2165. else
  2166. rcDst.right = rcDst.left + rcSrc.Width();
  2167. if(rcSrc.Height() > rcDst.Height())
  2168. rcSrc.bottom = rcSrc.top + rcDst.Height();
  2169. else
  2170. rcDst.bottom = rcDst.top + rcSrc.Height();
  2171. }
  2172. // enlarge only
  2173. if((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkEnlargeOnly))
  2174. {
  2175. if(rcSrc.Width() > rcDst.Width())
  2176. rcSrc.right = rcSrc.left + rcDst.Width();
  2177. if(rcSrc.Height() > rcDst.Height())
  2178. rcSrc.bottom = rcSrc.top + rcDst.Height();
  2179. }
  2180. // shrink only
  2181. if((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkShrinkOnly))
  2182. {
  2183. if(rcSrc.Width() < rcDst.Width())
  2184. rcDst.right = rcDst.left + rcSrc.Width();
  2185. if(rcSrc.Height() < rcDst.Height())
  2186. rcDst.bottom = rcDst.top + rcSrc.Height();
  2187. }
  2188. // preserve aspect ratio
  2189. if((GetWatermarkAlignment() & xtpReportWatermarkStretch) && (GetWatermarkAlignment() & xtpReportWatermarkPreserveRatio))
  2190. {
  2191. if(rcDst.Width() > (rcDst.Height() * rcSrc.Width() / rcSrc.Height()))
  2192. rcDst.right = rcDst.left + rcDst.Height() * rcSrc.Width() / rcSrc.Height();
  2193. if(rcDst.Height() > (rcDst.Width() * rcSrc.Height() / rcSrc.Width()))
  2194. rcDst.bottom = rcDst.top + rcDst.Width() * rcSrc.Height() / rcSrc.Width();
  2195. }
  2196. // alignment
  2197. //          if(!(GetWatermarkAlignment() & xtpReportWatermarkStretch))
  2198. {
  2199. // horizontal
  2200. switch(GetWatermarkAlignment() & xtpReportWatermarkHmask)
  2201. {
  2202. // center
  2203. case xtpReportWatermarkCenter :
  2204. rcDst.OffsetRect((rcAll.Width() - rcDst.Width()) / 2, 0);
  2205. break;
  2206. // right
  2207. case xtpReportWatermarkRight :
  2208. rcDst.OffsetRect(rcAll.Width() - rcDst.Width(), 0);
  2209. break;
  2210. // left
  2211. default :
  2212. break;
  2213. }
  2214. // vertical
  2215. switch(GetWatermarkAlignment() & xtpReportWatermarkVmask)
  2216. {
  2217. // center
  2218. case xtpReportWatermarkVCenter :
  2219. rcDst.OffsetRect(0, (rcAll.Height() - rcDst.Height()) / 2);
  2220. break;
  2221. // bottom
  2222. case xtpReportWatermarkBottom:
  2223. rcDst.OffsetRect(0, rcAll.Height() - rcDst.Height());
  2224. break;