home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / viewedit.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  37.7 KB  |  1,462 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include <ctype.h>
  13.  
  14. #ifdef AFX_CORE4_SEG
  15. #pragma code_seg(AFX_CORE4_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CEditView
  25.  
  26. #define new DEBUG_NEW
  27.  
  28. AFX_STATIC const UINT _afxMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
  29.  
  30. #ifdef _UNICODE
  31.  
  32. AFX_STATIC_DATA HFONT _afxUnicodeFont = 0;
  33.  
  34. void AFX_CDECL AfxEditviewTerm()
  35. {
  36.     AfxDeleteObject((HGDIOBJ*)&_afxUnicodeFont);
  37. }
  38. char _afxEditviewTerm = (char)atexit(&AfxEditviewTerm);
  39.  
  40. #endif //_UNICODE
  41.  
  42. BEGIN_MESSAGE_MAP(CEditView, CCtrlView)
  43.     //{{AFX_MSG_MAP(CEditView)
  44.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
  45.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
  46.     ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
  47.     ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
  48.     ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
  49.     ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
  50. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  51.     ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
  52. #endif // _WIN32_WCE_NO_FINDREPLACE
  53.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
  54.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
  55.     ON_CONTROL_REFLECT_EX(EN_CHANGE, OnEditChange)
  56.     ON_WM_CREATE()
  57.     ON_MESSAGE(WM_SETFONT, OnSetFont)
  58.     ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  59.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  60.     ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  61.     ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  62.     ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
  63.     ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  64. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  65.     ON_COMMAND(ID_EDIT_FIND, OnEditFind)
  66.     ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
  67.     ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
  68. #endif // _WIN32_WCE_NO_FINDREPLACE
  69.     ON_WM_DESTROY()
  70.     //}}AFX_MSG_MAP
  71. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  72.     // Special registered message for Find and Replace
  73.     ON_REGISTERED_MESSAGE(_afxMsgFindReplace, OnFindReplaceCmd)
  74. #endif // _WIN32_WCE_NO_FINDREPLACE
  75.     // Standard Print commands (print only - not preview)
  76. #if !defined(_WIN32_WCE_NO_PRINTING)
  77.     ON_COMMAND(ID_FILE_PRINT, CCtrlView::OnFilePrint)
  78.     ON_COMMAND(ID_FILE_PRINT_DIRECT, CCtrlView::OnFilePrint)
  79. #endif // _WIN32_WCE_NO_PRINTING
  80. #if defined(_WIN32_WCE)
  81. // WinCE: Trap the escape key because it causes problems with CEditView
  82. WCE_INS    ON_WM_GETDLGCODE()
  83. #endif // _WIN32_WCE
  84. END_MESSAGE_MAP()
  85.  
  86. const AFX_DATADEF DWORD CEditView::dwStyleDefault =
  87.     AFX_WS_DEFAULT_VIEW |
  88.     WS_HSCROLL | WS_VSCROLL |
  89.     ES_AUTOHSCROLL | ES_AUTOVSCROLL |
  90.     ES_MULTILINE | ES_NOHIDESEL;
  91.  
  92. // Operating system specific maximum buffer limit
  93. const AFX_DATADEF UINT CEditView::nMaxSize = 1024U*1024U-1;
  94.  
  95. #if !defined(_WIN32_WCE_NO_FINDREPLACE)  
  96. /////////////////////////////////////////////////////////////////////////////
  97. // _AFX_EDIT_STATE
  98.  
  99. _AFX_EDIT_STATE::_AFX_EDIT_STATE()
  100. {
  101.     // Note: it is only necessary to initialize non-zero data.
  102.  
  103.     bNext = TRUE;
  104. }
  105.  
  106. _AFX_EDIT_STATE::~_AFX_EDIT_STATE()
  107. {
  108. }
  109.  
  110. EXTERN_PROCESS_LOCAL(_AFX_EDIT_STATE, _afxEditState)
  111. #endif // _WIN32_WCE_NO_FINDREPLACE
  112.  
  113. /////////////////////////////////////////////////////////////////////////////
  114. // CEditView construction/destruction
  115.  
  116. // pass a NULL style because dwStyleDefault stays for backward compatibility
  117. CEditView::CEditView() : CCtrlView(_T("EDIT"), NULL)
  118. {
  119.     m_nTabStops = 8*4;  // default 8 character positions
  120. #if !defined(_WIN32_WCE_NO_PRINTING)
  121.     m_hPrinterFont = NULL;
  122.     m_hMirrorFont = NULL;
  123. #endif // _WIN32_WCE_NO_PRINTING
  124.     m_pShadowBuffer = NULL;
  125.     m_nShadowSize = 0;
  126. }
  127.  
  128. CEditView::~CEditView()
  129. {
  130.     ASSERT(m_hWnd == NULL);
  131.     ASSERT(m_pShadowBuffer == NULL || WCE_IF(TRUE,afxData.bWin95));
  132.     delete[] m_pShadowBuffer;
  133. }
  134.  
  135. BOOL CEditView::PreCreateWindow(CREATESTRUCT& cs)
  136. {
  137.     m_dwDefaultStyle = dwStyleDefault;
  138.     return CCtrlView::PreCreateWindow(cs);
  139. }
  140.  
  141. int CEditView::OnCreate(LPCREATESTRUCT lpcs)
  142. {
  143.     if (CCtrlView::OnCreate(lpcs) != 0)
  144.         return -1;
  145.  
  146. #ifdef _UNICODE
  147.     AfxLockGlobals(CRIT_EDITVIEW);
  148.     if (_afxUnicodeFont == NULL)
  149.     {
  150.         // get unicode font same size as system font
  151.         HFONT hSystemFont = (HFONT)GetStockObject(SYSTEM_FONT);
  152.         LOGFONT systemFont;
  153.         VERIFY(::GetObject(hSystemFont, sizeof(LOGFONT), (void*)&systemFont));
  154.  
  155.         // default size and facename, but allow customization
  156.         LOGFONT logFont; memset(&logFont, 0, sizeof(LOGFONT));
  157.         logFont.lfHeight = systemFont.lfHeight;
  158.         logFont.lfWeight = systemFont.lfWeight;
  159.         logFont.lfCharSet = DEFAULT_CHARSET;
  160.         lstrcpy(logFont.lfFaceName, _T("Lucida Sans Unicode"));
  161.         AfxCustomLogFont(AFX_IDS_UNICODE_FONT, &logFont);
  162.  
  163.         // attempt to create the font
  164.         _afxUnicodeFont = ::CreateFontIndirect(&logFont);
  165.         if (_afxUnicodeFont == NULL)
  166.             TRACE1("Unable to create unicode font '%s'.\n", logFont.lfFaceName);
  167.     }
  168.     AfxUnlockGlobals(CRIT_EDITVIEW);
  169.     // set unicode font instead of using system font
  170.     if (_afxUnicodeFont != NULL)
  171.         SendMessage(WM_SETFONT, (WPARAM)_afxUnicodeFont);
  172. #endif
  173.  
  174.     GetEditCtrl().LimitText(nMaxSize);
  175.     GetEditCtrl().SetTabStops(m_nTabStops);
  176.  
  177.     return 0;
  178. }
  179.  
  180. #if defined(_WIN32_WCE)
  181. // WinCE: the edit control processes escape and return keys differently if it thinks
  182. // it is parented by a a dialog box.  Handling WM_GETDLGCODE on our own fixes this problem.
  183. LRESULT CEditView::OnGetDlgCode()
  184. {
  185.     return (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS | DLGC_WANTALLKEYS);
  186. }
  187. #endif // _WIN32_WCE
  188.  
  189. void CEditView::OnDestroy()
  190. {
  191. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  192.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  193.     pEditState->pFindReplaceDlg = NULL;
  194. #endif // _WIN32_WCE_NO_FINDREPLACE
  195.  
  196.     CView::OnDestroy();
  197. }
  198.  
  199. // EDIT controls always turn off WS_BORDER and draw it themselves
  200. #if defined(_WIN32_WCE)  
  201. void CEditView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  202. {
  203.     ::AdjustWindowRectEx(lpClientRect, GetStyle() & ~(WS_HSCROLL|WS_VSCROLL), FALSE,
  204.         GetExStyle() & ~(WS_EX_CLIENTEDGE));
  205. }
  206. #else // _WIN32_WCE
  207. void CEditView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  208. {
  209.     if (nAdjustType != 0)
  210.     {
  211.         // default behavior for in-place editing handles scrollbars
  212.         DWORD dwStyle = GetStyle();
  213.         if (dwStyle & WS_VSCROLL)
  214.             lpClientRect->right += afxData.cxVScroll - CX_BORDER;
  215.         if (dwStyle & WS_HSCROLL)
  216.             lpClientRect->bottom += afxData.cyHScroll - CY_BORDER;
  217.         return;
  218.     }
  219.  
  220.     ::AdjustWindowRectEx(lpClientRect, GetStyle() | WS_BORDER, FALSE,
  221.         GetExStyle() & ~(WS_EX_CLIENTEDGE));
  222. }
  223. #endif // _WIN32_WCE
  224.  
  225. /////////////////////////////////////////////////////////////////////////////
  226. // CEditView document like functions
  227.  
  228. void CEditView::DeleteContents()
  229. {
  230.     ASSERT_VALID(this);
  231.     ASSERT(m_hWnd != NULL);
  232.     SetWindowText(NULL);
  233.     ASSERT_VALID(this);
  234. }
  235.  
  236. void CEditView::Serialize(CArchive& ar)
  237.     // Read and write CEditView object to archive, with length prefix.
  238. {
  239.     ASSERT_VALID(this);
  240.     ASSERT(m_hWnd != NULL);
  241.     if (ar.IsStoring())
  242.     {
  243.         UINT nLen = GetBufferLength();
  244.         ar << (DWORD)nLen;
  245.         WriteToArchive(ar);
  246.     }
  247.     else
  248.     {
  249.         DWORD dwLen;
  250.         ar >> dwLen;
  251.         if (dwLen > nMaxSize)
  252.             AfxThrowArchiveException(CArchiveException::badIndex);
  253.         UINT nLen = (UINT)dwLen;
  254.         ReadFromArchive(ar, nLen);
  255.     }
  256.     ASSERT_VALID(this);
  257. }
  258.  
  259. void CEditView::ReadFromArchive(CArchive& ar, UINT nLen)
  260.     // Read certain amount of text from the file, assume at least nLen
  261.     // characters (not bytes) are in the file.
  262. {
  263.     ASSERT_VALID(this);
  264.  
  265.     LPVOID hText = LocalAlloc(LMEM_MOVEABLE, (nLen+1)*sizeof(TCHAR));
  266.     if (hText == NULL)
  267.         AfxThrowMemoryException();
  268.  
  269.     LPTSTR lpszText = (LPTSTR)LocalLock(hText);
  270.     ASSERT(lpszText != NULL);
  271.     if (ar.Read(lpszText, nLen*sizeof(TCHAR)) != nLen*sizeof(TCHAR))
  272.     {
  273.         LocalUnlock(hText);
  274.         LocalFree(hText);
  275.         AfxThrowArchiveException(CArchiveException::endOfFile);
  276.     }
  277.     // Replace the editing edit buffer with the newly loaded data
  278.     lpszText[nLen] = '\0';
  279. #ifndef _UNICODE
  280.     if (afxData.bWin95)
  281.     {
  282.         // set the text with SetWindowText, then free
  283.         BOOL bResult = ::SetWindowText(m_hWnd, lpszText);
  284.         LocalUnlock(hText);
  285.         LocalFree(hText);
  286.  
  287.         // make sure that SetWindowText was successful
  288.         if (!bResult || ::GetWindowTextLength(m_hWnd) < (int)nLen)
  289.             AfxThrowMemoryException();
  290.  
  291.         // remove old shadow buffer
  292.         delete[] m_pShadowBuffer;
  293.         m_pShadowBuffer = NULL;
  294.         m_nShadowSize = 0;
  295.  
  296.         ASSERT_VALID(this);
  297.         return;
  298.     }
  299. #endif
  300. #if defined(_WIN32_WCE)
  301. // WinCE: it is necessary to maintain a shadow buffer since
  302. // EM_GETHANDLE is not supported.
  303.     BOOL bResult = ::SetWindowText(m_hWnd, lpszText);
  304.     LocalUnlock(hText);
  305.     LocalFree(hText);
  306.  
  307.     // make sure that SetWindowText was successful
  308.     if (!bResult || ::GetWindowTextLength(m_hWnd) < (int)nLen)
  309.         AfxThrowMemoryException();
  310.  
  311.     // remove old shadow buffer
  312.     delete[] m_pShadowBuffer;
  313.     m_pShadowBuffer = NULL;
  314.     m_nShadowSize = 0;
  315.  
  316.     ASSERT_VALID(this);
  317. #else // _WIN32_WCE
  318.     LocalUnlock(hText);
  319.     HLOCAL hOldText = GetEditCtrl().GetHandle();
  320.     ASSERT(hOldText != NULL);
  321.     LocalFree(hOldText);
  322.     GetEditCtrl().SetHandle((HLOCAL)(UINT)(DWORD)hText);
  323.     Invalidate();
  324.     ASSERT_VALID(this);
  325. #endif // _WIN32_WCE
  326. }
  327.  
  328. void CEditView::WriteToArchive(CArchive& ar)
  329.     // Write just the text to an archive, no length prefix.
  330. {
  331.     ASSERT_VALID(this);
  332.     LPCTSTR lpszText = LockBuffer();
  333.     ASSERT(lpszText != NULL);
  334.     UINT nLen = GetBufferLength();
  335.     TRY
  336.     {
  337.         ar.Write(lpszText, nLen*sizeof(TCHAR));
  338.     }
  339.     CATCH_ALL(e)
  340.     {
  341.         UnlockBuffer();
  342.         THROW_LAST();
  343.     }
  344.     END_CATCH_ALL
  345.     UnlockBuffer();
  346.     ASSERT_VALID(this);
  347. }
  348.  
  349. void CEditView::SerializeRaw(CArchive& ar)
  350.     // Read/Write object as stand-alone file.
  351. {
  352.     ASSERT_VALID(this);
  353.     if (ar.IsStoring())
  354.     {
  355.         WriteToArchive(ar);
  356.     }
  357.     else
  358.     {
  359.         CFile* pFile = ar.GetFile();
  360.         ASSERT(pFile->GetPosition() == 0);
  361.         DWORD nFileSize = pFile->GetLength();
  362.         if (nFileSize/sizeof(TCHAR) > nMaxSize)
  363.         {
  364.             AfxMessageBox(AFX_IDP_FILE_TOO_LARGE);
  365.             AfxThrowUserException();
  366.         }
  367.         // ReadFromArchive takes the number of characters as argument
  368.         ReadFromArchive(ar, (UINT)nFileSize/sizeof(TCHAR));
  369.     }
  370.     ASSERT_VALID(this);
  371. }
  372.  
  373. /////////////////////////////////////////////////////////////////////////////
  374. // CEditView Printing Helpers
  375.  
  376. AFX_STATIC UINT AFXAPI _AfxEndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex)
  377. {
  378.     ASSERT(AfxIsValidAddress(lpszText, nLen, FALSE));
  379.     LPCTSTR lpsz = lpszText + nIndex;
  380.     LPCTSTR lpszStop = lpszText + nLen;
  381.     while (lpsz < lpszStop && *lpsz != '\r')
  382.         ++lpsz;
  383.     return lpsz - lpszText;
  384. }
  385.  
  386. #if !defined(_WIN32_WCE_NO_PRINTING)
  387. AFX_STATIC UINT AFXAPI _AfxNextLine(LPCTSTR lpszText, UINT nLen, UINT nIndex)
  388. {
  389.     ASSERT(AfxIsValidAddress(lpszText, nLen, FALSE));
  390.     LPCTSTR lpsz = lpszText + nIndex;
  391.     LPCTSTR lpszStop = lpszText + nLen;
  392.     while (lpsz < lpszStop && *lpsz == '\r')
  393.         ++lpsz;
  394.     if (lpsz < lpszStop && *lpsz == '\n')
  395.         ++lpsz;
  396.     return lpsz - lpszText;
  397. }
  398.  
  399. AFX_STATIC UINT AFXAPI
  400. _AfxClipLine(CDC* pDC, int aCharWidths[256], int cxLine, int nTabStop,
  401.     LPCTSTR lpszText, UINT nIndex, UINT nIndexEnd)
  402. {
  403.     ASSERT_VALID(pDC);
  404.     ASSERT(nIndex < nIndexEnd);
  405.     ASSERT(AfxIsValidAddress(lpszText, nIndexEnd, FALSE));
  406.  
  407.     TEXTMETRIC tm;
  408.     ::GetTextMetrics(pDC->m_hDC, &tm);
  409.  
  410.     // make an initial guess on the number of characters that will fit
  411.     int cx = 0;
  412.     LPCTSTR lpszStart = lpszText + nIndex;
  413.     LPCTSTR lpszStop = lpszText + nIndexEnd;
  414.     LPCTSTR lpsz = lpszStart;
  415.     while (lpsz < lpszStop)
  416.     {
  417.         if (*lpsz == '\t')
  418.             cx += nTabStop - (cx % nTabStop);
  419.         else
  420.         {
  421. #ifdef _UNICODE
  422.             if (*lpsz <= 0xFF)
  423.                 cx += aCharWidths[(BYTE)*lpsz];
  424.             else
  425.                 cx += tm.tmAveCharWidth;
  426. #else //_UNICODE
  427.             if (_afxDBCS && _istlead(*lpsz))
  428.             {
  429.                 ++lpsz;
  430.                 cx += tm.tmAveCharWidth;
  431.             }
  432.             else
  433.                 cx += aCharWidths[(BYTE)*lpsz];
  434. #endif //!_UNICODE
  435.         }
  436.         ++lpsz;
  437.         if (cx > cxLine)
  438.             break;
  439.     }
  440.  
  441.     // adjust for errors in the guess
  442. #if defined(_WIN32_WCE)
  443.     cx = pDC->GetTextExtent(lpszStart, lpsz-lpszStart).cx;
  444. #else // _WIN32_WCE
  445.     cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  446. #endif // _WIN32_WCE
  447.     if (cx > cxLine)
  448.     {
  449.         // remove characters until it fits
  450.         do
  451.         {
  452.             ASSERT(lpsz != lpszStart);
  453.             if (_afxDBCS)
  454.                 lpsz = _tcsdec(lpszStart, lpsz);
  455.             else
  456.                 --lpsz;
  457. #if defined(_WIN32_WCE)
  458.             cx = pDC->GetTextExtent(lpszStart, lpsz-lpszStart).cx;
  459. #else // _WIN32_WCE
  460.             cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  461. #endif // _WIN32_WCE
  462.         } while (cx > cxLine);
  463.     }
  464.     else if (cx < cxLine)
  465.     {
  466.         // add characters until it doesn't fit
  467.         while (lpsz < lpszStop)
  468.         {
  469.             lpsz = _tcsinc(lpsz);
  470.             ASSERT(lpsz <= lpszStop);
  471. #if defined(_WIN32_WCE)
  472.             cx = pDC->GetTextExtent(lpszStart, lpsz-lpszStart).cx;
  473. #else // _WIN32_WCE
  474.             cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  475. #endif // _WIN32_WCE
  476.             if (cx > cxLine)
  477.             {
  478.                 if (_afxDBCS)
  479.                     lpsz = _tcsdec(lpszStart, lpsz);
  480.                 else
  481.                     --lpsz;
  482.                 break;
  483.             }
  484.         }
  485.     }
  486.  
  487.     // return index of character just past the last that would fit
  488.     return lpsz - lpszText;
  489. }
  490.  
  491. /////////////////////////////////////////////////////////////////////////////
  492. // CEditView Printing support
  493.  
  494. BOOL CEditView::OnPreparePrinting(CPrintInfo* pInfo)
  495. {
  496.     return DoPreparePrinting(pInfo);
  497. }
  498.  
  499. void CEditView::OnBeginPrinting(CDC* pDC, CPrintInfo*)
  500. {
  501.     ASSERT_VALID(this);
  502.     ASSERT_VALID(pDC);
  503.     // initialize page start vector
  504.     ASSERT(m_aPageStart.GetSize() == 0);
  505.     m_aPageStart.Add(0);
  506.     ASSERT(m_aPageStart.GetSize() > 0);
  507.  
  508.     if (m_hPrinterFont == NULL)
  509.     {
  510.         // get current screen font object metrics
  511.         CFont* pFont = GetFont();
  512.         LOGFONT lf;
  513.         LOGFONT lfSys;
  514.         if (pFont == NULL)
  515.             return;
  516.         VERIFY(pFont->GetObject(sizeof(LOGFONT), &lf));
  517.         VERIFY(::GetObject(::GetStockObject(SYSTEM_FONT), sizeof(LOGFONT),
  518.             &lfSys));
  519.         if (lstrcmpi((LPCTSTR)lf.lfFaceName, (LPCTSTR)lfSys.lfFaceName) == 0)
  520.             return;
  521.  
  522.         // map to printer font metrics
  523.         HDC hDCFrom = ::GetDC(NULL);
  524.         lf.lfHeight = ::WCE_FCTN(MulDiv)(lf.lfHeight, pDC->GetDeviceCaps(LOGPIXELSY),
  525.             ::GetDeviceCaps(hDCFrom, LOGPIXELSY));
  526.         lf.lfWidth = ::WCE_FCTN(MulDiv)(lf.lfWidth, pDC->GetDeviceCaps(LOGPIXELSX),
  527.             ::GetDeviceCaps(hDCFrom, LOGPIXELSX));
  528.         ::ReleaseDC(NULL, hDCFrom);
  529.  
  530.         // create it, if it fails we just use the printer's default.
  531.         m_hMirrorFont = ::CreateFontIndirect(&lf);
  532.         m_hPrinterFont = m_hMirrorFont;
  533.     }
  534.     ASSERT_VALID(this);
  535. }
  536.  
  537. BOOL CEditView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
  538.     // attempts pagination to pInfo->m_nCurPage, TRUE == success
  539. {
  540.     ASSERT_VALID(this);
  541.     ASSERT_VALID(pDC);
  542.  
  543.     CRect rectSave = pInfo->m_rectDraw;
  544.     UINT nPageSave = pInfo->m_nCurPage;
  545.     ASSERT(nPageSave > 1);
  546.     ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
  547.     VERIFY(pDC->SaveDC() != 0);
  548.     pDC->IntersectClipRect(0, 0, 0, 0);
  549.     pInfo->m_nCurPage = m_aPageStart.GetSize();
  550.     while (pInfo->m_nCurPage < nPageSave)
  551.     {
  552.         ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
  553.         OnPrepareDC(pDC, pInfo);
  554.         ASSERT(pInfo->m_bContinuePrinting);
  555.         pInfo->m_rectDraw.SetRect(0, 0,
  556.             pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  557.         pDC->DPtoLP(&pInfo->m_rectDraw);
  558.         OnPrint(pDC, pInfo);
  559.         if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
  560.             break;
  561.         ++pInfo->m_nCurPage;
  562.     }
  563.     BOOL bResult = pInfo->m_nCurPage == nPageSave;
  564.     pDC->RestoreDC(-1);
  565.     pInfo->m_nCurPage = nPageSave;
  566.     pInfo->m_rectDraw = rectSave;
  567.     ASSERT_VALID(this);
  568.     return bResult;
  569. }
  570.  
  571. void CEditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  572. {
  573.     ASSERT_VALID(this);
  574.     ASSERT_VALID(pDC);
  575.     ASSERT(pInfo != NULL);  // overriding OnPaint -- never get this.
  576.  
  577.     if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
  578.         !PaginateTo(pDC, pInfo))
  579.     {
  580.         // can't paginate to that page, thus cannot print it.
  581.         pInfo->m_bContinuePrinting = FALSE;
  582.     }
  583.     ASSERT_VALID(this);
  584. }
  585.  
  586. UINT CEditView::PrintInsideRect(CDC* pDC, RECT& rectLayout,
  587.     UINT nIndexStart, UINT nIndexStop)
  588.     // worker function for laying out text in a rectangle.
  589. {
  590.     ASSERT_VALID(this);
  591.     ASSERT_VALID(pDC);
  592.     BOOL bWordWrap = (GetStyle() & ES_AUTOHSCROLL) == 0;
  593.  
  594.     // get buffer and real starting and ending postions
  595.     UINT nLen = GetBufferLength();
  596.     if (nIndexStart >= nLen)
  597.         return nLen;
  598.     LPCTSTR lpszText = LockBuffer();
  599.     if (nIndexStop > nLen)
  600.         nIndexStop = nLen;
  601.     ASSERT(nIndexStart < nLen);
  602.  
  603.     // calculate text & tab metrics
  604.     TEXTMETRIC tm;
  605.     pDC->GetTextMetrics(&tm);
  606.     int cyChar = tm.tmHeight + tm.tmExternalLeading;
  607. #if defined(_WIN32_WCE)
  608.         int nTabStop = pDC->GetTextExtent(_T("\t"), 1).cx;
  609. #else // _WIN32_WCE
  610.     int nTabStop = m_nTabStops *
  611.         pDC->GetTabbedTextExtent(_T("\t"), 1, 0, NULL).cx / 8 / 4;
  612. #endif // _WIN32_WCE
  613.     int aCharWidths[256];
  614. #if defined(_WIN32_WCE)
  615.     for(TCHAR szChar[2]=_T("\0"); *szChar <= 255; (*szChar)++)
  616.         aCharWidths[*szChar] = pDC->GetTextExtent(szChar,1).cx;
  617. #else // _WIN32_WCE
  618.     pDC->GetCharWidth(0, 255, aCharWidths);
  619. #endif // _WIN32_WCE
  620.  
  621.     int y = rectLayout.top;
  622.     UINT cx = rectLayout.right - rectLayout.left;
  623.     UINT nIndex = nIndexStart;
  624.  
  625.     VERIFY(pDC->SaveDC() != 0);
  626.     BOOL bLayoutOnly = pDC->IntersectClipRect(&rectLayout) == NULLREGION;
  627.  
  628.     do
  629.     {
  630.         UINT nIndexEnd = _AfxEndOfLine(lpszText, nIndexStop, nIndex);
  631.         if (nIndex == nIndexEnd)
  632.         {
  633.             y += cyChar;
  634.         }
  635.         else if (bWordWrap)
  636.         {
  637.             // word-wrap printing
  638.             do
  639.             {
  640.                 UINT nIndexWrap = _AfxClipLine(pDC, aCharWidths,
  641.                     cx, nTabStop, lpszText, nIndex, nIndexEnd);
  642.                 UINT nIndexWord = nIndexWrap;
  643.                 if (nIndexWord != nIndexEnd)
  644.                 {
  645.                     while (nIndexWord > nIndex &&
  646.                       !_istspace(lpszText[nIndexWord]))
  647.                     {
  648.                         nIndexWord--;
  649.                     }
  650.                     if (nIndexWord == nIndex)
  651.                         nIndexWord = nIndexWrap;
  652.                 }
  653.                 CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
  654.                 if (!bLayoutOnly && pDC->RectVisible(rect))
  655.                 {
  656. #if defined(_WIN32_WCE)
  657.                     pDC->ExtTextOut(rect.left, y, 0, NULL,
  658.                         (LPCTSTR)(lpszText+nIndex), nIndexWord-nIndex, NULL);
  659. #else // _WIN32_WCE
  660.                     pDC->TabbedTextOut(rect.left, y,
  661.                         (LPCTSTR)(lpszText+nIndex), nIndexWord-nIndex, 1,
  662.                         &nTabStop, rect.left);
  663. #endif // _WIN32_WCE
  664.                 }
  665.                 y += cyChar;
  666.                 nIndex = nIndexWord;
  667.                 while (nIndex < nIndexEnd && _istspace(lpszText[nIndex]))
  668.                     nIndex++;
  669.             } while (nIndex < nIndexEnd && y+cyChar <= rectLayout.bottom);
  670.  
  671.             nIndexEnd = nIndex;
  672.         }
  673.         else
  674.         {
  675.             // non-word wrap printing (much easier and faster)
  676.             CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
  677.             if (!bLayoutOnly && pDC->RectVisible(rect))
  678.             {
  679.                 UINT nIndexClip = _AfxClipLine(pDC, aCharWidths, cx, nTabStop,
  680.                     lpszText, nIndex, nIndexEnd);
  681.                 if (nIndexClip < nIndexEnd)
  682.                 {
  683.                     if (_istlead(*(lpszText+nIndexClip)))
  684.                         nIndexClip++;
  685.                     nIndexClip++;
  686.                 }
  687. #if defined(_WIN32_WCE)
  688.                     pDC->ExtTextOut(rect.left, y, 0, NULL,
  689.                         (LPCTSTR)(lpszText+nIndex), nIndexClip-nIndex, NULL);
  690. #else // _WIN32_WCE
  691.                 pDC->TabbedTextOut(rect.left, y,
  692.                     (LPCTSTR)(lpszText+nIndex), nIndexClip-nIndex, 1,
  693.                     &nTabStop, rect.left);
  694. #endif // _WIN32_WCE
  695.             }
  696.             y += cyChar;
  697.         }
  698.         nIndex = _AfxNextLine(lpszText, nIndexStop, nIndexEnd);
  699.     }
  700.     while (nIndex < nIndexStop && y+cyChar <= rectLayout.bottom);
  701.  
  702.     pDC->RestoreDC(-1);
  703.     UnlockBuffer();
  704.     ASSERT_VALID(this);
  705.  
  706.     rectLayout.bottom = y;
  707.     return nIndex;
  708. }
  709.  
  710. void CEditView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
  711. {
  712.     ASSERT_VALID(this);
  713.     ASSERT_VALID(pDC);
  714.     ASSERT(pInfo != NULL);
  715.     ASSERT(pInfo->m_bContinuePrinting);
  716.  
  717.     CFont* pOldFont = NULL;
  718.     if (m_hPrinterFont != NULL)
  719.         pOldFont = pDC->SelectObject(CFont::FromHandle(m_hPrinterFont));
  720.     pDC->SetBkMode(TRANSPARENT);
  721.  
  722.     UINT nPage = pInfo->m_nCurPage;
  723.     ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
  724.     UINT nIndex = m_aPageStart[nPage-1];
  725.  
  726.     // print as much as possible in the current page.
  727.     nIndex = PrintInsideRect(pDC, pInfo->m_rectDraw, nIndex, GetBufferLength());
  728.  
  729.     if (pOldFont != NULL)
  730.         pDC->SelectObject(pOldFont);
  731.  
  732.     // update pagination information for page just printed
  733.     if (nPage == (UINT)m_aPageStart.GetSize())
  734.     {
  735.         if (nIndex < GetBufferLength())
  736.             m_aPageStart.Add(nIndex);
  737.     }
  738.     else
  739.     {
  740.         ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
  741.         ASSERT(nIndex == m_aPageStart[nPage+1-1]);
  742.     }
  743. }
  744.  
  745. void CEditView::OnEndPrinting(CDC*, CPrintInfo*)
  746. {
  747.     ASSERT_VALID(this);
  748.  
  749.     m_aPageStart.RemoveAll();
  750.     if (m_hMirrorFont != NULL && m_hPrinterFont == m_hMirrorFont)
  751.     {
  752.         AfxDeleteObject((HGDIOBJ*)&m_hMirrorFont);
  753.         m_hPrinterFont = NULL;
  754.     }
  755. }
  756. #endif // _WIN32_WCE_NO_PRINTING
  757.  
  758. /////////////////////////////////////////////////////////////////////////////
  759. // CEditView commands
  760.  
  761. void CEditView::OnUpdateNeedSel(CCmdUI* pCmdUI)
  762. {
  763.     ASSERT_VALID(this);
  764.     int nStartChar, nEndChar;
  765.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  766.     pCmdUI->Enable(nStartChar != nEndChar);
  767.     ASSERT_VALID(this);
  768. }
  769.  
  770. void CEditView::OnUpdateNeedClip(CCmdUI* pCmdUI)
  771. {
  772.     ASSERT_VALID(this);
  773. #if defined(_WIN32_WCE)
  774.     pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT)    ||
  775.                    ::IsClipboardFormatAvailable(CF_OEMTEXT) ||
  776.                    ::IsClipboardFormatAvailable(CF_UNICODETEXT)); 
  777. #else // _WIN32_WCE
  778.     pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
  779. #endif // _WIN32_WCE
  780.     ASSERT_VALID(this);
  781. }
  782.  
  783. void CEditView::OnUpdateNeedText(CCmdUI* pCmdUI)
  784. {
  785.     ASSERT_VALID(this);
  786.     pCmdUI->Enable(GetWindowTextLength() != 0);
  787.     ASSERT_VALID(this);
  788. }
  789.  
  790. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  791. void CEditView::OnUpdateNeedFind(CCmdUI* pCmdUI)
  792. {
  793.     ASSERT_VALID(this);
  794.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  795.     pCmdUI->Enable(GetWindowTextLength() != 0 &&
  796.         !pEditState->strFind.IsEmpty());
  797.     ASSERT_VALID(this);
  798. }
  799. #endif // _WIN32_WCE_NO_FINDREPLACE
  800.  
  801. void CEditView::OnUpdateEditUndo(CCmdUI* pCmdUI)
  802. {
  803.     ASSERT_VALID(this);
  804.     pCmdUI->Enable(GetEditCtrl().CanUndo());
  805.     ASSERT_VALID(this);
  806. }
  807.  
  808. BOOL CEditView::OnEditChange()
  809. {
  810.     ASSERT_VALID(this);
  811.     GetDocument()->SetModifiedFlag();
  812.     ASSERT_VALID(this);
  813.  
  814.     return FALSE;   // continue routing
  815. }
  816.  
  817. void CEditView::OnEditCut()
  818. {
  819.     ASSERT_VALID(this);
  820.     GetEditCtrl().Cut();
  821.     ASSERT_VALID(this);
  822. }
  823.  
  824. void CEditView::OnEditCopy()
  825. {
  826.     ASSERT_VALID(this);
  827.     GetEditCtrl().Copy();
  828.     ASSERT_VALID(this);
  829. }
  830.  
  831. void CEditView::OnEditPaste()
  832. {
  833.     ASSERT_VALID(this);
  834.     GetEditCtrl().Paste();
  835.     ASSERT_VALID(this);
  836. }
  837.  
  838. void CEditView::OnEditClear()
  839. {
  840.     ASSERT_VALID(this);
  841.     GetEditCtrl().Clear();
  842.     ASSERT_VALID(this);
  843. }
  844.  
  845. void CEditView::OnEditUndo()
  846. {
  847.     ASSERT_VALID(this);
  848.     GetEditCtrl().Undo();
  849.     ASSERT_VALID(this);
  850. }
  851.  
  852. void CEditView::OnEditSelectAll()
  853. {
  854.     ASSERT_VALID(this);
  855.     GetEditCtrl().SetSel(0, -1);
  856.     ASSERT_VALID(this);
  857. }
  858.  
  859. /////////////////////////////////////////////////////////////////////////////
  860. // CEditView Font Handling
  861.  
  862. LRESULT CEditView::OnSetFont(WPARAM, LPARAM)
  863. {
  864.     ASSERT_VALID(this);
  865.     Default();
  866.     GetEditCtrl().SetTabStops(m_nTabStops);
  867.     ASSERT_VALID(this);
  868.     return 0;
  869. }
  870.  
  871. #if !defined(_WIN32_WCE_NO_PRINTING)
  872. void CEditView::SetPrinterFont(CFont* pFont)
  873. {
  874.     ASSERT_VALID(this);
  875.     m_hPrinterFont = (HFONT)pFont->GetSafeHandle();
  876.     ASSERT_VALID(this);
  877. }
  878.  
  879. CFont* CEditView::GetPrinterFont() const
  880. {
  881.     ASSERT_VALID(this);
  882.     return CFont::FromHandle(m_hPrinterFont);
  883. }
  884. #endif // _WIN32_WCE_NO_PRINTING
  885.  
  886. /////////////////////////////////////////////////////////////////////////////
  887. // CEditView attributes
  888.  
  889. LPCTSTR CEditView::LockBuffer() const
  890. {
  891.     ASSERT_VALID(this);
  892.     ASSERT(m_hWnd != NULL);
  893. #ifndef _UNICODE
  894.     if (afxData.bWin95)
  895.     {
  896.         // under Win32s, it is necessary to maintain a shadow buffer
  897.         //  it is only updated when the control contents have been changed.
  898.         if (m_pShadowBuffer == NULL || GetEditCtrl().GetModify())
  899.         {
  900.             ASSERT(m_pShadowBuffer != NULL || m_nShadowSize == 0);
  901.             UINT nSize = GetWindowTextLength()+1;
  902.             if (nSize > m_nShadowSize)
  903.             {
  904.                 // need more room for shadow buffer
  905.                 CEditView* pThis = (CEditView*)this;
  906.                 delete[] m_pShadowBuffer;
  907.                 pThis->m_pShadowBuffer = NULL;
  908.                 pThis->m_nShadowSize = 0;
  909.                 pThis->m_pShadowBuffer = new TCHAR[nSize];
  910.                 pThis->m_nShadowSize = nSize;
  911.             }
  912.  
  913.             // update the shadow buffer with GetWindowText
  914.             ASSERT(m_nShadowSize >= nSize);
  915.             ASSERT(m_pShadowBuffer != NULL);
  916.             GetWindowText(m_pShadowBuffer, nSize);
  917.  
  918.             // turn off edit control's modify bit
  919.             GetEditCtrl().SetModify(FALSE);
  920.         }
  921.         return m_pShadowBuffer;
  922.     }
  923. #endif
  924.     // else -- running under non-subset Win32 system
  925. #if defined(_WIN32_WCE)
  926. // WinCE: it is necessary to maintain a shadow buffer since
  927. // EM_GETHANDLE is not supported.
  928.     if (m_pShadowBuffer == NULL || GetEditCtrl().GetModify())
  929.     {
  930.         ASSERT(m_pShadowBuffer != NULL || m_nShadowSize == 0);
  931.         UINT nSize = GetWindowTextLength()+1;
  932.         if (nSize > m_nShadowSize)
  933.         {
  934.             // need more room for shadow buffer
  935.             CEditView* pThis = (CEditView*)this;
  936.             delete[] m_pShadowBuffer;
  937.             pThis->m_pShadowBuffer = NULL;
  938.             pThis->m_nShadowSize = 0;
  939.             pThis->m_pShadowBuffer = new TCHAR[nSize];
  940.             pThis->m_nShadowSize = nSize;
  941.         }
  942.  
  943.         // update the shadow buffer with GetWindowText
  944.         ASSERT(m_nShadowSize >= nSize);
  945.         ASSERT(m_pShadowBuffer != NULL);
  946.         GetWindowText(m_pShadowBuffer, nSize);
  947.  
  948.         // turn off edit control's modify bit
  949.         GetEditCtrl().SetModify(FALSE);
  950.     }
  951.     return m_pShadowBuffer;
  952. #else // _WIN32_WCE
  953.     HLOCAL hLocal = GetEditCtrl().GetHandle();
  954.     ASSERT(hLocal != NULL);
  955.     LPCTSTR lpszText = (LPCTSTR)LocalLock(hLocal);
  956.     ASSERT(lpszText != NULL);
  957.     ASSERT_VALID(this);
  958.     return lpszText;
  959. #endif // _WIN32_WCE
  960. }
  961.  
  962. void CEditView::UnlockBuffer() const
  963. {
  964.     ASSERT_VALID(this);
  965.     ASSERT(m_hWnd != NULL);
  966. #ifndef _UNICODE
  967.     if (afxData.bWin95)
  968.         return;
  969. #endif
  970. #if !defined(_WIN32_WCE)
  971. // WinCE: LockBuffer doesn't really lock the buffer. A shadow buffer was used instead.
  972.     HLOCAL hLocal = GetEditCtrl().GetHandle();
  973.     ASSERT(hLocal != NULL);
  974.     LocalUnlock(hLocal);
  975. #endif // _WIN32_WCE
  976. }
  977.  
  978. // this function returns the length in characters
  979. UINT CEditView::GetBufferLength() const
  980. {
  981.     ASSERT_VALID(this);
  982.     ASSERT(m_hWnd != NULL);
  983.     LPCTSTR lpszText = LockBuffer();
  984.     UINT nLen = lstrlen(lpszText);
  985.     UnlockBuffer();
  986.     return nLen;
  987. }
  988.  
  989. void CEditView::GetSelectedText(CString& strResult) const
  990. {
  991.     ASSERT_VALID(this);
  992.     int nStartChar, nEndChar;
  993.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  994.     ASSERT((UINT)nEndChar <= GetBufferLength());
  995.     LPCTSTR lpszText = ((CEditView*)this)->LockBuffer();
  996.     UINT nLen = _AfxEndOfLine(lpszText, nEndChar, nStartChar) - nStartChar;
  997.     memcpy(strResult.GetBuffer(nLen), lpszText + nStartChar,
  998.         nLen * sizeof(TCHAR));
  999.     strResult.ReleaseBuffer(nLen);
  1000.     UnlockBuffer();
  1001.     ASSERT_VALID(this);
  1002. }
  1003.  
  1004. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  1005. /////////////////////////////////////////////////////////////////////////////
  1006. // CEditView Find & Replace
  1007.  
  1008. void CEditView::OnEditFind()
  1009. {
  1010.     ASSERT_VALID(this);
  1011.     OnEditFindReplace(TRUE);
  1012.     ASSERT_VALID(this);
  1013. }
  1014.  
  1015. void CEditView::OnEditReplace()
  1016. {
  1017.     ASSERT_VALID(this);
  1018.     OnEditFindReplace(FALSE);
  1019.     ASSERT_VALID(this);
  1020. }
  1021.  
  1022. void CEditView::OnEditRepeat()
  1023. {
  1024.     ASSERT_VALID(this);
  1025.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1026.     if (!FindText(pEditState->strFind,
  1027.         pEditState->bNext,
  1028.         pEditState->bCase))
  1029.     {
  1030.         OnTextNotFound(pEditState->strFind);
  1031.     }
  1032.     ASSERT_VALID(this);
  1033. }
  1034.  
  1035. void CEditView::OnEditFindReplace(BOOL bFindOnly)
  1036. {
  1037.     ASSERT_VALID(this);
  1038.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1039.     if (pEditState->pFindReplaceDlg != NULL)
  1040.     {
  1041.         if (pEditState->bFindOnly == bFindOnly)
  1042.         {
  1043.             pEditState->pFindReplaceDlg->SetActiveWindow();
  1044.             pEditState->pFindReplaceDlg->ShowWindow(SW_SHOW);
  1045.             return;
  1046.         }
  1047.         ASSERT(pEditState->bFindOnly != bFindOnly);
  1048.         pEditState->pFindReplaceDlg->SendMessage(WM_CLOSE);
  1049.         ASSERT(pEditState->pFindReplaceDlg == NULL);
  1050.         ASSERT_VALID(this);
  1051.     }
  1052.  
  1053.     CString strFind;
  1054.     GetSelectedText(strFind);
  1055.     if (strFind.IsEmpty())
  1056.         strFind = pEditState->strFind;
  1057.     CString strReplace = pEditState->strReplace;
  1058.     pEditState->pFindReplaceDlg = new CFindReplaceDialog;
  1059.     ASSERT(pEditState->pFindReplaceDlg != NULL);
  1060.     DWORD dwFlags = FR_HIDEWHOLEWORD;
  1061.     if (pEditState->bNext)
  1062.         dwFlags |= FR_DOWN;
  1063.     if (pEditState->bCase)
  1064.         dwFlags |= FR_MATCHCASE;
  1065.     if (!pEditState->pFindReplaceDlg->Create(bFindOnly, strFind,
  1066.         strReplace, dwFlags, this))
  1067.     {
  1068.         pEditState->pFindReplaceDlg = NULL;
  1069.         ASSERT_VALID(this);
  1070.         return;
  1071.     }
  1072.  
  1073.     pEditState->pFindReplaceDlg->SetActiveWindow();
  1074.     pEditState->pFindReplaceDlg->ShowWindow(SW_SHOW);
  1075.     ASSERT(pEditState->pFindReplaceDlg != NULL);
  1076.     pEditState->bFindOnly = bFindOnly;
  1077.     ASSERT_VALID(this);
  1078. }
  1079.  
  1080. void CEditView::OnFindNext(LPCTSTR lpszFind, BOOL bNext, BOOL bCase)
  1081. {
  1082.     ASSERT_VALID(this);
  1083.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1084.     pEditState->strFind = lpszFind;
  1085.     pEditState->bCase = bCase;
  1086.     pEditState->bNext = bNext;
  1087.  
  1088.     if (!FindText(pEditState->strFind, bNext, bCase))
  1089.         OnTextNotFound(pEditState->strFind);
  1090.     ASSERT_VALID(this);
  1091. }
  1092.  
  1093. void CEditView::OnReplaceSel(LPCTSTR lpszFind, BOOL bNext, BOOL bCase,
  1094.     LPCTSTR lpszReplace)
  1095. {
  1096.     ASSERT_VALID(this);
  1097.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1098.     pEditState->strFind = lpszFind;
  1099.     pEditState->strReplace = lpszReplace;
  1100.     pEditState->bCase = bCase;
  1101.     pEditState->bNext = bNext;
  1102.  
  1103.     if (!InitializeReplace())
  1104.         return;
  1105.  
  1106.     GetEditCtrl().ReplaceSel(pEditState->strReplace);
  1107.     FindText(pEditState->strFind, bNext, bCase);
  1108.     ASSERT_VALID(this);
  1109. }
  1110.  
  1111. void CEditView::OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bCase)
  1112. {
  1113.     ASSERT_VALID(this);
  1114.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1115.     pEditState->strFind = lpszFind;
  1116.     pEditState->strReplace = lpszReplace;
  1117.     pEditState->bCase = bCase;
  1118.     pEditState->bNext = TRUE;
  1119.  
  1120.     if (!InitializeReplace() &&
  1121.         !SameAsSelected(pEditState->strFind, pEditState->bCase))
  1122.     {
  1123.         // initial find was not successful
  1124.         return;
  1125.     }
  1126.  
  1127.     do
  1128.     {
  1129.         GetEditCtrl().ReplaceSel(pEditState->strReplace);
  1130.     } while (FindText(pEditState->strFind, 1, bCase));
  1131.  
  1132.     ASSERT_VALID(this);
  1133. }
  1134.  
  1135. BOOL CEditView::InitializeReplace()
  1136.     // helper to do find first if no selection
  1137. {
  1138.     ASSERT_VALID(this);
  1139.  
  1140.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1141.  
  1142.     // do find next if no selection
  1143.     int nStartChar, nEndChar;
  1144.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  1145.     if (nStartChar == nEndChar)
  1146.     {
  1147.         if (!FindText(pEditState->strFind, pEditState->bNext,
  1148.             pEditState->bCase))
  1149.         {
  1150.             // text not found
  1151.             OnTextNotFound(pEditState->strFind);
  1152.         }
  1153.         return FALSE;
  1154.     }
  1155.  
  1156.     if (!SameAsSelected(pEditState->strFind, pEditState->bCase))
  1157.     {
  1158.         if (!FindText(pEditState->strFind, pEditState->bNext,
  1159.             pEditState->bCase))
  1160.         {
  1161.             // text not found
  1162.             OnTextNotFound(pEditState->strFind);
  1163.         }
  1164.         return FALSE;
  1165.     }
  1166.  
  1167.     ASSERT_VALID(this);
  1168.     return TRUE;
  1169. }
  1170.  
  1171. LRESULT CEditView::OnFindReplaceCmd(WPARAM, LPARAM lParam)
  1172. {
  1173.     ASSERT_VALID(this);
  1174.  
  1175.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1176.     CFindReplaceDialog* pDialog = CFindReplaceDialog::GetNotifier(lParam);
  1177.     ASSERT(pDialog != NULL);
  1178.     ASSERT(pDialog == pEditState->pFindReplaceDlg);
  1179.     if (pDialog->IsTerminating())
  1180.     {
  1181.         pEditState->pFindReplaceDlg = NULL;
  1182.     }
  1183.     else if (pDialog->FindNext())
  1184.     {
  1185.         OnFindNext(pDialog->GetFindString(),
  1186.             pDialog->SearchDown(), pDialog->MatchCase());
  1187.     }
  1188.     else if (pDialog->ReplaceCurrent())
  1189.     {
  1190.         ASSERT(!pEditState->bFindOnly);
  1191.         OnReplaceSel(pDialog->GetFindString(),
  1192.             pDialog->SearchDown(), pDialog->MatchCase(),
  1193.             pDialog->GetReplaceString());
  1194.     }
  1195.     else if (pDialog->ReplaceAll())
  1196.     {
  1197.         ASSERT(!pEditState->bFindOnly);
  1198.         OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),
  1199.             pDialog->MatchCase());
  1200.     }
  1201.     ASSERT_VALID(this);
  1202.     return 0;
  1203. }
  1204.  
  1205. typedef int (WINAPI* AFX_COMPARE_PROC)(LPCTSTR str1, LPCTSTR str2);
  1206.  
  1207. BOOL CEditView::SameAsSelected(LPCTSTR lpszCompare, BOOL bCase)
  1208. {
  1209.     // check length first
  1210.     size_t nLen = lstrlen(lpszCompare);
  1211.     int nStartChar, nEndChar;
  1212.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  1213.     if (nLen != (size_t)(nEndChar - nStartChar))
  1214.         return FALSE;
  1215.  
  1216.     // length is the same, check contents
  1217.     CString strSelect;
  1218.     GetSelectedText(strSelect);
  1219.     return (bCase && lstrcmp(lpszCompare, strSelect) == 0) ||
  1220.         (!bCase && lstrcmpi(lpszCompare, strSelect) == 0);
  1221. }
  1222.  
  1223. BOOL CEditView::FindText(LPCTSTR lpszFind, BOOL bNext, BOOL bCase)
  1224. {
  1225.     ASSERT_VALID(this);
  1226.     ASSERT(lpszFind != NULL);
  1227.     ASSERT(*lpszFind != '\0');
  1228.  
  1229.     UINT nLen = GetBufferLength();
  1230.     int nStartChar, nEndChar;
  1231.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  1232.     UINT nStart = nStartChar;
  1233.     int iDir = bNext ? +1 : -1;
  1234.  
  1235.     // can't find a match before the first character
  1236.     if (nStart == 0 && iDir < 0)
  1237.         return FALSE;
  1238.  
  1239.     CWaitCursor wait;
  1240.     LPCTSTR lpszText = LockBuffer();
  1241.  
  1242.     if (iDir < 0)
  1243.     {
  1244.         // always go back one for search backwards
  1245.         nStart -= (lpszText+nStart) -
  1246.             _tcsdec(lpszText, lpszText+nStart);
  1247.     }
  1248.     else if (nStartChar != nEndChar && SameAsSelected(lpszFind, bCase))
  1249.     {
  1250.         // easy to go backward/forward with SBCS
  1251.         if (_istlead(lpszText[nStart]))
  1252.             nStart++;
  1253.         nStart += iDir;
  1254.     }
  1255.  
  1256.     // handle search with nStart past end of buffer
  1257.     size_t nLenFind = lstrlen(lpszFind);
  1258.     if (nStart+nLenFind-1 >= nLen)
  1259.     {
  1260.         if (iDir < 0 && nLen >= nLenFind)
  1261.         {
  1262.             if (_afxDBCS)
  1263.             {
  1264.                 // walk back to previous character n times
  1265.                 nStart = nLen;
  1266.                 int n = nLenFind;
  1267.                 while (n--)
  1268.                 {
  1269.                     nStart -= (lpszText+nStart) -
  1270.                         _tcsdec(lpszText, lpszText+nStart);
  1271.                 }
  1272.             }
  1273.             else
  1274.             {
  1275.                 // single-byte character set is easy and fast
  1276.                 nStart = nLen - nLenFind;
  1277.             }
  1278.             ASSERT(nStart+nLenFind-1 <= nLen);
  1279.         }
  1280.         else
  1281.         {
  1282.             UnlockBuffer();
  1283.             return FALSE;
  1284.         }
  1285.     }
  1286.  
  1287.     // start the search at nStart
  1288.     LPCTSTR lpsz = lpszText + nStart;
  1289.     AFX_COMPARE_PROC pfnCompare = bCase ? lstrcmp : lstrcmpi;
  1290.  
  1291.     if (_afxDBCS)
  1292.     {
  1293.         // double-byte string search
  1294.         LPCTSTR lpszStop;
  1295.         if (iDir > 0)
  1296.         {
  1297.             // start at current and find _first_ occurrance
  1298.             lpszStop = lpszText + nLen - nLenFind + 1;
  1299.         }
  1300.         else
  1301.         {
  1302.             // start at top and find _last_ occurrance
  1303.             lpszStop = lpsz;
  1304.             lpsz = lpszText;
  1305.         }
  1306.  
  1307.         LPCTSTR lpszFound = NULL;
  1308.         while (lpsz <= lpszStop)
  1309.         {
  1310.             if (!bCase || (*lpsz == *lpszFind &&
  1311.                 (!_istlead(*lpsz) || lpsz[1] == lpszFind[1])))
  1312.             {
  1313.                 LPTSTR lpch = (LPTSTR)(lpsz + nLenFind);
  1314.                 TCHAR chSave = *lpch;
  1315.                 *lpch = '\0';
  1316.                 int nResult = (*pfnCompare)(lpsz, lpszFind);
  1317.                 *lpch = chSave;
  1318.                 if (nResult == 0)
  1319.                 {
  1320.                     lpszFound = lpsz;
  1321.                     if (iDir > 0)
  1322.                         break;
  1323.                 }
  1324.             }
  1325.             lpsz = _tcsinc(lpsz);
  1326.         }
  1327.         UnlockBuffer();
  1328.  
  1329.         if (lpszFound != NULL)
  1330.         {
  1331.             int n = (int)(lpszFound - lpszText);
  1332.             GetEditCtrl().SetSel(n, n+nLenFind);
  1333.             return TRUE;
  1334.         }
  1335.     }
  1336.     else
  1337.     {
  1338.         // single-byte string search
  1339.         UINT nCompare;
  1340.         if (iDir < 0)
  1341.             nCompare = (UINT)(lpsz - lpszText) + 1;
  1342.         else
  1343.             nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1;
  1344.  
  1345.         while (nCompare > 0)
  1346.         {
  1347.             ASSERT(lpsz >= lpszText);
  1348.             ASSERT(lpsz+nLenFind-1 <= lpszText+nLen-1);
  1349.  
  1350.             LPSTR lpch = (LPSTR)(lpsz + nLenFind);
  1351.             char chSave = *lpch;
  1352.             *lpch = '\0';
  1353.             int nResult = (*pfnCompare)(lpsz, lpszFind);
  1354.             *lpch = chSave;
  1355.             if (nResult == 0)
  1356.             {
  1357.                 UnlockBuffer();
  1358.                 int n = (int)(lpsz - lpszText);
  1359.                 GetEditCtrl().SetSel(n, n+nLenFind);
  1360.                 ASSERT_VALID(this);
  1361.                 return TRUE;
  1362.             }
  1363.  
  1364.             // restore character at end of search
  1365.             *lpch = chSave;
  1366.  
  1367.             // move on to next substring
  1368.             nCompare--;
  1369.             lpsz += iDir;
  1370.         }
  1371.         UnlockBuffer();
  1372.     }
  1373.  
  1374.     ASSERT_VALID(this);
  1375.     return FALSE;
  1376. }
  1377.  
  1378. void CEditView::OnTextNotFound(LPCTSTR)
  1379. {
  1380.     ASSERT_VALID(this);
  1381.     MessageBeep(0);
  1382. }
  1383. #endif // _WIN32_WCE_NO_FINDREPLACE
  1384.  
  1385. /////////////////////////////////////////////////////////////////////////////
  1386. // CEditView Tab Stops
  1387.  
  1388. void CEditView::SetTabStops(int nTabStops)
  1389. {
  1390.     ASSERT_VALID(this);
  1391.     m_nTabStops = nTabStops;
  1392.     GetEditCtrl().SetTabStops(m_nTabStops);
  1393.     Invalidate();
  1394.     ASSERT_VALID(this);
  1395. }
  1396.  
  1397. /////////////////////////////////////////////////////////////////////////////
  1398. // CEditView diagnostics
  1399.  
  1400. #ifdef _DEBUG
  1401. void CEditView::AssertValid() const
  1402. {
  1403.     CCtrlView::AssertValid();
  1404. #if !defined(_WIN32_WCE_NO_PRINTING)
  1405.     ASSERT_VALID(&m_aPageStart);
  1406.     if (m_hPrinterFont != NULL)
  1407.         ASSERT_VALID(CFont::FromHandle(m_hPrinterFont));
  1408.     if (m_hMirrorFont != NULL)
  1409.         ASSERT_VALID(CFont::FromHandle(m_hMirrorFont));
  1410. #endif // _WIN32_WCE_NO_PRINTING
  1411. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  1412.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1413.     if (pEditState->pFindReplaceDlg != NULL)
  1414.         ASSERT_VALID(pEditState->pFindReplaceDlg);
  1415. #endif // _WIN32_WCE_NO_FINDREPLACE
  1416. }
  1417.  
  1418. void CEditView::Dump(CDumpContext& dc) const
  1419. {
  1420.     CCtrlView::Dump(dc);
  1421.  
  1422.     dc << "m_nTabStops = " << m_nTabStops;
  1423. #if !defined(_WIN32_WCE_NO_PRINTING)
  1424.     if (m_hPrinterFont != NULL)
  1425.         dc << "\nm_hPrinterFont " << (UINT)m_hPrinterFont;
  1426.     if (m_hMirrorFont != NULL)
  1427.         dc << "\nm_hMirrorFont " << (UINT)m_hMirrorFont;
  1428.     dc << "\nm_aPageStart: " << &m_aPageStart;
  1429. #endif // _WIN32_WCE_NO_PRINTING
  1430. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  1431.     dc << "\nstatic member data:";
  1432.     _AFX_EDIT_STATE* pEditState = _afxEditState;
  1433.     if (pEditState->pFindReplaceDlg != NULL)
  1434.     {
  1435.         dc << "\npFindReplaceDlg = "
  1436.             << (void*)pEditState->pFindReplaceDlg;
  1437.         dc << "\nbFindOnly = " << pEditState->bFindOnly;
  1438.     }
  1439.     dc << "\nstrFind = " << pEditState->strFind;
  1440.     dc << "\nstrReplace = " << pEditState->strReplace;
  1441.     dc << "\nbCase = " << pEditState->bCase;
  1442.     dc << "\nbNext = " << pEditState->bNext;
  1443. #endif // _WIN32_WCE_NO_FINDREPLACE
  1444.  
  1445.     dc << "\n";
  1446. }
  1447. #endif //_DEBUG
  1448.  
  1449. #ifdef AFX_INIT_SEG
  1450. #pragma code_seg(AFX_INIT_SEG)
  1451. #endif
  1452.  
  1453. IMPLEMENT_DYNCREATE(CEditView, CCtrlView)
  1454.  
  1455. #pragma warning(disable: 4074)
  1456. #pragma init_seg(lib)
  1457.  
  1458. #if !defined(_WIN32_WCE_NO_FINDREPLACE)
  1459. PROCESS_LOCAL(_AFX_EDIT_STATE, _afxEditState)
  1460. #endif // _WIN32_WCE_NO_FINDREPLACE
  1461. /////////////////////////////////////////////////////////////////////////////
  1462.