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.

552 lines
14 KiB

  1. //------------------------------------------------------------------------------
  2. // undo.cpp
  3. // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
  4. //
  5. // Undo support routines for TriEdit
  6. //
  7. //------------------------------------------------------------------------------
  8. #include "stdafx.h"
  9. #include <ocidl.h>
  10. #include "undo.h"
  11. #include "triedit.h"
  12. #include "document.h"
  13. ///////////////////////////////////////////////////////////////////////////////
  14. //
  15. // AddUndoUnit
  16. //
  17. // Add the given undo unit to the given Trident instance. Return S_OK
  18. // or a Trident error code.
  19. //
  20. HRESULT AddUndoUnit(IUnknown* punkTrident, IOleUndoUnit* pioleUndoUnit)
  21. {
  22. HRESULT hr = E_FAIL;
  23. IServiceProvider* piservProv;
  24. IOleUndoManager* pioleUndoManager;
  25. if (punkTrident && pioleUndoUnit)
  26. {
  27. hr = punkTrident->QueryInterface(IID_IServiceProvider, (LPVOID*)&piservProv);
  28. if (SUCCEEDED(hr))
  29. {
  30. _ASSERTE(piservProv);
  31. hr = piservProv->QueryService(IID_IOleUndoManager,
  32. IID_IOleUndoManager, (LPVOID*)&pioleUndoManager);
  33. if (SUCCEEDED(hr))
  34. {
  35. _ASSERTE(pioleUndoManager);
  36. hr = pioleUndoManager->Add(pioleUndoUnit);
  37. _ASSERTE(SUCCEEDED(hr));
  38. pioleUndoManager->Release();
  39. }
  40. piservProv->Release();
  41. }
  42. }
  43. return hr;
  44. }
  45. ///////////////////////////////////////////////////////////////////////////////
  46. //
  47. // EmptyUndoRedoStack
  48. //
  49. // If fUndo is TRUE, discard all undo items from the given undo manager.
  50. // If fUndo is FALSE, discard all redo items from the given undo manager
  51. // Return S_OK if all goes well, or a Trident error code otherwise.
  52. //
  53. HRESULT EmptyUndoRedoStack(BOOL fUndo, IOleUndoManager *pUndoManager)
  54. {
  55. CComPtr<IEnumOleUndoUnits> srpEnum;
  56. CComPtr<IOleUndoUnit> srpcd;
  57. ULONG cFetched=0, cTotal=0;
  58. HRESULT hr = E_FAIL;
  59. if (fUndo)
  60. {
  61. if (FAILED(hr = pUndoManager->EnumUndoable(&srpEnum)))
  62. goto Fail;
  63. }
  64. else
  65. {
  66. if (FAILED(hr = pUndoManager->EnumRedoable(&srpEnum)))
  67. goto Fail;
  68. }
  69. while (SUCCEEDED(srpEnum->Next(1, &srpcd, &cFetched)))
  70. {
  71. _ASSERTE(cFetched <=1);
  72. if (srpcd == NULL)
  73. break;
  74. cTotal++;
  75. srpcd.Release();
  76. }
  77. // get the one on top of the stack and discard from that
  78. if (cTotal > 0)
  79. {
  80. if (FAILED(hr = srpEnum->Reset()))
  81. goto Fail;
  82. if (FAILED(hr = srpEnum->Skip(cTotal-1)))
  83. goto Fail;
  84. srpcd.Release();
  85. if (FAILED(hr = srpEnum->Next(1, &srpcd, &cFetched)))
  86. goto Fail;
  87. _ASSERTE(cFetched ==1);
  88. if (FAILED(hr = pUndoManager->DiscardFrom(srpcd)))
  89. goto Fail;
  90. }
  91. Fail:
  92. return hr;
  93. }
  94. ///////////////////////////////////////////////////////////////////////////////
  95. //
  96. // GetUndoManager
  97. //
  98. // Obtain and return (under *ppOleUndoManager) the IOleUndoManager
  99. // associated with the given Trident instance. Return S_OK if a
  100. // manager was returned; E_FAIL otherwise.
  101. //
  102. HRESULT GetUndoManager(IUnknown* punkTrident, IOleUndoManager **ppOleUndoManager)
  103. {
  104. HRESULT hr = E_FAIL;
  105. CComPtr<IServiceProvider> srpiservProv;
  106. CComPtr<IOleUndoManager> srpioleUndoManager;
  107. _ASSERTE(ppOleUndoManager != NULL);
  108. _ASSERTE(punkTrident != NULL);
  109. if (punkTrident)
  110. {
  111. hr = punkTrident->QueryInterface(IID_IServiceProvider, (LPVOID*)&srpiservProv);
  112. if (SUCCEEDED(hr))
  113. {
  114. _ASSERTE(srpiservProv);
  115. if (SUCCEEDED(hr = srpiservProv->QueryService(IID_IOleUndoManager,
  116. IID_IOleUndoManager, (LPVOID*)&srpioleUndoManager)))
  117. {
  118. *ppOleUndoManager = srpioleUndoManager;
  119. (*ppOleUndoManager)->AddRef();
  120. }
  121. }
  122. }
  123. return hr;
  124. }
  125. ///////////////////////////////////////////////////////////////////////////////
  126. //
  127. // CUndo::CUndo
  128. // CUndo::~Undo
  129. //
  130. // Simple constructor and destructor for the CUndo class.
  131. //
  132. CUndo::CUndo()
  133. {
  134. m_cRef = 1;
  135. m_fUndo = TRUE;
  136. }
  137. CUndo::~CUndo()
  138. {
  139. }
  140. ///////////////////////////////////////////////////////////////////////////////
  141. //
  142. // CUndo::QueryInterface (IUnknown method)
  143. // CUndo::AddRef (IUnknown method)
  144. // CUndo::Release (IUnknown method)
  145. //
  146. // Implementations of the three IUnknown methods.
  147. //
  148. STDMETHODIMP CUndo::QueryInterface(REFIID riid, LPVOID* ppvObject)
  149. {
  150. if (!ppvObject)
  151. return E_POINTER;
  152. if (IsEqualGUID(riid, IID_IUnknown))
  153. *ppvObject = (IUnknown*)this;
  154. else
  155. if (IsEqualGUID(riid, IID_IOleUndoUnit))
  156. *ppvObject = (IOleUndoUnit*)this;
  157. else
  158. return E_NOINTERFACE;
  159. AddRef();
  160. return S_OK;
  161. }
  162. STDMETHODIMP_(ULONG) CUndo::AddRef(void)
  163. {
  164. return InterlockedIncrement((LONG*)&m_cRef);
  165. }
  166. STDMETHODIMP_(ULONG) CUndo::Release(void)
  167. {
  168. ULONG cRef = InterlockedDecrement((LONG*)&m_cRef);
  169. if (!cRef)
  170. delete this;
  171. return cRef;
  172. }
  173. ///////////////////////////////////////////////////////////////////////////////
  174. //
  175. // CUndoDrag::CUndoDrag
  176. // CUndoDrag::~CUndoDrag
  177. //
  178. // Constructor for an object which can undo the drag of an HTML element.
  179. //
  180. CUndoDrag::CUndoDrag(IHTMLStyle* pihtmlStyle, POINT ptOrig, POINT ptMove)
  181. {
  182. m_pihtmlStyle = pihtmlStyle;
  183. if (m_pihtmlStyle)
  184. m_pihtmlStyle->AddRef();
  185. m_ptOrig = ptOrig;
  186. m_ptMove = ptMove;
  187. }
  188. CUndoDrag::~CUndoDrag()
  189. {
  190. SAFERELEASE(m_pihtmlStyle);
  191. }
  192. ///////////////////////////////////////////////////////////////////////////////
  193. //
  194. // CUndoDrag::Do (IOleUndoUnit method)
  195. //
  196. // Do or undo dragging of an HTML element from place to place. Set or
  197. // restore the item's position. Return S_OK.
  198. //
  199. STDMETHODIMP CUndoDrag::Do(IOleUndoManager *pUndoManager)
  200. {
  201. HRESULT hr = S_OK;
  202. if (pUndoManager)
  203. {
  204. hr = pUndoManager->Add(this);
  205. }
  206. if (m_pihtmlStyle)
  207. {
  208. // We do a put_pixelLeft(-1) and put_pixelTop(-1) below in order
  209. // to work around a Trident problem. Sometimes they don't think
  210. // that anything has changed - these calls below fool them into
  211. // thinking that the values have changed.
  212. if (m_fUndo)
  213. {
  214. m_pihtmlStyle->put_pixelLeft(-1);
  215. m_pihtmlStyle->put_pixelLeft(m_ptOrig.x);
  216. m_pihtmlStyle->put_pixelTop(-1);
  217. m_pihtmlStyle->put_pixelTop(m_ptOrig.y);
  218. }
  219. else
  220. {
  221. m_pihtmlStyle->put_pixelLeft(-1);
  222. m_pihtmlStyle->put_pixelLeft(m_ptMove.x);
  223. m_pihtmlStyle->put_pixelTop(-1);
  224. m_pihtmlStyle->put_pixelTop(m_ptMove.y);
  225. }
  226. m_fUndo = !m_fUndo;
  227. }
  228. return hr;
  229. }
  230. ///////////////////////////////////////////////////////////////////////////////
  231. //
  232. // CUndoDrag::GetDescription (IOleUndoUnit method)
  233. //
  234. // Return the description of the undo item. Note that this function
  235. // returns an empty string since this is the only would-be localizable
  236. // content in TriEdit.
  237. //
  238. STDMETHODIMP CUndoDrag::GetDescription(BSTR *pBstr)
  239. {
  240. if (pBstr)
  241. {
  242. *pBstr = SysAllocString(_T(" "));
  243. return S_OK;
  244. }
  245. return E_FAIL;
  246. }
  247. ///////////////////////////////////////////////////////////////////////////////
  248. //
  249. // CUndoDrag::GetUnitType (IOleUndoUnit method)
  250. //
  251. // Return the CLSID and an identifier for the undo item.
  252. //
  253. STDMETHODIMP CUndoDrag::GetUnitType(CLSID *pClsid, LONG *plID)
  254. {
  255. if (pClsid)
  256. *pClsid = UID_TRIEDIT_UNDO;
  257. if (plID)
  258. *plID = TRIEDIT_UNDO_DRAG;
  259. return S_OK;
  260. }
  261. ///////////////////////////////////////////////////////////////////////////////
  262. //
  263. // CUndoDrag::OnNextAdd (IOleUndoUnit method)
  264. //
  265. // Do nothing, but do it extremely well.
  266. //
  267. STDMETHODIMP CUndoDrag::OnNextAdd(void)
  268. {
  269. return S_OK;
  270. }
  271. ///////////////////////////////////////////////////////////////////////////////
  272. //
  273. // CUndoPackManager::~CUndoPackManager
  274. //
  275. // Destructor for a CUndoPackManager object. If currently packing undo
  276. // items, end the packing before destroying the object.
  277. //
  278. CUndoPackManager::~CUndoPackManager(void)
  279. {
  280. if (m_fPacking)
  281. End();
  282. }
  283. ///////////////////////////////////////////////////////////////////////////////
  284. //
  285. // CUndoPackManager::Start
  286. //
  287. // Called to tell the pack manager to begin accumulating subsequent
  288. // undo units into a unit that can be undone in one fell swoop. Turn
  289. // on the packing flag. Return S_OK if all goes well or E_FAIL if
  290. // something goes wrong.
  291. //
  292. HRESULT CUndoPackManager::Start(void)
  293. {
  294. HRESULT hr = E_FAIL;
  295. CComPtr<IOleUndoManager> srpioleUndoManager;
  296. CComPtr<IEnumOleUndoUnits> srpEnum;
  297. CComPtr<IOleUndoUnit> srpcd;
  298. ULONG cFetched=0;
  299. _ASSERTE(m_indexStartPacking==0);
  300. if (FAILED(hr = GetUndoManager(m_srpUnkTrident, &srpioleUndoManager)))
  301. goto Fail;
  302. if (FAILED(hr = srpioleUndoManager->EnumUndoable(&srpEnum)))
  303. goto Fail;
  304. while(SUCCEEDED(srpEnum->Next(1, &srpcd, &cFetched)))
  305. {
  306. _ASSERTE(cFetched <=1);
  307. if (srpcd == NULL)
  308. break;
  309. m_indexStartPacking++;
  310. srpcd.Release();
  311. }
  312. m_fPacking = TRUE;
  313. Fail:
  314. if (!m_fPacking)
  315. m_indexStartPacking=0;
  316. return hr;
  317. }
  318. ///////////////////////////////////////////////////////////////////////////////
  319. //
  320. // CUndoPackManager::End
  321. //
  322. // Called to tell the pack manager to stop accumulating undo units. Pack
  323. // the accumulated undo units in to the parent undo unit and turn off
  324. // the packing flag. Return S_OK if all goes well or E_FAIL if something
  325. // goes wrong.
  326. //
  327. HRESULT CUndoPackManager::End(void)
  328. {
  329. HRESULT hr = E_FAIL;
  330. CUndoPackUnit *pUndoParentUnit;
  331. _ASSERTE(m_srpUnkTrident != NULL);
  332. pUndoParentUnit = new CUndoPackUnit();
  333. _ASSERTE(pUndoParentUnit != NULL);
  334. if (FAILED(hr = pUndoParentUnit->PackUndo(m_indexStartPacking, m_srpUnkTrident)))
  335. goto Fail;
  336. m_fPacking = FALSE;
  337. Fail:
  338. pUndoParentUnit->Release();
  339. return hr;
  340. }
  341. ///////////////////////////////////////////////////////////////////////////////
  342. //
  343. // CUndoPackUnit::Do (IOleUndoUnit method)
  344. //
  345. // Invoke the Do method of each undo unit referenced by the object. Return
  346. // S_OK.
  347. //
  348. STDMETHODIMP CUndoPackUnit::Do(IOleUndoManager *pUndoManager)
  349. {
  350. HRESULT hr = S_OK;
  351. for (INT i=sizeof(m_rgUndo)/sizeof(IOleUndoUnit*)-1; i >= 0; i--)
  352. {
  353. if (m_rgUndo[i] == NULL)
  354. continue;
  355. if (FAILED(hr = m_rgUndo[i]->Do(pUndoManager)))
  356. goto Fail;
  357. }
  358. ::EmptyUndoRedoStack(FALSE, pUndoManager);
  359. Fail:
  360. return hr;
  361. }
  362. ///////////////////////////////////////////////////////////////////////////////
  363. //
  364. // CUndoPackUnit::GetDescription (IOleUndoUnit method)
  365. //
  366. // Return the description of the undo item. Note that this function
  367. // returns an empty string since this string would be one of only
  368. // two localizable strings in TriEdit.
  369. //
  370. STDMETHODIMP CUndoPackUnit::GetDescription(BSTR *pBstr)
  371. {
  372. if (pBstr)
  373. {
  374. // In order to save localization work for the two TriEdit strings,
  375. // it was decided that we would return a blank string here
  376. *pBstr = SysAllocString(_T(" "));
  377. return S_OK;
  378. }
  379. return E_FAIL;
  380. }
  381. ///////////////////////////////////////////////////////////////////////////////
  382. //
  383. // CUndoPackUnit::GetUnitType (IOleUndoUnit method)
  384. //
  385. // Return the CLSID and an identifier for the undo item.
  386. //
  387. STDMETHODIMP CUndoPackUnit::GetUnitType(CLSID *pClsid, LONG *plID)
  388. {
  389. if (pClsid)
  390. *pClsid = UID_TRIEDIT_UNDO;
  391. if (plID)
  392. *plID = TRIEDIT_UNDO_PACK;
  393. return S_OK;
  394. }
  395. ///////////////////////////////////////////////////////////////////////////////
  396. //
  397. // CUndoPackUnit::OnNextAdd (IOleUndoUnit method)
  398. //
  399. // Do nothing, but do it extremely well.
  400. //
  401. STDMETHODIMP CUndoPackUnit::OnNextAdd(void)
  402. {
  403. return S_OK;
  404. }
  405. ///////////////////////////////////////////////////////////////////////////////
  406. //
  407. // CUndoPackUnit::PackUndo
  408. //
  409. // Pack all of the undo units starting at the given index in to
  410. // the parent undo manager. Return S_OK if all goes well, or
  411. // E_FAIL if something goes wrong.
  412. //
  413. HRESULT CUndoPackUnit::PackUndo(ULONG indexStartPacking, IUnknown *pUnkTrident)
  414. {
  415. HRESULT hr = E_FAIL;
  416. CComPtr<IOleUndoManager> srpioleUndoManager;
  417. CComPtr<IEnumOleUndoUnits> srpEnumUndo;
  418. CComPtr<IOleUndoUnit> rgUndo[cUndoPackMax]; // CONSIDER: allocate dynamically
  419. CComPtr<IOleUndoUnit> srpcd;
  420. ULONG cFetched=0, cUndo=0, i=0;
  421. if (FAILED(hr = GetUndoManager(pUnkTrident, &srpioleUndoManager)))
  422. goto Fail;
  423. if (FAILED(hr = srpioleUndoManager->EnumUndoable(&srpEnumUndo)))
  424. goto Fail;
  425. _ASSERTE(srpEnumUndo != NULL);
  426. while(SUCCEEDED(srpEnumUndo->Next(1, &srpcd, &cFetched)))
  427. {
  428. _ASSERTE(cFetched <= 1);
  429. if (srpcd == NULL)
  430. break;
  431. cUndo++;
  432. srpcd.Release();
  433. }
  434. // if there's nothing to pack
  435. if ((cUndo-indexStartPacking) == 0)
  436. return S_OK;
  437. if ((cUndo-indexStartPacking) > cUndoPackMax)
  438. return E_OUTOFMEMORY;
  439. // get the undo units that we want to pack
  440. if (FAILED(hr = srpEnumUndo->Reset()))
  441. goto Fail;
  442. if (FAILED(hr =srpEnumUndo->Skip(indexStartPacking)))
  443. goto Fail;
  444. if (FAILED(hr = srpEnumUndo->Next(cUndo-indexStartPacking, (IOleUndoUnit **) &m_rgUndo, &cFetched)))
  445. goto Fail;
  446. _ASSERTE(cFetched == (cUndo-indexStartPacking));
  447. // now clear the undo/redo stack and then adds back the undo unit except that one that we just packed
  448. if (FAILED(hr = srpEnumUndo->Reset()))
  449. goto Fail;
  450. if (FAILED(hr = srpEnumUndo->Next(cUndo, (IOleUndoUnit **) &rgUndo, &cFetched)))
  451. goto Fail;
  452. _ASSERTE(cFetched == cUndo);
  453. if (FAILED(hr = srpioleUndoManager->DiscardFrom(NULL)))
  454. goto Fail;
  455. for (i=0; i < indexStartPacking; i++)
  456. {
  457. if (FAILED(hr = srpioleUndoManager->Add(rgUndo[i])))
  458. goto Fail;
  459. }
  460. if (FAILED(hr = ::AddUndoUnit(pUnkTrident, this)))
  461. goto Fail;
  462. Fail:
  463. return hr;
  464. }