You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

633 lines
14 KiB
C++

// 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;
}
}
}