mirror of https://github.com/tongzx/nt5src
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.
631 lines
19 KiB
631 lines
19 KiB
// BrowseDlg.cpp
|
|
// Dialog box to enable user to select a directory and/or files.
|
|
|
|
// Author: t-michkr (June 22, 2000)
|
|
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <shlwapi.h>
|
|
#include <shellapi.h>
|
|
#include <tchar.h>
|
|
#include <assert.h>
|
|
#include "main.h"
|
|
#include "filebrowser.h"
|
|
#include "resource.h"
|
|
|
|
// Display browse dialog box, and return dir string.
|
|
PSTR BrowseForFolder(HWND hwnd, PSTR szInitialPath, UINT uiFlags);
|
|
|
|
// Expand a tree item to include sub items.
|
|
void AddTreeSubItems(HWND hwTree, HTREEITEM hParent);
|
|
|
|
// Remove a tree item's subitems
|
|
void RemoveTreeSubItems(HWND hwTree, HTREEITEM hParent);
|
|
|
|
void CheckTreeSubItems(HWND hwTree, HTREEITEM hChild);
|
|
|
|
// Given a path, select the appropriate item in the tree.
|
|
// If path is invalid, it will expand as much as possible
|
|
// (until invalid element appears)
|
|
void SelectItemFromFullPath(HWND hwTree, PTSTR szPath);
|
|
|
|
// Get full item path. Assumes szPath is a buffer of MAX_PATH size,
|
|
// initialized with '\0'.
|
|
void GetItemPath(HWND hwTree, HTREEITEM hItem, PTSTR szPath);
|
|
|
|
// Browse dialog proc
|
|
BOOL CALLBACK BrowseDialogProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
// Browse dialog box message handlers.
|
|
BOOL HandleInitBrowse(HWND hwnd);
|
|
void HandleBrowseCommand(HWND hwnd, UINT uiCtrlID, UINT uiNotify, HWND hwChild);
|
|
void HandleBrowseNotify(HWND hwnd, void* pvArg);
|
|
|
|
// Buffer to hold returned path
|
|
static TCHAR s_szPathBuffer[MAX_PATH];
|
|
static PTSTR s_szInitialPath = 0;
|
|
static UINT s_uiFlags;
|
|
static HIMAGELIST s_himlSystem = 0;
|
|
|
|
// Create browse dialog box, and return a path string, or
|
|
// NULL if cancel was selected.
|
|
PTSTR BrowseForFolder(HWND hwnd, PTSTR szInitialPath, UINT uiFlags)
|
|
{
|
|
CoInitialize(0);
|
|
|
|
s_szInitialPath = szInitialPath;
|
|
s_uiFlags = uiFlags;
|
|
|
|
PTSTR szRet = reinterpret_cast<TCHAR*>(DialogBox(GetModuleHandle(0),
|
|
MAKEINTRESOURCE(IDD_BROWSE), hwnd, BrowseDialogProc));
|
|
|
|
CoUninitialize();
|
|
return szRet;
|
|
}
|
|
|
|
// Browse dialog box proc.
|
|
BOOL CALLBACK BrowseDialogProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uiMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return HandleInitBrowse(hwnd);
|
|
break;
|
|
case WM_COMMAND:
|
|
HandleBrowseCommand(hwnd, LOWORD(wParam), HIWORD(wParam),
|
|
reinterpret_cast<HWND>(lParam));
|
|
break;
|
|
case WM_NOTIFY:
|
|
HandleBrowseNotify(hwnd, reinterpret_cast<void*>(lParam));
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Dialog box initialization, init tree and root tree items.
|
|
BOOL HandleInitBrowse(HWND hwnd)
|
|
{
|
|
// Get the treeview control
|
|
HWND hwTree = GetDlgItem(hwnd, IDC_DIRTREE);
|
|
if(!hwTree)
|
|
return FALSE;
|
|
|
|
SHFILEINFO sfi;
|
|
|
|
TreeView_SetImageList(hwTree, reinterpret_cast<HIMAGELIST>(SHGetFileInfo(TEXT("C:\\"),
|
|
0,&sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON)),
|
|
TVSIL_NORMAL);
|
|
|
|
// Get all user drives
|
|
DWORD dwLength = GetLogicalDriveStrings(0,0);
|
|
if(dwLength == 0)
|
|
return FALSE;
|
|
|
|
TCHAR* szDrives = new TCHAR[dwLength+1];
|
|
if(!szDrives)
|
|
return FALSE;
|
|
|
|
GetLogicalDriveStrings(dwLength, szDrives);
|
|
TCHAR* szCurrDrive = szDrives;
|
|
|
|
// Go through each drive
|
|
while(*szCurrDrive)
|
|
{
|
|
// Only pay attention to fixed drives (non-network, non-CD, non-floppy)
|
|
if(((GetDriveType(szCurrDrive) == DRIVE_FIXED) && (s_uiFlags & BF_HARDDRIVES))
|
|
|| ((GetDriveType(szCurrDrive) == DRIVE_REMOVABLE) && (s_uiFlags & BF_FLOPPYDRIVES))
|
|
|| ((GetDriveType(szCurrDrive) == DRIVE_CDROM) && (s_uiFlags & BF_CDROMDRIVES))
|
|
|| ((GetDriveType(szCurrDrive) == DRIVE_REMOTE) && (s_uiFlags & BF_NETWORKDRIVES)))
|
|
{
|
|
SHGetFileInfo(szCurrDrive, 0, &sfi, sizeof(sfi),
|
|
SHGFI_SYSICONINDEX);
|
|
|
|
// Get rid of the terminating '\'
|
|
szCurrDrive[lstrlen(szCurrDrive)-1] = TEXT('\0');
|
|
|
|
// Insert a disk drive item into the tree root.
|
|
TVINSERTSTRUCT tvis;
|
|
tvis.hParent = TVI_ROOT;
|
|
tvis.hInsertAfter = TVI_LAST;
|
|
tvis.itemex.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE| TVIF_TEXT;
|
|
tvis.itemex.iImage = sfi.iIcon;
|
|
tvis.itemex.iSelectedImage = sfi.iIcon;
|
|
tvis.itemex.pszText = szCurrDrive;
|
|
tvis.itemex.cchTextMax = lstrlen(szCurrDrive);
|
|
|
|
HTREEITEM hTreeItem = TreeView_InsertItem(hwTree, &tvis);
|
|
|
|
assert(hTreeItem);
|
|
|
|
// Add subitems to the item
|
|
AddTreeSubItems(hwTree, hTreeItem);
|
|
|
|
// Move to next drive
|
|
szCurrDrive += lstrlen(szCurrDrive) + 2;
|
|
}
|
|
else
|
|
// Move to next drive.
|
|
szCurrDrive += lstrlen(szCurrDrive) + 1;
|
|
}
|
|
|
|
delete szDrives;
|
|
|
|
// Select the first element.
|
|
HTREEITEM hItem = TreeView_GetChild(hwTree, TVI_ROOT);
|
|
TreeView_SelectItem(hwTree, hItem);
|
|
|
|
// Force tree to update, and restore original focus
|
|
SetFocus(hwTree);
|
|
SetFocus(GetDlgItem(hwnd, IDOK));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Catch notification messages, so we can control expansion/collapsing.
|
|
void HandleBrowseNotify(HWND hwnd, void* pvArg)
|
|
{
|
|
// Get tree control
|
|
HWND hwTree = GetDlgItem(hwnd, IDC_DIRTREE);
|
|
HWND hwFileList = GetDlgItem(hwnd, IDC_FILELISTCOMBO);
|
|
if(!hwTree || !hwFileList)
|
|
{
|
|
DestroyWindow(GetParent(hwnd));
|
|
return;
|
|
}
|
|
|
|
HTREEITEM hItem;
|
|
TCHAR szPath[MAX_PATH] = TEXT("\0");
|
|
|
|
// Get notification headers
|
|
NMHDR* pHdr = reinterpret_cast<NMHDR*>(pvArg);
|
|
LPNMTREEVIEW pnmTreeView = reinterpret_cast<LPNMTREEVIEW>(pvArg);
|
|
|
|
switch(pHdr->code)
|
|
{
|
|
// Expanding or collapsing, called for each child.
|
|
case TVN_ITEMEXPANDED:
|
|
|
|
// If we're expanding, get the sub items of all children
|
|
if(pnmTreeView->action & TVE_EXPAND)
|
|
{
|
|
// Switch our parent to an open folder icon.
|
|
if(TreeView_GetParent(hwTree, pnmTreeView->itemNew.hItem))
|
|
{
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, pnmTreeView->itemNew.hItem, szPath);
|
|
SHFILEINFO sfi;
|
|
|
|
SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),
|
|
SHGFI_SYSICONINDEX | SHGFI_OPENICON);
|
|
|
|
TVITEMEX tvitemex;
|
|
tvitemex.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE;
|
|
tvitemex.hItem = pnmTreeView->itemNew.hItem;
|
|
tvitemex.iImage = sfi.iIcon;
|
|
tvitemex.iSelectedImage = sfi.iIcon;
|
|
|
|
TreeView_SetItem(hwTree, &tvitemex);
|
|
}
|
|
|
|
// Add all sub-items to this item.
|
|
AddTreeSubItems(hwTree, pnmTreeView->itemNew.hItem);
|
|
|
|
// Go through each child, and and check if expansion should be allowed
|
|
HTREEITEM hChild = TreeView_GetChild(hwTree, pnmTreeView->itemNew.hItem);
|
|
while(hChild != NULL)
|
|
{
|
|
CheckTreeSubItems(hwTree, hChild);
|
|
hChild = TreeView_GetNextSibling(hwTree, hChild);
|
|
}
|
|
}
|
|
else if(pnmTreeView->action & TVE_COLLAPSE)
|
|
{
|
|
// Switch parent to a closed icon.
|
|
if(TreeView_GetParent(hwTree, pnmTreeView->itemNew.hItem))
|
|
{
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, pnmTreeView->itemNew.hItem, szPath);
|
|
SHFILEINFO sfi;
|
|
|
|
SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),
|
|
SHGFI_SYSICONINDEX | SHGFI_OPENICON);
|
|
|
|
TVITEMEX tvitemex;
|
|
tvitemex.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_HANDLE;
|
|
tvitemex.hItem = pnmTreeView->itemNew.hItem;
|
|
tvitemex.iImage = sfi.iIcon;
|
|
tvitemex.iSelectedImage = sfi.iIcon;
|
|
|
|
TreeView_SetItem(hwTree, &tvitemex);
|
|
}
|
|
|
|
// Remove all subitems for every child.
|
|
RemoveTreeSubItems(hwTree, pnmTreeView->itemNew.hItem);
|
|
CheckTreeSubItems(hwTree, pnmTreeView->itemNew.hItem);
|
|
}
|
|
break;
|
|
case TVN_SELCHANGED:
|
|
|
|
// Only bother updating edit box if the tree has the focus
|
|
if(GetFocus() == hwTree)
|
|
{
|
|
GetItemPath(hwTree, pnmTreeView->itemNew.hItem, szPath);
|
|
SetWindowText(hwFileList, szPath);
|
|
}
|
|
|
|
break;
|
|
|
|
// When treeview gains focus, make sure file list and tree view
|
|
// selection are in sync.
|
|
case NM_SETFOCUS:
|
|
hItem = TreeView_GetSelection(hwTree);
|
|
|
|
GetItemPath(hwTree, hItem, szPath);
|
|
SetWindowText(hwFileList, szPath);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Handle a command message.
|
|
void HandleBrowseCommand(HWND hwnd, UINT uiCtrlID, UINT uiNotify, HWND hwCtrl)
|
|
{
|
|
HWND hwTree = GetDlgItem(hwnd, IDC_DIRTREE);
|
|
HTREEITEM hSelected;
|
|
TVITEMEX tvItem;
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
switch(uiCtrlID)
|
|
{
|
|
// Get path of item, and return it.
|
|
case IDOK:
|
|
// Retrieve item from tree view.
|
|
hSelected = TreeView_GetSelection(hwTree);
|
|
if(!hSelected)
|
|
{
|
|
MessageBeep(0);
|
|
break;
|
|
}
|
|
|
|
s_szPathBuffer[0] = TEXT('\0');
|
|
|
|
GetItemPath(hwTree, hSelected, s_szPathBuffer);
|
|
if(s_szPathBuffer[lstrlen(s_szPathBuffer)-1]== TEXT('\\'))
|
|
s_szPathBuffer[lstrlen(s_szPathBuffer)-1] = TEXT('\0');
|
|
|
|
// Validate the path
|
|
if(GetFileAttributes(s_szPathBuffer)==static_cast<DWORD>(-1))
|
|
Error(hwnd, IDS_INVALIDPATH);
|
|
else
|
|
EndDialog(hwnd, reinterpret_cast<INT_PTR>(s_szPathBuffer));
|
|
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
// User selected cancel, just return null.
|
|
EndDialog(hwnd, 0);
|
|
break;
|
|
|
|
case IDC_FILELISTCOMBO:
|
|
switch(uiNotify)
|
|
{
|
|
case CBN_EDITCHANGE:
|
|
SendMessage(hwCtrl, WM_GETTEXT, MAX_PATH,
|
|
reinterpret_cast<LPARAM>(szPath));
|
|
|
|
SelectItemFromFullPath(hwTree, szPath);
|
|
break;
|
|
|
|
case CBN_DROPDOWN:
|
|
// clear the combo box.
|
|
SendMessage(hwCtrl, CB_RESETCONTENT, 0, 0);
|
|
|
|
// Fill the combo box with all the lowest level items under
|
|
// treeview selection
|
|
hSelected = TreeView_GetSelection(hwTree);
|
|
tvItem.mask = TVIF_STATE | TVIF_HANDLE;
|
|
tvItem.hItem = hSelected;
|
|
|
|
TreeView_GetItem(hwTree, &tvItem);
|
|
|
|
if(tvItem.state & TVIS_EXPANDED)
|
|
{
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, hSelected, szPath);
|
|
|
|
SendMessage(hwCtrl, CB_ADDSTRING, 0,
|
|
reinterpret_cast<LPARAM>(szPath));
|
|
|
|
HTREEITEM hItem = TreeView_GetChild(hwTree, tvItem.hItem);
|
|
while(hItem)
|
|
{
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, hItem, szPath);
|
|
SendMessage(hwCtrl, CB_ADDSTRING, 0,
|
|
reinterpret_cast<LPARAM>(szPath));
|
|
hItem = TreeView_GetNextSibling(hwTree, hItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HTREEITEM hItem;
|
|
hItem = TreeView_GetParent(hwTree, tvItem.hItem);
|
|
hItem = TreeView_GetChild(hwTree, hItem);
|
|
|
|
while(hItem)
|
|
{
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, hItem, szPath);
|
|
SendMessage(hwCtrl, CB_ADDSTRING, 0,
|
|
reinterpret_cast<LPARAM>(szPath));
|
|
hItem = TreeView_GetNextSibling(hwTree, hItem);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
break;
|
|
};
|
|
}
|
|
|
|
// Expand an item to get its full path.
|
|
void GetItemPath(HWND hwTree, HTREEITEM hItem, PTSTR szPath)
|
|
{
|
|
assert(hwTree);
|
|
assert(hItem);
|
|
assert(szPath);
|
|
assert(szPath[0] == TEXT('\0'));
|
|
|
|
// Recurse to get parent's path.
|
|
HTREEITEM hParent = TreeView_GetParent(hwTree, hItem);
|
|
if(hParent)
|
|
{
|
|
GetItemPath(hwTree, hParent, szPath);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
}
|
|
|
|
// Get item text, concatenate on current path..
|
|
TVITEMEX tvItem;
|
|
|
|
tvItem.mask = TVIF_TEXT | TVIF_HANDLE;
|
|
tvItem.hItem = hItem;
|
|
tvItem.pszText = szPath + lstrlen(szPath);
|
|
tvItem.cchTextMax = MAX_PATH - lstrlen(szPath);
|
|
|
|
TreeView_GetItem(hwTree, &tvItem);
|
|
}
|
|
|
|
// Remove all subitems below an element.
|
|
void RemoveTreeSubItems(HWND hwTree, HTREEITEM hParent)
|
|
{
|
|
assert(hwTree);
|
|
|
|
// Go through each child and delete.
|
|
HTREEITEM hChild = TreeView_GetChild(hwTree, hParent);
|
|
while(hChild != NULL)
|
|
{
|
|
HTREEITEM hSibling = TreeView_GetNextSibling(hwTree, hChild);
|
|
|
|
// Recursively delete all subitems in this child.
|
|
RemoveTreeSubItems(hwTree, hChild);
|
|
|
|
// Remove this item.
|
|
TreeView_DeleteItem(hwTree, hChild);
|
|
|
|
// Move to next.
|
|
hChild = hSibling;
|
|
}
|
|
}
|
|
|
|
// Add items below an element.
|
|
void AddTreeSubItems(HWND hwTree, HTREEITEM hParent)
|
|
{
|
|
assert(hwTree);
|
|
|
|
// Clear-out (to ensure we don't add items twice)
|
|
RemoveTreeSubItems(hwTree, hParent);
|
|
|
|
// Do an early out if the item has already been expanded
|
|
TVITEMEX tvitem;
|
|
tvitem.mask = TVIF_CHILDREN | TVIF_HANDLE;
|
|
tvitem.hItem = hParent;
|
|
TreeView_GetItem(hwTree, &tvitem);
|
|
if(tvitem.cChildren)
|
|
return;
|
|
|
|
// Do a search on all directories
|
|
TCHAR szPath[MAX_PATH] = TEXT("");
|
|
GetItemPath(hwTree, hParent, szPath);
|
|
|
|
WIN32_FIND_DATA findData;
|
|
|
|
lstrcat(szPath, TEXT("\\*.*"));
|
|
|
|
HANDLE hSearch = FindFirstFile(szPath, &findData);
|
|
if(hSearch == INVALID_HANDLE_VALUE)
|
|
return;
|
|
|
|
do
|
|
{
|
|
// Ignore if a relative directory (. or ..)
|
|
// or if no select files were selected and it is not a directory
|
|
// otherwise
|
|
if((findData.cFileName[0] != TEXT('.')) &&
|
|
((!(s_uiFlags & BF_SELECTFILES) &&
|
|
(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) ||
|
|
(s_uiFlags & BF_SELECTFILES)))
|
|
{
|
|
SHFILEINFO sfi;
|
|
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, hParent, szPath);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
lstrcat(szPath, findData.cFileName);
|
|
SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),
|
|
SHGFI_SYSICONINDEX);
|
|
|
|
// Insert an item representing this directory.
|
|
TVINSERTSTRUCT tvis;
|
|
tvis.hParent = hParent;
|
|
tvis.hInsertAfter = TVI_SORT;
|
|
tvis.itemex.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
|
|
tvis.itemex.iImage = sfi.iIcon;
|
|
tvis.itemex.iSelectedImage = sfi.iIcon;
|
|
tvis.itemex.pszText = findData.cFileName;
|
|
tvis.itemex.cchTextMax = lstrlen(findData.cFileName);
|
|
|
|
TreeView_InsertItem(hwTree, &tvis);
|
|
}
|
|
|
|
// Move to next file.
|
|
} while(FindNextFile(hSearch, &findData));
|
|
|
|
FindClose(hSearch);
|
|
}
|
|
|
|
void CheckTreeSubItems(HWND hwTree, HTREEITEM hParent)
|
|
{
|
|
assert(hwTree);
|
|
|
|
// Do a search on all directories
|
|
TCHAR szPath[MAX_PATH] = TEXT("");
|
|
GetItemPath(hwTree, hParent, szPath);
|
|
|
|
WIN32_FIND_DATA findData;
|
|
|
|
lstrcat(szPath, TEXT("\\*.*"));
|
|
|
|
HANDLE hSearch = FindFirstFile(szPath, &findData);
|
|
if(hSearch == INVALID_HANDLE_VALUE)
|
|
return;
|
|
|
|
do
|
|
{
|
|
// Ignore if a relative directory (. or ..)
|
|
// or if no select files were selected and it is not a directory
|
|
// otherwise
|
|
if((findData.cFileName[0] != TEXT('.')) &&
|
|
((!(s_uiFlags & BF_SELECTFILES) &&
|
|
(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) ||
|
|
(s_uiFlags & BF_SELECTFILES)))
|
|
{
|
|
SHFILEINFO sfi;
|
|
|
|
szPath[0] = TEXT('\0');
|
|
GetItemPath(hwTree, hParent, szPath);
|
|
lstrcat(szPath, TEXT("\\"));
|
|
lstrcat(szPath, findData.cFileName);
|
|
SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),
|
|
SHGFI_SYSICONINDEX);
|
|
|
|
// Insert an item representing this directory.
|
|
TVINSERTSTRUCT tvis;
|
|
tvis.hParent = hParent;
|
|
tvis.hInsertAfter = TVI_SORT;
|
|
tvis.itemex.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
|
|
tvis.itemex.iImage = sfi.iIcon;
|
|
tvis.itemex.iSelectedImage = sfi.iIcon;
|
|
tvis.itemex.pszText = findData.cFileName;
|
|
tvis.itemex.cchTextMax = lstrlen(findData.cFileName);
|
|
|
|
TreeView_InsertItem(hwTree, &tvis);
|
|
|
|
FindClose(hSearch);
|
|
return;
|
|
}
|
|
|
|
// Move to next file.
|
|
} while(FindNextFile(hSearch, &findData));
|
|
|
|
FindClose(hSearch);
|
|
}
|
|
|
|
// Given a relative path and a tree item, select a subitem from the relative path.
|
|
// Returns true if item successfully selected, false otherwise.
|
|
bool SelectSubitemFromPartialPath(HWND hwTree, HTREEITEM hItem, PTSTR szPath)
|
|
{
|
|
bool fExpandIt = false;
|
|
TCHAR* szPathDelim = _tcschr(szPath, TEXT('\\'));
|
|
|
|
if(szPathDelim)
|
|
{
|
|
if(szPathDelim == szPath)
|
|
return false;
|
|
*szPathDelim = TEXT('\0');
|
|
if(szPathDelim[1] == TEXT('\0'))
|
|
{
|
|
szPathDelim = 0;
|
|
fExpandIt = true;
|
|
}
|
|
}
|
|
|
|
// Find this path.
|
|
HTREEITEM hClosestChild = 0;
|
|
HTREEITEM hChild = TreeView_GetChild(hwTree, hItem);
|
|
while(hChild)
|
|
{
|
|
TCHAR szItemPath[MAX_PATH];
|
|
|
|
TVITEMEX tvitem;
|
|
tvitem.mask = TVIF_HANDLE | TVIF_TEXT;
|
|
tvitem.hItem = hChild;
|
|
tvitem.pszText = szItemPath;
|
|
tvitem.cchTextMax = MAX_PATH;
|
|
|
|
TreeView_GetItem(hwTree, &tvitem);
|
|
|
|
if(lstrcmpi(szPath,tvitem.pszText) == 0)
|
|
break;
|
|
else if((StrStrI(tvitem.pszText, szPath) == tvitem.pszText) && !fExpandIt)
|
|
{
|
|
hClosestChild = hChild;
|
|
break;
|
|
}
|
|
|
|
hChild = TreeView_GetNextSibling(hwTree, hChild);
|
|
}
|
|
|
|
if(!hChild)
|
|
{
|
|
if(!hClosestChild)
|
|
return false;
|
|
else
|
|
{
|
|
hChild = hClosestChild;
|
|
szPathDelim = 0;
|
|
}
|
|
}
|
|
|
|
// If nothing more on the path, select this item,
|
|
// or expand and continue
|
|
if(szPathDelim == 0)
|
|
{
|
|
if(fExpandIt)
|
|
TreeView_Expand(hwTree, hChild, TVE_EXPAND);
|
|
|
|
TreeView_SelectItem(hwTree, hChild);
|
|
}
|
|
else
|
|
{
|
|
if(fExpandIt)
|
|
TreeView_Expand(hwTree, hChild, TVE_EXPAND);
|
|
|
|
if(!SelectSubitemFromPartialPath(hwTree, hChild, szPathDelim+1))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Given a path, select the appropriate item in the tree.
|
|
// If path is invalid, it will expand as much as possible
|
|
// (until invalid element appears)
|
|
// szPath is trashed.
|
|
void SelectItemFromFullPath(HWND hwTree, PTSTR szPath)
|
|
{
|
|
if(!SelectSubitemFromPartialPath(hwTree, 0, szPath))
|
|
TreeView_SelectItem(hwTree, 0);
|
|
}
|