Leaked source code of windows server 2003
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.

609 lines
17 KiB

  1. /****************************************************************************\
  2. * edmlRare.c - Edit controls Routines Called rarely are to be
  3. * put in a seperate segment _EDMLRare. This file contains
  4. * these routines.
  5. *
  6. * Copyright (c) 1985 - 1999, Microsoft Corporation
  7. *
  8. * Multi-Line Support Routines called Rarely
  9. \****************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. /***************************************************************************\
  13. * MLInsertCrCrLf AorW
  14. *
  15. * Inserts CR CR LF characters into the text at soft (word-wrap) line
  16. * breaks. CR LF (hard) line breaks are unaffected. Assumes that the text
  17. * has already been formatted ie. ped->chLines is where we want the line
  18. * breaks to occur. Note that ped->chLines is not updated to reflect the
  19. * movement of text by the addition of CR CR LFs. Returns TRUE if successful
  20. * else notify parent and return FALSE if the memory couldn't be allocated.
  21. *
  22. * History:
  23. \***************************************************************************/
  24. BOOL MLInsertCrCrLf(
  25. PED ped)
  26. {
  27. ICH dch;
  28. ICH li;
  29. ICH lineSize;
  30. unsigned char *pchText;
  31. unsigned char *pchTextNew;
  32. if (!ped->fWrap || !ped->cch) {
  33. /*
  34. * There are no soft line breaks if word-wrapping is off or if no chars
  35. */
  36. return TRUE;
  37. }
  38. /*
  39. * Calc an upper bound on the number of additional characters we will be
  40. * adding to the text when we insert CR CR LFs.
  41. */
  42. dch = 3 * ped->cLines;
  43. if (!LOCALREALLOC(ped->hText, (ped->cch + dch) * ped->cbChar, 0, ped->hInstance, NULL)) {
  44. ECNotifyParent(ped, EN_ERRSPACE);
  45. return FALSE;
  46. }
  47. ped->cchAlloc = ped->cch + dch;
  48. /*
  49. * Move the text up dch bytes and then copy it back down, inserting the CR
  50. * CR LF's as necessary.
  51. */
  52. pchTextNew = pchText = ECLock(ped);
  53. pchText += dch * ped->cbChar;
  54. /*
  55. * We will use dch to keep track of how many chars we add to the text
  56. */
  57. dch = 0;
  58. /*
  59. * Copy the text up dch bytes to pchText. This will shift all indices in
  60. * ped->chLines up by dch bytes.
  61. */
  62. memmove(pchText, pchTextNew, ped->cch * ped->cbChar);
  63. /*
  64. * Now copy chars from pchText down to pchTextNew and insert CRCRLF at soft
  65. * line breaks.
  66. */
  67. if (ped->fAnsi) {
  68. for (li = 0; li < ped->cLines - 1; li++) {
  69. lineSize = ped->chLines[li + 1] - ped->chLines[li];
  70. memmove(pchTextNew, pchText, lineSize);
  71. pchTextNew += lineSize;
  72. pchText += lineSize;
  73. /*
  74. * If last character in newly copied line is not a line feed, then we
  75. * need to add the CR CR LF triple to the end
  76. */
  77. if (*(pchTextNew - 1) != 0x0A) {
  78. *pchTextNew++ = 0x0D;
  79. *pchTextNew++ = 0x0D;
  80. *pchTextNew++ = 0x0A;
  81. dch += 3;
  82. }
  83. }
  84. /*
  85. * Now move the last line up. It won't have any line breaks in it...
  86. */
  87. memmove(pchTextNew, pchText, ped->cch - ped->chLines[ped->cLines - 1]);
  88. } else { //!fAnsi
  89. LPWSTR pwchTextNew = (LPWSTR)pchTextNew;
  90. for (li = 0; li < ped->cLines - 1; li++) {
  91. lineSize = ped->chLines[li + 1] - ped->chLines[li];
  92. memmove(pwchTextNew, pchText, lineSize * sizeof(WCHAR));
  93. pwchTextNew += lineSize;
  94. pchText += lineSize * sizeof(WCHAR);
  95. /*
  96. * If last character in newly copied line is not a line feed, then we
  97. * need to add the CR CR LF triple to the end
  98. */
  99. if (*(pwchTextNew - 1) != 0x0A) {
  100. *pwchTextNew++ = 0x0D;
  101. *pwchTextNew++ = 0x0D;
  102. *pwchTextNew++ = 0x0A;
  103. dch += 3;
  104. }
  105. }
  106. /*
  107. * Now move the last line up. It won't have any line breaks in it...
  108. */
  109. memmove(pwchTextNew, pchText,
  110. (ped->cch - ped->chLines[ped->cLines - 1]) * sizeof(WCHAR));
  111. }
  112. ECUnlock(ped);
  113. if (dch) {
  114. /*
  115. * Update number of characters in text handle
  116. */
  117. ped->cch += dch;
  118. /*
  119. * So that the next time we do anything with the text, we can strip the
  120. * CRCRLFs
  121. */
  122. ped->fStripCRCRLF = TRUE;
  123. return TRUE;
  124. }
  125. return FALSE;
  126. }
  127. /***************************************************************************\
  128. * MLStripCrCrLf AorW
  129. *
  130. * Strips the CR CR LF character combination from the text. This
  131. * shows the soft (word wrapped) line breaks. CR LF (hard) line breaks are
  132. * unaffected.
  133. *
  134. * History:
  135. \***************************************************************************/
  136. void MLStripCrCrLf(
  137. PED ped)
  138. {
  139. if (ped->cch) {
  140. if (ped->fAnsi) {
  141. unsigned char *pchSrc;
  142. unsigned char *pchDst;
  143. unsigned char *pchLast;
  144. pchSrc = pchDst = ECLock(ped);
  145. pchLast = pchSrc + ped->cch;
  146. while (pchSrc < pchLast) {
  147. if ( (pchSrc[0] == 0x0D)
  148. && (pchSrc[1] == 0x0D)
  149. && (pchSrc[2] == 0x0A)
  150. ) {
  151. pchSrc += 3;
  152. ped->cch -= 3;
  153. } else {
  154. *pchDst++ = *pchSrc++;
  155. }
  156. }
  157. } else { // !fAnsi
  158. LPWSTR pwchSrc;
  159. LPWSTR pwchDst;
  160. LPWSTR pwchLast;
  161. pwchSrc = pwchDst = (LPWSTR)ECLock(ped);
  162. pwchLast = pwchSrc + ped->cch;
  163. while (pwchSrc < pwchLast) {
  164. if ( (pwchSrc[0] == 0x0D)
  165. && (pwchSrc[1] == 0x0D)
  166. && (pwchSrc[2] == 0x0A)
  167. ) {
  168. pwchSrc += 3;
  169. ped->cch -= 3;
  170. } else {
  171. *pwchDst++ = *pwchSrc++;
  172. }
  173. }
  174. }
  175. ECUnlock(ped);
  176. /*
  177. * Make sure we don't have any values past the last character
  178. */
  179. if (ped->ichCaret > ped->cch)
  180. ped->ichCaret = ped->cch;
  181. if (ped->ichMinSel > ped->cch)
  182. ped->ichMinSel = ped->cch;
  183. if (ped->ichMaxSel > ped->cch)
  184. ped->ichMaxSel = ped->cch;
  185. }
  186. }
  187. /***************************************************************************\
  188. * MLSetHandle AorW
  189. *
  190. * Sets the ped to contain the given handle.
  191. *
  192. * History:
  193. \***************************************************************************/
  194. void MLSetHandle(
  195. PED ped,
  196. HANDLE hNewText)
  197. {
  198. ICH newCch;
  199. ped->cch = ped->cchAlloc =
  200. LOCALSIZE(ped->hText = hNewText, ped->hInstance) / ped->cbChar;
  201. ped->fEncoded = FALSE;
  202. if (ped->cch) {
  203. /*
  204. * We have to do it this way in case the app gives us a zero size handle
  205. */
  206. if (ped->fAnsi)
  207. ped->cch = strlen(ECLock(ped));
  208. else
  209. ped->cch = wcslen((LPWSTR)ECLock(ped));
  210. ECUnlock(ped);
  211. }
  212. newCch = (ICH)(ped->cch + CCHALLOCEXTRA);
  213. /*
  214. * We do this LocalReAlloc in case the app changed the size of the handle
  215. */
  216. if (LOCALREALLOC(ped->hText, newCch*ped->cbChar, 0, ped->hInstance, NULL))
  217. ped->cchAlloc = newCch;
  218. ECResetTextInfo(ped);
  219. }
  220. /***************************************************************************\
  221. * MLGetLine AorW
  222. *
  223. * Copies maxCchToCopy bytes of line lineNumber to the buffer
  224. * lpBuffer. The string is not zero terminated.
  225. *
  226. * Returns number of characters copied
  227. *
  228. * History:
  229. \***************************************************************************/
  230. LONG MLGetLine(
  231. PED ped,
  232. ICH lineNumber, //WASDWORD
  233. ICH maxCchToCopy,
  234. LPSTR lpBuffer)
  235. {
  236. PSTR pText;
  237. ICH cchLen;
  238. if (lineNumber > ped->cLines - 1) {
  239. RIPERR1(ERROR_INVALID_PARAMETER,
  240. RIP_WARNING,
  241. "Invalid parameter \"lineNumber\" (%ld) to MLGetLine",
  242. lineNumber);
  243. return 0L;
  244. }
  245. cchLen = MLLine(ped, lineNumber);
  246. maxCchToCopy = min(cchLen, maxCchToCopy);
  247. if (maxCchToCopy) {
  248. pText = ECLock(ped) +
  249. ped->chLines[lineNumber] * ped->cbChar;
  250. memmove(lpBuffer, pText, maxCchToCopy*ped->cbChar);
  251. ECUnlock(ped);
  252. }
  253. return maxCchToCopy;
  254. }
  255. /***************************************************************************\
  256. * MLLineIndex AorW
  257. *
  258. * This function return s the number of character positions that occur
  259. * preceeding the first char in a given line.
  260. *
  261. * History:
  262. \***************************************************************************/
  263. ICH MLLineIndex(
  264. PED ped,
  265. ICH iLine) //WASINT
  266. {
  267. if (iLine == -1)
  268. iLine = ped->iCaretLine;
  269. if (iLine < ped->cLines) {
  270. return ped->chLines[iLine];
  271. } else {
  272. RIPERR1(ERROR_INVALID_PARAMETER,
  273. RIP_WARNING,
  274. "Invalid parameter \"iLine\" (%ld) to MLLineIndex",
  275. iLine);
  276. return (ICH)-1;
  277. }
  278. }
  279. /***************************************************************************\
  280. * MLLineLength AorW
  281. *
  282. * if ich = -1, return the length of the lines containing the current
  283. * selection but not including the selection. Otherwise, return the length of
  284. * the line containing ich.
  285. *
  286. * History:
  287. \***************************************************************************/
  288. ICH MLLineLength(
  289. PED ped,
  290. ICH ich)
  291. {
  292. ICH il1, il2;
  293. ICH temp;
  294. if (ich != 0xFFFFFFFF)
  295. return (MLLine(ped, MLIchToLine(ped, ich)));
  296. /*
  297. * Find length of lines corresponding to current selection
  298. */
  299. il1 = MLIchToLine(ped, ped->ichMinSel);
  300. il2 = MLIchToLine(ped, ped->ichMaxSel);
  301. if (il1 == il2)
  302. return (MLLine(ped, il1) - (ped->ichMaxSel - ped->ichMinSel));
  303. temp = ped->ichMinSel - ped->chLines[il1];
  304. temp += MLLine(ped, il2);
  305. temp -= (ped->ichMaxSel - ped->chLines[il2]);
  306. return temp;
  307. }
  308. /***************************************************************************\
  309. * MLSetSelection AorW
  310. *
  311. * Sets the selection to the points given and puts the cursor at
  312. * ichMaxSel.
  313. *
  314. * History:
  315. \***************************************************************************/
  316. void MLSetSelection(
  317. PED ped,
  318. BOOL fDoNotScrollCaret,
  319. ICH ichMinSel,
  320. ICH ichMaxSel)
  321. {
  322. HDC hdc;
  323. if (ichMinSel == 0xFFFFFFFF) {
  324. /*
  325. * Set no selection if we specify -1
  326. */
  327. ichMinSel = ichMaxSel = ped->ichCaret;
  328. }
  329. /*
  330. * Since these are unsigned, we don't check if they are greater than 0.
  331. */
  332. ichMinSel = min(ped->cch, ichMinSel);
  333. ichMaxSel = min(ped->cch, ichMaxSel);
  334. #ifdef FE_SB // MLSetSelectionHander()
  335. //
  336. // To avoid position to half of DBCS, check and ajust position if necessary
  337. //
  338. // We check ped->fDBCS and ped->fAnsi though ECAdjustIch checks these bits
  339. // at first. We're worrying about the overhead of ECLock and ECUnlock.
  340. //
  341. if ( ped->fDBCS && ped->fAnsi ) {
  342. PSTR pText;
  343. pText = ECLock(ped);
  344. ichMinSel = ECAdjustIch( ped, pText, ichMinSel );
  345. ichMaxSel = ECAdjustIch( ped, pText, ichMaxSel );
  346. ECUnlock(ped);
  347. }
  348. #endif // FE_SB
  349. /*
  350. * Set the caret's position to be at ichMaxSel.
  351. */
  352. ped->ichCaret = ichMaxSel;
  353. ped->iCaretLine = MLIchToLine(ped, ped->ichCaret);
  354. hdc = ECGetEditDC(ped, FALSE);
  355. MLChangeSelection(ped, hdc, ichMinSel, ichMaxSel);
  356. MLSetCaretPosition(ped, hdc);
  357. ECReleaseEditDC(ped, hdc, FALSE);
  358. #ifdef FE_SB // MLSetSelectionHander()
  359. if (!fDoNotScrollCaret)
  360. MLEnsureCaretVisible(ped);
  361. /*
  362. * #ifdef KOREA is history, with FE_SB (FarEast Single Binary).
  363. */
  364. #else
  365. #ifdef KOREA
  366. /*
  367. * Extra parameter specified interim character mode
  368. */
  369. MLEnsureCaretVisible(ped,NULL);
  370. #else
  371. if (!fDoNotScrollCaret)
  372. MLEnsureCaretVisible(ped);
  373. #endif
  374. #endif // FE_SB
  375. }
  376. /***************************************************************************\
  377. * MLSetTabStops AorW
  378. *
  379. *
  380. * MLSetTabStops(ped, nTabPos, lpTabStops)
  381. *
  382. * This sets the tab stop positions set by the App by sending
  383. * a EM_SETTABSTOPS message.
  384. *
  385. * nTabPos : Number of tab stops set by the caller
  386. * lpTabStops: array of tab stop positions in Dialog units.
  387. *
  388. * Returns:
  389. * TRUE if successful
  390. * FALSE if memory allocation error.
  391. *
  392. * History:
  393. \***************************************************************************/
  394. BOOL MLSetTabStops(
  395. PED ped,
  396. int nTabPos,
  397. LPINT lpTabStops)
  398. {
  399. int *pTabStops;
  400. /*
  401. * Check if tab positions already exist
  402. */
  403. if (!ped->pTabStops) {
  404. /*
  405. * Check if the caller wants the new tab positions
  406. */
  407. if (nTabPos) {
  408. /*
  409. * Allocate the array of tab stops
  410. */
  411. if (!(pTabStops = (LPINT)UserLocalAlloc(HEAP_ZERO_MEMORY, (nTabPos + 1) * sizeof(int)))) {
  412. return FALSE;
  413. }
  414. } else {
  415. return TRUE; /* No stops then and no stops now! */
  416. }
  417. } else {
  418. /*
  419. * Check if the caller wants the new tab positions
  420. */
  421. if (nTabPos) {
  422. /*
  423. * Check if the number of tab positions is different
  424. */
  425. if (ped->pTabStops[0] != nTabPos) {
  426. /*
  427. * Yes! So ReAlloc to new size
  428. */
  429. if (!(pTabStops = (LPINT)UserLocalReAlloc(ped->pTabStops,
  430. (nTabPos + 1) * sizeof(int), 0)))
  431. return FALSE;
  432. } else {
  433. pTabStops = ped->pTabStops;
  434. }
  435. } else {
  436. /*
  437. * Caller wants to remove all the tab stops; So, release
  438. */
  439. if (!UserLocalFree(ped->pTabStops))
  440. return FALSE; /* Failure */
  441. ped->pTabStops = NULL;
  442. goto RedrawAndReturn;
  443. }
  444. }
  445. /*
  446. * Copy the new tab stops onto the tab stop array after converting the
  447. * dialog co-ordinates into the pixel co-ordinates
  448. */
  449. ped->pTabStops = pTabStops;
  450. *pTabStops++ = nTabPos; /* First element contains the count */
  451. while (nTabPos--) {
  452. /*
  453. * aveCharWidth must be used instead of cxSysCharWidth.
  454. * Fix for Bug #3871 --SANKAR-- 03/14/91
  455. */
  456. *pTabStops++ = MultDiv(*lpTabStops++, ped->aveCharWidth, 4);
  457. }
  458. RedrawAndReturn:
  459. // Because the tabstops have changed, we need to recompute the
  460. // maxPixelWidth. Otherwise, horizontal scrolls will have problems.
  461. // Fix for Bug #6042 - 3/15/94
  462. MLBuildchLines(ped, 0, 0, FALSE, NULL, NULL);
  463. // Caret may have changed line by the line recalc above.
  464. MLUpdateiCaretLine(ped);
  465. MLEnsureCaretVisible(ped);
  466. // Also, we need to redraw the whole window.
  467. NtUserInvalidateRect(ped->hwnd, NULL, TRUE);
  468. return TRUE;
  469. }
  470. /***************************************************************************\
  471. * MLUndo AorW
  472. *
  473. * Handles Undo for multiline edit controls.
  474. *
  475. * History:
  476. \***************************************************************************/
  477. BOOL MLUndo(
  478. PED ped)
  479. {
  480. HANDLE hDeletedText = ped->hDeletedText;
  481. BOOL fDelete = (BOOL)(ped->undoType & UNDO_DELETE);
  482. ICH cchDeleted = ped->cchDeleted;
  483. ICH ichDeleted = ped->ichDeleted;
  484. if (ped->undoType == UNDO_NONE) {
  485. /*
  486. * No undo...
  487. */
  488. return FALSE;
  489. }
  490. ped->hDeletedText = NULL;
  491. ped->cchDeleted = 0;
  492. ped->ichDeleted = (ICH)-1;
  493. ped->undoType &= ~UNDO_DELETE;
  494. if (ped->undoType == UNDO_INSERT) {
  495. ped->undoType = UNDO_NONE;
  496. /*
  497. * Set the selection to the inserted text
  498. */
  499. MLSetSelection(ped, FALSE, ped->ichInsStart, ped->ichInsEnd);
  500. ped->ichInsStart = ped->ichInsEnd = (ICH)-1;
  501. /*
  502. * Now send a backspace to delete and save it in the undo buffer...
  503. */
  504. SendMessage(ped->hwnd, WM_CHAR, (WPARAM)VK_BACK, 0L);
  505. }
  506. if (fDelete) {
  507. /*
  508. * Insert deleted chars
  509. */
  510. /*
  511. * Set the selection to the inserted text
  512. */
  513. MLSetSelection(ped, FALSE, ichDeleted, ichDeleted);
  514. MLInsertText(ped, hDeletedText, cchDeleted, FALSE);
  515. UserGlobalFree(hDeletedText);
  516. MLSetSelection(ped, FALSE, ichDeleted, ichDeleted + cchDeleted);
  517. }
  518. return TRUE;
  519. }