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.

383 lines
9.6 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. }
  206. bStatus= TRUE; // found
  207. }
  208. return( bStatus );
  209. }
  210. // Recreate notepad edit window, get text from old window and put in new window.
  211. // Called when user changes style from wrap on/off
  212. //
  213. // Called with the style of the new window
  214. //
  215. BOOL NpReCreate( long style )
  216. {
  217. RECT rcT1;
  218. HWND hwndT1;
  219. HANDLE hT1;
  220. int cchTextNew;
  221. TCHAR* pchText;
  222. BOOL fWrapIsOn = ((style & WS_HSCROLL) != 0);
  223. HCURSOR hPrevCursor;
  224. BOOL bModified; // modify flag from old edit buffer
  225. // if wordwrap, remove soft carriage returns
  226. hPrevCursor= SetCursor( hWaitCursor ); // this may take some time...
  227. if( fWrapIsOn )
  228. {
  229. GotoAndScrollInView(1); // get around MLE bug
  230. SendMessage(hwndEdit, EM_FMTLINES, FALSE, 0L);
  231. }
  232. bModified= (SendMessage( hwndEdit, EM_GETMODIFY, 0,0 ) != 0);
  233. cchTextNew= (int)SendMessage( hwndEdit, WM_GETTEXTLENGTH, 0, 0L );
  234. hT1= LocalAlloc( LMEM_MOVEABLE, ByteCountOf(cchTextNew + 1) );
  235. if( !hT1 )
  236. {
  237. // failed, restore wordwrap; insert soft carriage returns
  238. if( fWrapIsOn )
  239. {
  240. SendMessage(hwndEdit, EM_FMTLINES, TRUE, 0L);
  241. }
  242. SetCursor( hPrevCursor );
  243. return FALSE;
  244. }
  245. GetClientRect( hwndNP, (LPRECT)&rcT1 );
  246. //
  247. // save the current edit control text.
  248. //
  249. pchText= LocalLock (hT1);
  250. SendMessage( hwndEdit, WM_GETTEXT, cchTextNew+1, (LPARAM)pchText );
  251. hwndT1= CreateWindowEx( WS_EX_CLIENTEDGE,
  252. TEXT("Edit"),
  253. TEXT(""), // pchText
  254. style,
  255. 0,
  256. 0,
  257. rcT1.right,
  258. rcT1.bottom,
  259. hwndNP,
  260. (HMENU)ID_EDIT,
  261. hInstanceNP, NULL );
  262. if( !hwndT1 )
  263. {
  264. SetCursor( hPrevCursor );
  265. if( fWrapIsOn ) // restore wordwrap
  266. {
  267. SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
  268. }
  269. LocalUnlock(hT1);
  270. LocalFree(hT1);
  271. return FALSE;
  272. }
  273. //
  274. // The user can "add" styles to the edit window after it is
  275. // created (like WS_EX_RTLREADING) when language packs are installed.
  276. // Preserve these styles when changing the word wrap.
  277. //
  278. SetWindowLong( hwndT1 ,
  279. GWL_EXSTYLE ,
  280. GetWindowLong( hwndEdit , GWL_EXSTYLE )|WS_EX_CLIENTEDGE ) ;
  281. // Set font before set text to save time calculating
  282. SendMessage( hwndT1, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0) );
  283. if (!SendMessage (hwndT1, WM_SETTEXT, 0, (LPARAM) pchText))
  284. {
  285. SetCursor( hPrevCursor );
  286. if( fWrapIsOn ) // restore wordwrap
  287. {
  288. SendMessage( hwndEdit, EM_FMTLINES, TRUE, 0L );
  289. }
  290. DestroyWindow( hwndT1 );
  291. LocalUnlock( hT1 );
  292. LocalFree( hT1 );
  293. return FALSE;
  294. }
  295. LocalUnlock(hT1);
  296. DestroyWindow( hwndEdit ); // out with the old
  297. hwndEdit = hwndT1; // in with the new
  298. // free the earlier allocated memory in hEdit
  299. if (hEdit)
  300. LocalFree(hEdit);
  301. hEdit = hT1;
  302. // limit text for safety's sake.
  303. PostMessage( hwndEdit, EM_LIMITTEXT, (WPARAM)CCHNPMAX, 0L );
  304. ShowWindow(hwndNP, SW_SHOW);
  305. SendMessage( hwndEdit, EM_SETMODIFY, bModified, 0L );
  306. SetFocus(hwndEdit);
  307. SetCursor( hPrevCursor ); // restore cursor
  308. // redraw the status bar
  309. if( fStatus )
  310. {
  311. RECT rcClient;
  312. GetClientRect(hwndNP, &rcClient);
  313. NPSize(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
  314. ShowWindow( hwndStatus, SW_SHOW );
  315. }
  316. return TRUE;
  317. }