// XTPReportInplaceControls.cpp // // This file is a part of the XTREME REPORTCONTROL MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "Common/Tmschema.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPCustomHeap.h" #include "Common/XTPSmartPtrInternalT.h" #include "Common/XTPColorManager.h" #include "XTPReportDefines.h" #include "XTPReportRecordItem.h" #include "XTPReportControl.h" #include "XTPReportInplaceControls.h" #include "XTPReportColumn.h" //#include "ItemTypes/XTPReportRecordItemText.h" #include "XTPReportRecordItemConstraint.h" #include "XTPReportPaintManager.h" #include "XTPReportRow.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CXTPReportInplaceControl::CXTPReportInplaceControl() { } CXTPReportInplaceControl::~CXTPReportInplaceControl() { SetItemArgs(0); } void CXTPReportInplaceControl::SetItemArgs(XTP_REPORTRECORDITEM_ARGS* pItemArgs) { if (pItemArgs) { pItemArgs->AddRef(); Release(); pItem = pItemArgs->pItem; pControl = pItemArgs->pControl; pRow = pItemArgs->pRow; pColumn = pItemArgs->pColumn; rcItem = pItemArgs->rcItem; } else { Release(); pItem = NULL; pControl = NULL; pRow = NULL; pColumn = NULL; } } ////////////////////////////////////////////////////////////////////////// // CXTPReportInplaceButton CXTPReportInplaceButton::CXTPReportInplaceButton(UINT nID) { m_nID = nID; m_nWidth = 17; m_nFixedHeight = 19; m_bInsideCell = FALSE; m_nIconIndex = XTP_REPORT_NOICON; m_bPressed = m_bOver = FALSE; m_nState = 0; m_nSpinIncrement = 0; m_unSpinTimerCnt = 0; m_unSpinTimerId = 0; m_nSpinMin = INT_MIN; m_nSpinMax = INT_MAX; m_nSpinStep = 1; m_Items2Show = 10; } void CXTPReportInplaceButton::Create(XTP_REPORTRECORDITEM_ARGS* pItemArgs, CRect& rcButtons) { m_bPressed = m_bOver = FALSE; m_nState = 0; m_nSpinIncrement = 0; m_unSpinTimerCnt = 0; m_unSpinTimerId = 0; SetItemArgs(pItemArgs); CRect rect(rcButtons); if (pControl->GetPaintManager()->IsFixedInplaceButtonHeight()) { rect.bottom = min(rect.bottom, rect.top + m_nFixedHeight); } if (m_bInsideCell) { rect.right = rcButtons.left; rect.left = rect.right - m_nWidth; rcButtons.left = rect.left; } else { rect.left = rcButtons.right; rect.right = rect.left + m_nWidth; rcButtons.right = rect.right; } //to keep focused frame no touched rect.top++; rect.bottom -= 2; rect.left--; if (m_nID == XTP_ID_REPORT_COMBOBUTTON) rect.right--; if (!m_hWnd) CStatic::Create(NULL, SS_NOTIFY | WS_CHILD, rect, pItemArgs->pControl); SetWindowPos(0, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW); } BEGIN_MESSAGE_MAP(CXTPReportInplaceButton, CStatic) //{{AFX_MSG_MAP(CXTPReportInplaceButton) ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_LBUTTONDBLCLK() ON_WM_MOUSEMOVE() ON_WM_CAPTURECHANGED() ON_WM_TIMER() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CXTPReportInplaceButton::OnPaint() { CPaintDC dc(this); if (pControl) { pControl->GetPaintManager()->DrawInplaceButton(&dc, this); } } void CXTPReportInplaceButton::OnFinalRelease() { if (m_hWnd != NULL) DestroyWindow(); CCmdTarget::OnFinalRelease(); } void CXTPReportInplaceButton::OnLButtonDown(UINT, CPoint point) { switch (m_nID) { case XTP_ID_REPORT_COMBOBUTTON : m_bOver = m_bPressed = TRUE; break; case XTP_ID_REPORT_EXPANDBUTTON : m_bOver = m_bPressed = TRUE; break; case XTP_ID_REPORT_SPINBUTTON : { CXTPClientRect rect(this); m_bOver = TRUE; rect.bottom -= rect.Height() / 2; m_nState = rect.PtInRect(point) ? SPNP_UP : SPNP_DOWN; m_nSpinIncrement = m_nState == SPNP_UP ? m_nSpinStep : -m_nSpinStep; pItem->OnInplaceButtonDown(this); // start timer m_unSpinTimerCnt = 0; m_unSpinTimerId = SetTimer(1, 500, NULL); break; } } Invalidate(FALSE); SetCapture(); } void CXTPReportInplaceButton::OnLButtonUp(UINT nFlags, CPoint point) { if ((m_bPressed || m_nState) && pItem) { if (m_unSpinTimerId) { KillTimer(1); m_unSpinTimerId = 0; } m_nSpinIncrement = 0; m_unSpinTimerCnt = 0; m_bPressed = FALSE; m_nState = 0; Invalidate(FALSE); ReleaseCapture(); if (m_bOver && m_nID != XTP_ID_REPORT_SPINBUTTON) { pItem->OnInplaceButtonDown(this); } } CStatic::OnLButtonUp(nFlags, point); } void CXTPReportInplaceButton::Activate() { m_bOver = m_bPressed = TRUE; Invalidate(FALSE); SetCapture(); } void CXTPReportInplaceButton::OnLButtonDblClk(UINT nFlags, CPoint point) { UNREFERENCED_PARAMETER(nFlags); if (m_nID == XTP_ID_REPORT_SPINBUTTON) { CXTPClientRect rect(this); if (rect.PtInRect(point)) { rect.bottom -= rect.Height() / 2; m_nState = rect.PtInRect(point) ? SPNP_UP : SPNP_DOWN; m_nSpinIncrement = m_nState == SPNP_UP ? m_nSpinStep : -m_nSpinStep; pItem->OnInplaceButtonDown(this); // start timer m_unSpinTimerCnt = 0; m_unSpinTimerId = SetTimer(1, 500, NULL); } Invalidate(FALSE); SetCapture(); } } void CXTPReportInplaceButton::OnMouseMove(UINT nFlags, CPoint point) { if (m_bPressed || m_nState) { CXTPClientRect rect(this); BOOL bOver; if (m_nID != XTP_ID_REPORT_SPINBUTTON) bOver = rect.PtInRect(point); else { bOver = rect.PtInRect(point) && (point.y < (rect.bottom - rect.Height() / 2) && m_nState == SPNP_UP || point.y >= (rect.bottom - rect.Height() / 2) && m_nState == SPNP_DOWN); } if ((bOver && !m_bOver) || (!bOver && m_bOver)) { m_bOver = bOver; if (m_nID == XTP_ID_REPORT_SPINBUTTON) { if (m_bOver) { m_nSpinIncrement = m_nState == SPNP_UP ? 1 : -1; m_unSpinTimerCnt = 0; m_unSpinTimerId = SetTimer(1, 500, NULL); // start timer } else if (m_unSpinTimerId) { // stop timer KillTimer(1); m_nSpinIncrement = 0; m_unSpinTimerCnt = 0; m_unSpinTimerId = 0; } } Invalidate(FALSE); } } CStatic::OnMouseMove(nFlags, point); } void CXTPReportInplaceButton::OnCaptureChanged(CWnd* pWnd) { m_bPressed = FALSE; m_nState = 0; Invalidate(FALSE); CStatic::OnCaptureChanged(pWnd); } void CXTPReportInplaceButton::OnTimer(UINT_PTR nIDEvent) { if (m_unSpinTimerCnt == 0 && abs(m_nSpinIncrement) < 10) { // first timer event, reset timer KillTimer(1); m_unSpinTimerId = SetTimer(1, 100, NULL); } m_unSpinTimerCnt++; if (m_unSpinTimerCnt >= 20 && abs(m_nSpinIncrement < 100000)) { m_nSpinIncrement *= 10; m_unSpinTimerCnt = 0; } pItem->OnInplaceButtonDown(this); CStatic::OnTimer(nIDEvent); } ////////////////////////////////////////////////////////////////////////// // CXTPReportInplaceList CXTPReportInplaceList::CXTPReportInplaceList() { m_bApply = FALSE; m_dwLastKeyDownTime = 0; m_Items2Show = 10; } void CXTPReportInplaceList::Create(XTP_REPORTRECORDITEM_ARGS* pItemArgs, CXTPReportRecordItemConstraints* pConstaints) { SetItemArgs(pItemArgs); CRect rect(pItemArgs->rcItem); if (!m_hWnd) { CListBox::CreateEx(WS_EX_TOOLWINDOW | (pControl->GetExStyle() & WS_EX_LAYOUTRTL), _T("LISTBOX"), _T(""), LBS_NOTIFY | WS_CHILD | WS_BORDER | WS_VSCROLL, CRect(0, 0, 0, 0), pControl, 0); SetOwner(pControl); } SetFont(pControl->GetPaintManager()->GetTextFont()); ResetContent(); int dx = rect.right - rect.left + 1; CWindowDC dc(pControl); CXTPFontDC font(&dc, GetFont()); int nThumbLength = GetSystemMetrics(SM_CXHTHUMB); CString strCaption = pItem->GetCaption(pColumn); DWORD dwData = pItem->GetSelectedConstraintData(pItemArgs); for (int i = 0; i < pConstaints->GetCount(); i++) { CXTPReportRecordItemConstraint* pConstaint = pConstaints->GetAt(i); CString str = pConstaint->m_strConstraint; int nIndex = AddString(str); SetItemDataPtr(nIndex, pConstaint); dx = max(dx, dc.GetTextExtent(str).cx + nThumbLength); if ((dwData == (DWORD)-1 && strCaption == str) || (dwData == pConstaint->m_dwData)) SetCurSel(nIndex); } int nHeight = GetItemHeight(0); rect.top = rect.bottom; //rect.bottom += nHeight * min(10, GetCount()) + 2; rect.bottom += nHeight * min(m_Items2Show, GetCount()) + 2; rect.left = rect.right - dx; pControl->ClientToScreen(&rect); CRect rcWork = XTPMultiMonitor()->GetWorkArea(rect); if (rect.bottom > rcWork.bottom && rect.top > rcWork.CenterPoint().y) rect.OffsetRect(0, - rect.Height() - pItemArgs->rcItem.Height()); if (rect.left < rcWork.left) rect.OffsetRect(rcWork.left - rect.left, 0); if (rect.right > rcWork.right) rect.OffsetRect(rcWork.right - rect.right, 0); SetFocus(); if (!m_hWnd) // Can be destroyed after focus set return; SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, 0); ModifyStyle(WS_CHILD, WS_POPUP); SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, (LONG_PTR)pControl->m_hWnd); SetWindowPos(&CWnd::wndTopMost, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER); CXTPMouseMonitor::SetupHook(this); } BEGIN_MESSAGE_MAP(CXTPReportInplaceList, CListBox) //{{AFX_MSG_MAP(CXTPReportInplaceList) ON_WM_MOUSEACTIVATE() ON_WM_KILLFOCUS() ON_WM_LBUTTONUP() ON_WM_CHAR() ON_WM_KEYDOWN() ON_WM_SYSKEYDOWN() ON_WM_GETDLGCODE() ON_WM_NCPAINT() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CXTPReportInplaceList::OnNcPaint() { Default(); CWindowDC dc(this); CXTPWindowRect rc(this); rc.OffsetRect(-rc.TopLeft()); dc.Draw3dRect(rc, GetSysColor(COLOR_WINDOWFRAME), GetSysColor(COLOR_WINDOWFRAME)); } int CXTPReportInplaceList::OnMouseActivate(CWnd* /*pDesktopWnd*/, UINT /*nHitTest*/, UINT /*message*/) { return MA_NOACTIVATE; } UINT CXTPReportInplaceList::OnGetDlgCode() { return DLGC_WANTALLKEYS; } void CXTPReportInplaceList::SetItemArgs(XTP_REPORTRECORDITEM_ARGS* pItemArgs) { m_bApply = FALSE; CXTPReportInplaceControl::SetItemArgs(pItemArgs); m_dwLastKeyDownTime = 0; m_strHotSearchContext.Empty(); } void CXTPReportInplaceList::PostNcDestroy() { CXTPMouseMonitor::SetupHook(NULL); SetItemArgs(NULL); CListBox::PostNcDestroy(); } void CXTPReportInplaceList::OnKillFocus(CWnd* pNewWnd) { //ASSERT(pItem || m_bApply); if (pItem && !m_bApply) pItem->OnEditCanceled(this); CListBox::OnKillFocus(pNewWnd); DestroyWindow(); } void CXTPReportInplaceList::OnLButtonUp(UINT, CPoint point) { CXTPClientRect rc(this); if (rc.PtInRect(point)) Apply(); else Cancel(); } void CXTPReportInplaceList::Cancel() { m_bApply = FALSE; GetOwner()->SetFocus(); } void CXTPReportInplaceList::Apply() { if (!pControl) return; CXTPReportControl* pReportControl = pControl; int nIndex = GetCurSel(); if (nIndex != LB_ERR) { m_bApply = TRUE; CXTPReportRecordItemConstraint* pConstraint = (CXTPReportRecordItemConstraint*)GetItemDataPtr(nIndex); XTP_REPORTRECORDITEM_ARGS itemArgs = *((XTP_REPORTRECORDITEM_ARGS*)this); itemArgs.AddRef(); pItem->OnConstraintChanged(&itemArgs, pConstraint); pReportControl->RedrawControl(); pReportControl->SendMessageToParent(itemArgs.pRow, itemArgs.pItem, itemArgs.pColumn, XTP_NM_REPORT_VALUECHANGED, 0); itemArgs.Release(); } pReportControl->SetFocus(); } void CXTPReportInplaceList::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { UNREFERENCED_PARAMETER(nRepCnt); UNREFERENCED_PARAMETER(nFlags); const DWORD cwdHotSearchTomeOut_ms = 1300; DWORD dwTime = GetTickCount(); if (dwTime - m_dwLastKeyDownTime > cwdHotSearchTomeOut_ms) m_strHotSearchContext.Empty(); m_dwLastKeyDownTime = dwTime; //---------------------------------------------- m_strHotSearchContext += (TCHAR)nChar; int nIndex = GetCurSel(); if (nIndex == LB_ERR) nIndex = 0; int nFindIdx = FindString(nIndex, m_strHotSearchContext); if (nFindIdx == LB_ERR && nIndex > 0) nFindIdx = FindString(0, m_strHotSearchContext); if (nFindIdx != LB_ERR) { SetCurSel(nFindIdx); if (nIndex != nFindIdx) OnSelectionChanged(nFindIdx); } } void CXTPReportInplaceList::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch (nChar) { case VK_UP: case VK_DOWN: case VK_PRIOR: case VK_NEXT: case VK_HOME: case VK_END: m_strHotSearchContext.Empty(); } //---------------------------------------------- if (nChar == VK_ESCAPE) { Cancel(); } else if (nChar == VK_RETURN || nChar == VK_F4) { Apply(); } else { int nPrevSel = CListBox::GetCurSel(); CListBox::OnKeyDown(nChar, nRepCnt, nFlags); int nActualSel = CListBox::GetCurSel(); if (nPrevSel != nActualSel) OnSelectionChanged(nActualSel); } } BOOL CXTPReportInplaceList::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN && pControl) { if (!pControl->OnPreviewKeyDown((UINT&)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam)) ) return TRUE; } if (pMsg->message == WM_KEYDOWN && IsDialogMessage(pMsg)) return TRUE; return CListBox::PreTranslateMessage(pMsg); } void CXTPReportInplaceList::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_DOWN || nChar == VK_UP) { Apply(); return; } CListBox::OnSysKeyDown(nChar, nRepCnt, nFlags); } void CXTPReportInplaceList::OnSelectionChanged(int nLBIndex) { CString strActual, str; CListBox::GetText(nLBIndex,strActual); CXTPReportRecordItemEditOptions* pEditOptions = pItem->GetEditOptions(pColumn); CXTPReportRecordItemConstraints* pConstraints = pEditOptions->GetConstraints(); int nCount = pConstraints->GetCount(); for (int nIndex = 0; nIndex < nCount; nIndex++) { CXTPReportRecordItemConstraint* pConstraint = pConstraints->GetAt(nIndex); str = pConstraint->m_strConstraint; if (strActual.CompareNoCase(str) == 0) { ((CXTPReportControl*) pControl)->OnConstraintSelecting(pRow, pItem, pColumn, pConstraint); break; } } }