// GridCustomHeapView.cpp // // (c)1998-2025 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 "GridCustomHeap.h" #include "GridCustomHeapDoc.h" #include "GridCustomHeapView.h" #include "MainFrm.h" #ifdef _DEBUG # define new DEBUG_NEW # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define COLUMN_CHECKBOX 0 #define COLUMN_TEXT 1 #define COLUMN_COSTRAINT 2 #define COLUMN_NUMBER 3 #define COLUMN_DATETIME 4 #define COLUMN_VARIANT 5 // XTP_DECLARE_HEAP_ALLOCATOR(CGridStringAllocator) // XTP_IMPLEMENT_HEAP_ALLOCATOR(CGridStringAllocator, TRUE) // typedef CXTPHeapStringT CGridString; ///////////////////////////////////////////////////////////////////////////// // CGridCustomHeapView IMPLEMENT_DYNCREATE(CGridCustomHeapView, CXTPGridView) BEGIN_MESSAGE_MAP(CGridCustomHeapView, CXTPGridView) //{{AFX_MSG_MAP(CGridCustomHeapView) ON_COMMAND(ID_ADD_10K_RECORDS, OnAdd10kRecords) ON_COMMAND(ID_ADD_20K_RECORDS, OnAdd20kRecords) ON_COMMAND(ID_BATCHADD_10K_RECORDS, OnBatchAdd10kRecords) ON_COMMAND(ID_BATCHADD_20K_RECORDS, OnBatchAdd20kRecords) ON_COMMAND(ID_REMOVE_ALL_RECORDS, OnRemoveAllRecords) ON_COMMAND(ID_VIEW_PREVIEW_MODE, OnViewPreviewMode) ON_UPDATE_COMMAND_UI(ID_VIEW_PREVIEW_MODE, OnUpdateViewPreviewMode) ON_COMMAND(ID_REMOVE_HALF_RECORDS, OnRemoveHalfRecords) ON_COMMAND(ID_FREE_EXTRA_BATCH_DATA, OnFreeExtraBatchData) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGridCustomHeapView construction/destruction CGridCustomHeapView::CGridCustomHeapView() { // TODO: add construction code here } CGridCustomHeapView::~CGridCustomHeapView() { } BOOL CGridCustomHeapView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CGridCustomHeapView printing BOOL CGridCustomHeapView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CGridCustomHeapView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CGridCustomHeapView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add cleanup after printing } ///////////////////////////////////////////////////////////////////////////// // CGridCustomHeapView diagnostics #ifdef _DEBUG void CGridCustomHeapView::AssertValid() const { CView::AssertValid(); } void CGridCustomHeapView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CGridCustomHeapDoc* CGridCustomHeapView::GetDocument() // non-debug version is inline { _ASSERTE(m_pDocument->IsKindOf(RUNTIME_CLASS(CGridCustomHeapDoc))); return (CGridCustomHeapDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CGridCustomHeapView message handlers void CGridCustomHeapView::OnInitialUpdate() { CXTPGridView::OnInitialUpdate(); // GetGridCtrl().ShowHeader(); CXTPGridControl& wndGrid = GetGridCtrl(); wndGrid.GetGridHeader()->SetAutoColumnSizing(FALSE); // wndGrid.AllowEdit(TRUE); // wndGrid.FocusSubItems(TRUE); wndGrid.ShowGroupBy(); wndGrid.EnableDragDrop(_T("GridCustomGeapSample"), xtpGridAllowDrag | xtpGridAllowDrop); //----------------------------------------------------------------------- wndGrid.AddColumn(new CXTPGridColumn(COLUMN_CHECKBOX, _T("Checkbox"), 100)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_TEXT, _T("Text"), 150)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_COSTRAINT, _T("Constraint"), 80, FALSE)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_NUMBER, _T("Number"), 100)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_DATETIME, _T("Date"), 150)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_VARIANT, _T("VARIANT"), 180)); for (int i = 0; i < 5; i++) { wndGrid.AddColumn(new CXTPGridColumn(COLUMN_VARIANT + i + 1, _T("Text"), 150)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_VARIANT + i + 2, _T("Number"), 70)); wndGrid.AddColumn(new CXTPGridColumn(COLUMN_VARIANT + i + 3, _T("Date"), 150)); } wndGrid.GetColumns()->GetAt(COLUMN_COSTRAINT)->GetEditOptions()->m_bConstraintEdit = TRUE; wndGrid.GetColumns()->GetAt(COLUMN_COSTRAINT)->GetEditOptions()->AddComboButton(); wndGrid.GetColumns()->GetAt(COLUMN_COSTRAINT)->GetEditOptions()->AddConstraint(_T("State 1"), 1); wndGrid.GetColumns()->GetAt(COLUMN_COSTRAINT)->GetEditOptions()->AddConstraint(_T("State 2"), 2); wndGrid.GetColumns()->GetAt(COLUMN_COSTRAINT)->GetEditOptions()->AddConstraint(_T("State 3"), 3); } void CGridCustomHeapView::AddRecord(int nState, LPCTSTR pcszText, double dNumber, const COleDateTime& dtDate, const COleVariant& varVariant, XTPGridCheckState checkState) { static const CString cstrNumberFormat(_T("%06.3f")); CXTPGridRecord* pRec = new CXTPGridRecord; CString strConstraint = GetGridCtrl() .GetColumns() ->GetAt(COLUMN_COSTRAINT) ->GetEditOptions() ->GetConstraints() ->GetAt(nState) ->m_strConstraint; pRec->AddItem(new CXTPGridRecordItemCheckbox(checkState, TRUE)); pRec->AddItem(new CXTPGridRecordItemText(pcszText)); pRec->AddItem(new CXTPGridRecordItemText(strConstraint)); pRec->AddItem(new CXTPGridRecordItemNumber(dNumber, cstrNumberFormat)); pRec->AddItem(new CXTPGridRecordItemDateTime(dtDate)); pRec->AddItem(new CXTPGridRecordItemVariant(varVariant)); for (int i = 0; i < 5; i++) { pRec->AddItem(new CXTPGridRecordItemText(pcszText)); pRec->AddItem(new CXTPGridRecordItemNumber(dNumber, cstrNumberFormat)); pRec->AddItem(new CXTPGridRecordItemDateTime(dtDate)); } CString strPreviewText; strPreviewText.Format(_T("%s, %s, %s, %s, %s"), pRec->GetItem(0)->GetCaption(NULL), pRec->GetItem(1)->GetCaption(NULL), pRec->GetItem(2)->GetCaption(NULL), pRec->GetItem(3)->GetCaption(NULL), pRec->GetItem(4)->GetCaption(NULL)); CXTPGridRecordItemPreview* pPreviewItem = new CXTPGridRecordItemPreview(strPreviewText); pRec->SetPreviewItem(pPreviewItem); GetGridCtrl().AddRecord(pRec); } void CGridCustomHeapView::AddRecords(int nCountToAdd) { CWaitCursor _wc; DWORD dwTime0 = ::GetTickCount(); int nRecords0 = GetGridCtrl().GetRecords()->GetCount(); CString strText; COleVariant varVariant; XTPGridCheckState checkState = xtpGridCheckStateInvalid; CWnd* pStatusBap = &((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar; for (int i = 0; i < nCountToAdd; i++) { int n = nRecords0 + i; int nState = n % 3; strText.Format(_T("[%d] - Test TEXT item"), n + 1); // just for test double dNumber = 77.77 * (n + 11) / (double)(n / 7.11 + 1.1); COleDateTime dtDate(2000 + ((n % 2) ? 1 : -1) * i % 400, n % 12 + 1, n % 28 + 1, n * 7 % 24, n * 31 % 60, n * 11 % 60); checkState = xtpGridCheckStateUnchecked; if (n % 2 == 0) { varVariant = (long)nState; checkState = xtpGridCheckStateChecked; } else if (n % 3 == 0) { varVariant = dtDate; checkState = xtpGridCheckStateIndeterminate; } else if (n % 5 == 0) { varVariant = strText; } else { varVariant = _T("this is a VARIANT field"); } AddRecord(nState, strText, dNumber, dtDate, varVariant, checkState); if (i % 2500 == 0) { CString str; str.Format(_T("Adding Records %d %%"), (i + 1) * 100 / nCountToAdd); pStatusBap->SetWindowText(str); pStatusBap->UpdateWindow(); } } pStatusBap->SetWindowText(_T("")); DWORD dwTime1 = ::GetTickCount(); GetGridCtrl().Populate(); DWORD dwTime2 = ::GetTickCount(); UpdateTitle(dwTime1 - dwTime0, dwTime2 - dwTime1); } XTP_DECLARE_BATCH_ALLOC_OBJ_DATA(CBatchGridRecord_Data); class CBatchGridRecord : public CXTPBatchAllocObjT { public: CBatchGridRecord() { // nGrowBy parameter set to expected items count to avoid additional re-allocations. m_arrItems.SetSize(0, 20); AddItem(&m_itemText1); AddItem(&m_itemText2); AddItem(&m_itemNumber1); AddItem(&m_itemDateTime); AddItem(&m_itemVariant); for (int i = 0; i < 5; i++) { AddItem(&m_itemTextA[i]); AddItem(&m_itemNumberA[i]); AddItem(&m_itemDateTimeA[i]); } } ~CBatchGridRecord() { m_arrItems.RemoveAll(); // don't call delete for each item. } public: CXTPGridRecordItemText m_itemText1; CXTPGridRecordItemText m_itemText2; CXTPGridRecordItemNumber m_itemNumber1; CXTPGridRecordItemDateTime m_itemDateTime; CXTPGridRecordItemVariant m_itemVariant; CXTPGridRecordItemText m_itemTextA[5]; CXTPGridRecordItemNumber m_itemNumberA[5]; CXTPGridRecordItemDateTime m_itemDateTimeA[5]; }; XTP_IMPLEMENT_BATCH_ALLOC_OBJ_DATA(CBatchGridRecord_Data, CBatchGridRecord, TRUE); void CGridCustomHeapView::BatchAddRecords(int nCountToAdd) { // CBatchGridRecord_Data::m_bDestroyEmptyBlocksOnFree = TRUE; // CBatchGridRecord_Data::m_bDestroyLastEmptyBlockOnFree = TRUE; // CBatchGridRecord_Data::m_nBlockSize = 5000; CWaitCursor _wc; DWORD dwTime0 = ::GetTickCount(); int i; int nRecords0 = GetGridCtrl().GetRecords()->GetCount(); CString strText; COleVariant varVariant; CWnd* pStatusBap = &((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar; // Expand array size once to avoid additional re-allocations. GetGridCtrl().GetRecords()->SetSize(nRecords0 + nCountToAdd, 10000); for (i = 0; i < nCountToAdd; i++) { CBatchGridRecord* pRec = new CBatchGridRecord(); // GetGridCtrl().GetRecords()->Add(pRec); // Set new records to array which was previously expanded by SetSize. GetGridCtrl().GetRecords()->SetAt(nRecords0 + i, pRec); int n = nRecords0 + i; int nState = n % 3; strText.Format(_T("[%d] - Test TEXT item"), n + 1); // just for test double dNumber = 77.77 * (n + 11) / (double)(n / 7.11 + 1.1); COleDateTime dtDate(2000 + ((n % 2) ? 1 : -1) * i % 400, n % 12 + 1, n % 28 + 1, n * 7 % 24, n * 31 % 60, n * 11 % 60); if (n % 2 == 0) { varVariant = (long)nState; } else if (n % 3 == 0) { varVariant = dtDate; } else if (n % 5 == 0) { varVariant = strText; } else { varVariant = _T("this is a VARIANT field"); } static const CString cstrNumberFormat(_T("%06.3f")); CString strConstraint = GetGridCtrl() .GetColumns() ->GetAt(COLUMN_COSTRAINT) ->GetEditOptions() ->GetConstraints() ->GetAt(nState) ->m_strConstraint; pRec->m_itemText1.SetValue(strText); pRec->m_itemText2.SetValue(strConstraint); pRec->m_itemNumber1.SetValue(dNumber); pRec->m_itemNumber1.SetFormatString(cstrNumberFormat); pRec->m_itemDateTime.SetValue(dtDate); pRec->m_itemVariant.SetValue(varVariant); for (int j = 0; j < 5; j++) { pRec->m_itemTextA[j].SetValue(strText); pRec->m_itemNumberA[j].SetValue(dNumber); pRec->m_itemDateTimeA[j].SetValue(dtDate); } if (i % 2500 == 0) { CString str; str.Format(_T("Adding Records %d %%"), (i + 1) * 100 / nCountToAdd); pStatusBap->SetWindowText(str); pStatusBap->UpdateWindow(); } } pStatusBap->SetWindowText(_T("")); DWORD dwTime1 = ::GetTickCount(); GetGridCtrl().Populate(); DWORD dwTime2 = ::GetTickCount(); UpdateTitle(dwTime1 - dwTime0, dwTime2 - dwTime1); } void CGridCustomHeapView::UpdateTitle(DWORD dwAddTime, DWORD dwPopulateTime) { int nRecordsCount = GetGridCtrl().GetRecords()->GetCount(); CString strTitleNew, strTitle = GetDocument()->GetTitle(); strTitle = strTitle.SpanExcluding(_T("-")); strTitle.TrimRight(); if (dwPopulateTime != (DWORD)-1) { strTitleNew.Format(_T("%s - records count [%d], Operation time %.3f sec (add/remove ") _T("records = %.3f sec, populate = %.3f sec)"), strTitle, nRecordsCount, (double)(dwAddTime + dwPopulateTime) / 1000.0, (double)dwAddTime / 1000.0, (double)dwPopulateTime / 1000.0); } else { strTitleNew.Format(_T("%s - records count [%d], Operation %.3f sec"), strTitle, nRecordsCount, (double)(dwAddTime) / 1000.0); } GetDocument()->SetTitle(strTitleNew); // strTitle.Format(_T("Allocators: Refs (heap handle) Data = %d (%x), Row = %d (%x), Str = %d //(%x)"), CXTPGridDataAllocator::ms_dwRefs, CXTPGridDataAllocator::ms_hCustomHeap, // CXTPGridRowAllocator::ms_dwRefs, CXTPGridRowAllocator::ms_hCustomHeap, // CXTPGridStringAllocator::ms_dwRefs, CXTPGridStringAllocator::ms_hCustomHeap); // // CWnd* pStatusBap = &((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar; // pStatusBap->SetWindowText(strTitle); } void CGridCustomHeapView::OnViewPreviewMode() { GetGridCtrl().EnablePreviewMode(!GetGridCtrl().IsPreviewMode()); GetGridCtrl().AdjustScrollBars(); GetGridCtrl().RedrawControl(); } void CGridCustomHeapView::OnUpdateViewPreviewMode(CCmdUI* pCmdUI) { pCmdUI->SetCheck(GetGridCtrl().IsPreviewMode()); } void CGridCustomHeapView::OnAdd10kRecords() { // GetGridCtrl().ResetContent(); AddRecords(10000); } void CGridCustomHeapView::OnAdd20kRecords() { // GetGridCtrl().ResetContent(); AddRecords(20000); } void CGridCustomHeapView::OnBatchAdd10kRecords() { // GetGridCtrl().ResetContent(); BatchAddRecords(10000); } void CGridCustomHeapView::OnBatchAdd20kRecords() { // GetGridCtrl().ResetContent(); BatchAddRecords(20000); } void CGridCustomHeapView::OnRemoveAllRecords() { CWaitCursor _wc; DWORD dwTime0 = ::GetTickCount(); // GetGridCtrl().GetRecords()->RemoveAll(); GetGridCtrl().ResetContent(); DWORD dwTime1 = ::GetTickCount(); // GetGridCtrl().Populate(); // DWORD dwTime2 = ::GetTickCount(); UpdateTitle(dwTime1 - dwTime0, (DWORD)-1); } void CGridCustomHeapView::OnRemoveHalfRecords() { CWaitCursor _wc; DWORD dwTime0 = ::GetTickCount(); CXTPGridRecords* pRecords = GetGridCtrl().GetRecords(); int nRecordsToDel = pRecords->GetCount() / 2 + 1; CWnd* pStatusBap = &((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar; for (int i = 0; i < nRecordsToDel && pRecords->GetCount(); i++) { int nRand = (int)RAND_S(); int nIndex = (pRecords->GetCount() * nRand) % pRecords->GetCount(); if (nIndex >= 0 && nIndex < pRecords->GetCount()) pRecords->RemoveAt(nIndex); if (i % 500 == 0) { CString str; str.Format(_T("Removing Records %d %%"), (i + 1) * 100 / nRecordsToDel); pStatusBap->SetWindowText(str); pStatusBap->UpdateWindow(); } } pStatusBap->SetWindowText(_T("")); DWORD dwTime1 = ::GetTickCount(); GetGridCtrl().Populate(); DWORD dwTime2 = ::GetTickCount(); UpdateTitle(dwTime1 - dwTime0, dwTime2 - dwTime1); } void CGridCustomHeapView::OnFreeExtraBatchData() { CBatchGridRecord::FreeExtraData(); CXTPGridControl::FreeRowBatchExtraData(); }