WindowsXP-SP1/enduser/netmeeting/ui/conf/roomlist.cpp
2020-09-30 16:53:49 +02:00

797 lines
19 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// File: roomlist.cpp
#include "precomp.h"
#include "resource.h"
#include "ConfRoom.h"
#include "RoomList.h"
#include "RToolbar.h"
#include "VidView.h"
#include "RostInfo.h"
#include "particip.h"
static const int RL_NUM_ICON_COLUMNS = 0;
/* C R O O M L I S T V I E W */
/*-------------------------------------------------------------------------
%%Function: CRoomListView
-------------------------------------------------------------------------*/
CRoomListView::CRoomListView():
// m_iSortColumn (0),
m_lUserData(0),
m_fSortAscending (TRUE)
{
DbgMsg(iZONE_OBJECTS, "Obj: %08X created CRoomListView", this);
}
CRoomListView::~CRoomListView()
{
ListView_DeleteAllItems(m_hWnd);
if(IsWindow())
{
DestroyWindow();
}
DbgMsg(iZONE_OBJECTS, "Obj: %08X destroyed CRoomListView", this);
}
CParticipant * CRoomListView::GetParticipant(void)
{
LPARAM lParam = GetSelectedLParam();
return (CParticipant *) lParam;
}
//////////////////////////////////////////////////////////////////////////
// CRoomListView::CView
VOID CRoomListView::Show(BOOL fVisible)
{
if (NULL != m_hWnd)
{
::ShowWindow(m_hWnd, fVisible ? SW_SHOW : SW_HIDE);
}
}
VOID CRoomListView::ShiftFocus(HWND hwndCur, BOOL fForward)
{
if ((NULL == hwndCur) && (NULL != m_hWnd))
{
::SetFocus(m_hWnd);
}
}
VOID CRoomListView::Redraw(void)
{
if (NULL == m_hWnd)
return;
// Invalidate entire client area and force erase:
::InvalidateRect(m_hWnd, NULL, TRUE);
// Force an immediate repaint:
::UpdateWindow(m_hWnd);
}
VOID CRoomListView::ForwardSysChangeMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Pass all messages to the list view window:
if (NULL != m_hWnd)
{
::SendMessage(m_hWnd, uMsg, wParam, lParam);
}
}
BOOL CRoomListView::Create(HWND hwndParent)
{
DBGENTRY(CRoomListView::FCreate);
RECT rcPos;
SetRect( &rcPos, 0, 0, 0, 0 );
DWORD dwStyle = WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_SHAREIMAGELISTS;
DWORD dwExStyle = WS_EX_CLIENTEDGE;
CWindowImpl<CRoomListView>::Create( hwndParent, rcPos, g_szEmpty, dwStyle, dwExStyle, ID_LISTVIEW );
if (NULL == m_hWnd)
return FALSE;
// initialize the list view window
// Associate the image list with the list view
ListView_SetImageList(m_hWnd, g_himlIconSmall, LVSIL_SMALL);
// Now initialize the columns we will need
// Initialize the LV_COLUMN structure
// the mask specifies that the .fmt, .ex, width, and .subitem members
// of the structure are valid,
LV_COLUMN lvC; // List View Column structure
ClearStruct(&lvC);
TCHAR pszText[256]; // place to store some text
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvC.fmt = LVCFMT_LEFT;
SIZE size;
GetDesiredSize(&size);
int iWidth = size.cx;
// default width of the non-icon columns (-1 to prevent creating a scrollbar)
int iIconColWidth = ::GetSystemMetrics(SM_CXSMICON) + 7; // 7 additional pixels
int iTextColWidth = ((iWidth - (RL_NUM_ICON_COLUMNS * iIconColWidth))
/ (NUM_COLUMNS - RL_NUM_ICON_COLUMNS)) - 1;
lvC.pszText = pszText;
// Add the columns.
for (int index = 0; index < NUM_COLUMNS; index++)
{
HD_ITEM hdi;
hdi.mask = HDI_IMAGE | HDI_FORMAT;
hdi.fmt = HDF_IMAGE;
lvC.iSubItem = index;
switch (index)
{
case COLUMN_INDEX_NAME:
default:
{
// These are text or text&icon columns
hdi.iImage = -1;
lvC.cx = iTextColWidth;
break;
}
}
LoadString(::GetInstanceHandle(),
IDS_COLUMN_NAME + index,
pszText,
CCHMAX(pszText));
if (-1 != ListView_InsertColumn(m_hWnd, index, &lvC))
{
if (-1 != hdi.iImage)
{
ASSERT(ListView_GetHeader(m_hWnd));
Header_SetItem(ListView_GetHeader(m_hWnd), index, &hdi);
}
}
else
{
WARNING_OUT(("Could not insert column %d in list view", index));
}
}
ASSERT(ListView_GetHeader(m_hWnd));
Header_SetImageList(ListView_GetHeader(m_hWnd), g_himlIconSmall);
// set the style to do drag and drop headers and full row select
dwExStyle = ListView_GetExtendedListViewStyle(m_hWnd);
dwExStyle |= (LVS_EX_SUBITEMIMAGES | LVS_EX_HEADERDRAGDROP);
ListView_SetExtendedListViewStyle(m_hWnd, dwExStyle);
return TRUE;
}
LRESULT CRoomListView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
int cx = LOWORD(lParam);
HWND hwndHeader = ListView_GetHeader(m_hWnd);
if (NULL != hwndHeader)
{
// This check is to avoid a RIP in debug windows
ListView_SetColumnWidth(m_hWnd, 0, cx);
}
bHandled = FALSE;
return(0);
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: Add(int iPosition, LPARAM lParam)
*
* PURPOSE: Adds a item to the list view
*
****************************************************************************/
BOOL CRoomListView::Add(int iPosition, CParticipant * pPart)
{
DebugEntry(CRoomListView::Add);
BOOL bRet = FALSE;
int nPrevCount = ListView_GetItemCount(m_hWnd);
LV_ITEM lvI; // List view item structure
// Fill in the LV_ITEM structure
// The mask specifies the the .pszText, .iImage, .lParam and .state
// members of the LV_ITEM structure are valid.
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
lvI.state = (0 == nPrevCount) ? LVIS_FOCUSED : 0;
lvI.stateMask = LVIS_FOCUSED;
lvI.iItem = iPosition;
lvI.iSubItem = 0;
// The parent window is responsible for storing the text. The List view
// window will send a LVN_GETDISPINFO when it needs the text to display
lvI.pszText = LPSTR_TEXTCALLBACK;
lvI.cchTextMax = MAX_ITEMLEN;
lvI.iImage = I_IMAGECALLBACK;
lvI.lParam = (LPARAM) pPart;
if (-1 != ListView_InsertItem(m_hWnd, &lvI))
{
pPart->AddRef(); // the ListView keeps a reference on this
// set the text for each of the columns for report view
for (int iSubItem = 1; iSubItem < NUM_COLUMNS; iSubItem++)
{
ListView_SetItemText( m_hWnd,
iPosition,
iSubItem,
LPSTR_TEXTCALLBACK);
}
ListView_SortItems( m_hWnd,
CRoomListView::RoomListViewCompareProc,
(LPARAM)(this));
}
DebugExitBOOL(CRoomListView::Add, bRet);
return bRet;
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: LParamToPos(LPARAM lParam)
*
* PURPOSE: Returns the position index associated with the lParam value
*
****************************************************************************/
int CRoomListView::LParamToPos(LPARAM lParam)
{
// Note: retuns -1 on failure
LV_FINDINFO lvF;
lvF.flags = LVFI_PARAM;
lvF.lParam = lParam;
return ListView_FindItem(m_hWnd, -1, &lvF);
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: GetSelectedLParam()
*
* PURPOSE: Returns the lParam of the selected item or NULL (no sel.)
*
****************************************************************************/
LPARAM CRoomListView::GetSelectedLParam()
{
LPARAM lRet = NULL;
if (::GetFocus() == m_hWnd)
{
// The list view has the focus, so find the selected item (if any)
int iItem = ListView_GetNextItem(m_hWnd, -1, LVNI_ALL | LVNI_SELECTED);
if (-1 != iItem)
{
LV_ITEM lvi;
lvi.iItem = iItem;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
if (ListView_GetItem(m_hWnd, &lvi))
{
lRet = lvi.lParam;
}
}
}
return lRet;
}
/* R E M O V E */
/*-------------------------------------------------------------------------
%%Function: Remove
Removes an item from the list view
-------------------------------------------------------------------------*/
VOID CRoomListView::Remove(LPARAM lParam)
{
DBGENTRY(CRoomListView::Remove);
int iPosition = LParamToPos(lParam);
if (-1 == iPosition)
return;
ListView_DeleteItem(m_hWnd, iPosition);
}
/* O N C H A N G E P A R T I C I P A N T */
/*-------------------------------------------------------------------------
%%Function: OnChangeParticipant
Updates the user's status information
-------------------------------------------------------------------------*/
VOID CRoomListView::OnChangeParticipant(CParticipant * pPart, NM_MEMBER_NOTIFY uNotify)
{
DBGENTRY(CRoomListView::OnChangeParticipant);
switch (uNotify)
{
case NM_MEMBER_ADDED:
{
// Add the new member to the start of the list
Add(0, pPart);
break;
}
case NM_MEMBER_REMOVED:
{
// Remove the member from the list
Remove((LPARAM) pPart);
break;
}
case NM_MEMBER_UPDATED:
{
int iPos = LParamToPos((LPARAM) pPart);
if (-1 == iPos)
return;
ListView_RedrawItems(m_hWnd, iPos, iPos);
ListView_SortItems(m_hWnd, CRoomListView::RoomListViewCompareProc, (LPARAM)(this));
break;
}
default:
break;
}
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: OnNotify(WPARAM, LPARAM)
*
* PURPOSE: Handles WM_NOTIFY messages sent to the list view
*
****************************************************************************/
LRESULT CRoomListView::OnNotify(WPARAM wParam, LPARAM lParam)
{
LRESULT lRet = 0L;
LV_DISPINFO *pLvdi = (LV_DISPINFO *)lParam;
ASSERT(pLvdi);
if (ID_LISTVIEW == wParam)
{
switch(pLvdi->hdr.code)
{
case NM_DBLCLK:
case NM_RETURN:
{
if (0x8000 & ::GetKeyState(VK_MENU))
{
::PostMessage(::GetMainWindow(), WM_COMMAND, IDM_POPUP_PROPERTIES, 0);
}
break;
}
case NM_CLICK:
case NM_RCLICK:
{
LV_HITTESTINFO lvhi;
::GetCursorPos(&(lvhi.pt));
::MapWindowPoints(NULL, m_hWnd, &(lvhi.pt), 1);
ListView_SubItemHitTest(m_hWnd, &lvhi);
if (LVHT_ONITEMICON | lvhi.flags)
{
lRet = OnClick(&lvhi, (NM_CLICK == pLvdi->hdr.code));
}
break;
}
case LVN_DELETEITEM:
{
NM_LISTVIEW * pnmv = (NM_LISTVIEW *) lParam;
CParticipant * pPart = (CParticipant *) pnmv->lParam;
ASSERT(pPart);
if (pPart)
{
pPart->Release();
}
break;
}
case LVN_GETDISPINFO:
{
GetDispInfo(pLvdi);
break;
}
case LVN_COLUMNCLICK:
{
// The user clicked on one of the column headings - sort by
// this column.
TRACE_OUT(("CRoomListView::OnNotify called (NM_COLUMNCLICK)"));
NM_LISTVIEW *pNm = (NM_LISTVIEW *)lParam;
ASSERT(pNm);
if (pNm->iSubItem == m_iSortColumn)
{
m_fSortAscending = !m_fSortAscending;
}
else
{
m_fSortAscending = TRUE;
}
// m_iSortColumn = pNm->iSubItem;
ListView_SortItems( pNm->hdr.hwndFrom,
CRoomListView::RoomListViewCompareProc,
(LPARAM)(this));
break;
}
default:
break;
}
}
return lRet;
}
/* G E T D I S P I N F O */
/*-------------------------------------------------------------------------
%%Function: GetDispInfo
Get the display information for a participant
-------------------------------------------------------------------------*/
VOID CRoomListView::GetDispInfo(LV_DISPINFO * pLvdi)
{
CParticipant * pPart = (CParticipant *) (pLvdi->item.lParam);
if (NULL == pPart)
return;
// Get the text
if (pLvdi->item.mask & LVIF_TEXT)
{
switch (pLvdi->item.iSubItem)
{
case COLUMN_INDEX_NAME:
{
lstrcpyn(pLvdi->item.pszText, pPart->GetPszName(), pLvdi->item.cchTextMax);
break;
}
default:
break;
}
}
// Get the Image
if (pLvdi->item.mask & LVIF_IMAGE)
{
switch (pLvdi->item.iSubItem)
{
case COLUMN_INDEX_NAME:
{
pLvdi->item.iImage = II_USER;
break;
}
default:
break;
}
}
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: LoadColumnInfo(RegEntry* pre)
*
* PURPOSE: Loads the column position info in the registry
*
****************************************************************************/
BOOL CRoomListView::LoadSettings(RegEntry* pre)
{
DebugEntry(CRoomListView::LoadColumnInfo);
// BUGBUG georgep: Using a fixed initial width for now; should take a max
// of longest name and the window width
ListView_SetColumnWidth(m_hWnd, 0, 300);
DebugExitBOOL(CRoomListView::LoadColumnInfo, TRUE);
return TRUE;
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: OnClick(LV_HITTESTINFO*, BOOL)
*
* PURPOSE: Handles creating a popup menu when clicking on some icons
*
****************************************************************************/
/* O N C L I C K */
/*-------------------------------------------------------------------------
%%Function: OnClick
Handles creating a popup menu when clicking on some icons
-------------------------------------------------------------------------*/
LRESULT CRoomListView::OnClick(LV_HITTESTINFO* plvhi, BOOL fLeftClick)
{
ASSERT(NULL != plvhi);
// Select the item:
ListView_SetItemState(m_hWnd, plvhi->iItem,
LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
switch (plvhi->iSubItem)
{
case COLUMN_INDEX_NAME:
{
if (fLeftClick)
return 0; // selection
break;
}
default:
return 0;
}
// convert back to screen coords
::MapWindowPoints(m_hWnd, NULL, &(plvhi->pt), 1);
OnPopup(plvhi->pt);
return 1;
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: OnPopup(POINT)
*
* PURPOSE: Handles popup menu
*
****************************************************************************/
BOOL CRoomListView::OnPopup(POINT pt)
{
CParticipant * pPart = GetParticipant();
if (NULL == pPart)
return FALSE;
// Get the menu for the popup from the resource file.
HMENU hMenu = LoadMenu(::GetInstanceHandle(), MAKEINTRESOURCE(IDR_USER_POPUP));
if (NULL == hMenu)
return FALSE;
// Get the first menu in it which we will use for the call to
// TrackPopup(). This could also have been created on the fly using
// CreatePopupMenu and then we could have used InsertMenu() or
// AppendMenu.
HMENU hMenuTrackPopup = GetSubMenu(hMenu, 0);
ASSERT(NULL != hMenuTrackPopup);
::EnableMenuItem(hMenuTrackPopup, IDM_POPUP_SPEEDDIAL,
pPart->FEnableCmdCreateSpeedDial() ? MF_ENABLED : MF_GRAYED);
::EnableMenuItem(hMenuTrackPopup, IDM_POPUP_ADDRESSBOOK,
pPart->FEnableCmdCreateWabEntry() ? MF_ENABLED : MF_GRAYED);
::EnableMenuItem(hMenuTrackPopup, IDM_POPUP_EJECT,
pPart->FEnableCmdEject() ? MF_ENABLED : MF_GRAYED);
// GiveControl/CancelGiveControl()
pPart->CalcControlCmd(hMenuTrackPopup);
BOOL fShowMenu = TRUE;
// Check to see if we have "special" coordinates that signify
// that we entered here as a result of a keyboard click
// instead of a mouse click - and if so, get some default coords
if ((0xFFFF == pt.x) && (0xFFFF == pt.y))
{
int iPos = LParamToPos((LPARAM)pPart);
RECT rctIcon;
if ((-1 == iPos) ||
(FALSE == ListView_GetItemRect( m_hWnd,
iPos,
&rctIcon,
LVIR_ICON)))
{
fShowMenu = FALSE;
}
else
{
// Convert from client coords to screen coords
::MapWindowPoints(m_hWnd, NULL, (LPPOINT)&rctIcon, 2);
pt.x = rctIcon.left + ((rctIcon.right - rctIcon.left) / 2);
pt.y = rctIcon.top + ((rctIcon.bottom - rctIcon.top) / 2);
}
}
if (fShowMenu)
{
HWND hwnd = ::GetMainWindow();
// Draw and track the "floating" popup
int cmd = TrackPopupMenu( hMenuTrackPopup,
TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
pt.x,
pt.y,
0,
hwnd,
NULL);
// Get this again since we just ended a message loop
pPart = GetParticipant();
if (0 != cmd && NULL != pPart)
{
pPart->OnCommand(hwnd, (WORD)cmd);
}
}
// We are finished with the menu now, so destroy it
DestroyMenu(hMenu);
return TRUE;
}
/****************************************************************************
*
* CLASS: CRoomListView
*
* MEMBER: Callback used for sorting the list view
*
****************************************************************************/
int CALLBACK CRoomListView::RoomListViewCompareProc(LPARAM lParam1,
LPARAM lParam2,
LPARAM lParamSort)
{
DebugEntry(RoomListViewCompareProc);
CParticipant * pPart1 = (CParticipant *)lParam1;
CParticipant * pPart2 = (CParticipant *)lParam2;
CRoomListView* prlv = (CRoomListView*) lParamSort;
ASSERT(prlv);
int iResult = 0;
if (pPart1 && pPart2)
{
switch (prlv->m_iSortColumn)
{
case COLUMN_INDEX_NAME:
{
LPTSTR lpStr1 = pPart1->GetPszName();
LPTSTR lpStr2 = pPart2->GetPszName();
iResult = lstrcmpi(lpStr1, lpStr2);
break;
}
default:
{
ERROR_OUT(("Sorting by unknown label"));
break;
}
}
}
if (!prlv->m_fSortAscending)
{
iResult = -iResult;
}
DebugExitINT(RoomListViewCompareProc, iResult);
return iResult;
}
VOID TileBltWatermark(UINT x, UINT y, UINT cx, UINT cy, UINT xOff, UINT yOff, HDC hdcDst, HDC hdcSrc,
UINT cxWatermark, UINT cyWatermark)
{
DBGENTRY(CRoomListView::TileBltWatermark)
int cxPart, cyPart;
BOOL fxTile, fyTile;
ReCheck:
fxTile = ((xOff + cx) > cxWatermark);
fyTile = ((yOff + cy) > cyWatermark);
if (!fxTile && !fyTile)
{
// no tiling needed -- blt and leave
BitBlt(hdcDst, x, y, cx, cy, hdcSrc, xOff, yOff, SRCCOPY);
DBGEXIT(CRoomListView::TileBltWatermark)
return;
}
if (!fxTile)
{
// vertically tile
cyPart = cyWatermark - yOff;
BitBlt(hdcDst, x, y, cx, cyPart, hdcSrc, xOff, yOff, SRCCOPY);
y += cyPart;
cy -= cyPart;
yOff = 0;
goto ReCheck;
}
if (!fyTile)
{
// horizontally tile
cxPart = cxWatermark - xOff;
BitBlt(hdcDst, x, y, cxPart, cy, hdcSrc, xOff, yOff, SRCCOPY);
x += cxPart;
cx -= cxPart;
xOff = 0;
goto ReCheck;
}
// tile both ways
cyPart = cyWatermark - yOff;
TileBltWatermark(x, y, cx, cyPart, xOff, yOff, hdcDst, hdcSrc, cxWatermark, cyWatermark);
y += cyPart;
cy -= cyPart;
yOff = 0;
goto ReCheck;
}
void CRoomListView::GetDesiredSize(SIZE *ppt)
{
// BUGBUG georgep: faking these numbers; should use something dependent on the font size
ppt->cx = 200;
ppt->cy = 100;
}
// a quick but simple function to convert the "unicode" characters
// from the H.245 roster info struct to ascii
int Unicode4ToAsciiOEM009(char *szIn, char *szOut)
{
while (*szIn)
{
*szOut = (*szIn) - 4;
szIn++;
szOut++;
}
*szOut = '\0';
return 0;
}