123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- // Windows Template Library - WTL version 10.0
- // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
- //
- // This file is a part of the Windows Template Library.
- // The use and distribution terms for this software are covered by the
- // Microsoft Public License (http://opensource.org/licenses/MS-PL)
- // which can be found in the file MS-PL.txt at the root folder.
- #ifndef __ATLFIND_H__
- #define __ATLFIND_H__
- #pragma once
- #ifndef __ATLCTRLS_H__
- #error atlfind.h requires atlctrls.h to be included first
- #endif
- #ifndef __ATLDLGS_H__
- #error atlfind.h requires atldlgs.h to be included first
- #endif
- #ifndef __ATLSTR_H__
- #error atlfind.h requires CString
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // Classes in this file:
- //
- // CEditFindReplaceImplBase<T, TFindReplaceDialog>
- // CEditFindReplaceImpl<T, TFindReplaceDialog>
- // CRichEditFindReplaceImpl<T, TFindReplaceDialog>
- namespace WTL
- {
- ///////////////////////////////////////////////////////////////////////////////
- // CEditFindReplaceImplBase - Base class for mixin classes that
- // help implement Find/Replace for CEdit or CRichEditCtrl based window classes.
- template <class T, class TFindReplaceDialog = CFindReplaceDialog>
- class CEditFindReplaceImplBase
- {
- protected:
- // Typedefs
- typedef CEditFindReplaceImplBase<T, TFindReplaceDialog> thisClass;
- // Enumerations
- enum TranslationTextItem
- {
- eText_OnReplaceAllMessage = 0,
- eText_OnReplaceAllTitle = 1,
- eText_OnTextNotFoundMessage = 2,
- eText_OnTextNotFoundTitle = 3
- };
- public:
- // Data members
- TFindReplaceDialog* m_pFindReplaceDialog;
- ATL::CString m_sFindNext, m_sReplaceWith;
- BOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown;
- LONG m_nInitialSearchPos;
- HCURSOR m_hOldCursor;
- // Constructors
- CEditFindReplaceImplBase() :
- m_pFindReplaceDialog(NULL),
- m_bFindOnly(TRUE),
- m_bFirstSearch(TRUE),
- m_bMatchCase(FALSE),
- m_bWholeWord(FALSE),
- m_bFindDown(TRUE),
- m_nInitialSearchPos(0),
- m_hOldCursor(NULL)
- {
- }
- // Message Handlers
- BEGIN_MSG_MAP(thisClass)
- ALT_MSG_MAP(1)
- MESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd)
- COMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind)
- COMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat)
- COMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace)
- END_MSG_MAP()
- LRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- TFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam);
- if(pDialog == NULL)
- {
- ATLASSERT(FALSE);
- ::MessageBeep(MB_ICONERROR);
- return 1;
- }
- ATLASSERT(pDialog == m_pFindReplaceDialog);
- LPFINDREPLACE findReplace = (LPFINDREPLACE)lParam;
- if((m_pFindReplaceDialog != NULL) && (findReplace != NULL))
- {
- if(pDialog->FindNext())
- {
- pT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(),
- pDialog->MatchCase(), pDialog->MatchWholeWord());
- }
- else if(pDialog->ReplaceCurrent())
- {
- pT->OnReplaceSel(pDialog->GetFindString(),
- pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(),
- pDialog->GetReplaceString());
- }
- else if(pDialog->ReplaceAll())
- {
- pT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),
- pDialog->MatchCase(), pDialog->MatchWholeWord());
- }
- else if(pDialog->IsTerminating())
- {
- // Dialog is going away (but hasn't gone away yet)
- // OnFinalMessage will "delete this"
- pT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog);
- m_pFindReplaceDialog = NULL;
- }
- }
- return 0;
- }
- LRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->FindReplace(TRUE);
- return 0;
- }
- LRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- // If the user is holding down SHIFT when hitting F3, we'll
- // search in reverse. Otherwise, we'll search forward.
- // (be sure to have an accelerator mapped to ID_EDIT_REPEAT
- // for both F3 and Shift+F3)
- m_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000);
- if(m_sFindNext.IsEmpty())
- {
- pT->FindReplace(TRUE);
- }
- else
- {
- if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
- pT->TextNotFound(m_sFindNext);
- }
- return 0;
- }
- LRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)
- {
- T* pT = static_cast<T*>(this);
- DWORD style = pT->GetStyle();
- if((style & ES_READONLY) != ES_READONLY)
- {
- pT->FindReplace(FALSE);
- }
- else
- {
- // Don't allow replace when the edit control is read only
- bHandled = FALSE;
- }
- return 0;
- }
- // Operations (overrideable)
- TFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace
- LPCTSTR lpszFindWhat,
- LPCTSTR lpszReplaceWith = NULL,
- DWORD dwFlags = FR_DOWN,
- HWND hWndParent = NULL)
- {
- // You can override all of this in a derived class
- TFindReplaceDialog* findReplaceDialog = NULL;
- ATLTRY(findReplaceDialog = new TFindReplaceDialog());
- if(findReplaceDialog == NULL)
- {
- ::MessageBeep(MB_ICONHAND);
- }
- else
- {
- HWND hWndFindReplace = findReplaceDialog->Create(bFindOnly,
- lpszFindWhat, lpszReplaceWith, dwFlags, hWndParent);
- if(hWndFindReplace == NULL)
- {
- delete findReplaceDialog;
- findReplaceDialog = NULL;
- }
- else
- {
- findReplaceDialog->SetActiveWindow();
- findReplaceDialog->ShowWindow(SW_SHOW);
- }
- }
- return findReplaceDialog;
- }
- void AdjustDialogPosition(HWND hWndDialog)
- {
- ATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog));
- T* pT = static_cast<T*>(this);
- LONG nStartChar = 0, nEndChar = 0;
- // Send EM_GETSEL so we can use both Edit and RichEdit
- // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&)
- ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
- POINT point = pT->PosFromChar(nStartChar);
- pT->ClientToScreen(&point);
- RECT rect = {};
- ::GetWindowRect(hWndDialog, &rect);
- if(::PtInRect(&rect, point) != FALSE)
- {
- if(point.y > (rect.bottom - rect.top))
- {
- ::OffsetRect(&rect, 0, point.y - rect.bottom - 20);
- }
- else
- {
- int nVertExt = GetSystemMetrics(SM_CYSCREEN);
- if((point.y + (rect.bottom - rect.top)) < nVertExt)
- ::OffsetRect(&rect, 0, 40 + point.y - rect.top);
- }
- ::MoveWindow(hWndDialog, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
- }
- }
- DWORD GetFindReplaceDialogFlags() const
- {
- DWORD dwFlags = 0;
- if(m_bFindDown)
- dwFlags |= FR_DOWN;
- if(m_bMatchCase)
- dwFlags |= FR_MATCHCASE;
- if(m_bWholeWord)
- dwFlags |= FR_WHOLEWORD;
- return dwFlags;
- }
- void FindReplace(BOOL bFindOnly)
- {
- T* pT = static_cast<T*>(this);
- m_bFirstSearch = TRUE;
- if(m_pFindReplaceDialog != NULL)
- {
- if(m_bFindOnly == bFindOnly)
- {
- m_pFindReplaceDialog->SetActiveWindow();
- m_pFindReplaceDialog->ShowWindow(SW_SHOW);
- return;
- }
- else
- {
- m_pFindReplaceDialog->SendMessage(WM_CLOSE);
- ATLASSERT(m_pFindReplaceDialog == NULL);
- }
- }
- ATLASSERT(m_pFindReplaceDialog == NULL);
- ATL::CString findNext;
- pT->GetSelText(findNext);
- // if selection is empty or spans multiple lines use old find text
- if(findNext.IsEmpty() || (findNext.FindOneOf(_T("\n\r")) != -1))
- findNext = m_sFindNext;
- ATL::CString replaceWith = m_sReplaceWith;
- DWORD dwFlags = pT->GetFindReplaceDialogFlags();
- m_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly,
- findNext, replaceWith, dwFlags, pT->operator HWND());
- ATLASSERT(m_pFindReplaceDialog != NULL);
- if(m_pFindReplaceDialog != NULL)
- m_bFindOnly = bFindOnly;
- }
- BOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/)
- {
- T* pT = static_cast<T*>(this);
- // check length first
- size_t nLen = lstrlen(lpszCompare);
- LONG nStartChar = 0, nEndChar = 0;
- // Send EM_GETSEL so we can use both Edit and RichEdit
- // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&)
- ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);
- if(nLen != (size_t)(nEndChar - nStartChar))
- return FALSE;
- // length is the same, check contents
- ATL::CString selectedText;
- pT->GetSelText(selectedText);
- return (bMatchCase && (selectedText.Compare(lpszCompare) == 0)) ||
- (!bMatchCase && (selectedText.CompareNoCase(lpszCompare) == 0));
- }
- void TextNotFound(LPCTSTR lpszFind)
- {
- T* pT = static_cast<T*>(this);
- m_bFirstSearch = TRUE;
- pT->OnTextNotFound(lpszFind);
- }
- ATL::CString GetTranslationText(enum TranslationTextItem eItem) const
- {
- ATL::CString text;
- switch(eItem)
- {
- case eText_OnReplaceAllMessage:
- text = _T("Replaced %d occurances of \"%s\" with \"%s\"");
- break;
- case eText_OnReplaceAllTitle:
- text = _T("Replace All");
- break;
- case eText_OnTextNotFoundMessage:
- text = _T("Unable to find the text \"%s\"");
- break;
- case eText_OnTextNotFoundTitle:
- text = _T("Text not found");
- break;
- }
- return text;
- }
- // Overrideable Handlers
- void OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord)
- {
- T* pT = static_cast<T*>(this);
- m_sFindNext = lpszFind;
- m_bMatchCase = bMatchCase;
- m_bWholeWord = bWholeWord;
- m_bFindDown = bFindDown;
- if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
- pT->TextNotFound(m_sFindNext);
- else
- pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND());
- }
- void OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace)
- {
- T* pT = static_cast<T*>(this);
- m_sFindNext = lpszFind;
- m_sReplaceWith = lpszReplace;
- m_bMatchCase = bMatchCase;
- m_bWholeWord = bWholeWord;
- m_bFindDown = bFindDown;
- if(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord))
- pT->ReplaceSel(m_sReplaceWith);
- if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
- pT->TextNotFound(m_sFindNext);
- else
- pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND());
- }
- void OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord)
- {
- T* pT = static_cast<T*>(this);
- m_sFindNext = lpszFind;
- m_sReplaceWith = lpszReplace;
- m_bMatchCase = bMatchCase;
- m_bWholeWord = bWholeWord;
- m_bFindDown = TRUE;
- // no selection or different than what looking for
- if(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord))
- {
- if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))
- {
- pT->TextNotFound(m_sFindNext);
- return;
- }
- }
- pT->OnReplaceAllCoreBegin();
- int replaceCount=0;
- do
- {
- ++replaceCount;
- pT->ReplaceSel(m_sReplaceWith);
- } while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown));
- pT->OnReplaceAllCoreEnd(replaceCount);
- }
- void OnReplaceAllCoreBegin()
- {
- T* pT = static_cast<T*>(this);
- m_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
- pT->HideSelection(TRUE, FALSE);
- }
- void OnReplaceAllCoreEnd(int replaceCount)
- {
- T* pT = static_cast<T*>(this);
- pT->HideSelection(FALSE, FALSE);
- ::SetCursor(m_hOldCursor);
- ATL::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage);
- if(message.GetLength() > 0)
- {
- ATL::CString formattedMessage;
- formattedMessage.Format(message, replaceCount, (LPCTSTR)m_sFindNext, (LPCTSTR)m_sReplaceWith);
- if(m_pFindReplaceDialog != NULL)
- {
- m_pFindReplaceDialog->MessageBox(formattedMessage,
- pT->GetTranslationText(eText_OnReplaceAllTitle),
- MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
- }
- else
- {
- pT->MessageBox(formattedMessage,
- pT->GetTranslationText(eText_OnReplaceAllTitle),
- MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
- }
- }
- }
- void OnTextNotFound(LPCTSTR lpszFind)
- {
- T* pT = static_cast<T*>(this);
- ATL::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage);
- if(message.GetLength() > 0)
- {
- ATL::CString formattedMessage;
- formattedMessage.Format(message, lpszFind);
- if(m_pFindReplaceDialog != NULL)
- {
- m_pFindReplaceDialog->MessageBox(formattedMessage,
- pT->GetTranslationText(eText_OnTextNotFoundTitle),
- MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
- }
- else
- {
- pT->MessageBox(formattedMessage,
- pT->GetTranslationText(eText_OnTextNotFoundTitle),
- MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
- }
- }
- else
- {
- ::MessageBeep(MB_ICONHAND);
- }
- }
- void OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/)
- {
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit
- // based window classes.
- // Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit.
- // Example:
- // class CMyEdit : public CWindowImpl<CMyEdit, CEdit>,
- // public CEditFindReplaceImpl<CMyEdit>
- // {
- // public:
- // BEGIN_MSG_MAP(CMyEdit)
- // // your handlers...
- // CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl<CMyEdit>, 1)
- // END_MSG_MAP()
- // // other stuff...
- // };
- template <class T, class TFindReplaceDialog = CFindReplaceDialog>
- class CEditFindReplaceImpl : public CEditFindReplaceImplBase<T, TFindReplaceDialog>
- {
- protected:
- typedef CEditFindReplaceImpl<T, TFindReplaceDialog> thisClass;
- typedef CEditFindReplaceImplBase<T, TFindReplaceDialog> baseClass;
- public:
- // Message Handlers
- BEGIN_MSG_MAP(thisClass)
- ALT_MSG_MAP(1)
- CHAIN_MSG_MAP_ALT(baseClass, 1)
- END_MSG_MAP()
- // Operations
- // Supported only for RichEdit, so this does nothing for Edit
- void HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE)
- {
- }
- // Operations (overrideable)
- BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE)
- {
- T* pT = static_cast<T*>(this);
- ATLASSERT(lpszFind != NULL);
- ATLASSERT(*lpszFind != _T('\0'));
- UINT nLen = pT->GetBufferLength();
- int nStartChar = 0, nEndChar = 0;
- pT->GetSel(nStartChar, nEndChar);
- UINT nStart = nStartChar;
- int iDir = bFindDown ? +1 : -1;
- // can't find a match before the first character
- if((nStart == 0) && (iDir < 0))
- return FALSE;
- LPCTSTR lpszText = pT->LockBuffer();
- bool isDBCS = false;
- #ifdef _MBCS
- CPINFO info = {};
- ::GetCPInfo(::GetOEMCP(), &info);
- isDBCS = (info.MaxCharSize > 1);
- #endif
- if(iDir < 0)
- {
- // always go back one for search backwards
- nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart));
- }
- else if((nStartChar != nEndChar) && (pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord)))
- {
- // easy to go backward/forward with SBCS
- #ifndef _UNICODE
- if(::IsDBCSLeadByte(lpszText[nStart]))
- nStart++;
- #endif
- nStart += iDir;
- }
- // handle search with nStart past end of buffer
- UINT nLenFind = ::lstrlen(lpszFind);
- if((nStart + nLenFind - 1) >= nLen)
- {
- if((iDir < 0) && (nLen >= nLenFind))
- {
- if(isDBCS)
- {
- // walk back to previous character n times
- nStart = nLen;
- int n = nLenFind;
- while(n--)
- {
- nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart));
- }
- }
- else
- {
- // single-byte character set is easy and fast
- nStart = nLen - nLenFind;
- }
- ATLASSERT((nStart + nLenFind - 1) <= nLen);
- }
- else
- {
- pT->UnlockBuffer();
- return FALSE;
- }
- }
- // start the search at nStart
- LPCTSTR lpsz = lpszText + nStart;
- typedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2);
- CompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi;
- if(isDBCS)
- {
- // double-byte string search
- LPCTSTR lpszStop = NULL;
- 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)
- {
- #ifndef _UNICODE
- if(!bMatchCase || ((*lpsz == *lpszFind) && (!::IsDBCSLeadByte(*lpsz) || (lpsz[1] == lpszFind[1]))))
- #else
- if(!bMatchCase || ((*lpsz == *lpszFind) && (lpsz[1] == lpszFind[1])))
- #endif
- {
- LPTSTR lpch = (LPTSTR)(lpsz + nLenFind);
- TCHAR chSave = *lpch;
- *lpch = _T('\0');
- int nResult = (*pfnCompare)(lpsz, lpszFind);
- *lpch = chSave;
- if(nResult == 0)
- {
- lpszFound = lpsz;
- if(iDir > 0)
- break;
- }
- }
- lpsz = ::CharNext(lpsz);
- }
- pT->UnlockBuffer();
- if(lpszFound != NULL)
- {
- int n = (int)(lpszFound - lpszText);
- pT->SetSel(n, n + nLenFind);
- return TRUE;
- }
- }
- else
- {
- // single-byte string search
- UINT nCompare = 0;
- if(iDir < 0)
- nCompare = (UINT)(lpsz - lpszText) + 1;
- else
- nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1;
- while(nCompare > 0)
- {
- ATLASSERT(lpsz >= lpszText);
- ATLASSERT((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)
- {
- pT->UnlockBuffer();
- int n = (int)(lpsz - lpszText);
- pT->SetSel(n, n + nLenFind);
- return TRUE;
- }
- // restore character at end of search
- *lpch = chSave;
- // move on to next substring
- nCompare--;
- lpsz += iDir;
- }
- pT->UnlockBuffer();
- }
- return FALSE;
- }
- LPCTSTR LockBuffer() const
- {
- const T* pT = static_cast<const T*>(this);
- ATLASSERT(pT->m_hWnd != NULL);
- #ifndef _UNICODE
- // If common controls version 6 is in use (such as via theming), then EM_GETHANDLE
- // will always return a UNICODE string. You're really not supposed to superclass
- // or subclass common controls with an ANSI windows procedure.
- DWORD dwMajor = 0, dwMinor = 0;
- HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
- if(SUCCEEDED(hRet) && (dwMajor >= 6))
- {
- ATLTRACE2(atlTraceUI, 0, _T("AtlFind Warning: You have compiled for MBCS/ANSI but are using common controls version 6 or later which are always Unicode.\r\n"));
- ATLASSERT(FALSE);
- }
- #endif // !_UNICODE
- HLOCAL hLocal = pT->GetHandle();
- ATLASSERT(hLocal != NULL);
- LPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal);
- ATLASSERT(lpszText != NULL);
- return lpszText;
- }
- void UnlockBuffer() const
- {
- const T* pT = static_cast<const T*>(this);
- ATLASSERT(pT->m_hWnd != NULL);
- HLOCAL hLocal = pT->GetHandle();
- ATLASSERT(hLocal != NULL);
- ::LocalUnlock(hLocal);
- }
- UINT GetBufferLength() const
- {
- const T* pT = static_cast<const T*>(this);
- ATLASSERT(pT->m_hWnd != NULL);
- UINT nLen = 0;
- LPCTSTR lpszText = pT->LockBuffer();
- if(lpszText != NULL)
- nLen = ::lstrlen(lpszText);
- pT->UnlockBuffer();
- return nLen;
- }
- LONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const
- {
- LPCTSTR lpsz = lpszText + nIndex;
- LPCTSTR lpszStop = lpszText + nLen;
- while((lpsz < lpszStop) && (*lpsz != _T('\r')))
- ++lpsz;
- return LONG(lpsz - lpszText);
- }
- LONG GetSelText(ATL::CString& strText) const
- {
- const T* pT = static_cast<const T*>(this);
- int nStartChar = 0, nEndChar = 0;
- pT->GetSel(nStartChar, nEndChar);
- ATLASSERT((UINT)nEndChar <= pT->GetBufferLength());
- LPCTSTR lpszText = pT->LockBuffer();
- LONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar;
- ATL::Checked::memcpy_s(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR));
- strText.ReleaseBuffer(nLen);
- pT->UnlockBuffer();
- return nLen;
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl
- // based window classes.
- // Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl.
- // Example:
- // class CMyRichEdit : public CWindowImpl<CMyRichEdit, CRichEditCtrl>,
- // public CRichEditFindReplaceImpl<CMyRichEdit>
- // {
- // public:
- // BEGIN_MSG_MAP(CMyRichEdit)
- // // your handlers...
- // CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl<CMyRichEdit>, 1)
- // END_MSG_MAP()
- // // other stuff...
- // };
- template <class T, class TFindReplaceDialog = CFindReplaceDialog>
- class CRichEditFindReplaceImpl : public CEditFindReplaceImplBase<T, TFindReplaceDialog>
- {
- protected:
- typedef CRichEditFindReplaceImpl<T, TFindReplaceDialog> thisClass;
- typedef CEditFindReplaceImplBase<T, TFindReplaceDialog> baseClass;
- public:
- BEGIN_MSG_MAP(thisClass)
- ALT_MSG_MAP(1)
- CHAIN_MSG_MAP_ALT(baseClass, 1)
- END_MSG_MAP()
- // Operations (overrideable)
- BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE)
- {
- T* pT = static_cast<T*>(this);
- ATLASSERT(lpszFind != NULL);
- FINDTEXTEX ft = {};
- pT->GetSel(ft.chrg);
- if(this->m_bFirstSearch)
- {
- if(bFindDown)
- this->m_nInitialSearchPos = ft.chrg.cpMin;
- else
- this->m_nInitialSearchPos = ft.chrg.cpMax;
- this->m_bFirstSearch = FALSE;
- }
- ft.lpstrText = (LPTSTR)lpszFind;
- if(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection
- {
- if(bFindDown)
- {
- ft.chrg.cpMin++;
- }
- else
- {
- // won't wraparound backwards
- ft.chrg.cpMin = __max(ft.chrg.cpMin, 0);
- }
- }
- DWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0;
- dwFlags |= bWholeWord ? FR_WHOLEWORD : 0;
- ft.chrg.cpMax = pT->GetTextLength() + this->m_nInitialSearchPos;
- if(bFindDown)
- {
- if(this->m_nInitialSearchPos >= 0)
- ft.chrg.cpMax = pT->GetTextLength();
- dwFlags |= FR_DOWN;
- ATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin);
- }
- else
- {
- if(this->m_nInitialSearchPos >= 0)
- ft.chrg.cpMax = 0;
- dwFlags &= ~FR_DOWN;
- ATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin);
- }
- BOOL bRet = FALSE;
- if(pT->FindAndSelect(dwFlags, ft) != -1)
- {
- bRet = TRUE; // we found the text
- }
- else if(this->m_nInitialSearchPos > 0)
- {
- // if the original starting point was not the beginning
- // of the buffer and we haven't already been here
- if(bFindDown)
- {
- ft.chrg.cpMin = 0;
- ft.chrg.cpMax = this->m_nInitialSearchPos;
- }
- else
- {
- ft.chrg.cpMin = pT->GetTextLength();
- ft.chrg.cpMax = this->m_nInitialSearchPos;
- }
- this->m_nInitialSearchPos = this->m_nInitialSearchPos - pT->GetTextLength();
- bRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE;
- }
- return bRet;
- }
- long FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft)
- {
- T* pT = static_cast<T*>(this);
- LONG index = pT->FindText(dwFlags, ft);
- if(index != -1) // i.e. we found something
- pT->SetSel(ft.chrgText);
- return index;
- }
- };
- } // namespace WTL
- #endif // __ATLFIND_H__
|