viewedit.cpp 33 KB

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