windows-nt/Source/XPSP1/NT/termsrv/admtools/winutils/tsadmin/apptree.cpp
2020-09-26 16:20:57 +08:00

965 lines
28 KiB
C++

/*******************************************************************************
*
* apptree.cpp
*
* implementation of the CAppTreeView class
*
* copyright notice: Copyright 1997, Citrix Systems Inc.
* Copyright (c) 1998 - 1999 Microsoft Corporation
*
* $Author: donm $ Don Messerli
*
* $Log: N:\nt\private\utils\citrix\winutils\tsadmin\VCS\apptree.cpp $
*
* Rev 1.2 16 Feb 1998 16:00:06 donm
* modifications to support pICAsso extension
*
* Rev 1.1 03 Nov 1997 15:21:24 donm
* update
*
* Rev 1.0 13 Oct 1997 22:31:20 donm
* Initial revision.
*
*******************************************************************************/
#include "stdafx.h"
#include "winadmin.h"
#include "admindoc.h"
#include "apptree.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////
// MESSAGE MAP: CAppTreeView
//
IMPLEMENT_DYNCREATE(CAppTreeView, CBaseTreeView)
BEGIN_MESSAGE_MAP(CAppTreeView, CBaseTreeView)
//{{AFX_MSG_MAP(CAppTreeView)
ON_MESSAGE(WM_EXT_ADD_APPLICATION, OnExtAddApplication)
ON_MESSAGE(WM_EXT_REMOVE_APPLICATION, OnExtRemoveApplication)
ON_MESSAGE(WM_EXT_APP_CHANGED, OnExtAppChanged)
ON_MESSAGE(WM_EXT_ADD_APP_SERVER, OnExtAddAppServer)
ON_MESSAGE(WM_EXT_REMOVE_APP_SERVER, OnExtRemoveAppServer)
ON_MESSAGE(WM_ADMIN_VIEWS_READY, OnAdminViewsReady)
ON_MESSAGE(WM_ADMIN_UPDATE_SERVER, OnAdminUpdateServer)
ON_MESSAGE(WM_ADMIN_ADD_WINSTATION, OnAdminAddWinStation)
ON_MESSAGE(WM_ADMIN_REMOVE_WINSTATION, OnAdminRemoveWinStation)
ON_MESSAGE(WM_ADMIN_UPDATE_WINSTATION, OnAdminUpdateWinStation)
ON_WM_CONTEXTMENU()
ON_NOTIFY(NM_RCLICK, AFX_IDW_PANE_FIRST, OnRClick)
ON_NOTIFY(NM_RCLICK, 1, OnRClick)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////
// CAppTreeView ctor
//
CAppTreeView::CAppTreeView()
{
} // end CAppTreeView ctor
//////////////////////////
// CAppTreeView dtor
//
CAppTreeView::~CAppTreeView()
{
} // end CAppTreeView dtor
#ifdef _DEBUG
//////////////////////////////////
// CAppTreeView::AssertValid
//
void CAppTreeView::AssertValid() const
{
CBaseTreeView::AssertValid();
} // end CAppTreeView::AssertValid
///////////////////////////
// CAppTreeView::Dump
//
void CAppTreeView::Dump(CDumpContext& dc) const
{
CBaseTreeView::Dump(dc);
} // end CAppTreeView::Dump
#endif
/////////////////////////////////////
// CAppTreeView::BuildImageList
//
// - calls m_imageList.Create(..) to create the image list
// - calls AddIconToImageList(..) to add the icons themselves and save
// off their indices
// - attaches the image list to the CTreeCtrl
//
void CAppTreeView::BuildImageList()
{
m_ImageList.Create(16, 16, TRUE, 7, 0);
m_idxApps = AddIconToImageList(IDI_APPS);
m_idxGenericApp = AddIconToImageList(IDI_GENERIC_APP);
m_idxServer = AddIconToImageList(IDI_SERVER);
m_idxNotSign = AddIconToImageList(IDI_NOTSIGN);
m_idxQuestion = AddIconToImageList(IDI_QUESTIONMARK);
m_idxUser = AddIconToImageList(IDI_USER);
m_idxCurrentServer = AddIconToImageList(IDI_CURRENT_SERVER);
m_idxCurrentUser = AddIconToImageList(IDI_CURRENT_USER);
m_idxServerNotConnected = AddIconToImageList(IDI_SERVER_NOT_CONNECTED);
// Overlay for Servers we can't talk to
m_ImageList.SetOverlayImage(m_idxNotSign, 1);
// Overlay for Servers we are currently gathering information about
m_ImageList.SetOverlayImage(m_idxQuestion, 2);
GetTreeCtrl().SetImageList(&m_ImageList, TVSIL_NORMAL);
} // end CAppTreeView::BuildImageList
//////////////////////////////////
// CAppTreeView::OnAdminViewsReady
//
LRESULT CAppTreeView::OnAdminViewsReady(WPARAM wParam, LPARAM lParam)
{
LockTreeControl();
// Get a pointer to our document
CWinAdminDoc *doc = (CWinAdminDoc*)GetDocument();
// add the root to the tree
CString citrix;
citrix.LoadString(IDS_PUBLISHED_APPS);
CTreeNode* pRootNode = new CTreeNode(NODE_PUBLISHED_APPS, NULL);
if(pRootNode) {
HTREEITEM hRoot = AddItemToTree(NULL, citrix, TVI_ROOT, m_idxApps, (DWORD)pRootNode);
if(!hRoot) delete pRootNode;
}
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnAdminViewsReady
////////////////////////////////
// CAppTreeView::OnExtAddApplication
//
// Message Handler to add a published application to the tree
// Pointer to ExtAddTreeNode is in wParam
// Pointer to CPublishedApp is in lParam
//
LRESULT CAppTreeView::OnExtAddApplication(WPARAM wParam, LPARAM lParam)
{
LockTreeControl();
ExtAddTreeNode *pExtAddTreeNode = (ExtAddTreeNode*)wParam;
// First make sure the application isn't already in the tree
HTREEITEM hRoot = GetTreeCtrl().GetRootItem();
// Get the first application
HTREEITEM hItem = GetTreeCtrl().GetNextItem(hRoot, TVGN_CHILD);
while(hItem) {
// Get the data attached to the tree item
CTreeNode *node = (CTreeNode*)GetTreeCtrl().GetItemData(hItem);
// Is this the application we want to add?
if((CObject*)node->GetTreeObject() == pExtAddTreeNode->pObject) return 0;
hItem = GetTreeCtrl().GetNextItem(hItem, TVGN_NEXT);
}
// Add the published application to the tree
// Create a CTreeNode object with info about this tree node
CTreeNode* pNode = new CTreeNode(NODE_APPLICATION, pExtAddTreeNode->pObject);
if(pNode) {
HTREEITEM hApplication = AddItemToTree(hRoot, pExtAddTreeNode->Name, TVI_SORT,
m_idxGenericApp, (DWORD)pNode);
if(!hApplication) delete pNode;
if(!((CPublishedApp*)pExtAddTreeNode->pObject)->IsState(PAS_GOOD))
GetTreeCtrl().SetItemState(hApplication, STATE_QUESTION, 0x0F00);
((CPublishedApp*)pExtAddTreeNode->pObject)->SetTreeItem(hApplication);
}
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnExtAddApplication
////////////////////////////////
// CAppTreeView::OnExtRemoveApplication
//
// Message Handler to remove a published application from the tree
// Pointer to CPublishedApp is in lParam
//
LRESULT CAppTreeView::OnExtRemoveApplication(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam);
CPublishedApp *pApplication = (CPublishedApp*)lParam;
HTREEITEM hApplication = pApplication->GetTreeItem();
if(!hApplication) return 0;
LockTreeControl();
// Get the data attached to this tree node
CTreeNode *node = (CTreeNode*)GetTreeCtrl().GetItemData(hApplication);
if(node) {
// Is this the application we want to remove
CPublishedApp *pTreeApp = (CPublishedApp*)node->GetTreeObject();
// Make sure the tree node is correct
if(pTreeApp != pApplication) {
UnlockTreeControl();
return 0;
}
}
else {
UnlockTreeControl();
return 0;
}
// Loop through it's children and delete their data
HTREEITEM hAppServer = GetTreeCtrl().GetNextItem(hApplication, TVGN_CHILD);
while(hAppServer) {
CTreeNode *pTreeNode = (CTreeNode*)GetTreeCtrl().GetItemData(hAppServer);
if(pTreeNode) {
delete pTreeNode;
}
// Loop through the users nodes under the AppServer in the tree
HTREEITEM hUser = GetTreeCtrl().GetNextItem(hAppServer, TVGN_CHILD);
while(hUser) {
CTreeNode *pTreeNode = (CTreeNode*)GetTreeCtrl().GetItemData(hUser);
if(pTreeNode) {
CWinStation *pWinStation = (CWinStation*)pTreeNode->GetTreeObject();
if(pWinStation)
pWinStation->SetAppTreeItem(NULL);
delete pTreeNode;
}
}
hAppServer = GetTreeCtrl().GetNextItem(hAppServer, TVGN_NEXT);
}
// Delete the data attached to the tree item
delete node;
// Let the application know he is no longer in the tree
pApplication->SetTreeItem(NULL);
// Remove the application from the tree
// This SHOULD remove all it's children
GetTreeCtrl().DeleteItem(hApplication);
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnExtRemoveApplication
/////////////////////////////////////////
// CAppTreeView::OnExtAppChanged
//
LRESULT CAppTreeView::OnExtAppChanged(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam);
// we only care if it is a state change
if(wParam & ACF_STATE) {
CPublishedApp *pApplication = (CPublishedApp*)lParam;
HTREEITEM hApplication = pApplication->GetTreeItem();
if(!hApplication) return 0;
LockTreeControl();
// Get the data attached to this tree node
CTreeNode *node = (CTreeNode*)GetTreeCtrl().GetItemData(hApplication);
if(node) {
// Is this the app we want to update?
CPublishedApp *pTreeApp = (CPublishedApp*)node->GetTreeObject();
// Make sure the tree node is correct
if(pTreeApp != pApplication) {
UnlockTreeControl();
return 0;
}
} else {
UnlockTreeControl();
return 0;
}
USHORT NewState;
// Remember the previous state
USHORT PreviousState = GetTreeCtrl().GetItemState(hApplication, 0x0F00);
// Change the icon/overlay for the app
// If we aren't done getting all the information about this app,
// put a question mark over the icon
if(pApplication->IsState(PAS_GETTING_INFORMATION)) NewState = STATE_QUESTION;
// If it is fine, we want to remove any overlays from the icon
else NewState = STATE_NORMAL;
// Set the tree item to the new state
GetTreeCtrl().SetItemState(hApplication, NewState, 0x0F00);
}
return 0;
} // end CAppTreeView::OnExtAppChanged
/////////////////////////////////////////
// CAppTreeView::DetermineServerIcon
//
// determines which icon to display for a Server
// in the tree
//
int CAppTreeView::DetermineServerIcon(CServer *pServer)
{
if(!pServer) return m_idxServerNotConnected;
int WhichIcon = m_idxServer;
// Is this the current server?
if(pServer->IsCurrentServer()) {
if(pServer->IsState(SS_NONE) || pServer->IsState(SS_NOT_CONNECTED))
WhichIcon = m_idxServerNotConnected;
else
WhichIcon = m_idxCurrentServer;
} else { // not the current server
if(pServer->IsState(SS_NONE) || pServer->IsState(SS_NOT_CONNECTED))
WhichIcon = m_idxServerNotConnected;
}
return WhichIcon;
} // end CAooTreeView::DetermineServerIcon
////////////////////////////////
// CAppTreeView::OnExtAddAppServer
//
// Message Handler to add a server beneath a published application
// Pointer to ExtAddTreeNode is in wParam
// Pointer to CAppServer is in lParam
//
LRESULT CAppTreeView::OnExtAddAppServer(WPARAM wParam, LPARAM lParam)
{
ExtAddTreeNode *pExtAddTreeNode = (ExtAddTreeNode*)wParam;
HTREEITEM hParent = pExtAddTreeNode->hParent;
if(!hParent) return 0;
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CServer *pServer = pDoc->FindServerByName(pExtAddTreeNode->Name);
LockTreeControl();
CTreeCtrl &tree = GetTreeCtrl();
// First make sure the server isn't already in the tree
// Get the first server under the application
HTREEITEM hItem = tree.GetNextItem(hParent, TVGN_CHILD);
while(hItem) {
// Get the data attached to the tree item
CTreeNode *node = (CTreeNode*)tree.GetItemData(hItem);
if(node) {
// Is this the server we want to add
CAppServer *pAppServer = (CAppServer*)node->GetTreeObject();
if(pAppServer == (CAppServer*)pExtAddTreeNode->pObject) {
UnlockTreeControl();
return 0;
}
}
hItem = tree.GetNextItem(hItem, TVGN_NEXT);
}
CTreeNode* pNode = new CTreeNode(NODE_APP_SERVER, pExtAddTreeNode->pObject);
if(pNode) {
HTREEITEM hServer = AddItemToTree(hParent, pExtAddTreeNode->Name, TVI_SORT,
DetermineServerIcon(pServer), (DWORD)pNode);
if(!hServer) delete pNode;
((CAppServer*)pExtAddTreeNode->pObject)->SetTreeItem(hServer);
if(pServer) {
// If the server isn't sane, put a not sign over the icon
if(!pServer->IsServerSane()) tree.SetItemState(hServer, STATE_NOT, 0x0F00);
// If we aren't done getting all the information about this server,
// put a question mark over the icon
else if(pServer->IsState(SS_GETTING_INFO)) tree.SetItemState(hServer, STATE_QUESTION, 0x0F00);
}
}
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnExtAddAppServer
////////////////////////////////
// CAppTreeView::OnExtRemoveAppServer
//
// Message Handler to remove a server from beneath a published application
// Pointer to CPublishedApp is in wParam
// Pointer to CAppServer is in lParam
//
LRESULT CAppTreeView::OnExtRemoveAppServer(WPARAM wParam, LPARAM lParam)
{
ASSERT(wParam);
ASSERT(lParam);
HTREEITEM hServer = ((CAppServer*)lParam)->GetTreeItem();
if(!hServer) return 0;
LockTreeControl();
CTreeCtrl &tree = GetTreeCtrl();
CTreeNode *ServerNode = (CTreeNode*)tree.GetItemData(hServer);
// Remove the Users underneath this server in the tree
HTREEITEM hUser = tree.GetNextItem(hServer, TVGN_CHILD);
while(hUser) {
// Get the data attached to the tree item
CTreeNode *node = (CTreeNode*)tree.GetItemData(hUser);
if(node) {
CWinStation *pWinStation = (CWinStation*)node->GetTreeObject();
pWinStation->SetAppTreeItem(NULL);
delete node;
}
hUser = tree.GetNextItem(hUser, TVGN_NEXT);
}
// Delete the data attached to the tree item
delete ServerNode;
// Let the AppServer know he is no longer in the tree
((CAppServer*)lParam)->SetTreeItem(NULL);
// Remove the AppServer from the tree
// This SHOULD remove all it's children
GetTreeCtrl().DeleteItem(hServer);
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnExtRemoveAppServer
/////////////////////////////////////////
// CAppTreeView::AddServerChildren
//
// Adds the Users running the published app on a given Server
// to the tree
//
void CAppTreeView::AddServerChildren(HTREEITEM hServer, CServer *pServer)
{
ASSERT(hServer);
ASSERT(pServer);
if(pServer->IsServerSane()) {
LockTreeControl();
HTREEITEM hParent = GetTreeCtrl().GetParentItem(hServer);
HTREEITEM hLastNode = hServer;
CTreeNode *pParentNode = (CTreeNode*)GetTreeCtrl().GetItemData(hParent);
CPublishedApp *pApplication = (CPublishedApp*)pParentNode->GetTreeObject();
pServer->LockWinStationList();
// Get a pointer to the server's list of WinStations
CObList *pWinStationList = pServer->GetWinStationList();
// Iterate through the WinStation list
POSITION pos = pWinStationList->GetHeadPosition();
while(pos) {
CWinStation *pWinStation = (CWinStation*)pWinStationList->GetNext(pos);
// We only care if the user is running this published app
if(pWinStation->GetState() == State_Active
&& pWinStation->HasUser()
&& pWinStation->IsRunningPublishedApp()
&& pWinStation->IsRunningPublishedApp(pApplication->GetName())) {
// Figure out what text to display
CString UserString;
if(wcslen(pWinStation->GetUserName())) {
UserString.Format(TEXT("%s (%s)"), pWinStation->GetName(), pWinStation->GetUserName());
}
else UserString.Format(TEXT("%s"), pWinStation->GetName());
CTreeNode *pNode = new CTreeNode(NODE_WINSTATION, pWinStation);
if(pNode) {
pNode->SetSortOrder(pWinStation->GetSortOrder());
hLastNode = AddItemToTree(hServer, UserString, TVI_SORT,
pWinStation->IsCurrentUser() ? m_idxCurrentUser : m_idxUser, (DWORD)pNode);
if(!hLastNode) delete pNode;
}
// The WinStation wants to know his tree item handle
pWinStation->SetAppTreeItem(hLastNode);
}
}
pServer->UnlockWinStationList();
UnlockTreeControl();
} // end if(pServer->IsServerSane())
} // end CAppTreeView::AddServerChildren
////////////////////////////////
// CAppTreeView::OnAdminUpdateServer
//
// Message handler to update a Server in the tree
// Pointer to CServer to update is in lParam
//
LRESULT CAppTreeView::OnAdminUpdateServer(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam);
CServer *pServer = (CServer*)lParam;
if(!pServer) return 0;
LockTreeControl();
// The server can be in the tree more than one place
UINT itemCount = GetTreeCtrl().GetCount();
HTREEITEM hTreeItem = GetTreeCtrl().GetRootItem();
for(UINT i = 0; i < itemCount; i++) {
CTreeNode *node = ((CTreeNode*)GetTreeCtrl().GetItemData(hTreeItem));
if(node) {
// we only care about app servers
if(node->GetNodeType() == NODE_APP_SERVER) {
CAppServer *pAppServer = (CAppServer*)node->GetTreeObject();
// Is it the same server?
if(0 == wcscmp(pAppServer->GetName(), pServer->GetName())) {
USHORT NewState;
// Remember the previous state
USHORT PreviousState = GetTreeCtrl().GetItemState(hTreeItem, 0x0F00);
// Change the icon/overlay for the server
// If the server isn't sane, put a not sign over the icon
if(!pServer->IsServerSane()) NewState = STATE_NOT;
// If we aren't done getting all the information about this server,
// put a question mark over the icon
else if(pServer->IsState(SS_GETTING_INFO)) NewState = STATE_QUESTION;
// If it is fine, we want to remove any overlays from the icon
else NewState = STATE_NORMAL;
// Set the tree item to the new state
GetTreeCtrl().SetItemState(hTreeItem, NewState, 0x0F00);
// If this Server was not opened and now is GOOD,
// add it's children to the tree
if(PreviousState != STATE_NORMAL && pServer->IsState(SS_GOOD)) {
int ServerIcon = DetermineServerIcon(pServer);
GetTreeCtrl().SetItemImage(hTreeItem, ServerIcon, ServerIcon);
AddServerChildren(hTreeItem, pServer);
}
else if(pServer->GetPreviousState() == SS_DISCONNECTING && pServer->IsState(SS_NOT_CONNECTED)) {
int ServerIcon = DetermineServerIcon(pServer);
GetTreeCtrl().SetItemImage(hTreeItem, ServerIcon, ServerIcon);
}
// If we changed the state of this server and it is the currently
// selected node in the tree, we need to send a message to change
// the view
// We also need to make sure this is the currently selected tree
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
if(NewState != PreviousState && hTreeItem == GetTreeCtrl().GetSelectedItem()
&& pDoc->GetCurrentTree() == TREEVIEW_APPS) {
#if 0
LONG Result;
OnSelChange(NULL, &Result);
#endif
ForceSelChange();
}
}
}
}
hTreeItem = GetNextItem(hTreeItem);
}
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnAdminUpdateServer
////////////////////////////////
// CAppTreeView::AddUser
//
HTREEITEM CAppTreeView::AddUser(CWinStation *pWinStation)
{
ASSERT(pWinStation);
HTREEITEM hWinStation = NULL;
// Find the published app that this WinStation is running in our tree
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
CPublishedApp *pApplication = pDoc->FindPublishedAppByName(pWinStation->GetPublishedAppName());
CServer *pServer = pWinStation->GetServer();
if(!pApplication) return NULL;
HTREEITEM hApplication = pApplication->GetTreeItem();
if(!hApplication) return NULL;
CTreeCtrl &tree = LockTreeControl();
// Find this WinStation's server under the published application in the tree
HTREEITEM hServer = NULL;
hServer = tree.GetChildItem(hApplication);
while(hServer) {
CTreeNode *pNode = (CTreeNode*)GetTreeCtrl().GetItemData(hServer);
CAppServer *pAppServer = (CAppServer*)pNode->GetTreeObject();
if(0 == wcscmp(pAppServer->GetName(), pServer->GetName())) {
// Figure out what text to display
CString UserString;
if(wcslen(pWinStation->GetUserName())) {
UserString.Format(TEXT("%s (%s)"), pWinStation->GetName(), pWinStation->GetUserName());
}
else UserString.Format(TEXT("%s"), pWinStation->GetName());
CTreeNode *pNewNode = new CTreeNode(NODE_WINSTATION, pWinStation);
if(pNewNode) {
hWinStation = AddItemToTree(hServer, UserString, TVI_SORT,
pWinStation->IsCurrentUser() ? m_idxCurrentUser : m_idxUser, (DWORD)pNewNode);
if(!hWinStation) delete pNewNode;
// The WinStation wants to know his tree item handle
pWinStation->SetAppTreeItem(hWinStation);
}
}
hServer = tree.GetNextSiblingItem(hServer);
}
UnlockTreeControl();
return hWinStation;
}
////////////////////////////////
// CAppTreeView::OnAdminAddWinStation
//
// Message handler to add a WinStation to the tree
// lParam = pointer to CWinStation to add
// wParam is TRUE if this is replacing a WinStation that was currently selected
//
LRESULT CAppTreeView::OnAdminAddWinStation(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam);
CWinStation *pWinStation = (CWinStation*)lParam;
if(!pWinStation) return 0;
// If this WinStation isn't running a published App, we
// don't give a damn
if(!pWinStation->IsState(State_Active) || !pWinStation->IsRunningPublishedApp())
return 0;
AddUser(pWinStation);
return 0;
} // end CAppTreeView::OnAdminAddWinStation
////////////////////////////////
// CAppTreeView::OnAdminUpdateWinStation
//
// Message handler to update a WinStation in the tree
// lParam = pointer to CWinStation to update
//
LRESULT CAppTreeView::OnAdminUpdateWinStation(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam);
CWinStation *pWinStation = (CWinStation*)lParam;
if(!pWinStation) return 0;
// If this WinStation isn't running a published App, we
// don't give a damn
if(!pWinStation->IsState(State_Active) || !pWinStation->IsRunningPublishedApp())
return 0;
// If this WinStation is already in the tree, we don't want to
// add it again
if(pWinStation->GetAppTreeItem())
return 0;
AddUser(pWinStation);
return 0;
} // end CAppTreeView::OnAdminUpdateWinStation
////////////////////////////////
// CAppTreeView::OnAdminRemoveWinStation
//
// Message handler to remove a WinStation from the tree
// lParam = pointer to CWinStation to remove
LRESULT CAppTreeView::OnAdminRemoveWinStation(WPARAM wParam, LPARAM lParam)
{
ASSERT(lParam);
BOOL CurrentInTree = FALSE;
CWinStation *pWinStation = (CWinStation*)lParam;
if(!pWinStation) return 0;
HTREEITEM hWinStation = pWinStation->GetAppTreeItem();
if(!hWinStation) return 0;
LockTreeControl();
// Get the data attached to this tree node
CTreeNode *node = (CTreeNode*)GetTreeCtrl().GetItemData(hWinStation);
if(node) {
// Is this the WinStation we want to update
CWinStation *pTreeWinStation = (CWinStation*)node->GetTreeObject();
// Make sure the tree node is correct
if(pTreeWinStation != pWinStation) {
UnlockTreeControl();
return 0;
}
} else {
UnlockTreeControl();
return 0;
}
// Delete the data attached to the tree item
delete node;
// Let the WinStation know he is no longer in the tree
pWinStation->SetAppTreeItem(NULL);
// Is this WinStation currently selected in the tree?
CurrentInTree = (GetTreeCtrl().GetSelectedItem() == hWinStation);
// Remove the WinStation from the tree
GetTreeCtrl().DeleteItem(hWinStation);
// If this WinStation is the currently selected node in the tree,
// make it not so
// This may not be necessary!
CWinAdminDoc *pDoc = (CWinAdminDoc*)((CWinAdminApp*)AfxGetApp())->GetDocument();
if(CurrentInTree && pDoc->GetCurrentTree() == TREEVIEW_APPS)
((CWinAdminDoc*)GetDocument())->SetCurrentView(VIEW_CHANGING);
UnlockTreeControl();
return 0;
} // end CAppTreeView::OnAdminRemoveWinStation
////////////////////////////////
// CAppTreeView::OnContextMenu
//
// Message handler called when user wants a context menu
// This happens when the user clicks the right mouse button,
// presses Shift-F10, or presses the menu key on a Windows keyboard
//
void CAppTreeView::OnContextMenu(CWnd* pWnd, CPoint ptScreen)
{
CTreeCtrl &tree = GetTreeCtrl();
UINT flags;
HTREEITEM hItem;
CPoint ptClient = ptScreen;
ScreenToClient(&ptClient);
// If we got here from the keyboard,
if(ptScreen.x == -1 && ptScreen.y == -1) {
hItem = tree.GetSelectedItem();
RECT rect;
tree.GetItemRect(hItem, &rect, 0);
ptScreen.x = rect.left + (rect.right - rect.left)/2;
ptScreen.y = rect.top + (rect.bottom - rect.top)/2;
ClientToScreen(&ptScreen);
}
else {
hItem = tree.HitTest(ptClient, &flags);
if((NULL == hItem) || !(TVHT_ONITEM & flags))
return;
}
// Pop-up the menu
CTreeNode *pNode = (CTreeNode*)tree.GetItemData(hItem);
CWinAdminDoc *pDoc = (CWinAdminDoc*)GetDocument();
pDoc->SetTreeTemp(pNode->GetTreeObject(), (pNode->GetNodeType()));
if(pNode) {
CMenu menu;
UINT nIDResource = 0;
switch(pNode->GetNodeType()) {
case NODE_APP_SERVER:
{
CAppServer *pAppServer = (CAppServer*)pNode->GetTreeObject();
CServer *pServer = ((CWinAdminDoc*)GetDocument())->FindServerByName(pAppServer->GetName());
if(pServer) {
pDoc->SetTreeTemp(pServer, NODE_SERVER);
} else return;
nIDResource = IDR_SERVER_POPUP;
}
break;
case NODE_WINSTATION:
nIDResource = IDR_WINSTATION_TREE_POPUP;
break;
}
if(nIDResource) {
if(menu.LoadMenu(nIDResource)) {
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON |
TPM_RIGHTBUTTON, ptScreen.x, ptScreen.y, AfxGetMainWnd());
}
}
} // end if(pNode)
} // end CAppTreeView::OnContextMenu
////////////////////////////////
// CAppTreeView::OnRClick
//
// The Tree Common Control sends a WM_NOTIFY of NM_RCLICK when
// the user presses the right mouse button in the tree
//
void CAppTreeView::OnRClick(NMHDR* pNMHDR, LRESULT* pResult)
{
CPoint ptScreen(::GetMessagePos());
LockTreeControl();
// Get a pointer to our document
CWinAdminDoc *doc = (CWinAdminDoc*)GetDocument();
CTreeCtrl &tree = GetTreeCtrl();
UINT flags;
HTREEITEM hItem;
CPoint ptClient = ptScreen;
ScreenToClient(&ptClient);
hItem = tree.HitTest(ptClient, &flags);
if((NULL == hItem) || !(TVHT_ONITEM & flags)) {
UnlockTreeControl();
return;
}
// Pop-up the menu
CTreeNode *pNode = (CTreeNode*)tree.GetItemData(hItem);
CWinAdminDoc *pDoc = (CWinAdminDoc*)GetDocument();
pDoc->SetTreeTemp(pNode->GetTreeObject(), (pNode->GetNodeType()));
if(pNode) {
CMenu menu;
UINT nIDResource = 0;
switch(pNode->GetNodeType()) {
case NODE_APP_SERVER:
{
CAppServer *pAppServer = (CAppServer*)pNode->GetTreeObject();
CServer *pServer = ((CWinAdminDoc*)GetDocument())->FindServerByName(pAppServer->GetName());
if(pServer) {
pDoc->SetTreeTemp(pServer, NODE_SERVER);
} else return;
nIDResource = IDR_SERVER_POPUP;
}
break;
case NODE_WINSTATION:
nIDResource = IDR_WINSTATION_TREE_POPUP;
break;
}
if(nIDResource) {
if(menu.LoadMenu(nIDResource)) {
menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON |
TPM_RIGHTBUTTON, ptScreen.x, ptScreen.y, AfxGetMainWnd());
}
}
} // end if(pNode)
UnlockTreeControl();
} // end CAppTreeView::OnRClick
////////////////////////////////
// CAppTreeView::OnLButtonDown
//
void CAppTreeView::OnLButtonDown(UINT nFlags, CPoint ptClient)
{
// Figure out what they clicked on
LockTreeControl();
CTreeCtrl &tree = GetTreeCtrl();
UINT flags;
HTREEITEM hItem;
hItem = tree.HitTest(ptClient, &flags);
if((NULL == hItem) || !(TVHT_ONITEM & flags)) {
UnlockTreeControl();
CTreeView::OnLButtonDown(nFlags, ptClient);
return;
}
// We only care about servers
CTreeNode *pNode = (CTreeNode*)tree.GetItemData(hItem);
if(pNode && pNode->GetNodeType() == NODE_APP_SERVER) {
// Is it the same item as is selected
if(hItem == tree.GetSelectedItem()) {
CAppServer *pAppServer = (CAppServer*)pNode->GetTreeObject();
CServer *pServer = ((CWinAdminDoc*)GetDocument())->FindServerByName(pAppServer->GetName());
// Is this server in the "just disconnected" state
// If both previous state and state are SS_NOT_CONNECTED,
// we know the user just disconnected from this server
if(pServer && pServer->IsState(SS_NOT_CONNECTED)) {
UnlockTreeControl();
LONG Result;
OnSelChange(NULL, &Result);
return;
}
}
}
UnlockTreeControl();
CTreeView::OnLButtonDown(nFlags, ptClient);
} // CAppTreeView::OnLButtonDown