Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

797 lines
21 KiB

  1. //***************************************************************************
  2. //
  3. // DETAILSVIEW.CPP
  4. //
  5. // Module: NLB Manager
  6. //
  7. // Purpose: Implements DetailsView, the right-hand details list view.
  8. //
  9. // Copyright (c)2001-2002 Microsoft Corporation, All Rights Reserved
  10. //
  11. // History:
  12. //
  13. // 07/30/01 JosephJ Created
  14. //
  15. //***************************************************************************
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include "private.h"
  19. #include "PortsPage.h"
  20. #include "detailsview.tmh"
  21. IMPLEMENT_DYNCREATE( DetailsView, CFormView )
  22. BEGIN_MESSAGE_MAP( DetailsView, CFormView )
  23. ON_NOTIFY(HDN_ITEMCLICK, 0, OnColumnClick)
  24. ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_DETAILS, OnNotifyKeyDown)
  25. ON_WM_SIZE()
  26. END_MESSAGE_MAP()
  27. DetailsView::DetailsView()
  28. : CFormView(IDD_DIALOG_DETAILSVIEW),
  29. m_initialized(FALSE),
  30. m_fPrepareToDeinitialize(FALSE)
  31. {
  32. InitializeCriticalSection(&m_crit);
  33. }
  34. DetailsView::~DetailsView()
  35. {
  36. DeleteCriticalSection(&m_crit);
  37. }
  38. void DetailsView::DoDataExchange(CDataExchange* pDX)
  39. {
  40. // IDC_TEXT_DETAILS_CAPTION
  41. // TRACE_CRIT(L"<-> %!FUNC!");
  42. CFormView::DoDataExchange(pDX);
  43. DDX_Control(pDX, IDC_LIST_DETAILS, m_ListCtrl);
  44. }
  45. Document*
  46. DetailsView::GetDocument()
  47. {
  48. return ( Document *) m_pDocument;
  49. }
  50. /*
  51. * Method: OnSize
  52. * Description: This method is called by the WM_NOTIFY handler whenever
  53. * a re-sizing of the details view occurs as the result of
  54. * a window re-size or moving one of the window splitters.
  55. */
  56. void
  57. DetailsView::OnSize( UINT nType, int cx, int cy )
  58. {
  59. /* Call the Parent class OnSize method first. */
  60. CFormView::OnSize( nType, cx, cy );
  61. /* Call Resize to re-size the list view to fit the window. */
  62. Resize();
  63. }
  64. /*
  65. * Method: Resize
  66. * Description: This method is called in several places to specifically
  67. * re-size the listview control to fit the window.
  68. */
  69. void
  70. DetailsView::Resize()
  71. {
  72. /* If the window has not yet been initialized, don't bother.
  73. This member is set in OnInitialUpdate. */
  74. if (m_initialized) {
  75. LONG Bottom;
  76. RECT Rect;
  77. /* Get a pointer to the caption edit box. */
  78. CWnd * ListCaption = GetDlgItem(IDC_TEXT_DETAILS_CAPTION);
  79. /* Get a pointer to the listview control. */
  80. CListCtrl & ListCtrl = GetListCtrl();
  81. /* Get the client rectangle of the caption dialog, which
  82. stretches across the top of the window. */
  83. ListCaption->GetClientRect(&Rect);
  84. /* Note the location of the bottom. */
  85. Bottom = Rect.bottom;
  86. /* Now, get the client rectangle of the entire frame. */
  87. GetClientRect(&Rect);
  88. /* Re-set the top to be the bottom of the caption, plus
  89. a little bit of empty space. */
  90. Rect.top = Bottom + 6;
  91. /* Re-set the window location of the LISTVIEW (Note: not
  92. the frame, just the listview). Basically, we're re-
  93. sizing the listview to be the same as the frame, but
  94. with its top equal to the bottom of the caption. */
  95. ListCtrl.MoveWindow(&Rect, TRUE);
  96. }
  97. }
  98. void
  99. DetailsView::OnInitialUpdate()
  100. {
  101. this->UpdateData(FALSE);
  102. //
  103. // register
  104. // with the document class,
  105. //
  106. GetDocument()->registerDetailsView(this);
  107. // initially nothing has been clicked.
  108. m_sort_column = -1;
  109. /* Mark the frame as initialized. This is needed
  110. by the Resize notification callback. */
  111. m_initialized = TRUE;
  112. /* Set the initial size of the listview. */
  113. Resize();
  114. }
  115. void DetailsView::OnColumnClick(NMHDR* pNotifyStruct, LRESULT* pResult)
  116. {
  117. TRACE_CRIT(L"<->%!FUNC!");
  118. PortListUtils::OnColumnClick(
  119. (LPNMLISTVIEW) pNotifyStruct,
  120. REF GetListCtrl(),
  121. FALSE, // FALSE == is host level
  122. REF m_sort_ascending,
  123. REF m_sort_column
  124. );
  125. }
  126. //
  127. // Handle a selection change notification from the left (tree) view
  128. //
  129. void
  130. DetailsView::HandleLeftViewSelChange(
  131. IN IUICallbacks::ObjectType objtype,
  132. IN ENGINEHANDLE ehId
  133. )
  134. {
  135. mfn_Lock();
  136. if (m_fPrepareToDeinitialize)
  137. {
  138. goto end;
  139. }
  140. if (ehId == NULL)
  141. {
  142. // Root view ...
  143. mfn_InitializeRootDisplay();
  144. goto end;
  145. }
  146. switch(objtype)
  147. {
  148. case IUICallbacks::OBJ_CLUSTER:
  149. mfn_InitializeClusterDisplay(ehId);
  150. break;
  151. case IUICallbacks::OBJ_INTERFACE:
  152. mfn_InitializeInterfaceDisplay(ehId);
  153. break;
  154. default: // other object type unexpected
  155. ASSERT(FALSE);
  156. break;
  157. }
  158. end:
  159. mfn_Unlock();
  160. return;
  161. }
  162. //
  163. // Handle an event relating to a specific instance of a specific
  164. // object type.
  165. //
  166. void
  167. DetailsView::HandleEngineEvent(
  168. IN IUICallbacks::ObjectType objtype,
  169. IN ENGINEHANDLE ehClusterId, // could be NULL
  170. IN ENGINEHANDLE ehObjId,
  171. IN IUICallbacks::EventCode evt
  172. )
  173. {
  174. if (m_fPrepareToDeinitialize)
  175. {
  176. goto end;
  177. }
  178. mfn_Lock();
  179. // DummyAction(L"DetailsView::HandleEngineEvent");
  180. //
  181. // If the object and type matches our, we'll re-draw our display...
  182. //
  183. if ((m_objType == objtype) && (m_ehObj == ehObjId))
  184. {
  185. //
  186. // It's us -- re-draw...
  187. //
  188. HandleLeftViewSelChange(objtype, ehObjId);
  189. }
  190. else if ((m_objType == IUICallbacks::OBJ_CLUSTER) && (m_ehObj == ehClusterId))
  191. {
  192. //
  193. // We're showing a cluster and this event is for one of our
  194. // interfaces -- for now we'll redraw ourselves. An optimization
  195. // would be to just re-draw that list element that represents the
  196. // interface.
  197. //
  198. HandleLeftViewSelChange(m_objType, m_ehObj);
  199. }
  200. else if ((m_objType == IUICallbacks::OBJ_INVALID) && (objtype == IUICallbacks::OBJ_CLUSTER))
  201. {
  202. //
  203. // We're showing the root display (list of clusters and this
  204. // event is a cluster update, so we need to refresh.
  205. //
  206. HandleLeftViewSelChange(objtype, NULL);
  207. }
  208. mfn_Unlock();
  209. end:
  210. return;
  211. }
  212. void
  213. DetailsView::mfn_InitializeRootDisplay(VOID)
  214. //
  215. // Initialize the details-view display with the root is selected.
  216. //
  217. {
  218. vector <ENGINEHANDLE> ClusterList;
  219. vector <ENGINEHANDLE>::iterator iCluster;
  220. CListCtrl& ctrl = GetListCtrl();
  221. CLocalLogger logDescription;
  222. NLBERROR nerr;
  223. int i = 0;
  224. enum
  225. {
  226. COL_CL_NAME,
  227. COL_CL_IP_ADDR,
  228. COL_CL_IP_MASK,
  229. COL_CL_MODE,
  230. COL_CL_RCT_ENABLED
  231. };
  232. mfn_Clear();
  233. logDescription.Log(
  234. IDS_DETAILS_ROOT_DESCRIPTION
  235. );
  236. mfn_UpdateCaption(logDescription.GetStringSafe());
  237. ctrl.SetImageList( GetDocument()->m_images48x48, LVSIL_SMALL );
  238. ctrl.InsertColumn( COL_CL_NAME,
  239. GETRESOURCEIDSTRING(IDS_DETAILS_COL_CLUSTER_NAME),
  240. // L"Cluster name",
  241. LVCFMT_LEFT,
  242. 175
  243. );
  244. ctrl.InsertColumn( COL_CL_IP_ADDR,
  245. GETRESOURCEIDSTRING(IDS_DETAILS_COL_CIP),
  246. // L"Cluster IP address",
  247. LVCFMT_LEFT,
  248. 140
  249. );
  250. ctrl.InsertColumn( COL_CL_IP_MASK,
  251. GETRESOURCEIDSTRING(IDS_DETAILS_COL_CIPMASK),
  252. // L"Cluster IP subnet mask",
  253. LVCFMT_LEFT,
  254. 140
  255. );
  256. ctrl.InsertColumn( COL_CL_MODE,
  257. GETRESOURCEIDSTRING(IDS_DETAILS_COL_CMODE),
  258. // L"Cluster mode",
  259. LVCFMT_LEFT,
  260. 100
  261. );
  262. ctrl.InsertColumn( COL_CL_RCT_ENABLED,
  263. GETRESOURCEIDSTRING(IDS_DETAILS_RCT_STATUS),
  264. // L"Remote control status",
  265. LVCFMT_LEFT,
  266. 125
  267. );
  268. nerr = gEngine.EnumerateClusters(ClusterList);
  269. if (FAILED(nerr)) goto end;
  270. for (iCluster = ClusterList.begin();
  271. iCluster != ClusterList.end();
  272. iCluster++)
  273. {
  274. ENGINEHANDLE ehCluster = (ENGINEHANDLE)*iCluster;
  275. CClusterSpec cSpec;
  276. INT iIcon;
  277. LPCWSTR szClusterIp = L"";
  278. LPCWSTR szClusterMask = L"";
  279. LPCWSTR szClusterName = L"";
  280. LPCWSTR szClusterMode = L"";
  281. LPCWSTR szClusterRctEnabled = L"";
  282. const WLBS_REG_PARAMS * pParams;
  283. nerr = gEngine.GetClusterSpec(ehCluster, REF cSpec);
  284. if (FAILED(nerr)) goto end;
  285. if (cSpec.m_ClusterNlbCfg.IsValidNlbConfig())
  286. {
  287. pParams = &cSpec.m_ClusterNlbCfg.NlbParams;
  288. szClusterName = pParams->domain_name;
  289. szClusterIp= pParams->cl_ip_addr;
  290. szClusterMask= pParams->cl_net_mask;
  291. szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_UNICAST); //"unicast";
  292. if (pParams->mcast_support)
  293. {
  294. if (pParams->fIGMPSupport)
  295. {
  296. szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_IGMP); //"IGMP multicast";
  297. }
  298. else
  299. {
  300. szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_MULTI); //"multicast";
  301. }
  302. }
  303. if (pParams->rct_enabled)
  304. {
  305. szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_ENABLED); //"enabled";
  306. }
  307. else
  308. {
  309. szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_DISABLED); //"disabled";
  310. }
  311. if (cSpec.m_fMisconfigured)
  312. {
  313. iIcon = Document::ICON_CLUSTER_BROKEN;
  314. }
  315. else
  316. {
  317. iIcon = Document::ICON_CLUSTER_OK;
  318. }
  319. //
  320. // Insert all the columns...
  321. //
  322. ctrl.InsertItem(
  323. LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
  324. i,
  325. szClusterName, // text
  326. 0, // nState
  327. 0, // nStateMask
  328. iIcon,
  329. (LPARAM) ehCluster // lParam
  330. );
  331. ctrl.SetItemText( i, COL_CL_IP_ADDR, szClusterIp);
  332. ctrl.SetItemText( i, COL_CL_IP_MASK, szClusterMask);
  333. ctrl.SetItemText( i, COL_CL_MODE, szClusterMode);
  334. ctrl.SetItemText( i, COL_CL_RCT_ENABLED, szClusterRctEnabled);
  335. i++;
  336. }
  337. }
  338. end:
  339. return;
  340. }
  341. void
  342. DetailsView::mfn_InitializeClusterDisplay(ENGINEHANDLE ehCluster)
  343. //
  344. // Initialize the details-view display with a cluster is selected.
  345. //
  346. {
  347. NLBERROR nerr;
  348. CClusterSpec cSpec;
  349. CListCtrl& ctrl = GetListCtrl();
  350. CLocalLogger logDescription;
  351. enum
  352. {
  353. COL_INTERFACE_NAME=0,
  354. COL_STATUS,
  355. COL_DED_IP_ADDR,
  356. COL_DED_IP_MASK,
  357. COL_HOST_PRIORITY,
  358. COL_HOST_INITIAL_STATE
  359. };
  360. mfn_Clear();
  361. nerr = gEngine.GetClusterSpec(
  362. ehCluster,
  363. REF cSpec
  364. );
  365. if (FAILED(nerr)) goto end;
  366. if (cSpec.m_ClusterNlbCfg.IsValidNlbConfig())
  367. {
  368. logDescription.Log(
  369. IDS_DETAILS_CLUSTER_DESCRIPTION,
  370. cSpec.m_ClusterNlbCfg.NlbParams.domain_name,
  371. cSpec.m_ClusterNlbCfg.NlbParams.cl_ip_addr
  372. );
  373. }
  374. mfn_UpdateCaption(logDescription.GetStringSafe());
  375. ctrl.SetImageList( GetDocument()->m_images48x48,
  376. LVSIL_SMALL );
  377. ctrl.InsertColumn( COL_INTERFACE_NAME,
  378. GETRESOURCEIDSTRING(IDS_DETAILS_COL_HOST),
  379. // L"Host(Interface)",
  380. LVCFMT_LEFT,
  381. 175
  382. );
  383. ctrl.InsertColumn( COL_STATUS,
  384. GETRESOURCEIDSTRING(IDS_DETAILS_COL_STATUS),
  385. // L"Status",
  386. LVCFMT_LEFT,
  387. 85
  388. );
  389. ctrl.InsertColumn( COL_DED_IP_ADDR,
  390. GETRESOURCEIDSTRING(IDS_DETAILS_COL_DIP),
  391. // L"Dedicated IP address",
  392. LVCFMT_LEFT,
  393. 140
  394. );
  395. ctrl.InsertColumn( COL_DED_IP_MASK,
  396. GETRESOURCEIDSTRING(IDS_DETAILS_COL_DIPMASK),
  397. // L"Dedicated IP subnet mask",
  398. LVCFMT_LEFT,
  399. 140
  400. );
  401. ctrl.InsertColumn( COL_HOST_PRIORITY,
  402. GETRESOURCEIDSTRING(IDS_DETAILS_COL_PRIORITY),
  403. // L"Host priority",
  404. LVCFMT_LEFT,
  405. 75
  406. );
  407. ctrl.InsertColumn( COL_HOST_INITIAL_STATE,
  408. GETRESOURCEIDSTRING(IDS_DETAILS_COL_INIT_STATE),
  409. // L"Initial host state",
  410. LVCFMT_LEFT,
  411. 100
  412. );
  413. //
  414. // Now we loop through the interfaces in the cluster, adding one line of
  415. // information on each;
  416. //
  417. for( int i = 0; i < cSpec.m_ehInterfaceIdList.size(); ++i )
  418. {
  419. CInterfaceSpec iSpec;
  420. CHostSpec hSpec;
  421. _bstr_t bstrStatus;
  422. _bstr_t bstrDisplayName;
  423. ENGINEHANDLE ehIID = cSpec.m_ehInterfaceIdList[i];
  424. INT iIcon = 0;
  425. WBEMSTATUS wStat;
  426. LPCWSTR szDisplayName = L"";
  427. LPCWSTR szStatus = L"";
  428. LPCWSTR szDedIp = L"";
  429. LPCWSTR szDedMask = L"";
  430. LPCWSTR szHostPriority = L"";
  431. LPCWSTR szHostInitialState = L"";
  432. WCHAR rgPriority[64];
  433. WCHAR rgInitialState[64];
  434. const WLBS_REG_PARAMS *pParams =
  435. &iSpec.m_NlbCfg.NlbParams;
  436. nerr = gEngine.GetInterfaceInformation(
  437. ehIID,
  438. REF hSpec,
  439. REF iSpec,
  440. REF bstrDisplayName,
  441. REF iIcon,
  442. REF bstrStatus
  443. );
  444. if (NLBFAILED(nerr))
  445. {
  446. continue;
  447. }
  448. else
  449. {
  450. szDisplayName = bstrDisplayName;
  451. szStatus = bstrStatus;
  452. }
  453. if (iSpec.m_NlbCfg.IsValidNlbConfig())
  454. {
  455. szDedIp = pParams->ded_ip_addr;
  456. szDedMask = pParams->ded_net_mask;
  457. StringCbPrintf(rgPriority, sizeof(rgPriority), L"%lu", pParams->host_priority);
  458. szHostPriority = rgPriority;
  459. // szHostInitialState
  460. switch(pParams->cluster_mode)
  461. {
  462. case CVY_HOST_STATE_STARTED:
  463. szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_STARTED); // L"started";
  464. break;
  465. case CVY_HOST_STATE_STOPPED:
  466. szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_STOPPED); // L"stopped";
  467. break;
  468. case CVY_HOST_STATE_SUSPENDED:
  469. szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_SUSPENDED); // L"suspended";
  470. break;
  471. default:
  472. szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_UNKNOWN); // L"unknown";
  473. break;
  474. }
  475. if (pParams->persisted_states & CVY_PERSIST_STATE_SUSPENDED)
  476. {
  477. StringCbPrintf(
  478. rgInitialState,
  479. sizeof(rgInitialState),
  480. (LPCWSTR) GETRESOURCEIDSTRING(IDS_DETAILS_PERSIST_SUSPEND), // L"%ws, persist suspend"
  481. szHostInitialState);
  482. szHostInitialState = rgInitialState;
  483. }
  484. }
  485. //
  486. // Insert all the columns...
  487. //
  488. ctrl.InsertItem(
  489. LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
  490. i,
  491. szDisplayName, // text
  492. 0, // nState
  493. 0, // nStateMask
  494. iIcon,
  495. (LPARAM) ehIID // lParam
  496. );
  497. ctrl.SetItemText( i, COL_STATUS, szStatus);
  498. ctrl.SetItemText( i, COL_DED_IP_ADDR, szDedIp);
  499. ctrl.SetItemText( i, COL_DED_IP_MASK, szDedMask);
  500. ctrl.SetItemText( i, COL_HOST_PRIORITY, szHostPriority);
  501. ctrl.SetItemText( i, COL_HOST_INITIAL_STATE, szHostInitialState);
  502. }
  503. //
  504. // Keep track of which object we're displaying...
  505. //
  506. m_ehObj = ehCluster;
  507. m_objType = IUICallbacks::OBJ_CLUSTER;
  508. end:
  509. return;
  510. }
  511. void
  512. DetailsView::mfn_InitializeInterfaceDisplay(ENGINEHANDLE ehInterface)
  513. //
  514. // Initialize the details-view display when an interface in a cluster is
  515. // selected.
  516. //
  517. {
  518. NLBERROR nerr;
  519. CInterfaceSpec ISpec;
  520. CListCtrl& ctrl = GetListCtrl();
  521. mfn_Clear();
  522. nerr = gEngine.GetInterfaceSpec(ehInterface, REF ISpec);
  523. if (NLBFAILED(nerr))
  524. {
  525. goto end;
  526. }
  527. //
  528. // Fill out the caption with host name and interface name...
  529. //
  530. {
  531. WBEMSTATUS wStat;
  532. LPWSTR szAdapter = L"";
  533. LPCWSTR szHostName = L"";
  534. CHostSpec hSpec;
  535. CLocalLogger log;
  536. nerr = gEngine.GetHostSpec(
  537. ISpec.m_ehHostId,
  538. REF hSpec
  539. );
  540. if (NLBOK(nerr))
  541. {
  542. szHostName = (LPCWSTR) hSpec.m_MachineName;
  543. if (szHostName == NULL)
  544. {
  545. szHostName = L"";
  546. }
  547. }
  548. wStat = ISpec.m_NlbCfg.GetFriendlyName(&szAdapter);
  549. if (FAILED(wStat))
  550. {
  551. szAdapter = NULL;
  552. }
  553. if (szAdapter == NULL)
  554. szAdapter = L"";
  555. log.Log(
  556. IDS_DETAILS_PORT_CAPTION,
  557. szHostName,
  558. szAdapter
  559. );
  560. delete szAdapter;
  561. mfn_UpdateCaption(log.GetStringSafe());
  562. }
  563. PortListUtils::LoadFromNlbCfg(
  564. &ISpec.m_NlbCfg,
  565. ctrl,
  566. FALSE, // FALSE == is host-level
  567. TRUE // TRUE == displaying in the details view
  568. );
  569. //
  570. // Keep track of which object we're displaying...
  571. //
  572. m_ehObj = ehInterface;
  573. m_objType = IUICallbacks::OBJ_INTERFACE;
  574. end:
  575. return;
  576. }
  577. void
  578. DetailsView::mfn_UpdateInterfaceInClusterDisplay(
  579. ENGINEHANDLE ehInterface,
  580. BOOL fDelete
  581. )
  582. //
  583. // Update or delete the specified interface from the cluster view.
  584. // Assumes that a cluster is selected in the left view.
  585. //
  586. {
  587. }
  588. void
  589. DetailsView::mfn_Clear(void)
  590. //
  591. // Delete all items and all columns in the list
  592. //
  593. {
  594. CListCtrl& ctrl = GetListCtrl();
  595. ctrl.DeleteAllItems();
  596. // Delete all of the previous columns.
  597. LV_COLUMN colInfo;
  598. ZeroMemory(&colInfo, sizeof(colInfo));
  599. colInfo.mask = LVCF_SUBITEM;
  600. while(ctrl.GetColumn(0, &colInfo))
  601. {
  602. ctrl.DeleteColumn(0);
  603. }
  604. ctrl.SetImageList( NULL, LVSIL_SMALL );
  605. mfn_UpdateCaption(L"");
  606. //
  607. // Clear currently displayed object handle and it's type.
  608. //
  609. m_ehObj = NULL;
  610. m_objType = IUICallbacks::OBJ_INVALID;
  611. }
  612. VOID
  613. DetailsView::mfn_UpdateCaption(LPCWSTR szText)
  614. {
  615. SetDlgItemText(IDC_TEXT_DETAILS_CAPTION, szText);
  616. }
  617. void
  618. DetailsView::mfn_Lock(void)
  619. {
  620. //
  621. // See notes.txt entry
  622. // 01/23/2002 JosephJ DEADLOCK in Leftview::mfn_Lock
  623. // for the reason for this convoluted implementation of mfn_Lock
  624. //
  625. while (!TryEnterCriticalSection(&m_crit))
  626. {
  627. ProcessMsgQueue();
  628. Sleep(100);
  629. }
  630. }
  631. void
  632. DetailsView::Deinitialize(void)
  633. {
  634. TRACE_INFO(L"-> %!FUNC!");
  635. ASSERT(m_fPrepareToDeinitialize);
  636. // DummyAction(L"Details::Deinitialize");
  637. TRACE_INFO(L"<- %!FUNC!");
  638. }
  639. void DetailsView::OnNotifyKeyDown( NMHDR* pNMHDR, LRESULT* pResult )
  640. {
  641. TRACE_CRIT(L"<->%!FUNC!");
  642. NMLVKEYDOWN *pkd = (NMLVKEYDOWN *) pNMHDR;
  643. if (pkd->wVKey == VK_F6 || pkd->wVKey == VK_TAB)
  644. {
  645. *pResult = 0;
  646. if (! (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
  647. {
  648. GetDocument()->SetFocusNextView(this, (int) pkd->wVKey);
  649. }
  650. else
  651. {
  652. GetDocument()->SetFocusPrevView(this, (int) pkd->wVKey);
  653. }
  654. }
  655. }
  656. void
  657. DetailsView::SetFocus(void)
  658. {
  659. //
  660. // We override our SetFocus, because we really need to set the focus
  661. // on our list control, and also select a listview item if there isn't
  662. // one selected...
  663. //
  664. CListCtrl& ctrl = GetListCtrl();
  665. POSITION pos = NULL;
  666. pos = ctrl.GetFirstSelectedItemPosition();
  667. //
  668. // If no item is selected, select one...
  669. //
  670. if(pos == NULL)
  671. {
  672. ctrl.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
  673. }
  674. ctrl.SetFocus();
  675. }