windows-nt/Source/XPSP1/NT/sdktools/winobj/wftree.c
2020-09-26 16:20:57 +08:00

759 lines
22 KiB
C

/****************************************************************************/
/* */
/* WFTREE.C - */
/* */
/* Windows File System Tree Window Proc Routines */
/* */
/****************************************************************************/
#include "winfile.h"
#include "winnet.h"
#include "lfn.h"
#include "wfcopy.h"
HICON GetTreeIcon(HWND hWnd);
VOID APIENTRY CheckEscapes(LPSTR);
HICON
GetTreeIcon(
HWND hWnd
)
{
HWND hwndTree, hwndDir;
hwndTree = HasTreeWindow(hWnd);
hwndDir = HasDirWindow(hWnd);
if (hwndTree && hwndDir)
return hicoTreeDir;
else if (hwndTree)
return hicoTree;
else
return hicoDir;
}
VOID
APIENTRY
GetTreeWindows(
HWND hwnd,
PHWND phwndTree,
PHWND phwndDir,
PHWND phwndDrives
)
{
if (phwndTree) {
*phwndTree = GetDlgItem(hwnd, IDCW_TREECONTROL);
}
if (phwndDir) {
*phwndDir = GetDlgItem(hwnd, IDCW_DIR);
}
if (phwndDrives) {
*phwndDrives = GetDlgItem(hwnd, IDCW_DRIVES);
}
}
// returns hwndTree, hwndDir or hwndDrives depending on the focus tracking
// for the window. if none is found we return NULL
HWND
APIENTRY
GetTreeFocus(
HWND hwndTree
)
{
HWND hwnd, hwndLast = NULL;
hwndLast = hwnd = (HWND)GetWindowLongPtr(hwndTree, GWLP_LASTFOCUS);
while (hwnd && hwnd != hwndTree) {
hwndLast = hwnd;
hwnd = GetParent(hwnd);
}
return hwndLast;
}
/*--------------------------------------------------------------------------*/
/* */
/* CompactPath() - */
/* */
/*--------------------------------------------------------------------------*/
BOOL
APIENTRY
CompactPath(
HDC hDC,
LPSTR lpszPath,
WORD dx
)
{
register INT len;
INT dxFixed, dxT;
LPSTR lpEnd; /* end of the unfixed string */
LPSTR lpFixed; /* start of text that we always display */
BOOL bEllipsesIn;
CHAR szTemp[MAXPATHLEN];
/* Does it already fit? */
MGetTextExtent(hDC, lpszPath, lstrlen(lpszPath), &dxFixed, NULL);
if (dxFixed <= (INT)dx)
return(TRUE);
/* Search backwards for the '\', and man, it better be there! */
lpFixed = lpszPath + lstrlen(lpszPath);
while (*lpFixed != '\\')
lpFixed = AnsiPrev(lpszPath, lpFixed);
/* Save this guy to prevent overlap. */
lstrcpy(szTemp, lpFixed);
lpEnd = lpFixed;
bEllipsesIn = FALSE;
MGetTextExtent(hDC, lpFixed, lstrlen(lpFixed), &dxFixed, NULL);
while (TRUE) {
MGetTextExtent(hDC, lpszPath, (int)(lpEnd - lpszPath), &dxT, NULL);
len = dxFixed + dxT;
if (bEllipsesIn)
len += dxEllipses;
if (len <= (INT)dx)
break;
bEllipsesIn = TRUE;
if (lpEnd <= lpszPath) {
/* Things didn't fit. */
lstrcpy(lpszPath, szEllipses);
lstrcat(lpszPath, szTemp);
return(FALSE);
}
/* Step back a character. */
lpEnd = AnsiPrev(lpszPath, lpEnd);
}
if (bEllipsesIn) {
lstrcpy(lpEnd, szEllipses);
lstrcat(lpEnd, szTemp);
}
return(TRUE);
}
//
// BOOL APIENTRY ResizeSplit(HWND hWnd, int dxSplit)
//
// creates/resizes children of the MDI child for the given path or resizes
// (perhaps creating and destroying) these guys based on the dxSplit
// parameter
//
// in:
// hWnd window to fiddle with
// dxSpit location of split between tree and dir panes
// if less than size limit no tree is created
// (current is destroyed)
// if past limit on right margin the dir window
// is destroyed (or not created)
//
// returns:
// TRUE success, windows created
// FALSE failure, windows failed creation, out of mem, or
// the tree was in a state the couldn't be resized
//
BOOL
APIENTRY
ResizeSplit(
HWND hWnd,
INT dxSplit
)
{
RECT rc;
HWND hwndTree, hwndDir, hwndDrives, hwndLB;
DWORD dwTemp;
GetTreeWindows(hWnd, &hwndTree, &hwndDir, &hwndDrives);
if (hwndTree && GetWindowLong(hwndTree, GWL_READLEVEL))
return FALSE;
GetClientRect(hWnd, &rc);
// create the drives
if (!hwndDrives) {
// make new drives window
hwndDrives = CreateWindowEx(0, szDrivesClass, NULL,
WS_CHILD | WS_VISIBLE,
0, 0, 0, 0,
hWnd, (HMENU)IDCW_DRIVES,
hAppInstance, NULL);
if (!hwndDrives)
return FALSE;
}
if (dxSplit > dxDriveBitmap * 2) {
if (!hwndTree) { // make new tree window
hwndTree = CreateWindowEx(0, szTreeControlClass,
NULL, WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hWnd, (HMENU)IDCW_TREECONTROL,
hAppInstance, NULL);
if (!hwndTree)
return FALSE;
// only reset this if the dir window already
// exists, that is we are creating the tree
// by splitting open a dir window
if (hwndDir)
SendMessage(hwndTree, TC_SETDRIVE, MAKEWORD(FALSE, 0), 0L);
}
} else if (hwndTree) { // we are closing the tree window
// If the directory window is empty, then set the focus to the
// drives window.
if (hwndDir) {
hwndLB = GetDlgItem (hwndDir,IDCW_LISTBOX);
if (hwndLB) {
SendMessage (hwndLB,LB_GETTEXT,0,(LPARAM)(LPSTR) &dwTemp);
if (!dwTemp)
SetFocus (hwndDrives);
}
}
DestroyWindow(hwndTree);
dxSplit = 0;
}
if ((rc.right - dxSplit) > dxDriveBitmap * 2) {
if (!hwndDir) {
hwndDir = CreateWindowEx(0, szDirClass, NULL,
WS_CHILD | WS_VISIBLE,
0, 0, 0, 0,
hWnd,(HMENU)IDCW_DIR,
hAppInstance, NULL);
if (!hwndDir)
return FALSE;
}
} else if (hwndDir) {
DestroyWindow(hwndDir);
dxSplit = rc.right;
}
UpdateStatus(hWnd);
SetWindowLong(hWnd, GWL_SPLIT, dxSplit);
return TRUE;
}
/*--------------------------------------------------------------------------*/
/* */
/* TreeWndProc() - */
/* */
/*--------------------------------------------------------------------------*/
/* WndProc for the MDI child window containing the drives, volume, and
* directory tree child windows.
*/
INT_PTR
APIENTRY
TreeWndProc(
HWND hWnd,
UINT wMsg,
WPARAM wParam,
LPARAM lParam
)
{
HWND hwndTree, hwndDir, hwndDrives, hwndFocus;
CHAR szDir[MAXPATHLEN];
RECT rc;
HDC hdc;
STKCHK();
switch (wMsg) {
case WM_FILESYSCHANGE:
MSG("TreeWndProc", "WM_FILESYSCHANGE");
if (hwndDir = HasDirWindow(hWnd))
SendMessage(hwndDir, wMsg, wParam, lParam);
break;
case FS_CHANGEDRIVES:
MSG("TreeWndProc", "FS_CHANGEDRIVES");
{
INT iNewDrive;
if (!(hwndDrives = GetDlgItem(hWnd, IDCW_DRIVES)))
break;
DestroyWindow(hwndDrives);
// see if this drive has gone, if so set this to the
// last drive in the list
iNewDrive = -1;
if (!IsValidDisk((INT)GetWindowLong(hWnd, GWL_TYPE))) {
iNewDrive = rgiDrive[cDrives - 1];
SetWindowLong(hWnd, GWL_TYPE, iNewDrive);
}
hwndDrives = CreateWindowEx(0, szDrivesClass, NULL,
WS_CHILD | WS_VISIBLE,
0, 0, 0, 0,
hWnd, (HMENU)IDCW_DRIVES,
hAppInstance,
NULL);
if (!hwndDrives)
return -1L;
// Don't show the new stuff if the tree window is iconic
if (IsIconic(hWnd))
break;
/* HACK! Send SIZENOMDICRAP in the wParam of the size message.
* This will re-compute the sizes of all three areas of
* the tree window (in case the drive section grows or
* shrinks) and not pass it the size message on to the
* DefMDIChildProc() */
GetClientRect(hWnd, &rc);
SendMessage(hWnd, WM_SIZE, SIZENOMDICRAP, MAKELONG(rc.right, rc.bottom));
// refresh the tree if necessary
if (iNewDrive >= 0) {
GetSelectedDirectory((WORD)(iNewDrive+1), szDir);
SendMessage(GetDlgItem(hWnd, IDCW_TREECONTROL),
TC_SETDRIVE, MAKEWORD(FALSE, 0), (LPARAM)szDir);
}
break;
}
case FS_GETSELECTION:
{
#define pfDir (BOOL *)lParam
LPSTR p;
MSG("TreeWndProc", "FS_GETSELECTION");
GetTreeWindows(hWnd, &hwndTree, &hwndDir, &hwndDrives);
hwndFocus = GetTreeFocus(hWnd);
if (hwndFocus == hwndDir || !hwndTree) {
return SendMessage(hwndDir, FS_GETSELECTION, wParam, lParam);
} else {
p = (LPSTR)LocalAlloc(LPTR, MAXPATHLEN);
if (p) {
SendMessage(hWnd, FS_GETDIRECTORY, MAXPATHLEN, (LPARAM)p);
StripBackslash(p);
CheckEscapes(p);
if (wParam == 2) { // BUG ??? wParam should be fMostRecentOnly
if (pfDir) {
*pfDir = IsLFN(p);
}
LocalFree((HANDLE)p);
return (INT_PTR)p;
}
}
if (pfDir) {
*pfDir = TRUE;
}
return (INT_PTR)p;
}
#undef pfDir
}
case FS_GETDIRECTORY:
MSG("TreeWndProc", "FS_GETDIRECTORY");
// wParam is the length of the string pointed to by lParam
// returns in lParam ANSI directory string with
// a trailing backslash. if you want to do a SetCurrentDirecotor()
// you must first StripBackslash() the thing!
GetMDIWindowText(hWnd, (LPSTR)lParam, (INT)wParam); // get the string
StripFilespec((LPSTR)lParam); // Remove the trailing extention
AddBackslash((LPSTR)lParam); // terminate with a backslash
break;
case FS_GETFILESPEC:
MSG("TreeWndProc", "FS_GETFILESPEC");
// returns the current filespec (from View.Include...). this is
// an uppercase ANSI string
GetMDIWindowText(hWnd, (LPSTR)lParam, (INT)wParam);
StripPath((LPSTR)lParam);
break;
// redirect these messages to the drive icons to get the same result as
// dropping on the active drive.
// this is especially useful when we are minimized
case WM_DRAGSELECT:
case WM_QUERYDROPOBJECT:
case WM_DROPOBJECT:
MSG("TreeWndProc", "WM..OBJECT");
// Do nothing
return(TRUE);
if (hwndDrives = HasDrivesWindow(hWnd)) {
return SendMessage(hwndDrives, wMsg, wParam, lParam);
}
if (hwndDir = HasDirWindow(hWnd)) {
return SendMessage(hwndDir, wMsg, wParam, lParam);
}
break;
case FS_GETDRIVE:
MSG("TreeWndProc", "FS_GETDRIVE");
GetTreeWindows(hWnd, &hwndTree, &hwndDir, NULL);
if (hwndTree)
return SendMessage(hwndTree, wMsg, wParam, lParam);
else
return SendMessage(hwndDir, wMsg, wParam, lParam);
break;
case WM_CREATE:
TRACE(BF_WM_CREATE, "TreeWndProc - WM_CREATE");
{
INT dxSplit;
WORD wDrive;
// lpcs->lpszName is the path we are opening the
// window for (has extension stuff "*.*")
#define lpcs ((LPCREATESTRUCT)lParam)
#define lpmdics ((LPMDICREATESTRUCT)(lpcs->lpCreateParams))
wDrive = lpcs->lpszName[0];
if (wDrive >= 'a')
wDrive -= 'a';
else
wDrive -= 'A';
SetWindowLong(hWnd, GWL_TYPE, wDrive);
dxSplit = (SHORT)LOWORD(lpmdics->lParam);
// if dxSplit is negative we split in the middle
if (dxSplit < 0)
dxSplit = lpcs->cx / 2;
SetWindowLong(hWnd, GWL_SPLIT, dxSplit);
SetWindowLongPtr(hWnd, GWLP_LASTFOCUS, 0);
SetWindowLong(hWnd, GWL_FSCFLAG, FALSE);
if (!ResizeSplit(hWnd, dxSplit))
return -1;
GetTreeWindows(hWnd, &hwndTree, &hwndDir, NULL);
SetWindowLongPtr(hWnd, GWLP_LASTFOCUS, (LONG_PTR)(hwndTree ? hwndTree : hwndDir));
break;
}
case WM_CLOSE:
MSG("TreeWndProc", "WM_CLOSE");
// don't allow the last MDI child to be closed!
if (hwndTree = HasTreeWindow(hWnd)) {
// don't close if we are reading the tree
if (GetWindowLong(hwndTree, GWL_READLEVEL))
break;
}
// don't leve current dir on floppies
GetSystemDirectory(szDir, sizeof(szDir));
SheSetCurDrive(DRIVEID(szDir));
if (!IsLastWindow())
goto DEF_MDI_PROC; // this will close this window
break;
case WM_MDIACTIVATE:
MSG("TreeWndProc", "WM_MDIACTIVATE");
if (GET_WM_MDIACTIVATE_FACTIVATE(hWnd, wParam, lParam)) { // we are receiving the activation
lFreeSpace = -1L;
UpdateStatus(hWnd);
hwndFocus = (HWND)GetWindowLongPtr(hWnd, GWLP_LASTFOCUS);
SetFocus(hwndFocus);
} else if (hwndDrives = HasDrivesWindow(hWnd))
SendMessage(hwndDrives,wMsg,wParam,lParam);
break;
case WM_SETFOCUS:
MSG("TreeWndProc", "WM_SETFOCUS");
hwndFocus = (HWND)GetWindowLongPtr(hWnd, GWLP_LASTFOCUS);
SetFocus(hwndFocus);
break;
case WM_INITMENUPOPUP:
MSG("TreeWndProc", "WM_INITMENUPOPUP");
if (HIWORD(lParam)) {
EnableMenuItem((HMENU)wParam, SC_CLOSE,
IsLastWindow() ? MF_BYCOMMAND | MF_DISABLED | MF_GRAYED :
MF_ENABLED);
}
break;
case WM_SYSCOMMAND:
MSG("TreeWndProc", "WM_SYSCOMMAND");
if (wParam != SC_SPLIT)
goto DEF_MDI_PROC;
GetClientRect(hWnd, &rc);
lParam = MAKELONG(rc.right / 2, 0);
// fall through
case WM_LBUTTONDOWN:
MSG("TreeWndProc", "WM_LBUTTONDOWN");
{
MSG msg;
INT x, y, dx, dy;
if (IsIconic(hWnd))
break;
if (hwndDrives = GetDlgItem(hWnd, IDCW_DRIVES)) {
GetClientRect(hwndDrives, &rc);
y = rc.bottom;
} else {
y = 0;
}
x = LOWORD(lParam);
GetClientRect(hWnd, &rc);
dx = 4;
dy = rc.bottom - y; // the height of the client less the drives window
hdc = GetDC(hWnd);
// split bar loop
PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
SetCapture(hWnd);
while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN ||
(msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)) {
if (msg.message == WM_LBUTTONUP || msg.message == WM_LBUTTONDOWN)
break;
if (msg.message == WM_KEYDOWN) {
if (msg.wParam == VK_LEFT) {
msg.message = WM_MOUSEMOVE;
msg.pt.x -= 2;
} else if (msg.wParam == VK_RIGHT) {
msg.message = WM_MOUSEMOVE;
msg.pt.x += 2;
} else if (msg.wParam == VK_RETURN ||
msg.wParam == VK_ESCAPE) {
break;
}
SetCursorPos(msg.pt.x, msg.pt.y);
}
if (msg.message == WM_MOUSEMOVE) {
// erase old
PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
ScreenToClient(hWnd, &msg.pt);
x = msg.pt.x;
// put down new
PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
}
} else {
DispatchMessage(&msg);
}
}
ReleaseCapture();
// erase old
PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
ReleaseDC(hWnd, hdc);
if (msg.wParam != VK_ESCAPE) {
if (ResizeSplit(hWnd, x))
SendMessage(hWnd, WM_SIZE, SIZENOMDICRAP, MAKELONG(rc.right, rc.bottom));
}
break;
}
case WM_QUERYDRAGICON:
MSG("TreeWndProc", "WM_QUERYDRAGICON");
return (INT_PTR)GetTreeIcon(hWnd);
break;
case WM_ERASEBKGND:
MSG("TreeWndProc", "WM_ERASEBKGND");
if (IsIconic(hWnd)) {
// this paints the background of the icon properly, doing
// brush allignment and other nasty stuff
DefWindowProc(hWnd, WM_ICONERASEBKGND, wParam, 0L);
} else {
goto DEF_MDI_PROC;
}
break;
case WM_PAINT:
MSG("TreeWndProc", "WM_PAINT");
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
if (IsIconic(hWnd)) {
DrawIcon(hdc, 0, 0, GetTreeIcon(hWnd));
} else {
RECT rc2;
GetClientRect(hWnd, &rc);
rc.left = GetSplit(hWnd);
if (rc.left >= rc.right)
rc.left = 0;
rc.right = rc.left + dxFrame;
GetClientRect(HasDrivesWindow(hWnd), &rc2);
rc2.top = rc2.bottom;
rc2.bottom += dyBorder;
rc2.left = rc.left;
rc2.right = rc.right;
FillRect(hdc, &rc2, GetStockObject(BLACK_BRUSH));
// draw the black pane handle
rc.top = rc.bottom - GetSystemMetrics(SM_CYHSCROLL);
FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
}
EndPaint(hWnd, &ps);
break;
}
case WM_SIZE:
if (wParam != SIZEICONIC)
ResizeWindows(hWnd,LOWORD(lParam),HIWORD(lParam));
// if wParam is SIZENOMDICRAP this WM_SIZE was generated by us.
// don't let this through to the DefMDIChildProc().
// that might change the min/max state, (show parameter)
if (wParam == SIZENOMDICRAP)
break;
/*** FALL THRU ***/
default:
DEF_MDI_PROC:
return DefMDIChildProc(hWnd, wMsg, wParam, lParam);
}
return 0L;
}
VOID
ResizeWindows(
HWND hwndParent,
WORD dxWindow,
WORD dyWindow
)
{
INT dy, split;
INT cDriveRows, cDrivesPerRow;
DWORD dw;
HWND hwndTree,hwndDir,hwndDrives;
GetTreeWindows(hwndParent, &hwndTree, &hwndDir, &hwndDrives);
split = GetSplit(hwndParent);
// user has been fixed to do this right
dy = dyWindow + dyBorder;
if (hwndTree) {
if (!hwndDir)
MoveWindow(hwndTree, dxFrame, 0, dxWindow - dxFrame + dyBorder, dy, TRUE);
else
MoveWindow(hwndTree, -dyBorder, 0, split + dyBorder, dy, TRUE);
}
if (hwndDir) {
if (!hwndTree)
MoveWindow(hwndDir, dxFrame, 0, dxWindow - dxFrame + dyBorder, dy, TRUE);
else
MoveWindow(hwndDir, split + dxFrame, 0,
dxWindow - split - dxFrame + dyBorder, dy, TRUE);
}
}