/*==========================================================================
*
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
*
* File: cGrpTree.cpp
* Content:An abstracted Tree control that knows how to handle
* DirectPlay system messages and enumerations.
*
***************************************************************************/
#include "cgrptree.h"
WNDPROCgwpOrigEditProc;
///////////////////////////////////////////////////////////////////////////////////////
long FAR PASCAL EditCtrlSubProc(HWND hWnd, WORD wMessage,WORD wParam,LONG lParam)
{
switch (wMessage)
{
case WM_GETDLGCODE:
return (DLGC_WANTALLKEYS |
CallWindowProc( gwpOrigEditProc, hWnd, wMessage,
wParam, lParam));
case WM_CHAR:
//Process this message to avoid message beeps.
if ((wParam == VK_RETURN) || (wParam == VK_TAB))
return 0;
break ;
default:
break;
} /* end switch */
return (CallWindowProc( gwpOrigEditProc, hWnd, wMessage,
wParam, lParam));
}
///////////////////////////////////////////////////////////////////////////////////////
BOOL FAR PASCAL TV_EnumPlayersCallback(DPID dpId,
DWORD dwPlayerType,
LPCDPNAME lpName,
DWORD dwFlags,
LPVOID lpContext)
{
LPENUMTREESTRUCT lp = (LPENUMTREESTRUCT) lpContext;
if (DPPLAYERTYPE_GROUP == dwPlayerType)
{
if (DPENUMGROUPS_SHORTCUT & dwFlags)
{
lp->lpTree->AddGroupToGroup( lp->dpidParent, dpId, dwFlags );
}
else
{
HRESULThr;
ENUMTREESTRUCTets;
ets.dpidParent = dpId;
ets.lpTree = lp->lpTree;
ets.bRecursive = lp->bRecursive;
if (NULL == lp->dpidParent)
{
lp->lpTree->CreateGroup( dpId, lpName->lpszShortNameA, dwFlags );
}
else
{
lp->lpTree->CreateGroupInGroup( lp->dpidParent, dpId, lpName->lpszShortNameA, dwFlags );
}
if (ets.bRecursive)
{
hr = lp->lpTree->m_lpDP3A->EnumGroupsInGroup(dpId, NULL,
TV_EnumPlayersCallback,
&ets, DPENUMPLAYERS_ALL );
hr = lp->lpTree->m_lpDP3A->EnumGroupPlayers(dpId, NULL,
TV_EnumPlayersCallback,
&ets, DPENUMPLAYERS_ALL );
}
}
}
else
{
if (lp->dpidParent)
{
lp->lpTree->AddPlayerToGroup( lp->dpidParent, dpId, dwFlags );
}
else
{
lp->lpTree->CreatePlayer( dpId, lpName->lpszShortNameA, dwFlags );
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
LPBRANCHSTRUCTlp1 = (LPBRANCHSTRUCT) lParam1,
lp2 = (LPBRANCHSTRUCT) lParam2;
if ( lp1->btType < lp2->btType )
{
return -1;
}
if (lp1->btType > lp2->btType )
{
return 1;
}
//if we got here, they are of the same type
//so sort alphabetically
LPDPNAMElpdpn1 = NULL,
lpdpn2 = NULL;
intiRes = 0;
HRESULThr = DPERR_GENERIC;
CGroupTree *lpgt = (CGroupTree *) lParamSort;
if ((lp1->btType == BT_PLAYER ) || (lp1->btType == BT_PLAYER_IN_GROUP ))
{
hr = lpgt->GetPlayerName( lp1->dpid, &lpdpn1 );
}
else
{
hr = lpgt->GetGroupName( lp1->dpid, &lpdpn1 );
}
if FAILED(hr)
{
goto FAILURE;
}
if ((lp2->btType == BT_PLAYER ) || (lp2->btType == BT_PLAYER_IN_GROUP ))
{
hr = lpgt->GetPlayerName( lp2->dpid, &lpdpn2 );
}
else
{
hr = lpgt->GetGroupName( lp2->dpid, &lpdpn2 );
}
if FAILED(hr)
{
goto FAILURE;
}
iRes = strcmp( lpdpn1->lpszShortNameA, lpdpn2->lpszShortNameA );
if ( 0 == iRes )
{
//The groups have the same name.
if ( lp1->dpid < lp2->dpid )
{
iRes = -1;
}
else if ( lp1->dpid > lp2->dpid )
{
iRes = 1;
}
else
{
iRes = -1;
}
}
FAILURE:
if (lpdpn1)
LocalFree(lpdpn1);
if (lpdpn2)
LocalFree(lpdpn2);
return iRes;
}
///////////////////////////////////////////////////////////////////////////////////////
CGroupTree::CGroupTree()
{
m_hInst = GetModuleHandle( NULL );
m_hwndTreeView = NULL;
m_hwndParent = NULL;
m_lpDP3A = NULL;
m_fDragging = FALSE;
m_dpidPlayer = 0;
m_dpidLastGroup = NULL;
// Prepare popup menus
m_hMenu = LoadMenu( m_hInst, MAKEINTRESOURCE(IDM_MENU) );
m_hRootMenu = GetSubMenu( m_hMenu, 0 );
m_hGroupMenu = GetSubMenu( m_hMenu, 1 );
m_hPlayerMenu = GetSubMenu( m_hMenu, 2 );
m_hShortcutMenu = GetSubMenu( m_hMenu, 3 );
m_hPlayerInGroupMenu= GetSubMenu( m_hMenu, 4 );
// Prepare tree icons
m_hImageList = ImageList_Create(32, 32, 0, 8, 8);
ImageList_SetBkColor(m_hImageList, GetSysColor(COLOR_WINDOW));
m_nGroupImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_CLOSEDDOOR)));
m_nInGroupImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_OPENDOOR)));
m_nPlayerImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_PLAYER)));
m_nShortcutInGroupImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SHORTCUT)));
m_nStagingAreaImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_STAGINGAREA)));
m_nSpectatorImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SPECTATOR)));
m_nSessionInProgressImg = ImageList_AddIcon(m_hImageList, LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_SESSIONINPROGRESS)));
ZeroMemory( &m_bsDragging, sizeof( BRANCHSTRUCT ) );
}
///////////////////////////////////////////////////////////////////////////////////////
CGroupTree::~CGroupTree()
{
if (m_hImageList)
{
ImageList_Destroy( m_hImageList );
m_hImageList = NULL;
}
DestroyMenu( m_hPlayerInGroupMenu );
DestroyMenu( m_hShortcutMenu );
DestroyMenu( m_hPlayerMenu );
DestroyMenu( m_hGroupMenu );
DestroyMenu( m_hRootMenu );
DestroyMenu( m_hMenu );
}
///////////////////////////////////////////////////////////////////////////////////////
BOOL CGroupTree::Init( HWND hWnd, LPDIRECTPLAY3A lpDP3A, DPID dpidPlayer )
{
if ( (hWnd) && (lpDP3A) && (dpidPlayer) )
{
m_hwndTreeView = hWnd;
m_hwndParent = GetParent( m_hwndTreeView );
m_lpDP3A = lpDP3A;
m_dpidPlayer = dpidPlayer;
TreeView_SetImageList(hWnd, m_hImageList, TVSIL_NORMAL);
return TRUE;
}
else
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::GetPlayerName( DPID dpidPlayer, LPDPNAME * lplpn)
{
HRESULThr= DPERR_GENERIC;
LPVOIDlpData= NULL;
DWORDdwSize= 0;
hr = m_lpDP3A->GetPlayerName( dpidPlayer, NULL, &dwSize );
if (DPERR_BUFFERTOOSMALL == hr )
{
lpData = LocalAlloc( LPTR, dwSize );
if ( NULL != lpData )
{
hr = m_lpDP3A->GetPlayerName( dpidPlayer, lpData, &dwSize );
if (FAILED(hr))
{
LocalFree( lpData );
lpData = NULL;
}
}
else
{
hr = DPERR_OUTOFMEMORY;
}
}
*lplpn = (LPDPNAME) lpData;
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::GetGroupName( DPID dpidGroup, LPDPNAME * lplpn)
{
HRESULThr= DPERR_GENERIC;
LPVOIDlpData = NULL;
DWORDdwSize= 0;
hr = m_lpDP3A->GetGroupName( dpidGroup, lpData, &dwSize );
if (DPERR_BUFFERTOOSMALL == hr )
{
lpData = LocalAlloc( LPTR, dwSize );
if ( NULL != lpData )
{
hr = m_lpDP3A->GetGroupName( dpidGroup, lpData, &dwSize );
if (FAILED(hr))
{
LocalFree( lpData );
lpData = NULL;
}
}
else
{
hr = DPERR_OUTOFMEMORY;
}
}
*lplpn = (LPDPNAME) lpData;
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HTREEITEM CGroupTree::FindItem( HTREEITEM htiSearchRoot,
DPID dpidTarget,
BRANCH_TYPE bt,
DWORD dwSearch )
{
TV_ITEM tvi;
HTREEITEMhItem,
htiSubSearch;
LPBRANCHSTRUCT lpbs = NULL;
if(TVI_ROOT == htiSearchRoot)
{
hItem = TreeView_GetRoot(m_hwndTreeView);
}
else
{
hItem = TreeView_GetChild( m_hwndTreeView, htiSearchRoot );
}
while(hItem)
{
ZeroMemory( &tvi, sizeof(TV_ITEM));
tvi.mask = TVIF_PARAM;
tvi.hItem = hItem;
TreeView_GetItem(m_hwndTreeView, &tvi);
lpbs = (LPBRANCHSTRUCT) tvi.lParam;
if ( (lpbs->dpid == dpidTarget) && ( bt == lpbs->btType))
{
return tvi.hItem;
}
if ( (lpbs->btType == BT_GROUP) && (ST_SEARCH_SUBGROUPS & dwSearch) )
{
htiSubSearch = FindItem( hItem, dpidTarget, bt, dwSearch );
if (htiSubSearch)
return (htiSubSearch);
}
hItem = TreeView_GetNextSibling(m_hwndTreeView, hItem);
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////////////
HTREEITEM CGroupTree::Insert( HTREEITEM htiParent, DPID dpID, LPSTR lpszShortNameA, BRANCH_TYPE bt, DWORD dwFlags )
{
LPBRANCHSTRUCTlpbs= NULL;
HTREEITEMhtrItem= NULL;
if ( lpbs = (LPBRANCHSTRUCT) LocalAlloc( LPTR, sizeof(BRANCHSTRUCT) ) )
{
TV_INSERTSTRUCTtvi;
TV_SORTCBtvscb;
ZeroMemory(lpbs, sizeof( BRANCHSTRUCT ) );
ZeroMemory(&tvscb, sizeof(tvscb));
ZeroMemory(&tvi, sizeof(tvi));
tvi.hParent= htiParent;
tvi.hInsertAfter= TVI_LAST;
tvi.item.mask= TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_TEXT;
tvi.item.pszText= lpszShortNameA;
tvi.item.cchTextMax= strlen(lpszShortNameA)+1;
switch( bt)
{
case BT_PLAYER:
case BT_PLAYER_IN_GROUP:
tvi.item.iImage = (DPPLAYER_SPECTATOR & dwFlags) ? m_nSpectatorImg: m_nPlayerImg;
tvi.item.iSelectedImage= tvi.item.iImage;
break;
case BT_GROUP:
if (DPGROUP_STAGINGAREA & dwFlags)
{
HRESULT hr;
LPDPLCONNECTION lp = NULL;
DWORDdwSize = 0;
BOOLbSessionInProgress = FALSE;
// if it is a staging area, check to see if the session is in progress.
hr = IDirectPlay3_GetGroupConnectionSettings( m_lpDP3A, 0, dpID, NULL, &dwSize );
if (DPERR_BUFFERTOOSMALL == hr )
{
lp = (LPDPLCONNECTION) GlobalAllocPtr( GHND, dwSize );
if (lp)
{
hr = IDirectPlay3_GetGroupConnectionSettings( m_lpDP3A, 0, dpID, lp, &dwSize );
if (!IsEqualGUID(lp->lpSessionDesc->guidInstance, GUID_NULL))
{
// If the server has assigned an instance guid
// to our connection structure, the session
// has already started.
bSessionInProgress = TRUE;
}
GlobalFreePtr(lp);
}
}
tvi.item.iImage = (bSessionInProgress)?m_nSessionInProgressImg:m_nStagingAreaImg;
tvi.item.iSelectedImage = tvi.item.iImage;
}
else
{
tvi.item.iImage = m_nGroupImg;
tvi.item.iSelectedImage = m_nInGroupImg;
}
break;
case BT_SHORTCUT_IN_GROUP:
tvi.item.iImage = m_nShortcutInGroupImg;
tvi.item.iSelectedImage= tvi.item.iImage;
break;
default:
//Invalid BranchType
break;
}
tvi.item.lParam= (LPARAM) lpbs;
lpbs->dpid= dpID;
lpbs->btType= bt;
lpbs->dwFlags= dwFlags;
htrItem = TreeView_InsertItem( m_hwndTreeView, &tvi );
tvscb.hParent = htiParent;
tvscb.lpfnCompare = CompareFunc;
tvscb.lParam = (LPARAM) this;
TreeView_SortChildrenCB( m_hwndTreeView, &tvscb, 0 );
if(TVI_ROOT != htiParent)
{
TreeView_Expand(m_hwndTreeView, htiParent, TVE_EXPAND);
}
Redraw();
}
return htrItem;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::CreatePlayer( DPID dpidPlayer, LPSTR lpszShortNameA, DWORD dwFlags )
{
/*
// We currently support only one local player. This section of code would create a
// new player at the root for each create player message received.
LPDPNAME lpn = NULL;
if (NULL == lpszShortNameA)
{
GetPlayerName(dpidPlayer, &lpn );
lpszShortNameA = lpn->lpszShortNameA;
}
if (lpszShortNameA)
{
Insert( TVI_ROOT, dpidPlayer, lpszShortNameA, BT_PLAYER, dwFlags );
}
if (lpn)
LocalFree(lpn);
*/
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::CreateGroup( DPID dpidGroup, LPSTR lpszShortNameA, DWORD dwFlags )
{
LPDPNAME lpn = NULL;
if (NULL == lpszShortNameA)
{
GetGroupName(dpidGroup, &lpn );
lpszShortNameA = lpn->lpszShortNameA;
}
if (lpszShortNameA)
{
Insert( TVI_ROOT, dpidGroup, lpszShortNameA, BT_GROUP, dwFlags );
}
if (lpn)
LocalFree(lpn);
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::CreateGroupInGroup( DPID dpidParentGroup, DPID dpidChildGroup, LPSTR lpszShortNameA, DWORD dwFlags )
{
HTREEITEM hParentItem = NULL;
if ( hParentItem = FindItem( TVI_ROOT, dpidParentGroup, BT_GROUP, ST_SEARCH_SUBGROUPS ) )
{
LPDPNAME lpn = NULL;
if (NULL == lpszShortNameA)
{
GetGroupName(dpidChildGroup, &lpn );
lpszShortNameA = lpn->lpszShortNameA;
}
if (lpszShortNameA)
{
Insert( hParentItem, dpidChildGroup, lpszShortNameA, BT_GROUP, dwFlags );
}
if (lpn)
LocalFree(lpn);
}
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::AddPlayerToGroup( DPID dpidGroup, DPID dpidPlayer, DWORD dwFlags )
{
HRESULThr = DPERR_GENERIC;
LPDPNAME lpPlayerName = NULL;
hr = GetPlayerName( dpidPlayer, &lpPlayerName );
if (SUCCEEDED(hr))
{
HTREEITEM hParentItem = NULL;
if ( hParentItem = FindItem( TVI_ROOT, dpidGroup, BT_GROUP, ST_SEARCH_SUBGROUPS ) )
{
Insert( hParentItem, dpidPlayer, lpPlayerName->lpszShortNameA, BT_PLAYER_IN_GROUP, dwFlags );
}
}
if (lpPlayerName)
LocalFree( lpPlayerName);
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::AddGroupToGroup( DPID dpidParentGroup, DPID dpidShortcut, DWORD dwFlags )
{
HRESULThr = DPERR_GENERIC;
LPDPNAME lpGroupName = NULL;
hr = GetGroupName( dpidShortcut, &lpGroupName );
if (SUCCEEDED(hr))
{
HTREEITEM hParentItem = NULL;
if ( hParentItem = FindItem( TVI_ROOT, dpidParentGroup, BT_GROUP, ST_SEARCH_SUBGROUPS ) )
{
Insert( hParentItem, dpidShortcut, lpGroupName->lpszShortNameA, BT_SHORTCUT_IN_GROUP, dwFlags );
}
}
if (lpGroupName)
LocalFree( lpGroupName);
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::DestroyPlayer(DPID dpidPlayer)
{
/*
// We are not currently adding additional players to the tree view. The
// Code below would add a player to the root of the tree control. If you
// want that functionality.
HTREEITEMhtiPlayer = FindItem( TVI_ROOT, dpidPlayer, BT_PLAYER, ST_NO_SUBGROUPS );
if ( htiPlayer )
{
TreeView_DeleteItem(m_hwndTreeView, htiPlayer);
Redraw();
}
*/
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::DestroyGroup(DPID dpidGroup)
{
HTREEITEMhtiGroup = FindItem( TVI_ROOT, dpidGroup, BT_GROUP, ST_SEARCH_SUBGROUPS );
if ( htiGroup )
{
TreeView_DeleteItem(m_hwndTreeView, htiGroup);
Redraw();
}
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::DeletePlayerFromGroup( DPID dpidGroup, DPID dpidPlayer )
{
HRESULThr = DPERR_GENERIC;
HTREEITEMhtiParent = NULL,
htiPlayer = NULL;
if ( htiParent = FindItem( TVI_ROOT, dpidGroup, BT_GROUP, ST_SEARCH_SUBGROUPS ) )
{
if ( htiPlayer = FindItem( htiParent, dpidPlayer, BT_PLAYER_IN_GROUP, ST_NO_SUBGROUPS ) )
{
TreeView_DeleteItem(m_hwndTreeView, htiPlayer);
hr = DP_OK;
Redraw();
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::DeleteGroupFromGroup( DPID dpidParentGroup, DPID dpidShortcut )
{
HRESULThr = DPERR_GENERIC;
HTREEITEMhtiParent = NULL,
htiShortcut = NULL;
if ( htiParent = FindItem( TVI_ROOT, dpidParentGroup, BT_GROUP, ST_SEARCH_SUBGROUPS ) )
{
if ( htiShortcut = FindItem( htiParent, dpidShortcut, BT_SHORTCUT_IN_GROUP, ST_NO_SUBGROUPS ) )
{
TreeView_DeleteItem(m_hwndTreeView, htiShortcut );
hr = DP_OK;
Redraw();
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::SetPlayerName( DPID dpidPlayer, LPSTR lpszShortName )
{
HRESULThr= DPERR_GENERIC;
hr = RecursiveRename( TVI_ROOT, dpidPlayer, lpszShortName );
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::SetGroupName( DPID dpidPlayer, LPSTR lpszShortName )
{
HRESULThr= DPERR_GENERIC;
hr = RecursiveRename( TVI_ROOT, dpidPlayer, lpszShortName );
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::RecursiveRename(HTREEITEM htiSearchRoot,
DPID dpidTarget,
LPSTR lpszName )
{
TV_ITEM tvi;
HTREEITEMhItem;
LPBRANCHSTRUCT lpbs = NULL;
if(TVI_ROOT == htiSearchRoot)
{
hItem = TreeView_GetRoot(m_hwndTreeView);
}
else
{
hItem = TreeView_GetChild( m_hwndTreeView, htiSearchRoot );
}
while(hItem)
{
ZeroMemory( &tvi, sizeof(TV_ITEM));
tvi.mask = TVIF_PARAM;
tvi.hItem = hItem;
TreeView_GetItem(m_hwndTreeView, &tvi);
lpbs = (LPBRANCHSTRUCT) tvi.lParam;
if (lpbs->dpid == dpidTarget)
{
ZeroMemory( &tvi, sizeof(TV_ITEM));
tvi.hItem = hItem;
tvi.mask = TVIF_TEXT;
tvi.pszText = lpszName;
tvi.cchTextMax = strlen(lpszName)+1;
TreeView_SetItem( m_hwndTreeView, &tvi );
}
if (lpbs->btType == BT_GROUP)
{
RecursiveRename( hItem, dpidTarget, lpszName );
}
hItem = TreeView_GetNextSibling(m_hwndTreeView, hItem);
}
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::Refresh( BOOL bRecursive )
{
HRESULThr = DPERR_GENERIC;
ENUMTREESTRUCTets;
ets.dpidParent = NULL;
ets.lpTree = this;
ets.bRecursive = bRecursive;
TreeView_DeleteAllItems( m_hwndTreeView );
if (m_lpDP3A)
{
//We don't see other root level players in the lobby world.
//hr = m_lpDP3A->EnumPlayers( NULL, TV_EnumPlayersCallback, &ets, DPENUMPLAYERS_ALL );
//if (SUCCEEDED( hr ))
//{
hr = m_lpDP3A->EnumGroups( NULL, TV_EnumPlayersCallback, &ets, DPENUMPLAYERS_ALL );
//}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
BOOL CGroupTree::Update(LPVOID lpvMsg)
{
DWORDdwMsgType= ((LPDPMSG_GENERIC)lpvMsg)->dwType;
LPSTRlpszShortName= NULL;
BOOLbReturn= TRUE;
// Draws the tree based strictly on system messages.
// If you place a call to this method in the area where you process
// your system messages, it should give you a good representation
// of the DirectPlay group structure as it is created.
switch(dwMsgType)
{
case DPSYS_CREATEPLAYERORGROUP:
{
LPDPMSG_CREATEPLAYERORGROUP lp = (LPDPMSG_CREATEPLAYERORGROUP)lpvMsg;
lpszShortName = lp->dpnName.lpszShortNameA;
if (DPPLAYERTYPE_PLAYER == lp->dwPlayerType)
{
CreatePlayer(lp->dpId, lpszShortName, lp->dwFlags );
}
else
{
if (NULL == lp->dpIdParent)
{
CreateGroup(lp->dpId, lpszShortName, lp->dwFlags );
}
else
{
CreateGroupInGroup(lp->dpIdParent, lp->dpId, lpszShortName, lp->dwFlags );
}
}
}
break;
case DPSYS_ADDPLAYERTOGROUP:
{
LPDPMSG_ADDPLAYERTOGROUP lp = (LPDPMSG_ADDPLAYERTOGROUP)lpvMsg;
DWORDdwFlags;
HRESULT hr = IDirectPlay3_GetPlayerFlags( m_lpDP3A, lp->dpIdPlayer, &dwFlags );
if (SUCCEEDED(hr))
{
// If I can't get his flags, he must have deleted himself
// by the time I got this message.
AddPlayerToGroup(lp->dpIdGroup, lp->dpIdPlayer,dwFlags );
}
}
break;
case DPSYS_ADDGROUPTOGROUP:
{
LPDPMSG_ADDGROUPTOGROUP lp = (LPDPMSG_ADDGROUPTOGROUP)lpvMsg;
DWORDdwFlags;
HRESULT hr = IDirectPlay3_GetGroupFlags( m_lpDP3A, lp->dpIdGroup, &dwFlags );
if (SUCCEEDED(hr))
{
// If I can't get his flags, he must have deleted himself
// by the time I got this message.
AddGroupToGroup(lp->dpIdParentGroup, lp->dpIdGroup, dwFlags );
}
}
break;
case DPSYS_DESTROYPLAYERORGROUP:
{
LPDPMSG_DESTROYPLAYERORGROUP lp = (LPDPMSG_DESTROYPLAYERORGROUP) lpvMsg;
if ( DPPLAYERTYPE_PLAYER == lp->dwPlayerType )
{
DestroyPlayer( lp->dpId );
}
else
{
DestroyGroup( lp->dpId );
}
}
break;
case DPSYS_DELETEGROUPFROMGROUP:
{
LPDPMSG_DELETEGROUPFROMGROUP lp =(LPDPMSG_DELETEGROUPFROMGROUP)lpvMsg;
DeleteGroupFromGroup( lp->dpIdParentGroup, lp->dpIdGroup );
}
break;
case DPSYS_DELETEPLAYERFROMGROUP:
{
LPDPMSG_DELETEPLAYERFROMGROUP lp =(LPDPMSG_DELETEPLAYERFROMGROUP)lpvMsg;
DeletePlayerFromGroup( lp->dpIdGroup, lp->dpIdPlayer );
}
break;
case DPSYS_SETPLAYERORGROUPDATA:
//Nothing for right now.
break;
case DPSYS_SETPLAYERORGROUPNAME:
{
LPDPMSG_SETPLAYERORGROUPNAME lp = (LPDPMSG_SETPLAYERORGROUPNAME)lpvMsg;
lpszShortName = lp->dpnName.lpszShortNameA;
if ( DPPLAYERTYPE_PLAYER == lp->dwPlayerType )
{
SetPlayerName(lp->dpId, lpszShortName );
}
else
{
SetGroupName(lp->dpId, lpszShortName );
}
}
break;
default:
//Code a new message...
bReturn = FALSE;
break;
}
return bReturn;
}
///////////////////////////////////////////////////////////////////////////////////////
DPID CGroupTree::GetDPIDOfCurrentSelection( LPBRANCHSTRUCT lpbt)
{
HTREEITEMhtItem;
TV_ITEMtvi;
ZeroMemory( &tvi, sizeof( TV_ITEM ) );
htItem = TreeView_GetSelection(m_hwndTreeView);
if (htItem)
{
tvi.mask = TVIF_PARAM;
tvi.hItem = htItem;
TreeView_GetItem(m_hwndTreeView, &tvi);
if (lpbt)
{
lpbt->dpid = ((LPBRANCHSTRUCT)(tvi.lParam))->dpid;
lpbt->btType = ((LPBRANCHSTRUCT)(tvi.lParam))->btType;
}
return ((LPBRANCHSTRUCT) (tvi.lParam))->dpid;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////
DPID CGroupTree::GetDPIDOfCurrentSelectionParent( LPBRANCHSTRUCT lpbt)
{
HTREEITEMhtChildItem, htItem;
TV_ITEMtvi;
ZeroMemory( &tvi, sizeof( TV_ITEM ) );
htChildItem = TreeView_GetSelection(m_hwndTreeView);
htItem = TreeView_GetParent( m_hwndTreeView, htChildItem );
if (htItem)
{
tvi.mask = TVIF_PARAM;
tvi.hItem = htItem;
TreeView_GetItem(m_hwndTreeView, &tvi);
if (lpbt)
{
lpbt->dpid = ((LPBRANCHSTRUCT)(tvi.lParam))->dpid;
lpbt->btType = ((LPBRANCHSTRUCT)(tvi.lParam))->btType;
}
return ((LPBRANCHSTRUCT) (tvi.lParam))->dpid;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::OnBeginDrag(NM_TREEVIEW *lpnmtv)
{
HIMAGELIST himl; // handle of image list
LPBRANCHSTRUCTlp = NULL;
int level = 0;
UINTxIndent = 0;
HTREEITEM htItem = NULL;
lp = (LPBRANCHSTRUCT)lpnmtv->itemNew.lParam;
m_bsDragging = *((LPBRANCHSTRUCT)(lpnmtv->itemNew.lParam));
GetBranchStructOfParent( lpnmtv->itemNew.hItem, &m_bsParentOfDragging );
// Tell the tree-view control to create an image to use
// for dragging.
himl = TreeView_CreateDragImage(m_hwndTreeView, lpnmtv->itemNew.hItem);
// Start the drag operation.
RECT rcItem;
TreeView_GetItemRect(m_hwndTreeView, lpnmtv->itemNew.hItem, &rcItem, FALSE);
htItem = lpnmtv->itemNew.hItem;
do
{
htItem = TreeView_GetParent( m_hwndTreeView, htItem );
level++;
}
while (htItem);
xIndent = TreeView_GetIndent( m_hwndTreeView ) * level;
BOOL b = ImageList_BeginDrag(himl, 0,
lpnmtv->ptDrag.x-rcItem.left - xIndent,
lpnmtv->ptDrag.y-rcItem.top);
// Hide the mouse cursor, and direct mouse input to the
// parent window.
ShowCursor( FALSE );
SetCapture(m_hwndParent);
m_fDragging = TRUE;
ImageList_DragEnter( m_hwndTreeView,
lpnmtv->ptDrag.x-rcItem.left - xIndent,
lpnmtv->ptDrag.y);
return;
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::OnMouseMove( LONG xCur, LONG yCur)
{
HTREEITEM htiTarget; // handle of target item
TV_HITTESTINFO tvht; // hit test information
TV_ITEMtvi;
ZeroMemory(&tvi, sizeof(TV_ITEM ) );
if (m_fDragging)
{
// Drag the item to the current position of the mouse cursor.
RECT rcTree, rcParent;
GetWindowRect( m_hwndParent, &rcParent );
GetWindowRect( m_hwndTreeView, &rcTree );
ImageList_DragMove(xCur, yCur);
// Find out if the cursor is on the item. If it is, highlight
// the item as a drop target.
tvht.pt.x = xCur;
tvht.pt.y = yCur;
if ((htiTarget = TreeView_HitTest(m_hwndTreeView, &tvht)) != NULL)
{
ImageList_DragLeave( m_hwndTreeView );
TreeView_SelectDropTarget(m_hwndTreeView, htiTarget);
ImageList_DragEnter( m_hwndTreeView, xCur, yCur);
tvi.mask = TVIF_PARAM;
tvi.hItem = htiTarget;
TreeView_GetItem(m_hwndTreeView, &tvi);
memcpy( &m_bsDropTarget, (LPBRANCHSTRUCT)(tvi.lParam), sizeof(BRANCHSTRUCT) );
}
else
{
ZeroMemory( &m_bsDropTarget, sizeof(BRANCHSTRUCT) );
}
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::OnLButtonUp(void)
{
if (m_fDragging)
{
ImageList_EndDrag();
ReleaseCapture();
ShowCursor( TRUE );
m_fDragging = FALSE;
ImageList_DragLeave( m_hwndTreeView );
if (m_bsDropTarget.dpid)
{
switch (m_bsDragging.btType )
{
case BT_PLAYER:
m_lpDP3A->AddPlayerToGroup(m_bsDropTarget.dpid, m_bsDragging.dpid );
break;
case BT_GROUP:
m_lpDP3A->AddGroupToGroup(m_bsDropTarget.dpid, m_bsDragging.dpid );
break;
case BT_PLAYER_IN_GROUP:
if (m_bsDropTarget.dpid != m_bsParentOfDragging.dpid)
{
m_lpDP3A->AddPlayerToGroup(m_bsDropTarget.dpid, m_bsDragging.dpid );
m_lpDP3A->DeletePlayerFromGroup(m_bsParentOfDragging.dpid, m_bsDragging.dpid );
}
break;
case BT_SHORTCUT_IN_GROUP:
if (m_bsDropTarget.dpid != m_bsParentOfDragging.dpid)
{
m_lpDP3A->AddGroupToGroup(m_bsDropTarget.dpid, m_bsDragging.dpid );
m_lpDP3A->DeleteGroupFromGroup(m_bsParentOfDragging.dpid, m_bsDragging.dpid );
}
break;
}
}
TreeView_SelectDropTarget( m_hwndTreeView, (HTREEITEM) NULL );
}
return;
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::Redraw(void)
{
RECT r;
GetWindowRect(m_hwndTreeView, &r );
InvalidateRect(m_hwndTreeView, &r, TRUE);
UpdateWindow(m_hwndParent);
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::OnRButtonDown( LONG xCur, LONG yCur)
{
HTREEITEM htiTarget; // handle of target item
TV_HITTESTINFO tvht; // hit test information
LPBRANCHSTRUCT lpbs = NULL;
HMENU hMenu = NULL;
TV_ITEMtvi;
ZeroMemory(&tvi, sizeof(TV_ITEM ) );
RECT rc;
GetWindowRect( m_hwndTreeView, &rc );
// Find out if the cursor is on the item. If it is, highlight
// the item as a drop target.
tvht.pt.x = xCur - rc.left;
tvht.pt.y = yCur - rc.top;
if ((htiTarget = TreeView_HitTest(m_hwndTreeView, &tvht)) != NULL)
{
TreeView_SelectItem(m_hwndTreeView, htiTarget);
tvi.mask = TVIF_PARAM;
tvi.hItem = htiTarget;
TreeView_GetItem(m_hwndTreeView, &tvi);
if (lpbs = (LPBRANCHSTRUCT)tvi.lParam)
{
m_dpidMenuTarget = lpbs->dpid;
switch (lpbs->btType)
{
case BT_GROUP:
hMenu = m_hGroupMenu;
EnableMenuItem(hMenu,ID_GROUP_STARTSESSION,
(DPGROUP_STAGINGAREA & lpbs->dwFlags)?MF_ENABLED:MF_GRAYED );
EnableMenuItem(hMenu,ID_GROUP_CONNECTIONSETTINGS,
(DPGROUP_STAGINGAREA & lpbs->dwFlags)?MF_ENABLED:MF_GRAYED );
break;
case BT_PLAYER:
hMenu = m_hPlayerMenu;
break;
case BT_SHORTCUT_IN_GROUP:
hMenu = m_hShortcutMenu;
break;
case BT_PLAYER_IN_GROUP:
hMenu = m_hPlayerInGroupMenu;
break;
default:
hMenu = m_hRootMenu;
break;
}
}
}
else
{
hMenu = m_hRootMenu;
}
TrackPopupMenuEx(hMenu,
TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
xCur, yCur, m_hwndParent, NULL );
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::OnDblClk( LONG xCur, LONG yCur)
{
HTREEITEM htiTarget; // handle of target item
TV_HITTESTINFO tvht; // hit test information
LPBRANCHSTRUCT lpbs = NULL;
HMENU hMenu = NULL;
TV_ITEMtvi;
ZeroMemory(&tvi, sizeof(TV_ITEM ) );
RECT rc;
GetWindowRect( m_hwndTreeView, &rc );
// Find out if the cursor is on the item. If it is, highlight
// the item as a drop target.
tvht.pt.x = xCur - rc.left;
tvht.pt.y = yCur - rc.top;
if ((htiTarget = TreeView_HitTest(m_hwndTreeView, &tvht)) != NULL)
{
TreeView_SelectItem(m_hwndTreeView, htiTarget);
tvi.mask = TVIF_PARAM;
tvi.hItem = htiTarget;
TreeView_GetItem(m_hwndTreeView, &tvi);
if (lpbs = (LPBRANCHSTRUCT)tvi.lParam)
{
m_dpidMenuTarget = lpbs->dpid;
switch (lpbs->btType)
{
case BT_SHORTCUT_IN_GROUP:
case BT_GROUP:
if (m_dpidLastGroup != lpbs->dpid)
{
m_lpDP3A->AddPlayerToGroup(lpbs->dpid, m_dpidPlayer );
m_lpDP3A->DeletePlayerFromGroup(m_dpidLastGroup, m_dpidPlayer );
m_dpidLastGroup = lpbs->dpid;
}
break;
default:
break;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////
HRESULT CGroupTree::BeginLabelEdit()
{
// Workaround for Windows tree control/dialog odd behavior
// Retrieve the handle of the edit control.
m_hwndEditCtrl = TreeView_GetEditControl( m_hwndTreeView );
// Subclass the edit control.
gwpOrigEditProc = (WNDPROC) SetWindowLong(m_hwndEditCtrl, GWL_WNDPROC, (LONG) EditCtrlSubProc );
return DP_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
void CGroupTree::EndLabelEdit( TV_DISPINFO FAR * lpTVDisp )
{
HRESULT hr;
// Subclass the edit control.
SetWindowLong(m_hwndEditCtrl, GWL_WNDPROC, (LONG) gwpOrigEditProc);
if (lpTVDisp->item.pszText)
{
LPBRANCHSTRUCT lpbs = (LPBRANCHSTRUCT) lpTVDisp->item.lParam;
hr = CheckAccessRights(lpTVDisp);
if (SUCCEEDED(hr))
{
DPNAME dpn;
dpn.dwSize = sizeof(DPNAME);
dpn.lpszShortNameA = lpTVDisp->item.pszText;
dpn.lpszLongNameA = lpTVDisp->item.pszText;
switch (lpbs->btType)
{
case BT_GROUP:
m_lpDP3A->SetGroupName(lpbs->dpid, &dpn, DPSET_REMOTE );
break;
case BT_PLAYER_IN_GROUP:
case BT_PLAYER:
m_lpDP3A->SetPlayerName(lpbs->dpid, &dpn, DPSET_REMOTE );
break;
}
}
else
{
MessageBox( m_hwndParent, "Cannot change the name of remote players or groups", "Error", MB_OK);
return;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////
DPID CGroupTree::GetBranchStructOfParent( HTREEITEM htChildItem, LPBRANCHSTRUCT lpbt)
{
HTREEITEMhtItem;
TV_ITEMtvi;
ZeroMemory( &tvi, sizeof( TV_ITEM ) );
ZeroMemory( lpbt, sizeof( BRANCHSTRUCT ) );
htItem = TreeView_GetParent( m_hwndTreeView, htChildItem );
if (htItem)
{
tvi.mask = TVIF_PARAM;
tvi.hItem = htItem;
TreeView_GetItem(m_hwndTreeView, &tvi);
if (lpbt)
{
*lpbt = *((LPBRANCHSTRUCT)(tvi.lParam));
}
return ((LPBRANCHSTRUCT) (tvi.lParam))->dpid;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////
BOOL CGroupTree::OnWM_NOTIFY( WPARAM wParam, LPARAM lParam )
{
int idCtrl = (int) wParam;
LPNMHDR pnmh = (LPNMHDR)lParam;
if (NULL == pnmh)
return FALSE;
NM_TREEVIEW*nmtv;
TV_ITEM*pItemNew = NULL;
TV_ITEM*pItemOld = NULL;
LPBRANCHSTRUCTlpBranch = NULL;
HRESULT hr;
switch(pnmh->code)
{
case NM_RCLICK:
{
POINT p;
GetCursorPos(&p);
OnRButtonDown(p.x, p.y );
}
break;
case NM_DBLCLK:
{
POINT p;
GetCursorPos(&p);
OnDblClk(p.x, p.y );
}
break;
case TVN_BEGINLABELEDIT:
hr = BeginLabelEdit();
if (FAILED(hr))
return TRUE;
break;
case TVN_ENDLABELEDIT:
EndLabelEdit((TV_DISPINFO FAR *) lParam);
break;
case TVN_SELCHANGING:
break;
case TVN_DELETEITEM:
nmtv= (NM_TREEVIEW *)lParam;
pItemOld= &nmtv->itemOld;
LocalFree( (LPVOID) pItemOld->lParam );
break;
case TVN_BEGINDRAG:
OnBeginDrag((NM_TREEVIEW *) lParam);
break;
}
return 0;
}
HRESULTCGroupTree::EditLabel()
{
HRESULT hr; // Initialized by call to CheckAccessRights()
HTREEITEMhtItem;
TV_ITEMtvi;
ZeroMemory( &tvi, sizeof( TV_ITEM ) );
htItem = TreeView_GetSelection(m_hwndTreeView);
if (htItem)
{
HWND hwnd = NULL;
hwnd = TreeView_EditLabel( m_hwndTreeView, htItem );
hr = (hwnd ? DP_OK : DPERR_ACCESSDENIED);
}
else
{
hr = DPERR_ACCESSDENIED;
}
return hr;
}
HRESULT CGroupTree::CheckAccessRights(TV_DISPINFO FAR * lpTVDisp)
{
HRESULT hr = DPERR_GENERIC;
DWORDdwFlags = 0;
BRANCHSTRUCT bsCurSel;
if (NULL == lpTVDisp)
{
GetDPIDOfCurrentSelection( &bsCurSel );
}
else
{
bsCurSel = *((LPBRANCHSTRUCT) lpTVDisp->item.lParam);
}
switch ( bsCurSel.btType )
{
case BT_PLAYER:
case BT_PLAYER_IN_GROUP:
hr = m_lpDP3A->GetPlayerFlags( bsCurSel.dpid, &dwFlags );
break;
case BT_GROUP:
hr = m_lpDP3A->GetGroupFlags( bsCurSel.dpid, &dwFlags );
break;
default:
break;
}
if (FAILED(hr))
return hr;
if (dwFlags & DPPLAYER_LOCAL )
{
hr = DP_OK;
}
else
{
hr = DPERR_ACCESSDENIED;
}
return hr;
}