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++

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