//***********************************************************************
//
// DriveView.cpp
//
//***********************************************************************
#include <afxwin.h>
#include <afxcview.h>
#include <afxcoll.h>
#include <afxmt.h>
#include "Resource.h"
#include "DriveView.h"
// Image list indexes
#define ILI_HARD_DISK 0
#define ILI_FLOPPY 1
#define ILI_CD_ROM 2
#define ILI_NET_DRIVE 3
#define ILI_RAM_DRIVE 4
#define ILI_CLOSED_FOLDER 5
#define ILI_OPEN_FOLDER 6
IMPLEMENT_DYNCREATE (CDriveView, CTreeView)
BEGIN_MESSAGE_MAP (CDriveView, CTreeView)
ON_WM_DESTROY ()
ON_NOTIFY_REFLECT (TVN_ITEMEXPANDING, OnItemExpanding)
ON_NOTIFY_REFLECT (TVN_SELCHANGED, OnSelChanged)
ON_MESSAGE (WM_USER, OnDriveContentsChanged)
END_MESSAGE_MAP ()
/////////////////////////////////////////////////////////////////////////
// Class constructor
CDriveView::CDriveView () : m_event (FALSE, TRUE)
{
m_nThreadCount = 0;
}
/////////////////////////////////////////////////////////////////////////
// Overridables
BOOL CDriveView::PreCreateWindow (CREATESTRUCT& cs)
{
if (!CTreeView::PreCreateWindow (cs))
return FALSE;
cs.style |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS;
return TRUE;
}
void CDriveView::OnInitialUpdate ()
{
CTreeView::OnInitialUpdate ();
m_imglDrives.Create (IDR_DRIVEIMAGES, 16, 1, RGB (255, 0, 255));
GetTreeCtrl ().SetImageList (&m_imglDrives, TVSIL_NORMAL);
InitTree ();
}
void CDriveView::OnSelectionChanged (CString& strPathName)
{
//
// NOTE: Override this function in a derived class to respond
// to selection changes differently. The default implementation
// calls UpdateAllViews to update other views of the document.
//
GetDocument ()->UpdateAllViews (this,
(LPARAM) (LPCTSTR) strPathName);
}
/////////////////////////////////////////////////////////////////////////
// Message handlers
void CDriveView::OnDestroy ()
{
// Kill all running file change notification threads.
if (m_nThreadCount) {
m_event.SetEvent ();
::WaitForMultipleObjects (m_nThreadCount, m_hThreads, TRUE,
INFINITE);
m_nThreadCount = 0;
}
// Call the base class's OnDestroy handler.
CTreeView::OnDestroy ();
}
void CDriveView::OnItemExpanding (NMHDR* pnmh, LRESULT* pResult)
{
NM_TREEVIEW* pnmtv = (NM_TREEVIEW*) pnmh;
HTREEITEM hItem = pnmtv->itemNew.hItem;
CString strPathName = GetPathFromItem (hItem);
*pResult = FALSE;
// Reset the drive node if the drive is empty or the media changed.
if (!IsMediaValid (strPathName)) {
HTREEITEM hRoot = GetDriveNode (hItem);
GetTreeCtrl ().Expand (hRoot, TVE_COLLAPSE);
DeleteChildren (hRoot);
AddDummyNode (hRoot);
*pResult = TRUE;
return;
}
// Delete the item if strPathName no longer specifies a valid path.
if (!IsPathValid (strPathName)) {
GetTreeCtrl ().DeleteItem (hItem);
*pResult = TRUE;
return;
}
// If the item is expanding, delete the dummy item attached to it
// and add folder items. If the item is collapsing instead, delete
// its folder items and add a dummy item if appropriate.
if (pnmtv->action == TVE_EXPAND) {
DeleteChildren (hItem);
if (!AddDirectoryNodes (hItem, strPathName))
*pResult = TRUE;
}
else {
DeleteChildren (hItem);
if (IsDriveNode (hItem))
AddDummyNode (hItem);
else
SetButtonState (hItem, strPathName);
}
}
void CDriveView::OnSelChanged (NMHDR* pnmh, LRESULT* pResult)
{
HTREEITEM hItem = ((NM_TREEVIEW*) pnmh)->itemNew.hItem;
CString strPathName = GetPathFromItem (hItem);
// Reset the drive node if the drive is empty or the media changed.
if (!IsMediaValid (strPathName)) {
HTREEITEM hRoot = GetDriveNode (hItem);
GetTreeCtrl ().Expand (hRoot, TVE_COLLAPSE);
DeleteChildren (hRoot);
AddDummyNode (hRoot);
return;
}
// Delete the item if strPathName no longer specifies a valid path.
if (!IsPathValid (strPathName)) {
GetTreeCtrl ().DeleteItem (hItem);
return;
}
// Update the item's button state if the item is not expanded.
if (!(GetTreeCtrl ().GetItemState (hItem, TVIS_EXPANDED) &
TVIS_EXPANDED) || !GetTreeCtrl ().ItemHasChildren (hItem))
UpdateButtonState (hItem, strPathName);
// Call the view's virtual OnSelectionChanged function.
OnSelectionChanged (strPathName);
}
LONG CDriveView::OnDriveContentsChanged (UINT wParam, LONG lParam)
{
RefreshDrive ((UINT) wParam);
return 0;
}
/////////////////////////////////////////////////////////////////////////
// Public member functions
void CDriveView::RefreshDrive (UINT nDrive)
{
// Find the HTREEITEM that corresponds to the target drive.
CString strDrive = "?:\\";
strDrive.SetAt (0, 0x41 + nDrive);
HTREEITEM hItem =
FindItem (GetTreeCtrl ().GetNextItem (NULL, TVGN_ROOT),
strDrive);
if (hItem == NULL)
return;
// Reset the drive node if the drive is empty or the media changed.
if (!IsMediaValid (strDrive)) {
GetTreeCtrl ().Expand (hItem, TVE_COLLAPSE);
DeleteChildren (hItem);
AddDummyNode (hItem);
return;
}
// Save the current drive and directory.
char szHome[MAX_PATH];
::GetCurrentDirectory (sizeof (szHome), szHome);
// Change to the root directory of the target drive.
if (!::SetCurrentDirectory ((LPCTSTR) strDrive))
return; // Invalid drive specification
// Refresh the drive node and all displayed subfolders.
if (hItem != NULL)
RefreshDirectory (hItem);
// Return to the original drive and directory.
::SetCurrentDirectory (szHome);
}
CString CDriveView::GetPathFromItem (HTREEITEM hItem)
{
CString strPathName;
while (hItem != NULL) {
CString string = GetTreeCtrl ().GetItemText (hItem);
if ((string.Right (1) != "\\") && !strPathName.IsEmpty ())
string += "\\";
strPathName = string + strPathName;
hItem = GetTreeCtrl ().GetParentItem (hItem);
}
return strPathName;
}
BOOL CDriveView::ExpandPath (LPCTSTR pszPath, BOOL bSelectItem)
{
if (::lstrlen (pszPath) < 3)
return FALSE;
// Begin by finding the corresponding drive node.
CString strPathName = pszPath;
CString strDrive = strPathName.Left (3);
HTREEITEM hItem =
FindItem (GetTreeCtrl ().GetNextItem (NULL, TVGN_ROOT),
strDrive);
if (hItem == NULL)
return FALSE; // Invalid drive specification
strPathName = strPathName.Right (strPathName.GetLength () - 3);
// Now bore down through the directory structure searching for the
// item that corresponds to the final directory name in pszPath.
while (strPathName.GetLength () > 0) {
GetTreeCtrl ().Expand (hItem, TVE_EXPAND);
hItem = GetTreeCtrl ().GetChildItem (hItem);
if (hItem == NULL)
return FALSE;
int nIndex = strPathName.Find ('\\');
hItem = FindItem (hItem, nIndex == -1 ? strPathName :
strPathName.Left (nIndex));
if (hItem == NULL)
return FALSE; // Invalid path name
if (nIndex == -1)
strPathName.Empty ();
else
strPathName = strPathName.Right (strPathName.GetLength () -
nIndex - 1);
}
GetTreeCtrl ().Expand (hItem, TVE_EXPAND);
if (bSelectItem)
GetTreeCtrl ().Select (hItem, TVGN_CARET);
return TRUE;
}
//////////////////////////////////////////////