Source code of Windows XP (NT5)
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.

1166 lines
29 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. FTMan
  5. File Name:
  6. FTTreeVw.cpp
  7. Abstract:
  8. Implementation of the CFTTreeView class. It is a tree view displaying:
  9. - all logical volumes
  10. - all physical partitions that are not logical volumes
  11. existing in the system
  12. Author:
  13. Cristian Teodorescu October 20, 1998
  14. Notes:
  15. Revision History:
  16. --*/
  17. #include "stdafx.h"
  18. #include "Actions.h"
  19. #include "FTDoc.h"
  20. #include "FTListVw.h"
  21. #include "FTTreeVw.h"
  22. #include "Item.h"
  23. #include "LogVol.h"
  24. #include "MainFrm.h"
  25. #include "PhPart.h"
  26. #include "Resource.h"
  27. #include "RootFree.h"
  28. #include "RootVol.h"
  29. #ifdef _DEBUG
  30. #define new DEBUG_NEW
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CFTTreeView
  36. IMPLEMENT_DYNCREATE(CFTTreeView, CTreeView)
  37. BEGIN_MESSAGE_MAP(CFTTreeView, CTreeView)
  38. //{{AFX_MSG_MAP(CFTTreeView)
  39. ON_WM_DESTROY()
  40. ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
  41. ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
  42. ON_COMMAND(ID_ITEM_EXPAND, OnItemExpand)
  43. ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
  44. ON_COMMAND(ID_VIEW_UP, OnViewUp)
  45. ON_UPDATE_COMMAND_UI(ID_VIEW_UP, OnUpdateViewUp)
  46. ON_COMMAND(ID_ACTION_ASSIGN, OnActionAssign)
  47. ON_UPDATE_COMMAND_UI(ID_ACTION_ASSIGN, OnUpdateActionAssign)
  48. ON_COMMAND(ID_ACTION_FTBREAK, OnActionFtbreak)
  49. ON_UPDATE_COMMAND_UI(ID_ACTION_FTBREAK, OnUpdateActionFtbreak)
  50. ON_COMMAND(ID_ACTION_CREATE_EXTENDED_PARTITION, OnActionCreateExtendedPartition)
  51. ON_UPDATE_COMMAND_UI(ID_ACTION_CREATE_EXTENDED_PARTITION, OnUpdateActionCreateExtendedPartition)
  52. ON_COMMAND(ID_ACTION_CREATE_PARTITION, OnActionCreatePartition)
  53. ON_UPDATE_COMMAND_UI(ID_ACTION_CREATE_PARTITION, OnUpdateActionCreatePartition)
  54. ON_COMMAND(ID_ACTION_DELETE, OnActionDelete)
  55. ON_UPDATE_COMMAND_UI(ID_ACTION_DELETE, OnUpdateActionDelete)
  56. ON_COMMAND(ID_ACTION_FTINIT, OnActionFtinit)
  57. ON_UPDATE_COMMAND_UI(ID_ACTION_FTINIT, OnUpdateActionFtinit)
  58. ON_COMMAND(ID_ACTION_FTSWAP, OnActionFtswap)
  59. ON_UPDATE_COMMAND_UI(ID_ACTION_FTSWAP, OnUpdateActionFtswap)
  60. //}}AFX_MSG_MAP
  61. // Status bar indicators handlers
  62. ON_UPDATE_COMMAND_UI(ID_INDICATOR_NAME, OnUpdateIndicatorName)
  63. ON_UPDATE_COMMAND_UI(ID_INDICATOR_TYPE, OnUpdateIndicatorType)
  64. ON_UPDATE_COMMAND_UI(ID_INDICATOR_DISKS, OnUpdateIndicatorDisks)
  65. ON_UPDATE_COMMAND_UI(ID_INDICATOR_SIZE, OnUpdateIndicatorSize)
  66. ON_UPDATE_COMMAND_UI(ID_INDICATOR_NOTHING, OnUpdateIndicatorNothing)
  67. END_MESSAGE_MAP()
  68. /////////////////////////////////////////////////////////////////////////////
  69. // CFTTreeView construction/destruction
  70. CFTTreeView::CFTTreeView()
  71. {
  72. // TODO: add construction code here
  73. }
  74. CFTTreeView::~CFTTreeView()
  75. {
  76. }
  77. BOOL CFTTreeView::PreCreateWindow(CREATESTRUCT& cs)
  78. {
  79. // TODO: Modify the Window class or styles here by modifying
  80. // the CREATESTRUCT cs
  81. return CTreeView::PreCreateWindow(cs);
  82. }
  83. /////////////////////////////////////////////////////////////////////////////
  84. // CFTTreeView drawing
  85. void CFTTreeView::OnDraw(CDC* pDC)
  86. {
  87. CFTDocument* pDoc = GetDocument();
  88. ASSERT_VALID(pDoc);
  89. // TODO: add draw code for native data here
  90. }
  91. void CFTTreeView::OnInitialUpdate()
  92. {
  93. MY_TRY
  94. CTreeView::OnInitialUpdate();
  95. // Set the "look and style" of the tree control
  96. GetTreeCtrl().ModifyStyle(0, TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS );
  97. // Create the image list associated with the tree control
  98. CImageList* pImageList = new CImageList();
  99. // The background color for mask is pink. All image's pixels of this color will take
  100. // the view's background color.
  101. if( pImageList->Create( IDB_IMAGELIST, 16, 15, RGB( 255, 0, 255 ) ) )
  102. GetTreeCtrl().SetImageList(pImageList, TVSIL_NORMAL);
  103. else
  104. AfxMessageBox( IDS_ERR_CREATE_IMAGELIST, MB_ICONSTOP );
  105. // Load the popup menu
  106. m_menuPopup.LoadMenu(IDM_POPUP);
  107. // TODO: You may populate your TreeView with items by directly accessing
  108. // its tree control through a call to GetTreeCtrl().
  109. // I commented this because the first refresh is done on WM_ACTIVATEAPP ( see MainFrm.cpp )
  110. //Refresh();
  111. AfxEnableAutoRefresh(TRUE);
  112. MY_CATCH_AND_REPORT
  113. }
  114. /////////////////////////////////////////////////////////////////////////////
  115. // CFTTreeView diagnostics
  116. #ifdef _DEBUG
  117. void CFTTreeView::AssertValid() const
  118. {
  119. CTreeView::AssertValid();
  120. }
  121. void CFTTreeView::Dump(CDumpContext& dc) const
  122. {
  123. CTreeView::Dump(dc);
  124. }
  125. CFTDocument* CFTTreeView::GetDocument() // non-debug version is inline
  126. {
  127. ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFTDocument)));
  128. return (CFTDocument*)m_pDocument;
  129. }
  130. #endif //_DEBUG
  131. /////////////////////////////////////////////////////////////////////////////
  132. // Tree handling methods
  133. HTREEITEM CFTTreeView::InsertItem( CItemData* pData, HTREEITEM hParent, HTREEITEM hInsertAfter )
  134. {
  135. MY_TRY
  136. // Just in case
  137. if( pData == NULL )
  138. return NULL;
  139. if( hParent != NULL )
  140. ASSERT( pData->GetParentData() == (CItemData*)(GetTreeCtrl().GetItemData( hParent ) ) );
  141. else
  142. ASSERT( pData->GetParentData() == NULL );
  143. TV_INSERTSTRUCT tvstruct;
  144. tvstruct.hParent = hParent;
  145. tvstruct.hInsertAfter = hInsertAfter;
  146. tvstruct.item.iImage = tvstruct.item.iSelectedImage = pData->GetImageIndex();
  147. CString strDisplayName;
  148. pData->GetDisplayExtendedName(strDisplayName);
  149. tvstruct.item.pszText = (LPTSTR)(LPCTSTR)strDisplayName;
  150. tvstruct.item.cChildren = pData->GetMembersNumber()>0 ? 1 : 0 ;
  151. tvstruct.item.lParam = (LPARAM)pData;
  152. tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM;
  153. // Insert the item
  154. HTREEITEM hItem = GetTreeCtrl().InsertItem(&tvstruct);
  155. // Update the m_hTreeItem member of pData
  156. pData->SetTreeItem(hItem);
  157. // If the item reports at least one member then a dummy child must be created so it
  158. // can be expanded later
  159. if( pData->GetMembersNumber() > 0 )
  160. {
  161. tvstruct.hParent = hItem;
  162. tvstruct.hInsertAfter = TVI_LAST;
  163. tvstruct.item.iImage = 0;
  164. tvstruct.item.iSelectedImage = 0;
  165. tvstruct.item.pszText = _T("Dummy");
  166. tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
  167. GetTreeCtrl().InsertItem(&tvstruct);
  168. }
  169. return hItem;
  170. MY_CATCH_REPORT_AND_RETURN_NULL
  171. }
  172. //Redisplay the name and the image of the item
  173. BOOL CFTTreeView::RefreshItem( HTREEITEM hItem )
  174. {
  175. MY_TRY
  176. TVITEM tvitem;
  177. tvitem.hItem = hItem;
  178. tvitem.mask = TVIF_PARAM;
  179. if( !GetTreeCtrl().GetItem( &tvitem ) )
  180. return FALSE;
  181. CItemData* pData = (CItemData*)(tvitem.lParam);
  182. CString strDisplayName;
  183. pData->GetDisplayExtendedName(strDisplayName);
  184. tvitem.pszText = (LPTSTR)(LPCTSTR)strDisplayName;
  185. tvitem.iImage = tvitem.iSelectedImage = pData->GetImageIndex();
  186. tvitem.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE ;
  187. return GetTreeCtrl().SetItem( &tvitem );
  188. MY_CATCH_REPORT_AND_RETURN_FALSE
  189. }
  190. BOOL CFTTreeView::AddItemMembers(HTREEITEM hItem)
  191. {
  192. MY_TRY
  193. CAutoRefresh ar(FALSE);
  194. if( !hItem )
  195. return TRUE;
  196. CWaitCursor wc;
  197. // Get the data associated with the item
  198. TVITEM tvItem;
  199. tvItem.hItem = hItem;
  200. tvItem.stateMask = TVIS_SELECTED;
  201. tvItem.mask = TVIF_PARAM | TVIF_STATE ;
  202. if( !GetTreeCtrl().GetItem(&tvItem) )
  203. return FALSE;
  204. CItemData* pData = (CItemData*)tvItem.lParam;
  205. ASSERT(pData);
  206. // If the members are already inserted then return
  207. if( pData->AreMembersInserted() )
  208. return TRUE;
  209. // Delete old subtree but let the root alive
  210. if( !DeleteItemSubtree(hItem, FALSE ) )
  211. return FALSE;
  212. // Get the members of this item
  213. CObArray arrMembers;
  214. CString strErrors;
  215. pData->ReadMembers(arrMembers, strErrors);
  216. if( !strErrors.IsEmpty() )
  217. {
  218. AfxMessageBox( strErrors, MB_ICONSTOP );
  219. wc.Restore();
  220. }
  221. // Add new items to the tree
  222. for( int i=0, nInsertedMembers = 0; i<arrMembers.GetSize(); i++ )
  223. {
  224. CItemData* pMemberData = (CItemData*)(arrMembers[i]);
  225. ASSERT(pMemberData);
  226. if( InsertItem(pMemberData, hItem, TVI_LAST ) )
  227. nInsertedMembers++;
  228. else
  229. {
  230. // Item data was not inserted in the tree so it must be deleted here
  231. delete pMemberData;
  232. }
  233. }
  234. arrMembers.RemoveAll();
  235. // Now the item has its members inserted in the tree
  236. pData->SetAreMembersInserted(TRUE);
  237. ASSERT( tvItem.hItem = hItem );
  238. tvItem.cChildren = nInsertedMembers;
  239. tvItem.mask = TVIF_CHILDREN ;
  240. GetTreeCtrl().SetItem(&tvItem);
  241. // If the item is selected synchronize the list view with the new list of members
  242. if( tvItem.state & TVIS_SELECTED )
  243. {
  244. CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, GetParentFrame() );
  245. CFTListView* pListView = pFrame->GetRightPane();
  246. if(pListView)
  247. pListView->SynchronizeMembersWithTree(pData);
  248. }
  249. return TRUE;
  250. MY_CATCH_REPORT_AND_RETURN_FALSE
  251. }
  252. BOOL CFTTreeView::DeleteItemSubtree(HTREEITEM hItem, BOOL bDeleteSubtreeRoot /*=TRUE*/)
  253. {
  254. if( !hItem )
  255. return TRUE;
  256. // Remove all members
  257. HTREEITEM hChild = GetTreeCtrl().GetChildItem(hItem);
  258. while( hChild != NULL )
  259. {
  260. HTREEITEM hTemp = GetTreeCtrl().GetNextSiblingItem(hChild);
  261. DeleteItemSubtree(hChild);
  262. hChild = hTemp;
  263. }
  264. TVITEM tvItem;
  265. tvItem.hItem = hItem;
  266. tvItem.mask = TVIF_PARAM;
  267. if( GetTreeCtrl().GetItem(&tvItem) )
  268. {
  269. CItemData* pItemData = (CItemData*)tvItem.lParam;
  270. if( bDeleteSubtreeRoot )
  271. {
  272. if( pItemData )
  273. delete pItemData;
  274. return GetTreeCtrl().DeleteItem(hItem);
  275. }
  276. else
  277. {
  278. // The members of this item are no more in the tree
  279. if( pItemData )
  280. pItemData->SetAreMembersInserted(FALSE);
  281. return TRUE;
  282. }
  283. }
  284. return FALSE;
  285. }
  286. BOOL CFTTreeView::DeleteAllItems()
  287. {
  288. BOOL bResult = TRUE;
  289. GetTreeCtrl().SelectItem(NULL);
  290. HTREEITEM hItem = GetTreeCtrl().GetRootItem();
  291. while( hItem )
  292. {
  293. HTREEITEM hTemp = GetTreeCtrl().GetNextSiblingItem( hItem );
  294. bResult = DeleteItemSubtree(hItem) && bResult;
  295. hItem = hTemp;
  296. }
  297. return bResult;
  298. }
  299. // Adds the snapshot of a subtree ( expanded items, selected items ) to the given snapshot
  300. void CFTTreeView::AddSubtreeSnapshot( HTREEITEM hSubtreeRoot, TREE_SNAPSHOT& snapshot )
  301. {
  302. MY_TRY
  303. if( hSubtreeRoot == NULL )
  304. return;
  305. UINT unItemState = GetTreeCtrl().GetItemState( hSubtreeRoot, TVIS_EXPANDED | TVIS_SELECTED );
  306. if( !unItemState )
  307. return;
  308. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData(hSubtreeRoot));
  309. ASSERT(pData);
  310. CItemID idItem( *pData );
  311. if( unItemState & TVIS_EXPANDED )
  312. snapshot.setExpandedItems.Add(idItem);
  313. if( unItemState & TVIS_SELECTED )
  314. snapshot.setSelectedItems.Add(idItem);
  315. HTREEITEM hChildItem = GetTreeCtrl().GetChildItem(hSubtreeRoot);
  316. while( hChildItem != NULL )
  317. {
  318. AddSubtreeSnapshot( hChildItem, snapshot );
  319. hChildItem = GetTreeCtrl().GetNextSiblingItem(hChildItem);
  320. }
  321. MY_CATCH_AND_REPORT
  322. }
  323. // Get the snapshot of the tree ( expanded items, selected items )
  324. void CFTTreeView::GetSnapshot( TREE_SNAPSHOT& snapshot )
  325. {
  326. MY_TRY
  327. CWaitCursor wc;
  328. snapshot.setExpandedItems.RemoveAll();
  329. snapshot.setSelectedItems.RemoveAll();
  330. HTREEITEM hItem = GetTreeCtrl().GetRootItem();
  331. while( hItem )
  332. {
  333. AddSubtreeSnapshot( hItem, snapshot );
  334. hItem = GetTreeCtrl().GetNextSiblingItem( hItem );
  335. }
  336. MY_CATCH_AND_REPORT
  337. }
  338. // Refresh the content of a subtree according with a certain snapshot ( expanded items, selected items )
  339. BOOL CFTTreeView::RefreshSubtree( HTREEITEM hSubtreeRoot, TREE_SNAPSHOT& snapshot )
  340. {
  341. MY_TRY
  342. BOOL bResult = TRUE;
  343. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData( hSubtreeRoot));
  344. ASSERT(pData);
  345. CItemID idItem( *pData );
  346. if( snapshot.setExpandedItems.InSet( idItem ) )
  347. {
  348. GetTreeCtrl().Expand( hSubtreeRoot, TVE_EXPAND );
  349. HTREEITEM hChildItem =GetTreeCtrl().GetChildItem(hSubtreeRoot);
  350. while( hChildItem != NULL )
  351. {
  352. bResult = RefreshSubtree( hChildItem, snapshot );
  353. hChildItem = GetTreeCtrl().GetNextSiblingItem(hChildItem);
  354. }
  355. }
  356. if( snapshot.setSelectedItems.InSet( idItem ) )
  357. GetTreeCtrl().SelectItem( hSubtreeRoot );
  358. return bResult;
  359. MY_CATCH_REPORT_AND_RETURN_FALSE
  360. }
  361. // Refresh the content of the tree view according to a certain snapshot ( expanded items, selected items )
  362. BOOL CFTTreeView::Refresh( TREE_SNAPSHOT& snapshot)
  363. {
  364. MY_TRY
  365. CAutoRefresh ar(FALSE);
  366. LockWindowUpdate();
  367. DeleteAllItems();
  368. // 1. Add the volumes root item and expand it is necessary
  369. // Create a volumes root item ...
  370. CRootVolumesData* pRootVolData = new CRootVolumesData;
  371. // Read its data ...
  372. CString strErrors;
  373. pRootVolData->ReadItemInfo(strErrors);
  374. if( !strErrors.IsEmpty() )
  375. AfxMessageBox( strErrors, MB_ICONSTOP );
  376. // Add it to the tree
  377. HTREEITEM hRoot = InsertItem( pRootVolData, NULL, TVI_FIRST );
  378. if( !hRoot )
  379. {
  380. delete pRootVolData;
  381. UnlockWindowUpdate();
  382. return FALSE;
  383. }
  384. // Refresh its subtree
  385. BOOL bResult = RefreshSubtree( hRoot, snapshot );
  386. // 2. Add the free spaces root item and expand it if necessary
  387. // Create a free spaces root item ...
  388. CRootFreeSpacesData* pRootFreeData = new CRootFreeSpacesData;
  389. // Read its data ...
  390. pRootFreeData->ReadItemInfo(strErrors);
  391. if( !strErrors.IsEmpty() )
  392. AfxMessageBox( strErrors, MB_ICONSTOP );
  393. // Add it to the tree
  394. hRoot = InsertItem( pRootFreeData, NULL, TVI_LAST );
  395. if( !hRoot )
  396. {
  397. DeleteAllItems();
  398. delete pRootFreeData;
  399. UnlockWindowUpdate();
  400. return FALSE;
  401. }
  402. // Refresh its subtree
  403. bResult = RefreshSubtree( hRoot, snapshot ) && bResult;
  404. UnlockWindowUpdate();
  405. return bResult;
  406. MY_CATCH_REPORT_AND_RETURN_FALSE
  407. }
  408. // Refresh the content of the tree view.
  409. BOOL CFTTreeView::Refresh()
  410. {
  411. CWaitCursor wc;
  412. CAutoRefresh ar(FALSE);
  413. TREE_SNAPSHOT snapshot;
  414. GetSnapshot(snapshot);
  415. return Refresh(snapshot);
  416. }
  417. // Performs some minor refreshment for the tree items. This should be called every TIMER_ELAPSE milliseconds.
  418. void CFTTreeView::RefreshOnTimer()
  419. {
  420. MY_TRY
  421. CAutoRefresh( FALSE );
  422. HTREEITEM hRootItem = GetTreeCtrl().GetRootItem();
  423. if( hRootItem == NULL )
  424. return;
  425. CObArray arrRefreshedItems;
  426. CWordArray arrRefreshFlags;
  427. ScanSubtreeOnTimer( hRootItem, arrRefreshedItems, arrRefreshFlags);
  428. if( arrRefreshedItems.GetSize() > 0 )
  429. {
  430. CWaitCursor wc;
  431. DisplayStatusBarMessage( IDS_STATUS_REFRESH );
  432. TRACE(_T("OnTimerRefresh: Some items under surveillance need some refreshment\n"));
  433. CObArray arrMount;
  434. for( int i = 0; i < arrRefreshedItems.GetSize(); i++ )
  435. {
  436. if( arrRefreshFlags[i] & ROTT_GotDriveLetterAndVolumeName )
  437. arrMount.Add( arrRefreshedItems[i] );
  438. }
  439. if( arrMount.GetSize() > 0 )
  440. QueryMountList( arrMount );
  441. HTREEITEM hSelectedItem = GetTreeCtrl().GetSelectedItem();
  442. CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, GetParentFrame() );
  443. CFTListView* pListView = pFrame->GetRightPane();
  444. for( i = 0; i < arrRefreshedItems.GetSize(); i++ )
  445. {
  446. // Refresh every item in this array
  447. CItemData* pData = (CItemData*)(arrRefreshedItems[i]);
  448. pData->SetImageIndex( pData->ComputeImageIndex() );
  449. RefreshItem( pData->GetTreeItem() );
  450. // If the item is also displayed in the list view ( equivalent with its parent being selected in
  451. // the tree view ) then refresh it there too
  452. if( ( pData->GetParentData() ) &&
  453. ( pData->GetParentData()->GetTreeItem() == hSelectedItem ) &&
  454. pListView )
  455. pListView->RefreshItem( pData->GetListItem() );
  456. }
  457. DisplayStatusBarMessage( AFX_IDS_IDLEMESSAGE );
  458. }
  459. MY_CATCH_AND_REPORT
  460. }
  461. // Scans a subtree for:
  462. // 1. Initializing stripe sets with parity that are not initializing anymore
  463. // 2. Regenerating mirror sets or stripe sets with parity that are not regenerating anymore
  464. // 3. Root volumes whose drive letter and volume name were eventually found
  465. void CFTTreeView::ScanSubtreeOnTimer( HTREEITEM hSubtreeRoot, CObArray& arrRefreshedItems, CWordArray& arrRefreshFlags)
  466. {
  467. MY_TRY
  468. ASSERT( hSubtreeRoot );
  469. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData( hSubtreeRoot ) );
  470. ASSERT( pData );
  471. ASSERT( pData->GetTreeItem() == hSubtreeRoot );
  472. WORD wRefreshFlags = 0;
  473. // Check if the drive letter and volume name are OK
  474. if( pData->IsRootVolume() && pData->GetVolumeName().IsEmpty() )
  475. {
  476. if( pData->ReadDriveLetterAndVolumeName() )
  477. {
  478. pData->SetValid(TRUE);
  479. wRefreshFlags |= ROTT_GotDriveLetterAndVolumeName;
  480. }
  481. }
  482. // Check for mirror sets and stripe sets with parity who just ended the regeneration of a member
  483. // Check also for stripe sets with parity who just ended their initialization
  484. if( pData->IsValid() && ( pData->GetItemType() == IT_LogicalVolume ) )
  485. {
  486. CLogicalVolumeData* pLogVolData = ( CLogicalVolumeData*)pData;
  487. if( ( pLogVolData->m_nVolType == FtMirrorSet ) ||
  488. ( pLogVolData->m_nVolType == FtStripeSetWithParity ) )
  489. {
  490. if( pLogVolData->m_StateInfo.stripeState.UnhealthyMemberState == FtMemberRegenerating )
  491. {
  492. CString strErrors;
  493. if( pLogVolData->ReadFTInfo( strErrors ) &&
  494. pLogVolData->m_StateInfo.stripeState.UnhealthyMemberState != FtMemberRegenerating )
  495. wRefreshFlags |= ROTT_EndRegeneration;
  496. }
  497. }
  498. if( pLogVolData->m_nVolType == FtStripeSetWithParity )
  499. {
  500. if( pLogVolData->m_StateInfo.stripeState.IsInitializing )
  501. {
  502. CString strErrors;
  503. if( pLogVolData->ReadFTInfo( strErrors ) &&
  504. !pLogVolData->m_StateInfo.stripeState.IsInitializing )
  505. wRefreshFlags |= ROTT_EndInitialization;
  506. }
  507. }
  508. }
  509. if( wRefreshFlags )
  510. {
  511. arrRefreshedItems.Add(pData);
  512. arrRefreshFlags.Add(wRefreshFlags);
  513. }
  514. // Now check the item's subtree
  515. if( !pData->AreMembersInserted() )
  516. return;
  517. HTREEITEM hChildItem = GetTreeCtrl().GetChildItem(hSubtreeRoot);
  518. USHORT unMember = 0;
  519. while( hChildItem != NULL )
  520. {
  521. if( wRefreshFlags & ( ROTT_EndRegeneration | ROTT_EndInitialization ) )
  522. {
  523. // Add all children to the refresh list
  524. CItemData* pChildData = (CItemData*)(GetTreeCtrl().GetItemData( hChildItem ) );
  525. ASSERT( pData );
  526. if( unMember == ((CLogicalVolumeData*)pData)->m_StateInfo.stripeState.UnhealthyMemberNumber )
  527. pChildData->SetMemberStatus( ((CLogicalVolumeData*)pData)->m_StateInfo.stripeState.UnhealthyMemberState );
  528. else
  529. pChildData->SetMemberStatus( FtMemberHealthy );
  530. arrRefreshedItems.Add( pChildData );
  531. arrRefreshFlags.Add( wRefreshFlags );
  532. }
  533. ScanSubtreeOnTimer(hChildItem, arrRefreshedItems, arrRefreshFlags );
  534. hChildItem = GetTreeCtrl().GetNextSiblingItem(hChildItem);
  535. unMember++;
  536. }
  537. MY_CATCH
  538. }
  539. void CFTTreeView::GetSelectedItems( CObArray& arrSelectedItems )
  540. {
  541. MY_TRY
  542. arrSelectedItems.RemoveAll();
  543. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  544. if( hItem != NULL )
  545. {
  546. CItemData* pData = (CItemData*)( GetTreeCtrl().GetItemData(hItem) );
  547. ASSERT(pData);
  548. arrSelectedItems.Add(pData);
  549. }
  550. MY_CATCH_AND_REPORT
  551. }
  552. /////////////////////////////////////////////////////////////////////////////
  553. // CFTTreeView message handlers
  554. void CFTTreeView::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
  555. {
  556. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  557. // TODO: Add your control notification handler code here
  558. *pResult = 0;
  559. HTREEITEM hItem = pNMTreeView->itemNew.hItem;
  560. ASSERT( hItem );
  561. CItemData* pData = (CItemData*)(pNMTreeView->itemNew.lParam);
  562. // When collapsing change the image for root items ( closed folder )
  563. if( pNMTreeView->action == TVE_COLLAPSE )
  564. {
  565. if( pData &&
  566. ( ( pData->GetItemType() == IT_RootVolumes ) ||
  567. ( pData->GetItemType() == IT_RootFreeSpaces ) ) )
  568. {
  569. pData->SetImageIndex( II_Root );
  570. GetTreeCtrl().SetItemImage( pNMTreeView->itemNew.hItem, II_Root, II_Root );
  571. }
  572. return;
  573. }
  574. // We are handling only the expandation of the item
  575. if( pNMTreeView->action == TVE_EXPAND )
  576. {
  577. // When expanding change the image for root items ( open folder )
  578. if( pData &&
  579. ( ( pData->GetItemType() == IT_RootVolumes ) ||
  580. ( pData->GetItemType() == IT_RootFreeSpaces ) ) )
  581. {
  582. pData->SetImageIndex( II_RootExpanded );
  583. GetTreeCtrl().SetItemImage( pNMTreeView->itemNew.hItem, II_RootExpanded, II_RootExpanded );
  584. }
  585. // Now it's time to prepare the item for expandation
  586. // Add all members of the item to the tree ( if they are already added to the tree AddItemMembers will return
  587. // without doing anything
  588. AddItemMembers(hItem);
  589. }
  590. }
  591. void CFTTreeView::OnDestroy()
  592. {
  593. GetTreeCtrl().SelectItem( NULL );
  594. // Delete all items and destroy their associated data
  595. DeleteAllItems();
  596. // Delete the image list
  597. CImageList* pImageList = GetTreeCtrl().GetImageList(TVSIL_NORMAL);
  598. if( pImageList )
  599. {
  600. pImageList->DeleteImageList();
  601. delete pImageList;
  602. }
  603. // Destroy the popup menu
  604. m_menuPopup.DestroyMenu();
  605. CTreeView::OnDestroy();
  606. // TODO: Add your message handler code here
  607. }
  608. void CFTTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
  609. {
  610. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  611. // TODO: Add your control notification handler code here
  612. *pResult = 0;
  613. CItemData* pNewData = (CItemData*)(pNMTreeView->itemNew.lParam);
  614. // Add all members of the item to the tree ( if they are already added to the tree AddItemMembers will return
  615. // without doing anything
  616. if( pNewData )
  617. AddItemMembers( pNewData->GetTreeItem() );
  618. CMainFrame* pFrame = STATIC_DOWNCAST(CMainFrame, GetParentFrame() );
  619. CFTListView* pListView = pFrame->GetRightPane();
  620. if(pListView)
  621. pListView->SynchronizeMembersWithTree(pNewData);
  622. }
  623. void CFTTreeView::OnItemExpand()
  624. {
  625. // TODO: Add your command handler code here
  626. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem( );
  627. if( !hItem)
  628. return;
  629. // Now reset the ExpandedOnce flag so the tree will receive OnItemExpanding notification
  630. TVITEM tvItem;
  631. tvItem.hItem = hItem;
  632. tvItem.state = 0;
  633. tvItem.stateMask = TVIS_EXPANDEDONCE;
  634. tvItem.mask = TVIF_STATE;
  635. GetTreeCtrl().SetItem(&tvItem);
  636. // Now toggle the status of the item ( expanded / collapsed )
  637. GetTreeCtrl().Expand( hItem, TVE_TOGGLE );
  638. }
  639. void CFTTreeView::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)
  640. {
  641. *pResult = 0;
  642. POINT pt;
  643. GetCursorPos( &pt );
  644. TVHITTESTINFO tvhittestinfo;
  645. tvhittestinfo.pt = pt;
  646. ScreenToClient( &(tvhittestinfo.pt) );
  647. GetTreeCtrl().HitTest( &tvhittestinfo );
  648. if( ( tvhittestinfo.hItem != NULL ) && ( tvhittestinfo.flags & TVHT_ONITEM ) )
  649. {
  650. GetTreeCtrl().SelectItem( tvhittestinfo.hItem );
  651. CMenu* pPopup = m_menuPopup.GetSubMenu(0);
  652. if( pPopup != NULL )
  653. pPopup->TrackPopupMenu( TPM_LEFTALIGN, pt.x, pt.y, AfxGetMainWnd(), NULL);
  654. }
  655. }
  656. void CFTTreeView::OnViewUp()
  657. {
  658. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  659. ASSERT( hItem );
  660. HTREEITEM hParentItem = GetTreeCtrl().GetParentItem( hItem );
  661. ASSERT( hParentItem );
  662. GetTreeCtrl().SelectItem( hParentItem );
  663. }
  664. void CFTTreeView::OnUpdateViewUp(CCmdUI* pCmdUI)
  665. {
  666. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  667. if( hItem == NULL )
  668. goto label_disable;
  669. if( GetTreeCtrl().GetParentItem( hItem ) == NULL )
  670. goto label_disable;
  671. pCmdUI->Enable(TRUE);
  672. return;
  673. label_disable:
  674. pCmdUI->Enable(FALSE);
  675. }
  676. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  677. // FT Actions
  678. void CFTTreeView::OnActionAssign()
  679. {
  680. CObArray arrSelectedItems;
  681. GetSelectedItems( arrSelectedItems );
  682. ActionAssign( arrSelectedItems );
  683. }
  684. void CFTTreeView::OnUpdateActionAssign(CCmdUI* pCmdUI)
  685. {
  686. CObArray arrSelectedItems;
  687. GetSelectedItems( arrSelectedItems );
  688. UpdateActionAssign( pCmdUI, arrSelectedItems );
  689. }
  690. void CFTTreeView::OnActionFtbreak()
  691. {
  692. CObArray arrSelectedItems;
  693. GetSelectedItems( arrSelectedItems );
  694. ActionFtbreak( arrSelectedItems );
  695. }
  696. void CFTTreeView::OnUpdateActionFtbreak(CCmdUI* pCmdUI)
  697. {
  698. CObArray arrSelectedItems;
  699. GetSelectedItems( arrSelectedItems );
  700. UpdateActionFtbreak( pCmdUI, arrSelectedItems );
  701. }
  702. void CFTTreeView::OnActionCreateExtendedPartition()
  703. {
  704. CObArray arrSelectedItems;
  705. GetSelectedItems( arrSelectedItems );
  706. ActionCreateExtendedPartition( arrSelectedItems );
  707. }
  708. void CFTTreeView::OnUpdateActionCreateExtendedPartition(CCmdUI* pCmdUI)
  709. {
  710. CObArray arrSelectedItems;
  711. GetSelectedItems( arrSelectedItems );
  712. UpdateActionCreateExtendedPartition( pCmdUI, arrSelectedItems );
  713. }
  714. void CFTTreeView::OnActionCreatePartition()
  715. {
  716. CObArray arrSelectedItems;
  717. GetSelectedItems( arrSelectedItems );
  718. ActionCreatePartition( arrSelectedItems );
  719. }
  720. void CFTTreeView::OnUpdateActionCreatePartition(CCmdUI* pCmdUI)
  721. {
  722. CObArray arrSelectedItems;
  723. GetSelectedItems( arrSelectedItems );
  724. UpdateActionCreatePartition( pCmdUI, arrSelectedItems );
  725. }
  726. void CFTTreeView::OnActionDelete()
  727. {
  728. CObArray arrSelectedItems;
  729. GetSelectedItems( arrSelectedItems );
  730. ActionDelete( arrSelectedItems );
  731. }
  732. void CFTTreeView::OnUpdateActionDelete(CCmdUI* pCmdUI)
  733. {
  734. CObArray arrSelectedItems;
  735. GetSelectedItems( arrSelectedItems );
  736. UpdateActionDelete( pCmdUI, arrSelectedItems );
  737. }
  738. void CFTTreeView::OnActionFtinit()
  739. {
  740. CObArray arrSelectedItems;
  741. GetSelectedItems( arrSelectedItems );
  742. ActionFtinit( arrSelectedItems );
  743. }
  744. void CFTTreeView::OnUpdateActionFtinit(CCmdUI* pCmdUI)
  745. {
  746. CObArray arrSelectedItems;
  747. GetSelectedItems( arrSelectedItems );
  748. UpdateActionFtinit( pCmdUI, arrSelectedItems );
  749. }
  750. void CFTTreeView::OnActionFtswap()
  751. {
  752. CObArray arrSelectedItems;
  753. GetSelectedItems( arrSelectedItems );
  754. ActionFtswap( arrSelectedItems );
  755. }
  756. void CFTTreeView::OnUpdateActionFtswap(CCmdUI* pCmdUI)
  757. {
  758. CObArray arrSelectedItems;
  759. GetSelectedItems( arrSelectedItems );
  760. UpdateActionFtswap( pCmdUI, arrSelectedItems );
  761. }
  762. void CFTTreeView::OnUpdateIndicatorName(CCmdUI* pCmdUI)
  763. {
  764. MY_TRY
  765. pCmdUI->Enable(TRUE);
  766. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  767. if( hItem == NULL )
  768. {
  769. pCmdUI->SetText( _T("") );
  770. return;
  771. }
  772. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData(hItem));
  773. ASSERT( pData );
  774. CString str;
  775. pData->GetDisplayName( str );
  776. pCmdUI->SetText( str );
  777. MY_CATCH
  778. }
  779. void CFTTreeView::OnUpdateIndicatorType(CCmdUI* pCmdUI)
  780. {
  781. MY_TRY
  782. pCmdUI->Enable(TRUE);
  783. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  784. if( hItem == NULL )
  785. {
  786. pCmdUI->SetText( _T("") );
  787. return;
  788. }
  789. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData(hItem));
  790. ASSERT( pData );
  791. CString str;
  792. pData->GetDisplayType( str );
  793. pCmdUI->SetText( str );
  794. MY_CATCH
  795. }
  796. void CFTTreeView::OnUpdateIndicatorDisks(CCmdUI* pCmdUI)
  797. {
  798. MY_TRY
  799. pCmdUI->Enable(TRUE);
  800. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  801. if( hItem == NULL )
  802. {
  803. pCmdUI->SetText( _T("") );
  804. return;
  805. }
  806. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData(hItem));
  807. ASSERT( pData );
  808. CString str;
  809. pData->GetDisplayDisksSet( str );
  810. pCmdUI->SetText( str );
  811. MY_CATCH
  812. }
  813. void CFTTreeView::OnUpdateIndicatorSize(CCmdUI* pCmdUI)
  814. {
  815. MY_TRY
  816. pCmdUI->Enable(TRUE);
  817. HTREEITEM hItem = GetTreeCtrl().GetSelectedItem();
  818. if( hItem == NULL )
  819. {
  820. pCmdUI->SetText( _T("") );
  821. return;
  822. }
  823. CItemData* pData = (CItemData*)(GetTreeCtrl().GetItemData(hItem));
  824. ASSERT( pData );
  825. CString str;
  826. pData->GetDisplaySize( str );
  827. pCmdUI->SetText( str );
  828. MY_CATCH
  829. }
  830. void CFTTreeView::OnUpdateIndicatorNothing(CCmdUI* pCmdUI)
  831. {
  832. MY_TRY
  833. pCmdUI->Enable(TRUE);
  834. pCmdUI->SetText( _T("") );
  835. MY_CATCH
  836. }
  837. /////////////////////////////////////////////////////////////////////////////
  838. // Friend methods
  839. /*
  840. Global function: GetVolumeReplacementForbiddenDisksSet
  841. Purpose: Retrieves the set of disks whose volumes cannot be used as replacements for a
  842. certain volume in a logical volume set ( stripe, mirror, stripe with parity, volume set )
  843. The function uses the volume hierarchy of the ( left pane )tree view
  844. Parameters: [IN] CFTTreeView* pTreeView
  845. Pointer to the tree view containing the volume hierarchy
  846. [IN] CItemData* pVolumeData
  847. Pointer to the volume data
  848. [OUT] CULONSet& setDisks
  849. The forbidden disks set
  850. Return value: -
  851. */
  852. void GetVolumeReplacementForbiddenDisksSet( CFTTreeView* pTreeView, CItemData* pVolumeData, CULONGSet& setDisks )
  853. {
  854. MY_TRY
  855. ASSERT( pTreeView );
  856. ASSERT( pVolumeData );
  857. setDisks.RemoveAll();
  858. HTREEITEM hVolumeItem = pVolumeData->GetTreeItem();
  859. ASSERT( hVolumeItem );
  860. HTREEITEM hParentItem = pTreeView->GetTreeCtrl().GetParentItem( hVolumeItem );
  861. // If our item has no parent then return an empty disks set
  862. if( hParentItem == NULL )
  863. return;
  864. CItemData* pParentData = (CItemData*)(pTreeView->GetTreeCtrl().GetItemData( hParentItem ));
  865. // hParentItem should be a valid item of the tree
  866. ASSERT( pParentData );
  867. // If the parent is not a logical volume return an empty disks set
  868. if( pParentData->GetItemType() != IT_LogicalVolume )
  869. return;
  870. // If the parent is a single FT partition return an empty disks set
  871. if( ((CLogicalVolumeData*)pParentData)->m_nVolType == FtPartition )
  872. return;
  873. // Now get the forbidden disks set of our item's parent
  874. GetVolumeReplacementForbiddenDisksSet( pTreeView, pParentData, setDisks );
  875. // Now add to the forbidden disks set the reunion of all our item's siblings disks sets
  876. // Attention: Only when the parent is a stripe, mirror or stripe set with parity! Not for volume sets!!
  877. if( ( ((CLogicalVolumeData*)pParentData)->m_nVolType == FtStripeSet ) ||
  878. ( ((CLogicalVolumeData*)pParentData)->m_nVolType == FtMirrorSet ) ||
  879. ( ((CLogicalVolumeData*)pParentData)->m_nVolType == FtStripeSetWithParity ) )
  880. {
  881. HTREEITEM hSiblingItem =pTreeView->GetTreeCtrl().GetChildItem(hParentItem);
  882. while( hSiblingItem != NULL )
  883. {
  884. if( hSiblingItem != hVolumeItem )
  885. {
  886. CItemData* pSiblingData = (CItemData*)(pTreeView->GetTreeCtrl().GetItemData(hSiblingItem));
  887. ASSERT(pSiblingData);
  888. setDisks += pSiblingData->GetDisksSet();
  889. }
  890. hSiblingItem = pTreeView->GetTreeCtrl().GetNextSiblingItem(hSiblingItem);
  891. }
  892. }
  893. MY_CATCH_AND_THROW
  894. }