home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / VIEWEDIT.CP_ / VIEWEDIT.CP
Encoding:
Text File  |  1993-02-08  |  27.2 KB  |  1,101 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 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 Microsoft
  7. // QuickHelp and/or WinHelp 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_CORE2_SEG
  15. #pragma code_seg(AFX_CORE2_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char BASED_CODE THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. /////////////////////////////////////////////////////////////////////////////
  24. // AFX_FRSTATE : last find/replace state
  25.  
  26. AFX_FRSTATE::AFX_FRSTATE()
  27. {
  28.     pFindReplaceDlg = NULL;
  29.     bCase = FALSE;
  30.     bNext = TRUE;
  31. }
  32.  
  33. #ifndef _AFXDLL
  34. static AFX_FRSTATE NEAR _afxLastFRState;
  35. #else
  36. #define _afxLastFRState (*_AfxGetAppData()->appLastFRState)
  37. #endif
  38.  
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CEditView
  41.  
  42. IMPLEMENT_DYNCREATE(CEditView, CView)
  43.  
  44. static const UINT NEAR nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
  45.  
  46. BEGIN_MESSAGE_MAP(CEditView, CView)
  47.     //{{AFX_MSG_MAP(CEditView)
  48.     ON_WM_CREATE()
  49.     ON_WM_PAINT()
  50.     ON_MESSAGE(WM_SETFONT, OnSetFont)
  51.     ON_EN_CHANGE(AFX_IDW_PANE_FIRST, OnEditChange)
  52.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
  53.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
  54.     ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
  55.     ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
  56.     ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  57.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  58.     ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  59.     ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  60.     ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
  61.     ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  62.     ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
  63.     ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
  64.     ON_COMMAND(ID_EDIT_FIND, OnEditFind)
  65.     ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
  66.     ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
  67.     ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
  68.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
  69.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
  70.     //}}AFX_MSG_MAP
  71.     ON_REGISTERED_MESSAGE(nMsgFindReplace, OnFindReplaceCmd)
  72.  
  73.     // Standard Print commands (print only - not preview)
  74.     ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  75. END_MESSAGE_MAP()
  76.  
  77. const DWORD CEditView::dwStyleDefault =
  78.     AFX_WS_DEFAULT_VIEW |
  79.     WS_HSCROLL | WS_VSCROLL |
  80.     ES_AUTOHSCROLL | ES_AUTOVSCROLL |
  81.     ES_MULTILINE | ES_NOHIDESEL;
  82.  
  83. // Operating system specific maximum buffer limit
  84. const UINT CEditView::nMaxSize = 42U*1024U;
  85.  
  86. // class name for control creation
  87. static char BASED_CODE szClassName[] = "EDIT";
  88.  
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CEditView construction/destruction
  91.  
  92. CEditView::CEditView()
  93. {
  94.     m_segText = NULL;
  95.     m_nTabStops = 8*4;  // default 8 character positions
  96.     m_hPrinterFont = NULL;
  97.     m_hMirrorFont = NULL;
  98. }
  99.  
  100. CEditView::~CEditView()
  101. {
  102.     ASSERT(m_hWnd == NULL);
  103.     if (m_segText != NULL)
  104.     {
  105.         HGLOBAL hText = (HGLOBAL)GlobalHandle((UINT)m_segText);
  106.         ASSERT(hText != NULL);
  107.         GlobalUnlock(hText);
  108.         GlobalFree(hText);
  109.     }
  110. }
  111.  
  112. WNDPROC* CEditView::GetSuperWndProcAddr()
  113. {
  114.     static WNDPROC NEAR pfnSuper;
  115.     return &pfnSuper;
  116. }
  117.  
  118. BOOL CEditView::PreCreateWindow(CREATESTRUCT& cs)
  119. {
  120.     ASSERT(cs.lpszClass == NULL);
  121.     cs.lpszClass = szClassName;
  122.  
  123.     if (m_segText == NULL)
  124.     {
  125.         // global alloc segment for edit control to use
  126.         HGLOBAL hText = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, 512);
  127.         if (hText == NULL)
  128.             return FALSE;
  129.         void FAR* p = GlobalLock(hText);
  130.         ASSERT(LOWORD(p) == 0);
  131.         m_segText = _AFX_FP_SEG(p);
  132.     }
  133.     ASSERT(m_segText != NULL);
  134.     cs.hInstance = (HINSTANCE)m_segText;
  135.  
  136.     // map default CView style to default CEditView style
  137.     if (cs.style == AFX_WS_DEFAULT_VIEW)
  138.         cs.style = dwStyleDefault;
  139.  
  140.     return TRUE;
  141. }
  142.  
  143. int CEditView::OnCreate(LPCREATESTRUCT lpcs)
  144. {
  145.     if (CView::OnCreate(lpcs) != 0)
  146.         return -1;
  147.     GetEditCtrl().LimitText(nMaxSize);
  148.     GetEditCtrl().SetTabStops(m_nTabStops);
  149.     return 0;
  150. }
  151.  
  152.  
  153. // EDIT controls always turn off WS_BORDER and draw it themselves
  154. void CEditView::CalcWindowRect(LPRECT lpClientRect)
  155. {
  156.     ::AdjustWindowRect(lpClientRect, GetStyle() | WS_BORDER, FALSE);
  157. }
  158.  
  159. /////////////////////////////////////////////////////////////////////////////
  160. // CEditView document like functions
  161.  
  162. void CEditView::DeleteContents()
  163. {
  164.     ASSERT_VALID(this);
  165.     ASSERT(m_hWnd != NULL);
  166.     SetWindowText(NULL);
  167.     ASSERT_VALID(this);
  168. }
  169.  
  170. void CEditView::Serialize(CArchive& ar)
  171.     // Read and write CEditView object to archive, with length prefix.
  172. {
  173.     ASSERT_VALID(this);
  174.     ASSERT(m_hWnd != NULL);
  175.     if (ar.IsStoring())
  176.     {
  177.         UINT nLen = GetBufferLength();
  178.         ar << (DWORD)nLen;
  179.         WriteToArchive(ar);
  180.     }
  181.     else
  182.     {
  183.         DWORD dwLen;
  184.         ar >> dwLen;
  185.         if (dwLen > nMaxSize)
  186.         {
  187.             AfxThrowArchiveException(CArchiveException::badIndex);
  188.             ASSERT(FALSE);
  189.         }
  190.         UINT nLen = (UINT)dwLen;
  191.         ReadFromArchive(ar, nLen);
  192.     }
  193.     ASSERT_VALID(this);
  194. }
  195.  
  196. void CEditView::ReadFromArchive(CArchive& ar, UINT nLen)
  197.     // Read certain amount of text from the file, assume at least nLen
  198.     // bytes are in the file.
  199. {
  200.     ASSERT_VALID(this);
  201.     LPVOID hText = _AfxLocalAlloc(m_segText, LMEM_MOVEABLE, nLen+1);
  202.     if (hText == NULL)
  203.     {
  204.         AfxThrowMemoryException();
  205.         ASSERT(FALSE);
  206.     }
  207.     LPSTR lpszText = (LPSTR)_AfxLocalLock(hText);
  208.     ASSERT(lpszText != NULL);
  209.     if (ar.Read(lpszText, nLen) != nLen)
  210.     {
  211.         _AfxLocalUnlock(hText);
  212.         _AfxLocalFree(hText);
  213.         AfxThrowArchiveException(CArchiveException::endOfFile);
  214.         ASSERT(FALSE);
  215.     }
  216.     // Replace the editing edit buffer with the newly loaded data
  217.     lpszText[nLen] = '\0';
  218.     _AfxLocalUnlock(hText);
  219.     HLOCAL hOldText = GetEditCtrl().GetHandle();
  220.     ASSERT(hOldText != NULL);
  221.     _AfxLocalFree((LPVOID)MAKELONG(hOldText, m_segText));
  222.     GetEditCtrl().SetHandle((HLOCAL)(UINT)(DWORD)hText);
  223.     Invalidate();
  224.     ASSERT_VALID(this);
  225. }
  226.  
  227. void CEditView::WriteToArchive(CArchive& ar)
  228.     // Write just the text to an archive, no length prefix.
  229. {
  230.     ASSERT_VALID(this);
  231.     LPCSTR lpszText = LockBuffer();
  232.     ASSERT(lpszText != NULL);
  233.     UINT nLen = GetBufferLength();
  234.     TRY
  235.     {
  236.         ar.Write(lpszText, nLen);
  237.     }
  238.     CATCH_ALL(e)
  239.     {
  240.         UnlockBuffer();
  241.         THROW_LAST();
  242.         ASSERT(FALSE);
  243.     }
  244.     END_CATCH_ALL
  245.     UnlockBuffer();
  246.     ASSERT_VALID(this);
  247. }
  248.  
  249. void CEditView::SerializeRaw(CArchive& ar)
  250.     // Read/Write object as stand-alone file.
  251. {
  252.     ASSERT_VALID(this);
  253.     if (ar.IsStoring())
  254.     {
  255.         WriteToArchive(ar);
  256.     }
  257.     else
  258.     {
  259.         CFile* pFile = ar.GetFile();
  260.         ASSERT(pFile->GetPosition() == 0);
  261.         DWORD nFileSize = pFile->GetLength();
  262.         if (nFileSize > nMaxSize)
  263.         {
  264.             AfxMessageBox(AFX_IDP_FILE_TOO_LARGE);
  265.             AfxThrowUserException();
  266.             ASSERT(FALSE);
  267.         }
  268.         ReadFromArchive(ar, (UINT)nFileSize);
  269.     }
  270.     ASSERT_VALID(this);
  271. }
  272.  
  273. /////////////////////////////////////////////////////////////////////////////
  274. // CEditView drawing
  275.  
  276. void CEditView::OnPaint()
  277. {
  278.     // do not call CView::OnPaint since it will call OnDraw
  279.     CWnd::OnPaint();
  280. }
  281.  
  282. void CEditView::OnDraw(CDC*)
  283. {
  284.     // do nothing here since CWnd::OnPaint() will repaint the EDIT control
  285. }
  286.  
  287. /////////////////////////////////////////////////////////////////////////////
  288. // CEditView Printing Helpers
  289.  
  290. static UINT NEAR PASCAL
  291. EndOfLine(LPCSTR lpszText, UINT nLen, UINT nIndex)
  292. {
  293.     ASSERT(AfxIsValidAddress(lpszText, nLen, FALSE));
  294.     while (nIndex < nLen && lpszText[nIndex] != '\r')
  295.         nIndex++;
  296.     return nIndex;
  297. }
  298.  
  299. static UINT NEAR PASCAL
  300. NextLine(LPCSTR lpszText, UINT nLen, UINT nIndex)
  301. {
  302.     ASSERT(AfxIsValidAddress(lpszText, nLen, FALSE));
  303.     while (nIndex < nLen && lpszText[nIndex] == '\r')
  304.         nIndex++;
  305.     if (nIndex < nLen && lpszText[nIndex] == '\n')
  306.         nIndex++;
  307.     return nIndex;
  308. }
  309.  
  310. static UINT NEAR PASCAL
  311. ClipLine(CDC* pDC, int aCharWidths[256], UINT cxLine, int nTabStop,
  312.     LPCSTR lpszText, UINT nIndex, UINT nIndexEnd)
  313. {
  314.     ASSERT_VALID(pDC);
  315.     ASSERT(nIndex < nIndexEnd);
  316.     ASSERT(AfxIsValidAddress(lpszText, nIndexEnd, FALSE));
  317.  
  318.     lpszText += nIndex;
  319.     UINT nMax = nIndexEnd - nIndex;
  320.  
  321.     int cx = 0;
  322.     UINT n = 0;
  323.     while (n < nMax)
  324.     {
  325.         if (lpszText[n] == '\t')
  326.             cx += nTabStop - (cx % nTabStop);
  327.         else
  328.             cx += aCharWidths[lpszText[n]];
  329.         n++;
  330.         if ((UINT)cx > cxLine)
  331.             break;
  332.     }
  333.  
  334.     cx = pDC->GetTabbedTextExtent(lpszText, n, 1, &nTabStop).cx;
  335.     if ((UINT)cx > cxLine)
  336.     {
  337.         do
  338.         {
  339.             ASSERT(n != 0);
  340.             n--;
  341.             cx = pDC->GetTabbedTextExtent(lpszText, n, 1, &nTabStop).cx;
  342.         } while ((UINT)cx > cxLine);
  343.     }
  344.     else if ((UINT)cx < cxLine)
  345.     {
  346.         while (n < nMax)
  347.         {
  348.             n++;
  349.             ASSERT(n <= nMax);
  350.             cx = pDC->GetTabbedTextExtent(lpszText, n, 1, &nTabStop).cx;
  351.             if ((UINT)cx > cxLine)
  352.             {
  353.                 n--;
  354.                 break;
  355.             }
  356.         }
  357.     }
  358.  
  359.     ASSERT(nIndex + n <= nIndexEnd);
  360.     return nIndex + n;
  361. }
  362.  
  363. /////////////////////////////////////////////////////////////////////////////
  364. // CEditView Printing support
  365.  
  366. BOOL CEditView::OnPreparePrinting(CPrintInfo* pInfo)
  367. {
  368.     return DoPreparePrinting(pInfo);
  369. }
  370.  
  371. void CEditView::OnBeginPrinting(CDC* pDC, CPrintInfo*)
  372. {
  373.     ASSERT_VALID(this);
  374.     ASSERT_VALID(pDC);
  375.     // initialize page start vector
  376.     ASSERT(m_aPageStart.GetSize() == 0);
  377.     m_aPageStart.Add(0);
  378.     ASSERT(m_aPageStart.GetSize() > 0);
  379.  
  380.     if (m_hPrinterFont == NULL)
  381.     {
  382.         // get current screen font object metrics
  383.         CFont* pFont = GetFont();
  384.         LOGFONT lf;
  385.         if (pFont == NULL)
  386.             return;
  387.         pFont->GetObject(sizeof(LOGFONT), &lf);
  388.         static char BASED_CODE szSystem[] = "system";
  389.         if (lstrcmpi((LPCSTR)lf.lfFaceName, szSystem) == 0)
  390.             return;
  391.  
  392.         // map to printer font metrics
  393.         HDC hDCFrom = ::GetDC(NULL);
  394.         lf.lfHeight = ::MulDiv(lf.lfHeight, pDC->GetDeviceCaps(LOGPIXELSY),
  395.             ::GetDeviceCaps(hDCFrom, LOGPIXELSY));
  396.         lf.lfWidth = ::MulDiv(lf.lfWidth, pDC->GetDeviceCaps(LOGPIXELSX),
  397.             ::GetDeviceCaps(hDCFrom, LOGPIXELSX));
  398.         ::ReleaseDC(NULL, hDCFrom);
  399.  
  400.         // create it, if it fails we just the the printer's default.
  401.         m_hMirrorFont = ::CreateFontIndirect(&lf);
  402.         m_hPrinterFont = m_hMirrorFont;
  403.     }
  404.     ASSERT_VALID(this);
  405. }
  406.  
  407.  
  408. BOOL
  409. CEditView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
  410.     // attempts pagination to pInfo->m_nCurPage, TRUE == success
  411. {
  412.     ASSERT_VALID(this);
  413.     ASSERT_VALID(pDC);
  414.  
  415.     CRect rectSave = pInfo->m_rectDraw;
  416.     UINT nPageSave = pInfo->m_nCurPage;
  417.     ASSERT(nPageSave > 1);
  418.     ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
  419.     int nSavedDC = pDC->SaveDC();
  420.     ASSERT(nSavedDC != 0);
  421.     pDC->IntersectClipRect(0, 0, 0, 0);
  422.     pInfo->m_nCurPage = m_aPageStart.GetSize();
  423.     while (pInfo->m_nCurPage < nPageSave)
  424.     {
  425.         ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
  426.         OnPrepareDC(pDC, pInfo);
  427.         ASSERT(pInfo->m_bContinuePrinting);
  428.         pInfo->m_rectDraw.SetRect(0, 0,
  429.             pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  430.         pDC->DPtoLP(&pInfo->m_rectDraw);
  431.         OnPrint(pDC, pInfo);
  432.         if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
  433.             break;
  434.         ++pInfo->m_nCurPage;
  435.     }
  436.     BOOL bResult = pInfo->m_nCurPage == nPageSave;
  437.     VERIFY(pDC->RestoreDC(nSavedDC));
  438.     pInfo->m_nCurPage = nPageSave;
  439.     pInfo->m_rectDraw = rectSave;
  440.     ASSERT_VALID(this);
  441.     return bResult;
  442. }
  443.  
  444. void CEditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  445. {
  446.     ASSERT_VALID(this);
  447.     ASSERT_VALID(pDC);
  448.     ASSERT(pInfo != NULL);  // overriding OnPaint -- never get this.
  449.  
  450.     if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
  451.         !PaginateTo(pDC, pInfo))
  452.     {
  453.         // can't paginate to that page, thus cannot print it.
  454.         pInfo->m_bContinuePrinting = FALSE;
  455.     }
  456.     ASSERT_VALID(this);
  457. }
  458.  
  459. UINT CEditView::PrintInsideRect(CDC* pDC, RECT& rectLayout,
  460.     UINT nIndexStart, UINT nIndexStop)
  461.     // worker function for laying out text in a rectangle.
  462. {
  463.     ASSERT_VALID(this);
  464.     ASSERT_VALID(pDC);
  465.     BOOL bWordWrap = (GetStyle() & ES_AUTOHSCROLL) == 0;
  466.  
  467.     // get buffer and real starting and ending postions
  468.     UINT nLen = GetBufferLength();
  469.     if (nIndexStart >= nLen)
  470.         return nLen;
  471.     LPCSTR lpszText = LockBuffer();
  472.     if (nIndexStop > nLen)
  473.         nIndexStop = nLen;
  474.     ASSERT(nIndexStart < nLen);
  475.  
  476.     // calculate text & tab metrics
  477.     TEXTMETRIC tm;
  478.     pDC->GetTextMetrics(&tm);
  479.     int cyChar = tm.tmHeight;
  480.     int nTabStop = m_nTabStops *
  481.         pDC->GetTabbedTextExtent("\t", 1, 0, NULL).cx / 8 / 4;
  482.     int aCharWidths[256];
  483.     pDC->GetCharWidth(0, 255, aCharWidths);
  484.  
  485.     int y = rectLayout.top;
  486.     UINT cx = rectLayout.right - rectLayout.left;
  487.     UINT nIndex = nIndexStart;
  488.  
  489.     int iSave = pDC->SaveDC();
  490.     BOOL bLayoutOnly = iSave != 0 &&
  491.         pDC->IntersectClipRect(&rectLayout) == NULLREGION;
  492.  
  493.     do
  494.     {
  495.         UINT nIndexEnd = EndOfLine(lpszText, nIndexStop, nIndex);
  496.         if (nIndex == nIndexEnd)
  497.         {
  498.             y += cyChar;
  499.             nIndex = NextLine(lpszText, nIndexStop, nIndexEnd);
  500.             continue;
  501.         }
  502.         if (bWordWrap)
  503.         {
  504.             // word-wrap printing
  505.             do
  506.             {
  507.                 UINT nIndexWrap = ClipLine(pDC, aCharWidths,
  508.                     cx, nTabStop, lpszText, nIndex, nIndexEnd);
  509.                 UINT nIndexWord = nIndexWrap;
  510.                 if (nIndexWord != nIndexEnd)
  511.                 {
  512.                     while (nIndexWord > nIndex &&
  513.                       !isspace(lpszText[nIndexWord]))
  514.                     {
  515.                         nIndexWord--;
  516.                     }
  517.                     if (nIndexWord == nIndex)
  518.                         nIndexWord = nIndexWrap;
  519.                 }
  520.                 CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
  521.                 if (!bLayoutOnly && pDC->RectVisible(rect))
  522.                 {
  523.                     pDC->TabbedTextOut(rect.left, y,
  524.                         (LPCSTR)(lpszText+nIndex), nIndexWord-nIndex, 1,
  525.                         &nTabStop, rect.left);
  526.                 }
  527.                 y += cyChar;
  528.                 nIndex = nIndexWord;
  529.                 while (nIndex < nIndexEnd && isspace(lpszText[nIndex]))
  530.                     nIndex++;
  531.             } while (nIndex < nIndexEnd && y+cyChar < rectLayout.bottom);
  532.  
  533.             nIndexEnd = nIndex;
  534.         }
  535.         else
  536.         {
  537.             // non-word wrap printing (much easier and faster)
  538.             CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
  539.             if (!bLayoutOnly && pDC->RectVisible(rect))
  540.             {
  541.                 UINT nIndexClip = ClipLine(pDC, aCharWidths, cx, nTabStop,
  542.                     lpszText, nIndex, nIndexEnd);
  543.                 if (nIndexClip < nIndexEnd)
  544.                     nIndexClip++;
  545.                 pDC->TabbedTextOut(rect.left, y,
  546.                     (LPCSTR)(lpszText+nIndex), nIndexClip-nIndex, 1,
  547.                     &nTabStop, rect.left);
  548.             }
  549.             y += cyChar;
  550.         }
  551.         nIndex = NextLine(lpszText, nIndexStop, nIndexEnd);
  552.     }
  553.     while (nIndex < nIndexStop && y+cyChar < rectLayout.bottom);
  554.  
  555.     if (iSave != 0)
  556.         pDC->RestoreDC(iSave);
  557.  
  558.     rectLayout.bottom = y;
  559.     UnlockBuffer();
  560.     ASSERT_VALID(this);
  561.     return nIndex;
  562. }
  563.  
  564. void CEditView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
  565. {
  566.     ASSERT_VALID(this);
  567.     ASSERT_VALID(pDC);
  568.     ASSERT(pInfo != NULL);
  569.     ASSERT(pInfo->m_bContinuePrinting);
  570.  
  571.     CFont* pOldFont = NULL;
  572.     if (m_hPrinterFont != NULL)
  573.         pOldFont = pDC->SelectObject(CFont::FromHandle(m_hPrinterFont));
  574.     pDC->SetBkMode(TRANSPARENT);
  575.  
  576.     UINT nPage = pInfo->m_nCurPage;
  577.     ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
  578.     UINT nIndex = m_aPageStart[nPage-1];
  579.  
  580.     // print as much as possible in the current page.
  581.     nIndex = PrintInsideRect(pDC, pInfo->m_rectDraw, nIndex, 0xFFFF);
  582.  
  583.     if (pOldFont != NULL)
  584.         pDC->SelectObject(pOldFont);
  585.  
  586.     // update pagination information for page just printed
  587.     if (nPage == (UINT)m_aPageStart.GetSize())
  588.     {
  589.         if (nIndex < GetBufferLength())
  590.             m_aPageStart.Add(nIndex);
  591.     }
  592.     else
  593.     {
  594.         ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
  595.         ASSERT(nIndex == m_aPageStart[nPage+1-1]);
  596.     }
  597. }
  598.  
  599. void CEditView::OnEndPrinting(CDC*, CPrintInfo*)
  600. {
  601.     ASSERT_VALID(this);
  602.  
  603.     m_aPageStart.RemoveAll();
  604.     if (m_hMirrorFont != NULL && m_hPrinterFont == m_hMirrorFont)
  605.     {
  606.         ::DeleteObject(m_hMirrorFont);
  607.         m_hMirrorFont = NULL;
  608.         m_hPrinterFont = NULL;
  609.     }
  610. }
  611.  
  612. /////////////////////////////////////////////////////////////////////////////
  613. // CEditView commands
  614.  
  615. void CEditView::OnUpdateNeedSel(CCmdUI* pCmdUI)
  616. {
  617.     ASSERT_VALID(this);
  618.     int nStartChar, nEndChar;
  619.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  620.     pCmdUI->Enable(nStartChar != nEndChar);
  621.     ASSERT_VALID(this);
  622. }
  623.  
  624. void CEditView::OnUpdateNeedClip(CCmdUI* pCmdUI)
  625. {
  626.     ASSERT_VALID(this);
  627.     pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
  628.     ASSERT_VALID(this);
  629. }
  630.  
  631. void CEditView::OnUpdateNeedText(CCmdUI* pCmdUI)
  632. {
  633.     ASSERT_VALID(this);
  634.     pCmdUI->Enable(GetBufferLength() != 0);
  635.     ASSERT_VALID(this);
  636. }
  637.  
  638. void CEditView::OnUpdateNeedFind(CCmdUI* pCmdUI)
  639. {
  640.     ASSERT_VALID(this);
  641.     pCmdUI->Enable(GetBufferLength() != 0 &&
  642.         !_afxLastFRState.strFind.IsEmpty());
  643.     ASSERT_VALID(this);
  644. }
  645.  
  646. void CEditView::OnUpdateEditUndo(CCmdUI* pCmdUI)
  647. {
  648.     ASSERT_VALID(this);
  649.     pCmdUI->Enable(GetEditCtrl().CanUndo());
  650.     ASSERT_VALID(this);
  651. }
  652.  
  653. void CEditView::OnEditChange()
  654. {
  655.     ASSERT_VALID(this);
  656.     GetDocument()->SetModifiedFlag();
  657.     ASSERT_VALID(this);
  658. }
  659.  
  660. void CEditView::OnEditCut()
  661. {
  662.     ASSERT_VALID(this);
  663.     GetEditCtrl().Cut();
  664.     ASSERT_VALID(this);
  665. }
  666.  
  667. void CEditView::OnEditCopy()
  668. {
  669.     ASSERT_VALID(this);
  670.     GetEditCtrl().Copy();
  671.     ASSERT_VALID(this);
  672. }
  673.  
  674. void CEditView::OnEditPaste()
  675. {
  676.     ASSERT_VALID(this);
  677.     GetEditCtrl().Paste();
  678.     ASSERT_VALID(this);
  679. }
  680.  
  681. void CEditView::OnEditClear()
  682. {
  683.     ASSERT_VALID(this);
  684.     GetEditCtrl().Clear();
  685.     ASSERT_VALID(this);
  686. }
  687.  
  688. void CEditView::OnEditUndo()
  689. {
  690.     ASSERT_VALID(this);
  691.     GetEditCtrl().Undo();
  692.     ASSERT_VALID(this);
  693. }
  694.  
  695. void CEditView::OnEditSelectAll()
  696. {
  697.     ASSERT_VALID(this);
  698.     GetEditCtrl().SetSel(0, -1);
  699.     ASSERT_VALID(this);
  700. }
  701.  
  702. /////////////////////////////////////////////////////////////////////////////
  703. // CEditView Font Handling
  704.  
  705. LRESULT CEditView::OnSetFont(WPARAM, LPARAM)
  706. {
  707.     ASSERT_VALID(this);
  708.     Default();
  709.     GetEditCtrl().SetTabStops(m_nTabStops);
  710.     ASSERT_VALID(this);
  711.     return 0;
  712. }
  713.  
  714. void CEditView::SetPrinterFont(CFont* pFont)
  715. {
  716.     ASSERT_VALID(this);
  717.     m_hPrinterFont = (HFONT)pFont->GetSafeHandle();
  718.     ASSERT_VALID(this);
  719. }
  720.  
  721. CFont* CEditView::GetPrinterFont() const
  722. {
  723.     ASSERT_VALID(this);
  724.     return CFont::FromHandle(m_hPrinterFont);
  725. }
  726.  
  727. /////////////////////////////////////////////////////////////////////////////
  728. // CEditView attributes
  729.  
  730. LPCSTR CEditView::LockBuffer() const
  731. {
  732.     ASSERT_VALID(this);
  733.     ASSERT(m_hWnd != NULL);
  734.     HLOCAL hLocal = GetEditCtrl().GetHandle();
  735.     ASSERT(hLocal != NULL);
  736.     LPCSTR lpszText = _AfxLocalLock((LPVOID)MAKELONG(hLocal, m_segText));
  737.     ASSERT(_AFX_FP_SEG(lpszText) == m_segText);
  738.     ASSERT_VALID(this);
  739.     return lpszText;
  740. }
  741.  
  742. void CEditView::UnlockBuffer() const
  743. {
  744.     ASSERT_VALID(this);
  745.     ASSERT(m_hWnd != NULL);
  746.     HLOCAL hLocal = GetEditCtrl().GetHandle();
  747.     ASSERT(hLocal != NULL);
  748.     _AfxLocalUnlock((LPVOID)MAKELONG(hLocal, m_segText));
  749. }
  750.  
  751. UINT CEditView::GetBufferLength() const
  752. {
  753.     ASSERT_VALID(this);
  754.     ASSERT(m_hWnd != NULL);
  755.     UINT nLen = GetWindowTextLength();
  756.     return nLen;
  757. }
  758.  
  759. void CEditView::GetSelectedText(CString& strResult) const
  760. {
  761.     ASSERT_VALID(this);
  762.     int nStartChar, nEndChar;
  763.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  764.     LPCSTR lpszText = ((CEditView*)this)->LockBuffer();
  765.     UINT nIndex = nStartChar;
  766.     ASSERT((UINT)nEndChar <= GetBufferLength());
  767.     UINT nIndexEnd = nIndex;
  768.     while (nIndexEnd < (UINT)nEndChar && lpszText[nIndexEnd] != '\r')
  769.         nIndexEnd++;
  770.     UINT nLen = nIndexEnd - nIndex;
  771.     _fmemcpy(strResult.GetBuffer(nLen), lpszText+nIndex, nLen);
  772.     strResult.ReleaseBuffer(nLen);
  773.     UnlockBuffer();
  774.     ASSERT_VALID(this);
  775. }
  776.  
  777. /////////////////////////////////////////////////////////////////////////////
  778. // CEditView Find & Replace
  779.  
  780. void CEditView::OnEditFind()
  781. {
  782.     ASSERT_VALID(this);
  783.     OnEditFindReplace(TRUE);
  784.     ASSERT_VALID(this);
  785. }
  786.  
  787. void CEditView::OnEditReplace()
  788. {
  789.     ASSERT_VALID(this);
  790.     OnEditFindReplace(FALSE);
  791.     ASSERT_VALID(this);
  792. }
  793.  
  794. void CEditView::OnEditRepeat()
  795. {
  796.     ASSERT_VALID(this);
  797.     if (!FindText(_afxLastFRState.strFind, _afxLastFRState.bNext,
  798.         _afxLastFRState.bCase))
  799.     {
  800.         OnTextNotFound(_afxLastFRState.strFind);
  801.     }
  802.     ASSERT_VALID(this);
  803. }
  804.  
  805. void CEditView::OnEditFindReplace(BOOL bFindOnly)
  806. {
  807.     ASSERT_VALID(this);
  808.     if (_afxLastFRState.pFindReplaceDlg != NULL)
  809.     {
  810.         if (_afxLastFRState.bFindOnly == bFindOnly)
  811.         {
  812.             _afxLastFRState.pFindReplaceDlg->SetActiveWindow();
  813.             return;
  814.         }
  815.         else
  816.         {
  817.             ASSERT(_afxLastFRState.bFindOnly != bFindOnly);
  818.             _afxLastFRState.pFindReplaceDlg->SendMessage(WM_CLOSE);
  819.             ASSERT(_afxLastFRState.pFindReplaceDlg == NULL);
  820.             ASSERT_VALID(this);
  821.         }
  822.     }
  823.     CString strFind;
  824.     GetSelectedText(strFind);
  825.     if (strFind.IsEmpty())
  826.         strFind = _afxLastFRState.strFind;
  827.     CString strReplace = _afxLastFRState.strReplace;
  828.     _afxLastFRState.pFindReplaceDlg = new CFindReplaceDialog;
  829.     ASSERT(_afxLastFRState.pFindReplaceDlg != NULL);
  830.     DWORD dwFlags = FR_HIDEWHOLEWORD;
  831.     if (_afxLastFRState.bNext)
  832.         dwFlags |= FR_DOWN;
  833.     if (_afxLastFRState.bCase)
  834.         dwFlags |= FR_MATCHCASE;
  835.     if (!_afxLastFRState.pFindReplaceDlg->Create(bFindOnly, strFind,
  836.         strReplace, dwFlags, this))
  837.     {
  838.         _afxLastFRState.pFindReplaceDlg = NULL;
  839.         ASSERT_VALID(this);
  840.         return;
  841.     }
  842.     ASSERT(_afxLastFRState.pFindReplaceDlg != NULL);
  843.     _afxLastFRState.bFindOnly = bFindOnly;
  844.     ASSERT_VALID(this);
  845. }
  846.  
  847. void CEditView::OnFindNext(LPCSTR lpszFind, BOOL bNext, BOOL bCase)
  848. {
  849.     ASSERT_VALID(this);
  850.     _afxLastFRState.strFind = lpszFind;
  851.     _afxLastFRState.bCase = bCase;
  852.     _afxLastFRState.bNext = bNext;
  853.  
  854.     if (!FindText(_afxLastFRState.strFind, bNext, bCase))
  855.         OnTextNotFound(_afxLastFRState.strFind);
  856.     ASSERT_VALID(this);
  857. }
  858.  
  859. void
  860. CEditView::OnReplaceSel(LPCSTR lpszFind, BOOL bNext, BOOL bCase,
  861.     LPCSTR lpszReplace)
  862. {
  863.     ASSERT_VALID(this);
  864.     _afxLastFRState.strFind = lpszFind;
  865.     _afxLastFRState.strReplace = lpszReplace;
  866.     _afxLastFRState.bCase = bCase;
  867.     _afxLastFRState.bNext = bNext;
  868.  
  869.     if (!InitializeReplace())
  870.         return;
  871.  
  872.     GetEditCtrl().ReplaceSel(_afxLastFRState.strReplace);
  873.     FindText(_afxLastFRState.strFind, bNext, bCase);
  874.     ASSERT_VALID(this);
  875. }
  876.  
  877. void
  878. CEditView::OnReplaceAll(LPCSTR lpszFind, LPCSTR lpszReplace, BOOL bCase)
  879. {
  880.     ASSERT_VALID(this);
  881.     _afxLastFRState.strFind = lpszFind;
  882.     _afxLastFRState.strReplace = lpszReplace;
  883.     _afxLastFRState.bCase = bCase;
  884.     _afxLastFRState.bNext = TRUE;
  885.  
  886.     if (!InitializeReplace())
  887.         return;
  888.  
  889.     do
  890.     {
  891.         GetEditCtrl().ReplaceSel(_afxLastFRState.strReplace);
  892.     } while (FindText(_afxLastFRState.strFind, 1, bCase));
  893.  
  894.     ASSERT_VALID(this);
  895. }
  896.  
  897. BOOL CEditView::InitializeReplace()
  898.     // helper to do find first if no selection
  899. {
  900.     ASSERT_VALID(this);
  901.  
  902.     // do find next if no selection
  903.     int nStartChar, nEndChar;
  904.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  905.     if (nStartChar == nEndChar)
  906.     {
  907.         if (!FindText(_afxLastFRState.strFind,
  908.           _afxLastFRState.bNext, _afxLastFRState.bCase))
  909.             OnTextNotFound(_afxLastFRState.strFind);
  910.         return FALSE;
  911.     }
  912.  
  913.     if (!SameAsSelected(_afxLastFRState.strFind, _afxLastFRState.bCase))
  914.     {
  915.         if (!FindText(_afxLastFRState.strFind,
  916.           _afxLastFRState.bNext, _afxLastFRState.bCase))
  917.             OnTextNotFound(_afxLastFRState.strFind);
  918.         return FALSE;
  919.     }
  920.  
  921.     ASSERT_VALID(this);
  922.     return TRUE;
  923. }
  924.  
  925. LRESULT CEditView::OnFindReplaceCmd(WPARAM, LPARAM lParam)
  926. {
  927.     ASSERT_VALID(this);
  928.     CFindReplaceDialog* pDialog = CFindReplaceDialog::GetNotifier(lParam);
  929.     ASSERT(pDialog != NULL);
  930.     ASSERT(pDialog == _afxLastFRState.pFindReplaceDlg);
  931.     if (pDialog->IsTerminating())
  932.     {
  933.         _afxLastFRState.pFindReplaceDlg = NULL;
  934.     }
  935.     else if (pDialog->FindNext())
  936.     {
  937.         OnFindNext(pDialog->GetFindString(),
  938.             pDialog->SearchDown(), pDialog->MatchCase());
  939.     }
  940.     else if (pDialog->ReplaceCurrent())
  941.     {
  942.         ASSERT(!_afxLastFRState.bFindOnly);
  943.         OnReplaceSel(pDialog->GetFindString(),
  944.             pDialog->SearchDown(), pDialog->MatchCase(),
  945.             pDialog->GetReplaceString());
  946.     }
  947.     else if (pDialog->ReplaceAll())
  948.     {
  949.         ASSERT(!_afxLastFRState.bFindOnly);
  950.         OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),
  951.             pDialog->MatchCase());
  952.     }
  953.     ASSERT_VALID(this);
  954.     return 0;
  955. }
  956.  
  957. typedef int (FAR __cdecl* AFX_COMPARE_PROC)
  958.     (const void FAR* str1, const void FAR* str2, size_t count);
  959.  
  960. BOOL CEditView::SameAsSelected(LPCSTR lpszCompare, BOOL bCase)
  961. {
  962.     // check length first
  963.     size_t nLen = lstrlen(lpszCompare);
  964.     int nStartChar, nEndChar;
  965.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  966.     if (nLen != (size_t)(nEndChar - nStartChar))
  967.         return FALSE;
  968.  
  969.     // length is the same, check contents
  970.     CString strSelect;
  971.     GetSelectedText(strSelect);
  972.     return (bCase && lstrcmp(lpszCompare, strSelect) == 0) ||
  973.         (!bCase && lstrcmpi(lpszCompare, strSelect) == 0);
  974. }
  975.  
  976. BOOL CEditView::FindText(LPCSTR lpszFind, BOOL bNext, BOOL bCase)
  977. {
  978.     ASSERT_VALID(this);
  979.     ASSERT(lpszFind != NULL);
  980.     ASSERT(*lpszFind != '\0');
  981.     UINT nLen = GetBufferLength();
  982.     int nStartChar, nEndChar;
  983.     GetEditCtrl().GetSel(nStartChar, nEndChar);
  984.     UINT nStart = nStartChar;
  985.     int iDir = bNext ? +1 : -1;
  986.  
  987.     if (nStartChar != nEndChar)
  988.     {
  989.         // search back and already at position zero, not found.
  990.         if (iDir == -1 && nStart == 0)
  991.             return FALSE;
  992.  
  993.         // jump ahead/back by one if find text is selected text
  994.         if (SameAsSelected(lpszFind, bCase))
  995.             nStart += iDir;
  996.     }
  997.  
  998.     size_t nLenSearch = lstrlen(lpszFind);
  999.     if (nStart+nLenSearch-1 >= nLen)
  1000.     {
  1001.         if (iDir == -1 && nLen >= nLenSearch)
  1002.         {
  1003.             nStart = nLen - nLenSearch;
  1004.             ASSERT(nStart+nLenSearch-1 < nLen);
  1005.         }
  1006.         else
  1007.             return FALSE;
  1008.     }
  1009.  
  1010.     LPCSTR lpszText = LockBuffer();
  1011.     LPCSTR lpsz = lpszText + nStart;
  1012.  
  1013.     AFX_COMPARE_PROC pfnCompare = bCase ? _fmemcmp : _fmemicmp;
  1014.     UINT nCompare;
  1015.     if (iDir < 0)
  1016.         nCompare = (UINT)(lpsz - lpszText) + 1;
  1017.     else
  1018.         nCompare = nLen - (UINT)(lpsz - lpszText) - nLenSearch + 1;
  1019.  
  1020.     while (nCompare > 0)
  1021.     {
  1022.         ASSERT(lpsz >= lpszText);
  1023.         ASSERT(lpsz+nLenSearch-1 <= lpszText+nLen-1);
  1024.         if ((*pfnCompare)(lpsz, lpszFind, nLenSearch) == 0)
  1025.         {
  1026.             UnlockBuffer();
  1027.             int n = (int)(lpsz - lpszText);
  1028.             GetEditCtrl().SetSel(n, n+nLenSearch);
  1029.             ASSERT_VALID(this);
  1030.             return TRUE;
  1031.         }
  1032.         nCompare--;
  1033.         lpsz += iDir;
  1034.     }
  1035.  
  1036.     UnlockBuffer();
  1037.     ASSERT_VALID(this);
  1038.     return FALSE;
  1039. }
  1040.  
  1041. void CEditView::OnTextNotFound(LPCSTR)
  1042. {
  1043.     ASSERT_VALID(this);
  1044.     MessageBeep(0);
  1045. }
  1046.  
  1047. /////////////////////////////////////////////////////////////////////////////
  1048. // CEditView Tab Stops
  1049.  
  1050. void CEditView::SetTabStops(int nTabStops)
  1051. {
  1052.     ASSERT_VALID(this);
  1053.     m_nTabStops = nTabStops;
  1054.     GetEditCtrl().SetTabStops(m_nTabStops);
  1055.     Invalidate();
  1056.     ASSERT_VALID(this);
  1057. }
  1058.  
  1059. /////////////////////////////////////////////////////////////////////////////
  1060. // CEditView diagnostics
  1061.  
  1062. #ifdef _DEBUG
  1063. void CEditView::AssertValid() const
  1064. {
  1065.     CView::AssertValid();
  1066.     ASSERT_VALID(&m_aPageStart);
  1067.     if (m_hPrinterFont != NULL)
  1068.         ASSERT_VALID(CFont::FromHandle(m_hPrinterFont));
  1069.     if (m_hMirrorFont != NULL)
  1070.         ASSERT_VALID(CFont::FromHandle(m_hMirrorFont));
  1071.     if (_afxLastFRState.pFindReplaceDlg != NULL)
  1072.         ASSERT_VALID(_afxLastFRState.pFindReplaceDlg);
  1073.     if (m_hWnd != NULL)
  1074.         ASSERT(m_segText != NULL);
  1075. }
  1076.  
  1077. void CEditView::Dump(CDumpContext& dc) const
  1078. {
  1079.     CView::Dump(dc);
  1080.     AFX_DUMP1(dc, "\nm_nTabStops = ", m_nTabStops);
  1081.     if (m_hPrinterFont != NULL)
  1082.         AFX_DUMP1(dc, "\nm_hPrinterFont ", (UINT)m_hPrinterFont);
  1083.     if (m_hMirrorFont != NULL)
  1084.         AFX_DUMP1(dc, "\nm_hMirrorFont ", (UINT)m_hMirrorFont);
  1085.     AFX_DUMP1(dc, "\nm_aPageStart ", &m_aPageStart);
  1086.     AFX_DUMP0(dc, "\n Static Member Data:");
  1087.     if (_afxLastFRState.pFindReplaceDlg != NULL)
  1088.     {
  1089.         AFX_DUMP1(dc, "\npFindReplaceDlg = ",
  1090.             (void*)_afxLastFRState.pFindReplaceDlg);
  1091.         AFX_DUMP1(dc, "\nbFindOnly = ", _afxLastFRState.bFindOnly);
  1092.     }
  1093.     AFX_DUMP1(dc, "\nstrFind = ", _afxLastFRState.strFind);
  1094.     AFX_DUMP1(dc, "\nstrReplace = ", _afxLastFRState.strReplace);
  1095.     AFX_DUMP1(dc, "\nbCase = ", _afxLastFRState.bCase);
  1096.     AFX_DUMP1(dc, "\nbNext = ", _afxLastFRState.bNext);
  1097. }
  1098. #endif //_DEBUG
  1099.  
  1100. /////////////////////////////////////////////////////////////////////////////
  1101.