www.pudn.com > RichEditGrid_src.zip > InPlaceEdit.cpp


// InPlaceEdit.cpp : implementation file 
// 
// Adapted by Chris Maunder  
// Copyright (c) 1998-2002. All Rights Reserved. 
// 
// The code contained in this file is based on the original 
// CInPlaceEdit from http://www.codeguru.com/listview/edit_subitems.shtml 
// 
// This code may be used in compiled form in any way you desire. This 
// file may be redistributed unmodified by any means PROVIDING it is  
// not sold for profit without the authors written consent, and  
// providing that this notice and the authors name and all copyright  
// notices remains intact.  
// 
// An email letting me know how you are using it would be nice as well.  
// 
// This file is provided "as is" with no expressed or implied warranty. 
// The author accepts no liability for any damage/loss of business that 
// this product may cause. 
// 
// For use with CGridCtrl v2.10+ 
// 
// History: 
//         10 May 1998  Uses GVN_ notifications instead of LVN_, 
//                      Sends notification messages to the parent,  
//                      instead of the parent's parent. 
//         15 May 1998  There was a problem when editing with the in-place editor,  
//                      there arises a general protection fault in user.exe, with a  
//                      few qualifications: 
//                         (1) This only happens with owner-drawn buttons; 
//                         (2) This only happens in Win95 
//                         (3) This only happens if the handler for the button does not  
//                             create a new window (even an AfxMessageBox will avoid the  
//                             crash) 
//                         (4) This will not happen if Spy++ is running. 
//                      PreTranslateMessage was added to route messages correctly. 
//                      (Matt Weagle found and fixed this problem) 
//         26 Jul 1998  Removed the ES_MULTILINE style - that fixed a few probs! 
//          6 Aug 1998  Added nID to the constructor param list 
//          6 Sep 1998  Space no longer clears selection when starting edit (Franco Bez) 
//         10 Apr 1999  Enter, Tab and Esc key prob fixed (Koay Kah Hoe) 
//                      Workaround for bizzare "shrinking window" problem in CE 
// 
///////////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "TCHAR.h" 
#include "InPlaceEdit.h" 
 
#include "GridCtrl.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CInPlaceEdit 
 
CInPlaceEdit::CInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID, 
                           int nRow, int nColumn, CString sInitText,  
                           UINT nFirstChar) 
{ 
    m_sInitText     = sInitText; 
    m_nRow          = nRow; 
    m_nColumn       = nColumn; 
    m_nLastChar     = 0;  
    m_bExitOnArrows = (nFirstChar != VK_LBUTTON);    // If mouse click brought us here, 
                                                     // then no exit on arrows 
 
    m_Rect = rect;  // For bizarre CE bug. 
     
    DWORD dwEditStyle = WS_BORDER|WS_CHILD|WS_VISIBLE| ES_AUTOHSCROLL //|ES_MULTILINE 
        | dwStyle; 
    if (!Create(dwEditStyle, rect, pParent, nID)) return; 
     
    SetFont(pParent->GetFont()); 
     
    SetWindowText(sInitText); 
    SetFocus(); 
     
    switch (nFirstChar){ 
        case VK_LBUTTON:  
        case VK_RETURN:   SetSel((int)_tcslen(m_sInitText), -1); return; 
        case VK_BACK:     SetSel((int)_tcslen(m_sInitText), -1); break; 
        case VK_TAB: 
        case VK_DOWN:  
        case VK_UP:    
        case VK_RIGHT: 
        case VK_LEFT:   
        case VK_NEXT:   
        case VK_PRIOR:  
        case VK_HOME: 
        case VK_SPACE: 
        case VK_END:      SetSel(0,-1); return; 
        default:          SetSel(0,-1); 
    } 
 
    // Added by KiteFly. When entering DBCS chars into cells the first char was being lost 
    // SenMessage changed to PostMessage (John Lagerquist) 
    if( nFirstChar < 0x80) 
        PostMessage(WM_CHAR, nFirstChar);    
    else 
        PostMessage(WM_IME_CHAR, nFirstChar); 
} 
 
CInPlaceEdit::~CInPlaceEdit() 
{ 
} 
 
BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit) 
    //{{AFX_MSG_MAP(CInPlaceEdit) 
    ON_WM_KILLFOCUS() 
    ON_WM_CHAR() 
    ON_WM_KEYDOWN() 
    ON_WM_GETDLGCODE() 
    ON_WM_CREATE() 
    //}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
//////////////////////////////////////////////////////////////////////////// 
// CInPlaceEdit message handlers 
 
// If an arrow key (or associated) is pressed, then exit if 
//  a) The Ctrl key was down, or 
//  b) m_bExitOnArrows == TRUE 
void CInPlaceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)  
{ 
    if ((nChar == VK_PRIOR || nChar == VK_NEXT || 
        nChar == VK_DOWN  || nChar == VK_UP   || 
        nChar == VK_RIGHT || nChar == VK_LEFT) && 
        (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0)) 
    { 
        m_nLastChar = nChar; 
        GetParent()->SetFocus(); 
        return; 
    } 
     
    CEdit::OnKeyDown(nChar, nRepCnt, nFlags); 
} 
 
// As soon as this edit loses focus, kill it. 
void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd) 
{ 
    CEdit::OnKillFocus(pNewWnd); 
    EndEdit(); 
} 
 
void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{ 
    if (nChar == VK_TAB || nChar == VK_RETURN) 
    { 
        m_nLastChar = nChar; 
        GetParent()->SetFocus();    // This will destroy this window 
        return; 
    } 
    if (nChar == VK_ESCAPE)  
    { 
        SetWindowText(m_sInitText);    // restore previous text 
        m_nLastChar = nChar; 
        GetParent()->SetFocus(); 
        return; 
    } 
     
    CEdit::OnChar(nChar, nRepCnt, nFlags); 
     
    // Resize edit control if needed 
     
    // Get text extent 
    CString str; 
    GetWindowText( str ); 
 
    // add some extra buffer 
    str += _T("  "); 
     
    CWindowDC dc(this); 
    CFont *pFontDC = dc.SelectObject(GetFont()); 
    CSize size = dc.GetTextExtent( str ); 
    dc.SelectObject( pFontDC ); 
        
    // Get client rect 
    CRect ParentRect; 
    GetParent()->GetClientRect( &ParentRect ); 
     
    // Check whether control needs to be resized 
    // and whether there is space to grow 
    if (size.cx > m_Rect.Width()) 
    { 
        if( size.cx + m_Rect.left < ParentRect.right ) 
            m_Rect.right = m_Rect.left + size.cx; 
        else 
            m_Rect.right = ParentRect.right; 
        MoveWindow( &m_Rect ); 
    } 
} 
 
UINT CInPlaceEdit::OnGetDlgCode()  
{ 
    return DLGC_WANTALLKEYS; 
} 
 
//////////////////////////////////////////////////////////////////////////// 
// CInPlaceEdit overrides 
 
// Stoopid win95 accelerator key problem workaround - Matt Weagle. 
BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)  
{ 
    // Catch the Alt key so we don't choke if focus is going to an owner drawn button 
    if (pMsg->message == WM_SYSCHAR) 
        return TRUE; 
     
    return CWnd::PreTranslateMessage(pMsg); 
} 
 
// Auto delete 
void CInPlaceEdit::PostNcDestroy()  
{ 
    CEdit::PostNcDestroy(); 
     
    delete this;	 
} 
 
//////////////////////////////////////////////////////////////////////////// 
// CInPlaceEdit implementation 
 
void CInPlaceEdit::EndEdit() 
{ 
    CString str; 
 
    // EFW - BUG FIX - Clicking on a grid scroll bar in a derived class 
    // that validates input can cause this to get called multiple times 
    // causing assertions because the edit control goes away the first time. 
    static BOOL bAlreadyEnding = FALSE; 
 
    if(bAlreadyEnding) 
        return; 
 
    bAlreadyEnding = TRUE; 
    GetWindowText(str); 
 
    // Send Notification to parent 
    GV_DISPINFO dispinfo; 
 
    dispinfo.hdr.hwndFrom = GetSafeHwnd(); 
    dispinfo.hdr.idFrom   = GetDlgCtrlID(); 
    dispinfo.hdr.code     = GVN_ENDLABELEDIT; 
 
    dispinfo.item.mask    = LVIF_TEXT|LVIF_PARAM; 
    dispinfo.item.row     = m_nRow; 
    dispinfo.item.col     = m_nColumn; 
    dispinfo.item.strText  = str; 
    dispinfo.item.lParam  = (LPARAM) m_nLastChar; 
 
    CWnd* pOwner = GetOwner(); 
    if (pOwner) 
        pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo ); 
 
    // Close this window (PostNcDestroy will delete this) 
    if (IsWindow(GetSafeHwnd())) 
        SendMessage(WM_CLOSE, 0, 0); 
    bAlreadyEnding = FALSE; 
}