|
|
//***************************************************************************
//
// DETAILSVIEW.CPP
//
// Module: NLB Manager
//
// Purpose: Implements DetailsView, the right-hand details list view.
//
// Copyright (c)2001-2002 Microsoft Corporation, All Rights Reserved
//
// History:
//
// 07/30/01 JosephJ Created
//
//***************************************************************************
#include "precomp.h"
#pragma hdrstop
#include "private.h"
#include "PortsPage.h"
#include "detailsview.tmh"
IMPLEMENT_DYNCREATE( DetailsView, CFormView )
BEGIN_MESSAGE_MAP( DetailsView, CFormView )
ON_NOTIFY(HDN_ITEMCLICK, 0, OnColumnClick) ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_DETAILS, OnNotifyKeyDown) ON_WM_SIZE()
END_MESSAGE_MAP()
DetailsView::DetailsView() : CFormView(IDD_DIALOG_DETAILSVIEW), m_initialized(FALSE), m_fPrepareToDeinitialize(FALSE) { InitializeCriticalSection(&m_crit); }
DetailsView::~DetailsView() { DeleteCriticalSection(&m_crit); }
void DetailsView::DoDataExchange(CDataExchange* pDX) { // IDC_TEXT_DETAILS_CAPTION
// TRACE_CRIT(L"<-> %!FUNC!");
CFormView::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_DETAILS, m_ListCtrl); }
Document* DetailsView::GetDocument() { return ( Document *) m_pDocument; }
/*
* Method: OnSize * Description: This method is called by the WM_NOTIFY handler whenever * a re-sizing of the details view occurs as the result of * a window re-size or moving one of the window splitters. */ void DetailsView::OnSize( UINT nType, int cx, int cy ) { /* Call the Parent class OnSize method first. */ CFormView::OnSize( nType, cx, cy );
/* Call Resize to re-size the list view to fit the window. */ Resize(); }
/*
* Method: Resize * Description: This method is called in several places to specifically * re-size the listview control to fit the window. */ void DetailsView::Resize() { /* If the window has not yet been initialized, don't bother.
This member is set in OnInitialUpdate. */ if (m_initialized) { LONG Bottom; RECT Rect; /* Get a pointer to the caption edit box. */ CWnd * ListCaption = GetDlgItem(IDC_TEXT_DETAILS_CAPTION);
/* Get a pointer to the listview control. */ CListCtrl & ListCtrl = GetListCtrl();
/* Get the client rectangle of the caption dialog, which
stretches across the top of the window. */ ListCaption->GetClientRect(&Rect); /* Note the location of the bottom. */ Bottom = Rect.bottom; /* Now, get the client rectangle of the entire frame. */ GetClientRect(&Rect); /* Re-set the top to be the bottom of the caption, plus
a little bit of empty space. */ Rect.top = Bottom + 6; /* Re-set the window location of the LISTVIEW (Note: not
the frame, just the listview). Basically, we're re- sizing the listview to be the same as the frame, but with its top equal to the bottom of the caption. */ ListCtrl.MoveWindow(&Rect, TRUE); } }
void DetailsView::OnInitialUpdate() {
this->UpdateData(FALSE);
//
// register
// with the document class,
//
GetDocument()->registerDetailsView(this);
// initially nothing has been clicked.
m_sort_column = -1;
/* Mark the frame as initialized. This is needed
by the Resize notification callback. */ m_initialized = TRUE;
/* Set the initial size of the listview. */ Resize(); }
void DetailsView::OnColumnClick(NMHDR* pNotifyStruct, LRESULT* pResult) { TRACE_CRIT(L"<->%!FUNC!"); PortListUtils::OnColumnClick( (LPNMLISTVIEW) pNotifyStruct, REF GetListCtrl(), FALSE, // FALSE == is host level
REF m_sort_ascending, REF m_sort_column );
}
//
// Handle a selection change notification from the left (tree) view
//
void DetailsView::HandleLeftViewSelChange( IN IUICallbacks::ObjectType objtype, IN ENGINEHANDLE ehId ) { mfn_Lock();
if (m_fPrepareToDeinitialize) { goto end; }
if (ehId == NULL) { // Root view ...
mfn_InitializeRootDisplay(); goto end; }
switch(objtype) { case IUICallbacks::OBJ_CLUSTER: mfn_InitializeClusterDisplay(ehId); break;
case IUICallbacks::OBJ_INTERFACE: mfn_InitializeInterfaceDisplay(ehId); break; default: // other object type unexpected
ASSERT(FALSE); break; }
end:
mfn_Unlock();
return; }
//
// Handle an event relating to a specific instance of a specific
// object type.
//
void DetailsView::HandleEngineEvent( IN IUICallbacks::ObjectType objtype, IN ENGINEHANDLE ehClusterId, // could be NULL
IN ENGINEHANDLE ehObjId, IN IUICallbacks::EventCode evt ) { if (m_fPrepareToDeinitialize) { goto end; }
mfn_Lock();
// DummyAction(L"DetailsView::HandleEngineEvent");
//
// If the object and type matches our, we'll re-draw our display...
//
if ((m_objType == objtype) && (m_ehObj == ehObjId)) { //
// It's us -- re-draw...
//
HandleLeftViewSelChange(objtype, ehObjId); } else if ((m_objType == IUICallbacks::OBJ_CLUSTER) && (m_ehObj == ehClusterId)) { //
// We're showing a cluster and this event is for one of our
// interfaces -- for now we'll redraw ourselves. An optimization
// would be to just re-draw that list element that represents the
// interface.
//
HandleLeftViewSelChange(m_objType, m_ehObj); } else if ((m_objType == IUICallbacks::OBJ_INVALID) && (objtype == IUICallbacks::OBJ_CLUSTER)) { //
// We're showing the root display (list of clusters and this
// event is a cluster update, so we need to refresh.
//
HandleLeftViewSelChange(objtype, NULL); } mfn_Unlock();
end: return;
}
void DetailsView::mfn_InitializeRootDisplay(VOID) //
// Initialize the details-view display with the root is selected.
//
{
vector <ENGINEHANDLE> ClusterList; vector <ENGINEHANDLE>::iterator iCluster; CListCtrl& ctrl = GetListCtrl(); CLocalLogger logDescription; NLBERROR nerr; int i = 0;
enum { COL_CL_NAME, COL_CL_IP_ADDR, COL_CL_IP_MASK, COL_CL_MODE, COL_CL_RCT_ENABLED };
mfn_Clear();
logDescription.Log( IDS_DETAILS_ROOT_DESCRIPTION );
mfn_UpdateCaption(logDescription.GetStringSafe());
ctrl.SetImageList( GetDocument()->m_images48x48, LVSIL_SMALL );
ctrl.InsertColumn( COL_CL_NAME, GETRESOURCEIDSTRING(IDS_DETAILS_COL_CLUSTER_NAME), // L"Cluster name",
LVCFMT_LEFT, 175 ); ctrl.InsertColumn( COL_CL_IP_ADDR, GETRESOURCEIDSTRING(IDS_DETAILS_COL_CIP), // L"Cluster IP address",
LVCFMT_LEFT, 140 ); ctrl.InsertColumn( COL_CL_IP_MASK, GETRESOURCEIDSTRING(IDS_DETAILS_COL_CIPMASK), // L"Cluster IP subnet mask",
LVCFMT_LEFT, 140 ); ctrl.InsertColumn( COL_CL_MODE, GETRESOURCEIDSTRING(IDS_DETAILS_COL_CMODE), // L"Cluster mode",
LVCFMT_LEFT, 100 ); ctrl.InsertColumn( COL_CL_RCT_ENABLED, GETRESOURCEIDSTRING(IDS_DETAILS_RCT_STATUS), // L"Remote control status",
LVCFMT_LEFT, 125 );
nerr = gEngine.EnumerateClusters(ClusterList);
if (FAILED(nerr)) goto end;
for (iCluster = ClusterList.begin(); iCluster != ClusterList.end(); iCluster++) { ENGINEHANDLE ehCluster = (ENGINEHANDLE)*iCluster; CClusterSpec cSpec; INT iIcon; LPCWSTR szClusterIp = L""; LPCWSTR szClusterMask = L""; LPCWSTR szClusterName = L""; LPCWSTR szClusterMode = L""; LPCWSTR szClusterRctEnabled = L""; const WLBS_REG_PARAMS * pParams; nerr = gEngine.GetClusterSpec(ehCluster, REF cSpec);
if (FAILED(nerr)) goto end;
if (cSpec.m_ClusterNlbCfg.IsValidNlbConfig()) { pParams = &cSpec.m_ClusterNlbCfg.NlbParams;
szClusterName = pParams->domain_name; szClusterIp= pParams->cl_ip_addr; szClusterMask= pParams->cl_net_mask; szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_UNICAST); //"unicast";
if (pParams->mcast_support) { if (pParams->fIGMPSupport) { szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_IGMP); //"IGMP multicast";
} else { szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_MULTI); //"multicast";
} } if (pParams->rct_enabled) { szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_ENABLED); //"enabled";
} else { szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_DISABLED); //"disabled";
}
if (cSpec.m_fMisconfigured) { iIcon = Document::ICON_CLUSTER_BROKEN; } else { iIcon = Document::ICON_CLUSTER_OK; }
//
// Insert all the columns...
//
ctrl.InsertItem( LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
i, szClusterName, // text
0, // nState
0, // nStateMask
iIcon, (LPARAM) ehCluster // lParam
); ctrl.SetItemText( i, COL_CL_IP_ADDR, szClusterIp); ctrl.SetItemText( i, COL_CL_IP_MASK, szClusterMask); ctrl.SetItemText( i, COL_CL_MODE, szClusterMode); ctrl.SetItemText( i, COL_CL_RCT_ENABLED, szClusterRctEnabled);
i++; } }
end:
return; }
void DetailsView::mfn_InitializeClusterDisplay(ENGINEHANDLE ehCluster) //
// Initialize the details-view display with a cluster is selected.
//
{ NLBERROR nerr; CClusterSpec cSpec; CListCtrl& ctrl = GetListCtrl(); CLocalLogger logDescription; enum { COL_INTERFACE_NAME=0, COL_STATUS, COL_DED_IP_ADDR, COL_DED_IP_MASK, COL_HOST_PRIORITY, COL_HOST_INITIAL_STATE };
mfn_Clear();
nerr = gEngine.GetClusterSpec( ehCluster, REF cSpec ); if (FAILED(nerr)) goto end;
if (cSpec.m_ClusterNlbCfg.IsValidNlbConfig()) { logDescription.Log( IDS_DETAILS_CLUSTER_DESCRIPTION, cSpec.m_ClusterNlbCfg.NlbParams.domain_name, cSpec.m_ClusterNlbCfg.NlbParams.cl_ip_addr ); }
mfn_UpdateCaption(logDescription.GetStringSafe());
ctrl.SetImageList( GetDocument()->m_images48x48, LVSIL_SMALL );
ctrl.InsertColumn( COL_INTERFACE_NAME, GETRESOURCEIDSTRING(IDS_DETAILS_COL_HOST), // L"Host(Interface)",
LVCFMT_LEFT, 175 ); ctrl.InsertColumn( COL_STATUS, GETRESOURCEIDSTRING(IDS_DETAILS_COL_STATUS), // L"Status",
LVCFMT_LEFT, 85 ); ctrl.InsertColumn( COL_DED_IP_ADDR, GETRESOURCEIDSTRING(IDS_DETAILS_COL_DIP), // L"Dedicated IP address",
LVCFMT_LEFT, 140 ); ctrl.InsertColumn( COL_DED_IP_MASK, GETRESOURCEIDSTRING(IDS_DETAILS_COL_DIPMASK), // L"Dedicated IP subnet mask",
LVCFMT_LEFT, 140 ); ctrl.InsertColumn( COL_HOST_PRIORITY, GETRESOURCEIDSTRING(IDS_DETAILS_COL_PRIORITY), // L"Host priority",
LVCFMT_LEFT, 75 ); ctrl.InsertColumn( COL_HOST_INITIAL_STATE, GETRESOURCEIDSTRING(IDS_DETAILS_COL_INIT_STATE), // L"Initial host state",
LVCFMT_LEFT, 100 );
//
// Now we loop through the interfaces in the cluster, adding one line of
// information on each;
//
for( int i = 0; i < cSpec.m_ehInterfaceIdList.size(); ++i ) { CInterfaceSpec iSpec; CHostSpec hSpec; _bstr_t bstrStatus; _bstr_t bstrDisplayName; ENGINEHANDLE ehIID = cSpec.m_ehInterfaceIdList[i]; INT iIcon = 0; WBEMSTATUS wStat; LPCWSTR szDisplayName = L""; LPCWSTR szStatus = L""; LPCWSTR szDedIp = L""; LPCWSTR szDedMask = L""; LPCWSTR szHostPriority = L""; LPCWSTR szHostInitialState = L""; WCHAR rgPriority[64]; WCHAR rgInitialState[64]; const WLBS_REG_PARAMS *pParams = &iSpec.m_NlbCfg.NlbParams;
nerr = gEngine.GetInterfaceInformation( ehIID, REF hSpec, REF iSpec, REF bstrDisplayName, REF iIcon, REF bstrStatus ); if (NLBFAILED(nerr)) { continue; } else { szDisplayName = bstrDisplayName; szStatus = bstrStatus; }
if (iSpec.m_NlbCfg.IsValidNlbConfig()) { szDedIp = pParams->ded_ip_addr; szDedMask = pParams->ded_net_mask;
StringCbPrintf(rgPriority, sizeof(rgPriority), L"%lu", pParams->host_priority); szHostPriority = rgPriority;
// szHostInitialState
switch(pParams->cluster_mode) { case CVY_HOST_STATE_STARTED: szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_STARTED); // L"started";
break;
case CVY_HOST_STATE_STOPPED: szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_STOPPED); // L"stopped";
break;
case CVY_HOST_STATE_SUSPENDED: szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_SUSPENDED); // L"suspended";
break;
default: szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_UNKNOWN); // L"unknown";
break; }
if (pParams->persisted_states & CVY_PERSIST_STATE_SUSPENDED) { StringCbPrintf( rgInitialState, sizeof(rgInitialState), (LPCWSTR) GETRESOURCEIDSTRING(IDS_DETAILS_PERSIST_SUSPEND), // L"%ws, persist suspend"
szHostInitialState); szHostInitialState = rgInitialState; } }
//
// Insert all the columns...
//
ctrl.InsertItem( LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
i, szDisplayName, // text
0, // nState
0, // nStateMask
iIcon, (LPARAM) ehIID // lParam
); ctrl.SetItemText( i, COL_STATUS, szStatus); ctrl.SetItemText( i, COL_DED_IP_ADDR, szDedIp); ctrl.SetItemText( i, COL_DED_IP_MASK, szDedMask); ctrl.SetItemText( i, COL_HOST_PRIORITY, szHostPriority); ctrl.SetItemText( i, COL_HOST_INITIAL_STATE, szHostInitialState); }
//
// Keep track of which object we're displaying...
//
m_ehObj = ehCluster; m_objType = IUICallbacks::OBJ_CLUSTER;
end: return; }
void DetailsView::mfn_InitializeInterfaceDisplay(ENGINEHANDLE ehInterface) //
// Initialize the details-view display when an interface in a cluster is
// selected.
//
{ NLBERROR nerr; CInterfaceSpec ISpec; CListCtrl& ctrl = GetListCtrl();
mfn_Clear();
nerr = gEngine.GetInterfaceSpec(ehInterface, REF ISpec);
if (NLBFAILED(nerr)) { goto end; }
//
// Fill out the caption with host name and interface name...
//
{ WBEMSTATUS wStat; LPWSTR szAdapter = L""; LPCWSTR szHostName = L""; CHostSpec hSpec; CLocalLogger log;
nerr = gEngine.GetHostSpec( ISpec.m_ehHostId, REF hSpec ); if (NLBOK(nerr)) { szHostName = (LPCWSTR) hSpec.m_MachineName; if (szHostName == NULL) { szHostName = L""; } }
wStat = ISpec.m_NlbCfg.GetFriendlyName(&szAdapter); if (FAILED(wStat)) { szAdapter = NULL; }
if (szAdapter == NULL) szAdapter = L""; log.Log( IDS_DETAILS_PORT_CAPTION, szHostName, szAdapter ); delete szAdapter;
mfn_UpdateCaption(log.GetStringSafe()); }
PortListUtils::LoadFromNlbCfg( &ISpec.m_NlbCfg, ctrl, FALSE, // FALSE == is host-level
TRUE // TRUE == displaying in the details view
); //
// Keep track of which object we're displaying...
//
m_ehObj = ehInterface; m_objType = IUICallbacks::OBJ_INTERFACE;
end:
return; }
void DetailsView::mfn_UpdateInterfaceInClusterDisplay( ENGINEHANDLE ehInterface, BOOL fDelete ) //
// Update or delete the specified interface from the cluster view.
// Assumes that a cluster is selected in the left view.
//
{ }
void DetailsView::mfn_Clear(void) //
// Delete all items and all columns in the list
//
{ CListCtrl& ctrl = GetListCtrl(); ctrl.DeleteAllItems();
// Delete all of the previous columns.
LV_COLUMN colInfo; ZeroMemory(&colInfo, sizeof(colInfo)); colInfo.mask = LVCF_SUBITEM;
while(ctrl.GetColumn(0, &colInfo)) { ctrl.DeleteColumn(0); } ctrl.SetImageList( NULL, LVSIL_SMALL ); mfn_UpdateCaption(L"");
//
// Clear currently displayed object handle and it's type.
//
m_ehObj = NULL; m_objType = IUICallbacks::OBJ_INVALID; }
VOID DetailsView::mfn_UpdateCaption(LPCWSTR szText) { SetDlgItemText(IDC_TEXT_DETAILS_CAPTION, szText); }
void DetailsView::mfn_Lock(void) { //
// See notes.txt entry
// 01/23/2002 JosephJ DEADLOCK in Leftview::mfn_Lock
// for the reason for this convoluted implementation of mfn_Lock
//
while (!TryEnterCriticalSection(&m_crit)) { ProcessMsgQueue(); Sleep(100); } }
void DetailsView::Deinitialize(void) { TRACE_INFO(L"-> %!FUNC!"); ASSERT(m_fPrepareToDeinitialize); // DummyAction(L"Details::Deinitialize");
TRACE_INFO(L"<- %!FUNC!"); }
void DetailsView::OnNotifyKeyDown( NMHDR* pNMHDR, LRESULT* pResult ) { TRACE_CRIT(L"<->%!FUNC!"); NMLVKEYDOWN *pkd = (NMLVKEYDOWN *) pNMHDR;
if (pkd->wVKey == VK_F6 || pkd->wVKey == VK_TAB) { *pResult = 0; if (! (::GetAsyncKeyState(VK_SHIFT) & 0x8000)) { GetDocument()->SetFocusNextView(this, (int) pkd->wVKey); } else { GetDocument()->SetFocusPrevView(this, (int) pkd->wVKey); } } }
void DetailsView::SetFocus(void) {
//
// We override our SetFocus, because we really need to set the focus
// on our list control, and also select a listview item if there isn't
// one selected...
//
CListCtrl& ctrl = GetListCtrl(); POSITION pos = NULL; pos = ctrl.GetFirstSelectedItemPosition();
//
// If no item is selected, select one...
//
if(pos == NULL) { ctrl.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED); }
ctrl.SetFocus(); }
|