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.

628 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: favorite.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // favorite.cpp
  11. #include "stdafx.h"
  12. #include "amcdoc.h"
  13. #include "favorite.h"
  14. #include "favui.h"
  15. //############################################################################
  16. //############################################################################
  17. //
  18. // Implementation of class CFavObject
  19. //
  20. //############################################################################
  21. //############################################################################
  22. CFavObject::CFavObject(bool bIsGroup)
  23. : m_pFavParent(NULL), m_pFavNext(NULL), m_pFavChild(NULL), m_bIsGroup(bIsGroup), m_strName(_T("")),
  24. m_strPath(_T(""))
  25. {
  26. }
  27. CFavObject::~CFavObject()
  28. {
  29. // delete siblings iteratively
  30. CFavObject* pFavSib = GetNext();
  31. while(pFavSib)
  32. {
  33. CFavObject* pFavNext = pFavSib->GetNext();
  34. pFavSib->SetNext(NULL);
  35. delete pFavSib;
  36. pFavSib = pFavNext;
  37. }
  38. // delete children recursively
  39. if (GetChild())
  40. delete GetChild();
  41. }
  42. int
  43. CFavObject::GetImage()
  44. {
  45. return ( IsGroup() ? eStockImage_Folder : eStockImage_Favorite);
  46. }
  47. int
  48. CFavObject::GetOpenImage()
  49. {
  50. return ( IsGroup() ? eStockImage_OpenFolder: eStockImage_Favorite);
  51. }
  52. DWORD
  53. CFavObject::GetChildCount()
  54. {
  55. ASSERT(IsGroup());
  56. DWORD dwCount = 0;
  57. CFavObject *pObject = m_pFavChild;
  58. while(pObject != NULL)
  59. {
  60. dwCount++;
  61. pObject = pObject->GetNext();
  62. }
  63. return dwCount;
  64. }
  65. void CFavObject::AddChild(CFavObject* pFavNew, CFavObject* pFavPrev)
  66. {
  67. ASSERT(IsGroup());
  68. ASSERT(pFavNew != NULL);
  69. // if adding to end, locate last child
  70. if (pFavPrev == LAST_FAVORITE)
  71. {
  72. pFavPrev = GetChild();
  73. if (pFavPrev != NULL)
  74. while (pFavPrev->GetNext()) pFavPrev = pFavPrev->GetNext();
  75. }
  76. // if no previous object
  77. if (pFavPrev == NULL)
  78. {
  79. // add as first child
  80. pFavNew->SetNext(GetChild());
  81. SetChild(pFavNew);
  82. }
  83. else
  84. {
  85. // add after previous
  86. pFavNew->SetNext(pFavPrev->GetNext());
  87. pFavPrev->SetNext(pFavNew);
  88. }
  89. // always set self as parent
  90. pFavNew->SetParent(this);
  91. }
  92. void CFavObject::RemoveChild(CFavObject* pFavDelete)
  93. {
  94. ASSERT(pFavDelete != NULL);
  95. ASSERT(pFavDelete->GetParent() == this);
  96. if (GetChild() == pFavDelete)
  97. {
  98. SetChild(pFavDelete->GetNext());
  99. }
  100. else
  101. {
  102. CFavObject* pFavPrev = GetChild();
  103. while(pFavPrev != NULL && pFavPrev->GetNext() != pFavDelete)
  104. pFavPrev = pFavPrev->GetNext();
  105. ASSERT(pFavPrev != NULL);
  106. pFavPrev->SetNext(pFavDelete->GetNext());
  107. }
  108. pFavDelete->SetNext(NULL);
  109. }
  110. void CFavObject::SetPath(LPCTSTR pszPath)
  111. {
  112. // Drop first part of path (because it is always the console root)
  113. // unless the shortcut is to the root itself
  114. TCHAR* pSep = _tcschr(pszPath, _T('\\'));
  115. m_strPath = (pSep != NULL) ? CharNext(pSep) : pszPath;
  116. }
  117. HRESULT
  118. CFavObject::ReadSerialObject (IStream &stm, UINT nVersion)
  119. {
  120. HRESULT hr = S_FALSE; // assume bad version
  121. if (nVersion == 1)
  122. {
  123. try
  124. {
  125. stm >> m_bIsGroup;
  126. stm >> m_strName;
  127. if(IsGroup())
  128. {
  129. DWORD cChildren = 0;
  130. stm >> cChildren;
  131. for(int i = 0; i< cChildren; i++)
  132. {
  133. CFavObject *pObject = new CFavObject(true); // the true parameter gets overwritten.
  134. hr = pObject->ReadSerialObject(stm, nVersion);
  135. if(FAILED(hr))
  136. {
  137. delete pObject;
  138. pObject = NULL;
  139. return hr;
  140. }
  141. AddChild(pObject);
  142. }
  143. hr = S_OK;
  144. }
  145. else // is an item
  146. {
  147. hr = m_memento.Read(stm);
  148. stm >> m_strPath;
  149. }
  150. }
  151. catch (_com_error& err)
  152. {
  153. hr = err.Error();
  154. ASSERT (false && "Caught _com_error");
  155. }
  156. }
  157. return hr;
  158. }
  159. //############################################################################
  160. //############################################################################
  161. //
  162. // Implementation of class CFavorites
  163. //
  164. //############################################################################
  165. //############################################################################
  166. CFavorites::CFavorites() : m_pFavRoot(NULL)
  167. {
  168. // create root group
  169. CString strName;
  170. LoadString(strName, IDS_FAVORITES);
  171. m_pFavRoot = new CFavObject(true /*bIsGroup*/);
  172. m_pFavRoot->m_strName = strName;
  173. }
  174. CFavorites::~CFavorites()
  175. {
  176. // delete the entire tree
  177. if (m_pFavRoot != NULL)
  178. delete m_pFavRoot;
  179. }
  180. /////////////////////////////////////////////////////////
  181. // CTreeSource methods
  182. TREEITEMID CFavorites::GetRootItem()
  183. {
  184. return TIDFromFavObj(m_pFavRoot);
  185. }
  186. TREEITEMID CFavorites::GetParentItem(TREEITEMID tid)
  187. {
  188. CFavObject* pFav = FavObjFromTID(tid);
  189. return TIDFromFavObj(pFav->GetParent());
  190. }
  191. TREEITEMID CFavorites::GetChildItem(TREEITEMID tid)
  192. {
  193. CFavObject* pFav = FavObjFromTID(tid);
  194. return TIDFromFavObj(pFav->GetChild());
  195. }
  196. TREEITEMID CFavorites::GetNextSiblingItem(TREEITEMID tid)
  197. {
  198. CFavObject* pFav = FavObjFromTID(tid);
  199. return TIDFromFavObj(pFav->GetNext());
  200. }
  201. LPARAM CFavorites::GetItemParam(TREEITEMID tid)
  202. {
  203. return 0;
  204. }
  205. void CFavorites::GetItemName(TREEITEMID tid, LPTSTR pszName, int cchMaxName)
  206. {
  207. ASSERT(pszName != NULL);
  208. CFavObject* pFav = FavObjFromTID(tid);
  209. lstrcpyn(pszName, pFav->GetName(), cchMaxName);
  210. }
  211. void CFavorites::GetItemPath(TREEITEMID tid, LPTSTR pszPath, int cchMaxPath)
  212. {
  213. ASSERT(pszPath != NULL);
  214. CFavObject* pFav = FavObjFromTID(tid);
  215. lstrcpyn(pszPath, pFav->GetPath(), cchMaxPath);
  216. }
  217. int CFavorites::GetItemImage(TREEITEMID tid)
  218. {
  219. CFavObject* pFav = FavObjFromTID(tid);
  220. return pFav->GetImage();
  221. }
  222. int CFavorites::GetItemOpenImage(TREEITEMID tid)
  223. {
  224. CFavObject* pFav = FavObjFromTID(tid);
  225. return pFav->GetOpenImage();
  226. }
  227. BOOL CFavorites::IsFolderItem(TREEITEMID tid)
  228. {
  229. CFavObject* pFav = FavObjFromTID(tid);
  230. return pFav->IsGroup();
  231. }
  232. ///////////////////////////////////////////////////////////////////////////
  233. // CFavorites methods
  234. HRESULT CFavorites::AddFavorite(TREEITEMID tidParent, LPCTSTR strName,
  235. CFavObject** ppFavRet)
  236. {
  237. ASSERT(tidParent != NULL && strName != NULL);
  238. ASSERT(FavObjFromTID(tidParent)->IsGroup());
  239. CFavObject* pFavParent = reinterpret_cast<CFavObject*>(tidParent);
  240. // Create a favorite item
  241. CFavObject* pFavItem = new CFavObject(false /*bIsGroup*/);
  242. if (pFavItem == NULL)
  243. return E_OUTOFMEMORY;
  244. pFavItem->m_strName = strName;
  245. // Add to end of group
  246. pFavParent->AddChild(pFavItem);
  247. // Notify all observers of addition
  248. FOR_EACH_OBSERVER(CTreeObserver, iter)
  249. {
  250. (*iter)->ItemAdded(TIDFromFavObj(pFavItem));
  251. }
  252. if (ppFavRet)
  253. *ppFavRet = pFavItem;
  254. return S_OK;
  255. }
  256. HRESULT CFavorites::AddGroup(TREEITEMID tidParent, LPCTSTR strName, CFavObject** ppFavRet)
  257. {
  258. ASSERT(tidParent != NULL && strName != NULL);
  259. ASSERT(FavObjFromTID(tidParent)->IsGroup());
  260. CFavObject* pFavParent = reinterpret_cast<CFavObject*>(tidParent);
  261. CFavObject* pFavGrp = new CFavObject(true /*bIsGroup*/);
  262. if (pFavGrp == NULL)
  263. return E_OUTOFMEMORY;
  264. pFavGrp->m_strName = strName;
  265. pFavParent->AddChild(pFavGrp);
  266. // Notify all observers of addition
  267. FOR_EACH_OBSERVER(CTreeObserver, iter)
  268. {
  269. (*iter)->ItemAdded(TIDFromFavObj(pFavGrp));
  270. }
  271. if (ppFavRet)
  272. *ppFavRet = pFavGrp;
  273. return S_OK;
  274. }
  275. HRESULT CFavorites::DeleteItem(TREEITEMID tid)
  276. {
  277. CFavObject* pFav = FavObjFromTID(tid);
  278. CFavObject* pFavParent = pFav->GetParent();
  279. if (pFavParent)
  280. pFavParent->RemoveChild(pFav);
  281. else
  282. m_pFavRoot = NULL;
  283. delete pFav;
  284. // Notify all observers of deletion
  285. FOR_EACH_OBSERVER(CTreeObserver, iter)
  286. {
  287. (*iter)->ItemRemoved((TREEITEMID)pFavParent, tid);
  288. }
  289. return S_OK;
  290. }
  291. HRESULT CFavorites::MoveItem(TREEITEMID tid, TREEITEMID tidNewGroup, TREEITEMID tidPrev)
  292. {
  293. CFavObject* pFav = FavObjFromTID(tid);
  294. CFavObject* pFavPrev = FavObjFromTID(tidPrev);
  295. ASSERT(FavObjFromTID(tidNewGroup)->IsGroup());
  296. CFavObject* pFavNewGroup = reinterpret_cast<CFavObject*>(tidNewGroup);
  297. // Verify not moving item into itself or under itself
  298. CFavObject* pFavTemp = pFavNewGroup;
  299. while (pFavTemp != NULL)
  300. {
  301. if (pFavTemp == pFav)
  302. return E_FAIL;
  303. pFavTemp = pFavTemp->GetParent();
  304. }
  305. // Remove object from current group
  306. CFavObject* pFavParent = pFav->GetParent();
  307. ASSERT(pFavParent != NULL);
  308. pFavParent->RemoveChild(pFav);
  309. // Notify all observers of removal
  310. FOR_EACH_OBSERVER(CTreeObserver, iter)
  311. {
  312. (*iter)->ItemRemoved((TREEITEMID)pFavParent, tid);
  313. }
  314. // Insert item into the new group
  315. pFavNewGroup->AddChild(pFav, pFavPrev);
  316. // Notify all observers of addition
  317. FOR_EACH_OBSERVER(CTreeObserver, iter1)
  318. {
  319. (*iter1)->ItemAdded(tid);
  320. }
  321. return S_OK;
  322. }
  323. HRESULT CFavorites::SetItemName(TREEITEMID tid, LPCTSTR pszName)
  324. {
  325. CFavObject* pFav = FavObjFromTID(tid);
  326. ASSERT(pszName != NULL && pszName[0] != 0);
  327. // Change item name
  328. pFav->m_strName = pszName;
  329. // Notify all observers of change
  330. FOR_EACH_OBSERVER(CTreeObserver, iter)
  331. {
  332. (*iter)->ItemChanged(tid, TIA_NAME);
  333. }
  334. return S_OK;
  335. }
  336. HRESULT CFavorites::AddToFavorites(LPCTSTR szName, LPCTSTR szPath, CMemento &memento, CWnd* pwndHost)
  337. {
  338. DECLARE_SC (sc, _T("CFavorites::AddToFavorites"));
  339. CAddFavDialog dlg(szName, this, pwndHost);
  340. CFavObject* pFavItem = NULL;
  341. sc = dlg.CreateFavorite(&pFavItem);
  342. // Note: S_FALSE is returned if user cancels dialog
  343. if (sc.ToHr() != S_OK)
  344. return (sc.ToHr());
  345. sc = ScCheckPointers (pFavItem, E_UNEXPECTED);
  346. if (sc)
  347. return (sc.ToHr());
  348. pFavItem->SetPath(szPath);
  349. pFavItem->SetMemento(memento);
  350. return S_OK;
  351. }
  352. CImageList* CFavorites::GetImageList()
  353. {
  354. if (m_ImageList != NULL)
  355. return CImageList::FromHandle (m_ImageList);
  356. do
  357. {
  358. BOOL bStat = m_ImageList.Create(16, 16, ILC_COLORDDB | ILC_MASK, 20, 10);
  359. if (!bStat)
  360. break;
  361. CBitmap bmap;
  362. bStat = bmap.LoadBitmap(IDB_AMC_NODES16);
  363. if (!bStat)
  364. break;
  365. int ipos = m_ImageList.Add(bmap, RGB(255,0,255));
  366. if (ipos == -1)
  367. break;
  368. }
  369. while (0);
  370. return CImageList::FromHandle (m_ImageList);
  371. }
  372. HRESULT CFavorites::OrganizeFavorites(CWnd* pwndHost)
  373. {
  374. COrganizeFavDialog dlg(this, pwndHost);
  375. dlg.DoModal();
  376. return S_OK;
  377. }
  378. HRESULT
  379. CFavorites::ReadSerialObject (IStream &stm, UINT nVersion)
  380. {
  381. HRESULT hr = m_pFavRoot->ReadSerialObject(stm, nVersion);
  382. if(FAILED(hr))
  383. return hr;
  384. // Notify all observers of addition
  385. FOR_EACH_OBSERVER(CTreeObserver, iter)
  386. {
  387. (*iter)->ItemRemoved(NULL, TIDFromFavObj(m_pFavRoot));
  388. (*iter)->ItemAdded(TIDFromFavObj(m_pFavRoot));
  389. }
  390. return hr;
  391. }
  392. bool
  393. CFavorites::IsEmpty()
  394. {
  395. // the list is empty if the root has no children.
  396. return (m_pFavRoot->GetChild()==NULL);
  397. }
  398. /*****************************************************************\
  399. | METHOD: CFavorites::Persist
  400. | DESCR: Persists favorites, by delegating to root item
  401. \*****************************************************************/
  402. void
  403. CFavorites::Persist(CPersistor &persistor)
  404. {
  405. DECLARE_SC(sc, TEXT("CFavorites::Persist"));
  406. sc = ScCheckPointers(m_pFavRoot, E_POINTER);
  407. if (sc)
  408. sc.Throw();
  409. persistor.Persist(*m_pFavRoot);
  410. }
  411. /*****************************************************************\
  412. | METHOD: CFavoriteXMLList::PersistItself
  413. | DESCR: "soft" version of Persist - ignores missing element
  414. | RETURN: true == element exists and persistence succeeded
  415. \*****************************************************************/
  416. bool
  417. CFavoriteXMLList::PersistItself(CPersistor& persistor)
  418. {
  419. DECLARE_SC(sc, TEXT("CFavoriteXMLList::PersistItself"));
  420. if (persistor.IsLoading())
  421. {
  422. if (!persistor.HasElement(GetXMLType(), NULL))
  423. return false;
  424. }
  425. persistor.Persist(*this);
  426. return true;
  427. }
  428. /*****************************************************************\
  429. | METHOD: CFavoriteXMLList::Persist
  430. | DESCR: Perists collection (linked list) contents
  431. \*****************************************************************/
  432. void
  433. CFavoriteXMLList::Persist(CPersistor& persistor)
  434. {
  435. if (persistor.IsStoring())
  436. {
  437. for (CFavObject *pObj = m_rpRoot; pObj; pObj = pObj->GetNext())
  438. {
  439. persistor.Persist(*pObj);
  440. }
  441. }
  442. else
  443. {
  444. ASSERT(m_rpRoot == NULL); // this is to upload new entries only!!!
  445. m_rpRoot = NULL;
  446. XMLListCollectionBase::Persist(persistor);
  447. }
  448. }
  449. /*****************************************************************\
  450. | METHOD: CFavoriteXMLList::OnNewElement
  451. | DESCR: called for every new element when loading
  452. \*****************************************************************/
  453. void
  454. CFavoriteXMLList::OnNewElement(CPersistor& persistor)
  455. {
  456. DECLARE_SC(sc, TEXT("CFavoriteXMLList::OnNewElement"));
  457. CFavObject **pObj = &m_rpRoot;
  458. while (*pObj)
  459. pObj = &(*pObj)->m_pFavNext;
  460. CFavObject *pNewObj = new CFavObject(false);
  461. *pObj = pNewObj;
  462. sc = ScCheckPointers(pNewObj, E_OUTOFMEMORY);
  463. if (sc)
  464. sc.Throw();
  465. pNewObj->SetParent(m_Parent);
  466. persistor.Persist(*pNewObj);
  467. }
  468. /*****************************************************************\
  469. | METHOD: CFavObject::Persist
  470. | DESCR: Persists Favorites item.
  471. \*****************************************************************/
  472. void
  473. CFavObject::Persist(CPersistor &persistor)
  474. {
  475. persistor.PersistString(XML_ATTR_NAME, m_strName);
  476. // persist the type of favorite
  477. CStr strType(IsGroup() ? XML_VAL_FAVORITE_GROUP : XML_VAL_FAVORITE_SINGLE);
  478. persistor.PersistAttribute(XML_ATTR_FAVORITE_TYPE, strType);
  479. m_bIsGroup = (0 == strType.CompareNoCase(XML_VAL_FAVORITE_GROUP));
  480. // its either group or memento.
  481. if (IsGroup())
  482. {
  483. CFavoriteXMLList children(m_pFavChild, this);
  484. children.PersistItself(persistor);
  485. }
  486. else // if (!IsGroup())
  487. {
  488. persistor.Persist(m_memento);
  489. }
  490. }