Source code of Windows XP (NT5)
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
9.7 KiB

  1. /*
  2. * misc notepad functions
  3. * Copyright (C) 1984-2000 Microsoft Corporation
  4. */
  5. #include "precomp.h"
  6. BOOL fCase = FALSE; // Flag specifying case sensitive search
  7. BOOL fReverse = FALSE; // Flag for direction of search
  8. extern HWND hDlgFind; // handle to modeless FindText window
  9. LPTSTR ReverseScan(
  10. LPTSTR lpSource,
  11. LPTSTR lpLast,
  12. LPTSTR lpSearch,
  13. BOOL fCaseSensitive )
  14. {
  15. TCHAR cLastCharU;
  16. TCHAR cLastCharL;
  17. INT iLen;
  18. cLastCharU= (TCHAR) (INT_PTR) CharUpper( (LPTSTR)(INT_PTR)(*lpSearch) );
  19. cLastCharL= (TCHAR) (INT_PTR) CharLower( (LPTSTR)(INT_PTR)(*lpSearch) );
  20. iLen = lstrlen(lpSearch);
  21. if (!lpLast)
  22. lpLast = lpSource + lstrlen(lpSource);
  23. do
  24. {
  25. if (lpLast == lpSource)
  26. return NULL;
  27. --lpLast;
  28. if (fCaseSensitive)
  29. {
  30. if (*lpLast != *lpSearch)
  31. continue;
  32. }
  33. else
  34. {
  35. if( !( *lpLast == cLastCharU || *lpLast == cLastCharL ) )
  36. continue;
  37. }
  38. if (fCaseSensitive)
  39. {
  40. if (!_tcsncmp( lpLast, lpSearch, iLen))
  41. break;
  42. }
  43. else
  44. {
  45. //
  46. // compare whole string using locale specific comparison.
  47. // do not use C runtime version since it may be wrong.
  48. //
  49. if( 2 == CompareString( LOCALE_USER_DEFAULT,
  50. NORM_IGNORECASE | SORT_STRINGSORT | NORM_STOP_ON_NULL,
  51. lpLast, iLen,
  52. lpSearch, iLen) )
  53. break;
  54. }
  55. } while (TRUE);
  56. return lpLast;
  57. }
  58. LPTSTR ForwardScan(LPTSTR lpSource, LPTSTR lpSearch, BOOL fCaseSensitive )
  59. {
  60. TCHAR cFirstCharU;
  61. TCHAR cFirstCharL;
  62. int iLen = lstrlen(lpSearch);
  63. cFirstCharU= (TCHAR) (INT_PTR) CharUpper( (LPTSTR)(INT_PTR)(*lpSearch) );
  64. cFirstCharL= (TCHAR) (INT_PTR) CharLower( (LPTSTR)(INT_PTR)(*lpSearch) );
  65. while (*lpSource)
  66. {
  67. if (fCaseSensitive)
  68. {
  69. if (*lpSource != *lpSearch)
  70. {
  71. lpSource++;
  72. continue;
  73. }
  74. }
  75. else
  76. {
  77. if( !( *lpSource == cFirstCharU || *lpSource == cFirstCharL ) )
  78. {
  79. lpSource++;
  80. continue;
  81. }
  82. }
  83. if (fCaseSensitive)
  84. {
  85. if (!_tcsncmp( lpSource, lpSearch, iLen))
  86. break;
  87. }
  88. else
  89. {
  90. if( 2 == CompareString( LOCALE_USER_DEFAULT,
  91. NORM_IGNORECASE | SORT_STRINGSORT | NORM_STOP_ON_NULL,
  92. lpSource, iLen,
  93. lpSearch, iLen) )
  94. break;
  95. }
  96. lpSource++;
  97. }
  98. return *lpSource ? lpSource : NULL;
  99. }
  100. // search forward or backward in the edit control text for the given pattern
  101. // It is the responsibility of the caller to set the cursor
  102. BOOL Search (TCHAR * szKey)
  103. {
  104. BOOL bStatus= FALSE;
  105. TCHAR * pStart, *pMatch;
  106. DWORD StartIndex, LineNum, EndIndex;
  107. DWORD SelStart, SelEnd, i;
  108. HANDLE hEText; // handle to edit text
  109. UINT uSelState;
  110. HMENU hMenu;
  111. BOOL bSelectAll = FALSE;
  112. if (!*szKey)
  113. return( bStatus );
  114. SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&SelStart, (LPARAM)&SelEnd);
  115. // when we finish the search, we highlight the text found, and continue
  116. // the search after the end of the highlighted position (in forward
  117. // case) or from the begining of the highlighted position in the reverse
  118. // direction (in reverse case). this would break if the user has
  119. // selected all text. this hack would take care of it. (this is consistent
  120. // with VC editors' search too.
  121. hMenu = GetMenu(hwndNP);
  122. uSelState = GetMenuState(GetSubMenu(hMenu, 1), M_SELECTALL, MF_BYCOMMAND);
  123. if (uSelState == MF_GRAYED)
  124. {
  125. bSelectAll = TRUE;
  126. SelStart = SelEnd =0;
  127. }
  128. //
  129. // get pointer to edit control text to search
  130. //
  131. hEText= (HANDLE) SendMessage( hwndEdit, EM_GETHANDLE, 0, 0 );
  132. if( !hEText ) // silently return if we can't get it
  133. {
  134. return( bStatus );
  135. }
  136. pStart= LocalLock( hEText );
  137. if( !pStart )
  138. {
  139. return( bStatus );
  140. }
  141. if (fReverse)
  142. {
  143. // Get current line number
  144. LineNum= (DWORD)SendMessage(hwndEdit, EM_LINEFROMCHAR, SelStart, 0);
  145. // Get index to start of the line
  146. StartIndex= (DWORD)SendMessage(hwndEdit, EM_LINEINDEX, LineNum, 0);
  147. // Set upper limit for search text
  148. EndIndex= SelStart;
  149. pMatch= NULL;
  150. // Search line by line, from LineNum to 0
  151. i = LineNum;
  152. while (TRUE)
  153. {
  154. pMatch= ReverseScan(pStart+StartIndex,pStart+EndIndex,szKey,fCase);
  155. if (pMatch)
  156. break;
  157. // current StartIndex is the upper limit for the next search
  158. EndIndex= StartIndex;
  159. if (i)
  160. {
  161. // Get start of the next line
  162. i-- ;
  163. StartIndex = (DWORD)SendMessage(hwndEdit, EM_LINEINDEX, i, 0);
  164. }
  165. else
  166. break ;
  167. }
  168. }
  169. else
  170. {
  171. pMatch= ForwardScan(pStart+SelEnd, szKey, fCase);
  172. }
  173. LocalUnlock(hEText);
  174. if (pMatch == NULL)
  175. {
  176. //
  177. // alert user on not finding any text unless it is replace all
  178. //
  179. if( !(FR.Flags & FR_REPLACEALL) )
  180. {
  181. HANDLE hPrevCursor= SetCursor( hStdCursor );
  182. AlertBox( hDlgFind ? hDlgFind : hwndNP,
  183. szNN,
  184. szCFS,
  185. szSearch,
  186. MB_APPLMODAL | MB_OK | MB_ICONINFORMATION);
  187. SetCursor( hPrevCursor );
  188. }
  189. }
  190. else
  191. {
  192. SelStart = (DWORD)(pMatch - pStart);
  193. SendMessage( hwndEdit, EM_SETSEL, SelStart, SelStart+lstrlen(szKey));
  194. // since we are selecting the found text, enable SelectAll again.
  195. if (bSelectAll)
  196. {
  197. EnableMenuItem(GetSubMenu(hMenu, 1), M_SELECTALL, MF_ENABLED);
  198. }
  199. //
  200. // show the selected text unless it is replace all
  201. //
  202. if( !(FR.Flags & FR_REPLACEALL) )
  203. {
  204. SendMessage(hwndEdit, EM_SCROLLCARET, 0, 0);
  205. UpdateStatusBar( TRUE );
  206. }
  207. bStatus= TRUE; // found
  208. }
  209. return( bStatus );
  210. }
  211. // Recreate notepad edit window, get text from old window and put in new window.
  212. // Called when user changes style from wrap on/off
  213. //
  214. // Called with the style of the new window
  215. //
  216. BOOL NpReCreate( long style )
  217. {
  218. RECT rcT1;
  219. HWND hwndT1;
  220. HANDLE hT1;
  221. int cchTextNew;
  222. TCHAR* pchText;
  223. BOOL fWrapIsOn = ((style & WS_HSCROLL) != 0);
  224. HCURSOR hPrevCursor;
  225. BOOL bModified; // modify flag from old edit buffer
  226. // if wordwrap, remove soft carriage returns
  227. hPrevCursor= SetCursor( hWaitCursor ); // this may take some time...
  228. if( fWrapIsOn )
  229. {
  230. GotoAndScrollInView(1); // get around MLE bug
  231. SendMessage(hwndEdit, EM_FMTLINES, FALSE, 0L);
  232. }
  233. bModified= (SendMessage( hwndEdit, EM_GETMODIFY, 0,0 ) != 0);
  234. cchTextNew= (int)SendMessage( hwndEdit, WM_GETTEXTLENGTH, 0, 0L );
  235. hT1= LocalAlloc( LMEM_MOVEABLE, ByteCountOf(cchTextNew + 1) );
  236. if( !hT1 )
  237. {
  238. // failed, restore wordwrap; insert soft carriage returns
  239. if( fWrapIsOn )
  240. {
  241. SendMessage(hwndEdit, EM_FMTLINES, TRUE, 0L);
  242. }
  243. SetCursor( hPrevCursor );
  244. return FALSE;
  245. }
  246. GetClientRect( hwndNP, (LPRECT)&rcT1 );
  247. //
  248. // save the current edit control text.
  249. //
  250. pchText= LocalLock (hT1);
  251. SendMessage( hwndEdit, WM_GETTEXT, cchTextNew+1, (LPARAM)pchText );
  252. hwndT1= CreateWindowEx( WS_EX_CLIENTEDGE,
  253. TEXT("Edit"),
  254. TEXT(""), // pchText
  255. style,
  256. 0,
  257. 0,
  258. rcT1.right,
  259. rcT1.bottom,
  260. hwndNP,
  261. (HMENU)ID_EDIT,
  262. hInstanceNP, NULL );
  263. if( !hwndT1 )
  264. {
  265. SetCursor( hPrevCursor );
  266. if( fWrapIsOn ) // restore wordwrap
  267. {
  268. SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
  269. }
  270. LocalUnlock(hT1);
  271. LocalFree(hT1);
  272. return FALSE;
  273. }
  274. //
  275. // The user can "add" styles to the edit window after it is
  276. // created (like WS_EX_RTLREADING) when language packs are installed.
  277. // Preserve these styles when changing the word wrap.
  278. //
  279. SetWindowLong( hwndT1 ,
  280. GWL_EXSTYLE ,
  281. GetWindowLong( hwndEdit , GWL_EXSTYLE )|WS_EX_CLIENTEDGE ) ;
  282. // Set font before set text to save time calculating
  283. SendMessage( hwndT1, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0) );
  284. if (!SendMessage (hwndT1, WM_SETTEXT, 0, (LPARAM) pchText))
  285. {
  286. SetCursor( hPrevCursor );
  287. if( fWrapIsOn ) // restore wordwrap
  288. {
  289. SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
  290. }
  291. DestroyWindow( hwndT1 );
  292. LocalUnlock( hT1 );
  293. LocalFree( hT1 );
  294. return FALSE;
  295. }
  296. LocalUnlock(hT1);
  297. DestroyWindow( hwndEdit ); // out with the old
  298. hwndEdit = hwndT1; // in with the new
  299. // free the earlier allocated memory in hEdit
  300. if (hEdit)
  301. LocalFree(hEdit);
  302. hEdit = hT1;
  303. // limit text for safety's sake.
  304. PostMessage( hwndEdit, EM_LIMITTEXT, (WPARAM)CCHNPMAX, 0L );
  305. ShowWindow(hwndNP, SW_SHOW);
  306. SendMessage( hwndEdit, EM_SETMODIFY, bModified, 0L );
  307. SetFocus(hwndEdit);
  308. SetCursor( hPrevCursor ); // restore cursor
  309. // redraw the status bar
  310. if( fStatus )
  311. {
  312. RECT rcClient;
  313. GetClientRect(hwndNP, &rcClient);
  314. NPSize(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
  315. UpdateStatusBar( TRUE );
  316. ShowWindow( hwndStatus, SW_SHOW );
  317. }
  318. return TRUE;
  319. }