Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

899 lines
20 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module objmgr.cpp. Object manager implementation | manages a
  5. * collection of OLE embedded objects
  6. *
  7. * Author: alexgo 11/5/95
  8. *
  9. * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
  10. */
  11. #include "_common.h"
  12. #include "_objmgr.h"
  13. #include "_edit.h"
  14. #include "_disp.h"
  15. #include "_select.h"
  16. #include "_rtext.h"
  17. ASSERTDATA
  18. //
  19. // PUBLIC methods
  20. //
  21. /*
  22. * CObjectMgr::GetObjectCount
  23. *
  24. * @mfunc returns the number of embedded objects currently in
  25. * the document.
  26. *
  27. * @rdesc LONG, the count
  28. */
  29. LONG CObjectMgr::GetObjectCount()
  30. {
  31. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetObjectCount");
  32. return _objarray.Count();
  33. }
  34. /*
  35. * CObjectMgr::GetLinkCount()
  36. *
  37. * @mfunc returns the number of embedded objects which are links
  38. *
  39. * @rdesc LONG, the count
  40. */
  41. LONG CObjectMgr::GetLinkCount()
  42. {
  43. LONG count = 0;
  44. COleObject *pobj;
  45. LONG i;
  46. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetLinkCount");
  47. for(i = 0; i < _objarray.Count(); i++)
  48. {
  49. pobj = *_objarray.Elem(i);
  50. if(pobj && pobj->IsLink())
  51. count++;
  52. }
  53. return count;
  54. }
  55. /*
  56. * CObjectMgr::GetObjectFromCp(cp)
  57. *
  58. * @mfunc fetches an object corresponding to the given cp
  59. *
  60. * @rdesc the object @ a cp; NULL if nothing found
  61. *
  62. * @comm the algorithm is a modified binary search. Since the
  63. * "typical" access pattern will be to linearly access the
  64. * objects, we used the cached index to guess first. If
  65. * that doesn't work, we resort to a binary search.
  66. */
  67. COleObject *CObjectMgr::GetObjectFromCp(
  68. LONG cp) //@parm cp for the object
  69. {
  70. COleObject *pobj = NULL;
  71. LONG i = 0;
  72. // No tracing on this method as it's too noisy.
  73. if(_objarray.Count() > 0)
  74. {
  75. if(_lastindex < _objarray.Count())
  76. {
  77. pobj = *_objarray.Elem(_lastindex);
  78. if(pobj && pobj->GetCp() == cp)
  79. return pobj;
  80. }
  81. // The quick lookup failed; try a binary search.
  82. i = FindIndexForCp(cp);
  83. // Because of the insert at end case, i may be equal
  84. // to the count of objects().
  85. pobj = NULL;
  86. if(i < _objarray.Count())
  87. pobj = *_objarray.Elem(i);
  88. }
  89. // FindIndex will return a matching or _near_ index.
  90. // In this case, we only want a matching index
  91. if(pobj)
  92. {
  93. if(pobj->GetCp() != cp)
  94. pobj = NULL;
  95. else
  96. {
  97. // Set the cached index to be the next one,
  98. // so that somebody walking through objects in
  99. // cp order will always get immediate hits.
  100. _lastindex = i + 1;
  101. }
  102. }
  103. #ifdef DEBUG
  104. // Make sure the binary search found the right thing
  105. for( i = 0 ; i < _objarray.Count(); i++ )
  106. {
  107. COleObject *pobj2 = *_objarray.Elem(i);
  108. if( pobj2 )
  109. {
  110. if(*_objarray.Elem(i) == pobj)
  111. {
  112. Assert((*_objarray.Elem(i))->GetCp() == cp);
  113. }
  114. else
  115. Assert((*_objarray.Elem(i))->GetCp() != cp);
  116. }
  117. }
  118. #endif //DEBUG
  119. return pobj;
  120. }
  121. /*
  122. * CObjectMgr::CountObjects (&cObjects, cp)
  123. *
  124. * @mfunc Count char counts upto <p cObjects> objects away The direction of
  125. * counting is determined by the sign of <p cObjects>.
  126. *
  127. * @rdesc Return the signed cch counted and set <p cObjects> to count of
  128. * objects actually counted. If <p cobject> <gt> 0 and cp is at
  129. * the last object, no change is made and 0 is returned.
  130. *
  131. * @devnote This is called from TOM, which uses LONGs for cp's (because VB
  132. * can't use unsigned quantities)
  133. */
  134. LONG CObjectMgr::CountObjects (
  135. LONG& cObjects, //@parm Count of objects to get cch for
  136. LONG cp) //@parm cp to start counting from
  137. {
  138. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::CountObjects");
  139. LONG iStart, iEnd;
  140. LONG iMaxEnd = (LONG)_objarray.Count() - 1;
  141. if(!cObjects || !_objarray.Count())
  142. {
  143. cObjects = 0;
  144. return 0;
  145. }
  146. iStart = (LONG)FindIndexForCp(cp);
  147. // if we are looking past either end, return 0
  148. if (iStart > iMaxEnd && cObjects > 0 ||
  149. iStart == 0 && cObjects < 0 )
  150. {
  151. cObjects = 0;
  152. return 0;
  153. }
  154. // If the index that we found is on an object and
  155. // we are looking forward, it should be skipped.
  156. if( iStart < (LONG)_objarray.Count() &&
  157. (LONG)(*_objarray.Elem(iStart))->GetCp() == cp &&
  158. cObjects > 0)
  159. {
  160. iStart++;
  161. }
  162. if(cObjects < 0)
  163. {
  164. if(-cObjects > iStart) // Going past the beginning
  165. {
  166. iEnd = 0;
  167. cObjects = -iStart;
  168. }
  169. else
  170. iEnd = iStart + cObjects;
  171. }
  172. else
  173. {
  174. if(cObjects > iMaxEnd - iStart) //Going past the end
  175. {
  176. iEnd = iMaxEnd;
  177. cObjects = iMaxEnd - iStart + 1;
  178. }
  179. else
  180. iEnd = iStart + cObjects - 1;
  181. }
  182. Assert(iEnd >= 0 && iEnd < (LONG)_objarray.Count() );
  183. return (*_objarray.Elem(iEnd))->GetCp() - cp;
  184. }
  185. /*
  186. * CObjectMgr::CountObjectsInRange (cpMin, cpMost)
  187. *
  188. * @mfunc Count the number of objects in the given range.
  189. *
  190. * @rdesc Return the number of objects.
  191. */
  192. LONG CObjectMgr::CountObjectsInRange (
  193. LONG cpMin, //@parm Beginning of range
  194. LONG cpMost) //@parm End of range
  195. {
  196. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::CountObjectsInRange");
  197. //Get the indexes for the objects at or after cpMin and cpMost
  198. //respectively.
  199. return FindIndexForCp(cpMost) - FindIndexForCp(cpMin);
  200. }
  201. /*
  202. * CObjectMgr::GetFirstObjectInRange (cpMin, cpMost)
  203. *
  204. * @mfunc Get the first object in the given range.
  205. *
  206. * @rdesc Pointer to first object in range, or NULL if none.
  207. */
  208. COleObject * CObjectMgr::GetFirstObjectInRange (
  209. LONG cpMin, //@parm Beginning of range
  210. LONG cpMost) //@parm End of range
  211. {
  212. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetFirstObjectInRange");
  213. if (cpMin == cpMost)
  214. // degenerate range no object selected
  215. return NULL;
  216. LONG iLast = (LONG)_objarray.Count() - 1; // Index for next object
  217. LONG iObj = FindIndexForCp(cpMin); // at or after cpMin
  218. //Make sure this is an existing object.
  219. if(iObj <= iLast)
  220. {
  221. //Make sure it is within the range
  222. COleObject * pObj = *_objarray.Elem(iObj);
  223. if(pObj && pObj->GetCp() <= cpMost)
  224. return pObj;
  225. }
  226. return NULL;
  227. }
  228. /*
  229. * CObjectMgr::GetObjectFromIndex(index)
  230. *
  231. * @mfunc retrieves the object at the indicated index
  232. *
  233. * @rdesc a pointer to the object, if found, NULL otherwise
  234. */
  235. COleObject *CObjectMgr::GetObjectFromIndex(
  236. LONG index) //@parm Index to use
  237. {
  238. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::GetObjectFromIndex");
  239. if( index < _objarray.Count() )
  240. return *_objarray.Elem(index);
  241. return NULL;
  242. }
  243. /*
  244. * CObjectMgr::InsertObject(prg, preobj, publdr)
  245. *
  246. * @mfunc inserts an object at the indicated index. It is the
  247. * caller's responsibility to handle inserting any data
  248. * (such as WCH_EMBEDDING) into the text stream.
  249. *
  250. * @rdesc HRESULT
  251. */
  252. HRESULT CObjectMgr::InsertObject(
  253. CTxtRange * prg, //@parm Where object is inserted
  254. REOBJECT * preobj, //@parm Object to insert
  255. IUndoBuilder *publdr) //@parm Undo context
  256. {
  257. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::InsertObject");
  258. WCHAR ch = WCH_EMBEDDING;
  259. LONG cp = prg->GetCp();
  260. HRESULT hr;
  261. COleObject *pobj = (COleObject *)(preobj->polesite);
  262. if(preobj->dwFlags & REO_USEASBACKGROUND)
  263. publdr = NULL;
  264. if (prg->ReplaceRange(1, &ch, publdr, SELRR_IGNORE) != 1) // Insert WCH_EMBEDDING
  265. return E_FAIL;
  266. // Let the client know what we're up to
  267. if (_precall)
  268. {
  269. hr = _precall->QueryInsertObject(&preobj->clsid, preobj->pstg,
  270. REO_CP_SELECTION);
  271. if( hr != NOERROR )
  272. return hr;
  273. }
  274. // Set some stuff up first; since we may make outgoing calls, don't
  275. // change our internal state yet.
  276. hr = pobj->InitFromREOBJECT(cp, preobj);
  277. if( hr != NOERROR )
  278. return hr;
  279. hr = RestoreObject(pobj);
  280. if(preobj->dwFlags & REO_USEASBACKGROUND)
  281. {
  282. CTxtEdit *ped = prg->GetPed();
  283. CDocInfo *pDocInfo = ped->GetDocInfo();
  284. HDC hdcBitmap = CreateCompatibleDC(W32->GetScreenDC());
  285. if(hdcBitmap)
  286. {
  287. if(pDocInfo->_nFillType == -1)
  288. {
  289. SIZEUV size;
  290. pobj->GetSize(size);
  291. pDocInfo->_nFillType = 3;
  292. pDocInfo->_xScale = 100;
  293. pDocInfo->_yScale = 100;
  294. pDocInfo->_xExtGoal = TwipsFromHimetric(size.du);
  295. pDocInfo->_yExtGoal = TwipsFromHimetric(size.dv);
  296. }
  297. LONG dxBitmap = ped->_pdp->LXtoDX(pDocInfo->_xExtGoal*pDocInfo->_xScale / 100);
  298. LONG dyBitmap = ped->_pdp->LYtoDY(pDocInfo->_yExtGoal*pDocInfo->_yScale / 100);
  299. RECT rc = {0, 0, dxBitmap, dyBitmap};
  300. HBITMAP hbitmap = CreateCompatibleBitmap(W32->GetScreenDC(), dxBitmap, dyBitmap);
  301. if(hbitmap)
  302. {
  303. HBITMAP hbitmapSave = (HBITMAP)SelectObject(hdcBitmap, hbitmap);
  304. HBRUSH hbrush = CreateSolidBrush(pDocInfo->_crColor);
  305. HBRUSH hbrushOld = (HBRUSH)SelectObject(hdcBitmap, hbrush);
  306. PatBlt(hdcBitmap, 0, 0, dxBitmap, dyBitmap, PATCOPY);
  307. SelectObject(hdcBitmap, hbrushOld);
  308. DeleteObject(hbrush);
  309. OleDraw(pobj->GetIUnknown(), pobj->GetDvaspect(), hdcBitmap, &rc);
  310. if(pDocInfo->_hBitmapBack)
  311. DeleteObject(pDocInfo->_hBitmapBack);
  312. pDocInfo->_hBitmapBack = hbitmap;
  313. SelectObject(hdcBitmap, hbitmapSave);
  314. }
  315. DeleteObject(hdcBitmap);
  316. }
  317. prg->Set(prg->GetCp(), 1);
  318. prg->ReplaceRange(0, NULL, NULL, SELRR_IGNORE, NULL, RR_NO_TRD_CHECK);
  319. }
  320. return hr;
  321. }
  322. /*
  323. * CObjectMgr::RestoreObject(pobj)
  324. *
  325. * @mfunc [re-]inserts the given object into the list of objects
  326. * in the backing store
  327. *
  328. * @rdesc HRESULT
  329. */
  330. HRESULT CObjectMgr::RestoreObject(
  331. COleObject *pobj) //@parm Object to insert
  332. {
  333. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::RestoreObject");
  334. COleObject **ppobj = _objarray.Insert(FindIndexForCp(pobj->GetCp()), 1);
  335. if( ppobj == NULL )
  336. return E_OUTOFMEMORY;
  337. *ppobj = pobj;
  338. pobj->AddRef();
  339. return NOERROR;
  340. }
  341. /*
  342. * CObjectMgr::SetRECallback(precall)
  343. *
  344. * @mfunc sets the callback interface
  345. *
  346. * @rdesc void
  347. */
  348. void CObjectMgr::SetRECallback(
  349. IRichEditOleCallback *precall) //@parm Callback interface pointer
  350. {
  351. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::SetRECallback");
  352. if( _precall )
  353. SafeReleaseAndNULL((IUnknown**)&_precall);
  354. _precall = precall;
  355. if( _precall )
  356. _precall->AddRef();
  357. }
  358. /*
  359. * CObjectMgr::SetHostNames(pszApp, pszDoc)
  360. *
  361. * @mfunc set host names for this edit instance
  362. *
  363. * @rdesc NOERROR or E_OUTOFMEMORY
  364. */
  365. HRESULT CObjectMgr::SetHostNames(
  366. LPWSTR pszApp, //@parm app name
  367. LPWSTR pszDoc) //@parm doc name
  368. {
  369. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::SetHostNames");
  370. HRESULT hr = NOERROR;
  371. if( _pszApp )
  372. {
  373. delete _pszApp;
  374. _pszApp = NULL;
  375. }
  376. if( _pszDoc )
  377. {
  378. delete _pszDoc;
  379. _pszDoc = NULL;
  380. }
  381. if( pszApp )
  382. {
  383. _pszApp = new WCHAR[wcslen(pszApp) + 1];
  384. if( _pszApp )
  385. wcscpy(_pszApp, pszApp);
  386. else
  387. hr = E_OUTOFMEMORY;
  388. }
  389. if( pszDoc )
  390. {
  391. _pszDoc = new WCHAR[wcslen(pszDoc) + 1];
  392. if( _pszDoc )
  393. wcscpy(_pszDoc, pszDoc);
  394. else
  395. hr = E_OUTOFMEMORY;
  396. }
  397. return hr;
  398. }
  399. /*
  400. * CObjectMgr::CObjectMgr
  401. *
  402. * @mfunc constructor
  403. */
  404. CObjectMgr::CObjectMgr()
  405. {
  406. _pobjselect = NULL;
  407. _pobjactive = NULL;
  408. }
  409. /*
  410. * CObjectMgr::~CObjectMgr
  411. *
  412. * @mfunc destructor
  413. */
  414. CObjectMgr::~CObjectMgr()
  415. {
  416. LONG i, count;
  417. COleObject *pobj;
  418. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::~CObjectMgr");
  419. count = _objarray.Count();
  420. for( i = 0; i < count; i++ )
  421. {
  422. pobj = *_objarray.Elem(i);
  423. // We NULL stuff here to try to protect ourselves
  424. // better in re-entrancy cases.
  425. *_objarray.Elem(i) = NULL;
  426. if( pobj )
  427. {
  428. pobj->Close(OLECLOSE_NOSAVE);
  429. pobj->MakeZombie();
  430. SafeReleaseAndNULL((IUnknown**)&pobj);
  431. }
  432. }
  433. if( _precall )
  434. SafeReleaseAndNULL((IUnknown**)&_precall);
  435. if( _pszApp )
  436. delete _pszApp;
  437. if( _pszDoc )
  438. delete _pszDoc;
  439. }
  440. /*
  441. * CObjectMgr::ReplaceRange (cp, cchDel, publdr)
  442. *
  443. * @mfunc handles the deletion of objects from a given range. This
  444. * method _must_ be called before any floating range notifications
  445. * are sent.
  446. */
  447. void CObjectMgr::ReplaceRange(
  448. LONG cp, //@parm cp starting the deletion
  449. LONG cchDel, //@parm Count of characters deleted
  450. IUndoBuilder *publdr) //@parm Undo builder for this actions
  451. {
  452. LONG i;
  453. LONG iDel = -1,
  454. cDel = 0; // index at which to delete && number of objects
  455. // to delete.
  456. COleObject *pobj;
  457. // nothing deleted, don't bother doing anything.
  458. if( !cchDel )
  459. return;
  460. // Basically, we loop through all of the objects within the
  461. // range of deleted text and ask them to delete themselves.
  462. // We remember the range of objects deleted (the starting index
  463. // and # of objects deleted) so that we can remove them from
  464. // the array all at once.
  465. i = FindIndexForCp(cp);
  466. while( i < _objarray.Count() )
  467. {
  468. pobj = *_objarray.Elem(i);
  469. if( pobj && pobj->GetCp() >= cp)
  470. {
  471. if( pobj->GetCp() < (cp + cchDel) )
  472. {
  473. if( _pobjactive == pobj )
  474. {
  475. // Deactivate the object just to be on the safe side.
  476. _pobjactive->DeActivateObj();
  477. _pobjactive = NULL;
  478. }
  479. if(iDel == -1)
  480. iDel = i;
  481. cDel++;
  482. if (_precall)
  483. {
  484. IOleObject *poo;
  485. if (pobj->GetIUnknown()->QueryInterface(IID_IOleObject,
  486. (void **)&poo) == NOERROR)
  487. {
  488. _precall->DeleteObject(poo);
  489. poo->Release();
  490. }
  491. }
  492. // if the object was selected, then it obviously
  493. // can't be anymore!
  494. if( _pobjselect == pobj )
  495. {
  496. _pobjselect = NULL;
  497. }
  498. pobj->Delete(publdr);
  499. *_objarray.Elem(i) = NULL;
  500. pobj->Release();
  501. }
  502. else
  503. break;
  504. }
  505. i++;
  506. }
  507. if(cDel)
  508. _objarray.Remove(iDel, cDel);
  509. return;
  510. }
  511. //
  512. // PRIVATE methods
  513. //
  514. /*
  515. * CObjectMgr::FindIndexForCp(cp)
  516. *
  517. * @mfunc does a binary search to find the index at which an object
  518. * at the given cp exists or should be inserted.
  519. *
  520. * @rdesc LONG, an index
  521. */
  522. LONG CObjectMgr::FindIndexForCp(
  523. LONG cp)
  524. {
  525. LONG l, r;
  526. COleObject *pobj = NULL;
  527. LONG i = 0;
  528. l = 0;
  529. r = _objarray.Count() - 1;
  530. while( r >= l )
  531. {
  532. i = (l + r)/2;
  533. pobj = *_objarray.Elem(i);
  534. if( !pobj )
  535. {
  536. TRACEWARNSZ("null entry in object table. Recovering...");
  537. for( i = 0 ; i < _objarray.Count() -1; i++ )
  538. {
  539. pobj = *_objarray.Elem(i);
  540. if( pobj && pobj->GetCp() >= cp )
  541. return i;
  542. }
  543. return i;
  544. }
  545. if( pobj->GetCp() == cp )
  546. return i;
  547. else if( pobj->GetCp() < cp )
  548. l = i + 1;
  549. else
  550. r = i - 1;
  551. }
  552. // Yikes! nothing was found. Fixup i so that
  553. // it points to the correct index for insertion.
  554. Assert(pobj || (!pobj && i == 0));
  555. if(pobj)
  556. {
  557. Assert(pobj->GetCp() != cp);
  558. if( pobj->GetCp() < cp )
  559. i++;
  560. }
  561. return i;
  562. }
  563. /*
  564. * CObjectMgr::HandleDoubleClick(ped, &pt, flags)
  565. *
  566. * @mfunc Handles a double click message, potentially activating
  567. * an object.
  568. *
  569. * @rdesc BOOL-- TRUE if double click-processing is completely
  570. * finished.
  571. */
  572. BOOL CObjectMgr::HandleDoubleClick(
  573. CTxtEdit *ped, //@parm edit context
  574. const POINTUV &pt,//@parm point of click (WM_LBUTTONDBLCLK wparam)
  575. DWORD flags) //@parm flags (lparam)
  576. {
  577. LONG cp;
  578. COleObject *pobj;
  579. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN,
  580. "CObjectMgr::HandleDoubleClick");
  581. ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE, NULL, NULL, &cp);
  582. pobj = GetObjectFromCp(cp);
  583. if (!pobj)
  584. return FALSE;
  585. if (_pobjactive != pobj)
  586. {
  587. //Deactivate currently active object if any.
  588. if (_pobjactive)
  589. _pobjactive->DeActivateObj();
  590. #ifndef NOINKOBJECT
  591. if (pobj->IsInkObject())
  592. {
  593. if (pobj->_pILineInfo)
  594. {
  595. CTxtSelection * psel = ped->GetSel();
  596. if (psel && psel->GetCch() == 1) // Only handle single Ink object being selected
  597. {
  598. BSTR bstr = NULL;
  599. UINT icch;
  600. HRESULT hr = E_FAIL;
  601. ILineInfo *pLineInfo = pobj->_pILineInfo;
  602. pLineInfo->AddRef();
  603. hr = pLineInfo->TopCandidates(0, &bstr, &icch, 1, 0);
  604. if (SUCCEEDED(hr) && bstr)
  605. psel->TypeText(bstr);
  606. if (bstr)
  607. SysFreeString(bstr);
  608. pLineInfo->Release();
  609. }
  610. }
  611. return TRUE;
  612. }
  613. else
  614. #endif // NOINKOBJECT
  615. {
  616. POINT ptxy;
  617. ped->_pdp->PointFromPointuv(ptxy, pt);
  618. return pobj->ActivateObj(WM_LBUTTONDBLCLK, flags, MAKELONG(ptxy.x, ptxy.y));
  619. }
  620. }
  621. return TRUE;
  622. }
  623. /*
  624. * CObjectMgr::HandleClick(ped, &pt)
  625. *
  626. * @mfunc
  627. * The position of the caret is changing. We need to
  628. * Deactivate the active object, if any. If the change is
  629. * because of a mouse click and there is an object at this
  630. * cp, we set a new individually selected object. Otherwise
  631. * we set the individually selected object to NULL.
  632. *
  633. * @rdesc returns TRUE if this method set the selection. Otherwise,
  634. * returns FALSE;
  635. */
  636. ClickStatus CObjectMgr::HandleClick(
  637. CTxtEdit *ped, //@parm the edit context
  638. const POINTUV &pt)//@parm the point of the mouse click
  639. {
  640. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::HandleClick");
  641. COleObject * pobjnew;//, * pobjold;
  642. CTxtSelection * psel;
  643. LONG cp;
  644. LONG cpMin, cpMost;
  645. if( _pobjactive )
  646. {
  647. _pobjactive->DeActivateObj();
  648. return CLICK_OBJDEACTIVATED;
  649. }
  650. ped->_pdp->CpFromPoint(pt, NULL, NULL, NULL, FALSE, NULL, NULL, &cp);
  651. pobjnew = GetObjectFromCp(cp);
  652. //If we clicked on an object, set the selection to this object.
  653. //CTxtSelection::UpdateSelection will be called as a result of this
  654. //and will determine the highlighting.
  655. if(pobjnew)
  656. {
  657. cp = pobjnew->GetCp();
  658. psel = ped->GetSel();
  659. if (psel->GetRange(cpMin, cpMost) > 1 && cpMin <= cp && cp <= cpMost)
  660. {
  661. // There is more than one character in the selection
  662. // And the object is part of the selection.
  663. // Do not change the selection
  664. return CLICK_SHOULDDRAG;
  665. }
  666. // don't reset the selection if the object is already selected
  667. if( pobjnew != _pobjselect )
  668. {
  669. // Freeze the Display while we handle this click
  670. CFreezeDisplay fd(ped->_pdp);
  671. psel->SetSelection(cp, cp+1);
  672. if (GetSingleSelect())
  673. {
  674. // Note thate the call to SetSelection may have set selected object to NULL !!!!
  675. // This can happen in some strange scenarios where our state is out of whack
  676. AssertSz(GetSingleSelect() == pobjnew, "Object NOT Selected!!");
  677. return CLICK_OBJSELECTED;
  678. }
  679. return CLICK_IGNORED;
  680. }
  681. return CLICK_OBJSELECTED;
  682. }
  683. return CLICK_IGNORED;
  684. }
  685. /*
  686. * CObjectMgr::HandleSingleSelect(ped, cp, fHiLite)
  687. *
  688. * @mfunc
  689. * When an object is selected and it is the only thing selected, we do
  690. * not highlight it by inverting it. We Draw a frame and handles around
  691. * it. This function is called either because an object has been
  692. * selected and it is the only thing selected, or because we need to
  693. * check for an object that used to be in this state but may no longer be.
  694. */
  695. void CObjectMgr::HandleSingleSelect(
  696. CTxtEdit *ped, //@parm edit context
  697. LONG cp, //@parm cp of object
  698. BOOL fHiLite) //@parm is this a call for hding the selection
  699. {
  700. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEINTERN, "CObjectMgr::HandleSingleSelect");
  701. COleObject* pobjnew = GetObjectFromCp(cp);
  702. //This should only be called when we know we have a singley selected
  703. //object. However, there are boundary cases (such as inserting an object)
  704. //where WCH_EMBEDDING is the backing store yet no object exists. These
  705. //cases are OK; thus, we check for NULL on pobjnew.
  706. if(pobjnew)
  707. {
  708. //The object is the same as the currently selected object (if any)
  709. //we are deselecting it. This works like a toggle unless state is messed up.
  710. //If the object is different, we are replacing the current selected
  711. //object (if any).
  712. if(!fHiLite && _pobjselect)
  713. {
  714. // This covers _pobjselct == pobjnew Normal case
  715. // and _pobjselect != pobjnew Degenerate case.
  716. _pobjselect->SetREOSELECTED(FALSE);
  717. _pobjselect = NULL;
  718. //Remove frame/handles from currently selected object.
  719. ped->_pdp->OnPostReplaceRange(CP_INFINITE, 0, 0, cp, cp + 1, NULL);
  720. }
  721. else if(fHiLite && pobjnew != _pobjselect)
  722. {
  723. // Only do this if we are setting a new selection.
  724. _pobjselect = pobjnew;
  725. _pobjselect->SetREOSELECTED(TRUE);
  726. //Draw frame/handles on newly selected object.
  727. ped->_pdp->OnPostReplaceRange(CP_INFINITE, 0, 0, cp, cp + 1, NULL);
  728. }
  729. else
  730. {
  731. // We want to hilite the selection but the object is already selected.
  732. // Or we want to undo hilite on the selection but the selected object is NULL.
  733. // Do nothing.
  734. }
  735. }
  736. }
  737. /*
  738. * CObjectMgr::ActivateObjectsAs (rclsid, rclsidAs)
  739. *
  740. * @mfunc Handles a request by the user to activate all objects of a particular
  741. * class as objects of another class.
  742. *
  743. * @rdesc
  744. * HRESULT Success code.
  745. */
  746. HRESULT CObjectMgr::ActivateObjectsAs(
  747. REFCLSID rclsid,
  748. REFCLSID rclsidAs)
  749. {
  750. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CObjectMgr::ActivateObjectsAs");
  751. COleObject * pobj;
  752. HRESULT hr, hrLatest;
  753. // Tell the system to treat all rclsid objects as rclsidAs
  754. hr = CoTreatAsClass(rclsid, rclsidAs);
  755. if( hr != NOERROR )
  756. return hr;
  757. LONG cobj = GetObjectCount();
  758. // Go through objects, letting them decide if
  759. // they have anything to do for this.
  760. for (LONG iobj = 0; iobj < cobj; iobj++)
  761. {
  762. pobj = GetObjectFromIndex(iobj);
  763. hrLatest = pobj->ActivateAs(rclsid, rclsidAs);
  764. // Make hr the latest hresult unless we have previously had an error.
  765. if(hr == NOERROR)
  766. hr = hrLatest;
  767. }
  768. return hr;
  769. }
  770. #ifdef DEBUG
  771. void CObjectMgr::DbgDump(void)
  772. {
  773. Tracef(TRCSEVNONE, "Object Manager %d objects", _objarray.Count());
  774. for(LONG i = 0 ; i < _objarray.Count(); i++)
  775. {
  776. COleObject *pobj = *_objarray.Elem(i);
  777. if(pobj)
  778. pobj->DbgDump(i);
  779. }
  780. }
  781. #endif