#include "stdafx.h"
#include "AllSrvUI.h"
#include "AllSrvUISheet.h"
#include "PagePlayers.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CPagePlayers, CPropertyPage)
BEGIN_AUTO_SIZER_MAP(_AutoSizerMap)
AUTO_SIZER_ENTRY(IDC_BOOT_PLAYERS , LeftRight, 0, Right, NoRefresh)
AUTO_SIZER_ENTRY(IDC_BOOT_PLAYERS , TopBottom, 0, Bottom, NoRefresh)
AUTO_SIZER_ENTRY(IDC_SEND_CHAT_CAPTION, TopBottom, 0, Bottom, NoRefresh)
AUTO_SIZER_ENTRY(IDC_SEND_CHAT_TEXT , Right, 0, Right, NoRefresh)
AUTO_SIZER_ENTRY(IDC_SEND_CHAT_TEXT , TopBottom, 0, Bottom, NoRefresh)
AUTO_SIZER_ENTRY(IDC_PLAYER_LIST , Right, 0, Right, NoRefresh)
AUTO_SIZER_ENTRY(IDC_PLAYER_LIST , Bottom, 0, Bottom, NoRefresh)
END_AUTO_SIZER_MAP()
BEGIN_MESSAGE_MAP(CPagePlayers, CPropertyPage)
ON_NOTIFY(HDN_ENDDRAG, 0, OnEndDragPlayerList)
ON_NOTIFY(HDN_ENDTRACK, 0, OnEndTrackPlayerList)
ON_WM_TIMER()
ON_NOTIFY(LVN_ITEMCHANGED, IDC_PLAYER_LIST, OnItemChangedPlayerList)
ON_NOTIFY(LVN_DELETEITEM, IDC_PLAYER_LIST, OnDeleteItemPlayerList)
ON_BN_CLICKED(IDC_BOOT_PLAYERS, OnBootPlayers)
END_MESSAGE_MAP()
CPagePlayers::CPagePlayers() :
CPropertyPage(CPagePlayers::IDD)
{
m_strSendChat = _T("");
HRESULT hr = m_spStrings.CreateInstance("TCObj.Strings");
if (FAILED(hr))
GetSheet()->HandleError(hr, "creating TCObj.Strings helper object", true);
}
void CPagePlayers::OnEvent(IAGCEvent* pEvent)
{
AGCEventID eEvent;
if (FAILED(pEvent->get_ID(&eEvent)))
return;
switch (eEvent)
{
case EventID_GameCreated:
case EventID_GameDestroyed:
{
UpdateUI();
break;
}
case EventID_LoginGame:
{
AddPlayer(pEvent);
break;
}
case EventID_LogoutGame:
{
RemovePlayer(pEvent);
break;
}
case EventID_ShipChangesSectors:
{
SectorOrTeamChange(pEvent, 2, L"New Sector Name");
break;
}
case EventID_LeaveTeam:
case EventID_JoinTeam:
{
SectorOrTeamChange(pEvent, 1, L"TeamName");
break;
}
case EventID_TeamInfoChange:
{
TeamInfoChange(pEvent);
break;
}
}
}
BOOL CPagePlayers::OnSetActive()
{
LoadFromRegistry();
UpdateUI();
return CPropertyPage::OnSetActive();
}
BOOL CPagePlayers::PreTranslateMessage(MSG* pMsg)
{
if (WM_KEYDOWN == pMsg->message)
{
if (VK_RETURN == pMsg->wParam)
{
if (&m_comboSendChat == GetFocus() ||
&m_comboSendChat == GetFocus()->GetParent())
{
SendChat();
return true;
}
}
}
return CPropertyPage::PreTranslateMessage(pMsg);
}
void CPagePlayers::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BOOT_PLAYERS, m_btnBootPlayers);
DDX_Control(pDX, IDC_SEND_CHAT_CAPTION, m_staticSendChat);
DDX_Control(pDX, IDC_SEND_CHAT_TEXT, m_comboSendChat);
DDX_CBString(pDX, IDC_SEND_CHAT_TEXT, m_strSendChat);
DDX_Control(pDX, IDC_PLAYER_LIST, m_listPlayers);
}
LRESULT CPagePlayers::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lr;
if (m_AutoSizer.ProcessMessage(message, wParam, lParam, &lr))
return lr;
return CPropertyPage::WindowProc(message, wParam, lParam);
}
void CPagePlayers::LoadFromRegistry()
{
CRegKey key;
key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI);
CComBSTR bstrColumnOrder;
LoadRegString(key, TEXT("PlayerListColumnOrder"), bstrColumnOrder);
m_spStrings->RemoveAll();
m_spStrings->AddDelimited(CComBSTR(L","), bstrColumnOrder);
long cOrderedColumns = 0;
m_spStrings->get_Count(&cOrderedColumns);
if (c_cColumns == cOrderedColumns)
{
int vecOrder[c_cColumns];
for (CComVariant i(0L); V_I4(&i) < c_cColumns; ++V_I4(&i))
{
bstrColumnOrder.Empty();
m_spStrings->get_Item(&i, &bstrColumnOrder);
vecOrder[V_I4(&i)] = _wtoi(bstrColumnOrder);
}
m_listPlayers.SetColumnOrderArray(c_cColumns, vecOrder);
}
CComBSTR bstrColumnWidths;
LoadRegString(key, TEXT("PlayerListColumnWidths"), bstrColumnWidths);
m_spStrings->RemoveAll();
m_spStrings->AddDelimited(CComBSTR(L","), bstrColumnWidths);
long cWidthColumns = 0;
m_spStrings->get_Count(&cWidthColumns);
if (c_cColumns == cWidthColumns)
{
for (CComVariant i(0L); V_I4(&i) < c_cColumns; ++V_I4(&i))
{
bstrColumnWidths.Empty();
m_spStrings->get_Item(&i, &bstrColumnWidths);
m_listPlayers.SetColumnWidth(V_I4(&i), _wtoi(bstrColumnWidths));
}
}
else
{
for (int i = 0; i < c_cColumns; ++i)
{
TCHAR szColumn[_MAX_PATH];
LVCOLUMN lvc = {LVCF_TEXT, 0, 0, szColumn, sizeofArray(szColumn)};
m_listPlayers.GetColumn(i, &lvc);
int cx = m_listPlayers.GetStringWidth(CString(szColumn) + TEXT(" "));
m_listPlayers.SetColumnWidth(i, cx);
}
}
m_comboSendChat.ResetContent();
CRegKey keyMRU;
if (ERROR_SUCCESS == keyMRU.Create(key, TEXT("SendChatMRU")))
{
DWORD cStrings = 0;
keyMRU.QueryValue(cStrings, TEXT(".Count"));
for (DWORD i = 0; i < cStrings; ++i)
{
TCHAR szInt[16];
CString strMRUItem;
LoadRegString(keyMRU, _itot(i, szInt, 10), strMRUItem);
strMRUItem.TrimLeft();
strMRUItem.TrimRight();
if (!strMRUItem.IsEmpty())
m_comboSendChat.InsertString(i, strMRUItem);
}
}
}
void CPagePlayers::SavePlayerListColumnOrderToRegistry()
{
CRegKey key;
key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI);
int vecOrder[c_cColumns];
for (int iCol = 0; iCol < c_cColumns; ++iCol)
vecOrder[iCol] = iCol;
m_listPlayers.GetColumnOrderArray(vecOrder, c_cColumns);
CString strColumnOrder;
for (int i = 0; i < c_cColumns; ++i)
{
if (i)
strColumnOrder += ",";
TCHAR szNum[16];
strColumnOrder += _itot(vecOrder[i], szNum, 10);
}
key.SetValue(strColumnOrder, TEXT("PlayerListColumnOrder"));
}
void CPagePlayers::SavePlayerListColumnWidthsToRegistry()
{
CRegKey key;
key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI);
CString strColumnWidths;
for (int i = 0; i < c_cColumns; ++i)
{
if (i)
strColumnWidths += ",";
TCHAR szNum[16];
strColumnWidths += _itot(m_listPlayers.GetColumnWidth(i), szNum, 10);
}
key.SetValue(strColumnWidths, TEXT("PlayerListColumnWidths"));
}
void CPagePlayers::SaveSendChatMRUToRegistry()
{
CRegKey key;
if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI))
return;
CRegKey keyMRU;
if (ERROR_SUCCESS != keyMRU.Create(key, TEXT("SendChatMRU")))
return;
int cStrings = min(m_comboSendChat.GetCount(), c_cMaxChatsInRegistry);
keyMRU.SetValue(cStrings, TEXT(".Count"));
for (int i = 0; i < cStrings; ++i)
{
TCHAR szInt[16];
CString strMRUItem;
m_comboSendChat.GetLBText(i, strMRUItem);
keyMRU.SetValue(strMRUItem, _itot(i, szInt, 10));
}
}
void CPagePlayers::UpdateUI(bool bUpdateData)
{
if (bUpdateData)
UpdateData();
bool bGameInProgress = NULL != GetSheet()->GetGame();
UINT cSelectedItems = m_listPlayers.GetSelectedCount();
m_staticSendChat.EnableWindow(bGameInProgress && cSelectedItems);
m_comboSendChat.EnableWindow(bGameInProgress && cSelectedItems);
m_btnBootPlayers.EnableWindow(bGameInProgress && cSelectedItems);
}
void CPagePlayers::SendChat()
{
CWaitCursor wait;
UpdateData();
UINT cSelectedItems = m_listPlayers.GetSelectedCount();
if (!cSelectedItems)
return;
m_strSendChat.TrimLeft();
m_strSendChat.TrimRight();
if (!m_strSendChat.IsEmpty())
{
int iFound = m_comboSendChat.FindStringExact(-1, m_strSendChat);
if (iFound >= 0)
m_comboSendChat.DeleteString(iFound);
m_comboSendChat.InsertString(0, m_strSendChat);
int cStrings;
do
{
cStrings = m_comboSendChat.GetCount();
if (cStrings > c_cMaxChatsInRegistry)
{
m_comboSendChat.DeleteString(cStrings - 1);
}
} while (cStrings > c_cMaxChatsInRegistry);
CComBSTR bstrSendChat(m_strSendChat);
if (m_listPlayers.GetItemCount() == static_cast<int>(cSelectedItems))
{
GetSheet()->GetGame()->SendChat(bstrSendChat, -1);
}
else
{
POSITION it = m_listPlayers.GetFirstSelectedItemPosition();
while (it)
{
int iIndex = m_listPlayers.GetNextSelectedItem(it);
_ASSERTE(-1 != iIndex);
DWORD dwItemData = m_listPlayers.GetItemData(iIndex);
IAdminShip* pShip = reinterpret_cast<IAdminShip*>(dwItemData);
_ASSERTE(pShip);
pShip->SendChat(bstrSendChat, -1);
}
}
m_strSendChat.Empty();
UpdateData(false);
SaveSendChatMRUToRegistry();
}
}
void CPagePlayers::PopulatePlayersList()
{
CWaitCursor wait;
LPCSTR pszContext = "retrieving collection of players in game";
m_listPlayers.DeleteAllItems();
if (NULL == GetSheet()->GetGame())
return;
IAdminUsersPtr spUsers;
HRESULT hr = GetSheet()->GetGame()->get_Users(&spUsers);
if (FAILED(hr))
{
GetSheet()->HandleError(hr, pszContext, true);
return;
}
IUnknownPtr spEnumUnk;
if (FAILED(hr = spUsers->get__NewEnum(&spEnumUnk)))
{
GetSheet()->HandleError(hr, pszContext, true);
return;
}
IEnumVARIANTPtr spEnum(spEnumUnk);
if (NULL == spEnum)
{
GetSheet()->HandleError(E_NOINTERFACE, pszContext, true);
return;
}
int iIndex = 0;
CComVariant players[32];
do
{
ULONG cFetched;
if (FAILED(hr = spEnum->Next(sizeofArray(players), players, &cFetched)))
{
GetSheet()->HandleError(hr, pszContext, true);
return;
}
for (ULONG i = 0; i < cFetched; ++i)
{
VARTYPE vt = V_VT(&players[i]);
if (VT_DISPATCH != vt && VT_UNKNOWN != vt)
{
GetSheet()->HandleError(DISP_E_TYPEMISMATCH, pszContext, true);
return;
}
IAdminUserPtr spUser(V_DISPATCH(&players[i]));
if (NULL == spUser)
{
GetSheet()->HandleError(E_NOINTERFACE, pszContext, true);
return;
}
players[i].Clear();
IAdminShipPtr spShip;
if (FAILED(hr = spUser->get_Ship(&spShip)))
{
GetSheet()->HandleError(hr, pszContext, true);
return;
}
CComBSTR bstrName, bstrTeam, bstrSector;
spShip->get_Name(&bstrName);
IAGCTeamPtr spTeam;
spShip->get_Team(&spTeam);
if (NULL != spTeam)
spTeam->get_Name(&bstrTeam);
IAGCSectorPtr spSector;
spShip->get_Sector(&spSector);
if (NULL != spSector)
spSector->get_Name(&bstrSector);
USES_CONVERSION;
m_listPlayers.InsertItem(iIndex, OLE2CT(bstrName));
m_listPlayers.SetItemText(iIndex, c_iColumnTeam, OLE2CT(bstrTeam));
m_listPlayers.SetItemText(iIndex, c_iColumnSector, OLE2CT(bstrSector));
m_listPlayers.SetItemData(iIndex, reinterpret_cast<DWORD>(spShip.Detach()));
++iIndex;
}
} while (S_FALSE != hr);
}
void CPagePlayers::AddPlayer(IAGCEvent* pEvent)
{
CWaitCursor wait;
LPCSTR pszContext = "adding new player to the list";
HRESULT hr;
CComBSTR bstrName;
pEvent->get_SubjectName(&bstrName);
long idPlayer = -1;
pEvent->get_SubjectID(&idPlayer);
_ASSERTE(bstrName.Length());
USES_CONVERSION;
LV_FINDINFO lvfi = {LVFI_STRING, OLE2CT(bstrName)};
int iIndex = m_listPlayers.FindItem(&lvfi);
_ASSERTE(-1 == iIndex);
IAdminUserPtr spUser;
if (FAILED(hr = GetSheet()->GetServer()->get_FindUser(bstrName, &spUser)))
{
GetSheet()->HandleError(hr, pszContext, true);
return;
}
IAdminShipPtr spShip;
if (FAILED(hr = spUser->get_Ship(&spShip)))
{
GetSheet()->HandleError(hr, pszContext, true);
return;
}
iIndex = m_listPlayers.GetItemCount();
m_listPlayers.InsertItem(iIndex, OLE2CT(bstrName));
m_listPlayers.SetItemText(iIndex, c_iColumnTeam, TEXT(""));
m_listPlayers.SetItemText(iIndex, c_iColumnSector, TEXT(""));
m_listPlayers.SetItemData(iIndex, reinterpret_cast<DWORD>(spShip.Detach()));
}
void CPagePlayers::RemovePlayer(IAGCEvent* pEvent)
{
CComBSTR bstrName;
pEvent->get_SubjectName(&bstrName);
_ASSERTE(bstrName.Length());
USES_CONVERSION;
LV_FINDINFO lvfi = {LVFI_STRING, OLE2CT(bstrName)};
int iIndex = m_listPlayers.FindItem(&lvfi);
_ASSERTE(-1 != iIndex);
m_listPlayers.DeleteItem(iIndex);
}
void CPagePlayers::SectorOrTeamChange(IAGCEvent* pEvent, int iColumn,
LPCOLESTR pszProperty)
{
CWaitCursor wait;
CComBSTR bstrName, bstrProperty;
pEvent->get_SubjectName(&bstrName);
CComVariant varNewPropertyName;
pEvent->get_Property(&CComVariant(pszProperty), &varNewPropertyName);
varNewPropertyName.ChangeType(VT_BSTR);
bstrProperty = V_BSTR(&varNewPropertyName);
_ASSERTE(bstrName.Length());
USES_CONVERSION;
LV_FINDINFO lvfi = {LVFI_STRING, OLE2CT(bstrName)};
int iIndex = m_listPlayers.FindItem(&lvfi);
_ASSERTE(iIndex >= 0);
m_listPlayers.SetItemText(iIndex, iColumn,
bstrProperty.Length() ? OLE2CT(bstrProperty) : TEXT(""));
}
void CPagePlayers::TeamInfoChange(IAGCEvent* pEvent)
{
CWaitCursor wait;
CComBSTR bstrTeam, bstrTeamNew;
pEvent->get_SubjectName(&bstrTeam);
CComVariant varTeamNew;
pEvent->get_Property(&CComVariant(L"NewTeamName"), &varTeamNew);
varTeamNew.ChangeType(VT_BSTR);
CString strTeam(bstrTeam), strTeamNew(V_BSTR(&varTeamNew));
_ASSERTE(!strTeam.IsEmpty());
int cPlayers = m_listPlayers.GetItemCount();
for (int i = 0; i < cPlayers; ++i)
{
CString str(m_listPlayers.GetItemText(i, c_iColumnTeam));
if (str == strTeam)
m_listPlayers.SetItemText(i, c_iColumnTeam, strTeamNew);
}
}
BOOL CPagePlayers::OnInitDialog()
{
GetSheet()->GetSession()->ActivateEvents(EventID_GameCreated, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_GameDestroyed, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_LoginGame, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_LogoutGame, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_ShipChangesSectors, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_LeaveTeam, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_JoinTeam, -1);
GetSheet()->GetSession()->ActivateEvents(EventID_TeamInfoChange, -1);
CPropertyPage::OnInitDialog();
m_AutoSizer.SetWindowAndRules(*this, _AutoSizerMap);
DWORD dwExStyle = LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP;
m_listPlayers.SetExtendedStyle(dwExStyle);
m_listPlayers.InsertColumn(c_iColumnName , CString((LPCSTR)IDS_COLUMN_PLAYER));
m_listPlayers.InsertColumn(c_iColumnTeam , CString((LPCSTR)IDS_COLUMN_TEAM ));
m_listPlayers.InsertColumn(c_iColumnSector, CString((LPCSTR)IDS_COLUMN_SECTOR));
LoadFromRegistry();
UpdateData(false);
UpdateUI();
PopulatePlayersList();
return true;
}
void CPagePlayers::OnEndDragPlayerList(NMHDR* pNMHDR, LRESULT* pResult)
{
HD_NOTIFY* phdn = (HD_NOTIFY*)pNMHDR;
if (pNMHDR->hwndFrom != m_listPlayers.GetHeaderCtrl()->GetSafeHwnd())
return;
KillTimer(c_idTimerReorder);
SetTimer(c_idTimerReorder, c_dwDelayReorder, NULL);
*pResult = 0;
}
void CPagePlayers::OnEndTrackPlayerList(NMHDR* pNMHDR, LRESULT* pResult)
{
HD_NOTIFY* phdn = (HD_NOTIFY*)pNMHDR;
if (pNMHDR->hwndFrom != m_listPlayers.GetHeaderCtrl()->GetSafeHwnd())
return;
KillTimer(c_idTimerResize);
SetTimer(c_idTimerResize, c_dwDelayResize, NULL);
*pResult = 0;
}
void CPagePlayers::OnTimer(UINT nIDEvent)
{
switch (nIDEvent)
{
case c_idTimerReorder:
KillTimer(nIDEvent);
SavePlayerListColumnOrderToRegistry();
return;
case c_idTimerResize:
KillTimer(nIDEvent);
SavePlayerListColumnWidthsToRegistry();
return;
}
CPropertyPage::OnTimer(nIDEvent);
}
void CPagePlayers::OnItemChangedPlayerList(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMLV = reinterpret_cast<NM_LISTVIEW*>(pNMHDR);
if (pNMLV->uChanged & LVIF_STATE)
UpdateUI();
*pResult = 0;
}
void CPagePlayers::OnDeleteItemPlayerList(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMLV = reinterpret_cast<NM_LISTVIEW*>(pNMHDR);
IAdminShip* pShip = reinterpret_cast<IAdminShip*>(pNMLV->lParam);
_ASSERTE(pShip);
pShip->Release();
*pResult = 0;
}
void CPagePlayers::OnBootPlayers()
{
HRESULT hr;
LPCSTR pszContext = "booting player from the game";
int cSelected = m_listPlayers.GetSelectedCount();
_ASSERTE(cSelected);
CString strText;
if (1 == cSelected)
strText.LoadString(IDS_BOOT_SELECTED_ONE);
else
strText.Format(IDS_BOOT_SELECTED, cSelected);
UINT nFlags = MB_ICONQUESTION | MB_YESNO;
int nResponse = MessageBox(strText, NULL, nFlags);
if (IDYES != nResponse)
return;
POSITION it = m_listPlayers.GetFirstSelectedItemPosition();
while (it)
{
int iIndex = m_listPlayers.GetNextSelectedItem(it);
_ASSERTE(-1 != iIndex);
DWORD dwItemData = m_listPlayers.GetItemData(iIndex);
IAdminShip* pShip = reinterpret_cast<IAdminShip*>(dwItemData);
_ASSERTE(pShip);
IAdminUserPtr spUser;
if (FAILED(hr = pShip->get_User(&spUser)))
{
GetSheet()->HandleError(hr, pszContext, false);
return;
}
if (FAILED(hr = spUser->Boot()))
{
GetSheet()->HandleError(hr, pszContext, false);
return;
}
}
m_listPlayers.SetFocus();
m_btnBootPlayers.SetButtonStyle(
m_btnBootPlayers.GetButtonStyle() & ~BS_DEFPUSHBUTTON);
}