home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
- #include <ctype.h>
-
- #ifdef AFX_CORE4_SEG
- #pragma code_seg(AFX_CORE4_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView
-
- #define new DEBUG_NEW
-
- AFX_STATIC const UINT _afxMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
-
- #ifdef _UNICODE
-
- AFX_STATIC_DATA HFONT _afxUnicodeFont = 0;
-
- void AFX_CDECL AfxEditviewTerm()
- {
- AfxDeleteObject((HGDIOBJ*)&_afxUnicodeFont);
- }
- char _afxEditviewTerm = (char)atexit(&AfxEditviewTerm);
-
- #endif //_UNICODE
-
- BEGIN_MESSAGE_MAP(CEditView, CCtrlView)
- //{{AFX_MSG_MAP(CEditView)
- ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
- ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
- ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
- ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
- ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
- ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
- ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
- ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
- ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
- ON_CONTROL_REFLECT_EX(EN_CHANGE, OnEditChange)
- ON_WM_CREATE()
- ON_MESSAGE(WM_SETFONT, OnSetFont)
- ON_COMMAND(ID_EDIT_CUT, OnEditCut)
- ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
- ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
- ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
- ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
- ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
- ON_COMMAND(ID_EDIT_FIND, OnEditFind)
- ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
- ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
- ON_WM_DESTROY()
- //}}AFX_MSG_MAP
- // Special registered message for Find and Replace
- ON_REGISTERED_MESSAGE(_afxMsgFindReplace, OnFindReplaceCmd)
- // Standard Print commands (print only - not preview)
- ON_COMMAND(ID_FILE_PRINT, CCtrlView::OnFilePrint)
- ON_COMMAND(ID_FILE_PRINT_DIRECT, CCtrlView::OnFilePrint)
- END_MESSAGE_MAP()
-
- const AFX_DATADEF DWORD CEditView::dwStyleDefault =
- AFX_WS_DEFAULT_VIEW |
- WS_HSCROLL | WS_VSCROLL |
- ES_AUTOHSCROLL | ES_AUTOVSCROLL |
- ES_MULTILINE | ES_NOHIDESEL;
-
- // Operating system specific maximum buffer limit
- const AFX_DATADEF UINT CEditView::nMaxSize = 1024U*1024U-1;
-
- /////////////////////////////////////////////////////////////////////////////
- // _AFX_EDIT_STATE
-
- _AFX_EDIT_STATE::_AFX_EDIT_STATE()
- {
- // Note: it is only necessary to initialize non-zero data.
-
- bNext = TRUE;
- }
-
- _AFX_EDIT_STATE::~_AFX_EDIT_STATE()
- {
- }
-
- EXTERN_PROCESS_LOCAL(_AFX_EDIT_STATE, _afxEditState)
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView construction/destruction
-
- // pass a NULL style because dwStyleDefault stays for backward compatibility
- CEditView::CEditView() : CCtrlView(_T("EDIT"), NULL)
- {
- m_nTabStops = 8*4; // default 8 character positions
- m_hPrinterFont = NULL;
- m_hMirrorFont = NULL;
- m_pShadowBuffer = NULL;
- m_nShadowSize = 0;
- }
-
- CEditView::~CEditView()
- {
- ASSERT(m_hWnd == NULL);
- ASSERT(m_pShadowBuffer == NULL || afxData.bWin95);
- delete[] m_pShadowBuffer;
- }
-
- BOOL CEditView::PreCreateWindow(CREATESTRUCT& cs)
- {
- m_dwDefaultStyle = dwStyleDefault;
- return CCtrlView::PreCreateWindow(cs);
- }
-
- int CEditView::OnCreate(LPCREATESTRUCT lpcs)
- {
- if (CCtrlView::OnCreate(lpcs) != 0)
- return -1;
-
- #ifdef _UNICODE
- AfxLockGlobals(CRIT_EDITVIEW);
- if (_afxUnicodeFont == NULL)
- {
- // get unicode font same size as system font
- HFONT hSystemFont = (HFONT)GetStockObject(SYSTEM_FONT);
- LOGFONT systemFont;
- VERIFY(::GetObject(hSystemFont, sizeof(LOGFONT), (void*)&systemFont));
-
- // default size and facename, but allow customization
- LOGFONT logFont; memset(&logFont, 0, sizeof(LOGFONT));
- logFont.lfHeight = systemFont.lfHeight;
- logFont.lfWeight = systemFont.lfWeight;
- logFont.lfCharSet = DEFAULT_CHARSET;
- lstrcpy(logFont.lfFaceName, _T("Lucida Sans Unicode"));
- AfxCustomLogFont(AFX_IDS_UNICODE_FONT, &logFont);
-
- // attempt to create the font
- _afxUnicodeFont = ::CreateFontIndirect(&logFont);
- if (_afxUnicodeFont == NULL)
- TRACE1("Unable to create unicode font '%s'.\n", logFont.lfFaceName);
- }
- AfxUnlockGlobals(CRIT_EDITVIEW);
- // set unicode font instead of using system font
- if (_afxUnicodeFont != NULL)
- SendMessage(WM_SETFONT, (WPARAM)_afxUnicodeFont);
- #endif
-
- GetEditCtrl().LimitText(nMaxSize);
- GetEditCtrl().SetTabStops(m_nTabStops);
-
- return 0;
- }
-
- void CEditView::OnDestroy()
- {
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- pEditState->pFindReplaceDlg = NULL;
-
- CView::OnDestroy();
- }
-
- // EDIT controls always turn off WS_BORDER and draw it themselves
- void CEditView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
- {
- if (nAdjustType != 0)
- {
- // default behavior for in-place editing handles scrollbars
- DWORD dwStyle = GetStyle();
- if (dwStyle & WS_VSCROLL)
- lpClientRect->right += afxData.cxVScroll - CX_BORDER;
- if (dwStyle & WS_HSCROLL)
- lpClientRect->bottom += afxData.cyHScroll - CY_BORDER;
- return;
- }
-
- ::AdjustWindowRectEx(lpClientRect, GetStyle() | WS_BORDER, FALSE,
- GetExStyle() & ~(WS_EX_CLIENTEDGE));
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView document like functions
-
- void CEditView::DeleteContents()
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd != NULL);
- SetWindowText(NULL);
- ASSERT_VALID(this);
- }
-
- void CEditView::Serialize(CArchive& ar)
- // Read and write CEditView object to archive, with length prefix.
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd != NULL);
- if (ar.IsStoring())
- {
- UINT nLen = GetBufferLength();
- ar << (DWORD)nLen;
- WriteToArchive(ar);
- }
- else
- {
- DWORD dwLen;
- ar >> dwLen;
- if (dwLen > nMaxSize)
- AfxThrowArchiveException(CArchiveException::badIndex);
- UINT nLen = (UINT)dwLen;
- ReadFromArchive(ar, nLen);
- }
- ASSERT_VALID(this);
- }
-
- void CEditView::ReadFromArchive(CArchive& ar, UINT nLen)
- // Read certain amount of text from the file, assume at least nLen
- // characters (not bytes) are in the file.
- {
- ASSERT_VALID(this);
-
- LPVOID hText = LocalAlloc(LMEM_MOVEABLE, (nLen+1)*sizeof(TCHAR));
- if (hText == NULL)
- AfxThrowMemoryException();
-
- LPTSTR lpszText = (LPTSTR)LocalLock(hText);
- ASSERT(lpszText != NULL);
- if (ar.Read(lpszText, nLen*sizeof(TCHAR)) != nLen*sizeof(TCHAR))
- {
- LocalUnlock(hText);
- LocalFree(hText);
- AfxThrowArchiveException(CArchiveException::endOfFile);
- }
- // Replace the editing edit buffer with the newly loaded data
- lpszText[nLen] = '\0';
- #ifndef _UNICODE
- if (afxData.bWin95)
- {
- // set the text with SetWindowText, then free
- BOOL bResult = ::SetWindowText(m_hWnd, lpszText);
- LocalUnlock(hText);
- LocalFree(hText);
-
- // make sure that SetWindowText was successful
- if (!bResult || ::GetWindowTextLength(m_hWnd) < (int)nLen)
- AfxThrowMemoryException();
-
- // remove old shadow buffer
- delete[] m_pShadowBuffer;
- m_pShadowBuffer = NULL;
- m_nShadowSize = 0;
-
- ASSERT_VALID(this);
- return;
- }
- #endif
- LocalUnlock(hText);
- HLOCAL hOldText = GetEditCtrl().GetHandle();
- ASSERT(hOldText != NULL);
- LocalFree(hOldText);
- GetEditCtrl().SetHandle((HLOCAL)(UINT)(DWORD)hText);
- Invalidate();
- ASSERT_VALID(this);
- }
-
- void CEditView::WriteToArchive(CArchive& ar)
- // Write just the text to an archive, no length prefix.
- {
- ASSERT_VALID(this);
- LPCTSTR lpszText = LockBuffer();
- ASSERT(lpszText != NULL);
- UINT nLen = GetBufferLength();
- TRY
- {
- ar.Write(lpszText, nLen*sizeof(TCHAR));
- }
- CATCH_ALL(e)
- {
- UnlockBuffer();
- THROW_LAST();
- }
- END_CATCH_ALL
- UnlockBuffer();
- ASSERT_VALID(this);
- }
-
- void CEditView::SerializeRaw(CArchive& ar)
- // Read/Write object as stand-alone file.
- {
- ASSERT_VALID(this);
- if (ar.IsStoring())
- {
- WriteToArchive(ar);
- }
- else
- {
- CFile* pFile = ar.GetFile();
- ASSERT(pFile->GetPosition() == 0);
- DWORD nFileSize = pFile->GetLength();
- if (nFileSize/sizeof(TCHAR) > nMaxSize)
- {
- AfxMessageBox(AFX_IDP_FILE_TOO_LARGE);
- AfxThrowUserException();
- }
- // ReadFromArchive takes the number of characters as argument
- ReadFromArchive(ar, (UINT)nFileSize/sizeof(TCHAR));
- }
- ASSERT_VALID(this);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView Printing Helpers
-
- AFX_STATIC UINT AFXAPI _AfxEndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex)
- {
- ASSERT(AfxIsValidAddress(lpszText, nLen, FALSE));
- LPCTSTR lpsz = lpszText + nIndex;
- LPCTSTR lpszStop = lpszText + nLen;
- while (lpsz < lpszStop && *lpsz != '\r')
- ++lpsz;
- return lpsz - lpszText;
- }
-
- AFX_STATIC UINT AFXAPI _AfxNextLine(LPCTSTR lpszText, UINT nLen, UINT nIndex)
- {
- ASSERT(AfxIsValidAddress(lpszText, nLen, FALSE));
- LPCTSTR lpsz = lpszText + nIndex;
- LPCTSTR lpszStop = lpszText + nLen;
- while (lpsz < lpszStop && *lpsz == '\r')
- ++lpsz;
- if (lpsz < lpszStop && *lpsz == '\n')
- ++lpsz;
- return lpsz - lpszText;
- }
-
- AFX_STATIC UINT AFXAPI
- _AfxClipLine(CDC* pDC, int aCharWidths[256], int cxLine, int nTabStop,
- LPCTSTR lpszText, UINT nIndex, UINT nIndexEnd)
- {
- ASSERT_VALID(pDC);
- ASSERT(nIndex < nIndexEnd);
- ASSERT(AfxIsValidAddress(lpszText, nIndexEnd, FALSE));
-
- TEXTMETRIC tm;
- ::GetTextMetrics(pDC->m_hDC, &tm);
-
- // make an initial guess on the number of characters that will fit
- int cx = 0;
- LPCTSTR lpszStart = lpszText + nIndex;
- LPCTSTR lpszStop = lpszText + nIndexEnd;
- LPCTSTR lpsz = lpszStart;
- while (lpsz < lpszStop)
- {
- if (*lpsz == '\t')
- cx += nTabStop - (cx % nTabStop);
- else
- {
- #ifdef _UNICODE
- if (*lpsz <= 0xFF)
- cx += aCharWidths[(BYTE)*lpsz];
- else
- cx += tm.tmAveCharWidth;
- #else //_UNICODE
- if (_afxDBCS && _istlead(*lpsz))
- {
- ++lpsz;
- cx += tm.tmAveCharWidth;
- }
- else
- cx += aCharWidths[(BYTE)*lpsz];
- #endif //!_UNICODE
- }
- ++lpsz;
- if (cx > cxLine)
- break;
- }
-
- // adjust for errors in the guess
- cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
- if (cx > cxLine)
- {
- // remove characters until it fits
- do
- {
- ASSERT(lpsz != lpszStart);
- if (_afxDBCS)
- lpsz = _tcsdec(lpszStart, lpsz);
- else
- --lpsz;
- cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
- } while (cx > cxLine);
- }
- else if (cx < cxLine)
- {
- // add characters until it doesn't fit
- while (lpsz < lpszStop)
- {
- lpsz = _tcsinc(lpsz);
- ASSERT(lpsz <= lpszStop);
- cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
- if (cx > cxLine)
- {
- if (_afxDBCS)
- lpsz = _tcsdec(lpszStart, lpsz);
- else
- --lpsz;
- break;
- }
- }
- }
-
- // return index of character just past the last that would fit
- return lpsz - lpszText;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView Printing support
-
- BOOL CEditView::OnPreparePrinting(CPrintInfo* pInfo)
- {
- return DoPreparePrinting(pInfo);
- }
-
- void CEditView::OnBeginPrinting(CDC* pDC, CPrintInfo*)
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pDC);
- // initialize page start vector
- ASSERT(m_aPageStart.GetSize() == 0);
- m_aPageStart.Add(0);
- ASSERT(m_aPageStart.GetSize() > 0);
-
- if (m_hPrinterFont == NULL)
- {
- // get current screen font object metrics
- CFont* pFont = GetFont();
- LOGFONT lf;
- LOGFONT lfSys;
- if (pFont == NULL)
- return;
- VERIFY(pFont->GetObject(sizeof(LOGFONT), &lf));
- VERIFY(::GetObject(::GetStockObject(SYSTEM_FONT), sizeof(LOGFONT),
- &lfSys));
- if (lstrcmpi((LPCTSTR)lf.lfFaceName, (LPCTSTR)lfSys.lfFaceName) == 0)
- return;
-
- // map to printer font metrics
- HDC hDCFrom = ::GetDC(NULL);
- lf.lfHeight = ::MulDiv(lf.lfHeight, pDC->GetDeviceCaps(LOGPIXELSY),
- ::GetDeviceCaps(hDCFrom, LOGPIXELSY));
- lf.lfWidth = ::MulDiv(lf.lfWidth, pDC->GetDeviceCaps(LOGPIXELSX),
- ::GetDeviceCaps(hDCFrom, LOGPIXELSX));
- ::ReleaseDC(NULL, hDCFrom);
-
- // create it, if it fails we just use the printer's default.
- m_hMirrorFont = ::CreateFontIndirect(&lf);
- m_hPrinterFont = m_hMirrorFont;
- }
- ASSERT_VALID(this);
- }
-
- BOOL CEditView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
- // attempts pagination to pInfo->m_nCurPage, TRUE == success
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pDC);
-
- CRect rectSave = pInfo->m_rectDraw;
- UINT nPageSave = pInfo->m_nCurPage;
- ASSERT(nPageSave > 1);
- ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
- VERIFY(pDC->SaveDC() != 0);
- pDC->IntersectClipRect(0, 0, 0, 0);
- pInfo->m_nCurPage = m_aPageStart.GetSize();
- while (pInfo->m_nCurPage < nPageSave)
- {
- ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
- OnPrepareDC(pDC, pInfo);
- ASSERT(pInfo->m_bContinuePrinting);
- pInfo->m_rectDraw.SetRect(0, 0,
- pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
- pDC->DPtoLP(&pInfo->m_rectDraw);
- OnPrint(pDC, pInfo);
- if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
- break;
- ++pInfo->m_nCurPage;
- }
- BOOL bResult = pInfo->m_nCurPage == nPageSave;
- pDC->RestoreDC(-1);
- pInfo->m_nCurPage = nPageSave;
- pInfo->m_rectDraw = rectSave;
- ASSERT_VALID(this);
- return bResult;
- }
-
- void CEditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pDC);
- ASSERT(pInfo != NULL); // overriding OnPaint -- never get this.
-
- if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
- !PaginateTo(pDC, pInfo))
- {
- // can't paginate to that page, thus cannot print it.
- pInfo->m_bContinuePrinting = FALSE;
- }
- ASSERT_VALID(this);
- }
-
- UINT CEditView::PrintInsideRect(CDC* pDC, RECT& rectLayout,
- UINT nIndexStart, UINT nIndexStop)
- // worker function for laying out text in a rectangle.
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pDC);
- BOOL bWordWrap = (GetStyle() & ES_AUTOHSCROLL) == 0;
-
- // get buffer and real starting and ending postions
- UINT nLen = GetBufferLength();
- if (nIndexStart >= nLen)
- return nLen;
- LPCTSTR lpszText = LockBuffer();
- if (nIndexStop > nLen)
- nIndexStop = nLen;
- ASSERT(nIndexStart < nLen);
-
- // calculate text & tab metrics
- TEXTMETRIC tm;
- pDC->GetTextMetrics(&tm);
- int cyChar = tm.tmHeight + tm.tmExternalLeading;
- int nTabStop = m_nTabStops *
- pDC->GetTabbedTextExtent(_T("\t"), 1, 0, NULL).cx / 8 / 4;
- int aCharWidths[256];
- pDC->GetCharWidth(0, 255, aCharWidths);
-
- int y = rectLayout.top;
- UINT cx = rectLayout.right - rectLayout.left;
- UINT nIndex = nIndexStart;
-
- VERIFY(pDC->SaveDC() != 0);
- BOOL bLayoutOnly = pDC->IntersectClipRect(&rectLayout) == NULLREGION;
-
- do
- {
- UINT nIndexEnd = _AfxEndOfLine(lpszText, nIndexStop, nIndex);
- if (nIndex == nIndexEnd)
- {
- y += cyChar;
- }
- else if (bWordWrap)
- {
- // word-wrap printing
- do
- {
- UINT nIndexWrap = _AfxClipLine(pDC, aCharWidths,
- cx, nTabStop, lpszText, nIndex, nIndexEnd);
- UINT nIndexWord = nIndexWrap;
- if (nIndexWord != nIndexEnd)
- {
- while (nIndexWord > nIndex &&
- !_istspace(lpszText[nIndexWord]))
- {
- nIndexWord--;
- }
- if (nIndexWord == nIndex)
- nIndexWord = nIndexWrap;
- }
- CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
- if (!bLayoutOnly && pDC->RectVisible(rect))
- {
- pDC->TabbedTextOut(rect.left, y,
- (LPCTSTR)(lpszText+nIndex), nIndexWord-nIndex, 1,
- &nTabStop, rect.left);
- }
- y += cyChar;
- nIndex = nIndexWord;
- while (nIndex < nIndexEnd && _istspace(lpszText[nIndex]))
- nIndex++;
- } while (nIndex < nIndexEnd && y+cyChar <= rectLayout.bottom);
-
- nIndexEnd = nIndex;
- }
- else
- {
- // non-word wrap printing (much easier and faster)
- CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
- if (!bLayoutOnly && pDC->RectVisible(rect))
- {
- UINT nIndexClip = _AfxClipLine(pDC, aCharWidths, cx, nTabStop,
- lpszText, nIndex, nIndexEnd);
- if (nIndexClip < nIndexEnd)
- {
- if (_istlead(*(lpszText+nIndexClip)))
- nIndexClip++;
- nIndexClip++;
- }
- pDC->TabbedTextOut(rect.left, y,
- (LPCTSTR)(lpszText+nIndex), nIndexClip-nIndex, 1,
- &nTabStop, rect.left);
- }
- y += cyChar;
- }
- nIndex = _AfxNextLine(lpszText, nIndexStop, nIndexEnd);
- }
- while (nIndex < nIndexStop && y+cyChar <= rectLayout.bottom);
-
- pDC->RestoreDC(-1);
- UnlockBuffer();
- ASSERT_VALID(this);
-
- rectLayout.bottom = y;
- return nIndex;
- }
-
- void CEditView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
- {
- ASSERT_VALID(this);
- ASSERT_VALID(pDC);
- ASSERT(pInfo != NULL);
- ASSERT(pInfo->m_bContinuePrinting);
-
- CFont* pOldFont = NULL;
- if (m_hPrinterFont != NULL)
- pOldFont = pDC->SelectObject(CFont::FromHandle(m_hPrinterFont));
- pDC->SetBkMode(TRANSPARENT);
-
- UINT nPage = pInfo->m_nCurPage;
- ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
- UINT nIndex = m_aPageStart[nPage-1];
-
- // print as much as possible in the current page.
- nIndex = PrintInsideRect(pDC, pInfo->m_rectDraw, nIndex, GetBufferLength());
-
- if (pOldFont != NULL)
- pDC->SelectObject(pOldFont);
-
- // update pagination information for page just printed
- if (nPage == (UINT)m_aPageStart.GetSize())
- {
- if (nIndex < GetBufferLength())
- m_aPageStart.Add(nIndex);
- }
- else
- {
- ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
- ASSERT(nIndex == m_aPageStart[nPage+1-1]);
- }
- }
-
- void CEditView::OnEndPrinting(CDC*, CPrintInfo*)
- {
- ASSERT_VALID(this);
-
- m_aPageStart.RemoveAll();
- if (m_hMirrorFont != NULL && m_hPrinterFont == m_hMirrorFont)
- {
- AfxDeleteObject((HGDIOBJ*)&m_hMirrorFont);
- m_hPrinterFont = NULL;
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView commands
-
- void CEditView::OnUpdateNeedSel(CCmdUI* pCmdUI)
- {
- ASSERT_VALID(this);
- int nStartChar, nEndChar;
- GetEditCtrl().GetSel(nStartChar, nEndChar);
- pCmdUI->Enable(nStartChar != nEndChar);
- ASSERT_VALID(this);
- }
-
- void CEditView::OnUpdateNeedClip(CCmdUI* pCmdUI)
- {
- ASSERT_VALID(this);
- pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
- ASSERT_VALID(this);
- }
-
- void CEditView::OnUpdateNeedText(CCmdUI* pCmdUI)
- {
- ASSERT_VALID(this);
- pCmdUI->Enable(GetWindowTextLength() != 0);
- ASSERT_VALID(this);
- }
-
- void CEditView::OnUpdateNeedFind(CCmdUI* pCmdUI)
- {
- ASSERT_VALID(this);
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- pCmdUI->Enable(GetWindowTextLength() != 0 &&
- !pEditState->strFind.IsEmpty());
- ASSERT_VALID(this);
- }
-
- void CEditView::OnUpdateEditUndo(CCmdUI* pCmdUI)
- {
- ASSERT_VALID(this);
- pCmdUI->Enable(GetEditCtrl().CanUndo());
- ASSERT_VALID(this);
- }
-
- BOOL CEditView::OnEditChange()
- {
- ASSERT_VALID(this);
- GetDocument()->SetModifiedFlag();
- ASSERT_VALID(this);
-
- return FALSE; // continue routing
- }
-
- void CEditView::OnEditCut()
- {
- ASSERT_VALID(this);
- GetEditCtrl().Cut();
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditCopy()
- {
- ASSERT_VALID(this);
- GetEditCtrl().Copy();
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditPaste()
- {
- ASSERT_VALID(this);
- GetEditCtrl().Paste();
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditClear()
- {
- ASSERT_VALID(this);
- GetEditCtrl().Clear();
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditUndo()
- {
- ASSERT_VALID(this);
- GetEditCtrl().Undo();
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditSelectAll()
- {
- ASSERT_VALID(this);
- GetEditCtrl().SetSel(0, -1);
- ASSERT_VALID(this);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView Font Handling
-
- LRESULT CEditView::OnSetFont(WPARAM, LPARAM)
- {
- ASSERT_VALID(this);
- Default();
- GetEditCtrl().SetTabStops(m_nTabStops);
- ASSERT_VALID(this);
- return 0;
- }
-
- void CEditView::SetPrinterFont(CFont* pFont)
- {
- ASSERT_VALID(this);
- m_hPrinterFont = (HFONT)pFont->GetSafeHandle();
- ASSERT_VALID(this);
- }
-
- CFont* CEditView::GetPrinterFont() const
- {
- ASSERT_VALID(this);
- return CFont::FromHandle(m_hPrinterFont);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView attributes
-
- LPCTSTR CEditView::LockBuffer() const
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd != NULL);
- #ifndef _UNICODE
- if (afxData.bWin95)
- {
- // under Win32s, it is necessary to maintain a shadow buffer
- // it is only updated when the control contents have been changed.
- if (m_pShadowBuffer == NULL || GetEditCtrl().GetModify())
- {
- ASSERT(m_pShadowBuffer != NULL || m_nShadowSize == 0);
- UINT nSize = GetWindowTextLength()+1;
- if (nSize > m_nShadowSize)
- {
- // need more room for shadow buffer
- CEditView* pThis = (CEditView*)this;
- delete[] m_pShadowBuffer;
- pThis->m_pShadowBuffer = NULL;
- pThis->m_nShadowSize = 0;
- pThis->m_pShadowBuffer = new TCHAR[nSize];
- pThis->m_nShadowSize = nSize;
- }
-
- // update the shadow buffer with GetWindowText
- ASSERT(m_nShadowSize >= nSize);
- ASSERT(m_pShadowBuffer != NULL);
- GetWindowText(m_pShadowBuffer, nSize);
-
- // turn off edit control's modify bit
- GetEditCtrl().SetModify(FALSE);
- }
- return m_pShadowBuffer;
- }
- #endif
- // else -- running under non-subset Win32 system
- HLOCAL hLocal = GetEditCtrl().GetHandle();
- ASSERT(hLocal != NULL);
- LPCTSTR lpszText = (LPCTSTR)LocalLock(hLocal);
- ASSERT(lpszText != NULL);
- ASSERT_VALID(this);
- return lpszText;
- }
-
- void CEditView::UnlockBuffer() const
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd != NULL);
- #ifndef _UNICODE
- if (afxData.bWin95)
- return;
- #endif
- HLOCAL hLocal = GetEditCtrl().GetHandle();
- ASSERT(hLocal != NULL);
- LocalUnlock(hLocal);
- }
-
- // this function returns the length in characters
- UINT CEditView::GetBufferLength() const
- {
- ASSERT_VALID(this);
- ASSERT(m_hWnd != NULL);
- LPCTSTR lpszText = LockBuffer();
- UINT nLen = lstrlen(lpszText);
- UnlockBuffer();
- return nLen;
- }
-
- void CEditView::GetSelectedText(CString& strResult) const
- {
- ASSERT_VALID(this);
- int nStartChar, nEndChar;
- GetEditCtrl().GetSel(nStartChar, nEndChar);
- ASSERT((UINT)nEndChar <= GetBufferLength());
- LPCTSTR lpszText = ((CEditView*)this)->LockBuffer();
- UINT nLen = _AfxEndOfLine(lpszText, nEndChar, nStartChar) - nStartChar;
- memcpy(strResult.GetBuffer(nLen), lpszText + nStartChar,
- nLen * sizeof(TCHAR));
- strResult.ReleaseBuffer(nLen);
- UnlockBuffer();
- ASSERT_VALID(this);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView Find & Replace
-
- void CEditView::OnEditFind()
- {
- ASSERT_VALID(this);
- OnEditFindReplace(TRUE);
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditReplace()
- {
- ASSERT_VALID(this);
- OnEditFindReplace(FALSE);
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditRepeat()
- {
- ASSERT_VALID(this);
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- if (!FindText(pEditState->strFind,
- pEditState->bNext,
- pEditState->bCase))
- {
- OnTextNotFound(pEditState->strFind);
- }
- ASSERT_VALID(this);
- }
-
- void CEditView::OnEditFindReplace(BOOL bFindOnly)
- {
- ASSERT_VALID(this);
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- if (pEditState->pFindReplaceDlg != NULL)
- {
- if (pEditState->bFindOnly == bFindOnly)
- {
- pEditState->pFindReplaceDlg->SetActiveWindow();
- pEditState->pFindReplaceDlg->ShowWindow(SW_SHOW);
- return;
- }
- ASSERT(pEditState->bFindOnly != bFindOnly);
- pEditState->pFindReplaceDlg->SendMessage(WM_CLOSE);
- ASSERT(pEditState->pFindReplaceDlg == NULL);
- ASSERT_VALID(this);
- }
-
- CString strFind;
- GetSelectedText(strFind);
- if (strFind.IsEmpty())
- strFind = pEditState->strFind;
- CString strReplace = pEditState->strReplace;
- pEditState->pFindReplaceDlg = new CFindReplaceDialog;
- ASSERT(pEditState->pFindReplaceDlg != NULL);
- DWORD dwFlags = FR_HIDEWHOLEWORD;
- if (pEditState->bNext)
- dwFlags |= FR_DOWN;
- if (pEditState->bCase)
- dwFlags |= FR_MATCHCASE;
- if (!pEditState->pFindReplaceDlg->Create(bFindOnly, strFind,
- strReplace, dwFlags, this))
- {
- pEditState->pFindReplaceDlg = NULL;
- ASSERT_VALID(this);
- return;
- }
-
- pEditState->pFindReplaceDlg->SetActiveWindow();
- pEditState->pFindReplaceDlg->ShowWindow(SW_SHOW);
- ASSERT(pEditState->pFindReplaceDlg != NULL);
- pEditState->bFindOnly = bFindOnly;
- ASSERT_VALID(this);
- }
-
- void CEditView::OnFindNext(LPCTSTR lpszFind, BOOL bNext, BOOL bCase)
- {
- ASSERT_VALID(this);
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- pEditState->strFind = lpszFind;
- pEditState->bCase = bCase;
- pEditState->bNext = bNext;
-
- if (!FindText(pEditState->strFind, bNext, bCase))
- OnTextNotFound(pEditState->strFind);
- ASSERT_VALID(this);
- }
-
- void CEditView::OnReplaceSel(LPCTSTR lpszFind, BOOL bNext, BOOL bCase,
- LPCTSTR lpszReplace)
- {
- ASSERT_VALID(this);
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- pEditState->strFind = lpszFind;
- pEditState->strReplace = lpszReplace;
- pEditState->bCase = bCase;
- pEditState->bNext = bNext;
-
- if (!InitializeReplace())
- return;
-
- GetEditCtrl().ReplaceSel(pEditState->strReplace);
- FindText(pEditState->strFind, bNext, bCase);
- ASSERT_VALID(this);
- }
-
- void CEditView::OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bCase)
- {
- ASSERT_VALID(this);
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- pEditState->strFind = lpszFind;
- pEditState->strReplace = lpszReplace;
- pEditState->bCase = bCase;
- pEditState->bNext = TRUE;
-
- if (!InitializeReplace() &&
- !SameAsSelected(pEditState->strFind, pEditState->bCase))
- {
- // initial find was not successful
- return;
- }
-
- do
- {
- GetEditCtrl().ReplaceSel(pEditState->strReplace);
- } while (FindText(pEditState->strFind, 1, bCase));
-
- ASSERT_VALID(this);
- }
-
- BOOL CEditView::InitializeReplace()
- // helper to do find first if no selection
- {
- ASSERT_VALID(this);
-
- _AFX_EDIT_STATE* pEditState = _afxEditState;
-
- // do find next if no selection
- int nStartChar, nEndChar;
- GetEditCtrl().GetSel(nStartChar, nEndChar);
- if (nStartChar == nEndChar)
- {
- if (!FindText(pEditState->strFind, pEditState->bNext,
- pEditState->bCase))
- {
- // text not found
- OnTextNotFound(pEditState->strFind);
- }
- return FALSE;
- }
-
- if (!SameAsSelected(pEditState->strFind, pEditState->bCase))
- {
- if (!FindText(pEditState->strFind, pEditState->bNext,
- pEditState->bCase))
- {
- // text not found
- OnTextNotFound(pEditState->strFind);
- }
- return FALSE;
- }
-
- ASSERT_VALID(this);
- return TRUE;
- }
-
- LRESULT CEditView::OnFindReplaceCmd(WPARAM, LPARAM lParam)
- {
- ASSERT_VALID(this);
-
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- CFindReplaceDialog* pDialog = CFindReplaceDialog::GetNotifier(lParam);
- ASSERT(pDialog != NULL);
- ASSERT(pDialog == pEditState->pFindReplaceDlg);
- if (pDialog->IsTerminating())
- {
- pEditState->pFindReplaceDlg = NULL;
- }
- else if (pDialog->FindNext())
- {
- OnFindNext(pDialog->GetFindString(),
- pDialog->SearchDown(), pDialog->MatchCase());
- }
- else if (pDialog->ReplaceCurrent())
- {
- ASSERT(!pEditState->bFindOnly);
- OnReplaceSel(pDialog->GetFindString(),
- pDialog->SearchDown(), pDialog->MatchCase(),
- pDialog->GetReplaceString());
- }
- else if (pDialog->ReplaceAll())
- {
- ASSERT(!pEditState->bFindOnly);
- OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),
- pDialog->MatchCase());
- }
- ASSERT_VALID(this);
- return 0;
- }
-
- typedef int (WINAPI* AFX_COMPARE_PROC)(LPCTSTR str1, LPCTSTR str2);
-
- BOOL CEditView::SameAsSelected(LPCTSTR lpszCompare, BOOL bCase)
- {
- // check length first
- size_t nLen = lstrlen(lpszCompare);
- int nStartChar, nEndChar;
- GetEditCtrl().GetSel(nStartChar, nEndChar);
- if (nLen != (size_t)(nEndChar - nStartChar))
- return FALSE;
-
- // length is the same, check contents
- CString strSelect;
- GetSelectedText(strSelect);
- return (bCase && lstrcmp(lpszCompare, strSelect) == 0) ||
- (!bCase && lstrcmpi(lpszCompare, strSelect) == 0);
- }
-
- BOOL CEditView::FindText(LPCTSTR lpszFind, BOOL bNext, BOOL bCase)
- {
- ASSERT_VALID(this);
- ASSERT(lpszFind != NULL);
- ASSERT(*lpszFind != '\0');
-
- UINT nLen = GetBufferLength();
- int nStartChar, nEndChar;
- GetEditCtrl().GetSel(nStartChar, nEndChar);
- UINT nStart = nStartChar;
- int iDir = bNext ? +1 : -1;
-
- // can't find a match before the first character
- if (nStart == 0 && iDir < 0)
- return FALSE;
-
- CWaitCursor wait;
- LPCTSTR lpszText = LockBuffer();
-
- if (iDir < 0)
- {
- // always go back one for search backwards
- nStart -= (lpszText+nStart) -
- _tcsdec(lpszText, lpszText+nStart);
- }
- else if (nStartChar != nEndChar && SameAsSelected(lpszFind, bCase))
- {
- // easy to go backward/forward with SBCS
- if (_istlead(lpszText[nStart]))
- nStart++;
- nStart += iDir;
- }
-
- // handle search with nStart past end of buffer
- size_t nLenFind = lstrlen(lpszFind);
- if (nStart+nLenFind-1 >= nLen)
- {
- if (iDir < 0 && nLen >= nLenFind)
- {
- if (_afxDBCS)
- {
- // walk back to previous character n times
- nStart = nLen;
- int n = nLenFind;
- while (n--)
- {
- nStart -= (lpszText+nStart) -
- _tcsdec(lpszText, lpszText+nStart);
- }
- }
- else
- {
- // single-byte character set is easy and fast
- nStart = nLen - nLenFind;
- }
- ASSERT(nStart+nLenFind-1 <= nLen);
- }
- else
- {
- UnlockBuffer();
- return FALSE;
- }
- }
-
- // start the search at nStart
- LPCTSTR lpsz = lpszText + nStart;
- AFX_COMPARE_PROC pfnCompare = bCase ? lstrcmp : lstrcmpi;
-
- if (_afxDBCS)
- {
- // double-byte string search
- LPCTSTR lpszStop;
- if (iDir > 0)
- {
- // start at current and find _first_ occurrance
- lpszStop = lpszText + nLen - nLenFind + 1;
- }
- else
- {
- // start at top and find _last_ occurrance
- lpszStop = lpsz;
- lpsz = lpszText;
- }
-
- LPCTSTR lpszFound = NULL;
- while (lpsz <= lpszStop)
- {
- if (!bCase || (*lpsz == *lpszFind &&
- (!_istlead(*lpsz) || lpsz[1] == lpszFind[1])))
- {
- LPTSTR lpch = (LPTSTR)(lpsz + nLenFind);
- TCHAR chSave = *lpch;
- *lpch = '\0';
- int nResult = (*pfnCompare)(lpsz, lpszFind);
- *lpch = chSave;
- if (nResult == 0)
- {
- lpszFound = lpsz;
- if (iDir > 0)
- break;
- }
- }
- lpsz = _tcsinc(lpsz);
- }
- UnlockBuffer();
-
- if (lpszFound != NULL)
- {
- int n = (int)(lpszFound - lpszText);
- GetEditCtrl().SetSel(n, n+nLenFind);
- return TRUE;
- }
- }
- else
- {
- // single-byte string search
- UINT nCompare;
- if (iDir < 0)
- nCompare = (UINT)(lpsz - lpszText) + 1;
- else
- nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1;
-
- while (nCompare > 0)
- {
- ASSERT(lpsz >= lpszText);
- ASSERT(lpsz+nLenFind-1 <= lpszText+nLen-1);
-
- LPSTR lpch = (LPSTR)(lpsz + nLenFind);
- char chSave = *lpch;
- *lpch = '\0';
- int nResult = (*pfnCompare)(lpsz, lpszFind);
- *lpch = chSave;
- if (nResult == 0)
- {
- UnlockBuffer();
- int n = (int)(lpsz - lpszText);
- GetEditCtrl().SetSel(n, n+nLenFind);
- ASSERT_VALID(this);
- return TRUE;
- }
-
- // restore character at end of search
- *lpch = chSave;
-
- // move on to next substring
- nCompare--;
- lpsz += iDir;
- }
- UnlockBuffer();
- }
-
- ASSERT_VALID(this);
- return FALSE;
- }
-
- void CEditView::OnTextNotFound(LPCTSTR)
- {
- ASSERT_VALID(this);
- MessageBeep(0);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView Tab Stops
-
- void CEditView::SetTabStops(int nTabStops)
- {
- ASSERT_VALID(this);
- m_nTabStops = nTabStops;
- GetEditCtrl().SetTabStops(m_nTabStops);
- Invalidate();
- ASSERT_VALID(this);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // CEditView diagnostics
-
- #ifdef _DEBUG
- void CEditView::AssertValid() const
- {
- CCtrlView::AssertValid();
- ASSERT_VALID(&m_aPageStart);
- if (m_hPrinterFont != NULL)
- ASSERT_VALID(CFont::FromHandle(m_hPrinterFont));
- if (m_hMirrorFont != NULL)
- ASSERT_VALID(CFont::FromHandle(m_hMirrorFont));
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- if (pEditState->pFindReplaceDlg != NULL)
- ASSERT_VALID(pEditState->pFindReplaceDlg);
- }
-
- void CEditView::Dump(CDumpContext& dc) const
- {
- CCtrlView::Dump(dc);
-
- dc << "m_nTabStops = " << m_nTabStops;
- if (m_hPrinterFont != NULL)
- dc << "\nm_hPrinterFont " << (UINT)m_hPrinterFont;
- if (m_hMirrorFont != NULL)
- dc << "\nm_hMirrorFont " << (UINT)m_hMirrorFont;
- dc << "\nm_aPageStart: " << &m_aPageStart;
- dc << "\nstatic member data:";
- _AFX_EDIT_STATE* pEditState = _afxEditState;
- if (pEditState->pFindReplaceDlg != NULL)
- {
- dc << "\npFindReplaceDlg = "
- << (void*)pEditState->pFindReplaceDlg;
- dc << "\nbFindOnly = " << pEditState->bFindOnly;
- }
- dc << "\nstrFind = " << pEditState->strFind;
- dc << "\nstrReplace = " << pEditState->strReplace;
- dc << "\nbCase = " << pEditState->bCase;
- dc << "\nbNext = " << pEditState->bNext;
-
- dc << "\n";
- }
- #endif //_DEBUG
-
- #ifdef AFX_INIT_SEG
- #pragma code_seg(AFX_INIT_SEG)
- #endif
-
- IMPLEMENT_DYNCREATE(CEditView, CCtrlView)
-
- #pragma warning(disable: 4074)
- #pragma init_seg(lib)
-
- PROCESS_LOCAL(_AFX_EDIT_STATE, _afxEditState)
-
- /////////////////////////////////////////////////////////////////////////////
-