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.

2496 lines
66 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: listview.cpp
  7. //
  8. // Contents: Implements Mobsync Custom Listview/TreeView control
  9. //
  10. // Classes: CListView
  11. //
  12. // Notes:
  13. //
  14. // History: 23-Jul-98 rogerg Created.
  15. //
  16. //--------------------------------------------------------------------------
  17. #include "lib.h"
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Member: CListView::CListView, public
  21. //
  22. // Synopsis: Constructor
  23. //
  24. // Arguments: hwnd - hwnd of the listView we are wrapping
  25. // hwndParent - Parent for this HWND.
  26. // idCtrl - ControlID for this item
  27. // msgNotify - messageID to use for sending notifyCommand to the Parent.
  28. //
  29. // Returns:
  30. //
  31. // Modifies:
  32. //
  33. // History: 23-Jul-98 rogerg Created.
  34. //
  35. //----------------------------------------------------------------------------
  36. CListView::CListView(HWND hwnd,HWND hwndParent,int idCtrl,UINT MsgNotify)
  37. {
  38. Assert(hwnd);
  39. m_hwnd = hwnd;
  40. m_hwndParent = hwndParent; // if parent null we just don't send notify messages
  41. m_idCtrl = idCtrl;
  42. m_MsgNotify = MsgNotify;
  43. m_pListViewItems = NULL;
  44. m_iListViewNodeCount = 0;
  45. m_iListViewArraySize = 0;
  46. m_iNumColumns = 0;
  47. m_iCheckCount = 0;
  48. m_dwExStyle = 0;
  49. // Up to caller to setup listView as OwnerData
  50. Assert(GetWindowLongA(m_hwnd,GWL_STYLE) & LVS_OWNERDATA);
  51. ListView_SetCallbackMask(m_hwnd, LVIS_STATEIMAGEMASK); // set for checkmark
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // Member: CListView::~CListView, public
  56. //
  57. // Synopsis: Constructor
  58. //
  59. // Arguments:
  60. //
  61. // Returns:
  62. //
  63. // Modifies:
  64. //
  65. // History: 23-Jul-98 rogerg Created.
  66. //
  67. //----------------------------------------------------------------------------
  68. CListView::~CListView()
  69. {
  70. DeleteAllItems();
  71. }
  72. //+---------------------------------------------------------------------------
  73. //
  74. // Member: CListView::DeleteAllItems, public
  75. //
  76. // Synopsis: Removes all items from the ListView
  77. //
  78. // Arguments:
  79. //
  80. // Returns:
  81. //
  82. // Modifies:
  83. //
  84. // History: 23-Jul-98 rogerg Created.
  85. //
  86. //----------------------------------------------------------------------------
  87. BOOL CListView::DeleteAllItems()
  88. {
  89. BOOL fReturn;
  90. fReturn = ListView_DeleteAllItems(m_hwnd);
  91. if (fReturn)
  92. {
  93. if (m_iListViewNodeCount)
  94. {
  95. LPLISTVIEWITEM pListViewCurItem;
  96. Assert(m_pListViewItems);
  97. // loop through the listview items deleting any subitems
  98. pListViewCurItem = m_pListViewItems + m_iListViewNodeCount -1;
  99. while(pListViewCurItem >= m_pListViewItems)
  100. {
  101. if(pListViewCurItem->pSubItems)
  102. {
  103. DeleteListViewItemSubItems(pListViewCurItem);
  104. }
  105. if (pListViewCurItem->lvItemEx.pszText)
  106. {
  107. Assert(LVIF_TEXT & pListViewCurItem->lvItemEx.mask);
  108. FREE(pListViewCurItem->lvItemEx.pszText);
  109. }
  110. if (pListViewCurItem->lvItemEx.pBlob)
  111. {
  112. Assert(LVIFEX_BLOB & pListViewCurItem->lvItemEx.maskEx);
  113. FREE(pListViewCurItem->lvItemEx.pBlob);
  114. }
  115. pListViewCurItem--;
  116. }
  117. m_iListViewNodeCount = 0;
  118. }
  119. // free our item buffer
  120. if (m_pListViewItems)
  121. {
  122. FREE(m_pListViewItems);
  123. m_pListViewItems = NULL;
  124. m_iListViewArraySize = 0;
  125. }
  126. m_iCheckCount = 0;
  127. }
  128. return fReturn;
  129. }
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Member: CListView::GetItemCount, public
  133. //
  134. // Synopsis: returns total number of items in the listview.
  135. //
  136. // Arguments:
  137. //
  138. // Returns:
  139. //
  140. // Modifies:
  141. //
  142. // History: 23-Jul-98 rogerg Created.
  143. //
  144. //----------------------------------------------------------------------------
  145. int CListView::GetItemCount()
  146. {
  147. return m_iListViewNodeCount;
  148. }
  149. //+---------------------------------------------------------------------------
  150. //
  151. // Member: CListView::GetSelectedCount, public
  152. //
  153. // Synopsis: returns number of selected items from the listview
  154. //
  155. // Arguments:
  156. //
  157. // Returns:
  158. //
  159. // Modifies:
  160. //
  161. // History: 23-Jul-98 rogerg Created.
  162. //
  163. //----------------------------------------------------------------------------
  164. UINT CListView::GetSelectedCount()
  165. {
  166. Assert(m_hwnd);
  167. return ListView_GetSelectedCount(m_hwnd);
  168. }
  169. //+---------------------------------------------------------------------------
  170. //
  171. // Member: CListView::GetSelectionMark, public
  172. //
  173. // Synopsis: returns index of the selection mark
  174. //
  175. // Arguments:
  176. //
  177. // Returns: itemId of the selection
  178. //
  179. // Modifies:
  180. //
  181. // History: 23-Jul-98 rogerg Created.
  182. //
  183. //----------------------------------------------------------------------------
  184. int CListView::GetSelectionMark()
  185. {
  186. int iNativeListViewId;
  187. int iReturnItem = -1;
  188. LPLISTVIEWITEM pListViewItem;
  189. Assert(m_hwnd);
  190. iNativeListViewId = ListView_GetSelectionMark(m_hwnd);
  191. if (-1 != iNativeListViewId)
  192. {
  193. pListViewItem = ListViewItemFromNativeListViewItemId(iNativeListViewId);
  194. if (pListViewItem)
  195. {
  196. iReturnItem = pListViewItem->lvItemEx.iItem;
  197. Assert(pListViewItem->iNativeListViewItemId == iNativeListViewId);
  198. }
  199. }
  200. return iReturnItem;
  201. }
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Member: CListView::GetImageList, public
  205. //
  206. // Synopsis: returns specified imagelist
  207. //
  208. // Arguments:
  209. //
  210. // Returns:
  211. //
  212. // Modifies:
  213. //
  214. // History: 23-Jul-98 rogerg Created.
  215. //
  216. //----------------------------------------------------------------------------
  217. HIMAGELIST CListView::GetImageList(int iImageList)
  218. {
  219. Assert(m_hwnd);
  220. return ListView_GetImageList(m_hwnd,iImageList);
  221. }
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Member: CListView::SetImageList, public
  225. //
  226. // Synopsis: sets specified imagelist
  227. //
  228. // Arguments:
  229. //
  230. // Returns:
  231. //
  232. // Modifies:
  233. //
  234. // History: 23-Jul-98 rogerg Created.
  235. //
  236. //----------------------------------------------------------------------------
  237. HIMAGELIST CListView::SetImageList(HIMAGELIST himage,int iImageList)
  238. {
  239. Assert(m_hwnd);
  240. return ListView_SetImageList(m_hwnd,himage,iImageList);
  241. }
  242. //+---------------------------------------------------------------------------
  243. //
  244. // Member: CListView::SetExtendedListViewStyle, public
  245. //
  246. // Synopsis: sets the list view style
  247. //
  248. // Arguments:
  249. //
  250. // Returns:
  251. //
  252. // Modifies:
  253. //
  254. // History: 23-Jul-98 rogerg Created.
  255. //
  256. //----------------------------------------------------------------------------
  257. void CListView::SetExtendedListViewStyle(DWORD dwExStyle)
  258. {
  259. // !!Handle checkboxes ourselves.
  260. // AssertSz(0,"impl extended style with checkboxes");
  261. Assert(m_hwnd);
  262. ListView_SetExtendedListViewStyle(m_hwnd,dwExStyle);
  263. m_dwExStyle = dwExStyle;
  264. }
  265. //+---------------------------------------------------------------------------
  266. //
  267. // Member: CListView::InsertItem, public
  268. //
  269. // Synopsis: wrapper for ListView_InsertItem
  270. //
  271. // Arguments:
  272. //
  273. // Returns:
  274. //
  275. // Modifies:
  276. //
  277. // History: 23-Jul-98 rogerg Created.
  278. //
  279. //----------------------------------------------------------------------------
  280. BOOL CListView::InsertItem(LPLVITEMEX pitem)
  281. {
  282. LPLISTVIEWITEM pNewListViewItem = NULL;
  283. LPLISTVIEWITEM pListViewSubItems = NULL;
  284. LPWSTR pszText = NULL;
  285. LPLVBLOB pBlob = NULL;
  286. int iListViewIndex; // location item will be inserted
  287. int iParentIndex = LVI_ROOT;
  288. BOOL fInsertNative = FALSE;
  289. int iIndent = 0; // indent for the item.
  290. int iNativeInsertAtItemID = -1;
  291. // Cannot use insert to add a subitem
  292. // and need at least one column
  293. if (0 != pitem->iSubItem || (0 == m_iNumColumns))
  294. {
  295. Assert(0 != m_iNumColumns);
  296. Assert(0 == pitem->iSubItem);
  297. goto error;
  298. }
  299. Assert(0 == (pitem->maskEx & ~(LVIFEX_VALIDFLAGMASK)));
  300. // if a parent is specified check for special flags and
  301. // calc iItem or determine given iItem is invalid
  302. // #define LVI_ROOT -1; // itemID to pass in for ParenItemID for root
  303. // #define LVI_FIRST -0x0FFFE
  304. // #define LVI_LAST -0x0FFFF
  305. // While validatin Determine if item should be immediately added to the listview
  306. // by a) if has parent that is expanded and has an assigned listviewID
  307. // or b) this is a toplevel item.
  308. // this is done when validating the itemID and setting the fInsertNative var
  309. LPLISTVIEWITEM pParentItem;
  310. LISTVIEWITEM lviRootNode;
  311. // if have a valid parent look it up else use the root
  312. if ((LVIFEX_PARENT & pitem->maskEx) && !(LVI_ROOT == pitem->iParent) )
  313. {
  314. pParentItem = ListViewItemFromIndex(pitem->iParent);
  315. }
  316. else
  317. {
  318. pParentItem = &lviRootNode;
  319. lviRootNode.lvItemEx.iItem = LVI_ROOT;
  320. lviRootNode.lvItemEx.iIndent = -1;
  321. lviRootNode.fExpanded = TRUE;
  322. }
  323. if (NULL == pParentItem)
  324. {
  325. Assert(NULL != pParentItem);
  326. goto error;
  327. }
  328. // found parent so go ahead and set the iIndent
  329. iParentIndex = pParentItem->lvItemEx.iItem;
  330. iIndent = pParentItem->lvItemEx.iIndent + 1;
  331. fInsertNative = pParentItem->fExpanded;
  332. // if LVI_FIRST for item then parent item + 1
  333. // else we need to find either the next node
  334. // at the same level as the parent or hit the
  335. // end of the list.
  336. if (LVI_FIRST == pitem->iItem)
  337. {
  338. iListViewIndex = pParentItem->lvItemEx.iItem + 1;
  339. }
  340. else
  341. {
  342. int iNextParentiItem = -1;
  343. LPLISTVIEWITEM pNextParent = pParentItem + 1;
  344. LPLISTVIEWITEM pLastItem = m_pListViewItems + m_iListViewNodeCount -1;
  345. // if parent is the root node then skip since know Nextparent is the
  346. // last node.
  347. if (pParentItem != &lviRootNode)
  348. {
  349. // calc of last item assumes have at least one node
  350. // if we don't then how can we have a parent?
  351. if (m_iListViewNodeCount < 1)
  352. {
  353. goto error;
  354. }
  355. while (pNextParent <= pLastItem)
  356. {
  357. if (pNextParent->lvItemEx.iIndent == pParentItem->lvItemEx.iIndent)
  358. {
  359. iNextParentiItem = pNextParent->lvItemEx.iItem;
  360. break;
  361. }
  362. ++pNextParent;
  363. }
  364. }
  365. // if out of loop and NexParentItem is still -1 means hit the
  366. // end of list
  367. if (-1 == iNextParentiItem)
  368. {
  369. if (m_iListViewNodeCount)
  370. {
  371. iNextParentiItem = pLastItem->lvItemEx.iItem + 1;
  372. }
  373. else
  374. {
  375. iNextParentiItem = 0;
  376. }
  377. }
  378. if (LVI_LAST == pitem->iItem)
  379. {
  380. iListViewIndex = iNextParentiItem;
  381. }
  382. else
  383. {
  384. // if user specified theitem it better fall within a valid range.
  385. if (pitem->iItem > iNextParentiItem ||
  386. pitem->iItem <= pParentItem->lvItemEx.iItem)
  387. {
  388. Assert(pitem->iItem <= iNextParentiItem);
  389. Assert(pitem->iItem > pParentItem->lvItemEx.iItem);
  390. goto error;
  391. }
  392. iListViewIndex = pitem->iItem;
  393. }
  394. }
  395. // make sure buffer is big enough
  396. // !!! Warning any pointers items in the ListView Array
  397. // will be invalid after the realloc/alloc.
  398. if (m_iListViewArraySize < (m_iListViewNodeCount + 1))
  399. {
  400. int iNewArraySize = m_iListViewNodeCount + 10;
  401. LPLISTVIEWITEM pListViewItemsOrig = m_pListViewItems;
  402. ULONG cbAlloc = iNewArraySize*sizeof(LISTVIEWITEM);
  403. if (m_pListViewItems)
  404. {
  405. if (ERROR_SUCCESS != REALLOC((void **)&m_pListViewItems, cbAlloc))
  406. {
  407. FREE(m_pListViewItems);
  408. m_pListViewItems = NULL;
  409. }
  410. }
  411. else
  412. {
  413. m_pListViewItems = (LPLISTVIEWITEM) ALLOC(cbAlloc);
  414. }
  415. // if couldn't alloc or realloc failed then fail the insert
  416. if (NULL == m_pListViewItems)
  417. {
  418. m_pListViewItems = pListViewItemsOrig;
  419. goto error;
  420. }
  421. m_iListViewArraySize = iNewArraySize;
  422. }
  423. Assert(m_pListViewItems);
  424. if (NULL == m_pListViewItems)
  425. {
  426. goto error;
  427. }
  428. // if have subitems make sure we can allocate the subitems before
  429. // moving all the nodes. This is number of columns minus one since
  430. // column offset 0 is stored in main array
  431. pListViewSubItems = NULL;
  432. if (m_iNumColumns > 1)
  433. {
  434. ULONG ulAllocSize = (m_iNumColumns -1)*sizeof(LISTVIEWITEM);
  435. int iSubItem;
  436. LPLISTVIEWITEM pCurSubItem;
  437. pListViewSubItems = (LPLISTVIEWITEM) ALLOC(ulAllocSize);
  438. if (NULL == pListViewSubItems)
  439. {
  440. goto error;
  441. }
  442. pCurSubItem = pListViewSubItems;
  443. iSubItem = 1;
  444. while (iSubItem < m_iNumColumns)
  445. {
  446. pCurSubItem->lvItemEx.iItem = iListViewIndex;
  447. pCurSubItem->lvItemEx.iSubItem = iSubItem;
  448. ++iSubItem;
  449. ++pCurSubItem;
  450. }
  451. }
  452. // make sure can allocate text and anything else
  453. // that can faile if need to before move
  454. // everything down so don't have to undo.
  455. if (pitem->mask & LVIF_TEXT)
  456. {
  457. int cchSize;
  458. if (NULL == pitem->pszText)
  459. {
  460. pszText = NULL;
  461. }
  462. else
  463. {
  464. cchSize = (lstrlen(pitem->pszText) + 1);
  465. pszText = (LPWSTR) ALLOC(cchSize * sizeof(WCHAR));
  466. if (NULL == pszText)
  467. {
  468. goto error;
  469. }
  470. StrCpyN(pszText, pitem->pszText, cchSize);
  471. }
  472. }
  473. if (pitem->maskEx & LVIFEX_BLOB)
  474. {
  475. ULONG cbSize;
  476. if (NULL == pitem->pBlob)
  477. {
  478. Assert(pitem->pBlob);
  479. goto error;
  480. }
  481. cbSize = pitem->pBlob->cbSize;
  482. pBlob = (LPLVBLOB) ALLOC(cbSize);
  483. if (NULL == pBlob)
  484. {
  485. goto error;
  486. }
  487. memcpy(pBlob,pitem->pBlob,cbSize);
  488. }
  489. // !!!Nothing should fail after this line other than possibly
  490. // inserting into the Native ListView in which case
  491. // it will still be in our list but not shown to the User.
  492. // Move existing elements down that item is inserted ahead of.
  493. // if the item is going to be immediately added to the ListView then
  494. pNewListViewItem = m_pListViewItems + iListViewIndex;
  495. if (m_iListViewNodeCount)
  496. {
  497. LPLISTVIEWITEM pListViewMoveItem;
  498. pListViewMoveItem = m_pListViewItems + m_iListViewNodeCount -1;
  499. Assert(m_iListViewArraySize > m_iListViewNodeCount);
  500. while (pListViewMoveItem >= pNewListViewItem) // want >= so move node at current item location
  501. {
  502. int iMoveParent;
  503. ++(pListViewMoveItem->lvItemEx.iItem); // increment the iItem
  504. // if parent fails within move range increment the ParentId
  505. iMoveParent = pListViewMoveItem->lvItemEx.iParent;
  506. if ( (LVI_ROOT != iMoveParent) && (iMoveParent >= iListViewIndex))
  507. {
  508. ++(pListViewMoveItem->lvItemEx.iParent);
  509. }
  510. *(pListViewMoveItem + 1) = *(pListViewMoveItem);
  511. --pListViewMoveItem;
  512. }
  513. }
  514. // now insert the item at the specified location
  515. ++m_iListViewNodeCount;
  516. pNewListViewItem->pSubItems = pListViewSubItems;
  517. pNewListViewItem->fExpanded = TRUE; /// Review if want this to be user defined.but we expand children by default
  518. pNewListViewItem->iChildren = 0;
  519. pNewListViewItem->iNativeListViewItemId = -1;
  520. // fixup lvItem data
  521. pNewListViewItem->lvItemEx = *pitem;
  522. pNewListViewItem->lvItemEx.pszText = pszText;
  523. pNewListViewItem->lvItemEx.iItem = iListViewIndex;
  524. pNewListViewItem->lvItemEx.iIndent = iIndent;
  525. pNewListViewItem->lvItemEx.maskEx |= LVIFEX_PARENT; // always force valid parent
  526. pNewListViewItem->lvItemEx.pBlob = pBlob;
  527. pNewListViewItem->lvItemEx.iParent = iParentIndex;
  528. // Review - For now Don't call SetItem so State CheckBox isn't updated.
  529. // Client must call SetItem after the insert to setup the ImageState
  530. // Assert that client isn't passing in a statImage on an Insert.
  531. Assert(!(pNewListViewItem->lvItemEx.mask & LVIF_STATE)
  532. || !(pNewListViewItem->lvItemEx.stateMask & LVIS_STATEIMAGEMASK));
  533. pNewListViewItem->lvItemEx.state = 0;
  534. pNewListViewItem->lvItemEx.stateMask = 0;
  535. // if have a parent other than the root incrment its children count
  536. // !! Note have to find again in case a realloc happened
  537. if (iParentIndex != LVI_ROOT)
  538. {
  539. pParentItem = ListViewItemFromIndex(iParentIndex);
  540. Assert(pParentItem);
  541. if (pParentItem)
  542. {
  543. ++(pParentItem->iChildren);
  544. }
  545. }
  546. if (fInsertNative)
  547. {
  548. // walk back and add 1 to
  549. // first item we come to that already is in the listview. if none assigned
  550. // iNativeInsertAtItemID should be zero.
  551. iNativeInsertAtItemID = 0;
  552. LPLISTVIEWITEM pListViewPrevItem;
  553. pListViewPrevItem = pNewListViewItem -1;
  554. while (pListViewPrevItem >= m_pListViewItems)
  555. {
  556. if (-1 != pListViewPrevItem->iNativeListViewItemId)
  557. {
  558. iNativeInsertAtItemID = pListViewPrevItem->iNativeListViewItemId + 1;
  559. break;
  560. }
  561. --pListViewPrevItem;
  562. }
  563. }
  564. else
  565. {
  566. iNativeInsertAtItemID = -1;
  567. }
  568. if (-1 != iNativeInsertAtItemID)
  569. {
  570. LV_ITEM lvi = { 0 };
  571. LPLISTVIEWITEM pListViewMoveItem;
  572. LPLISTVIEWITEM pLastItem;
  573. Assert(fInsertNative);
  574. lvi.iItem = iNativeInsertAtItemID;
  575. pNewListViewItem->iNativeListViewItemId = ListView_InsertItem(m_hwnd,&lvi);
  576. Assert(iNativeInsertAtItemID == pNewListViewItem->iNativeListViewItemId);
  577. if (-1 != pNewListViewItem->iNativeListViewItemId)
  578. {
  579. // fix up NativeIds of items below
  580. pLastItem = m_pListViewItems + m_iListViewNodeCount - 1;
  581. pListViewMoveItem = pNewListViewItem + 1;
  582. while (pListViewMoveItem <= pLastItem)
  583. {
  584. if (-1 != pListViewMoveItem->iNativeListViewItemId)
  585. {
  586. ++(pListViewMoveItem->iNativeListViewItemId);
  587. }
  588. ++pListViewMoveItem;
  589. }
  590. }
  591. }
  592. // after calling native listview fix up the state vars in local item to
  593. // not include the low byte
  594. pNewListViewItem->lvItemEx.state &= ~0xFF;
  595. pNewListViewItem->lvItemEx.stateMask &= ~0xFF;
  596. return iListViewIndex; // return new index even if fail to add to native listview
  597. error:
  598. if (pListViewSubItems)
  599. {
  600. FREE(pListViewSubItems);
  601. }
  602. if (pszText)
  603. {
  604. FREE(pszText);
  605. }
  606. if (pBlob)
  607. {
  608. FREE(pBlob);
  609. }
  610. return FALSE;
  611. }
  612. //+---------------------------------------------------------------------------
  613. //
  614. // Member: CListView::DeleteItem, public
  615. //
  616. // Synopsis: Deletes the specified lvItem
  617. //
  618. // Arguments:
  619. //
  620. // Returns:
  621. //
  622. // Modifies:
  623. //
  624. // History: 23-Jul-98 rogerg Created.
  625. //
  626. //----------------------------------------------------------------------------
  627. BOOL CListView::DeleteItem(int iItem)
  628. {
  629. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(iItem);
  630. LPLISTVIEWITEM pListViewCurItem;
  631. LPLISTVIEWITEM pListViewLastItem;
  632. int iNativeListViewId;
  633. int iParent;
  634. if (NULL == pListViewItem || (m_iListViewNodeCount < 1))
  635. {
  636. Assert(pListViewItem);
  637. Assert(m_iListViewNodeCount > 0); // should be at least one item.
  638. return FALSE;
  639. }
  640. // delete the item data and then move all items below this one up
  641. // in the array. if the Item is in the ListView and native delete succeeded
  642. // decrement their nativeID count.
  643. // !REMEMBER TO DECREMENT THE parents iChildren count if have a parent and
  644. // total count of number of items in the list view.
  645. if (0 != pListViewItem->iChildren)
  646. {
  647. Assert(0 == pListViewItem->iChildren); // don't support delete of parent nodes.
  648. return FALSE;
  649. }
  650. iNativeListViewId = pListViewItem->iNativeListViewItemId;
  651. iParent = pListViewItem->lvItemEx.iParent;
  652. // update toplevel vars and item info by calling
  653. // setitem to uncheck and clear text, and blob so
  654. LVITEMEX pitem;
  655. pitem.iItem = iItem;
  656. pitem.iSubItem = 0;
  657. pitem.mask = LVIF_TEXT;
  658. pitem.maskEx = LVIFEX_BLOB;
  659. pitem.pszText = NULL;
  660. pitem.pBlob = NULL;
  661. // only need to set the state if have checkboxes
  662. if (m_dwExStyle & LVS_EX_CHECKBOXES)
  663. {
  664. pitem.mask |= LVIF_STATE;
  665. pitem.state = LVIS_STATEIMAGEMASK_UNCHECK;
  666. pitem.stateMask = LVIS_STATEIMAGEMASK;
  667. }
  668. SetItem(&pitem);
  669. // update parent to tell it it has one less item.
  670. if (LVI_ROOT != iParent)
  671. {
  672. LPLISTVIEWITEM pListViewItemParent;
  673. if (pListViewItemParent = ListViewItemFromIndex(iParent))
  674. {
  675. --(pListViewItemParent->iChildren);
  676. Assert(pListViewItemParent->iChildren >= 0);
  677. }
  678. Assert(pListViewItemParent);
  679. }
  680. // set the current item to the end of the list
  681. Assert(m_iListViewNodeCount >= 1); // if no nodes should have already bailed.
  682. pListViewLastItem = m_pListViewItems + m_iListViewNodeCount - 1;
  683. // delete the SubItems if any associated with the ListView.
  684. DeleteListViewItemSubItems(pListViewItem);
  685. Assert(NULL == pListViewItem->lvItemEx.pszText);
  686. Assert(NULL == pListViewItem->lvItemEx.pBlob);
  687. // delete the item from the native listView if fails will just have
  688. // a blank item at the bottom of the native listview.
  689. if (-1 != iNativeListViewId)
  690. {
  691. ListView_DeleteItem(m_hwnd,iNativeListViewId);
  692. }
  693. // decrement the toplevel nodecount
  694. --m_iListViewNodeCount;
  695. pListViewCurItem = pListViewItem;
  696. // move items remaining in the ListView up updateing iNativeListViewId
  697. // if appropriate.
  698. while (pListViewCurItem < pListViewLastItem)
  699. {
  700. *(pListViewCurItem) = *(pListViewCurItem + 1);
  701. if ( (-1 != iNativeListViewId)
  702. && (-1 != pListViewCurItem->iNativeListViewItemId))
  703. {
  704. --pListViewCurItem->iNativeListViewItemId;
  705. }
  706. --(pListViewCurItem->lvItemEx.iItem); // decrement it iItem
  707. // if items parentID falls within pListViewItem and this item
  708. // range need to update our iParent.
  709. // parent should nevert be == iItem since don't allow nodes
  710. // with children to be deleted but check <= anyways
  711. if (LVI_ROOT != pListViewCurItem->lvItemEx.iParent)
  712. {
  713. if (iItem <= pListViewCurItem->lvItemEx.iParent)
  714. {
  715. --(pListViewCurItem->lvItemEx.iParent);
  716. }
  717. }
  718. ++pListViewCurItem;
  719. }
  720. return TRUE;
  721. }
  722. //+---------------------------------------------------------------------------
  723. //
  724. // Member: CListView::DeleteChildren, public
  725. //
  726. // Synopsis: Deletes all child nodes associated with the item.
  727. //
  728. // Arguments:
  729. //
  730. // Returns:
  731. //
  732. // Modifies:
  733. //
  734. // History: 23-Jul-98 rogerg Created.
  735. //
  736. //----------------------------------------------------------------------------
  737. BOOL CListView::DeleteChildren(int iItem)
  738. {
  739. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(iItem);
  740. LPLISTVIEWITEM pListViewCurItem;
  741. LPLISTVIEWITEM pLastListViewItem;
  742. int iNumChildren;
  743. if (!pListViewItem || m_iListViewNodeCount < 1)
  744. {
  745. Assert(pListViewItem);
  746. Assert(m_iListViewNodeCount >= 1); // should at least have one node.
  747. return FALSE;
  748. }
  749. iNumChildren = pListViewItem->iChildren;
  750. pLastListViewItem = m_pListViewItems + m_iListViewNodeCount - 1;
  751. if (0 > iNumChildren)
  752. {
  753. Assert(0 <= iNumChildren); // this count should never go negative.
  754. return FALSE;
  755. }
  756. // if no children just return;
  757. if (0 == iNumChildren)
  758. {
  759. return TRUE;
  760. }
  761. // verify all children don't have any children of there own. if they
  762. // do we don't support this. Also verify that don't run off
  763. // end of the list in which case we fail too.
  764. pListViewCurItem = pListViewItem + iNumChildren;
  765. if (pListViewCurItem > pLastListViewItem)
  766. {
  767. AssertSz(0,"Children run off end of ListView");
  768. return FALSE;
  769. }
  770. while (pListViewCurItem > pListViewItem)
  771. {
  772. if (pListViewCurItem->iChildren > 0)
  773. {
  774. AssertSz(0,"Trying to DeleteChildren when Children have Children");
  775. return FALSE;
  776. }
  777. --pListViewCurItem;
  778. }
  779. // all items verified, just loop through deleting the items starting at the bottom.
  780. pListViewCurItem = pListViewItem + iNumChildren;
  781. while (pListViewCurItem > pListViewItem)
  782. {
  783. DeleteItem(pListViewCurItem->lvItemEx.iItem); // if any fail delete what we can.
  784. --pListViewCurItem;
  785. }
  786. return TRUE;
  787. }
  788. //+---------------------------------------------------------------------------
  789. //
  790. // Member: CListView::SetItem, public
  791. //
  792. // Synopsis: wrapper for ListView_SetItem
  793. //
  794. // Arguments:
  795. //
  796. // Returns:
  797. //
  798. // Modifies:
  799. //
  800. // History: 23-Jul-98 rogerg Created.
  801. //
  802. //----------------------------------------------------------------------------
  803. BOOL CListView::SetItem(LPLVITEMEX pitem)
  804. {
  805. int iNativeListViewItemId;
  806. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(pitem->iItem,pitem->iSubItem,&iNativeListViewItemId);
  807. LPLVITEMEX plvItemEx;
  808. BOOL fCheckCountChanged = FALSE;
  809. LVITEMSTATE fNewCheckCountState;
  810. LPWSTR pszNewText = NULL;
  811. LPLVBLOB pNewBlob = NULL;
  812. if (NULL == pListViewItem)
  813. {
  814. Assert(pListViewItem);
  815. return FALSE;
  816. }
  817. Assert(pListViewItem->lvItemEx.iSubItem == pitem->iSubItem);
  818. Assert(pListViewItem->lvItemEx.iSubItem > 0
  819. || pListViewItem->iNativeListViewItemId == iNativeListViewItemId);
  820. plvItemEx = &(pListViewItem->lvItemEx);
  821. // allocate new text
  822. if (LVIF_TEXT & pitem->mask)
  823. {
  824. int cchSize;
  825. if (NULL == pitem->pszText)
  826. {
  827. pszNewText = NULL;
  828. }
  829. else
  830. {
  831. cchSize = (lstrlen(pitem->pszText) + 1);
  832. pszNewText = (LPWSTR) ALLOC(cchSize *sizeof(WCHAR));
  833. if (NULL == pszNewText)
  834. {
  835. goto error;
  836. }
  837. StrCpyN(pszNewText, pitem->pszText, cchSize);
  838. }
  839. }
  840. // allocate new blob
  841. if (LVIFEX_BLOB & pitem->maskEx)
  842. {
  843. if (NULL == pitem->pBlob)
  844. {
  845. pNewBlob = NULL;
  846. }
  847. else
  848. {
  849. pNewBlob = (LPLVBLOB) ALLOC(pitem->pBlob->cbSize);
  850. if (NULL == pNewBlob)
  851. {
  852. goto error;
  853. }
  854. memcpy(pNewBlob,pitem->pBlob,pitem->pBlob->cbSize);
  855. }
  856. }
  857. // now that can't fail update the text and blob field appropriately
  858. if (LVIF_TEXT & pitem->mask)
  859. {
  860. if (plvItemEx->pszText)
  861. {
  862. FREE(plvItemEx->pszText);
  863. }
  864. plvItemEx->pszText = pszNewText;
  865. plvItemEx->mask |= LVIF_TEXT;
  866. pszNewText = NULL;
  867. }
  868. if (LVIFEX_BLOB & pitem->maskEx)
  869. {
  870. if (plvItemEx->pBlob)
  871. {
  872. FREE(plvItemEx->pBlob);
  873. }
  874. plvItemEx->pBlob = pNewBlob;
  875. plvItemEx->mask |= LVIFEX_BLOB;
  876. pNewBlob = NULL;
  877. }
  878. if (LVIF_IMAGE & pitem->mask)
  879. {
  880. plvItemEx->mask |= LVIF_IMAGE;
  881. plvItemEx->iImage = pitem->iImage;
  882. }
  883. if (LVIF_PARAM & pitem->mask)
  884. {
  885. plvItemEx->mask |= LVIF_PARAM;
  886. plvItemEx->lParam = pitem->lParam;
  887. }
  888. // update the item state.
  889. if (LVIF_STATE & pitem->mask)
  890. {
  891. plvItemEx->mask |= LVIF_STATE;
  892. // only care about #define LVIS_OVERLAYMASK, LVIS_STATEIMAGEMASK
  893. if (pitem->stateMask & LVIS_OVERLAYMASK)
  894. {
  895. plvItemEx->stateMask |= LVIS_OVERLAYMASK;
  896. plvItemEx->state = (pitem->state & LVIS_OVERLAYMASK )
  897. + (plvItemEx->state & ~LVIS_OVERLAYMASK);
  898. }
  899. if (pitem->stateMask & LVIS_STATEIMAGEMASK)
  900. {
  901. // update the m_iCheckCount (indeterminate doesn't contribute.
  902. if ( (plvItemEx->iSubItem == 0)
  903. && ( (pitem->state & LVIS_STATEIMAGEMASK) != (plvItemEx->state & LVIS_STATEIMAGEMASK)))
  904. {
  905. // don't set fCheckCountChange unless it actually did.
  906. if ( (pListViewItem->lvItemEx.state & LVIS_STATEIMAGEMASK) == LVIS_STATEIMAGEMASK_CHECK)
  907. {
  908. fCheckCountChanged = TRUE;
  909. fNewCheckCountState = LVITEMEXSTATE_UNCHECKED;
  910. --m_iCheckCount;
  911. }
  912. if ( (pitem->state & LVIS_STATEIMAGEMASK) == LVIS_STATEIMAGEMASK_CHECK)
  913. {
  914. fCheckCountChanged = TRUE;
  915. fNewCheckCountState = LVITEMEXSTATE_CHECKED;
  916. ++m_iCheckCount;
  917. }
  918. Assert(m_iCheckCount >= 0);
  919. Assert(m_iCheckCount <= m_iListViewNodeCount);
  920. }
  921. plvItemEx->stateMask |= LVIS_STATEIMAGEMASK;
  922. plvItemEx->state = (pitem->state & LVIS_STATEIMAGEMASK)
  923. + (plvItemEx->state & ~LVIS_STATEIMAGEMASK);
  924. }
  925. }
  926. // if the check count changed and we have checkboxes send the notification
  927. // if item state has changed send the count notification
  928. if (fCheckCountChanged && m_hwndParent && (m_dwExStyle & LVS_EX_CHECKBOXES))
  929. {
  930. NMLISTVIEWEXITEMCHECKCOUNT lvCheckCount;
  931. lvCheckCount.hdr.hwndFrom = m_hwnd;
  932. lvCheckCount.hdr.idFrom = m_idCtrl;
  933. lvCheckCount.hdr.code = LVNEX_ITEMCHECKCOUNT;
  934. lvCheckCount.iCheckCount = m_iCheckCount;
  935. lvCheckCount.iItemId = pitem->iItem;
  936. lvCheckCount.dwItemState = fNewCheckCountState; // new state of the item whose checkcount has changed.
  937. SendMessage(m_hwndParent,m_MsgNotify,m_idCtrl,(LPARAM) &lvCheckCount);
  938. }
  939. // if item is in the native list view, redraw item to reflect new state
  940. // bug bug, doesn't handle subitems
  941. if (-1 != iNativeListViewItemId)
  942. {
  943. // if state changed pass it along for focus
  944. if ((LVIF_STATE & pitem->mask) && (0 == pitem->iSubItem))
  945. {
  946. int stateMask = pitem->stateMask & 0xff;
  947. if (stateMask)
  948. {
  949. ListView_SetItemState(m_hwnd,iNativeListViewItemId,pitem->state,stateMask);
  950. }
  951. }
  952. ListView_RedrawItems(m_hwnd,iNativeListViewItemId,iNativeListViewItemId);
  953. }
  954. return TRUE;
  955. error:
  956. if (pszNewText)
  957. {
  958. FREE(pszNewText);
  959. }
  960. if (pNewBlob)
  961. {
  962. FREE(pNewBlob);
  963. }
  964. return FALSE;
  965. }
  966. //+---------------------------------------------------------------------------
  967. //
  968. // Member: CListView::SetItemState, public
  969. //
  970. // Synopsis: wrapper for ListView_SetItemState
  971. //
  972. // Arguments:
  973. //
  974. // Returns:
  975. //
  976. // Modifies:
  977. //
  978. // History: 23-Jul-98 rogerg Created.
  979. //
  980. //----------------------------------------------------------------------------
  981. BOOL CListView::SetItemState(int iItem,UINT state,UINT mask)
  982. {
  983. LVITEMEX lvitemEx;
  984. lvitemEx.iItem = iItem;
  985. lvitemEx.iSubItem = 0;
  986. lvitemEx.mask = LVIF_STATE ;
  987. lvitemEx.state = state;
  988. lvitemEx.stateMask = mask;
  989. lvitemEx.maskEx = 0;
  990. return SetItem(&lvitemEx);
  991. }
  992. //+---------------------------------------------------------------------------
  993. //
  994. // Member: CListView::SetItemlParam, public
  995. //
  996. // Synopsis: wrapper for setting the lParam
  997. //
  998. // Arguments:
  999. //
  1000. // Returns:
  1001. //
  1002. // Modifies:
  1003. //
  1004. // History: 23-Jul-98 rogerg Created.
  1005. //
  1006. //----------------------------------------------------------------------------
  1007. BOOL CListView::SetItemlParam(int iItem,LPARAM lParam)
  1008. {
  1009. LVITEMEX lvitemEx;
  1010. lvitemEx.iItem = iItem;
  1011. lvitemEx.iSubItem = 0;
  1012. lvitemEx.mask = LVIF_PARAM ;
  1013. lvitemEx.lParam = lParam;
  1014. lvitemEx.maskEx = 0;
  1015. return SetItem(&lvitemEx);
  1016. }
  1017. //+---------------------------------------------------------------------------
  1018. //
  1019. // Member: CListView::SetItemText, public
  1020. //
  1021. // Synopsis: wrapper for setting the item text.
  1022. //
  1023. // Arguments:
  1024. //
  1025. // Returns:
  1026. //
  1027. // Modifies:
  1028. //
  1029. // History: 23-Jul-98 rogerg Created.
  1030. //
  1031. //----------------------------------------------------------------------------
  1032. BOOL CListView::SetItemText(int iItem,int iSubItem,LPWSTR pszText)
  1033. {
  1034. LVITEMEX lvitemEx;
  1035. lvitemEx.iItem = iItem;
  1036. lvitemEx.iSubItem = iSubItem;
  1037. lvitemEx.mask = LVIF_TEXT;
  1038. lvitemEx.pszText = pszText;
  1039. lvitemEx.maskEx = 0;
  1040. return SetItem(&lvitemEx);
  1041. }
  1042. //+---------------------------------------------------------------------------
  1043. //
  1044. // Member: CListView::GetItem, public
  1045. //
  1046. // Synopsis: wrapper for ListView_GetItem
  1047. //
  1048. // Arguments:
  1049. //
  1050. // Returns:
  1051. //
  1052. // Modifies:
  1053. //
  1054. // History: 23-Jul-98 rogerg Created.
  1055. //
  1056. //----------------------------------------------------------------------------
  1057. BOOL CListView::GetItem(LPLVITEMEX pitem)
  1058. {
  1059. int iNativeListViewItemId;
  1060. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(pitem->iItem,pitem->iSubItem,&iNativeListViewItemId);
  1061. if (NULL == pListViewItem)
  1062. {
  1063. Assert(pListViewItem);
  1064. return FALSE;
  1065. }
  1066. // add text first. Since it is the only item
  1067. if (LVIF_TEXT & pitem->mask)
  1068. {
  1069. if (!(pListViewItem->lvItemEx.pszText) || (0 == pitem->cchTextMax)
  1070. || !(pListViewItem->lvItemEx.mask & LVIF_TEXT) )
  1071. {
  1072. pitem->pszText = NULL;
  1073. }
  1074. else
  1075. {
  1076. int cchListTextSize = lstrlen(pListViewItem->lvItemEx.pszText);
  1077. StrCpyN(pitem->pszText,pListViewItem->lvItemEx.pszText,pitem->cchTextMax);
  1078. }
  1079. }
  1080. if (LVIF_IMAGE & pitem->mask)
  1081. {
  1082. pitem->iImage = pListViewItem->lvItemEx.iImage;
  1083. }
  1084. if (LVIF_PARAM & pitem->mask)
  1085. {
  1086. pitem->lParam = pListViewItem->lvItemEx.lParam;
  1087. }
  1088. // update the item state.
  1089. if (LVIF_STATE & pitem->mask)
  1090. {
  1091. pitem->state = pListViewItem->lvItemEx.state;
  1092. }
  1093. return TRUE;
  1094. }
  1095. //+---------------------------------------------------------------------------
  1096. //
  1097. // Member: CListView::GetItemText, public
  1098. //
  1099. // Synopsis: wrapper for ListView_GetItem
  1100. //
  1101. // Arguments:
  1102. //
  1103. // Returns:
  1104. //
  1105. // Modifies:
  1106. //
  1107. // History: 23-Jul-98 rogerg Created.
  1108. //
  1109. //----------------------------------------------------------------------------
  1110. BOOL CListView::GetItemText(int iItem,int iSubItem,LPWSTR pszText,int cchTextMax)
  1111. {
  1112. LVITEMEX lvitem;
  1113. lvitem.mask = LVIF_TEXT;
  1114. lvitem.maskEx = 0;
  1115. lvitem.iItem = iItem;
  1116. lvitem.iSubItem = iSubItem;
  1117. lvitem.pszText = pszText;
  1118. lvitem.cchTextMax = cchTextMax;
  1119. return GetItem(&lvitem);
  1120. }
  1121. //+---------------------------------------------------------------------------
  1122. //
  1123. // Member: CListView::GetItemlParam, public
  1124. //
  1125. // Synopsis: wrapper for gettting the lparam
  1126. //
  1127. // Arguments:
  1128. //
  1129. // Returns:
  1130. //
  1131. // Modifies:
  1132. //
  1133. // History: 23-Jul-98 rogerg Created.
  1134. //
  1135. //----------------------------------------------------------------------------
  1136. BOOL CListView::GetItemlParam(int iItem,LPARAM *plParam)
  1137. {
  1138. LVITEMEX lvitem;
  1139. BOOL fReturn;
  1140. lvitem.mask = LVIF_PARAM;
  1141. lvitem.maskEx = 0;
  1142. lvitem.iItem = iItem;
  1143. lvitem.iSubItem = 0;
  1144. if (fReturn = GetItem(&lvitem))
  1145. {
  1146. *plParam = lvitem.lParam;
  1147. }
  1148. return fReturn;
  1149. }
  1150. //+---------------------------------------------------------------------------
  1151. //
  1152. // Member: CListView::GetHwnd, public
  1153. //
  1154. // Synopsis: return Hwnd of the ListView
  1155. //
  1156. //
  1157. // Arguments:
  1158. //
  1159. // Returns:
  1160. //
  1161. // Modifies:
  1162. //
  1163. // History: 07-Sep-98 rogerg Created.
  1164. //
  1165. //----------------------------------------------------------------------------
  1166. HWND CListView::GetHwnd()
  1167. {
  1168. return m_hwnd;
  1169. }
  1170. //+---------------------------------------------------------------------------
  1171. //
  1172. // Member: CListView::GetParent, public
  1173. //
  1174. // Synopsis: return Hwnd of the ListViews Parent
  1175. //
  1176. //
  1177. // Arguments:
  1178. //
  1179. // Returns:
  1180. //
  1181. // Modifies:
  1182. //
  1183. // History: 07-Sep-98 rogerg Created.
  1184. //
  1185. //----------------------------------------------------------------------------
  1186. HWND CListView::GetParent()
  1187. {
  1188. return m_hwndParent;
  1189. }
  1190. //+---------------------------------------------------------------------------
  1191. //
  1192. // Member: CListView::GetCheckState, public
  1193. //
  1194. // Synopsis: wrapper for ListView_GetCheckState
  1195. //
  1196. // return state from LVITEMEXSTATE enum
  1197. // !!!return -1 if not item match to have same behavior as ListView
  1198. //
  1199. // Arguments:
  1200. //
  1201. // Returns:
  1202. //
  1203. // Modifies:
  1204. //
  1205. // History: 23-Jul-98 rogerg Created.
  1206. //
  1207. //----------------------------------------------------------------------------
  1208. int CListView::GetCheckState(int iItem)
  1209. {
  1210. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(iItem);
  1211. UINT state;
  1212. if (NULL == pListViewItem)
  1213. {
  1214. return -1; // return -1 same as for native listbox
  1215. }
  1216. // check state is actually define -1 than the image.
  1217. // Don't know why. Just what the native listview does.
  1218. // change whant supply our own image that will map exactly
  1219. state = ((pListViewItem->lvItemEx.state & LVIS_STATEIMAGEMASK) >> 12) -1;
  1220. #ifdef _DEBUG
  1221. if (-1 != pListViewItem->iNativeListViewItemId)
  1222. {
  1223. UINT lvState = ListView_GetCheckState(m_hwnd,pListViewItem->iNativeListViewItemId);
  1224. Assert(state == lvState);
  1225. }
  1226. #endif // _DEBUG
  1227. // if this is a toplevel item then okay for state to be
  1228. // negative -1. Should change this when go indeterminate.
  1229. // Review - maybe just make -1 indeterinate state.
  1230. if (-1 == state && 0 == pListViewItem->lvItemEx.iIndent)
  1231. {
  1232. state = LVITEMEXSTATE_INDETERMINATE;
  1233. }
  1234. Assert(state <= LVITEMEXSTATE_INDETERMINATE);
  1235. return state;
  1236. }
  1237. //+---------------------------------------------------------------------------
  1238. //
  1239. // Member: CListView::GetCheckedItemsCount, public
  1240. //
  1241. // Synopsis: returns the number of checked items in the list.
  1242. //
  1243. //
  1244. // Arguments:
  1245. //
  1246. // Returns:
  1247. //
  1248. // Modifies:
  1249. //
  1250. // History: 23-Jul-98 rogerg Created.
  1251. //
  1252. //----------------------------------------------------------------------------
  1253. int CListView::GetCheckedItemsCount()
  1254. {
  1255. return m_iCheckCount;
  1256. }
  1257. //+---------------------------------------------------------------------------
  1258. //
  1259. // Member: CListView::SetColumn, public
  1260. //
  1261. // Synopsis: wrapper for ListView_SetColumn
  1262. //
  1263. //
  1264. // Arguments:
  1265. //
  1266. // Returns:
  1267. //
  1268. // Modifies:
  1269. //
  1270. // History: 23-Jul-98 rogerg Created.
  1271. //
  1272. //----------------------------------------------------------------------------
  1273. BOOL CListView::SetColumn(int iCol,LV_COLUMN * pColumn)
  1274. {
  1275. Assert(m_hwnd);
  1276. return ListView_SetColumn(m_hwnd,iCol,pColumn);
  1277. }
  1278. //+---------------------------------------------------------------------------
  1279. //
  1280. // Member: CListView::InsertColumn, public
  1281. //
  1282. // Synopsis: wrapper for ListView_InsertColumn
  1283. //
  1284. //
  1285. // Arguments:
  1286. //
  1287. // Returns:
  1288. //
  1289. // Modifies:
  1290. //
  1291. // History: 23-Jul-98 rogerg Created.
  1292. //
  1293. //----------------------------------------------------------------------------
  1294. int CListView::InsertColumn(int iCol,LV_COLUMN * pColumn)
  1295. {
  1296. int iReturn;
  1297. Assert(m_hwnd);
  1298. iReturn = ListView_InsertColumn(m_hwnd,iCol,pColumn);
  1299. if (-1 != iReturn)
  1300. {
  1301. m_iNumColumns++;
  1302. // need to realloc any existing listviewItems with subitems and move
  1303. // the column appropriate
  1304. //currently only support setting up columns before adding any items
  1305. Assert(0 == m_iListViewNodeCount);
  1306. }
  1307. return iReturn;
  1308. }
  1309. //+---------------------------------------------------------------------------
  1310. //
  1311. // Member: CListView::SetColumnWidth, public
  1312. //
  1313. // Synopsis: wrapper for ListView_SetColumnWidth
  1314. //
  1315. //
  1316. // Arguments:
  1317. //
  1318. // Returns:
  1319. //
  1320. // Modifies:
  1321. //
  1322. // History: 23-Jul-98 rogerg Created.
  1323. //
  1324. //----------------------------------------------------------------------------
  1325. BOOL CListView::SetColumnWidth(int iCol,int cx)
  1326. {
  1327. Assert(m_hwnd);
  1328. return ListView_SetColumnWidth(m_hwnd,iCol,cx);
  1329. }
  1330. //+---------------------------------------------------------------------------
  1331. //
  1332. // Member: CListView::Expand, public
  1333. //
  1334. // Synopsis: expands all children of specified Item
  1335. //
  1336. // Arguments:
  1337. //
  1338. // Returns:
  1339. //
  1340. // Modifies:
  1341. //
  1342. // History: 23-Jul-98 rogerg Created.
  1343. //
  1344. //----------------------------------------------------------------------------
  1345. BOOL CListView::Expand(int iItemId)
  1346. {
  1347. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(iItemId);
  1348. if (!pListViewItem)
  1349. {
  1350. return FALSE;
  1351. }
  1352. return ExpandCollapse(pListViewItem,TRUE);
  1353. }
  1354. //+---------------------------------------------------------------------------
  1355. //
  1356. // Member: CListView::Collapse, public
  1357. //
  1358. // Synopsis: collapses all children of specified Item
  1359. //
  1360. // Arguments:
  1361. //
  1362. // Returns:
  1363. //
  1364. // Modifies:
  1365. //
  1366. // History: 23-Jul-98 rogerg Created.
  1367. //
  1368. //----------------------------------------------------------------------------
  1369. BOOL CListView::Collapse(int iItemId)
  1370. {
  1371. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(iItemId);
  1372. if (!pListViewItem)
  1373. {
  1374. return FALSE;
  1375. }
  1376. return ExpandCollapse(pListViewItem,FALSE);
  1377. }
  1378. //+---------------------------------------------------------------------------
  1379. //
  1380. // Member: CListView::FindItemFromBlob, public
  1381. //
  1382. // Synopsis: returns first item in list that matches blob
  1383. //
  1384. // Arguments:
  1385. //
  1386. // Returns:
  1387. //
  1388. // Modifies:
  1389. //
  1390. // History: 23-Jul-98 rogerg Created.
  1391. //
  1392. //----------------------------------------------------------------------------
  1393. int CListView::FindItemFromBlob(LPLVBLOB pBlob)
  1394. {
  1395. LPLISTVIEWITEM pListViewItem;
  1396. // if not items just return
  1397. if (m_iListViewNodeCount < 1)
  1398. {
  1399. return -1;
  1400. }
  1401. pListViewItem = m_pListViewItems + m_iListViewNodeCount -1;
  1402. while(pListViewItem >= m_pListViewItems)
  1403. {
  1404. if (IsEqualBlob(pBlob,pListViewItem->lvItemEx.pBlob))
  1405. {
  1406. return pListViewItem->lvItemEx.iItem;
  1407. }
  1408. --pListViewItem;
  1409. }
  1410. return -1;
  1411. }
  1412. //+---------------------------------------------------------------------------
  1413. //
  1414. // Member: CListView::GetItemBlob, public
  1415. //
  1416. // Synopsis: finds blob is any associated with an
  1417. // item and then fill in mem pointed
  1418. // to by pBlob if cbSize in BlobStruc is >
  1419. // specified cbBlockSize NULL is returned
  1420. //
  1421. // Arguments:
  1422. //
  1423. // Returns: NULL on failure
  1424. // on success a pointer to the passed in buffer
  1425. // strictly for convenience to the caller.
  1426. //
  1427. // Modifies:
  1428. //
  1429. // History: 23-Jul-98 rogerg Created.
  1430. //
  1431. //----------------------------------------------------------------------------
  1432. LPLVBLOB CListView::GetItemBlob(int ItemId,LPLVBLOB pBlob,ULONG cbBlobSize)
  1433. {
  1434. LPLISTVIEWITEM pListViewItem = ListViewItemFromIndex(ItemId);
  1435. LPLVBLOB pItemBlob;
  1436. if (!pListViewItem
  1437. || (NULL == pListViewItem->lvItemEx.pBlob)
  1438. || (NULL == pBlob))
  1439. {
  1440. Assert(pListViewItem);
  1441. Assert(pBlob);
  1442. return NULL;
  1443. }
  1444. pItemBlob = pListViewItem->lvItemEx.pBlob;
  1445. // make sure out buffer is big enough
  1446. if (cbBlobSize < pItemBlob->cbSize)
  1447. {
  1448. Assert(cbBlobSize >= pItemBlob->cbSize);
  1449. return NULL;
  1450. }
  1451. memcpy(pBlob,pItemBlob,pItemBlob->cbSize);
  1452. return pBlob;
  1453. }
  1454. //+---------------------------------------------------------------------------
  1455. //
  1456. // Member: CListView::IsEqualBlob, private
  1457. //
  1458. // Synopsis: compares two blobs. Valid to pass in NULL put two NULLS is
  1459. // not a match.
  1460. //
  1461. // Arguments:
  1462. //
  1463. // Returns:
  1464. //
  1465. // Modifies:
  1466. //
  1467. // History: 23-Jul-98 rogerg Created.
  1468. //
  1469. //----------------------------------------------------------------------------
  1470. BOOL CListView::IsEqualBlob(LPLVBLOB pBlob1,LPLVBLOB pBlob2)
  1471. {
  1472. if (NULL == pBlob1 || NULL == pBlob2)
  1473. {
  1474. return FALSE;
  1475. }
  1476. // compare sizes
  1477. if (pBlob1->cbSize != pBlob2->cbSize)
  1478. {
  1479. return FALSE;
  1480. }
  1481. if (0 != memcmp(pBlob1,pBlob2,pBlob2->cbSize))
  1482. {
  1483. return FALSE;
  1484. }
  1485. return TRUE;
  1486. }
  1487. //+---------------------------------------------------------------------------
  1488. //
  1489. // Member: CListView::OnNotify, public
  1490. //
  1491. // Synopsis: Called by client whenever a native listview
  1492. // notifiication is sent. We turn around, package
  1493. // it up and send it as our notification message.
  1494. //
  1495. // Arguments:
  1496. //
  1497. // Returns:
  1498. //
  1499. // Modifies:
  1500. //
  1501. // History: 23-Jul-98 rogerg Created.
  1502. //
  1503. //----------------------------------------------------------------------------
  1504. LRESULT CListView::OnNotify(LPNMHDR pnmv)
  1505. {
  1506. LPNMLISTVIEW pnlv = (LPNMLISTVIEW) pnmv;
  1507. NMLISTVIEWEX nmvEx;
  1508. LPLISTVIEWITEM pListViewItem;
  1509. if ((NULL == pnmv) || ( ((int) pnmv->idFrom) != m_idCtrl) || (NULL == m_hwndParent))
  1510. {
  1511. Assert(pnmv);
  1512. Assert( ((int) pnmv->idFrom) == m_idCtrl);
  1513. Assert(m_hwndParent);
  1514. return 0;
  1515. }
  1516. // take care of notifies we handle ourselves.
  1517. switch(pnmv->code)
  1518. {
  1519. case LVN_GETDISPINFOW:
  1520. {
  1521. OnGetDisplayInfo(pnmv->code,(LV_DISPINFO *) pnmv);
  1522. return 0;
  1523. break;
  1524. }
  1525. case NM_DBLCLK:
  1526. case NM_CLICK:
  1527. {
  1528. LV_HITTESTINFO lvhti;
  1529. RECT Rect;
  1530. lvhti.pt = pnlv->ptAction;
  1531. // Have the ListView tell us what element this was on
  1532. if (-1 != ListView_HitTest(m_hwnd, &lvhti))
  1533. {
  1534. // if flags are onitem change to either label or state depending
  1535. // on the click positiion
  1536. if (LVHT_ONITEM == lvhti.flags)
  1537. {
  1538. lvhti.flags = LVHT_ONITEMLABEL;
  1539. if (ListView_GetSubItemRect(m_hwnd,pnlv->iItem,0,LVIR_ICON,&Rect))
  1540. {
  1541. if (lvhti.pt.x < Rect.left)
  1542. {
  1543. lvhti.flags = LVHT_ONITEMSTATEICON;
  1544. }
  1545. else if (lvhti.pt.x <= Rect.right)
  1546. {
  1547. // this doesn't ever get hit since icon is between label and state
  1548. // but its here for completeness.
  1549. lvhti.flags = LVHT_ONITEMICON;
  1550. }
  1551. }
  1552. }
  1553. if (OnHandleUIEvent(pnmv->code,lvhti.flags,0,pnlv->iItem))
  1554. {
  1555. return 0; // don't pass on clicks we process
  1556. }
  1557. }
  1558. break;
  1559. }
  1560. case LVN_KEYDOWN:
  1561. {
  1562. LV_KEYDOWN* pnkd = (LV_KEYDOWN*) pnmv;
  1563. int iItem;
  1564. if (-1 != (iItem = ListView_GetSelectionMark(m_hwnd)))
  1565. {
  1566. if(OnHandleUIEvent(pnmv->code,0,pnkd->wVKey,iItem))
  1567. {
  1568. return 0;
  1569. }
  1570. }
  1571. break;
  1572. }
  1573. default:
  1574. break;
  1575. }
  1576. Assert(LVNEX_ITEMCHANGED == LVN_ITEMCHANGED);
  1577. Assert(LVNEX_DBLCLK == NM_DBLCLK);
  1578. Assert(LVNEX_CLICK == NM_CLICK);
  1579. // only pass along notifications we know how to handle
  1580. if (LVN_ITEMCHANGED != pnmv->code && NM_DBLCLK != pnmv->code && NM_CLICK != pnmv->code)
  1581. {
  1582. return 0;
  1583. }
  1584. // listview can send a iItem of -1 for example when
  1585. // a double-click or click occurs in empty space.
  1586. // if get a -1 just pass through
  1587. if (-1 == pnlv->iItem)
  1588. {
  1589. memcpy(&(nmvEx.nmListView),pnmv,sizeof(nmvEx.nmListView));
  1590. nmvEx.iParent = -1;
  1591. nmvEx.pBlob = NULL;
  1592. }
  1593. else
  1594. {
  1595. pListViewItem = ListViewItemFromNativeListViewItemId(pnlv->iItem);
  1596. if (NULL == pListViewItem)
  1597. {
  1598. // if couldn't find itme
  1599. Assert(pListViewItem);
  1600. return 0;
  1601. }
  1602. // assumes only pass along notifications of
  1603. // type LPNMLISTVIEW
  1604. // fix up the notify structure
  1605. memcpy(&(nmvEx.nmListView),pnmv,sizeof(nmvEx.nmListView));
  1606. nmvEx.nmListView.iItem = pListViewItem->lvItemEx.iItem; // make item point to our internal id
  1607. nmvEx.iParent = pListViewItem->lvItemEx.iParent;
  1608. nmvEx.pBlob = pListViewItem->lvItemEx.pBlob;
  1609. if (LVIF_STATE & pnlv->uChanged )
  1610. {
  1611. // update our internal itemState for the item.
  1612. // Note don't care about lower state bits
  1613. if ( (pnlv->uNewState ^ pnlv->uOldState) & LVIS_STATEIMAGEMASK)
  1614. {
  1615. pListViewItem->lvItemEx.state = (pnlv->uNewState & LVIS_STATEIMAGEMASK)
  1616. + (pListViewItem->lvItemEx.state & ~LVIS_STATEIMAGEMASK);
  1617. }
  1618. if ( (pnlv->uNewState ^ pnlv->uOldState) & LVIS_OVERLAYMASK)
  1619. {
  1620. pListViewItem->lvItemEx.state = (pnlv->uNewState & LVIS_OVERLAYMASK)
  1621. + (pListViewItem->lvItemEx.state & ~LVIS_OVERLAYMASK);
  1622. }
  1623. }
  1624. }
  1625. // send off the message
  1626. return SendMessage(m_hwndParent,m_MsgNotify,m_idCtrl,(LPARAM) &nmvEx);
  1627. }
  1628. //+---------------------------------------------------------------------------
  1629. //
  1630. // Member: CListView::ListViewItemFromNativeListViewItemId, private
  1631. //
  1632. // Synopsis: Given a native listview control itemId finds our internal ListViewItem
  1633. //
  1634. // Arguments:
  1635. //
  1636. // Returns:
  1637. //
  1638. // Modifies:
  1639. //
  1640. // History: 23-Jul-98 rogerg Created.
  1641. //
  1642. //----------------------------------------------------------------------------
  1643. LPLISTVIEWITEM CListView::ListViewItemFromNativeListViewItemId(int iNativeListViewItemId)
  1644. {
  1645. return ListViewItemFromNativeListViewItemId(iNativeListViewItemId,0);
  1646. }
  1647. //+---------------------------------------------------------------------------
  1648. //
  1649. // Member: CListView::ListViewItemFromNativeListViewItemId, private
  1650. //
  1651. // Synopsis: Given a native listview control itemId finds our internal ListViewItem
  1652. //
  1653. // Arguments: iNativeListViewItemId - ItemId of the ListViewItem
  1654. // iNativeListViewSubItemId - SubItemID of the ListViewItem
  1655. // piNativeListViewItemId - [out] on succes iteId in nativelistview.
  1656. //
  1657. // Returns:
  1658. //
  1659. // Modifies:
  1660. //
  1661. // History: 23-Jul-98 rogerg Created.
  1662. //
  1663. //----------------------------------------------------------------------------
  1664. LPLISTVIEWITEM CListView::ListViewItemFromNativeListViewItemId(int iNativeListViewItemId,
  1665. int iSubItem)
  1666. {
  1667. LPLISTVIEWITEM pListViewItem;
  1668. if (-1 == iNativeListViewItemId)
  1669. {
  1670. return NULL;
  1671. }
  1672. if (NULL == m_pListViewItems || m_iListViewNodeCount < 1
  1673. || (iSubItem > m_iNumColumns - 1))
  1674. {
  1675. Assert(NULL != m_pListViewItems);
  1676. Assert(m_iListViewNodeCount >= 1);
  1677. Assert(iSubItem <= (m_iNumColumns - 1));
  1678. return NULL;
  1679. }
  1680. pListViewItem = m_pListViewItems + m_iListViewNodeCount -1;
  1681. while(pListViewItem >= m_pListViewItems)
  1682. {
  1683. if (iNativeListViewItemId == pListViewItem->iNativeListViewItemId)
  1684. {
  1685. break;
  1686. }
  1687. --pListViewItem;
  1688. }
  1689. if (pListViewItem < m_pListViewItems)
  1690. {
  1691. return NULL;
  1692. }
  1693. // if subItem is zero then we just return this listviewItem, else
  1694. // need to walk forward the subItem array.
  1695. if (0 == iSubItem)
  1696. {
  1697. return pListViewItem;
  1698. }
  1699. Assert(m_iNumColumns > 1); // should have already caught about but double-check
  1700. pListViewItem = pListViewItem->pSubItems + iSubItem -1;
  1701. return pListViewItem;
  1702. }
  1703. //+---------------------------------------------------------------------------
  1704. //
  1705. // Member: CListView::ListViewItemFromIndex, private
  1706. //
  1707. // Synopsis: Finds internal listviewItem from ItemID we gave to client.
  1708. //
  1709. // Arguments:
  1710. //
  1711. // Returns:
  1712. //
  1713. // Modifies:
  1714. //
  1715. // History: 23-Jul-98 rogerg Created.
  1716. //
  1717. //----------------------------------------------------------------------------
  1718. LPLISTVIEWITEM CListView::ListViewItemFromIndex(int iItemID)
  1719. {
  1720. return ListViewItemFromIndex(iItemID,0,NULL);
  1721. }
  1722. //+---------------------------------------------------------------------------
  1723. //
  1724. // Member: CListView::ListViewItemFromIndex, private
  1725. //
  1726. // Synopsis: Finds internal listviewItem from ItemID we gave to client.
  1727. //
  1728. // Arguments:
  1729. //
  1730. // Returns:
  1731. //
  1732. // Modifies:
  1733. //
  1734. // History: 23-Jul-98 rogerg Created.
  1735. //
  1736. //----------------------------------------------------------------------------
  1737. LPLISTVIEWITEM CListView::ListViewItemFromIndex(int iItemID,int iSubitem,int *piNativeListViewItemId)
  1738. {
  1739. LPLISTVIEWITEM pListViewItem;
  1740. // if item isn't valid return NULL
  1741. if (iItemID < 0 || iItemID >= m_iListViewNodeCount
  1742. || (iSubitem > m_iNumColumns - 1))
  1743. {
  1744. Assert(iItemID >= 0);
  1745. Assert(iSubitem <= m_iNumColumns - 1);
  1746. // Assert(iItemID < m_iListViewNodeCount); choice dlg Calls GetCheckState until hits -1.
  1747. return NULL;
  1748. }
  1749. pListViewItem = m_pListViewItems + iItemID;
  1750. if (piNativeListViewItemId)
  1751. {
  1752. *piNativeListViewItemId = pListViewItem->iNativeListViewItemId;
  1753. }
  1754. if (0 == iSubitem)
  1755. {
  1756. return pListViewItem;
  1757. }
  1758. pListViewItem = pListViewItem->pSubItems + iSubitem -1;
  1759. return pListViewItem;
  1760. }
  1761. //+---------------------------------------------------------------------------
  1762. //
  1763. // Member: CListView::DeleteListViewItemSubItems, private
  1764. //
  1765. // Synopsis: Helper function to delete subItems associated with a ListViewItem
  1766. //
  1767. // Arguments:
  1768. //
  1769. // Returns:
  1770. //
  1771. // Modifies:
  1772. //
  1773. // History: 04-Aug-98 rogerg Created.
  1774. //
  1775. //----------------------------------------------------------------------------
  1776. void CListView::DeleteListViewItemSubItems(LPLISTVIEWITEM pListItem)
  1777. {
  1778. LPLISTVIEWITEM pListViewSubItem;
  1779. // if not subItems or number of columns isn't at least 2 bail.
  1780. if ((NULL == pListItem->pSubItems) || (m_iNumColumns < 2))
  1781. {
  1782. Assert(NULL == pListItem->pSubItems && m_iNumColumns < 2); // should always match.
  1783. return;
  1784. }
  1785. pListViewSubItem = pListItem->pSubItems + m_iNumColumns -2; // -2 ; covers first subItem and column of main item
  1786. // free any text associated with the subItems
  1787. Assert(m_iNumColumns > 1);
  1788. Assert(pListViewSubItem >= pListItem->pSubItems);
  1789. while (pListViewSubItem >= pListItem->pSubItems)
  1790. {
  1791. if (pListViewSubItem->lvItemEx.pszText)
  1792. {
  1793. Assert(LVIF_TEXT & pListViewSubItem->lvItemEx.mask);
  1794. FREE(pListViewSubItem->lvItemEx.pszText);
  1795. }
  1796. --pListViewSubItem;
  1797. }
  1798. FREE(pListItem->pSubItems);
  1799. pListItem->pSubItems = NULL;
  1800. }
  1801. //+---------------------------------------------------------------------------
  1802. //
  1803. // Member: CListView::ExpandCollapse, private
  1804. //
  1805. // Synopsis: Expands or collapses children of given node.
  1806. //
  1807. // Arguments:
  1808. //
  1809. // Returns:
  1810. //
  1811. // Modifies:
  1812. //
  1813. // History: 23-Jul-98 rogerg Created.
  1814. //
  1815. //----------------------------------------------------------------------------
  1816. BOOL CListView::ExpandCollapse(LPLISTVIEWITEM pListViewItem,BOOL fExpand)
  1817. {
  1818. LPLISTVIEWITEM pCurListViewItem = pListViewItem + 1;
  1819. LPLISTVIEWITEM pLastListViewItem = m_pListViewItems + m_iListViewNodeCount -1;
  1820. int iIndent = pListViewItem->lvItemEx.iIndent;
  1821. int iInsertDeleteCount = 0;
  1822. LV_ITEM lvi = { 0 };
  1823. Assert(pListViewItem);
  1824. Assert(m_iListViewNodeCount);
  1825. // if specified node isn't in the list view fail
  1826. if (-1 == pListViewItem->iNativeListViewItemId)
  1827. {
  1828. Assert(-1 != pListViewItem->iNativeListViewItemId);
  1829. return FALSE;
  1830. }
  1831. lvi.iItem = pListViewItem->iNativeListViewItemId + 1;
  1832. while (pCurListViewItem <= pLastListViewItem
  1833. && pCurListViewItem->lvItemEx.iIndent > iIndent)
  1834. {
  1835. if (fExpand)
  1836. {
  1837. if ( (-1 == pCurListViewItem->iNativeListViewItemId)
  1838. && (pCurListViewItem->lvItemEx.iIndent == iIndent + 1)) // only expand next level deep
  1839. {
  1840. pCurListViewItem->iNativeListViewItemId = ListView_InsertItem(m_hwnd,&lvi);
  1841. Assert(pCurListViewItem->iNativeListViewItemId == lvi.iItem);
  1842. if (-1 != pCurListViewItem->iNativeListViewItemId)
  1843. {
  1844. ++lvi.iItem;
  1845. ++iInsertDeleteCount;
  1846. }
  1847. }
  1848. }
  1849. else
  1850. {
  1851. if (-1 != pCurListViewItem->iNativeListViewItemId)
  1852. {
  1853. pCurListViewItem->fExpanded = FALSE;
  1854. if (ListView_DeleteItem(m_hwnd,lvi.iItem))
  1855. {
  1856. pCurListViewItem->iNativeListViewItemId = -1;
  1857. --iInsertDeleteCount;
  1858. }
  1859. }
  1860. }
  1861. ++pCurListViewItem;
  1862. }
  1863. // fixup nativeIds of any remaining items in the list
  1864. while (pCurListViewItem <= pLastListViewItem)
  1865. {
  1866. if (-1 != pCurListViewItem->iNativeListViewItemId)
  1867. {
  1868. pCurListViewItem->iNativeListViewItemId += iInsertDeleteCount;
  1869. Assert(pCurListViewItem->iNativeListViewItemId >= 0);
  1870. Assert(pCurListViewItem->iNativeListViewItemId < m_iListViewNodeCount);
  1871. }
  1872. ++pCurListViewItem;
  1873. }
  1874. pListViewItem->fExpanded = fExpand;
  1875. return TRUE;
  1876. }
  1877. //+---------------------------------------------------------------------------
  1878. //
  1879. // Member: CListView::OnGetDisplayInfo, private
  1880. //
  1881. // Synopsis: Handles Display info notification.
  1882. //
  1883. // Arguments: code - code from notification header either
  1884. // LVN_GETDISPINFOW, LVN_GETDISPINFOA. need this
  1885. // so know how to handle Text.
  1886. //
  1887. // Returns:
  1888. //
  1889. // Modifies:
  1890. //
  1891. // History: 23-Jul-98 rogerg Created.
  1892. //
  1893. //----------------------------------------------------------------------------
  1894. void CListView::OnGetDisplayInfo(UINT code,LV_DISPINFO *plvdi)
  1895. {
  1896. LPLISTVIEWITEM pListViewItem = ListViewItemFromNativeListViewItemId(plvdi->item.iItem,
  1897. plvdi->item.iSubItem);
  1898. if (NULL == pListViewItem)
  1899. return;
  1900. // verify subitem iound matches item we asked for.
  1901. Assert(pListViewItem->lvItemEx.iSubItem == plvdi->item.iSubItem);
  1902. // The ListView needs text for this row
  1903. if (plvdi->item.mask & LVIF_TEXT)
  1904. {
  1905. if (pListViewItem->lvItemEx.pszText)
  1906. {
  1907. if (LVN_GETDISPINFOW == code)
  1908. {
  1909. StrCpyN(plvdi->item.pszText,pListViewItem->lvItemEx.pszText,plvdi->item.cchTextMax);
  1910. }
  1911. }
  1912. }
  1913. // The ListView needs an image
  1914. if (plvdi->item.mask & LVIF_IMAGE)
  1915. {
  1916. // plvdi->item.iItem, plvdi->item.iSubItem, &(plvdi->item.iImage));
  1917. plvdi->item.iImage = pListViewItem->lvItemEx.iImage;
  1918. }
  1919. // The ListView needs the indent level
  1920. if (plvdi->item.mask & LVIF_INDENT)
  1921. {
  1922. // if (m_fThreadMessages)
  1923. // m_pTable->GetIndentLevel(plvdi->item.iItem, (LPDWORD) &(plvdi->item.iIndent));
  1924. // else
  1925. // for no checks on top-level set image state to empty pict and
  1926. // indent to -1. Need additional State Logic if want to
  1927. // choose if toplevel checks are shown.
  1928. plvdi->item.iIndent = pListViewItem->lvItemEx.iIndent;
  1929. if ( (m_dwExStyle & LVS_EX_CHECKBOXES) && (0 == plvdi->item.iIndent) )
  1930. {
  1931. plvdi->item.iIndent = -1;
  1932. }
  1933. }
  1934. // The ListView needs the state image
  1935. if (plvdi->item.mask & LVIF_STATE)
  1936. {
  1937. //nt iIcon = 0;
  1938. // _GetColumnStateImage(plvdi->item.iItem, plvdi->item.iSubItem, &iIcon);
  1939. plvdi->item.state = pListViewItem->lvItemEx.state & LVIS_STATEIMAGEMASK;
  1940. }
  1941. }
  1942. //+---------------------------------------------------------------------------
  1943. //
  1944. // Member: CListView::OnHandleUIEvent private
  1945. //
  1946. // Synopsis: sent when a click or double-click,keyboard, is sent to
  1947. // the listview
  1948. //
  1949. // Arguments: code - indicates why this function was called
  1950. // Support NM_DBLCLK, NM_CLICK, LVN_KEYDOWN:
  1951. //
  1952. // flags - flags from hitTest. Only valid for DBCLK and CLICK
  1953. // flag = LVHT_ONITEMSTATEICON | LVHT_ONITEMICON) |LVHT_ONITEMLABEL
  1954. // wVKey - Virtual key code of key presses. Ony valide cfor LVN_KEYDOWN
  1955. // iItemNative - ItemID in NativeListView
  1956. //
  1957. //
  1958. // Returns: TRUE - if handled event and notification shouldn't be passed on.
  1959. //
  1960. // Modifies:
  1961. //
  1962. // History: 23-Jul-98 rogerg Created.
  1963. //
  1964. //----------------------------------------------------------------------------
  1965. BOOL CListView::OnHandleUIEvent(UINT code,UINT flags,WORD wVKey,int iItemNative)
  1966. {
  1967. LPLISTVIEWITEM pListViewItem = ListViewItemFromNativeListViewItemId(iItemNative);
  1968. int iStateMask;
  1969. BOOL fItemHasCheckBoxes; // for now this is hardcoded depending on the indent. Need to change this.
  1970. BOOL fToggleCheckBox = FALSE;
  1971. BOOL fExpand = FALSE;
  1972. BOOL fCollapse = FALSE;
  1973. BOOL fReturn = FALSE;
  1974. if (NULL == pListViewItem)
  1975. {
  1976. return TRUE; // no need passing this on
  1977. }
  1978. fItemHasCheckBoxes = pListViewItem->lvItemEx.iIndent ? TRUE : FALSE;
  1979. // If Item has chechboxes toggle on keyboard space or mouse clicks
  1980. // over the itemState Icon.
  1981. // double-clicks on itemIcon togles the whether the branch is expanded/collasse
  1982. // if left/right keyboard expand collapse
  1983. switch(code)
  1984. {
  1985. case LVN_KEYDOWN:
  1986. {
  1987. switch(wVKey)
  1988. {
  1989. case VK_SPACE:
  1990. if (fItemHasCheckBoxes)
  1991. {
  1992. fToggleCheckBox = TRUE;
  1993. }
  1994. break;
  1995. case VK_RIGHT:
  1996. case VK_LEFT:
  1997. if (pListViewItem->iChildren)
  1998. {
  1999. fExpand = VK_RIGHT == wVKey ? TRUE : FALSE;
  2000. fCollapse = !fExpand;
  2001. }
  2002. break;
  2003. default:
  2004. break;
  2005. }
  2006. }
  2007. case NM_DBLCLK:
  2008. if ( (flags & LVHT_ONITEMICON) && (pListViewItem->iChildren))
  2009. {
  2010. fExpand = pListViewItem->fExpanded ? FALSE : TRUE;
  2011. fCollapse = !fExpand;
  2012. break;
  2013. }
  2014. // double-click falls through to a click.
  2015. case NM_CLICK:
  2016. if ((flags & LVHT_ONITEMSTATEICON)
  2017. && fItemHasCheckBoxes)
  2018. {
  2019. fToggleCheckBox = TRUE;
  2020. }
  2021. break;
  2022. default:
  2023. break;
  2024. }
  2025. if (fExpand || fCollapse)
  2026. {
  2027. // don't bother if already in current state
  2028. if (pListViewItem->fExpanded != fExpand)
  2029. {
  2030. ExpandCollapse(pListViewItem,fExpand);
  2031. }
  2032. return TRUE;
  2033. }
  2034. else if (fToggleCheckBox)
  2035. {
  2036. // for now just toggle the state. if have children need to set them appropriately.
  2037. iStateMask = LVITEMEXSTATE_CHECKED == GetCheckState(pListViewItem->lvItemEx.iItem)
  2038. ? LVIS_STATEIMAGEMASK_UNCHECK : LVIS_STATEIMAGEMASK_CHECK;
  2039. SetItemState(pListViewItem->lvItemEx.iItem,iStateMask,LVIS_STATEIMAGEMASK);
  2040. return TRUE;
  2041. }
  2042. return fReturn; // default we pass it along
  2043. }