629 lines
15 KiB
C++
629 lines
15 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
|
//
|
|
// File: favorite.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
// favorite.cpp
|
|
|
|
#include "stdafx.h"
|
|
#include "amcdoc.h"
|
|
#include "favorite.h"
|
|
#include "favui.h"
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CFavObject
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
CFavObject::CFavObject(bool bIsGroup)
|
|
: m_pFavParent(NULL), m_pFavNext(NULL), m_pFavChild(NULL), m_bIsGroup(bIsGroup), m_strName(_T("")),
|
|
m_strPath(_T(""))
|
|
{
|
|
}
|
|
|
|
CFavObject::~CFavObject()
|
|
{
|
|
// delete siblings iteratively
|
|
CFavObject* pFavSib = GetNext();
|
|
while(pFavSib)
|
|
{
|
|
CFavObject* pFavNext = pFavSib->GetNext();
|
|
pFavSib->SetNext(NULL);
|
|
|
|
delete pFavSib;
|
|
pFavSib = pFavNext;
|
|
}
|
|
|
|
// delete children recursively
|
|
if (GetChild())
|
|
delete GetChild();
|
|
}
|
|
|
|
|
|
int
|
|
CFavObject::GetImage()
|
|
{
|
|
return ( IsGroup() ? eStockImage_Folder : eStockImage_Favorite);
|
|
}
|
|
|
|
int
|
|
CFavObject::GetOpenImage()
|
|
{
|
|
return ( IsGroup() ? eStockImage_OpenFolder: eStockImage_Favorite);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CFavObject::GetChildCount()
|
|
{
|
|
ASSERT(IsGroup());
|
|
DWORD dwCount = 0;
|
|
CFavObject *pObject = m_pFavChild;
|
|
|
|
while(pObject != NULL)
|
|
{
|
|
dwCount++;
|
|
pObject = pObject->GetNext();
|
|
}
|
|
|
|
return dwCount;
|
|
}
|
|
|
|
void CFavObject::AddChild(CFavObject* pFavNew, CFavObject* pFavPrev)
|
|
{
|
|
ASSERT(IsGroup());
|
|
ASSERT(pFavNew != NULL);
|
|
|
|
// if adding to end, locate last child
|
|
if (pFavPrev == LAST_FAVORITE)
|
|
{
|
|
pFavPrev = GetChild();
|
|
if (pFavPrev != NULL)
|
|
while (pFavPrev->GetNext()) pFavPrev = pFavPrev->GetNext();
|
|
}
|
|
|
|
// if no previous object
|
|
if (pFavPrev == NULL)
|
|
{
|
|
// add as first child
|
|
pFavNew->SetNext(GetChild());
|
|
SetChild(pFavNew);
|
|
}
|
|
else
|
|
{
|
|
// add after previous
|
|
pFavNew->SetNext(pFavPrev->GetNext());
|
|
pFavPrev->SetNext(pFavNew);
|
|
}
|
|
|
|
// always set self as parent
|
|
pFavNew->SetParent(this);
|
|
}
|
|
|
|
void CFavObject::RemoveChild(CFavObject* pFavDelete)
|
|
{
|
|
ASSERT(pFavDelete != NULL);
|
|
ASSERT(pFavDelete->GetParent() == this);
|
|
|
|
if (GetChild() == pFavDelete)
|
|
{
|
|
SetChild(pFavDelete->GetNext());
|
|
}
|
|
else
|
|
{
|
|
CFavObject* pFavPrev = GetChild();
|
|
while(pFavPrev != NULL && pFavPrev->GetNext() != pFavDelete)
|
|
pFavPrev = pFavPrev->GetNext();
|
|
|
|
ASSERT(pFavPrev != NULL);
|
|
pFavPrev->SetNext(pFavDelete->GetNext());
|
|
}
|
|
|
|
pFavDelete->SetNext(NULL);
|
|
}
|
|
|
|
void CFavObject::SetPath(LPCTSTR pszPath)
|
|
{
|
|
// Drop first part of path (because it is always the console root)
|
|
// unless the shortcut is to the root itself
|
|
TCHAR* pSep = _tcschr(pszPath, _T('\\'));
|
|
m_strPath = (pSep != NULL) ? CharNext(pSep) : pszPath;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CFavObject::ReadSerialObject (IStream &stm, UINT nVersion)
|
|
{
|
|
HRESULT hr = S_FALSE; // assume bad version
|
|
|
|
if (nVersion == 1)
|
|
{
|
|
try
|
|
{
|
|
stm >> m_bIsGroup;
|
|
stm >> m_strName;
|
|
|
|
if(IsGroup())
|
|
{
|
|
DWORD cChildren = 0;
|
|
stm >> cChildren;
|
|
|
|
for(int i = 0; i< cChildren; i++)
|
|
{
|
|
CFavObject *pObject = new CFavObject(true); // the true parameter gets overwritten.
|
|
hr = pObject->ReadSerialObject(stm, nVersion);
|
|
if(FAILED(hr))
|
|
{
|
|
delete pObject;
|
|
pObject = NULL;
|
|
return hr;
|
|
}
|
|
|
|
AddChild(pObject);
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
else // is an item
|
|
{
|
|
hr = m_memento.Read(stm);
|
|
stm >> m_strPath;
|
|
}
|
|
}
|
|
catch (_com_error& err)
|
|
{
|
|
hr = err.Error();
|
|
ASSERT (false && "Caught _com_error");
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CFavorites
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
CFavorites::CFavorites() : m_pFavRoot(NULL)
|
|
{
|
|
// create root group
|
|
CString strName;
|
|
LoadString(strName, IDS_FAVORITES);
|
|
|
|
m_pFavRoot = new CFavObject(true /*bIsGroup*/);
|
|
m_pFavRoot->m_strName = strName;
|
|
}
|
|
|
|
|
|
CFavorites::~CFavorites()
|
|
{
|
|
// delete the entire tree
|
|
if (m_pFavRoot != NULL)
|
|
delete m_pFavRoot;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// CTreeSource methods
|
|
|
|
TREEITEMID CFavorites::GetRootItem()
|
|
{
|
|
return TIDFromFavObj(m_pFavRoot);
|
|
}
|
|
|
|
|
|
TREEITEMID CFavorites::GetParentItem(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
return TIDFromFavObj(pFav->GetParent());
|
|
}
|
|
|
|
|
|
TREEITEMID CFavorites::GetChildItem(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
return TIDFromFavObj(pFav->GetChild());
|
|
}
|
|
|
|
|
|
TREEITEMID CFavorites::GetNextSiblingItem(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
return TIDFromFavObj(pFav->GetNext());
|
|
}
|
|
|
|
|
|
LPARAM CFavorites::GetItemParam(TREEITEMID tid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void CFavorites::GetItemName(TREEITEMID tid, LPTSTR pszName, int cchMaxName)
|
|
{
|
|
ASSERT(pszName != NULL);
|
|
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
lstrcpyn(pszName, pFav->GetName(), cchMaxName);
|
|
}
|
|
|
|
void CFavorites::GetItemPath(TREEITEMID tid, LPTSTR pszPath, int cchMaxPath)
|
|
{
|
|
ASSERT(pszPath != NULL);
|
|
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
lstrcpyn(pszPath, pFav->GetPath(), cchMaxPath);
|
|
}
|
|
|
|
int CFavorites::GetItemImage(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
return pFav->GetImage();
|
|
}
|
|
|
|
int CFavorites::GetItemOpenImage(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
return pFav->GetOpenImage();
|
|
}
|
|
|
|
|
|
|
|
BOOL CFavorites::IsFolderItem(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
return pFav->IsGroup();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// CFavorites methods
|
|
|
|
HRESULT CFavorites::AddFavorite(TREEITEMID tidParent, LPCTSTR strName,
|
|
CFavObject** ppFavRet)
|
|
{
|
|
ASSERT(tidParent != NULL && strName != NULL);
|
|
ASSERT(FavObjFromTID(tidParent)->IsGroup());
|
|
|
|
CFavObject* pFavParent = reinterpret_cast<CFavObject*>(tidParent);
|
|
|
|
// Create a favorite item
|
|
CFavObject* pFavItem = new CFavObject(false /*bIsGroup*/);
|
|
if (pFavItem == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pFavItem->m_strName = strName;
|
|
|
|
// Add to end of group
|
|
pFavParent->AddChild(pFavItem);
|
|
|
|
// Notify all observers of addition
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter)
|
|
{
|
|
(*iter)->ItemAdded(TIDFromFavObj(pFavItem));
|
|
}
|
|
|
|
if (ppFavRet)
|
|
*ppFavRet = pFavItem;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CFavorites::AddGroup(TREEITEMID tidParent, LPCTSTR strName, CFavObject** ppFavRet)
|
|
{
|
|
ASSERT(tidParent != NULL && strName != NULL);
|
|
ASSERT(FavObjFromTID(tidParent)->IsGroup());
|
|
|
|
CFavObject* pFavParent = reinterpret_cast<CFavObject*>(tidParent);
|
|
|
|
CFavObject* pFavGrp = new CFavObject(true /*bIsGroup*/);
|
|
if (pFavGrp == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pFavGrp->m_strName = strName;
|
|
|
|
pFavParent->AddChild(pFavGrp);
|
|
|
|
// Notify all observers of addition
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter)
|
|
{
|
|
(*iter)->ItemAdded(TIDFromFavObj(pFavGrp));
|
|
}
|
|
|
|
if (ppFavRet)
|
|
*ppFavRet = pFavGrp;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CFavorites::DeleteItem(TREEITEMID tid)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
|
|
CFavObject* pFavParent = pFav->GetParent();
|
|
|
|
if (pFavParent)
|
|
pFavParent->RemoveChild(pFav);
|
|
else
|
|
m_pFavRoot = NULL;
|
|
|
|
delete pFav;
|
|
|
|
// Notify all observers of deletion
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter)
|
|
{
|
|
(*iter)->ItemRemoved((TREEITEMID)pFavParent, tid);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CFavorites::MoveItem(TREEITEMID tid, TREEITEMID tidNewGroup, TREEITEMID tidPrev)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
CFavObject* pFavPrev = FavObjFromTID(tidPrev);
|
|
|
|
ASSERT(FavObjFromTID(tidNewGroup)->IsGroup());
|
|
CFavObject* pFavNewGroup = reinterpret_cast<CFavObject*>(tidNewGroup);
|
|
|
|
// Verify not moving item into itself or under itself
|
|
CFavObject* pFavTemp = pFavNewGroup;
|
|
while (pFavTemp != NULL)
|
|
{
|
|
if (pFavTemp == pFav)
|
|
return E_FAIL;
|
|
pFavTemp = pFavTemp->GetParent();
|
|
}
|
|
|
|
// Remove object from current group
|
|
CFavObject* pFavParent = pFav->GetParent();
|
|
ASSERT(pFavParent != NULL);
|
|
pFavParent->RemoveChild(pFav);
|
|
|
|
// Notify all observers of removal
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter)
|
|
{
|
|
(*iter)->ItemRemoved((TREEITEMID)pFavParent, tid);
|
|
}
|
|
|
|
// Insert item into the new group
|
|
pFavNewGroup->AddChild(pFav, pFavPrev);
|
|
|
|
// Notify all observers of addition
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter1)
|
|
{
|
|
(*iter1)->ItemAdded(tid);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CFavorites::SetItemName(TREEITEMID tid, LPCTSTR pszName)
|
|
{
|
|
CFavObject* pFav = FavObjFromTID(tid);
|
|
ASSERT(pszName != NULL && pszName[0] != 0);
|
|
|
|
// Change item name
|
|
pFav->m_strName = pszName;
|
|
|
|
// Notify all observers of change
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter)
|
|
{
|
|
(*iter)->ItemChanged(tid, TIA_NAME);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CFavorites::AddToFavorites(LPCTSTR szName, LPCTSTR szPath, CMemento &memento, CWnd* pwndHost)
|
|
{
|
|
DECLARE_SC (sc, _T("CFavorites::AddToFavorites"));
|
|
CAddFavDialog dlg(szName, this, pwndHost);
|
|
|
|
CFavObject* pFavItem = NULL;
|
|
sc = dlg.CreateFavorite(&pFavItem);
|
|
|
|
// Note: S_FALSE is returned if user cancels dialog
|
|
if (sc.ToHr() != S_OK)
|
|
return (sc.ToHr());
|
|
|
|
sc = ScCheckPointers (pFavItem, E_UNEXPECTED);
|
|
if (sc)
|
|
return (sc.ToHr());
|
|
|
|
pFavItem->SetPath(szPath);
|
|
pFavItem->SetMemento(memento);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
CImageList* CFavorites::GetImageList()
|
|
{
|
|
if (m_ImageList != NULL)
|
|
return CImageList::FromHandle (m_ImageList);
|
|
|
|
do
|
|
{
|
|
BOOL bStat = m_ImageList.Create(16, 16, ILC_COLORDDB | ILC_MASK, 20, 10);
|
|
if (!bStat)
|
|
break;
|
|
|
|
CBitmap bmap;
|
|
bStat = bmap.LoadBitmap(IDB_AMC_NODES16);
|
|
if (!bStat)
|
|
break;
|
|
|
|
int ipos = m_ImageList.Add(bmap, RGB(255,0,255));
|
|
if (ipos == -1)
|
|
break;
|
|
}
|
|
while (0);
|
|
|
|
return CImageList::FromHandle (m_ImageList);
|
|
}
|
|
|
|
|
|
HRESULT CFavorites::OrganizeFavorites(CWnd* pwndHost)
|
|
{
|
|
COrganizeFavDialog dlg(this, pwndHost);
|
|
dlg.DoModal();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CFavorites::ReadSerialObject (IStream &stm, UINT nVersion)
|
|
{
|
|
HRESULT hr = m_pFavRoot->ReadSerialObject(stm, nVersion);
|
|
if(FAILED(hr))
|
|
return hr;
|
|
|
|
// Notify all observers of addition
|
|
FOR_EACH_OBSERVER(CTreeObserver, iter)
|
|
{
|
|
(*iter)->ItemRemoved(NULL, TIDFromFavObj(m_pFavRoot));
|
|
(*iter)->ItemAdded(TIDFromFavObj(m_pFavRoot));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
bool
|
|
CFavorites::IsEmpty()
|
|
{
|
|
// the list is empty if the root has no children.
|
|
return (m_pFavRoot->GetChild()==NULL);
|
|
}
|
|
|
|
/*****************************************************************\
|
|
| METHOD: CFavorites::Persist
|
|
| DESCR: Persists favorites, by delegating to root item
|
|
\*****************************************************************/
|
|
void
|
|
CFavorites::Persist(CPersistor &persistor)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CFavorites::Persist"));
|
|
|
|
sc = ScCheckPointers(m_pFavRoot, E_POINTER);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
persistor.Persist(*m_pFavRoot);
|
|
}
|
|
|
|
/*****************************************************************\
|
|
| METHOD: CFavoriteXMLList::PersistItself
|
|
| DESCR: "soft" version of Persist - ignores missing element
|
|
| RETURN: true == element exists and persistence succeeded
|
|
\*****************************************************************/
|
|
bool
|
|
CFavoriteXMLList::PersistItself(CPersistor& persistor)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CFavoriteXMLList::PersistItself"));
|
|
|
|
if (persistor.IsLoading())
|
|
{
|
|
if (!persistor.HasElement(GetXMLType(), NULL))
|
|
return false;
|
|
}
|
|
|
|
persistor.Persist(*this);
|
|
return true;
|
|
}
|
|
|
|
/*****************************************************************\
|
|
| METHOD: CFavoriteXMLList::Persist
|
|
| DESCR: Perists collection (linked list) contents
|
|
\*****************************************************************/
|
|
void
|
|
CFavoriteXMLList::Persist(CPersistor& persistor)
|
|
{
|
|
if (persistor.IsStoring())
|
|
{
|
|
for (CFavObject *pObj = m_rpRoot; pObj; pObj = pObj->GetNext())
|
|
{
|
|
persistor.Persist(*pObj);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(m_rpRoot == NULL); // this is to upload new entries only!!!
|
|
m_rpRoot = NULL;
|
|
XMLListCollectionBase::Persist(persistor);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************\
|
|
| METHOD: CFavoriteXMLList::OnNewElement
|
|
| DESCR: called for every new element when loading
|
|
\*****************************************************************/
|
|
void
|
|
CFavoriteXMLList::OnNewElement(CPersistor& persistor)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CFavoriteXMLList::OnNewElement"));
|
|
|
|
CFavObject **pObj = &m_rpRoot;
|
|
while (*pObj)
|
|
pObj = &(*pObj)->m_pFavNext;
|
|
|
|
CFavObject *pNewObj = new CFavObject(false);
|
|
*pObj = pNewObj;
|
|
|
|
sc = ScCheckPointers(pNewObj, E_OUTOFMEMORY);
|
|
if (sc)
|
|
sc.Throw();
|
|
|
|
pNewObj->SetParent(m_Parent);
|
|
persistor.Persist(*pNewObj);
|
|
}
|
|
|
|
/*****************************************************************\
|
|
| METHOD: CFavObject::Persist
|
|
| DESCR: Persists Favorites item.
|
|
\*****************************************************************/
|
|
void
|
|
CFavObject::Persist(CPersistor &persistor)
|
|
{
|
|
persistor.PersistString(XML_ATTR_NAME, m_strName);
|
|
// persist the type of favorite
|
|
CStr strType(IsGroup() ? XML_VAL_FAVORITE_GROUP : XML_VAL_FAVORITE_SINGLE);
|
|
persistor.PersistAttribute(XML_ATTR_FAVORITE_TYPE, strType);
|
|
m_bIsGroup = (0 == strType.CompareNoCase(XML_VAL_FAVORITE_GROUP));
|
|
|
|
// its either group or memento.
|
|
if (IsGroup())
|
|
{
|
|
CFavoriteXMLList children(m_pFavChild, this);
|
|
children.PersistItself(persistor);
|
|
}
|
|
else // if (!IsGroup())
|
|
{
|
|
persistor.Persist(m_memento);
|
|
}
|
|
}
|