You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
10 KiB
385 lines
10 KiB
/*
|
|
* misc notepad functions
|
|
* Copyright (C) 1984-2000 Microsoft Corporation
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
BOOL fCase = FALSE; // Flag specifying case sensitive search
|
|
BOOL fReverse = FALSE; // Flag for direction of search
|
|
|
|
extern HWND hDlgFind; // handle to modeless FindText window
|
|
|
|
LPTSTR ReverseScan(
|
|
LPTSTR lpSource,
|
|
LPTSTR lpLast,
|
|
LPTSTR lpSearch,
|
|
BOOL fCaseSensitive )
|
|
{
|
|
TCHAR cLastCharU;
|
|
TCHAR cLastCharL;
|
|
INT iLen;
|
|
|
|
cLastCharU= (TCHAR) (INT_PTR) CharUpper( (LPTSTR)(INT_PTR)(*lpSearch) );
|
|
cLastCharL= (TCHAR) (INT_PTR) CharLower( (LPTSTR)(INT_PTR)(*lpSearch) );
|
|
|
|
iLen = lstrlen(lpSearch);
|
|
|
|
if (!lpLast)
|
|
lpLast = lpSource + lstrlen(lpSource);
|
|
|
|
do
|
|
{
|
|
if (lpLast == lpSource)
|
|
return NULL;
|
|
|
|
--lpLast;
|
|
|
|
if (fCaseSensitive)
|
|
{
|
|
if (*lpLast != *lpSearch)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if( !( *lpLast == cLastCharU || *lpLast == cLastCharL ) )
|
|
continue;
|
|
}
|
|
|
|
if (fCaseSensitive)
|
|
{
|
|
if (!_tcsncmp( lpLast, lpSearch, iLen))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// compare whole string using locale specific comparison.
|
|
// do not use C runtime version since it may be wrong.
|
|
//
|
|
|
|
if( 2 == CompareString( LOCALE_USER_DEFAULT,
|
|
NORM_IGNORECASE | SORT_STRINGSORT | NORM_STOP_ON_NULL,
|
|
lpLast, iLen,
|
|
lpSearch, iLen) )
|
|
break;
|
|
}
|
|
} while (TRUE);
|
|
|
|
return lpLast;
|
|
}
|
|
|
|
LPTSTR ForwardScan(LPTSTR lpSource, LPTSTR lpSearch, BOOL fCaseSensitive )
|
|
{
|
|
TCHAR cFirstCharU;
|
|
TCHAR cFirstCharL;
|
|
int iLen = lstrlen(lpSearch);
|
|
|
|
cFirstCharU= (TCHAR) (INT_PTR) CharUpper( (LPTSTR)(INT_PTR)(*lpSearch) );
|
|
cFirstCharL= (TCHAR) (INT_PTR) CharLower( (LPTSTR)(INT_PTR)(*lpSearch) );
|
|
|
|
while (*lpSource)
|
|
{
|
|
if (fCaseSensitive)
|
|
{
|
|
if (*lpSource != *lpSearch)
|
|
{
|
|
lpSource++;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !( *lpSource == cFirstCharU || *lpSource == cFirstCharL ) )
|
|
{
|
|
lpSource++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (fCaseSensitive)
|
|
{
|
|
if (!_tcsncmp( lpSource, lpSearch, iLen))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if( 2 == CompareString( LOCALE_USER_DEFAULT,
|
|
NORM_IGNORECASE | SORT_STRINGSORT | NORM_STOP_ON_NULL,
|
|
lpSource, iLen,
|
|
lpSearch, iLen) )
|
|
break;
|
|
}
|
|
|
|
lpSource++;
|
|
}
|
|
|
|
return *lpSource ? lpSource : NULL;
|
|
}
|
|
|
|
|
|
// search forward or backward in the edit control text for the given pattern
|
|
// It is the responsibility of the caller to set the cursor
|
|
|
|
BOOL Search (TCHAR * szKey)
|
|
{
|
|
BOOL bStatus= FALSE;
|
|
TCHAR * pStart, *pMatch;
|
|
DWORD StartIndex, LineNum, EndIndex;
|
|
DWORD SelStart, SelEnd, i;
|
|
HANDLE hEText; // handle to edit text
|
|
UINT uSelState;
|
|
HMENU hMenu;
|
|
BOOL bSelectAll = FALSE;
|
|
|
|
|
|
if (!*szKey)
|
|
return( bStatus );
|
|
|
|
SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&SelStart, (LPARAM)&SelEnd);
|
|
|
|
|
|
// when we finish the search, we highlight the text found, and continue
|
|
// the search after the end of the highlighted position (in forward
|
|
// case) or from the begining of the highlighted position in the reverse
|
|
// direction (in reverse case). this would break if the user has
|
|
// selected all text. this hack would take care of it. (this is consistent
|
|
// with VC editors' search too.
|
|
|
|
hMenu = GetMenu(hwndNP);
|
|
uSelState = GetMenuState(GetSubMenu(hMenu, 1), M_SELECTALL, MF_BYCOMMAND);
|
|
if (uSelState == MF_GRAYED)
|
|
{
|
|
bSelectAll = TRUE;
|
|
SelStart = SelEnd =0;
|
|
}
|
|
|
|
|
|
//
|
|
// get pointer to edit control text to search
|
|
//
|
|
|
|
hEText= (HANDLE) SendMessage( hwndEdit, EM_GETHANDLE, 0, 0 );
|
|
if( !hEText ) // silently return if we can't get it
|
|
{
|
|
return( bStatus );
|
|
}
|
|
pStart= LocalLock( hEText );
|
|
if( !pStart )
|
|
{
|
|
return( bStatus );
|
|
}
|
|
|
|
if (fReverse)
|
|
{
|
|
// Get current line number
|
|
LineNum= (DWORD)SendMessage(hwndEdit, EM_LINEFROMCHAR, SelStart, 0);
|
|
// Get index to start of the line
|
|
StartIndex= (DWORD)SendMessage(hwndEdit, EM_LINEINDEX, LineNum, 0);
|
|
// Set upper limit for search text
|
|
EndIndex= SelStart;
|
|
pMatch= NULL;
|
|
|
|
// Search line by line, from LineNum to 0
|
|
i = LineNum;
|
|
while (TRUE)
|
|
{
|
|
pMatch= ReverseScan(pStart+StartIndex,pStart+EndIndex,szKey,fCase);
|
|
if (pMatch)
|
|
break;
|
|
// current StartIndex is the upper limit for the next search
|
|
EndIndex= StartIndex;
|
|
|
|
if (i)
|
|
{
|
|
// Get start of the next line
|
|
i-- ;
|
|
StartIndex = (DWORD)SendMessage(hwndEdit, EM_LINEINDEX, i, 0);
|
|
}
|
|
else
|
|
break ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pMatch= ForwardScan(pStart+SelEnd, szKey, fCase);
|
|
}
|
|
|
|
LocalUnlock(hEText);
|
|
|
|
if (pMatch == NULL)
|
|
{
|
|
//
|
|
// alert user on not finding any text unless it is replace all
|
|
//
|
|
if( !(FR.Flags & FR_REPLACEALL) )
|
|
{
|
|
HANDLE hPrevCursor= SetCursor( hStdCursor );
|
|
AlertBox( hDlgFind ? hDlgFind : hwndNP,
|
|
szNN,
|
|
szCFS,
|
|
szSearch,
|
|
MB_APPLMODAL | MB_OK | MB_ICONINFORMATION);
|
|
SetCursor( hPrevCursor );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelStart = (DWORD)(pMatch - pStart);
|
|
SendMessage( hwndEdit, EM_SETSEL, SelStart, SelStart+lstrlen(szKey));
|
|
|
|
// since we are selecting the found text, enable SelectAll again.
|
|
if (bSelectAll)
|
|
{
|
|
EnableMenuItem(GetSubMenu(hMenu, 1), M_SELECTALL, MF_ENABLED);
|
|
}
|
|
|
|
//
|
|
// show the selected text unless it is replace all
|
|
//
|
|
|
|
if( !(FR.Flags & FR_REPLACEALL) )
|
|
{
|
|
SendMessage(hwndEdit, EM_SCROLLCARET, 0, 0);
|
|
UpdateStatusBar( TRUE );
|
|
}
|
|
bStatus= TRUE; // found
|
|
}
|
|
|
|
return( bStatus );
|
|
}
|
|
|
|
// Recreate notepad edit window, get text from old window and put in new window.
|
|
// Called when user changes style from wrap on/off
|
|
//
|
|
// Called with the style of the new window
|
|
//
|
|
|
|
BOOL NpReCreate( long style )
|
|
{
|
|
RECT rcT1;
|
|
HWND hwndT1;
|
|
HANDLE hT1;
|
|
int cchTextNew;
|
|
TCHAR* pchText;
|
|
BOOL fWrapIsOn = ((style & WS_HSCROLL) != 0);
|
|
HCURSOR hPrevCursor;
|
|
BOOL bModified; // modify flag from old edit buffer
|
|
|
|
// if wordwrap, remove soft carriage returns
|
|
|
|
hPrevCursor= SetCursor( hWaitCursor ); // this may take some time...
|
|
if( fWrapIsOn )
|
|
{
|
|
GotoAndScrollInView(1); // get around MLE bug
|
|
|
|
SendMessage(hwndEdit, EM_FMTLINES, FALSE, 0L);
|
|
}
|
|
|
|
bModified= (SendMessage( hwndEdit, EM_GETMODIFY, 0,0 ) != 0);
|
|
|
|
cchTextNew= (int)SendMessage( hwndEdit, WM_GETTEXTLENGTH, 0, 0L );
|
|
hT1= LocalAlloc( LMEM_MOVEABLE, ByteCountOf(cchTextNew + 1) );
|
|
if( !hT1 )
|
|
{
|
|
// failed, restore wordwrap; insert soft carriage returns
|
|
if( fWrapIsOn )
|
|
{
|
|
SendMessage(hwndEdit, EM_FMTLINES, TRUE, 0L);
|
|
}
|
|
SetCursor( hPrevCursor );
|
|
return FALSE;
|
|
}
|
|
|
|
GetClientRect( hwndNP, (LPRECT)&rcT1 );
|
|
|
|
//
|
|
// save the current edit control text.
|
|
//
|
|
|
|
pchText= LocalLock (hT1);
|
|
SendMessage( hwndEdit, WM_GETTEXT, cchTextNew+1, (LPARAM)pchText );
|
|
hwndT1= CreateWindowEx( WS_EX_CLIENTEDGE,
|
|
TEXT("Edit"),
|
|
TEXT(""), // pchText
|
|
style,
|
|
0,
|
|
0,
|
|
rcT1.right,
|
|
rcT1.bottom,
|
|
hwndNP,
|
|
(HMENU)ID_EDIT,
|
|
hInstanceNP, NULL );
|
|
if( !hwndT1 )
|
|
{
|
|
SetCursor( hPrevCursor );
|
|
if( fWrapIsOn ) // restore wordwrap
|
|
{
|
|
SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
|
|
}
|
|
LocalUnlock(hT1);
|
|
LocalFree(hT1);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The user can "add" styles to the edit window after it is
|
|
// created (like WS_EX_RTLREADING) when language packs are installed.
|
|
// Preserve these styles when changing the word wrap.
|
|
//
|
|
|
|
SetWindowLong( hwndT1 ,
|
|
GWL_EXSTYLE ,
|
|
GetWindowLong( hwndEdit , GWL_EXSTYLE )|WS_EX_CLIENTEDGE ) ;
|
|
|
|
// Set font before set text to save time calculating
|
|
SendMessage( hwndT1, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0) );
|
|
|
|
if (!SendMessage (hwndT1, WM_SETTEXT, 0, (LPARAM) pchText))
|
|
{
|
|
SetCursor( hPrevCursor );
|
|
if( fWrapIsOn ) // restore wordwrap
|
|
{
|
|
SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
|
|
}
|
|
DestroyWindow( hwndT1 );
|
|
LocalUnlock( hT1 );
|
|
LocalFree( hT1 );
|
|
return FALSE;
|
|
}
|
|
LocalUnlock(hT1);
|
|
|
|
|
|
DestroyWindow( hwndEdit ); // out with the old
|
|
hwndEdit = hwndT1; // in with the new
|
|
|
|
// free the earlier allocated memory in hEdit
|
|
|
|
if (hEdit)
|
|
LocalFree(hEdit);
|
|
|
|
hEdit = hT1;
|
|
|
|
// limit text for safety's sake.
|
|
|
|
PostMessage( hwndEdit, EM_LIMITTEXT, (WPARAM)CCHNPMAX, 0L );
|
|
|
|
ShowWindow(hwndNP, SW_SHOW);
|
|
SendMessage( hwndEdit, EM_SETMODIFY, bModified, 0L );
|
|
SetFocus(hwndEdit);
|
|
|
|
SetCursor( hPrevCursor ); // restore cursor
|
|
|
|
// redraw the status bar
|
|
|
|
if( fStatus )
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(hwndNP, &rcClient);
|
|
NPSize(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
|
|
UpdateStatusBar( TRUE );
|
|
ShowWindow( hwndStatus, SW_SHOW );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|