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.

3763 lines
128 KiB

  1. //------------------------------------------------------------------------------
  2. // icmdtgt.cpp
  3. // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
  4. //
  5. // Author
  6. // bash
  7. //
  8. // History
  9. // 7-19-97 created (bash)
  10. //
  11. // Implementation of IOleCommandTarget
  12. //
  13. //------------------------------------------------------------------------------
  14. #include "stdafx.h"
  15. #include <mshtmcid.h>
  16. #include <designer.h>
  17. //#include "mfcincl.h"
  18. #include "triedit.h"
  19. #include "document.h"
  20. #include "triedcid.h" //TriEdit Command IDs here.
  21. #include "dispatch.h"
  22. #include "undo.h"
  23. #define CMDSTATE_NOTSUPPORTED 0
  24. #define CMDSTATE_DISABLED OLECMDF_SUPPORTED
  25. #define CMDSTATE_UP (OLECMDF_SUPPORTED | OLECMDF_ENABLED)
  26. #define CMDSTATE_DOWN (OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_LATCHED)
  27. #define CMDSTATE_NINCHED (OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED)
  28. // Mapping from TriEdit to Trident commands
  29. typedef struct {
  30. ULONG cmdTriEdit;
  31. ULONG cmdTrident;
  32. } CMDMAP;
  33. ///////////////////////////////////////////////////////////////////////////////
  34. //
  35. // CTriEditDocument::MapTriEditCommand
  36. //
  37. // Map the given TriEdit IDM to the equivalent Trident IDM.
  38. //
  39. // Return:
  40. // Mapped command under *pCmdTrident and S_OK for a valid command.
  41. // E_FAIL for an invalid command.
  42. //
  43. HRESULT CTriEditDocument::MapTriEditCommand(ULONG cmdTriEdit, ULONG *pCmdTrident)
  44. {
  45. static CMDMAP rgCmdMap[] = {
  46. { IDM_TRIED_ACTIVATEACTIVEXCONTROLS, IDM_NOACTIVATENORMALOLECONTROLS },
  47. { IDM_TRIED_ACTIVATEAPPLETS, IDM_NOACTIVATEJAVAAPPLETS },
  48. { IDM_TRIED_ACTIVATEDTCS, IDM_NOACTIVATEDESIGNTIMECONTROLS },
  49. { IDM_TRIED_BACKCOLOR, IDM_BACKCOLOR },
  50. { IDM_TRIED_BLOCKFMT, IDM_BLOCKFMT },
  51. { IDM_TRIED_BOLD, IDM_BOLD },
  52. { IDM_TRIED_BROWSEMODE, IDM_BROWSEMODE },
  53. { IDM_TRIED_COPY, IDM_COPY },
  54. { IDM_TRIED_CUT, IDM_CUT },
  55. { IDM_TRIED_DELETE, IDM_DELETE },
  56. { IDM_TRIED_EDITMODE, IDM_EDITMODE },
  57. { IDM_TRIED_FIND, IDM_FIND },
  58. { IDM_TRIED_FONT, IDM_FONT },
  59. { IDM_TRIED_FONTNAME, IDM_FONTNAME },
  60. { IDM_TRIED_FONTSIZE, IDM_FONTSIZE },
  61. { IDM_TRIED_FORECOLOR, IDM_FORECOLOR },
  62. { IDM_TRIED_GETBLOCKFMTS, IDM_GETBLOCKFMTS },
  63. { IDM_TRIED_HYPERLINK, IDM_HYPERLINK },
  64. { IDM_TRIED_IMAGE, IDM_IMAGE },
  65. { IDM_TRIED_INDENT, IDM_INDENT },
  66. { IDM_TRIED_ITALIC, IDM_ITALIC },
  67. { IDM_TRIED_JUSTIFYCENTER, IDM_JUSTIFYCENTER },
  68. { IDM_TRIED_JUSTIFYLEFT, IDM_JUSTIFYLEFT },
  69. { IDM_TRIED_JUSTIFYRIGHT, IDM_JUSTIFYRIGHT },
  70. { IDM_TRIED_ORDERLIST, IDM_ORDERLIST },
  71. { IDM_TRIED_OUTDENT, IDM_OUTDENT },
  72. { IDM_TRIED_PASTE, IDM_PASTE },
  73. { IDM_TRIED_PRINT, IDM_PRINT },
  74. { IDM_TRIED_REDO, IDM_REDO },
  75. { IDM_TRIED_REMOVEFORMAT, IDM_REMOVEFORMAT },
  76. { IDM_TRIED_SELECTALL, IDM_SELECTALL },
  77. { IDM_TRIED_SHOWBORDERS, IDM_SHOWZEROBORDERATDESIGNTIME },
  78. { IDM_TRIED_SHOWDETAILS, IDM_SHOWALLTAGS },
  79. { IDM_TRIED_UNDERLINE, IDM_UNDERLINE },
  80. { IDM_TRIED_UNDO, IDM_UNDO },
  81. { IDM_TRIED_UNLINK, IDM_UNLINK },
  82. { IDM_TRIED_UNORDERLIST, IDM_UNORDERLIST }
  83. };
  84. if (NULL == pCmdTrident)
  85. return E_POINTER;
  86. for (int i=0; i < sizeof(rgCmdMap)/sizeof(CMDMAP); ++i)
  87. {
  88. if (cmdTriEdit == rgCmdMap[i].cmdTriEdit)
  89. {
  90. *pCmdTrident = rgCmdMap[i].cmdTrident;
  91. return S_OK;
  92. }
  93. }
  94. return E_FAIL;
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////
  97. //
  98. // CTriEditDocument::SetUpDefaults
  99. //
  100. // Set Trident flags to the TriEdit default values:
  101. //
  102. // IDM_PRESERVEUNDOALWAYS On
  103. // IDM_NOFIXUPURLSONPASTE On
  104. // IDM_NOACTIVATEDESIGNTIMECONTROLS Off
  105. // IDM_NOACTIVATEJAVAAPPLETS On
  106. // IDM_NOACTIVATENORMALOLECONTROLS On
  107. //
  108. //
  109. // No return value.
  110. void CTriEditDocument::SetUpDefaults()
  111. {
  112. VARIANT var;
  113. // Turn on Trident's preserve undo flag for setting properties
  114. V_VT(&var) = VT_BOOL;
  115. V_BOOL(&var) = TRUE;
  116. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  117. 6049, // IDM_PRESERVEUNDOALWAYS
  118. OLECMDEXECOPT_DONTPROMPTUSER,
  119. &var,
  120. NULL);
  121. // Turn on Trident's url fixup flag for paste and drag-drop
  122. V_VT(&var) = VT_BOOL;
  123. V_BOOL(&var) = TRUE;
  124. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  125. 2335, // IDM_NOFIXUPURLSONPASTE
  126. OLECMDEXECOPT_DONTPROMPTUSER,
  127. &var,
  128. NULL);
  129. // Set up defaults for Activating DTCs but not Applets or other ActiveX Controls
  130. V_VT(&var) = VT_BOOL;
  131. V_BOOL(&var) = FALSE;
  132. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  133. IDM_NOACTIVATEDESIGNTIMECONTROLS,
  134. OLECMDEXECOPT_DONTPROMPTUSER,
  135. &var,
  136. NULL);
  137. V_VT(&var) = VT_BOOL;
  138. V_BOOL(&var) = TRUE;
  139. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  140. IDM_NOACTIVATEJAVAAPPLETS,
  141. OLECMDEXECOPT_DONTPROMPTUSER,
  142. &var,
  143. NULL);
  144. V_VT(&var) = VT_BOOL;
  145. V_BOOL(&var) = TRUE;
  146. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  147. IDM_NOACTIVATENORMALOLECONTROLS,
  148. OLECMDEXECOPT_DONTPROMPTUSER,
  149. &var,
  150. NULL);
  151. }
  152. ///////////////////////////////////////////////////////////////////////////////
  153. //
  154. //
  155. // CTriEditDocument::SetUpGlyphTable
  156. //
  157. // Load the glyphs from the DLL and install them in Trident's table. No return
  158. // value.
  159. //
  160. void CTriEditDocument::SetUpGlyphTable(BOOL fDetails)
  161. {
  162. VARIANT var;
  163. const int RuleMax = 100; // This needs to be updated if we ever have a long rule
  164. const int PathMax = 256; // For %program files%\common files\microsoft shared\triedit\triedit.dll
  165. int iGlyphTableStart = IDS_GLYPHTABLESTART;
  166. int iGlyphTableEnd = fDetails ? IDS_GLYPHTABLEEND : IDS_GLYPHTABLEFORMEND;
  167. TCHAR szPathName[PathMax];
  168. TCHAR szRule[RuleMax + PathMax];
  169. TCHAR szGlyphTable[(RuleMax + PathMax) * (IDS_GLYPHTABLEEND - IDS_GLYPHTABLESTART + 1)];
  170. TCHAR *pchGlyphTable, *pchTemp;
  171. // Get full path name for triedit.dll
  172. ::GetModuleFileName(_Module.GetModuleInstance(),
  173. szPathName,
  174. sizeof(szPathName)
  175. );
  176. // Load glyph table
  177. pchGlyphTable = szGlyphTable;
  178. for (int i = iGlyphTableStart; i <= iGlyphTableEnd; i++)
  179. {
  180. ::LoadString(_Module.GetModuleInstance(), i, szRule, RuleMax);
  181. pchTemp = wcsstr(szRule, _T("!"));
  182. if (pchTemp) // else bad rule, ignore
  183. {
  184. *pchTemp = 0;
  185. // Copy upto the "!"
  186. wcscpy(pchGlyphTable, szRule);
  187. pchGlyphTable += wcslen(szRule);
  188. // Append pathname
  189. wcscpy(pchGlyphTable, szPathName);
  190. pchGlyphTable += wcslen(szPathName);
  191. // Skip past "!"
  192. pchTemp = pchTemp + 1;
  193. // Copy remaining characters
  194. wcscpy(pchGlyphTable, pchTemp);
  195. pchGlyphTable += wcslen(pchTemp);
  196. }
  197. }
  198. // First empty the glyph table
  199. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  200. IDM_EMPTYGLYPHTABLE,
  201. OLECMDEXECOPT_DONTPROMPTUSER,
  202. NULL,
  203. NULL);
  204. V_VT(&var) = VT_BSTR;
  205. V_BSTR(&var) = SysAllocString(szGlyphTable);
  206. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3,
  207. IDM_ADDTOGLYPHTABLE,
  208. OLECMDEXECOPT_DONTPROMPTUSER,
  209. &var,
  210. NULL);
  211. VariantInit(&var);
  212. }
  213. ///////////////////////////////////////////////////////////////////////////////
  214. //
  215. // CTriEditDocument::QueryStatus
  216. //
  217. // Report on the status of the given array of TriEdit and Trident commands.
  218. // Pass Trident commands on to Trident. Fix the Trident return value to
  219. // compensate for some inconsistencies. Return S_OK if all goes well, or
  220. // E_FAIL if not.
  221. //
  222. STDMETHODIMP CTriEditDocument::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  223. OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  224. {
  225. OLECMD *pCmd;
  226. INT c;
  227. HRESULT hr;
  228. if (pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, GUID_TriEditCommandGroup))
  229. {
  230. // Loop through each command in the ary, setting the status of each.
  231. for (pCmd = prgCmds, c = cCmds; --c >= 0; pCmd++)
  232. {
  233. // Assume this is a valid command and set default command status to DISABLED.
  234. // The state will get reset to UP, DOWN or NOTSUPPORTED in the switch statement below.
  235. pCmd->cmdf = CMDSTATE_DISABLED;
  236. switch(pCmd->cmdID)
  237. {
  238. case IDM_TRIED_IS_1D_ELEMENT:
  239. case IDM_TRIED_IS_2D_ELEMENT:
  240. {
  241. if (SUCCEEDED(GetElement()) && m_pihtmlElement)
  242. {
  243. pCmd->cmdf = CMDSTATE_UP;
  244. }
  245. break;
  246. }
  247. case IDM_TRIED_SET_ALIGNMENT:
  248. {
  249. pCmd->cmdf = CMDSTATE_UP;
  250. break;
  251. }
  252. case IDM_TRIED_LOCK_ELEMENT:
  253. {
  254. if (SUCCEEDED(GetElement()) && m_pihtmlElement)
  255. {
  256. BOOL f2d=FALSE;
  257. if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d)
  258. {
  259. BOOL fLocked=FALSE;
  260. pCmd->cmdf =
  261. (SUCCEEDED(IsLocked(m_pihtmlElement, &fLocked)) && fLocked)
  262. ? CMDSTATE_DOWN : CMDSTATE_UP;
  263. }
  264. }
  265. break;
  266. }
  267. case IDM_TRIED_CONSTRAIN:
  268. {
  269. pCmd->cmdf = (m_fConstrain) ? CMDSTATE_DOWN : CMDSTATE_UP;
  270. break;
  271. }
  272. case IDM_TRIED_SEND_TO_BACK:
  273. case IDM_TRIED_SEND_TO_FRONT:
  274. case IDM_TRIED_SEND_BACKWARD:
  275. case IDM_TRIED_SEND_FORWARD:
  276. case IDM_TRIED_SEND_BEHIND_1D:
  277. case IDM_TRIED_SEND_FRONT_1D:
  278. {
  279. if (SUCCEEDED(GetElement()) && m_pihtmlElement)
  280. {
  281. BOOL f2d=FALSE;
  282. if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d)
  283. {
  284. pCmd->cmdf = CMDSTATE_UP;
  285. }
  286. }
  287. break;
  288. }
  289. case IDM_TRIED_NUDGE_ELEMENT:
  290. {
  291. BOOL f2d = FALSE;
  292. if (SUCCEEDED(GetElement()) && m_pihtmlElement
  293. && SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d)
  294. {
  295. BOOL fLock = FALSE;
  296. if (!(SUCCEEDED(IsLocked(m_pihtmlElement, &fLock)) && fLock))
  297. pCmd->cmdf = CMDSTATE_UP;
  298. }
  299. break;
  300. }
  301. case IDM_TRIED_MAKE_ABSOLUTE:
  302. {
  303. if (SUCCEEDED(GetElement()) && m_pihtmlElement)
  304. {
  305. BOOL f2d = FALSE;
  306. if (SUCCEEDED(IsElementDTC(m_pihtmlElement)))
  307. break;
  308. if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)))
  309. {
  310. BOOL f2dCapable=FALSE;
  311. if ( f2d )
  312. {
  313. pCmd->cmdf = CMDSTATE_DOWN;
  314. }
  315. else if (SUCCEEDED(Is2DCapable(m_pihtmlElement, &f2dCapable)) && f2dCapable)
  316. {
  317. pCmd->cmdf = CMDSTATE_UP;
  318. }
  319. }
  320. }
  321. break;
  322. }
  323. case IDM_TRIED_SET_2D_DROP_MODE:
  324. {
  325. pCmd->cmdf = (m_f2dDropMode) ? CMDSTATE_DOWN : CMDSTATE_UP;
  326. break;
  327. }
  328. case IDM_TRIED_INSERTROW:
  329. case IDM_TRIED_DELETEROWS:
  330. case IDM_TRIED_INSERTCELL:
  331. case IDM_TRIED_DELETECELLS:
  332. case IDM_TRIED_INSERTCOL:
  333. {
  334. pCmd->cmdf = (IsSelectionInTable() == S_OK && GetSelectionTypeInTable() != -1)? CMDSTATE_UP : CMDSTATE_DISABLED;
  335. break;
  336. }
  337. case IDM_TRIED_MERGECELLS:
  338. {
  339. ULONG grf = IsSelectionInTable() == S_OK ? GetSelectionTypeInTable() : 0;
  340. pCmd->cmdf = ( (grf != -1) && (!(grf & grfSelectOneCell) && (grf & (grfInSingleRow|grpSelectEntireRow)))) ? CMDSTATE_UP : CMDSTATE_DISABLED;
  341. break;
  342. }
  343. case IDM_TRIED_SPLITCELL:
  344. {
  345. ULONG grf = IsSelectionInTable() == S_OK ? GetSelectionTypeInTable() : 0;
  346. pCmd->cmdf = ((grf != -1) && (grf & grfSelectOneCell)) ? CMDSTATE_UP : CMDSTATE_DISABLED;
  347. break;
  348. }
  349. case IDM_TRIED_DELETECOLS:
  350. {
  351. ULONG grf = IsSelectionInTable() == S_OK ? GetSelectionTypeInTable() : 0;
  352. pCmd->cmdf = ((grf != -1) && (grf & grfInSingleRow)) ? CMDSTATE_UP : CMDSTATE_DISABLED;
  353. break;
  354. }
  355. case IDM_TRIED_INSERTTABLE:
  356. {
  357. pCmd->cmdf = FEnableInsertTable() ? CMDSTATE_UP : CMDSTATE_DISABLED;
  358. break;
  359. }
  360. case IDM_TRIED_DOVERB:
  361. {
  362. if (SUCCEEDED(GetElement()) && m_pihtmlElement && SUCCEEDED(DoVerb(NULL, TRUE)))
  363. pCmd->cmdf = CMDSTATE_UP;
  364. break;
  365. }
  366. case IDM_TRIED_ACTIVATEACTIVEXCONTROLS:
  367. case IDM_TRIED_ACTIVATEAPPLETS:
  368. case IDM_TRIED_ACTIVATEDTCS:
  369. case IDM_TRIED_BACKCOLOR:
  370. case IDM_TRIED_BLOCKFMT:
  371. case IDM_TRIED_BOLD:
  372. case IDM_TRIED_BROWSEMODE:
  373. case IDM_TRIED_COPY:
  374. case IDM_TRIED_CUT:
  375. case IDM_TRIED_DELETE:
  376. case IDM_TRIED_EDITMODE:
  377. case IDM_TRIED_FIND:
  378. case IDM_TRIED_FONT:
  379. case IDM_TRIED_FONTNAME:
  380. case IDM_TRIED_FONTSIZE:
  381. case IDM_TRIED_FORECOLOR:
  382. case IDM_TRIED_GETBLOCKFMTS:
  383. case IDM_TRIED_HYPERLINK:
  384. case IDM_TRIED_IMAGE:
  385. case IDM_TRIED_INDENT:
  386. case IDM_TRIED_ITALIC:
  387. case IDM_TRIED_JUSTIFYCENTER:
  388. case IDM_TRIED_JUSTIFYLEFT:
  389. case IDM_TRIED_JUSTIFYRIGHT:
  390. case IDM_TRIED_ORDERLIST:
  391. case IDM_TRIED_OUTDENT:
  392. case IDM_TRIED_PASTE:
  393. case IDM_TRIED_PRINT:
  394. case IDM_TRIED_REDO:
  395. case IDM_TRIED_REMOVEFORMAT:
  396. case IDM_TRIED_SELECTALL:
  397. case IDM_TRIED_SHOWBORDERS:
  398. case IDM_TRIED_SHOWDETAILS:
  399. case IDM_TRIED_UNDERLINE:
  400. case IDM_TRIED_UNDO:
  401. case IDM_TRIED_UNLINK:
  402. case IDM_TRIED_UNORDERLIST:
  403. {
  404. // We will return E_UNEXPECTED if Trident's command target is not available
  405. hr = E_UNEXPECTED;
  406. _ASSERTE(m_pCmdTgtTrident);
  407. if (m_pCmdTgtTrident)
  408. {
  409. OLECMD olecmd;
  410. olecmd.cmdf = pCmd->cmdf;
  411. if (SUCCEEDED(MapTriEditCommand(pCmd->cmdID, &olecmd.cmdID)))
  412. {
  413. hr = m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, pCmdText);
  414. }
  415. pCmd->cmdf = olecmd.cmdf;
  416. }
  417. if (FAILED(hr))
  418. return hr;
  419. // Trident returns NOTSUPPORTED sometimes when they really mean DISABLED, so we fix this up here.
  420. if (pCmd->cmdf == CMDSTATE_NOTSUPPORTED)
  421. pCmd->cmdf = CMDSTATE_DISABLED;
  422. // Trident returns CMDSTATE_DISABLED for IDM_TRIED_GETBLOCKFMTS but this command should never be disabled
  423. if (pCmd->cmdID == IDM_TRIED_GETBLOCKFMTS)
  424. pCmd->cmdf = CMDSTATE_UP;
  425. // Trident bug: Trident returns the wrong value for IDM_TRIED_SHOWBORDERS,
  426. // IDM_TRIED_SHOWDETAILS and the IDM_TRIED_ACTIVATE* commands, so we fix
  427. // them up here. We don't have code for IDM_TRIED_ACTIVATE* since the logic
  428. // of the Trident commands is actually reverse in these cases.
  429. if (pCmd->cmdID == IDM_TRIED_SHOWBORDERS ||
  430. pCmd->cmdID == IDM_TRIED_SHOWDETAILS)
  431. {
  432. if (pCmd->cmdf == CMDSTATE_UP)
  433. pCmd->cmdf = CMDSTATE_DOWN;
  434. else if (pCmd->cmdf == CMDSTATE_DOWN)
  435. pCmd->cmdf = CMDSTATE_UP;
  436. }
  437. break;
  438. }
  439. default:
  440. {
  441. pCmd->cmdf = CMDSTATE_NOTSUPPORTED;
  442. break;
  443. }
  444. } // switch
  445. } // for
  446. return S_OK;
  447. }
  448. else if (m_pCmdTgtTrident)
  449. {
  450. hr = m_pCmdTgtTrident->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
  451. if (hr != S_OK)
  452. return hr;
  453. // Loop through each command in the ary, fixing up the status of each.
  454. for (pCmd = prgCmds, c = cCmds; --c >= 0; pCmd++)
  455. {
  456. // Trident returns NOTSUPPORTED sometimes when they really mean DISABLED.
  457. if (pCmd->cmdf == CMDSTATE_NOTSUPPORTED)
  458. pCmd->cmdf = CMDSTATE_DISABLED;
  459. if (pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, CMDSETID_Forms3))
  460. {
  461. // Trident returns CMDSTATE_DISABLED for IDM_GETBLOCKFMTS but this command should never be disabled
  462. if (pCmd->cmdID == IDM_GETBLOCKFMTS)
  463. pCmd->cmdf = CMDSTATE_UP;
  464. // Trident bug: Trident returns the wrong value for IDM_SHOWZEROBORDER*,
  465. // IDM_SHOWALLTAGS and the IDM_NOACTIVATE* commands, so we fix
  466. // them up here.
  467. if (pCmd->cmdID == IDM_NOACTIVATENORMALOLECONTROLS ||
  468. pCmd->cmdID == IDM_NOACTIVATEJAVAAPPLETS ||
  469. pCmd->cmdID == IDM_NOACTIVATEDESIGNTIMECONTROLS ||
  470. pCmd->cmdID == IDM_SHOWZEROBORDERATDESIGNTIME ||
  471. pCmd->cmdID == IDM_SHOWALLTAGS)
  472. {
  473. if (pCmd->cmdf == CMDSTATE_UP)
  474. pCmd->cmdf = CMDSTATE_DOWN;
  475. else if (pCmd->cmdf == CMDSTATE_DOWN)
  476. pCmd->cmdf = CMDSTATE_UP;
  477. }
  478. }
  479. }
  480. return S_OK;
  481. }
  482. return E_UNEXPECTED;
  483. }
  484. ///////////////////////////////////////////////////////////////////////////////
  485. //
  486. // CTriEditDocument::Exec
  487. //
  488. // Perform the given TriEdit or Trident command. Pass Trident commands on to
  489. // Trident for execution. Return S_OK if all goes well or E_FAIL if not.
  490. //
  491. STDMETHODIMP CTriEditDocument::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  492. DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  493. {
  494. if (pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, GUID_TriEditCommandGroup) &&
  495. m_pUnkTrident)
  496. {
  497. HRESULT hr = GetElement();
  498. switch(nCmdID)
  499. {
  500. case IDM_TRIED_IS_1D_ELEMENT: //[out,VT_BOOL]
  501. if (pvaOut && m_pihtmlElement &&
  502. SUCCEEDED(VariantChangeType(pvaOut, pvaOut, 0, VT_BOOL)))
  503. {
  504. hr = Is2DElement(m_pihtmlElement, (BOOL*)&pvaOut->boolVal);
  505. _ASSERTE(SUCCEEDED(hr));
  506. if (SUCCEEDED(hr))
  507. {
  508. pvaOut->boolVal = !pvaOut->boolVal;
  509. }
  510. }
  511. break;
  512. case IDM_TRIED_IS_2D_ELEMENT: //[out,VT_BOOL]
  513. if (pvaOut && m_pihtmlElement &&
  514. SUCCEEDED(VariantChangeType(pvaOut, pvaOut, 0, VT_BOOL)))
  515. {
  516. hr = Is2DElement(m_pihtmlElement, (BOOL*)&pvaOut->boolVal);
  517. _ASSERTE(SUCCEEDED(hr));
  518. }
  519. break;
  520. case IDM_TRIED_NUDGE_ELEMENT: //[in,VT_BYREF (VARIANT.byref=LPPOINT)]
  521. {
  522. BOOL fLock = FALSE;
  523. IsLocked(m_pihtmlElement, &fLock);
  524. if (!pvaIn)
  525. hr = E_FAIL;
  526. else if (!fLock && VT_BYREF == pvaIn->vt && pvaIn->byref)
  527. {
  528. hr = NudgeElement(m_pihtmlElement, (LPPOINT)pvaIn->byref);
  529. _ASSERTE(SUCCEEDED(hr));
  530. }
  531. }
  532. break;
  533. case IDM_TRIED_SET_ALIGNMENT: //[in,VT_BYREF (VARIANT.byref=LPPOINT)]
  534. if (!pvaIn)
  535. hr = E_FAIL;
  536. else if (VT_BYREF == pvaIn->vt && pvaIn->byref)
  537. {
  538. hr = SetAlignment((LPPOINT)pvaIn->byref);
  539. _ASSERTE(SUCCEEDED(hr));
  540. }
  541. break;
  542. case IDM_TRIED_LOCK_ELEMENT:
  543. if (m_pihtmlElement)
  544. {
  545. BOOL f2d=FALSE;
  546. BOOL fLocked=TRUE;
  547. if (SUCCEEDED(Is2DElement(m_pihtmlElement, &f2d)) && f2d &&
  548. SUCCEEDED(IsLocked(m_pihtmlElement, &fLocked)))
  549. {
  550. hr = LockElement(m_pihtmlElement, !fLocked);
  551. _ASSERTE(SUCCEEDED(hr));
  552. }
  553. }
  554. break;
  555. case IDM_TRIED_SEND_TO_BACK:
  556. if (m_pihtmlElement)
  557. {
  558. hr = AssignZIndex(m_pihtmlElement, SEND_TO_BACK);
  559. _ASSERTE(SUCCEEDED(hr));
  560. }
  561. break;
  562. case IDM_TRIED_SEND_TO_FRONT:
  563. if (m_pihtmlElement)
  564. {
  565. hr = AssignZIndex(m_pihtmlElement, SEND_TO_FRONT);
  566. _ASSERTE(SUCCEEDED(hr));
  567. }
  568. break;
  569. case IDM_TRIED_SEND_BACKWARD:
  570. if (m_pihtmlElement)
  571. {
  572. hr = AssignZIndex(m_pihtmlElement, SEND_BACKWARD);
  573. _ASSERTE(SUCCEEDED(hr));
  574. }
  575. break;
  576. case IDM_TRIED_SEND_FORWARD:
  577. if (m_pihtmlElement)
  578. {
  579. hr = AssignZIndex(m_pihtmlElement, SEND_FORWARD);
  580. _ASSERTE(SUCCEEDED(hr));
  581. }
  582. break;
  583. case IDM_TRIED_SEND_BEHIND_1D:
  584. if (m_pihtmlElement)
  585. {
  586. hr = AssignZIndex(m_pihtmlElement, SEND_BEHIND_1D);
  587. _ASSERTE(SUCCEEDED(hr));
  588. }
  589. break;
  590. case IDM_TRIED_SEND_FRONT_1D:
  591. if (m_pihtmlElement)
  592. {
  593. hr = AssignZIndex(m_pihtmlElement, SEND_FRONT_1D);
  594. _ASSERTE(SUCCEEDED(hr));
  595. }
  596. break;
  597. case IDM_TRIED_CONSTRAIN:
  598. if (!pvaIn)
  599. hr = E_FAIL;
  600. else if (SUCCEEDED(hr = VariantChangeType(pvaIn, pvaIn, 0, VT_BOOL)))
  601. {
  602. hr = Constrain((BOOL)pvaIn->boolVal);
  603. }
  604. break;
  605. case IDM_TRIED_SET_2D_DROP_MODE:
  606. if (!pvaIn)
  607. hr = E_FAIL;
  608. else if (SUCCEEDED(hr = VariantChangeType(pvaIn, pvaIn, 0, VT_BOOL)))
  609. {
  610. m_f2dDropMode = pvaIn->boolVal;
  611. }
  612. break;
  613. case IDM_TRIED_INSERTROW:
  614. hr = InsertTableRow();
  615. break;
  616. case IDM_TRIED_INSERTCOL:
  617. hr = InsertTableCol();
  618. break;
  619. case IDM_TRIED_INSERTCELL:
  620. hr = InsertTableCell();
  621. break;
  622. case IDM_TRIED_DELETEROWS:
  623. hr = DeleteTableRows();
  624. break;
  625. case IDM_TRIED_DELETECOLS:
  626. hr = DeleteTableCols();
  627. break;
  628. case IDM_TRIED_DELETECELLS:
  629. hr = DeleteTableCells();
  630. break;
  631. case IDM_TRIED_MERGECELLS:
  632. hr = MergeTableCells();
  633. break;
  634. case IDM_TRIED_SPLITCELL:
  635. hr = SplitTableCell();
  636. break;
  637. case IDM_TRIED_INSERTTABLE:
  638. hr = InsertTable(pvaIn);
  639. break;
  640. case IDM_TRIED_DOVERB:
  641. if (m_pihtmlElement)
  642. hr = DoVerb(pvaIn, FALSE);
  643. else
  644. hr = E_FAIL;
  645. break;
  646. case IDM_TRIED_MAKE_ABSOLUTE:
  647. if (m_pihtmlElement)
  648. {
  649. BOOL f2d = FALSE;
  650. hr = Is2DElement(m_pihtmlElement, &f2d);
  651. if (SUCCEEDED(hr))
  652. {
  653. BOOL f2dCapable=FALSE;
  654. if ( f2d )
  655. {
  656. hr = Make1DElement(m_pihtmlElement);
  657. _ASSERTE(SUCCEEDED(hr));
  658. }
  659. else if (SUCCEEDED(Is2DCapable(m_pihtmlElement, &f2dCapable)) && f2dCapable)
  660. {
  661. hr = Make2DElement(m_pihtmlElement);
  662. _ASSERTE(SUCCEEDED(hr));
  663. }
  664. }
  665. }
  666. break;
  667. case IDM_TRIED_ACTIVATEACTIVEXCONTROLS:
  668. case IDM_TRIED_ACTIVATEAPPLETS:
  669. case IDM_TRIED_ACTIVATEDTCS:
  670. case IDM_TRIED_BACKCOLOR:
  671. case IDM_TRIED_BLOCKFMT:
  672. case IDM_TRIED_BOLD:
  673. case IDM_TRIED_BROWSEMODE:
  674. case IDM_TRIED_COPY:
  675. case IDM_TRIED_CUT:
  676. case IDM_TRIED_DELETE:
  677. case IDM_TRIED_EDITMODE:
  678. case IDM_TRIED_FIND:
  679. case IDM_TRIED_FONT:
  680. case IDM_TRIED_FONTNAME:
  681. case IDM_TRIED_FONTSIZE:
  682. case IDM_TRIED_FORECOLOR:
  683. case IDM_TRIED_GETBLOCKFMTS:
  684. case IDM_TRIED_HYPERLINK:
  685. case IDM_TRIED_IMAGE:
  686. case IDM_TRIED_INDENT:
  687. case IDM_TRIED_ITALIC:
  688. case IDM_TRIED_JUSTIFYCENTER:
  689. case IDM_TRIED_JUSTIFYLEFT:
  690. case IDM_TRIED_JUSTIFYRIGHT:
  691. case IDM_TRIED_ORDERLIST:
  692. case IDM_TRIED_OUTDENT:
  693. case IDM_TRIED_PASTE:
  694. case IDM_TRIED_PRINT:
  695. case IDM_TRIED_REDO:
  696. case IDM_TRIED_REMOVEFORMAT:
  697. case IDM_TRIED_SELECTALL:
  698. case IDM_TRIED_SHOWBORDERS:
  699. case IDM_TRIED_SHOWDETAILS:
  700. case IDM_TRIED_UNDERLINE:
  701. case IDM_TRIED_UNDO:
  702. case IDM_TRIED_UNLINK:
  703. case IDM_TRIED_UNORDERLIST:
  704. {
  705. ULONG cmdTrident;
  706. VARIANT varColor;
  707. // We will return E_FAIL if Trident's command target is not available
  708. hr = E_FAIL;
  709. _ASSERTE(m_pCmdTgtTrident);
  710. if (m_pCmdTgtTrident && (SUCCEEDED(MapTriEditCommand(nCmdID, &cmdTrident))))
  711. {
  712. if (nCmdID == IDM_TRIED_ACTIVATEACTIVEXCONTROLS ||
  713. nCmdID == IDM_TRIED_ACTIVATEAPPLETS ||
  714. nCmdID == IDM_TRIED_ACTIVATEDTCS)
  715. {
  716. if (pvaIn && pvaIn->vt == VT_BOOL)
  717. pvaIn->boolVal = !pvaIn->boolVal;
  718. }
  719. // Trident bug: When you exec the forecolor, fontname or fontsize command, they also change the backcolor,
  720. // so we apply a workaround here. The workaround is to save the old backcolor and exec it later.
  721. if (pvaIn && (nCmdID == IDM_TRIED_FORECOLOR || nCmdID == IDM_TRIED_FONTNAME || nCmdID == IDM_TRIED_FONTSIZE))
  722. {
  723. HRESULT hrT;
  724. VariantInit(&varColor);
  725. V_VT(&varColor) = VT_I4;
  726. hrT = m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &varColor);
  727. _ASSERTE(SUCCEEDED(hrT));
  728. }
  729. // Trident bug: When you exec the block format command with "Normal", they don't remove OL and UL tags
  730. if (pvaIn && nCmdID == IDM_TRIED_BLOCKFMT && pvaIn->vt == VT_BSTR && (_wcsicmp(pvaIn->bstrVal, L"Normal") == 0))
  731. {
  732. OLECMD olecmd;
  733. olecmd.cmdID = IDM_ORDERLIST;
  734. olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
  735. if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
  736. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_ORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  737. olecmd.cmdID = IDM_UNORDERLIST;
  738. olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
  739. if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
  740. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_UNORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  741. }
  742. hr = m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, cmdTrident, nCmdExecOpt, pvaIn, pvaOut);
  743. if (pvaIn && (nCmdID == IDM_TRIED_FORECOLOR || nCmdID == IDM_TRIED_FONTNAME || nCmdID == IDM_TRIED_FONTSIZE))
  744. {
  745. HRESULT hrT;
  746. hrT = m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, &varColor, NULL);
  747. _ASSERTE(SUCCEEDED(hrT));
  748. }
  749. else if (nCmdID == IDM_TRIED_SHOWDETAILS && pvaIn && pvaIn->vt == VT_BOOL)
  750. {
  751. SetUpGlyphTable(pvaIn->boolVal);
  752. }
  753. // Trident bug: They enable the justify commands but not actually support them.
  754. // We workaround this by returning S_OK for these no matter what Trident returns.
  755. if (nCmdID == IDM_TRIED_JUSTIFYLEFT || nCmdID == IDM_TRIED_JUSTIFYCENTER || nCmdID == IDM_TRIED_JUSTIFYRIGHT)
  756. hr = S_OK;
  757. }
  758. break;
  759. }
  760. default:
  761. hr = E_FAIL;
  762. break;
  763. }
  764. if (pvaIn)
  765. VariantClear(pvaIn);
  766. // We shouldn't return any unexpected error codes here, so return E_FAIL
  767. if (FAILED(hr))
  768. hr = E_FAIL;
  769. return hr;
  770. }
  771. else if (m_pCmdTgtTrident)
  772. {
  773. HRESULT hr;
  774. BOOL fTridentCmdSet;
  775. VARIANT varColor;
  776. fTridentCmdSet = pguidCmdGroup && IsEqualGUID((const GUID&)*pguidCmdGroup, CMDSETID_Forms3);
  777. #ifdef NEEDED
  778. if (fTridentCmdSet)
  779. {
  780. if (nCmdID == IDM_PARSECOMPLETE)
  781. OnObjectModelComplete();
  782. return S_OK;
  783. }
  784. #endif //NEEDED
  785. // Trident bug: When you exec the forecolor, fontname or fontsize command, they also change the backcolor,
  786. // so we apply a workaround here. The workaround is to save the old backcolor and exec it later.
  787. if (pvaIn && fTridentCmdSet && (nCmdID == IDM_FORECOLOR || nCmdID == IDM_FONTNAME || nCmdID == IDM_FONTSIZE))
  788. {
  789. HRESULT hrT;
  790. VariantInit(&varColor);
  791. V_VT(&varColor) = VT_I4;
  792. hrT = m_pCmdTgtTrident->Exec(pguidCmdGroup, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, NULL, &varColor);
  793. _ASSERTE(SUCCEEDED(hrT));
  794. }
  795. // Trident bug: When you exec the block format command with "Normal", they don't remove OL and UL tags
  796. if (pvaIn && fTridentCmdSet && nCmdID == IDM_BLOCKFMT && pvaIn->vt == VT_BSTR && (_wcsicmp(pvaIn->bstrVal, L"Normal") == 0))
  797. {
  798. OLECMD olecmd;
  799. olecmd.cmdID = IDM_ORDERLIST;
  800. olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
  801. if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
  802. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_ORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  803. olecmd.cmdID = IDM_UNORDERLIST;
  804. olecmd.cmdf = CMDSTATE_NOTSUPPORTED;
  805. if (S_OK == m_pCmdTgtTrident->QueryStatus(&CMDSETID_Forms3, 1, &olecmd, NULL) && olecmd.cmdf == CMDSTATE_DOWN)
  806. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_UNORDERLIST, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  807. }
  808. hr = m_pCmdTgtTrident->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  809. if (pvaIn && fTridentCmdSet && (nCmdID == IDM_FORECOLOR || nCmdID == IDM_FONTNAME || nCmdID == IDM_FONTSIZE))
  810. {
  811. HRESULT hrT;
  812. hrT = m_pCmdTgtTrident->Exec(pguidCmdGroup, IDM_BACKCOLOR, OLECMDEXECOPT_DONTPROMPTUSER, &varColor, NULL);
  813. _ASSERTE(SUCCEEDED(hrT));
  814. }
  815. else if ((nCmdID == IDM_SHOWALLTAGS || nCmdID == IDM_SHOWMISCTAGS) && pvaIn && pvaIn->vt == VT_BOOL)
  816. {
  817. SetUpGlyphTable(pvaIn->boolVal);
  818. }
  819. // Trident bug: They enable the justify commands but not actually support them.
  820. // We workaround this by returning S_OK for these no matter what Trident returns.
  821. if (fTridentCmdSet && (nCmdID == IDM_JUSTIFYLEFT || nCmdID == IDM_JUSTIFYCENTER || nCmdID == IDM_JUSTIFYRIGHT))
  822. hr = S_OK;
  823. return hr;
  824. }
  825. return E_UNEXPECTED;
  826. }
  827. ///////////////////////////////////////////////////////////////////////////////
  828. //
  829. // CTriEditDocument::Is2DElement
  830. //
  831. // Test the given HTML element to ascertain if it is 2D positioned or not.
  832. // Return:
  833. // S_OK and *pf2D = TRUE if the element is 2D positioned.
  834. // S_OK and *pf2D = FALSE if the element is not 2D positioned.
  835. //
  836. HRESULT CTriEditDocument::Is2DElement(IHTMLElement* pihtmlElement, BOOL* pf2D)
  837. {
  838. IHTMLStyle* pihtmlStyle = NULL;
  839. BSTR bstrPosition = NULL;
  840. BOOL f2DCapable;
  841. _ASSERTE(pihtmlElement);
  842. _ASSERTE(pf2D);
  843. *pf2D = FALSE;
  844. if (SUCCEEDED(Is2DCapable(pihtmlElement, &f2DCapable)))
  845. {
  846. if (f2DCapable && SUCCEEDED(pihtmlElement->get_style(&pihtmlStyle)))
  847. {
  848. _ASSERTE(pihtmlStyle);
  849. if (SUCCEEDED(pihtmlStyle->get_position(&bstrPosition)))
  850. {
  851. if (bstrPosition)
  852. {
  853. *pf2D = (_wcsicmp(bstrPosition, L"absolute") == 0);
  854. SysFreeString(bstrPosition);
  855. }
  856. SAFERELEASE(pihtmlStyle);
  857. }
  858. }
  859. }
  860. return S_OK;
  861. }
  862. ///////////////////////////////////////////////////////////////////////////////
  863. //
  864. // CTriEDitDocument::NudgeElement
  865. //
  866. // Move the given HTML element (which must be 2D positioned) as indicated
  867. // by pptNudge, further adjusted by the grid spacing in m_ptAlign. Returns
  868. // S_OK if all goes well; E_UNEXPECTED otherwise.
  869. //
  870. HRESULT CTriEditDocument::NudgeElement(IHTMLElement* pihtmlElement, LPPOINT pptNudge)
  871. {
  872. HRESULT hr = E_UNEXPECTED;
  873. IHTMLStyle* pihtmlStyle = NULL;
  874. long x, y;
  875. _ASSERTE(pihtmlElement);
  876. _ASSERTE(pptNudge);
  877. if (pihtmlElement)
  878. {
  879. if (SUCCEEDED(pihtmlElement->get_style(&pihtmlStyle)) &&
  880. pihtmlStyle &&
  881. SUCCEEDED(pihtmlStyle->get_pixelTop(&y)) &&
  882. SUCCEEDED(pihtmlStyle->get_pixelLeft(&x)))
  883. {
  884. if (x == 0 || y == 0)
  885. {
  886. IHTMLElement *pihtmlElementParent = NULL;
  887. RECT rcElement, rcParent;
  888. if (SUCCEEDED(pihtmlElement->get_offsetParent(&pihtmlElementParent))
  889. && pihtmlElementParent)
  890. {
  891. if (SUCCEEDED(GetElementPosition(pihtmlElement, &rcElement)))
  892. {
  893. ::SetRect(&rcParent, 0, 0, 0, 0);
  894. if (SUCCEEDED(GetElementPosition(pihtmlElementParent, &rcParent)))
  895. {
  896. x = rcElement.left - rcParent.left;
  897. y = rcElement.top - rcParent.top;
  898. }
  899. }
  900. pihtmlElementParent->Release();
  901. }
  902. }
  903. x += pptNudge->x;
  904. y += pptNudge->y;
  905. if (pptNudge->x != 0)
  906. {
  907. if (x >= 0)
  908. x -= (x % m_ptAlign.x);
  909. else
  910. x -= (((x % m_ptAlign.x) ? m_ptAlign.x : 0) + (x % m_ptAlign.x));
  911. }
  912. if (pptNudge->y != 0)
  913. {
  914. if (y >= 0)
  915. y -= (y % m_ptAlign.y);
  916. else
  917. y -= (((y % m_ptAlign.y) ? m_ptAlign.y : 0) + (y % m_ptAlign.y));
  918. }
  919. pihtmlStyle->put_pixelTop(y);
  920. pihtmlStyle->put_pixelLeft(x);
  921. return S_OK;
  922. }
  923. }
  924. SAFERELEASE(pihtmlStyle);
  925. return hr;
  926. }
  927. ///////////////////////////////////////////////////////////////////////////////
  928. //
  929. // CTriEditDocument::SetAlignment
  930. //
  931. // Set the TriEdit alignment values as indicated. Return S_OK if all goes
  932. // well; or E_POINTER if a bad pointer is supplied.
  933. //
  934. HRESULT CTriEditDocument::SetAlignment(LPPOINT pptAlign)
  935. {
  936. _ASSERTE(pptAlign);
  937. if (pptAlign)
  938. {
  939. m_ptAlign.x = max(pptAlign->x, 1);
  940. m_ptAlign.y = max(pptAlign->y, 1);
  941. return S_OK;
  942. }
  943. return E_POINTER;
  944. }
  945. ///////////////////////////////////////////////////////////////////////////////
  946. //
  947. // CTriEditDocument::LockElement
  948. //
  949. // Set or clear the TriEdit design-time locking flag (an expando attribute) as
  950. // indicated by fLock. Return S_OK if all goes well; E_FAIL if not. Note that
  951. // setting the locking flag also sets the top and left attributes if they
  952. // were not already set.
  953. //
  954. HRESULT CTriEditDocument::LockElement(IHTMLElement* pihtmlElement, BOOL fLock)
  955. {
  956. IHTMLStyle* pihtmlStyle=NULL;
  957. HRESULT hr = E_FAIL;
  958. VARIANT var;
  959. VARIANT_BOOL fSuccess = FALSE;
  960. if (pihtmlElement)
  961. {
  962. hr = pihtmlElement->get_style(&pihtmlStyle);
  963. _ASSERTE(SUCCEEDED(hr));
  964. if (SUCCEEDED(hr))
  965. {
  966. _ASSERTE(pihtmlStyle);
  967. if (pihtmlStyle)
  968. {
  969. if(!fLock)
  970. {
  971. hr = pihtmlStyle->removeAttribute(DESIGN_TIME_LOCK, 0, &fSuccess);
  972. _ASSERTE(fSuccess);
  973. }
  974. else
  975. {
  976. // Trident doesn't persist the Design_Time_Lock attribute
  977. // if left, top, width and height properties are not present as part of
  978. // the elements style attribute. Hence as a part of locking the element
  979. // we also assign the top and left styles only if they don't exist.
  980. LONG lTop, lLeft;
  981. pihtmlStyle->get_pixelTop(&lTop);
  982. pihtmlStyle->get_pixelLeft(&lLeft);
  983. if (lTop == 0 || lLeft == 0)
  984. {
  985. IHTMLElement *pihtmlElementParent = NULL;
  986. if (SUCCEEDED(pihtmlElement->get_offsetParent(&pihtmlElementParent))
  987. && pihtmlElementParent)
  988. {
  989. if (SUCCEEDED(GetElementPosition(pihtmlElement, &m_rcElement)))
  990. {
  991. RECT rcParent;
  992. ::SetRect(&rcParent, 0, 0, 0, 0);
  993. if (SUCCEEDED(GetElementPosition(pihtmlElementParent, &rcParent)))
  994. {
  995. m_rcElement.left = m_rcElement.left - rcParent.left;
  996. m_rcElement.top = m_rcElement.top - rcParent.top;
  997. pihtmlStyle->put_pixelTop(m_rcElement.top);
  998. pihtmlStyle->put_pixelLeft(m_rcElement.left);
  999. }
  1000. }
  1001. pihtmlElementParent->Release();
  1002. }
  1003. }
  1004. VariantInit(&var);
  1005. var.vt = VT_BSTR;
  1006. var.bstrVal = SysAllocString(L"True");
  1007. hr = pihtmlStyle->setAttribute(DESIGN_TIME_LOCK, var, 0);
  1008. hr = SUCCEEDED(hr) ? S_OK:E_FAIL;
  1009. }
  1010. pihtmlStyle->Release();
  1011. }
  1012. }
  1013. if (SUCCEEDED(hr))
  1014. {
  1015. RECT rcElement;
  1016. hr = GetElementPosition(pihtmlElement, &rcElement);
  1017. _ASSERTE(SUCCEEDED(hr));
  1018. if (SUCCEEDED(hr))
  1019. {
  1020. InflateRect(&rcElement, ELEMENT_GRAB_SIZE, ELEMENT_GRAB_SIZE);
  1021. if( SUCCEEDED(hr = GetTridentWindow()))
  1022. {
  1023. _ASSERTE(m_hwndTrident);
  1024. InvalidateRect(m_hwndTrident,&rcElement, FALSE);
  1025. }
  1026. }
  1027. // Trident doesn't set itself to be dirty, so force the dirty state.
  1028. VariantInit(&var);
  1029. var.vt = VT_BOOL;
  1030. var.boolVal = TRUE;
  1031. if (m_pCmdTgtTrident)
  1032. m_pCmdTgtTrident->Exec(&CMDSETID_Forms3, IDM_SETDIRTY, 0, &var, NULL);
  1033. }
  1034. }
  1035. return hr;
  1036. }
  1037. ///////////////////////////////////////////////////////////////////////////////
  1038. //
  1039. // CTriEditDocument::IsLocked
  1040. //
  1041. // Test the given HTML element to ascertain if it is design-time locked or not.
  1042. // Return:
  1043. // S_OK and *pfLocked = TRUE if the element is design-time locked.
  1044. // S_OK and *pfLocked = FALSE if the element is not design-time locked.
  1045. //
  1046. HRESULT CTriEditDocument::IsLocked(IHTMLElement* pihtmlElement, BOOL* pfLocked)
  1047. {
  1048. IHTMLStyle* pihtmlStyle=NULL;
  1049. BSTR bstrAttributeName = NULL;
  1050. HRESULT hr = E_FAIL;
  1051. VARIANT var;
  1052. VariantInit(&var);
  1053. var.vt = VT_BSTR;
  1054. var.bstrVal = NULL;
  1055. if (pihtmlElement)
  1056. {
  1057. hr = pihtmlElement->get_style(&pihtmlStyle);
  1058. _ASSERTE(SUCCEEDED(hr));
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. _ASSERTE(pihtmlStyle);
  1062. if (pihtmlStyle)
  1063. {
  1064. bstrAttributeName = SysAllocString(DESIGN_TIME_LOCK);
  1065. if (bstrAttributeName)
  1066. {
  1067. hr = pihtmlStyle->getAttribute(bstrAttributeName, 0, &var);
  1068. _ASSERTE(SUCCEEDED(hr));
  1069. if (var.bstrVal == NULL)
  1070. *pfLocked = FALSE;
  1071. else
  1072. *pfLocked = TRUE;
  1073. SysFreeString(bstrAttributeName);
  1074. }
  1075. pihtmlStyle->Release();
  1076. }
  1077. }
  1078. }
  1079. return hr;
  1080. }
  1081. ///////////////////////////////////////////////////////////////////////////////
  1082. //
  1083. //
  1084. // CTriEditDocument::Make1DElement
  1085. //
  1086. // Set the given HTML element to layout in the flow. As a side effect this
  1087. // also removes any design-time lock on the element. Return S_OK if all goes
  1088. // well; E_UNEXPECTED otherwise.
  1089. //
  1090. HRESULT CTriEditDocument::Make1DElement(IHTMLElement* pihtmlElement)
  1091. {
  1092. IHTMLStyle* pihtmlStyle=NULL;
  1093. VARIANT_BOOL fSuccess = FALSE;
  1094. VARIANT var;
  1095. HRESULT hr;
  1096. if (pihtmlElement)
  1097. {
  1098. pihtmlElement->get_style(&pihtmlStyle);
  1099. _ASSERTE(pihtmlStyle);
  1100. if (pihtmlStyle)
  1101. {
  1102. VariantInit(&var);
  1103. var.vt = VT_I4;
  1104. var.lVal = 0;
  1105. hr = pihtmlStyle->put_zIndex(var);
  1106. _ASSERTE(SUCCEEDED(hr));
  1107. pihtmlStyle->removeAttribute(DESIGN_TIME_LOCK, 0, &fSuccess);
  1108. pihtmlStyle->removeAttribute(L"position", 0, &fSuccess);
  1109. pihtmlStyle->Release();
  1110. }
  1111. }
  1112. return (fSuccess? S_OK: E_UNEXPECTED);
  1113. }
  1114. ///////////////////////////////////////////////////////////////////////////////
  1115. //
  1116. //
  1117. // CTriEditDocument::Make2DElement
  1118. //
  1119. // Set the given HTML element to be positioned. Return S_OK if all goes
  1120. // well; E_FAIL otherwise.
  1121. //
  1122. HRESULT CTriEditDocument::Make2DElement(IHTMLElement* pihtmlElement, POINT *ppt)
  1123. {
  1124. IHTMLElement* pihtmlElementParent = NULL;
  1125. IHTMLElementCollection* pihtmlCollection = NULL;
  1126. IHTMLElement* pihtmlElementNew = NULL;
  1127. IHTMLStyle* pihtmlElementStyle = NULL;
  1128. VARIANT var;
  1129. LONG lSourceIndex;
  1130. HRESULT hr = E_FAIL;
  1131. BSTR bstrOuterHtml = NULL;
  1132. _ASSERTE(pihtmlElement);
  1133. if(!pihtmlElement)
  1134. {
  1135. return E_FAIL;
  1136. }
  1137. hr = pihtmlElement->get_style(&pihtmlElementStyle);
  1138. _ASSERTE(SUCCEEDED(hr) && pihtmlElementStyle);
  1139. if (FAILED(hr) || !pihtmlElementStyle)
  1140. {
  1141. return E_FAIL;
  1142. }
  1143. // The reason to save the source index here is that once we call put_outerHTML
  1144. // the element is lost, we later use the source index to get back the element from the collection.
  1145. // Note that the source index remains the same after put_outerHTML.
  1146. hr = pihtmlElement->get_sourceIndex(&lSourceIndex);
  1147. _ASSERTE(SUCCEEDED(hr) && (lSourceIndex != -1));
  1148. if (lSourceIndex == -1 || FAILED(hr))
  1149. {
  1150. return E_FAIL;
  1151. }
  1152. hr = pihtmlElement->get_offsetParent(&pihtmlElementParent);
  1153. _ASSERTE(SUCCEEDED(hr) && pihtmlElementParent);
  1154. if (SUCCEEDED(hr) && pihtmlElementParent)
  1155. {
  1156. VariantInit(&var);
  1157. var.vt = VT_BSTR;
  1158. var.bstrVal = SysAllocString(L"absolute");
  1159. hr = pihtmlElementStyle->setAttribute(L"position", var, 1);
  1160. if (var.bstrVal)
  1161. SysFreeString(var.bstrVal);
  1162. _ASSERTE(SUCCEEDED(hr));
  1163. if (SUCCEEDED(hr))
  1164. {
  1165. if (SUCCEEDED(hr = GetElementPosition(pihtmlElement, &m_rcElement)))
  1166. {
  1167. IHTMLTable* pihtmlTable = NULL;
  1168. IHTMLElement* pihtmlElementTemp = NULL, *pihtmlElementPrev = NULL;
  1169. RECT rcParent;
  1170. BOOL f2d = FALSE;
  1171. BOOL fIsIE5AndBeyond = IsIE5OrBetterInstalled();
  1172. ::SetRect(&rcParent, 0, 0, 0, 0);
  1173. pihtmlElementTemp = pihtmlElementParent;
  1174. pihtmlElementTemp->AddRef();
  1175. // Handle tables specially since the offset parent may have been the TD or the TR
  1176. while (pihtmlElementTemp)
  1177. {
  1178. if (SUCCEEDED(pihtmlElementTemp->QueryInterface(IID_IHTMLTable, (void **)&pihtmlTable)) && pihtmlTable)
  1179. break;
  1180. pihtmlElementPrev = pihtmlElementTemp;
  1181. pihtmlElementPrev->get_offsetParent(&pihtmlElementTemp);
  1182. SAFERELEASE(pihtmlElementPrev);
  1183. }
  1184. // If parent is a 2d element, we need to offset its top and left
  1185. if (pihtmlElementTemp && SUCCEEDED(Is2DElement(pihtmlElementTemp, &f2d)) && f2d)
  1186. {
  1187. GetElementPosition(pihtmlElementTemp, &rcParent);
  1188. }
  1189. else if (SUCCEEDED(Is2DElement(pihtmlElementParent, &f2d)) && f2d)
  1190. {
  1191. GetElementPosition(pihtmlElementParent, &rcParent);
  1192. }
  1193. SAFERELEASE(pihtmlTable);
  1194. SAFERELEASE(pihtmlElementTemp);
  1195. SAFERELEASE(pihtmlElementPrev);
  1196. m_rcElement.left = (ppt ? ppt->x : m_rcElement.left) - rcParent.left;
  1197. m_rcElement.top = (ppt ? ppt->y : m_rcElement.top) - rcParent.top;
  1198. // We need to call get_outerHTML and put_outerHTML to work around a Trident bug
  1199. // We should not really have to call these here, but the element doesn't get
  1200. // updated unless we do this.
  1201. if (fIsIE5AndBeyond || SUCCEEDED(hr = pihtmlElement->get_outerHTML(&bstrOuterHtml)))
  1202. {
  1203. if (fIsIE5AndBeyond || SUCCEEDED(hr = pihtmlElement->put_outerHTML(bstrOuterHtml)))
  1204. {
  1205. hr = GetAllCollection(&pihtmlCollection);
  1206. _ASSERTE(SUCCEEDED(hr));
  1207. _ASSERTE(pihtmlCollection);
  1208. if (SUCCEEDED(hr) && pihtmlCollection)
  1209. {
  1210. hr = GetCollectionElement(pihtmlCollection, lSourceIndex, &pihtmlElementNew);
  1211. _ASSERTE(SUCCEEDED(hr));
  1212. _ASSERTE(pihtmlElementNew);
  1213. if (SUCCEEDED(hr) && pihtmlElementNew)
  1214. {
  1215. hr = SelectElement(pihtmlElementNew, pihtmlElementParent);
  1216. GetElement(); // to update m_pihtmlElement and friends after the above SelectElement
  1217. if (SUCCEEDED(hr))
  1218. {
  1219. hr = AssignZIndex(pihtmlElementNew, MADE_ABSOLUTE);
  1220. _ASSERTE(SUCCEEDED(hr));
  1221. if (SUCCEEDED(hr))
  1222. {
  1223. SAFERELEASE(pihtmlElementStyle);
  1224. if (SUCCEEDED(hr = pihtmlElementNew->get_style(&pihtmlElementStyle)))
  1225. {
  1226. pihtmlElementStyle->put_pixelLeft(m_rcElement.left);
  1227. pihtmlElementStyle->put_pixelTop(m_rcElement.top);
  1228. VariantInit(&var);
  1229. var.vt = VT_BOOL;
  1230. var.boolVal = FALSE;
  1231. pihtmlElementNew->scrollIntoView(var);
  1232. }
  1233. }
  1234. }
  1235. }
  1236. }
  1237. }
  1238. }
  1239. }
  1240. }
  1241. }
  1242. if (bstrOuterHtml)
  1243. SysFreeString(bstrOuterHtml);
  1244. SAFERELEASE(pihtmlElementParent);
  1245. SAFERELEASE(pihtmlElementStyle);
  1246. SAFERELEASE(pihtmlElementNew);
  1247. SAFERELEASE(pihtmlCollection);
  1248. return hr;
  1249. }
  1250. ///////////////////////////////////////////////////////////////////////////////
  1251. //
  1252. // CTriEditDocument::Constrain
  1253. //
  1254. // Set the TriEdit constraint flag as indicated by fConstrain. Also, reset
  1255. // the constraint direction to CONSTRAIN_NONE. Return S_OK.
  1256. HRESULT CTriEditDocument::Constrain(BOOL fConstrain)
  1257. {
  1258. m_fConstrain = (fConstrain) ? TRUE:FALSE;
  1259. m_eDirection = CONSTRAIN_NONE;
  1260. return S_OK;
  1261. }
  1262. typedef struct SELCELLINFO
  1263. {
  1264. LONG cCellIndex; // cell index in a row
  1265. LONG cRowIndex; // which row is this cell in
  1266. CComPtr<IDispatch> srpCell; // cell element
  1267. CComPtr<IDispatch> srpRow; // row element
  1268. CComPtr<IDispatch> srpTable;
  1269. } SELCELLINFO;
  1270. ///////////////////////////////////////////////////////////////////////////////
  1271. //
  1272. // CTriEditDocument::GetTableRowElementAndTableFromCell
  1273. //
  1274. // Given the IDispatch pointer to an element within a table, return the
  1275. // row index in *pindexRow (if pindexRow is not NULL) and/or the
  1276. // actual row element in *psrpRow (if psrpRow is not NULL) of the
  1277. // element within the table. If psrpTable is not NULL, return the
  1278. // table containing the element therein. Return S_OK if all goes well,
  1279. // or E_FAIL if something goes wrong.
  1280. //
  1281. HRESULT CTriEditDocument::GetTableRowElementAndTableFromCell(IDispatch *srpCell, LONG *pindexRow , IDispatch **psrpRow, IDispatch **psrpTable)
  1282. {
  1283. CComPtr<IDispatch> srpParent,srpElement;
  1284. HRESULT hr = E_FAIL;
  1285. CComBSTR bstrTag;
  1286. _ASSERTE(srpCell != NULL);
  1287. if (pindexRow == NULL && psrpRow == NULL)
  1288. goto Fail;
  1289. srpParent = srpCell;
  1290. while (srpParent != NULL)
  1291. {
  1292. srpElement.Release();
  1293. if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
  1294. goto Fail;
  1295. if (srpElement == NULL)
  1296. {
  1297. hr = E_FAIL;
  1298. goto Fail;
  1299. }
  1300. bstrTag.Empty();
  1301. if (FAILED(hr = GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
  1302. goto Fail;
  1303. if (lstrcmpi(_T("TR"), OLE2T(bstrTag)) == 0)
  1304. {
  1305. if (psrpRow != NULL)
  1306. {
  1307. *psrpRow = srpElement;
  1308. (*psrpRow)->AddRef();
  1309. }
  1310. if (pindexRow != NULL)
  1311. {
  1312. if (FAILED(hr = GetDispatchProperty(srpElement, L"rowIndex", VT_I4, pindexRow)))
  1313. goto Fail;
  1314. }
  1315. break;
  1316. }
  1317. srpParent = srpElement;
  1318. }
  1319. if (psrpTable != NULL)
  1320. {
  1321. srpParent = srpElement;
  1322. while (srpParent != NULL)
  1323. {
  1324. srpElement.Release();
  1325. if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
  1326. goto Fail;
  1327. if (srpElement == NULL)
  1328. {
  1329. hr = E_FAIL;
  1330. goto Fail;
  1331. }
  1332. bstrTag.Empty();
  1333. if (FAILED(hr = GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
  1334. goto Fail;
  1335. if (lstrcmpi(_T("TABLE"), OLE2T(bstrTag)) == 0)
  1336. {
  1337. if (psrpTable != NULL)
  1338. {
  1339. *psrpTable = srpElement;
  1340. (*psrpTable)->AddRef();
  1341. }
  1342. break;
  1343. }
  1344. srpParent = srpElement;
  1345. }
  1346. }
  1347. Fail:
  1348. return hr;
  1349. }
  1350. ///////////////////////////////////////////////////////////////////////////////
  1351. //
  1352. // CTriEditDocument::FEnableInsertTable
  1353. //
  1354. // Return TRUE if the Trident selection is within a table and if the selection
  1355. // type and location will allow elements to be inserted within the table.
  1356. // Return FALSE otherwise.
  1357. //
  1358. BOOL CTriEditDocument::FEnableInsertTable(void)
  1359. {
  1360. BOOL fRet = FALSE;
  1361. CComPtr<IDispatch> srpRange,srpParent,srpElement;
  1362. CComPtr<IHTMLSelectionObject> srpSel;
  1363. CComPtr<IHTMLDocument2> srpiHTMLDoc;
  1364. CComBSTR bstr;
  1365. CComBSTR bstrTag;
  1366. if (FAILED(m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
  1367. goto Fail;
  1368. if (FAILED(srpiHTMLDoc->get_selection(&srpSel)))
  1369. goto Fail;
  1370. if (FAILED(GetDispatchProperty(srpSel, L"type", VT_BSTR, &bstr)))
  1371. goto Fail;
  1372. if (lstrcmpi(_T("CONTROL"), OLE2T(bstr)) == 0)
  1373. {
  1374. return FALSE;
  1375. }
  1376. if (FAILED(CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpRange)))
  1377. goto Fail;
  1378. if (srpRange == NULL)
  1379. goto Fail;
  1380. srpParent = srpRange;
  1381. while (srpParent != NULL)
  1382. {
  1383. srpElement.Release();
  1384. if (FAILED(GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
  1385. goto Fail;
  1386. if (srpElement == NULL)
  1387. break;
  1388. bstrTag.Empty();
  1389. if (FAILED(GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
  1390. goto Fail;
  1391. if (lstrcmpi(_T("INPUT"), OLE2T(bstrTag)) == 0)
  1392. {
  1393. return FALSE;
  1394. }
  1395. srpParent = srpElement;
  1396. }
  1397. // if the selection is inside a table, make sure only one cell is selected
  1398. if (IsSelectionInTable() == S_OK)
  1399. {
  1400. UINT grf = GetSelectionTypeInTable();
  1401. if (grf != -1 && !(grf & grfSelectOneCell))
  1402. return FALSE;
  1403. }
  1404. fRet = TRUE;
  1405. Fail:
  1406. return fRet;
  1407. }
  1408. ///////////////////////////////////////////////////////////////////////////////
  1409. //
  1410. // CTriEditDocument::IsSelectionInTable
  1411. //
  1412. // Return S_OK if the Trident selection is within a table. Return
  1413. // E_FAIL otherwise.
  1414. //
  1415. HRESULT CTriEditDocument::IsSelectionInTable(IDispatch **ppTable)
  1416. {
  1417. HRESULT hr=0;
  1418. CComPtr<IHTMLSelectionObject> srpSel;
  1419. CComPtr<IDispatch> srpRange,srpParent,srpElement;
  1420. CComPtr<IHTMLDocument2> srpiHTMLDoc;
  1421. CComBSTR bstrTag;
  1422. BOOL fTable= FALSE;
  1423. if (FAILED(hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
  1424. goto Fail;
  1425. if (FAILED(hr = srpiHTMLDoc->get_selection(&srpSel)))
  1426. goto Fail;
  1427. if (FAILED(hr = CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpRange)))
  1428. goto Fail;
  1429. srpParent = srpRange;
  1430. while (srpParent != NULL)
  1431. {
  1432. srpElement.Release();
  1433. if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&srpElement)))
  1434. goto Fail;
  1435. if (srpElement == NULL)
  1436. break;
  1437. bstrTag.Empty();
  1438. if (FAILED(hr = GetDispatchProperty(srpElement, L"tagName", VT_BSTR, &bstrTag)))
  1439. goto Fail;
  1440. if (lstrcmpi(_T("TABLE"), OLE2T(bstrTag)) == 0)
  1441. {
  1442. if (ppTable != NULL)
  1443. {
  1444. *ppTable = srpElement;
  1445. (*ppTable)->AddRef();
  1446. }
  1447. fTable = TRUE;
  1448. break;
  1449. }
  1450. else if (lstrcmpi(_T("CAPTION"), OLE2T(bstrTag)) == 0)
  1451. {
  1452. fTable = FALSE;
  1453. break;
  1454. }
  1455. srpParent = srpElement;
  1456. }
  1457. Fail:
  1458. return fTable ? S_OK : E_FAIL;
  1459. }
  1460. ///////////////////////////////////////////////////////////////////////////////
  1461. //
  1462. // CTriEditDocument::FillInSelectionCellsInfo
  1463. //
  1464. // Fill *pSelStart with the information concerning the table cell containing
  1465. // the beginning of the Trident selection and *pSelSle with the information
  1466. // on the table cell at the end of the selection. Return S_OK if all goes well,
  1467. // or E_FAIL otherwise.
  1468. HRESULT CTriEditDocument::FillInSelectionCellsInfo(struct SELCELLINFO * pselStart, struct SELCELLINFO *pselEnd)
  1469. {
  1470. CComPtr<IHTMLDocument2> srpiHTMLDoc;
  1471. CComPtr<IHTMLSelectionObject> srpSel;
  1472. CComPtr<IHTMLTxtRange> srpRange[2];
  1473. CComPtr<IDispatch> srpParent;
  1474. CComBSTR bstrText, bstrTag;;
  1475. LONG cReturn=0;
  1476. HRESULT i=0, hr=0;
  1477. LONG cCharSelected=0;
  1478. WCHAR *pData = NULL;
  1479. BOOL fContain = FALSE;
  1480. if (FAILED(hr = IsSelectionInTable()))
  1481. goto Fail;
  1482. if (FAILED(hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
  1483. goto Fail;
  1484. if (FAILED(hr = srpiHTMLDoc->get_selection(&srpSel)))
  1485. goto Fail;
  1486. for (i=0; i<2 ; i++)
  1487. {
  1488. // BUG 568250. We HAD treated the dispatch like a text range, this now crashes.
  1489. CComPtr<IDispatch> srpDisp;
  1490. if (FAILED(hr = CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpDisp)))
  1491. {
  1492. goto Fail;
  1493. }
  1494. else
  1495. {
  1496. if (FAILED(hr = srpDisp->QueryInterface(&srpRange[i])))
  1497. goto Fail;
  1498. }
  1499. }
  1500. bstrText.Empty();
  1501. hr = srpRange[0]->get_text(&bstrText);
  1502. if (FAILED(hr))
  1503. goto Fail;
  1504. cCharSelected = bstrText ? ocslen(bstrText) : 0;
  1505. pData = (WCHAR *) bstrText;
  1506. // VID98 bug 3117: trident use '0x0D' to mark column/row and this char is ignored when
  1507. // move range so we need to deduct these characters
  1508. while (pData != NULL && *pData !='\0')
  1509. {
  1510. if (*pData == 0x0D)
  1511. cCharSelected--;
  1512. pData++;
  1513. }
  1514. if (pselStart != NULL)
  1515. {
  1516. hr = srpRange[0]->collapse(TRUE);
  1517. if (FAILED(hr))
  1518. goto Fail;
  1519. srpParent = srpRange[0];
  1520. while (srpParent != NULL)
  1521. {
  1522. pselStart->srpCell.Release();
  1523. if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&pselStart->srpCell)))
  1524. goto Fail;
  1525. if (pselStart->srpCell == NULL)
  1526. {
  1527. hr = E_FAIL;
  1528. goto Fail;
  1529. }
  1530. bstrTag.Empty();
  1531. if (FAILED(hr = GetDispatchProperty(pselStart->srpCell, L"tagName", VT_BSTR, &bstrTag)))
  1532. goto Fail;
  1533. if (lstrcmpi(_T("TD"), OLE2T(bstrTag)) == 0 || lstrcmpi(_T("TH"), OLE2T(bstrTag)) == 0)
  1534. {
  1535. break;
  1536. }
  1537. srpParent = pselStart->srpCell;
  1538. }
  1539. _ASSERTE(pselStart->srpCell != NULL);
  1540. if (FAILED(hr = GetDispatchProperty(pselStart->srpCell, L"cellIndex", VT_I4, &pselStart->cCellIndex)))
  1541. goto Fail;
  1542. pselStart->srpRow.Release();
  1543. if (FAILED(hr = GetTableRowElementAndTableFromCell(pselStart->srpCell, &pselStart->cRowIndex, &pselStart->srpRow, &pselStart->srpTable)))
  1544. goto Fail;
  1545. }
  1546. if (pselEnd != NULL)
  1547. {
  1548. hr = srpRange[1]->collapse(FALSE);
  1549. if (FAILED(hr))
  1550. goto Fail;
  1551. if (cCharSelected != 0)
  1552. {
  1553. hr = srpRange[1]->moveStart(L"Character", -1, &cReturn);
  1554. if (FAILED(hr))
  1555. goto Fail;
  1556. hr = srpRange[1]->moveEnd(L"Character", -1, &cReturn);
  1557. if (FAILED(hr))
  1558. goto Fail;
  1559. }
  1560. srpParent = srpRange[1];
  1561. while (srpParent != NULL)
  1562. {
  1563. pselEnd->srpCell.Release();
  1564. if (FAILED(hr = GetDispatchProperty(srpParent, L"parentElement", VT_DISPATCH, (void**)&pselEnd->srpCell)))
  1565. goto Fail;
  1566. if (pselEnd->srpCell == NULL)
  1567. {
  1568. hr = E_FAIL;
  1569. goto Fail;
  1570. }
  1571. bstrTag.Empty();
  1572. if (FAILED(hr = GetDispatchProperty(pselEnd->srpCell, L"tagName", VT_BSTR, &bstrTag)))
  1573. goto Fail;
  1574. if (lstrcmpi(_T("TD"), OLE2T(bstrTag)) == 0 || lstrcmpi(_T("TH"), OLE2T(bstrTag)) == 0)
  1575. {
  1576. break;
  1577. }
  1578. srpParent = pselEnd->srpCell;
  1579. }
  1580. _ASSERTE(pselEnd->srpCell != NULL);
  1581. if (FAILED(hr = GetDispatchProperty(pselEnd->srpCell, L"cellIndex", VT_I4, &pselEnd->cCellIndex)))
  1582. goto Fail;
  1583. pselEnd->srpRow.Release();
  1584. if (FAILED(hr = GetTableRowElementAndTableFromCell(pselEnd->srpCell, &pselEnd->cRowIndex, &pselEnd->srpRow, &pselEnd->srpTable)))
  1585. goto Fail;
  1586. }
  1587. if (pselEnd != NULL && pselStart != NULL)
  1588. {
  1589. // VID 98 bug 3116: we need to check if first cell and last cell are in the same table. If they are not
  1590. // the row index and cell index we just got do not make sense
  1591. if (FAILED(hr = CallDispatchMethod(pselEnd->srpTable, L"contains", VTS_DISPATCH VTS_BOOL_RETURN, pselStart->srpRow, &fContain)))
  1592. goto Fail;
  1593. if (!fContain)
  1594. return E_FAIL;
  1595. fContain = FALSE;
  1596. if (FAILED(hr = CallDispatchMethod(pselStart->srpTable, L"contains", VTS_DISPATCH VTS_BOOL_RETURN, pselEnd->srpRow, &fContain)))
  1597. goto Fail;
  1598. if (!fContain)
  1599. return E_FAIL;
  1600. }
  1601. Fail:
  1602. return hr;
  1603. }
  1604. ///////////////////////////////////////////////////////////////////////////////
  1605. //
  1606. // CTriEditDocument::GetSelectionTypeInTable
  1607. //
  1608. // Return a set of flags that characterize the current selection. Return
  1609. // -1 if something goes wrong. The flags are as follows:
  1610. //
  1611. // grfInSingleRow Selection is comprised of one or more cells
  1612. // within a single row.
  1613. //
  1614. // grfSelectOneCell Selection is comprised of a single cell.
  1615. //
  1616. // grpSelectEntireRow Selection is comprised of one or more
  1617. // complete rows.
  1618. ULONG CTriEditDocument::GetSelectionTypeInTable(void)
  1619. {
  1620. CComPtr<IDispatch> srpCells;
  1621. struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
  1622. LONG cCells=0;
  1623. HRESULT hr=0;
  1624. ULONG grf=0;
  1625. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
  1626. goto Fail;
  1627. if (selinfo[0].cRowIndex == selinfo[1].cRowIndex)
  1628. {
  1629. grf |= grfInSingleRow;
  1630. if (selinfo[0].cCellIndex == selinfo[1].cCellIndex)
  1631. grf |= grfSelectOneCell;
  1632. }
  1633. else
  1634. {
  1635. grf &= ~grfInSingleRow;
  1636. }
  1637. if (selinfo[0].cCellIndex != 0)
  1638. grf &= ~grpSelectEntireRow;
  1639. else
  1640. {
  1641. srpCells.Release();
  1642. if (FAILED(hr = GetDispatchProperty(selinfo[1].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  1643. goto Fail;
  1644. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  1645. goto Fail;
  1646. if (selinfo[1].cCellIndex != cCells-1)
  1647. grf &= ~grpSelectEntireRow;
  1648. else
  1649. grf |= grpSelectEntireRow;
  1650. }
  1651. Fail:
  1652. return FAILED(hr) ? -1 : grf;
  1653. }
  1654. ///////////////////////////////////////////////////////////////////////////////
  1655. //
  1656. // CTriEditDocument::CopyProperty
  1657. //
  1658. // Copy properties from the pFrom element on to the pTo element. Return S_OK.
  1659. //
  1660. HRESULT CTriEditDocument::CopyProperty(IDispatch *pFrom, IDispatch *pTo)
  1661. {
  1662. CComVariant varProp;
  1663. CComBSTR bstrProp;
  1664. VARIANT_BOOL bProp;
  1665. bstrProp.Empty();
  1666. if (SUCCEEDED(GetDispatchProperty(pFrom, L"align", VT_BSTR, (void **)&bstrProp)))
  1667. {
  1668. if (lstrcmpW(bstrProp, L""))
  1669. PutDispatchProperty(pTo, L"align", VT_BSTR, bstrProp);
  1670. }
  1671. bstrProp.Empty();
  1672. if (SUCCEEDED(GetDispatchProperty(pFrom, L"vAlign", VT_BSTR, (void **)&bstrProp)))
  1673. {
  1674. if (lstrcmpW(bstrProp, L""))
  1675. PutDispatchProperty(pTo, L"vAlign", VT_BSTR, bstrProp);
  1676. }
  1677. bstrProp.Empty();
  1678. if (SUCCEEDED(GetDispatchProperty(pFrom, L"background", VT_BSTR, (void **)&bstrProp)))
  1679. {
  1680. if (lstrcmpW(bstrProp, L""))
  1681. PutDispatchProperty(pTo, L"background", VT_BSTR, bstrProp);
  1682. }
  1683. bstrProp.Empty();
  1684. if (SUCCEEDED(GetDispatchProperty(pFrom, L"lang", VT_BSTR, (void **)&bstrProp)))
  1685. {
  1686. if (lstrcmpW(bstrProp, L""))
  1687. PutDispatchProperty(pTo, L"lang", VT_BSTR, bstrProp);
  1688. }
  1689. bstrProp.Empty();
  1690. if (SUCCEEDED(GetDispatchProperty(pFrom, L"className", VT_BSTR, (void **)&bstrProp)))
  1691. {
  1692. if (lstrcmpW(bstrProp, L""))
  1693. PutDispatchProperty(pTo, L"className", VT_BSTR, bstrProp);
  1694. }
  1695. varProp.Clear();
  1696. if (SUCCEEDED(GetDispatchProperty(pFrom, L"bgColor", VT_VARIANT, (void **)&varProp)))
  1697. PutDispatchProperty(pTo, L"bgColor", VT_VARIANT, varProp);
  1698. varProp.Clear();
  1699. if (SUCCEEDED(GetDispatchProperty(pFrom, L"borderColor", VT_VARIANT, (void **)&varProp)))
  1700. PutDispatchProperty(pTo, L"borderColor", VT_VARIANT, varProp);
  1701. varProp.Clear();
  1702. if (SUCCEEDED(GetDispatchProperty(pFrom, L"borderColorLight", VT_VARIANT, (void **)&varProp)))
  1703. PutDispatchProperty(pTo, L"borderColorLight", VT_VARIANT, varProp);
  1704. varProp.Clear();
  1705. if (SUCCEEDED(GetDispatchProperty(pFrom, L"borderColorDark", VT_VARIANT, (void **)&varProp)))
  1706. PutDispatchProperty(pTo, L"borderColorDark", VT_VARIANT, varProp);
  1707. varProp.Clear();
  1708. if (SUCCEEDED(GetDispatchProperty(pFrom, L"height", VT_VARIANT, (void **)&varProp)))
  1709. PutDispatchProperty(pTo, L"height", VT_VARIANT, varProp);
  1710. varProp.Clear();
  1711. if (SUCCEEDED(GetDispatchProperty(pFrom, L"width", VT_VARIANT, (void **)&varProp)))
  1712. PutDispatchProperty(pTo, L"width", VT_VARIANT, varProp);
  1713. if (SUCCEEDED(GetDispatchProperty(pFrom, L"noWrap", VT_BOOL, (void **)&bProp)))
  1714. {
  1715. #pragma warning(disable: 4310) // cast truncates constant value
  1716. if (bProp == VARIANT_TRUE)
  1717. #pragma warning(default: 4310) // cast truncates constant value
  1718. PutDispatchProperty(pTo, L"noWrap", VT_BOOL, bProp);
  1719. }
  1720. return S_OK;
  1721. }
  1722. ///////////////////////////////////////////////////////////////////////////////
  1723. //
  1724. // CTriEditDocument::CopyStyle
  1725. //
  1726. // Copy style properties from style element pFrom on to style element pTo.
  1727. // Return S_OK.
  1728. //
  1729. HRESULT CTriEditDocument::CopyStyle(IDispatch *pFrom, IDispatch *pTo)
  1730. {
  1731. CComPtr<IDispatch> srpStyleTo, srpStyleFrom;
  1732. if (SUCCEEDED(GetDispatchProperty(pFrom, L"style", VT_DISPATCH, (void **)&srpStyleFrom)))
  1733. {
  1734. if (SUCCEEDED(GetDispatchProperty(pTo, L"style", VT_DISPATCH, (void **)&srpStyleTo)))
  1735. {
  1736. CComVariant varProp;
  1737. CComBSTR bstrProp;
  1738. bstrProp.Empty();
  1739. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundAttachment", VT_BSTR, (void **)&bstrProp)))
  1740. {
  1741. if (lstrcmpW(bstrProp, L""))
  1742. PutDispatchProperty(srpStyleTo, L"backgroundAttachment", VT_BSTR, bstrProp);
  1743. }
  1744. bstrProp.Empty();
  1745. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundImage", VT_BSTR, (void **)&bstrProp)))
  1746. {
  1747. if (lstrcmpW(bstrProp, L""))
  1748. PutDispatchProperty(srpStyleTo, L"backgroundImage", VT_BSTR, bstrProp);
  1749. }
  1750. bstrProp.Empty();
  1751. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundRepeat", VT_BSTR, (void **)&bstrProp)))
  1752. {
  1753. if (lstrcmpW(bstrProp, L""))
  1754. PutDispatchProperty(srpStyleTo, L"backgroundRepeat", VT_BSTR, bstrProp);
  1755. }
  1756. bstrProp.Empty();
  1757. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderBottom", VT_BSTR, (void **)&bstrProp)))
  1758. {
  1759. if (lstrcmpW(bstrProp, L""))
  1760. PutDispatchProperty(srpStyleTo, L"borderBottom", VT_BSTR, bstrProp);
  1761. }
  1762. bstrProp.Empty();
  1763. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderLeft", VT_BSTR, (void **)&bstrProp)))
  1764. {
  1765. if (lstrcmpW(bstrProp, L""))
  1766. PutDispatchProperty(srpStyleTo, L"borderLeft", VT_BSTR, bstrProp);
  1767. }
  1768. bstrProp.Empty();
  1769. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderTop", VT_BSTR, (void **)&bstrProp)))
  1770. {
  1771. if (lstrcmpW(bstrProp, L""))
  1772. PutDispatchProperty(srpStyleTo, L"borderTop", VT_BSTR, bstrProp);
  1773. }
  1774. bstrProp.Empty();
  1775. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"borderRight", VT_BSTR, (void **)&bstrProp)))
  1776. {
  1777. if (lstrcmpW(bstrProp, L""))
  1778. PutDispatchProperty(srpStyleTo, L"borderRight", VT_BSTR, bstrProp);
  1779. }
  1780. bstrProp.Empty();
  1781. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontFamily", VT_BSTR, (void **)&bstrProp)))
  1782. {
  1783. if (lstrcmpW(bstrProp, L""))
  1784. PutDispatchProperty(srpStyleTo, L"fontFamily", VT_BSTR, bstrProp);
  1785. }
  1786. bstrProp.Empty();
  1787. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontStyle", VT_BSTR, (void **)&bstrProp)))
  1788. {
  1789. if (lstrcmpW(bstrProp, L""))
  1790. PutDispatchProperty(srpStyleTo, L"fontStyle", VT_BSTR, bstrProp);
  1791. }
  1792. bstrProp.Empty();
  1793. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontVariant", VT_BSTR, (void **)&bstrProp)))
  1794. {
  1795. if (lstrcmpW(bstrProp, L""))
  1796. PutDispatchProperty(srpStyleTo, L"fontVariant", VT_BSTR, bstrProp);
  1797. }
  1798. bstrProp.Empty();
  1799. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontWeight", VT_BSTR, (void **)&bstrProp)))
  1800. {
  1801. if (lstrcmpW(bstrProp, L""))
  1802. PutDispatchProperty(srpStyleTo, L"fontWeight", VT_BSTR, bstrProp);
  1803. }
  1804. bstrProp.Empty();
  1805. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"textAlign", VT_BSTR, (void **)&bstrProp)))
  1806. {
  1807. if (lstrcmpW(bstrProp, L""))
  1808. PutDispatchProperty(srpStyleTo, L"textAlign", VT_BSTR, bstrProp);
  1809. }
  1810. bstrProp.Empty();
  1811. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"textTransform", VT_BSTR, (void **)&bstrProp)))
  1812. {
  1813. if (lstrcmpW(bstrProp, L""))
  1814. PutDispatchProperty(srpStyleTo, L"textTransform", VT_BSTR, bstrProp);
  1815. }
  1816. bstrProp.Empty();
  1817. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"textDecoration", VT_BSTR, (void **)&bstrProp)))
  1818. {
  1819. if (lstrcmpW(bstrProp, L""))
  1820. PutDispatchProperty(srpStyleTo, L"textDecoration", VT_BSTR, bstrProp);
  1821. }
  1822. varProp.Clear();
  1823. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"backgroundcolor", VT_VARIANT, (void **)&varProp)))
  1824. PutDispatchProperty(srpStyleTo, L"backgroundcolor", VT_VARIANT, varProp);
  1825. varProp.Clear();
  1826. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"color", VT_VARIANT, (void **)&varProp)))
  1827. PutDispatchProperty(srpStyleTo, L"color", VT_VARIANT, varProp);
  1828. varProp.Clear();
  1829. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"fontSize", VT_VARIANT, (void **)&varProp)))
  1830. PutDispatchProperty(srpStyleTo, L"fontSize", VT_VARIANT, varProp);
  1831. varProp.Clear();
  1832. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"height", VT_VARIANT, (void **)&varProp)))
  1833. PutDispatchProperty(srpStyleTo, L"height", VT_VARIANT, varProp);
  1834. varProp.Clear();
  1835. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"letterSpacing", VT_VARIANT, (void **)&varProp)))
  1836. PutDispatchProperty(srpStyleTo, L"letterSpacing", VT_VARIANT, varProp);
  1837. varProp.Clear();
  1838. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"lineHeight", VT_VARIANT, (void **)&varProp)))
  1839. PutDispatchProperty(srpStyleTo, L"lineHeight", VT_VARIANT, varProp);
  1840. varProp.Clear();
  1841. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingRight", VT_VARIANT, (void **)&varProp)))
  1842. PutDispatchProperty(srpStyleTo, L"paddingRight", VT_VARIANT, varProp);
  1843. varProp.Clear();
  1844. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingBottom", VT_VARIANT, (void **)&varProp)))
  1845. PutDispatchProperty(srpStyleTo, L"paddingBottom", VT_VARIANT, varProp);
  1846. varProp.Clear();
  1847. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingLeft", VT_VARIANT, (void **)&varProp)))
  1848. PutDispatchProperty(srpStyleTo, L"paddingLeft", VT_VARIANT, varProp);
  1849. varProp.Clear();
  1850. if (SUCCEEDED(GetDispatchProperty(srpStyleFrom, L"paddingTop", VT_VARIANT, (void **)&varProp)))
  1851. PutDispatchProperty(srpStyleTo, L"paddingTop", VT_VARIANT, varProp);
  1852. }
  1853. }
  1854. return S_OK;
  1855. }
  1856. ///////////////////////////////////////////////////////////////////////////////
  1857. //
  1858. // CTriEditDocument::DeleteTableRows
  1859. //
  1860. // Delete the table row(s) contained within the Trident selection. The
  1861. // entire operation is a single undo unit. Return S_OK or a Trident error.
  1862. //
  1863. HRESULT CTriEditDocument::DeleteTableRows(void)
  1864. {
  1865. HRESULT hr = S_OK;
  1866. CComPtr<IHTMLElement> srpTable;
  1867. struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
  1868. INT i=0;
  1869. CUndoPackManager undoPackMgr(m_pUnkTrident);
  1870. if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
  1871. goto Fail;
  1872. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
  1873. goto Fail;
  1874. undoPackMgr.Start();
  1875. for(i= selinfo[0].cRowIndex; i <= selinfo[1].cRowIndex; i++)
  1876. {
  1877. if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
  1878. goto Fail;
  1879. }
  1880. Fail:
  1881. return hr;
  1882. }
  1883. ///////////////////////////////////////////////////////////////////////////////
  1884. //
  1885. // CTriEditDocument::DeleteRowEx
  1886. //
  1887. // Delete the indicated table row. If the row is the only row in the table,
  1888. // delete the whole table. Return S_OK or a Trident error.
  1889. //
  1890. inline HRESULT CTriEditDocument::DeleteRowEx(IHTMLElement *pTable, LONG index)
  1891. {
  1892. HRESULT hr = S_OK;
  1893. CComPtr<IDispatch> srpRows;
  1894. INT cRows = 0;
  1895. if (FAILED(hr = GetDispatchProperty(pTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  1896. goto Fail;
  1897. if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
  1898. goto Fail;
  1899. // if this is the only row in the table, delete the whole table
  1900. if (cRows == 1)
  1901. {
  1902. _ASSERT(index == 0);
  1903. hr = DeleteTable(pTable);
  1904. }
  1905. else
  1906. {
  1907. if (FAILED(hr = CallDispatchMethod(pTable, L"deleteRow", VTS_I4, index)))
  1908. goto Fail;
  1909. }
  1910. Fail:
  1911. return hr;
  1912. }
  1913. ///////////////////////////////////////////////////////////////////////////////
  1914. //
  1915. // CTriEditDocument::DeleteCellEx
  1916. //
  1917. // Delete the indicated cell from the indicated row of the given table. If
  1918. // the cell is the only row in the table, delete the whole table. Return
  1919. // S_OK or a Trident error.
  1920. //
  1921. inline HRESULT CTriEditDocument::DeleteCellEx(IHTMLElement *pTable, IDispatch *pRow, LONG indexRow, LONG indexCell)
  1922. {
  1923. HRESULT hr = S_OK;
  1924. CComPtr<IDispatch> srpCells;
  1925. INT cCells = 0;
  1926. if (FAILED(hr = GetDispatchProperty(pRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  1927. goto Fail;
  1928. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  1929. goto Fail;
  1930. // if this is the only cell in the table, delete the whole row
  1931. if (cCells == 1)
  1932. {
  1933. _ASSERT(indexCell == 0);
  1934. hr = DeleteRowEx(pTable, indexRow);
  1935. }
  1936. else
  1937. {
  1938. if (FAILED(hr = CallDispatchMethod(pRow, L"deleteCell", VTS_I4, indexCell)))
  1939. goto Fail;
  1940. }
  1941. Fail:
  1942. return hr;
  1943. }
  1944. ///////////////////////////////////////////////////////////////////////////////
  1945. //
  1946. // CTriEditDocument::DeleteTable
  1947. //
  1948. // Delete the given table. Return S_OK if all goes well; E_FAIL if something
  1949. // goes wrong.
  1950. //
  1951. HRESULT CTriEditDocument::DeleteTable(IHTMLElement *pTable)
  1952. {
  1953. CComPtr<IHTMLElement> srpParent;
  1954. HRESULT hr = E_FAIL;
  1955. _ASSERTE(pTable != NULL);
  1956. if (pTable == NULL)
  1957. goto Fail;
  1958. if (FAILED(hr=pTable->get_offsetParent(&srpParent)))
  1959. goto Fail;
  1960. _ASSERTE(srpParent != NULL);
  1961. if (FAILED(hr = SelectElement(pTable, srpParent)))
  1962. goto Fail;
  1963. hr = Exec(&CMDSETID_Forms3, IDM_DELETE, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  1964. Fail:
  1965. return hr;
  1966. }
  1967. ///////////////////////////////////////////////////////////////////////////////
  1968. //
  1969. // CTriEditDocument::InsertTableRow
  1970. //
  1971. // Insert a new table row in to the table which contains the Trident selection,
  1972. // in the row preceding the selection. The new row will have the same number of
  1973. // cells as the row containing the selection. The colSpan of each new cell
  1974. // will be copied from the row containing the selection. The entire operation
  1975. // is a single undo unit. Returns S_OK or a Trident error.
  1976. //
  1977. HRESULT CTriEditDocument::InsertTableRow(void)
  1978. {
  1979. HRESULT hr = S_OK;
  1980. CComPtr<IDispatch> srpCell,srpCellNew, srpTable,srpCells,srpRows,srpNewRow,srpCellsNew;
  1981. LONG ccolSpan=0;
  1982. LONG cCells=0,i=0;
  1983. struct SELCELLINFO selinfo;
  1984. CUndoPackManager undoPackMgr(m_pUnkTrident);
  1985. undoPackMgr.Start();
  1986. if (FAILED(hr = IsSelectionInTable(&srpTable)))
  1987. goto Fail;
  1988. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo, NULL)))
  1989. goto Fail;
  1990. if (FAILED(hr = CallDispatchMethod(srpTable, L"insertRow", VTS_I4, selinfo.cRowIndex)))
  1991. goto Fail;
  1992. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  1993. goto Fail;
  1994. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, selinfo.cRowIndex, &srpNewRow)))
  1995. goto Fail;
  1996. CopyStyle(selinfo.srpRow, srpNewRow);
  1997. // get the number of cells contains in the selected row
  1998. if (FAILED(hr = GetDispatchProperty(selinfo.srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  1999. goto Fail;
  2000. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2001. goto Fail;
  2002. // now insert cells
  2003. for (i=cCells-1; i >=0; i--)
  2004. {
  2005. if (FAILED(hr = CallDispatchMethod(srpNewRow, L"insertCell", VTS_I4, 0)))
  2006. goto Fail;
  2007. srpCell.Release();
  2008. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
  2009. goto Fail;
  2010. srpCellsNew.Release();
  2011. if (FAILED(hr = GetDispatchProperty(srpNewRow, L"cells", VT_DISPATCH, (void**)&srpCellsNew)))
  2012. goto Fail;
  2013. srpCellNew.Release();
  2014. if (FAILED(hr = CallDispatchMethod(srpCellsNew, L"Item", VTS_I4 VTS_DISPATCH_RETURN, 0, &srpCellNew)))
  2015. goto Fail;
  2016. CopyStyle(srpCell, srpCellNew);
  2017. CopyProperty(srpCell, srpCellNew);
  2018. {
  2019. VARIANT width;
  2020. VariantInit(&width);
  2021. if (SUCCEEDED(hr = GetDispatchProperty(srpCell, L"width", VT_VARIANT, &width)))
  2022. PutDispatchProperty(srpCellNew, L"width", VT_VARIANT, width);
  2023. }
  2024. if (SUCCEEDED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpan)))
  2025. PutDispatchProperty(srpCellNew, L"colSpan", VT_I4, ccolSpan);
  2026. }
  2027. Fail:
  2028. return hr;
  2029. }
  2030. ///////////////////////////////////////////////////////////////////////////////
  2031. //
  2032. // CTriEditDocument::MapCellToFirstRowCell
  2033. //
  2034. // Given a table cell in pselInfo, return (by modifying pselInfo) the cell in
  2035. // the first row with the same column position, accounting for colSpans. Return
  2036. // S_OK or a Trident error.
  2037. //
  2038. HRESULT CTriEditDocument::MapCellToFirstRowCell(IDispatch *srpTable, struct SELCELLINFO *pselinfo)
  2039. {
  2040. HRESULT hr = 0;
  2041. CComPtr<IDispatch> srpCell, srpCells,srpRow,srpRows;
  2042. INT i=0,iCellIndex=0,iColSpanCurRow=0,cSpan=0,iColSpanFirstRow=0,crowSpan=0;
  2043. _ASSERTE(pselinfo != NULL);
  2044. // if current selection is not first row, find the corresponding first row cell index
  2045. if (pselinfo->cRowIndex == 0)
  2046. return S_OK;
  2047. srpCells.Release();
  2048. _ASSERTE(pselinfo->srpRow != NULL);
  2049. if (FAILED(hr = GetDispatchProperty(pselinfo->srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2050. goto Fail;
  2051. for (i=0; i < pselinfo->cCellIndex ; i++)
  2052. {
  2053. srpCell.Release();
  2054. _ASSERTE(srpCells != NULL);
  2055. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
  2056. goto Fail;
  2057. _ASSERTE(srpCell != NULL);
  2058. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
  2059. goto Fail;
  2060. iColSpanCurRow += cSpan;
  2061. }
  2062. srpRows.Release();
  2063. _ASSERTE(srpTable != NULL);
  2064. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2065. goto Fail;
  2066. _ASSERTE(srpRows != NULL);
  2067. srpRow.Release();
  2068. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item",VTS_I4 VTS_DISPATCH_RETURN, 0, &srpRow)))
  2069. goto Fail;
  2070. srpCells.Release();
  2071. if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2072. goto Fail;
  2073. iCellIndex=-1;
  2074. while(iColSpanCurRow >= iColSpanFirstRow)
  2075. {
  2076. iCellIndex++;
  2077. srpCell.Release();
  2078. _ASSERTE(srpCells != NULL);
  2079. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, iCellIndex, &srpCell)))
  2080. goto Fail;
  2081. // we might hit the end. If so, first row is shorter than curret row and there's no mapping first row, bail out...
  2082. if (srpCell == NULL)
  2083. {
  2084. hr = E_FAIL;
  2085. goto Fail;
  2086. }
  2087. _ASSERTE(srpCell != NULL);
  2088. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
  2089. goto Fail;
  2090. iColSpanFirstRow += cSpan;
  2091. if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &crowSpan)))
  2092. goto Fail;
  2093. if (crowSpan > pselinfo->cRowIndex)
  2094. {
  2095. iColSpanCurRow += cSpan;
  2096. }
  2097. }
  2098. pselinfo->srpCell = srpCell;
  2099. pselinfo->srpRow.Release();
  2100. if (FAILED(hr = GetTableRowElementAndTableFromCell(pselinfo->srpCell, NULL, &pselinfo->srpRow)))
  2101. goto Fail;
  2102. pselinfo->cRowIndex = 0;
  2103. _ASSERTE(iCellIndex >= 0);
  2104. pselinfo->cCellIndex = iCellIndex;
  2105. Fail:
  2106. return hr;
  2107. }
  2108. ///////////////////////////////////////////////////////////////////////////////
  2109. //
  2110. // CTriEditDocument::InsertTableCol
  2111. //
  2112. // Insert a new column in to the table containing the selection, at the column
  2113. // of the selection. The entire operation is a single undo unit. Return S_OK
  2114. // or a Trident error.
  2115. //
  2116. HRESULT CTriEditDocument::InsertTableCol(void)
  2117. {
  2118. HRESULT hr = S_OK;
  2119. CComPtr<IDispatch> srpCellNew, srpTable,srpRows,srpRow,srpCells,srpCell;
  2120. LONG cRows=0,i=0, j=0, iColSpanInsert=0, iColSpanCur=0, cSpan=0,crowSpan = 0, cCells=0;
  2121. struct SELCELLINFO selinfo;
  2122. INT *pccolFix = NULL;
  2123. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2124. undoPackMgr.Start();
  2125. if (FAILED(hr = IsSelectionInTable(&srpTable)))
  2126. goto Fail;
  2127. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo, NULL)))
  2128. goto Fail;
  2129. MapCellToFirstRowCell(srpTable, &selinfo);
  2130. srpCells.Release();
  2131. _ASSERTE(selinfo.srpRow != NULL);
  2132. if (FAILED(hr = GetDispatchProperty(selinfo.srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2133. goto Fail;
  2134. _ASSERTE(srpTable != NULL);
  2135. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2136. goto Fail;
  2137. _ASSERTE(srpRows != NULL);
  2138. if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
  2139. goto Fail;
  2140. pccolFix = new INT[cRows];
  2141. _ASSERTE(pccolFix != NULL);
  2142. for (i=0; i< cRows; i++)
  2143. *(pccolFix+i) = 0;
  2144. for (i=0; i < selinfo.cCellIndex; i++)
  2145. {
  2146. srpCell.Release();
  2147. _ASSERTE(srpCells != NULL);
  2148. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell))) goto Fail;
  2149. _ASSERTE(srpCell != NULL);
  2150. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
  2151. goto Fail;
  2152. iColSpanInsert += cSpan;
  2153. if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &crowSpan)))
  2154. goto Fail;
  2155. // if someone before the current cell has row span, this needs to propogate to
  2156. // the next spanned rows
  2157. if (crowSpan > 1)
  2158. {
  2159. for (j= selinfo.cRowIndex+1; j < (selinfo.cRowIndex+crowSpan); j++)
  2160. *(pccolFix+j) += cSpan;
  2161. }
  2162. }
  2163. for (i=0; i < cRows;)
  2164. {
  2165. srpRow.Release();
  2166. _ASSERTE(srpRows != NULL);
  2167. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpRow)))
  2168. goto Fail;
  2169. srpCells.Release();
  2170. _ASSERTE(srpRow != NULL);
  2171. if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2172. goto Fail;
  2173. _ASSERTE(srpCells != NULL);
  2174. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2175. goto Fail;
  2176. iColSpanCur = *(pccolFix+i);
  2177. for (j=0; j < cCells; j++)
  2178. {
  2179. srpCell.Release();
  2180. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpCell))) goto Fail;
  2181. _ASSERTE(srpCell != NULL);
  2182. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cSpan)))
  2183. goto Fail;
  2184. if (iColSpanCur >= iColSpanInsert)
  2185. break;
  2186. iColSpanCur += cSpan;
  2187. }
  2188. _ASSERTE(srpRow != NULL);
  2189. if (FAILED(hr = CallDispatchMethod(srpRow, L"insertCell", VTS_I4, j)))
  2190. goto Fail;
  2191. srpCells.Release();
  2192. if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2193. goto Fail;
  2194. srpCellNew.Release();
  2195. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpCellNew)))
  2196. goto Fail;
  2197. if (!(!srpCell))
  2198. {
  2199. CopyStyle(srpCell, srpCellNew);
  2200. CopyProperty(srpCell, srpCellNew);
  2201. {
  2202. VARIANT height;
  2203. VariantInit(&height);
  2204. if (SUCCEEDED(hr = GetDispatchProperty(srpCell, L"height", VT_VARIANT, &height)))
  2205. PutDispatchProperty(srpCellNew, L"height", VT_VARIANT, height);
  2206. }
  2207. if (SUCCEEDED(GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &cSpan)))
  2208. PutDispatchProperty(srpCellNew, L"rowSpan", VT_I4, cSpan);
  2209. }
  2210. // cSpan might be 0 if we are inserting a cell into an empty row
  2211. i += max(1, cSpan);
  2212. }
  2213. Fail:
  2214. if (pccolFix != NULL)
  2215. delete [] pccolFix;
  2216. return hr;
  2217. }
  2218. ///////////////////////////////////////////////////////////////////////////////
  2219. //
  2220. // CTriEditDocument::DeleteTableCols
  2221. //
  2222. // Delete the table columns that are contained within the Trident selection.
  2223. // The entire operation is a single undo unit. Return S_OK or a Trident error.
  2224. //
  2225. HRESULT CTriEditDocument::DeleteTableCols(void)
  2226. {
  2227. CComPtr<IDispatch> srpRows,srpRow,srpCells,srpCell;
  2228. CComPtr<IHTMLElement> srpTable;
  2229. struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
  2230. LONG cRows=0, i=0, j=0, k=0, cCells=0;
  2231. HRESULT hr=0;
  2232. LONG iColSpanStart=0, iColSpanEnd=0,cColSpan=0,iColSpanCur=0, crowSpan=0;
  2233. INT * pccolFixStart=NULL, *pccolFixEnd = NULL;
  2234. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2235. undoPackMgr.Start();
  2236. if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
  2237. goto Fail;
  2238. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
  2239. goto Fail;
  2240. if (!FAILED(MapCellToFirstRowCell(srpTable, &selinfo[1])))
  2241. MapCellToFirstRowCell(srpTable, &selinfo[0]);
  2242. _ASSERTE(selinfo[0].srpRow != NULL);
  2243. if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2244. goto Fail;
  2245. _ASSERTE(srpCells != NULL);
  2246. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2247. goto Fail;
  2248. _ASSERTE(selinfo[1].cRowIndex == selinfo[0].cRowIndex);
  2249. _ASSERTE(selinfo[1].cCellIndex >= selinfo[0].cCellIndex);
  2250. srpRows.Release();
  2251. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2252. goto Fail;
  2253. _ASSERTE(srpRows != NULL);
  2254. if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
  2255. goto Fail;
  2256. pccolFixEnd = new INT[cRows];
  2257. pccolFixStart = new INT[cRows];
  2258. for (i=0; i< cRows; i++)
  2259. {
  2260. *(pccolFixStart+i) = 0;
  2261. *(pccolFixEnd+i) = 0;
  2262. }
  2263. for (i=0; i<= selinfo[1].cCellIndex; i++)
  2264. {
  2265. srpCell.Release();
  2266. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell))) goto Fail;
  2267. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cColSpan)))
  2268. goto Fail;
  2269. if (i < selinfo[0].cCellIndex)
  2270. iColSpanStart += cColSpan;
  2271. if (i <= selinfo[1].cCellIndex)
  2272. iColSpanEnd += cColSpan;
  2273. if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &crowSpan)))
  2274. goto Fail;
  2275. if (crowSpan > 1)
  2276. {
  2277. if (i < selinfo[0].cCellIndex)
  2278. {
  2279. for (j= selinfo[0].cRowIndex+1; j < selinfo[0].cRowIndex+crowSpan; j++)
  2280. *(pccolFixStart+j) += cColSpan;
  2281. }
  2282. if (i <= selinfo[1].cCellIndex)
  2283. {
  2284. for (j= selinfo[0].cRowIndex+1; j < selinfo[0].cRowIndex+crowSpan; j++)
  2285. *(pccolFixEnd+j) += cColSpan;
  2286. }
  2287. }
  2288. }
  2289. for (j=cRows-1; j >= 0; j--)
  2290. {
  2291. srpRow.Release();
  2292. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpRow)))
  2293. goto Fail;
  2294. srpCells.Release();
  2295. if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2296. goto Fail;
  2297. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2298. goto Fail;
  2299. iColSpanCur = 0;
  2300. _ASSERTE(iColSpanEnd-*(pccolFixEnd+j) >= 0);
  2301. _ASSERTE(iColSpanStart-*(pccolFixStart+j) >= 0);
  2302. for (i=0, k=0; iColSpanCur <= (iColSpanEnd-*(pccolFixEnd+j)) && k < cCells ; i++, k++)
  2303. {
  2304. srpCell.Release();
  2305. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
  2306. goto Fail;
  2307. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &cColSpan)))
  2308. goto Fail;
  2309. if (iColSpanCur >= (iColSpanStart-*(pccolFixStart+j)) && iColSpanCur < (iColSpanEnd-*(pccolFixEnd+j)))
  2310. {
  2311. if (FAILED(hr = DeleteCellEx(srpTable, srpRow, j, i)))
  2312. goto Fail;
  2313. i--; // we've deleted one cell, need to decrement cell index
  2314. }
  2315. iColSpanCur += cColSpan;
  2316. }
  2317. }
  2318. Fail:
  2319. if (pccolFixStart != NULL)
  2320. {
  2321. delete [] pccolFixStart;
  2322. }
  2323. if (pccolFixEnd != NULL)
  2324. {
  2325. delete [] pccolFixEnd;
  2326. }
  2327. return hr;
  2328. }
  2329. ///////////////////////////////////////////////////////////////////////////////
  2330. //
  2331. // CTriEditDocument::InsertTableCell
  2332. //
  2333. // Insert a table cell before the cell containing the Trident selection; copy
  2334. // the properties and style of the cell containing the selection to the new
  2335. // cell. The entire operation is a single undo unit. Returns S_OK or a Trident
  2336. // error.
  2337. //
  2338. HRESULT CTriEditDocument::InsertTableCell(void)
  2339. {
  2340. HRESULT hr = S_OK;
  2341. struct SELCELLINFO selinfo;
  2342. CComPtr<IDispatch> srpCellNew, srpCells;
  2343. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2344. undoPackMgr.Start();
  2345. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo, NULL)))
  2346. goto Fail;
  2347. if (FAILED(hr = CallDispatchMethod(selinfo.srpRow, L"insertCell", VTS_I4, selinfo.cCellIndex)))
  2348. goto Fail;
  2349. srpCells.Release();
  2350. if (FAILED(hr = GetDispatchProperty(selinfo.srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2351. goto Fail;
  2352. srpCellNew.Release();
  2353. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, selinfo.cCellIndex, &srpCellNew)))
  2354. goto Fail;
  2355. CopyStyle(selinfo.srpCell, srpCellNew);
  2356. CopyProperty(selinfo.srpCell, srpCellNew);
  2357. Fail:
  2358. return hr;
  2359. }
  2360. ///////////////////////////////////////////////////////////////////////////////
  2361. //
  2362. // CTriEditDocument::DeleteTableCells
  2363. //
  2364. // Delete the table cells contained within the Trident selection. Delete entire
  2365. // rows as indicated. The entire operation is a single undo unit. Return
  2366. // S_OK or a Trident error.
  2367. //
  2368. HRESULT CTriEditDocument::DeleteTableCells(void)
  2369. {
  2370. CComPtr<IHTMLElement> srpTable,srpCells;
  2371. struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
  2372. LONG i=0, cCells=0;
  2373. HRESULT hr=0;
  2374. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2375. undoPackMgr.Start();
  2376. if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
  2377. goto Fail;
  2378. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
  2379. goto Fail;
  2380. if (selinfo[0].cRowIndex == selinfo[1].cRowIndex) // same row
  2381. {
  2382. srpCells.Release();
  2383. if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2384. goto Fail;
  2385. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2386. goto Fail;
  2387. // if the selection is select all the cells in this row, delete the whole row instead
  2388. if ( cCells == selinfo[1].cCellIndex+1 && selinfo[0].cCellIndex == 0)
  2389. {
  2390. if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
  2391. goto Fail;
  2392. }
  2393. else // delete cell by cell
  2394. {
  2395. for (i = selinfo[1].cCellIndex; i >= selinfo[0].cCellIndex; i--)
  2396. {
  2397. if (FAILED(hr = DeleteCellEx(srpTable, selinfo[0].srpRow, selinfo[0].cRowIndex, i)))
  2398. goto Fail;
  2399. }
  2400. }
  2401. }
  2402. else
  2403. {
  2404. srpCells.Release();
  2405. if (FAILED(hr = GetDispatchProperty(selinfo[1].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2406. goto Fail;
  2407. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2408. goto Fail;
  2409. // if the selection ends at the last cell of the row, delete the whole row instead
  2410. if ( cCells == selinfo[1].cCellIndex+1)
  2411. {
  2412. if (FAILED(hr = DeleteRowEx(srpTable, selinfo[1].cRowIndex)))
  2413. goto Fail;
  2414. }
  2415. else // delete cell by cell
  2416. {
  2417. for (i = selinfo[1].cCellIndex; i >= 0; i--)
  2418. {
  2419. if (FAILED(hr = DeleteCellEx(srpTable, selinfo[1].srpRow, selinfo[1].cRowIndex, i)))
  2420. goto Fail;
  2421. }
  2422. }
  2423. for (i = selinfo[1].cRowIndex-1; i > selinfo[0].cRowIndex; i--)
  2424. {
  2425. if (FAILED(hr = DeleteRowEx(srpTable, i)))
  2426. goto Fail;
  2427. }
  2428. if (selinfo[0].cCellIndex == 0) // if the selection is from first cell of a row across other rows, delete the whole row instead
  2429. {
  2430. if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
  2431. goto Fail;
  2432. }
  2433. else // delete cell by cell
  2434. {
  2435. srpCells.Release();
  2436. if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2437. goto Fail;
  2438. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2439. goto Fail;
  2440. for (i = cCells-1; i >= selinfo[0].cCellIndex; i--)
  2441. {
  2442. if (FAILED(hr = DeleteCellEx(srpTable, selinfo[0].srpRow, selinfo[0].cRowIndex, i)))
  2443. goto Fail;
  2444. }
  2445. }
  2446. }
  2447. Fail:
  2448. return hr;
  2449. }
  2450. ///////////////////////////////////////////////////////////////////////////////
  2451. //
  2452. // CTriEditDocument::MergeTableCells
  2453. //
  2454. // Merge the indicated cells in to a single cell, and adjust its colSpan.
  2455. // The cells must be within a single table row. The innerHTML of all merged cells
  2456. // is concatenated and placed in the remaining cell. Return S_OK or a Trident error.
  2457. //
  2458. HRESULT CTriEditDocument::MergeTableCells(IDispatch* srpTable, INT iRow, INT iIndexStart, INT iIndexEnd)
  2459. {
  2460. CComPtr<IDispatch> srpCells,srpRows,srpCurRow,srpCell;
  2461. INT ccolSpanTotal=0, i=0, ccolSpan=0;
  2462. HRESULT hr=0;
  2463. CComBSTR bstrText;
  2464. CComBSTR bstrMergedText;
  2465. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2466. goto Fail;
  2467. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, iRow, &srpCurRow)))
  2468. goto Fail;
  2469. srpCells.Release();
  2470. if (FAILED(hr = GetDispatchProperty(srpCurRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2471. goto Fail;
  2472. bstrMergedText.Empty();
  2473. ccolSpanTotal = 0;
  2474. for (i = iIndexEnd; i >= iIndexStart; i--)
  2475. {
  2476. srpCell.Release();
  2477. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
  2478. goto Fail;
  2479. bstrText.Empty();
  2480. if (FAILED(hr = GetDispatchProperty(srpCell, L"innerHTML", VT_BSTR, &bstrText)))
  2481. goto Fail;
  2482. bstrText += bstrMergedText;
  2483. bstrMergedText = bstrText;
  2484. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpan)))
  2485. goto Fail;
  2486. ccolSpanTotal += ccolSpan;
  2487. if (i != iIndexStart)
  2488. {
  2489. if (FAILED(hr = DeleteCellEx((IHTMLElement*)srpTable, srpCurRow, iRow, i)))
  2490. goto Fail;
  2491. }
  2492. else
  2493. {
  2494. if (FAILED(hr = PutDispatchProperty(srpCell, L"colSpan", VT_I4, ccolSpanTotal)))
  2495. goto Fail;
  2496. if (FAILED(hr = PutDispatchProperty(srpCell, L"innerHTML", VT_BSTR, bstrMergedText)))
  2497. goto Fail;
  2498. }
  2499. }
  2500. Fail:
  2501. return hr;
  2502. }
  2503. ///////////////////////////////////////////////////////////////////////////////
  2504. //
  2505. // CTriEditDocument::MergeTableCells
  2506. //
  2507. // Merge the cells in the Trident selection in to a single cell, and adjust that
  2508. // cell's colSpan. The cells must be within a single table row. The innerHTML of
  2509. // all merged cells is concatenated and placed in the remaining cell. Return S_OK
  2510. // or a Trident error.
  2511. //
  2512. HRESULT CTriEditDocument::MergeTableCells(void)
  2513. {
  2514. CComPtr<IDispatch> srpCell, srpCells,srpElement,srpRows,srpRow;
  2515. CComPtr<IHTMLElement> srpTable;
  2516. struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
  2517. LONG i=0, cCells=0;
  2518. HRESULT hr=0;
  2519. CComBSTR bstrText;
  2520. CComBSTR bstrMergedText;
  2521. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2522. undoPackMgr.Start();
  2523. if (FAILED(hr = IsSelectionInTable((IDispatch**)&srpTable)))
  2524. goto Fail;
  2525. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
  2526. goto Fail;
  2527. if (selinfo[0].cRowIndex == selinfo[1].cRowIndex)
  2528. {
  2529. if (selinfo[1].cCellIndex == selinfo[0].cCellIndex)
  2530. {
  2531. hr = S_OK;
  2532. goto Fail;
  2533. }
  2534. if (FAILED(hr = MergeTableCells(srpTable, selinfo[0].cRowIndex, selinfo[0].cCellIndex, selinfo[1].cCellIndex)))
  2535. goto Fail;
  2536. }
  2537. else
  2538. {
  2539. srpCells.Release();
  2540. if (FAILED(hr = GetDispatchProperty(selinfo[1].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2541. goto Fail;
  2542. if (FAILED(hr = MergeTableCells(srpTable, selinfo[1].cRowIndex, 0, selinfo[1].cCellIndex)))
  2543. goto Fail;
  2544. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2545. goto Fail;
  2546. for (i = selinfo[1].cRowIndex-1; i > selinfo[0].cRowIndex; i--)
  2547. {
  2548. srpElement.Release();
  2549. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpElement)))
  2550. goto Fail;
  2551. srpCells.Release();
  2552. if (FAILED(hr = GetDispatchProperty(srpElement, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2553. goto Fail;
  2554. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2555. goto Fail;
  2556. if (FAILED(hr = MergeTableCells(srpTable, i, 0, cCells-1)))
  2557. goto Fail;
  2558. }
  2559. srpCells.Release();
  2560. if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2561. goto Fail;
  2562. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2563. goto Fail;
  2564. if (FAILED(hr = MergeTableCells(srpTable, selinfo[0].cRowIndex, selinfo[0].cCellIndex, cCells-1)))
  2565. goto Fail;
  2566. bstrMergedText.Empty();
  2567. for (i = selinfo[0].cRowIndex; i <= selinfo[1].cRowIndex; i++)
  2568. {
  2569. srpRows.Release();
  2570. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2571. goto Fail;
  2572. srpRow.Release();
  2573. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, selinfo[0].cRowIndex, &srpRow)))
  2574. goto Fail;
  2575. srpCells.Release();
  2576. if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2577. goto Fail;
  2578. srpCell.Release();
  2579. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, 0, &srpCell)))
  2580. goto Fail;
  2581. bstrText.Empty();
  2582. if (FAILED(hr = GetDispatchProperty(srpCell, L"innerHTML", VT_BSTR, &bstrText)))
  2583. goto Fail;
  2584. bstrMergedText += L"<P>";
  2585. bstrMergedText += bstrText;
  2586. bstrMergedText += L"</P>";
  2587. if (i != selinfo[1].cRowIndex)
  2588. {
  2589. if (FAILED(hr = DeleteRowEx(srpTable, selinfo[0].cRowIndex)))
  2590. goto Fail;
  2591. }
  2592. }
  2593. if (FAILED(hr = PutDispatchProperty(srpCell, L"innerHTML", VT_BSTR, bstrMergedText)))
  2594. goto Fail;
  2595. }
  2596. Fail:
  2597. return hr;
  2598. }
  2599. ///////////////////////////////////////////////////////////////////////////////
  2600. //
  2601. // CTriEditDocument::SplitTableCell
  2602. //
  2603. // Split the indicated table cell in to two cells and adjust the colSpan
  2604. // of the relevant cells in the other rows as needed. The entire operation is
  2605. // a single undo unit. Return S_OK or a Trident error.
  2606. //
  2607. HRESULT CTriEditDocument::SplitTableCell(IDispatch *srpTable, INT iRow, INT index)
  2608. {
  2609. CComPtr<IDispatch> srpCellSplit, srpCells,srpCell,srpElement,srpRows,srpRow,srpCurRow,srpCellNew;
  2610. INT cRows=0,i=0,j=0,ccolSpan=0,ccolSpanCur=0,crowSpan=0, cCells=0;
  2611. HRESULT hr=0;
  2612. CComBSTR bstrText;
  2613. INT *pccolFix = NULL;
  2614. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2615. undoPackMgr.Start();
  2616. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2617. goto Fail;
  2618. if (FAILED(hr = GetDispatchProperty(srpRows, L"length", VT_I4, &cRows)))
  2619. goto Fail;
  2620. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, iRow, &srpCurRow)))
  2621. goto Fail;
  2622. if (FAILED(hr = CallDispatchMethod(srpCurRow, L"insertCell", VTS_I4, index+1)))
  2623. goto Fail;
  2624. srpCells.Release();
  2625. if (FAILED(hr = GetDispatchProperty(srpCurRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2626. goto Fail;
  2627. srpCellNew.Release();
  2628. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, index+1, &srpCellNew)))
  2629. goto Fail;
  2630. srpCellSplit.Release();
  2631. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, index, (void**)&srpCellSplit)))
  2632. goto Fail;
  2633. ccolSpan=0;
  2634. if (FAILED(hr = GetDispatchProperty(srpCellSplit, L"colSpan", VT_I4, &ccolSpan)))
  2635. goto Fail;
  2636. CopyStyle(srpCellSplit, srpCellNew);
  2637. CopyProperty(srpCellSplit, srpCellNew);
  2638. if (ccolSpan == 1)
  2639. {
  2640. INT ccolSpanStart = 0,ccolSpanEnd=0;
  2641. INT ccolSpanTmp = 0, cRowSpan = 0;
  2642. pccolFix = new INT[cRows];
  2643. for (j=0; j < cRows; j++)
  2644. *(pccolFix+j) = 0;
  2645. for (j=0; j<index;j++)
  2646. {
  2647. srpCell.Release();
  2648. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, (void**)&srpCell)))
  2649. goto Fail;
  2650. ccolSpanTmp = 0;
  2651. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpanTmp)))
  2652. goto Fail;
  2653. ccolSpanStart += ccolSpanTmp;
  2654. if (FAILED(hr = GetDispatchProperty(srpCell, L"rowSpan", VT_I4, &cRowSpan)))
  2655. goto Fail;
  2656. if (cRowSpan > 1)
  2657. for (i = index+1; i < index+cRowSpan; i++)
  2658. *(pccolFix+i) += ccolSpanTmp;
  2659. }
  2660. ccolSpanEnd = ccolSpanStart + ccolSpan;
  2661. for (j=0; j < cRows; j++)
  2662. {
  2663. if (j == iRow)
  2664. continue;
  2665. srpRow.Release();
  2666. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, j, &srpRow)))
  2667. goto Fail;
  2668. srpCells.Release();
  2669. if (FAILED(hr = GetDispatchProperty(srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2670. goto Fail;
  2671. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2672. goto Fail;
  2673. ccolSpanCur = *(pccolFix+j);
  2674. for(i=0 ; i < cCells; i++)
  2675. {
  2676. srpCell.Release();
  2677. if (FAILED(hr = CallDispatchMethod(srpCells, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpCell)))
  2678. goto Fail;
  2679. ccolSpan=0;
  2680. if (FAILED(hr = GetDispatchProperty(srpCell, L"colSpan", VT_I4, &ccolSpan)))
  2681. goto Fail;
  2682. if (ccolSpanStart <= ccolSpanCur && ccolSpanCur < ccolSpanEnd)
  2683. {
  2684. if (FAILED(hr = PutDispatchProperty(srpCell, L"colSpan", VT_I4, ccolSpan+1)))
  2685. goto Fail;
  2686. }
  2687. if (ccolSpanCur >= ccolSpanEnd)
  2688. break;
  2689. ccolSpanCur += ccolSpan;
  2690. }
  2691. }
  2692. }
  2693. else
  2694. {
  2695. if (FAILED(hr = PutDispatchProperty(srpCellNew, L"colSpan", VT_I4, ccolSpan/2)))
  2696. goto Fail;
  2697. if (FAILED(hr = PutDispatchProperty(srpCellSplit, L"colSpan", VT_I4, ccolSpan-ccolSpan/2)))
  2698. goto Fail;
  2699. }
  2700. // now copy row span
  2701. if (FAILED(hr = GetDispatchProperty(srpCellSplit, L"rowSpan", VT_I4, &crowSpan)))
  2702. goto Fail;
  2703. if (FAILED(hr = PutDispatchProperty(srpCellNew, L"rowSpan", VT_I4, crowSpan)))
  2704. goto Fail;
  2705. Fail:
  2706. if (pccolFix != NULL)
  2707. {
  2708. delete [] pccolFix;
  2709. }
  2710. return hr;
  2711. }
  2712. ///////////////////////////////////////////////////////////////////////////////
  2713. //
  2714. // CTriEditDocument::SplitTableCell
  2715. //
  2716. // Split the table cell in the Trident selection in to two cells and adjust the
  2717. // colSpan of the relevant cells in the other rows as needed. The entire operation
  2718. // is a single undo unit. Return S_OK or a Trident error.
  2719. //
  2720. HRESULT CTriEditDocument::SplitTableCell(void)
  2721. {
  2722. CComPtr<IDispatch> srpCell, srpTable,srpCells,srpElement,srpRows,srpRow;
  2723. struct SELCELLINFO selinfo[2]; // 0 is start cell, 1 is end cell
  2724. LONG i=0, j=0,cCells=0;
  2725. HRESULT hr=0;
  2726. CUndoPackManager undoPackMgr(m_pUnkTrident);
  2727. undoPackMgr.Start();
  2728. if (FAILED(hr = IsSelectionInTable(&srpTable)))
  2729. goto Fail;
  2730. if (FAILED(hr = FillInSelectionCellsInfo(&selinfo[0], &selinfo[1])))
  2731. goto Fail;
  2732. if (FAILED(hr = GetDispatchProperty(srpTable, L"rows", VT_DISPATCH, (void**)&srpRows)))
  2733. goto Fail;
  2734. if (selinfo[0].cRowIndex == selinfo[1].cRowIndex)
  2735. {
  2736. for (i = selinfo[1].cCellIndex; i >= selinfo[0].cCellIndex; i--)
  2737. {
  2738. if (FAILED(hr = SplitTableCell(srpTable, selinfo[0].cRowIndex, i)))
  2739. goto Fail;
  2740. }
  2741. }
  2742. else
  2743. {
  2744. for (i = selinfo[1].cCellIndex; i >= 0; i--)
  2745. {
  2746. if (FAILED(hr = SplitTableCell(srpTable, selinfo[1].cRowIndex, i)))
  2747. goto Fail;
  2748. }
  2749. for (i = selinfo[1].cRowIndex-1; i > selinfo[0].cRowIndex; i--)
  2750. {
  2751. srpElement.Release();
  2752. if (FAILED(hr = CallDispatchMethod(srpRows, L"Item", VTS_I4 VTS_DISPATCH_RETURN, i, &srpElement)))
  2753. goto Fail;
  2754. srpCells.Release();
  2755. if (FAILED(hr = GetDispatchProperty(srpElement, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2756. goto Fail;
  2757. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2758. goto Fail;
  2759. for (j = cCells-1; j >= 0; j--)
  2760. {
  2761. if (FAILED(hr = SplitTableCell(srpTable, i, j)))
  2762. goto Fail;
  2763. }
  2764. }
  2765. srpCells.Release();
  2766. if (FAILED(hr = GetDispatchProperty(selinfo[0].srpRow, L"cells", VT_DISPATCH, (void**)&srpCells)))
  2767. goto Fail;
  2768. if (FAILED(hr = GetDispatchProperty(srpCells, L"length", VT_I4, &cCells)))
  2769. goto Fail;
  2770. for (i = cCells-1; i >= selinfo[0].cCellIndex; i--)
  2771. {
  2772. if (FAILED(hr = SplitTableCell(srpTable, selinfo[0].cRowIndex, i)))
  2773. goto Fail;
  2774. }
  2775. }
  2776. Fail:
  2777. return hr;
  2778. }
  2779. ///////////////////////////////////////////////////////////////////////////////
  2780. //
  2781. // CTriEditDocument::InsertTable
  2782. //
  2783. // Insert a table in to the document at the selection point. All parameters
  2784. // are optional and taken from members of pvarargIn as follows:
  2785. //
  2786. // pvarargIn[0] I4 - Number of rows; default 0.
  2787. // pvarargIn[1] I4 - Number of columns; default 0.
  2788. // pvarargIn[2] BSTR - Table tag attributes; default "".
  2789. // pvarargIn[3] BSTR - Table cell attributes; default "".
  2790. // pvarargIn[4] BSTR - Table caption; default "".
  2791. //
  2792. // pvarArgIn must be sipplied even if the default values are to be used for
  2793. // all parameters. The entire operation is a single undo unit. The wait cursor
  2794. // is displayed since this can be a fairly time-consuming operation. Returns S_OK
  2795. // or a Trident error.
  2796. //
  2797. HRESULT CTriEditDocument::InsertTable(VARIANTARG *pvarargIn)
  2798. {
  2799. HRESULT hr=0;
  2800. CComPtr<IHTMLSelectionObject> srpSel;
  2801. CComPtr<IDispatch> srpRange;
  2802. CComPtr<IDispatch> srpCell;
  2803. CComPtr<IHTMLDocument2> srpiHTMLDoc;
  2804. CComBSTR bstrHtml;
  2805. CComBSTR bstrTblAttr;
  2806. CComBSTR bstrTCellAttr;
  2807. CComBSTR bstrCaption;
  2808. int i=0, j=0, iRow=0, iCol=0;
  2809. VARIANT rgvar[5];
  2810. HCURSOR hOldCursor;
  2811. if (pvarargIn == NULL)
  2812. return E_FAIL;
  2813. hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  2814. for(i = 0; i < sizeof(rgvar)/sizeof(VARIANT); i++)
  2815. VariantInit(&rgvar[i]);
  2816. // default
  2817. iRow=1;
  2818. iCol=1;
  2819. bstrTCellAttr.Empty();
  2820. bstrTblAttr.Empty();
  2821. if (pvarargIn != NULL)
  2822. {
  2823. LONG lLBound=0, lUBound=0,lIndex=0;
  2824. SAFEARRAY *psa;
  2825. LONG cParam; // number of parameters host passes in
  2826. psa = V_ARRAY(pvarargIn);
  2827. SafeArrayGetLBound(psa, 1, &lLBound);
  2828. SafeArrayGetUBound(psa, 1, &lUBound);
  2829. cParam = 0;
  2830. _ASSERTE(lLBound == 0);
  2831. _ASSERTE(lUBound - lLBound < 5);
  2832. for (lIndex = lLBound; lIndex <= lUBound && cParam < sizeof(rgvar)/sizeof(VARIANT); lIndex++)
  2833. {
  2834. SafeArrayGetElement(psa, &lIndex, &rgvar[cParam++]);
  2835. }
  2836. // first element: number of rows
  2837. if (cParam >= 1)
  2838. iRow = V_I4(&rgvar[0]);
  2839. // 2'rd element: number of columns
  2840. if (cParam >= 2)
  2841. iCol = V_I4(&rgvar[1]);
  2842. // 3'rd element: table tag attributes
  2843. if (cParam >= 3)
  2844. bstrTblAttr = V_BSTR(&rgvar[2]);
  2845. // 4'th element: table cell tag attributes
  2846. if (cParam >= 4)
  2847. bstrTCellAttr = V_BSTR(&rgvar[3]);
  2848. if (cParam >= 5)
  2849. bstrCaption = V_BSTR(&rgvar[4]);
  2850. }
  2851. if (iRow < 0 || iCol < 0)
  2852. goto Fail;
  2853. bstrHtml.Empty();
  2854. bstrHtml += "<TABLE ";
  2855. if (bstrTblAttr != NULL)
  2856. bstrHtml += bstrTblAttr;
  2857. bstrHtml += ">";
  2858. if (bstrCaption != NULL)
  2859. {
  2860. bstrHtml += "<CAPTION>";
  2861. bstrHtml += bstrCaption;
  2862. bstrHtml += "</CAPTION>";
  2863. }
  2864. bstrHtml +="<TBODY>";
  2865. for (i=0; i<iRow; i++)
  2866. {
  2867. bstrHtml += "<TR>";
  2868. for (j=0; j<iCol; j++)
  2869. {
  2870. bstrHtml += "<TD ";
  2871. if (bstrTCellAttr != NULL)
  2872. bstrHtml += bstrTCellAttr;
  2873. bstrHtml +="></TD>";
  2874. }
  2875. bstrHtml += "</TR>";
  2876. }
  2877. bstrHtml += "</TBODY></TABLE>";
  2878. if (FAILED(hr = m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void**)&srpiHTMLDoc)))
  2879. goto Fail;
  2880. if (FAILED(hr = srpiHTMLDoc->get_selection(&srpSel)))
  2881. goto Fail;
  2882. if (FAILED(hr = CallDispatchMethod(srpSel, L"createRange", VTS_DISPATCH_RETURN, (void**)&srpRange)))
  2883. goto Fail;
  2884. if (FAILED(hr = CallDispatchMethod(srpRange, L"pasteHTML", VTS_BSTR, bstrHtml)))
  2885. goto Fail;
  2886. Fail:
  2887. for(i = 0; i < sizeof(rgvar)/sizeof(VARIANT); i++)
  2888. VariantClear(&rgvar[i]);
  2889. ::SetCursor(hOldCursor);
  2890. return hr;
  2891. }
  2892. ///////////////////////////////////////////////////////////////////////////////
  2893. //
  2894. // CTriEditDocument::DoVerb
  2895. //
  2896. // Execute the verb in pvarargIn (or OLEIVERB_PRIMARY if pvarargIn is NULL)
  2897. // on the current object (which must QI for IHTMLObjectElement). Return E_FAIL
  2898. // or the code returned as a result of executing the verb,
  2899. //
  2900. HRESULT CTriEditDocument::DoVerb(VARIANTARG *pvarargIn, BOOL fQueryStatus)
  2901. {
  2902. LONG iVerb;
  2903. IHTMLObjectElement *piHTMLObjectElement = NULL;
  2904. IDispatch *pDisp = NULL;
  2905. IOleObject *pOleObj = NULL;
  2906. HRESULT hr = E_FAIL;
  2907. _ASSERTE(m_pihtmlElement != NULL);
  2908. if (SUCCEEDED(m_pihtmlElement->QueryInterface(IID_IHTMLObjectElement, (void **)&piHTMLObjectElement)) && piHTMLObjectElement)
  2909. {
  2910. if (SUCCEEDED(piHTMLObjectElement->get_object(&pDisp)) && pDisp)
  2911. {
  2912. if (SUCCEEDED(pDisp->QueryInterface(IID_IOleObject, (void **)&pOleObj)) && pOleObj)
  2913. {
  2914. if (fQueryStatus) // In the query status case, we're done
  2915. hr = S_OK;
  2916. else
  2917. {
  2918. if (pvarargIn == NULL)
  2919. iVerb = OLEIVERB_PRIMARY;
  2920. else if (pvarargIn->vt == VT_I4)
  2921. iVerb = V_I4(pvarargIn);
  2922. else
  2923. {
  2924. hr = E_INVALIDARG;
  2925. goto LSkipDoVerb;
  2926. }
  2927. GetTridentWindow();
  2928. _ASSERTE(m_hwndTrident != NULL);
  2929. hr = pOleObj->DoVerb(iVerb, NULL, NULL, 0, m_hwndTrident, NULL);
  2930. }
  2931. LSkipDoVerb:
  2932. pOleObj->Release();
  2933. }
  2934. pDisp->Release();
  2935. }
  2936. piHTMLObjectElement->Release();
  2937. }
  2938. return hr;
  2939. }
  2940. ///////////////////////////////////////////////////////////////////////////////
  2941. //
  2942. // CTriEditDocument::GetDocument
  2943. //
  2944. // Return the IHTMLDocument pointer (under *ppihtmlDocument) and S_OK, or
  2945. // E_FAIL/E_POINTER.
  2946. //
  2947. STDMETHODIMP CTriEditDocument::GetDocument(IHTMLDocument2** ppihtmlDocument)
  2948. {
  2949. _ASSERTE(ppihtmlDocument);
  2950. if (ppihtmlDocument)
  2951. {
  2952. if (m_pUnkTrident)
  2953. {
  2954. return m_pUnkTrident->QueryInterface(IID_IHTMLDocument2,
  2955. (LPVOID*)ppihtmlDocument);
  2956. }
  2957. return E_FAIL;
  2958. }
  2959. return E_POINTER;
  2960. }
  2961. ///////////////////////////////////////////////////////////////////////////////
  2962. //
  2963. // CTriEditDocument::GetAllColllection
  2964. //
  2965. // Return the all collection of the HTML document (under *ppihtmlCollection),
  2966. // or E_FAIL.
  2967. //
  2968. STDMETHODIMP CTriEditDocument::GetAllCollection(IHTMLElementCollection** ppihtmlCollection)
  2969. {
  2970. IHTMLDocument2* pihtmlDoc2;
  2971. HRESULT hr=E_FAIL;
  2972. _ASSERTE(ppihtmlCollection);
  2973. if (ppihtmlCollection && SUCCEEDED(GetDocument(&pihtmlDoc2)))
  2974. {
  2975. _ASSERTE(pihtmlDoc2);
  2976. hr = pihtmlDoc2->get_all(ppihtmlCollection);
  2977. pihtmlDoc2->Release();
  2978. }
  2979. return hr;
  2980. }
  2981. ///////////////////////////////////////////////////////////////////////////////
  2982. //
  2983. // CTriEditDocument::GetCollectionElement
  2984. //
  2985. // Return the indicated element from the given collection under *ppihtmlElement.
  2986. // Return S_OK if all goes well,or E_FAIL or a Triedent error on error.
  2987. //
  2988. STDMETHODIMP CTriEditDocument::GetCollectionElement(
  2989. IHTMLElementCollection* pihtmlCollection,
  2990. LONG iElem, IHTMLElement** ppihtmlElement)
  2991. {
  2992. VARIANT var;
  2993. VARIANT varEmpty;
  2994. IDispatch* pidispElement=NULL;
  2995. HRESULT hr = E_FAIL;
  2996. _ASSERTE(pihtmlCollection && iElem >= 0 && ppihtmlElement);
  2997. if (!pihtmlCollection || iElem < 0 || !ppihtmlElement)
  2998. return E_POINTER;
  2999. *ppihtmlElement = NULL; //initialize [out] parameter
  3000. VariantInit(&var);
  3001. var.vt = VT_I4;
  3002. var.lVal = iElem;
  3003. VariantInit(&varEmpty);
  3004. varEmpty.vt = VT_EMPTY;
  3005. hr = pihtmlCollection->item(var, varEmpty, &pidispElement);
  3006. if (SUCCEEDED(hr))
  3007. {
  3008. if (pidispElement)
  3009. {
  3010. hr = pidispElement->QueryInterface(IID_IHTMLElement, (LPVOID*)ppihtmlElement);
  3011. pidispElement->Release();
  3012. }
  3013. else
  3014. {
  3015. hr = E_FAIL;
  3016. }
  3017. }
  3018. return hr;
  3019. }
  3020. ///////////////////////////////////////////////////////////////////////////////
  3021. //
  3022. //
  3023. // CTriEditDocument::Is2DCapable
  3024. //
  3025. // Return (under *pfBool) TRUE if the given HTML element can be positioned
  3026. // out of the flow as a 2D element, or FALSE if not. Return S_OK in either
  3027. // case. Return E_FAIL or a Trident error if something goes wrong.
  3028. //
  3029. STDMETHODIMP CTriEditDocument::Is2DCapable(IHTMLElement* pihtmlElement, BOOL* pfBool)
  3030. {
  3031. HRESULT hr= E_FAIL;
  3032. CComBSTR bstrTag;
  3033. _ASSERTE(pihtmlElement);
  3034. if (!pihtmlElement || !pfBool)
  3035. return E_POINTER;
  3036. *pfBool = FALSE;
  3037. bstrTag.Empty();
  3038. if (FAILED(hr = GetDispatchProperty(pihtmlElement, L"tagName", VT_BSTR, &bstrTag)))
  3039. return E_FAIL;
  3040. if (lstrcmpi(_T("APPLET"), OLE2T(bstrTag)) == 0 ||
  3041. lstrcmpi(_T("BUTTON"), OLE2T(bstrTag)) == 0 ||
  3042. lstrcmpi(_T("DIV"), OLE2T(bstrTag)) == 0 ||
  3043. lstrcmpi(_T("EMBED"), OLE2T(bstrTag)) == 0 ||
  3044. lstrcmpi(_T("FIELDSET"), OLE2T(bstrTag)) == 0 ||
  3045. lstrcmpi(_T("HR"), OLE2T(bstrTag)) == 0 ||
  3046. lstrcmpi(_T("IFRAME"), OLE2T(bstrTag)) == 0 ||
  3047. lstrcmpi(_T("IMG"), OLE2T(bstrTag)) == 0 ||
  3048. lstrcmpi(_T("INPUT"), OLE2T(bstrTag)) == 0 ||
  3049. lstrcmpi(_T("MARQUEE"), OLE2T(bstrTag)) == 0 ||
  3050. lstrcmpi(_T("OBJECT"), OLE2T(bstrTag)) == 0 ||
  3051. lstrcmpi(_T("SELECT"), OLE2T(bstrTag)) == 0 ||
  3052. lstrcmpi(_T("SPAN"), OLE2T(bstrTag)) == 0 ||
  3053. lstrcmpi(_T("TABLE"), OLE2T(bstrTag)) == 0 ||
  3054. lstrcmpi(_T("TEXTAREA"), OLE2T(bstrTag)) == 0 )
  3055. {
  3056. *pfBool = TRUE;
  3057. return S_OK;
  3058. }
  3059. return S_OK;
  3060. }
  3061. ///////////////////////////////////////////////////////////////////////////////
  3062. //
  3063. // CTriEditDocument::SelectElement
  3064. //
  3065. // Select the given element within Trident as a site selection. Return S_OK or
  3066. // a Trident error.
  3067. //
  3068. STDMETHODIMP CTriEditDocument::SelectElement(IHTMLElement* pihtmlElement, IHTMLElement* pihtmlElementParent)
  3069. {
  3070. IHTMLControlElement* picont=NULL;
  3071. IHTMLElement* piParent=NULL;
  3072. IDispatch* pidisp=NULL;
  3073. IHTMLTextContainer* pitext=NULL;
  3074. IHTMLControlRange* pirange=NULL;
  3075. HRESULT hr;
  3076. CComBSTR bstrTag;
  3077. if ( !pihtmlElement || !pihtmlElementParent )
  3078. return E_FAIL;
  3079. hr = pihtmlElement->QueryInterface(IID_IHTMLControlElement, (LPVOID*)&picont);
  3080. if ( FAILED(hr) )
  3081. goto CleanUp;
  3082. _ASSERTE(picont);
  3083. hr = pihtmlElementParent->QueryInterface(IID_IHTMLTextContainer, (LPVOID*)&pitext);
  3084. if ( FAILED(hr) )
  3085. goto CleanUp;
  3086. _ASSERTE(pitext);
  3087. hr = pitext->createControlRange(&pidisp);
  3088. if ( FAILED(hr) )
  3089. goto CleanUp;
  3090. _ASSERTE(pitext);
  3091. hr = pidisp->QueryInterface(IID_IHTMLControlRange, (LPVOID*)&pirange);
  3092. if ( FAILED(hr) )
  3093. goto CleanUp;
  3094. _ASSERTE(pirange);
  3095. hr = pirange->add(picont);
  3096. if ( FAILED(hr) )
  3097. goto CleanUp;
  3098. hr = pirange->select();
  3099. CleanUp:
  3100. SAFERELEASE(picont);
  3101. SAFERELEASE(piParent);
  3102. SAFERELEASE(pidisp);
  3103. SAFERELEASE(pitext);
  3104. SAFERELEASE(pirange);
  3105. return hr;
  3106. }
  3107. ///////////////////////////////////////////////////////////////////////////////
  3108. //
  3109. // CTriEditDocument::IsElementDTC
  3110. //
  3111. // Return S_OK if the given element is a DTC (Design-Time Control) or E_FAIL
  3112. // if not.
  3113. //
  3114. HRESULT CTriEditDocument::IsElementDTC(IHTMLElement *pihtmlElement)
  3115. {
  3116. IHTMLObjectElement *piHTMLObjectElement = NULL;
  3117. IDispatch *pDisp = NULL;
  3118. IActiveDesigner *piActiveDesigner = NULL;
  3119. IUnknown *piUnk = NULL;
  3120. if (SUCCEEDED(pihtmlElement->QueryInterface(IID_IHTMLObjectElement, (void **)&piHTMLObjectElement)) && piHTMLObjectElement)
  3121. {
  3122. if (SUCCEEDED(piHTMLObjectElement->get_object(&pDisp)) && pDisp)
  3123. {
  3124. if (SUCCEEDED(pDisp->QueryInterface(IID_IUnknown, (void **)&piUnk)) && piUnk)
  3125. {
  3126. if (SUCCEEDED(piUnk->QueryInterface(IID_IActiveDesigner, (void **)&piActiveDesigner)) && piActiveDesigner)
  3127. {
  3128. piHTMLObjectElement->Release();
  3129. pDisp->Release();
  3130. piUnk->Release();
  3131. piActiveDesigner->Release();
  3132. return S_OK;
  3133. }
  3134. piUnk->Release();
  3135. }
  3136. pDisp->Release();
  3137. }
  3138. piHTMLObjectElement->Release();
  3139. }
  3140. return E_FAIL;
  3141. }