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.

519 lines
14 KiB

  1. /*
  2. * @doc TOM
  3. *
  4. * @module tomsel.cpp - Implement the CTxtSelection Class |
  5. *
  6. * This module contains the TOM ITextSelection implementation for
  7. * the selection object
  8. *
  9. * History: <nl>
  10. * 5/24/95 - Alex Gounares: stubs <nl>
  11. * 8/95 - Murray Sargent: core implementation
  12. *
  13. * @comm
  14. * The "cursor-pad" functions (Left, Right, Up, Down, Home, End)
  15. * are simple generalizations of the corresponding keystrokes and have
  16. * to express the same UI. Consequently they are typically not as
  17. * efficient for moving the cursor around as ITextRange methods, which
  18. * are designed for particular purposes. This is especially true for
  19. * counts larger than one.
  20. *
  21. * @devnote
  22. * All ITextSelection methods inherited from ITextRange are handled by
  23. * the ITextRange methods, since they either don't affect the display of
  24. * the selection (e.g., Get methods), or virtual methods are used that
  25. * perform the appropriate updating of the selection on screen.
  26. *
  27. * Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
  28. */
  29. #include "_common.h"
  30. #include "_select.h"
  31. #include "_disp.h"
  32. #include "_edit.h"
  33. #define DEBUG_CLASSNAME CTxtSelection
  34. #include "_invar.h"
  35. //---------------------- CTxtSelection methods ------------------------------------
  36. /*
  37. * CTxtSelection::EndKey (Unit, Extend, pDelta)
  38. *
  39. * @mfunc
  40. * Act as UI End key, such that <p Extend> is TRUE corresponds to the
  41. * Shift key being depressed and <p Unit> = start of line/document for
  42. * Ctrl key not being/being depressed. Returns *<p pDelta> = count of
  43. * characters active end is moved forward, i.e., a number >= 0.
  44. *
  45. * @rdesc
  46. * HRESULT = (invalid Unit) ? E_INVALIDARG :
  47. * (if change) ? NOERROR : S_FALSE
  48. */
  49. STDMETHODIMP CTxtSelection::EndKey (
  50. long Unit, //@parm Unit to use
  51. long Extend, //@parm Extend selection or go to IP
  52. long * pDelta) //@parm Out parm to receive count of chars moved
  53. {
  54. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::EndKey");
  55. return Homer(Unit, Extend, pDelta, End);
  56. }
  57. /*
  58. * CTxtSelection::GetFlags (pFlags)
  59. *
  60. * @mfunc
  61. * Set <p pFlags> = this text selection's flags
  62. *
  63. * @rdesc
  64. * HRESULT = (<p pFlags>) ? NOERROR : E_INVALIDARG
  65. */
  66. STDMETHODIMP CTxtSelection::GetFlags(
  67. long * pFlags) //@parm Out parm to receive selection flags
  68. {
  69. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::GetFlags");
  70. if(!pFlags)
  71. return E_INVALIDARG;
  72. if(IsZombie())
  73. {
  74. *pFlags = tomSelStartActive | tomSelReplace;
  75. return CO_E_RELEASED;
  76. }
  77. DWORD dwFlags = _cch <= 0; // Store tomSelStartActive value
  78. if(_fCaretNotAtBOL)
  79. dwFlags |= tomSelAtEOL;
  80. if(GetPed()->_fOverstrike)
  81. dwFlags |= tomSelOvertype;
  82. if(GetPed()->_fFocus)
  83. dwFlags |= tomSelActive;
  84. *pFlags = dwFlags | tomSelReplace; // tomSelReplace isn't optional
  85. return NOERROR;
  86. }
  87. /*
  88. * CTxtSelection::GetSelectionType (pType)
  89. *
  90. * @mfunc
  91. * Set *pType = type of this text selection
  92. *
  93. * @rdesc
  94. * HRESULT = <p pType> ? NOERROR : E_INVALIDARG
  95. */
  96. STDMETHODIMP CTxtSelection::GetType(
  97. long * pType) //@parm Out parm to receive selection type
  98. {
  99. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::GetSelectionType");
  100. if(!pType)
  101. return E_INVALIDARG;
  102. *pType = !_cch ? tomSelectionIP
  103. : (_cch == -1 && _rpTX.GetChar() == WCH_EMBEDDING ||
  104. _cch == 1 && GetPrevChar() == WCH_EMBEDDING)
  105. ? tomSelectionInlineShape : tomSelectionNormal;
  106. return IsZombie() ? CO_E_RELEASED : NOERROR;
  107. }
  108. /*
  109. * CTxtSelection::HomeKey (Unit, Extend, pDelta)
  110. *
  111. * @mfunc
  112. * Act as UI Home key, such that <p Extend> is TRUE corresponds to the
  113. * Shift key being depressed and <p Unit> = start of line/document for
  114. * Ctrl key not being/being depressed. Returns *<p pDelta> = count of
  115. * characters active end is moved forward, i.e., a number <= 0.
  116. *
  117. * @rdesc
  118. * HRESULT = (invalid Unit) ? E_INVALIDARG :
  119. * (if change) ? NOERROR : S_FALSE
  120. */
  121. STDMETHODIMP CTxtSelection::HomeKey (
  122. long Unit, //@parm Unit to use
  123. long Extend, //@parm Extend selection or go to IP
  124. long * pDelta) //@parm Out parm to receive count of chars moved
  125. {
  126. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::HomeKey");
  127. return Homer(Unit, Extend, pDelta, Home);
  128. }
  129. /*
  130. * CTxtSelection::MoveDown (Unit, Count, Extend, pDelta)
  131. *
  132. * @mfunc
  133. * Act as UI Down arrow, such that <p Extend> is TRUE corresponds to the
  134. * Shift key being depressed and <p Unit> = tomLine/tomParagraph for
  135. * Ctrl key not being/being depressed. In addition, <p Unit> can equal
  136. * tomWindow/tomWindowEnd for the Ctrl key not being/being depressed.
  137. * This second pair emulates PgDn behavior. The method returns
  138. * *<p pDelta> = actual count of units moved.
  139. *
  140. * @rdesc
  141. * HRESULT = (if change) ? NOERROR : S_FALSE
  142. */
  143. STDMETHODIMP CTxtSelection::MoveDown (
  144. long Unit, //@parm Unit to use
  145. long Count, //@parm Number of Units to move
  146. long Extend, //@parm Extend selection or go to IP
  147. long * pDelta) //@parm Out parm to receive actual count of
  148. // Units moved
  149. {
  150. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::MoveDown");
  151. return GeoMover(Unit, Count, Extend, pDelta, 3);
  152. }
  153. /*
  154. * CTxtSelection::MoveLeft (Unit, Count, Extend, pDelta)
  155. *
  156. * @mfunc
  157. * Act as UI left arrow, such that <p Extend> is TRUE corresponds to the
  158. * Shift key being depressed and <p Unit> = tomChar/tomWord for Ctrl key
  159. * not being/being depressed. Returns *<p pDelta> = actual count of
  160. * units moved
  161. *
  162. * @rdesc
  163. * HRESULT = (if change) ? NOERROR : S_FALSE
  164. */
  165. STDMETHODIMP CTxtSelection::MoveLeft (
  166. long Unit, //@parm Unit to use
  167. long Count, //@parm Number of Units to move
  168. long Extend, //@parm Extend selection or go to IP
  169. long * pDelta) //@parm Out parm to receive actual count of
  170. // Units moved
  171. {
  172. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::MoveLeft");
  173. return GeoMover(Unit, Count, Extend, pDelta, 0);
  174. }
  175. /*
  176. * CTxtSelection::MoveRight (Unit, Count, Extend, pDelta)
  177. *
  178. * @mfunc
  179. * Act as UI right arrow, such that <p Extend> is TRUE corresponds to the
  180. * Shift key being depressed and <p Unit> = tomChar/tomWord for Ctrl key
  181. * not being/being depressed. Returns *<p pDelta> = actual count of
  182. * units moved
  183. *
  184. * @rdesc
  185. * HRESULT = (if change) ? NOERROR : S_FALSE
  186. */
  187. STDMETHODIMP CTxtSelection::MoveRight (
  188. long Unit, //@parm Unit to use
  189. long Count, //@parm Number of Units to move
  190. long Extend, //@parm Extend selection or go to IP
  191. long * pDelta) //@parm Out parm to receive actual count of
  192. // Units moved
  193. {
  194. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::MoveRight");
  195. return GeoMover(Unit, Count, Extend, pDelta, 1);
  196. }
  197. /*
  198. * CTxtSelection::MoveUp (Unit, Count, Extend, pDelta)
  199. *
  200. * @mfunc
  201. * Act as UI Up arrow, such that <p Extend> is TRUE corresponds to the
  202. * Shift key being depressed and <p Unit> = tomLine/tomParagraph for
  203. * Ctrl key not being/being depressed. In addition, <p Unit> can equal
  204. * tomWindow/tomWindowEnd for the Ctrl key not being/being depressed.
  205. * This second pair emulates PgUp behavior. The method returns
  206. * *<p pDelta> = actual count of units moved.
  207. *
  208. * @rdesc
  209. * HRESULT = (if change) ? NOERROR : S_FALSE
  210. */
  211. STDMETHODIMP CTxtSelection::MoveUp (
  212. long Unit, //@parm Unit to use
  213. long Count, //@parm Number of Units to move
  214. long Extend, //@parm Extend selection or go to IP
  215. long * pDelta) //@parm Out parm to receive actual count of
  216. // Units moved
  217. {
  218. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::MoveUp");
  219. return GeoMover(Unit, Count, Extend, pDelta, 2);
  220. }
  221. /*
  222. * CTxtSelection::SetFlags (Flags)
  223. *
  224. * @mfunc
  225. * Set this text selection's flags = Flags
  226. *
  227. * @rdesc
  228. * HRESULT = NOERROR
  229. *
  230. * @comm
  231. * RichEdit ignores tomSelReplace since it's always on
  232. */
  233. STDMETHODIMP CTxtSelection::SetFlags(
  234. long Flags) //@parm New flag values
  235. {
  236. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::SetFlags");
  237. if(IsZombie())
  238. return CO_E_RELEASED;
  239. _fCaretNotAtBOL = (Flags & tomSelAtEOL) != 0;
  240. GetPed()->_fOverstrike = (Flags & tomSelOvertype) != 0;
  241. if(!(Flags & tomSelStartActive) ^ (_cch > 0))
  242. FlipRange();
  243. if((Flags & tomSelActive) && !GetPed()->_fFocus)
  244. GetPed()->TxSetFocus();
  245. return NOERROR;
  246. }
  247. /*
  248. * CTxtRange::SetPoint (x, y, Extend)
  249. *
  250. * @mfunc
  251. * Select text at or up through (depending on <p Extend>) the point
  252. * (<p x>, <p y>).
  253. *
  254. * @rdesc
  255. * HRESULT = NOERROR
  256. */
  257. STDMETHODIMP CTxtSelection::SetPoint (
  258. long x, //@parm Horizontal coord of point to select
  259. long y, //@parm Vertical coord of point to select
  260. long Extend) //@parm Whether to extend selection to point
  261. {
  262. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::SelectPoint");
  263. if(IsZombie())
  264. return CO_E_RELEASED;
  265. CCallMgr callmgr(GetPed());
  266. POINT pt = {x, y};
  267. if(Extend)
  268. ExtendSelection (pt);
  269. else
  270. SetCaret(pt, FALSE);
  271. return NOERROR;
  272. }
  273. /*
  274. * CTxtSelection::TypeText (bstr)
  275. *
  276. * @mfunc
  277. * Type the string given by bstr at this selection as if someone typed it.
  278. * This is similar to the underlying ITextRange::SetText() method, but is
  279. * sensitive to the Ins/Ovr key state.
  280. *
  281. * @rdesc
  282. * HRESULT = !<p bstr> ? E_INVALIDARG :
  283. * (whole string typed) ? NOERROR : S_FALSE
  284. * @comm
  285. * This is faster than sending chars via SendMessage(), but it's slower
  286. * than using ITextRange::SetText()
  287. */
  288. STDMETHODIMP CTxtSelection::TypeText (
  289. BSTR bstr) //@parm String to type into this selection
  290. {
  291. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtSelection::TypeText");
  292. if(!bstr)
  293. return E_INVALIDARG;
  294. if(IsZombie())
  295. return CO_E_RELEASED;
  296. CCallMgr callmgr(GetPed());
  297. if(!GetPed()->IsntProtectedOrReadOnly(WM_CHAR, 0, 0))
  298. return E_ACCESSDENIED;
  299. BOOL fOver = GetPed()->_fOverstrike;
  300. DWORD iCount;
  301. OLECHAR * pch = bstr;
  302. IUndoBuilder * publdr;
  303. CGenUndoBuilder undobldr(GetPed(), UB_AUTOCOMMIT, &publdr);
  304. CFreezeDisplay fd(_pdp);
  305. iCount = SysStringLen(bstr);
  306. for ( ; iCount && PutChar(*pch++, fOver, publdr); iCount--)
  307. {
  308. // Simulate one character input at a time
  309. undobldr.Done();
  310. }
  311. return iCount ? S_FALSE : NOERROR;
  312. }
  313. //--------------------- ITextSelection PRIVATE helper methods -----------------------------
  314. /*
  315. * @doc INTERNAL
  316. *
  317. * CTxtSelection::GeoMover (Unit, Count, Extend, pDelta, iDir)
  318. *
  319. * @mfunc
  320. * Helper function to move active end <p Count> <p Unit>s geometrically
  321. *
  322. * Extends range if <p Extend> is TRUE; else collapses range to Start if
  323. * <p Count> <lt> 0 and to End if <p Count> <gt> 0.
  324. *
  325. * Sets *<p pDelta> = count of Units moved
  326. *
  327. * Used by ITextSelection::Left(), Right(), Up(), and Down()
  328. *
  329. * @rdesc
  330. * HRESULT = (if change) ? NOERROR : (if Unit supported) ? S_FALSE
  331. * : E_NOTIMPL
  332. */
  333. HRESULT CTxtSelection::GeoMover (
  334. long Unit, //@parm Unit to use
  335. long Count, //@parm Number of Units to move
  336. long Extend, //@parm Extend selection or go to IP
  337. long * pDelta, //@parm Out parm to receive count of Units moved
  338. LONG iDir) //@parm Direction to move in if Count > 0
  339. {
  340. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEINTERN, "CTxtSelection::GeoMover");
  341. if(pDelta) // Default no movement
  342. *pDelta = 0;
  343. if(IsZombie())
  344. return CO_E_RELEASED;
  345. CCallMgr callmgr(GetPed());
  346. LONG CountSave = Count;
  347. LONG cp;
  348. LONG cUnit;
  349. LONG iDefUnit = (iDir & 0xfe) == 2 ? tomLine : tomCharacter;
  350. BOOL fCollapse = !Extend && _cch;
  351. BOOL fCtrl = Unit != iDefUnit;
  352. _fExtend = Extend != 0;
  353. if(Count < 0)
  354. {
  355. Count = -Count;
  356. iDir ^= 1;
  357. }
  358. if(iDefUnit == tomLine) // Up or Down
  359. {
  360. if(Unit == tomScreen)
  361. {
  362. iDir ^= 6; // Convert Up/Down to PgUp/PgDn
  363. fCtrl = FALSE;
  364. }
  365. else if(Unit == tomWindow) // Go to top/bottom of window
  366. {
  367. iDir ^= 6; // Convert Up/Down to PgUp/PgDn
  368. Count = 1; // Be sure Count = 1
  369. } // Leave fCtrl = 1
  370. else if(fCtrl && Unit != tomParagraph)
  371. return E_INVALIDARG;
  372. }
  373. else if(fCtrl && Unit != tomWord)
  374. return E_INVALIDARG;
  375. for (cUnit = Count; Count; Count--)
  376. {
  377. cp = GetCp(); // Save cp for comparison
  378. switch(iDir) // iDir bit 0 inc/dec for 1/0
  379. { // iDir values are chosen contiguously
  380. case 0: // to encourage compiler to use a
  381. Left(fCtrl); // jump table
  382. break;
  383. case 1: // tomCharacter/tomWord OK here
  384. Right(fCtrl);
  385. break;
  386. case 2: // tomLine/tomParagraph OK here
  387. Up(fCtrl);
  388. break;
  389. case 3: // tomLine/tomParagraph OK here
  390. Down(fCtrl);
  391. break;
  392. case 4: // tomWindow/tomScreen OK here
  393. PageUp(fCtrl);
  394. break;
  395. case 5: // tomWindow/tomScreen OK here
  396. PageDown(fCtrl);
  397. }
  398. if(cp == GetCp() && !fCollapse) // Didn't move or collapse
  399. break; // so we're done
  400. fCollapse = FALSE; // Collapse counts as a Unit
  401. }
  402. cUnit -= Count; // Count of Units moved
  403. if(CountSave < 0)
  404. cUnit = -cUnit; // Negative Counts get negative results
  405. if(pDelta)
  406. *pDelta = cUnit;
  407. return cUnit ? NOERROR : S_FALSE;
  408. }
  409. /*
  410. * CTxtSelection::Homer (Unit, Extend, pDelta, pfn)
  411. *
  412. * @mfunc
  413. * Helper function to move active end Home or End depending on pfn
  414. *
  415. * Extends range if <p Extend> is TRUE; else collapses range to Start if
  416. * <p Count> <lt> 0 and to End if <p Count> <gt> 0.
  417. *
  418. * Sets *<p pDelta> = count of chars moved forward
  419. *
  420. * Used by ITextSelection::Home(), End()
  421. *
  422. * @rdesc
  423. * HRESULT = (invalid Unit) ? E_INVALIDARG :
  424. * (if change) ? NOERROR : S_FALSE
  425. */
  426. HRESULT CTxtSelection::Homer (
  427. long Unit, //@parm Unit to use
  428. long Extend, //@parm Extend selection or go to IP
  429. long * pDelta, //@parm Out parm to receive count of Units moved
  430. BOOL (CTxtSelection::*pfn)(BOOL)) //@parm Direction to move in
  431. {
  432. TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEINTERN, "CTxtSelection::Homer");
  433. if(pDelta) // Default no movement
  434. *pDelta = 0;
  435. if(IsZombie())
  436. return CO_E_RELEASED;
  437. if(Unit != tomLine && Unit != tomStory)
  438. return E_INVALIDARG;
  439. CCallMgr callmgr(GetPed());
  440. LONG cch = GetCp();
  441. _fExtend = Extend != 0;
  442. (this->*pfn)(Unit != tomLine);
  443. cch = GetCp() - cch;
  444. if(pDelta)
  445. *pDelta = cch;
  446. return cch ? NOERROR : S_FALSE;
  447. }