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.
522 lines
11 KiB
C++
522 lines
11 KiB
C++
2 years ago
|
// XTPReportInplaceEdit.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
|
||
|
|
||
|
IMPLEMENT_DYNAMIC(CXTPReportInplaceEdit, CEdit)
|
||
|
|
||
|
CXTPReportInplaceEdit::CXTPReportInplaceEdit()
|
||
|
{
|
||
|
m_pSelectedConstraint = NULL;
|
||
|
m_clrText = 0;
|
||
|
m_bSetWindowText = FALSE;
|
||
|
}
|
||
|
|
||
|
CXTPReportInplaceEdit::~CXTPReportInplaceEdit()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CXTPReportInplaceEdit, CEdit)
|
||
|
//{{AFX_MSG_MAP(CXTPReportInplaceEdit)
|
||
|
ON_WM_MOUSEACTIVATE()
|
||
|
ON_WM_CTLCOLOR_REFLECT()
|
||
|
ON_CONTROL_REFLECT(EN_KILLFOCUS, OnEnKillfocus)
|
||
|
ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange)
|
||
|
ON_WM_LBUTTONDBLCLK()
|
||
|
ON_WM_KEYDOWN()
|
||
|
ON_WM_SYSKEYDOWN()
|
||
|
ON_WM_GETDLGCODE()
|
||
|
ON_WM_CHAR()
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
|
||
|
void CXTPReportInplaceEdit::HideWindow()
|
||
|
{
|
||
|
if (m_hWnd)
|
||
|
{
|
||
|
ShowWindow(SW_HIDE);
|
||
|
SetItemArgs(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::Create(XTP_REPORTRECORDITEM_ARGS* pItemArgs)
|
||
|
{
|
||
|
SetItemArgs(pItemArgs);
|
||
|
m_pSelectedConstraint = NULL;
|
||
|
|
||
|
XTP_REPORTRECORDITEM_METRICS* pMetrics = new XTP_REPORTRECORDITEM_METRICS;
|
||
|
|
||
|
pItemArgs->pRow->FillMetrics(pColumn, pItem, pMetrics);
|
||
|
|
||
|
if (!pControl->IsVirtualMode())
|
||
|
{
|
||
|
CXTPReportRecordItemText* pTextItem = DYNAMIC_DOWNCAST(CXTPReportRecordItemText, pItem);
|
||
|
|
||
|
if (pTextItem != NULL)
|
||
|
{
|
||
|
pMetrics->strText = pTextItem->GetValue();
|
||
|
}
|
||
|
else //not CXTPReportRecordItemText case!
|
||
|
{
|
||
|
pMetrics->strText = pItem->GetCaption(pColumn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CXTPReportRecordItemEditOptions* pEditOptions = pItem->GetEditOptions(pColumn);
|
||
|
ASSERT(pEditOptions);
|
||
|
if (!pEditOptions)
|
||
|
return;
|
||
|
CRect rect = pItemArgs->rcItem;
|
||
|
|
||
|
rect.DeflateRect(1, 1, 1, 2);
|
||
|
|
||
|
m_clrText = pMetrics->clrForeground;
|
||
|
m_strValue = pMetrics->strText;
|
||
|
m_strText_prev = pMetrics->strText;
|
||
|
|
||
|
DWORD dwEditStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | pEditOptions->m_dwEditStyle;
|
||
|
|
||
|
// Remove alignment from style
|
||
|
dwEditStyle &= ~(ES_LEFT | ES_CENTER | ES_RIGHT);
|
||
|
|
||
|
if (pControl->GetPaintManager()->m_bUseEditTextAlignment)
|
||
|
{
|
||
|
if (pMetrics->nColumnAlignment & DT_RIGHT)
|
||
|
dwEditStyle |= ES_RIGHT;
|
||
|
else if (pMetrics->nColumnAlignment & DT_CENTER)
|
||
|
dwEditStyle |= ES_CENTER;
|
||
|
}
|
||
|
|
||
|
if (m_hWnd)
|
||
|
{
|
||
|
DWORD dwStyle = WS_CHILD | WS_VISIBLE | ES_READONLY;
|
||
|
|
||
|
if ((GetStyle() & dwStyle) != (dwEditStyle & dwStyle))
|
||
|
DestroyWindow();
|
||
|
}
|
||
|
|
||
|
if (!m_hWnd)
|
||
|
{
|
||
|
CEdit::Create(dwEditStyle, rect, pControl, 0);
|
||
|
}
|
||
|
|
||
|
if (pControl->GetExStyle() & WS_EX_RTLREADING)
|
||
|
{
|
||
|
ModifyStyleEx(0, WS_EX_RTLREADING);
|
||
|
}
|
||
|
|
||
|
SetLimitText(pEditOptions->m_nMaxLength);
|
||
|
|
||
|
//SetFocus();
|
||
|
SetFont(pMetrics->pFont);
|
||
|
SetWindowText(m_strValue);
|
||
|
|
||
|
pMetrics->InternalRelease();
|
||
|
|
||
|
SetMargins(1, 1);
|
||
|
|
||
|
if (rect.right > rect.left)
|
||
|
{
|
||
|
SetWindowPos(0, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_SHOWWINDOW);
|
||
|
//CEdit::SetRect(rect);
|
||
|
SetFocus();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HideWindow();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::SetWindowText(LPCTSTR lpszString)
|
||
|
{
|
||
|
m_bSetWindowText = TRUE;
|
||
|
|
||
|
CWnd::SetWindowText(lpszString);
|
||
|
m_strText_prev = lpszString;
|
||
|
|
||
|
m_bSetWindowText = FALSE;
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::SetFont(CFont* pFont)
|
||
|
{
|
||
|
m_fntEdit.DeleteObject();
|
||
|
LOGFONT lf;
|
||
|
pFont->GetLogFont(&lf);
|
||
|
m_fntEdit.CreateFontIndirect(&lf);
|
||
|
|
||
|
CEdit::SetFont(&m_fntEdit);
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::OnEnKillfocus()
|
||
|
{
|
||
|
if (pControl && pItem)
|
||
|
{
|
||
|
pItem->OnValidateEdit((XTP_REPORTRECORDITEM_ARGS*)this);
|
||
|
HideWindow();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::OnEnChange()
|
||
|
{
|
||
|
if (m_bSetWindowText || !pControl || !pItem)
|
||
|
return;
|
||
|
|
||
|
CString strValue, strValNew;
|
||
|
GetWindowText(strValue);
|
||
|
strValNew = strValue;
|
||
|
|
||
|
//recover previous selection by diff between old and new text - compare from the start and from the end
|
||
|
int kO = strValue.GetLength();
|
||
|
int kP = m_strText_prev.GetLength();
|
||
|
int K = min(kO, kP);
|
||
|
int kOld(0);
|
||
|
int kOldEnd(kP);
|
||
|
if (m_strText_prev != strValue)
|
||
|
{
|
||
|
for (int j = 0; j < K; j++)
|
||
|
{
|
||
|
if (m_strText_prev[j] != strValue[j])
|
||
|
{
|
||
|
kOld = j;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (int jB = 1; jB <= K; jB++)
|
||
|
{
|
||
|
if (m_strText_prev[kP - jB] != strValue[kO - jB])
|
||
|
{
|
||
|
kOldEnd = kP + 1 - jB;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
BOOL bCommit = pItem->OnEditChanging((XTP_REPORTRECORDITEM_ARGS*)this, strValNew);
|
||
|
|
||
|
if (!bCommit || strValNew != strValue)
|
||
|
{
|
||
|
int nSelStart = 0, nSelEnd = 0;
|
||
|
GetSel(nSelStart, nSelEnd);
|
||
|
|
||
|
int kN = strValNew.GetLength();
|
||
|
int kk = min(kO, kN);
|
||
|
if (strValNew != strValue) //it means that bCommit is TRUE
|
||
|
{
|
||
|
SetWindowText(strValNew);
|
||
|
int k(kk - 1);
|
||
|
for (int j = 0; j < kk; j++)
|
||
|
{
|
||
|
if (strValNew[j] != strValue[j])
|
||
|
{
|
||
|
k = j;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
SetSel(k, k);
|
||
|
}
|
||
|
else //it means that bCommit is FALSE - need rollback
|
||
|
{
|
||
|
SetWindowText(m_strText_prev);
|
||
|
|
||
|
SetSel(kOld, kOldEnd);
|
||
|
//Cursor position before 1st OnEditChanging - handler - modified symbol
|
||
|
if (nSelStart == kO && nSelEnd == kO && kP < kO)
|
||
|
SetSel(nSelStart, nSelEnd);
|
||
|
|
||
|
if (nSelStart == 1 && nSelEnd == 1 && kP < kO)
|
||
|
SetSel(0, 0);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_strText_prev = strValue;
|
||
|
//Normal (default) cursor positioning
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int CXTPReportInplaceEdit::OnMouseActivate(CWnd* , UINT , UINT ) //(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
|
||
|
{
|
||
|
return MA_NOACTIVATE;
|
||
|
}
|
||
|
|
||
|
UINT CXTPReportInplaceEdit::OnGetDlgCode()
|
||
|
{
|
||
|
return DLGC_WANTALLKEYS;
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
{
|
||
|
if (!pControl)
|
||
|
return;
|
||
|
|
||
|
if (nChar == VK_TAB)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (nChar == VK_ESCAPE)
|
||
|
{
|
||
|
pControl->EditItem(NULL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (nChar == VK_RETURN)
|
||
|
{
|
||
|
if ((GetStyle() & ES_WANTRETURN) == 0)
|
||
|
{
|
||
|
pControl->EditItem(NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CEdit::OnChar(nChar, nRepCnt, nFlags);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (pItem && pColumn && pItem->GetEditOptions(pColumn)->m_bConstraintEdit)
|
||
|
{
|
||
|
CXTPReportRecordItemEditOptions *pEditOptions = pItem->GetEditOptions(pColumn);
|
||
|
|
||
|
CXTPReportRecordItemConstraints *pConstraints = pEditOptions->GetConstraints();
|
||
|
int nCount = pConstraints->GetCount();
|
||
|
if (nCount > 0)
|
||
|
{
|
||
|
|
||
|
CString str, strActual;
|
||
|
GetWindowText(str);
|
||
|
strActual = str;
|
||
|
|
||
|
CXTPReportRecordItemConstraint *pConstraint = NULL;
|
||
|
|
||
|
if (NULL != m_pSelectedConstraint)
|
||
|
{
|
||
|
pConstraint = m_pSelectedConstraint;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pConstraint = pEditOptions->FindConstraint(str);
|
||
|
}
|
||
|
|
||
|
|
||
|
int nIndexStart, nIndex;
|
||
|
nIndexStart = nIndex = (pConstraint == NULL ? nCount - 1 : pConstraint->GetIndex());
|
||
|
|
||
|
CString strSeach ((TCHAR)nChar);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
nIndex = nIndex < nCount - 1 ? nIndex + 1 : 0;
|
||
|
|
||
|
pConstraint = pConstraints->GetAt(nIndex);
|
||
|
str = pConstraint->m_strConstraint;
|
||
|
|
||
|
if (strSeach.CompareNoCase(str.Left(1)) == 0)
|
||
|
{
|
||
|
m_pSelectedConstraint = pConstraint;
|
||
|
SetWindowText(str);
|
||
|
SetSel(0, -1);
|
||
|
|
||
|
if (strActual.CompareNoCase(str) != 0)
|
||
|
((CXTPReportControl*)pControl)->OnConstraintSelecting(pRow, pItem, pColumn, pConstraint);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
} while (nIndex != nIndexStart);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (nChar == 1 && nFlags == 30) //Ctrl+A case
|
||
|
{
|
||
|
SetSel(0, -1);
|
||
|
}
|
||
|
CEdit::OnChar(nChar, nRepCnt, nFlags);
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
{
|
||
|
CXTPReportControl* _pControl = pControl;
|
||
|
if (!_pControl)
|
||
|
return;
|
||
|
|
||
|
if (nChar == VK_TAB)
|
||
|
{
|
||
|
_pControl->SetFocus();
|
||
|
_pControl->SendMessage(WM_CHAR, nChar);
|
||
|
return;
|
||
|
}
|
||
|
if (nChar == VK_ESCAPE)
|
||
|
{
|
||
|
SetWindowText(m_strValue);
|
||
|
return;
|
||
|
}
|
||
|
else if (nChar == VK_F5)
|
||
|
{
|
||
|
_pControl->Recalc(TRUE);
|
||
|
return;
|
||
|
}
|
||
|
else if (nChar == VK_RETURN)
|
||
|
{
|
||
|
if ((GetStyle() & ES_WANTRETURN) == 0)
|
||
|
return;
|
||
|
|
||
|
if (GetKeyState(VK_CONTROL) < 0) // ES_WANTRETURN is set and Ctrl+Enter is pressed
|
||
|
{
|
||
|
pControl->EditItem(NULL);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if (nChar == VK_UP || nChar == VK_DOWN || nChar == VK_PRIOR || nChar == VK_NEXT)
|
||
|
{
|
||
|
if (pItem && pColumn && pItem->GetEditOptions(pColumn)->m_bConstraintEdit)
|
||
|
{
|
||
|
CXTPReportRecordItemConstraint* pConstraint;
|
||
|
CXTPReportRecordItemEditOptions* pEditOptions = pItem->GetEditOptions(pColumn);
|
||
|
CXTPReportRecordItemConstraints* pConstraints = pEditOptions->GetConstraints();
|
||
|
|
||
|
int nCount = pConstraints->GetCount();
|
||
|
if (nCount > 1)
|
||
|
{
|
||
|
CString strActual, str;
|
||
|
GetWindowText(strActual);
|
||
|
|
||
|
int nIndex = 0; // the first item
|
||
|
|
||
|
if (nChar == VK_NEXT)
|
||
|
{
|
||
|
nIndex = nCount - 1; // the last item
|
||
|
}
|
||
|
else if (nChar != VK_PRIOR)
|
||
|
{
|
||
|
// look for the actually selected item
|
||
|
for (int i = 0; i < nCount; i++)
|
||
|
{
|
||
|
pConstraint = pConstraints->GetAt(i);
|
||
|
|
||
|
if (strActual.CompareNoCase(pConstraint->m_strConstraint) == 0)
|
||
|
{
|
||
|
if (nChar == VK_UP)
|
||
|
nIndex = max(0, i - 1);
|
||
|
else if (nChar == VK_DOWN)
|
||
|
nIndex = min(nCount-1, i + 1);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pConstraint = pConstraints->GetAt(max(0, min(nIndex, nCount-1)));
|
||
|
str = pConstraint->m_strConstraint;
|
||
|
m_pSelectedConstraint = pConstraint;
|
||
|
|
||
|
// set the default font, because user could change the font (for ex. to striked one)
|
||
|
SetFont(pControl->GetPaintManager()->GetTextFont());
|
||
|
SetWindowText(str);
|
||
|
SetSel(0, -1);
|
||
|
|
||
|
if (strActual.CompareNoCase(str) != 0)
|
||
|
((CXTPReportControl*)pControl)->OnConstraintSelecting(pRow, pItem, pColumn, pConstraint);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
||
|
{
|
||
|
if ((nChar == VK_UP || nChar == VK_DOWN) && pControl)
|
||
|
{
|
||
|
if (pControl->GetInplaceButtons()->GetSize() > 0)
|
||
|
{
|
||
|
CXTPReportInplaceButton* pButton = pControl->GetInplaceButtons()->GetAt(0);
|
||
|
|
||
|
if (pButton->GetItem() == pItem)
|
||
|
{
|
||
|
pItem->OnInplaceButtonDown(pButton);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CEdit::OnSysKeyDown(nChar, nRepCnt, nFlags);
|
||
|
}
|
||
|
|
||
|
BOOL CXTPReportInplaceEdit::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 CEdit::PreTranslateMessage(pMsg);
|
||
|
}
|
||
|
|
||
|
void CXTPReportInplaceEdit::OnLButtonDblClk(UINT nFlags, CPoint point)
|
||
|
{
|
||
|
if (pRow && pItem)
|
||
|
{
|
||
|
MapWindowPoints(pControl, &point, 1);
|
||
|
pRow->OnDblClick(point);
|
||
|
}
|
||
|
|
||
|
if (pItem)
|
||
|
{
|
||
|
CEdit::OnLButtonDblClk(nFlags, point);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HBRUSH CXTPReportInplaceEdit::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
|
||
|
{
|
||
|
pDC->SetTextColor(m_clrText);
|
||
|
|
||
|
return GetSysColorBrush(COLOR_WINDOW);
|
||
|
}
|