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.

6716 lines
183 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: cclvctl.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // cclvctl.cpp : implementation file
  11. //
  12. #include "stdafx.h"
  13. #include "cclvctl.h"
  14. #include <malloc.h>
  15. #include <wtypes.h>
  16. #include "amcdoc.h"
  17. #include "amcview.h"
  18. #include "mmcres.h"
  19. #include "treectrl.h"
  20. #include "util.h"
  21. #include "amcpriv.h"
  22. #include "rsltitem.h"
  23. #include "columninfo.h"
  24. #include "bitmap.h"
  25. #ifdef _DEBUG
  26. #define new DEBUG_NEW
  27. #endif
  28. //############################################################################
  29. //############################################################################
  30. //
  31. // Traces
  32. //
  33. //############################################################################
  34. //############################################################################
  35. #ifdef DBG
  36. CTraceTag tagList(TEXT("List View"), TEXT("List View"));
  37. CTraceTag tagListImages(_T("Images"), _T("List view (draw when changed)"));
  38. CTraceTag tagColumn(TEXT("Columns"), TEXT("Columns"));
  39. #endif //DBG
  40. DEBUG_DECLARE_INSTANCE_COUNTER(CAMCListView);
  41. //############################################################################
  42. //############################################################################
  43. //
  44. // Implementation of class CColumnsBase
  45. //
  46. //############################################################################
  47. //############################################################################
  48. /*+-------------------------------------------------------------------------*
  49. * class CColumnsBase
  50. *
  51. *
  52. * PURPOSE: Implements the Columns automation interface.
  53. *
  54. *+-------------------------------------------------------------------------*/
  55. class CColumnsBase :
  56. public CMMCIDispatchImpl<Columns>,
  57. public CTiedComObject<CCCListViewCtrl>,
  58. public CTiedObject // this is for enumerators
  59. {
  60. protected:
  61. typedef CCCListViewCtrl CMyTiedObject;
  62. public:
  63. BEGIN_MMC_COM_MAP(CColumnsBase)
  64. END_MMC_COM_MAP()
  65. // Columns interface
  66. public:
  67. MMC_METHOD2(Item, long /*Index*/, PPCOLUMN /*ppColumn*/);
  68. // properties
  69. MMC_METHOD1(get_Count, PLONG /*pCount*/);
  70. };
  71. // this typedefs the real CColumns class. Implements get__NewEnum using CMMCEnumerator
  72. typedef CMMCNewEnumImpl<CColumnsBase, int> CColumns;
  73. /*+-------------------------------------------------------------------------*
  74. * class CColumn
  75. *
  76. *
  77. * PURPOSE: Implements the Node automation interface, for a result node
  78. *
  79. *+-------------------------------------------------------------------------*/
  80. class CColumn :
  81. public CMMCIDispatchImpl<Column>,
  82. public CTiedComObject<CCCListViewCtrl>,
  83. public CListViewObserver
  84. {
  85. protected:
  86. typedef CCCListViewCtrl CMyTiedObject;
  87. public:
  88. BEGIN_MMC_COM_MAP(CColumn)
  89. END_MMC_COM_MAP()
  90. // Column methods
  91. public:
  92. MMC_METHOD1_PARAM( Name, /*[out, retval]*/ BSTR* /*Name*/ , m_iIndex);
  93. MMC_METHOD1_PARAM( get_Width, /*[out, retval]*/ PLONG /*Width*/, m_iIndex);
  94. MMC_METHOD1_PARAM( put_Width, /*[in]*/ long /*Width*/, m_iIndex);
  95. MMC_METHOD1_PARAM( get_DisplayPosition, /*[out, retval]*/ PLONG /*DisplayPosition*/, m_iIndex);
  96. MMC_METHOD1_PARAM( put_DisplayPosition, /*[in]*/ long /*Index*/, m_iIndex);
  97. MMC_METHOD1_PARAM( get_Hidden, /*[out, retval]*/ PBOOL /*Hidden*/, m_iIndex );
  98. MMC_METHOD1_PARAM( put_Hidden, /*[in]*/ BOOL /*Hidden*/ , m_iIndex );
  99. MMC_METHOD1_PARAM( SetAsSortColumn, /*[in]*/ ColumnSortOrder /*SortOrder*/, m_iIndex);
  100. MMC_METHOD1_PARAM( IsSortColumn, PBOOL /*IsSortColumn*/, m_iIndex);
  101. CColumn() : m_iIndex(-1) { }
  102. void SetIndex(int iIndex) { m_iIndex = iIndex; }
  103. // observed events
  104. // called when column is inserted to listview
  105. virtual ::SC ScOnListViewColumnInserted (int nIndex);
  106. // called when column is deleted from listview
  107. virtual ::SC ScOnListViewColumnDeleted (int nIndex);
  108. private: // implementation
  109. int m_iIndex;
  110. };
  111. /////////////////////////////////////////////////////////////////////////////
  112. // CAMCHeaderCtrl
  113. // This class is defined just to intercept the header's set focus
  114. BEGIN_MESSAGE_MAP(CAMCHeaderCtrl, CHeaderCtrl)
  115. ON_WM_SETFOCUS()
  116. ON_WM_SETCURSOR()
  117. END_MESSAGE_MAP()
  118. void CAMCHeaderCtrl::OnSetFocus(CWnd *pOldWnd)
  119. {
  120. // Make sure list view is made active, but don't steal focus from header
  121. CAMCListView* pwndParent = dynamic_cast<CAMCListView*>(GetParent());
  122. ASSERT(pwndParent != NULL);
  123. pwndParent->GetParentFrame()->SetActiveView(pwndParent, FALSE);
  124. CHeaderCtrl::OnSetFocus(pOldWnd);
  125. }
  126. //+-------------------------------------------------------------------
  127. //
  128. // Member: CAMCHeaderCtrl::OnSetCursor
  129. //
  130. // Synopsis: If the cursor is on hidden column do not show the divider
  131. // cursor. WM_SETCURSOR handler.
  132. //
  133. // Arguments: [pWnd] - window which generated the message.
  134. // [nHitTest] - hittest flag.
  135. // [message] -
  136. //
  137. // Returns: BOOL, TRUE stop processing further.
  138. //
  139. //--------------------------------------------------------------------
  140. BOOL CAMCHeaderCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  141. {
  142. // 1. If the mouse is on the header window.
  143. if ( (nHitTest == HTCLIENT) && (pWnd == this) )
  144. {
  145. // 2. Get its position.
  146. CPoint pt (GetMessagePos());
  147. ScreenToClient (&pt);
  148. // 3. Do a hit test
  149. HDHITTESTINFO hitinfo;
  150. ZeroMemory(&hitinfo, sizeof(hitinfo));
  151. hitinfo.pt = pt;
  152. if (SendMessage(HDM_HITTEST, 0, reinterpret_cast<LPARAM>(&hitinfo) ) != -1)
  153. {
  154. // 4. If the mouse is on a column of zero width and it is hidden do not
  155. // process the message further.
  156. // 4.a) HHT_ONDIVOPEN : pt is on the divider of an item that has a width of zero.
  157. // b) HHT_ONDIVIDER : pt is on the divider between two header items.
  158. if ( ( (HHT_ONDIVOPEN | HHT_ONDIVIDER) & hitinfo.flags) &&
  159. (IsColumnHidden(hitinfo.iItem /*column index*/)) )
  160. {
  161. // Set default arrow cursor.
  162. ::SetCursor(::LoadCursor(NULL, IDC_ARROW) );
  163. return TRUE;
  164. }
  165. }
  166. }
  167. return CHeaderCtrl::OnSetCursor(pWnd, nHitTest, message);
  168. }
  169. //+-------------------------------------------------------------------
  170. //
  171. // Member: CAMCHeaderCtrl::IsColumnHidden
  172. //
  173. // Synopsis: Is the given column hidden?
  174. //
  175. // Arguments: [iCol] - given column
  176. //
  177. // Returns: bool
  178. //
  179. //--------------------------------------------------------------------
  180. bool CAMCHeaderCtrl::IsColumnHidden(int iCol)
  181. {
  182. // Get param to determine if column is hidden.
  183. HDITEM hdItem;
  184. ZeroMemory(&hdItem, sizeof(hdItem));
  185. hdItem.mask = HDI_LPARAM;
  186. if (GetItem(iCol, &hdItem))
  187. {
  188. CHiddenColumnInfo hci (hdItem.lParam);
  189. if (hci.fHidden)
  190. return true;
  191. }
  192. return false;
  193. }
  194. /////////////////////////////////////////////////////////////////////////////
  195. // CAMCListView
  196. const UINT CAMCListView::m_nColumnPersistedDataChangedMsg = ::RegisterWindowMessage (_T("CAMCListView::OnColumnPersistedDataChanged"));
  197. BEGIN_MESSAGE_MAP(CAMCListView, CListView)
  198. //{{AFX_MSG_MAP(CAMCListView)
  199. ON_WM_CREATE()
  200. ON_WM_KEYUP()
  201. ON_WM_KEYDOWN()
  202. ON_WM_SYSKEYDOWN()
  203. ON_WM_SYSCHAR()
  204. ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBeginDrag)
  205. ON_NOTIFY_REFLECT(LVN_BEGINRDRAG, OnBeginRDrag)
  206. ON_WM_MOUSEACTIVATE()
  207. ON_WM_SETFOCUS()
  208. ON_WM_PAINT()
  209. ON_WM_SIZE()
  210. ON_NOTIFY(HDN_BEGINTRACK, 0, OnBeginTrack)
  211. //}}AFX_MSG_MAP
  212. ON_REGISTERED_MESSAGE (m_nColumnPersistedDataChangedMsg, OnColumnPersistedDataChanged)
  213. END_MESSAGE_MAP()
  214. BOOL CAMCListView::PreCreateWindow(CREATESTRUCT& cs)
  215. {
  216. cs.style |= WS_BORDER |
  217. WS_CLIPSIBLINGS |
  218. WS_CLIPCHILDREN |
  219. LVS_SHAREIMAGELISTS |
  220. LVS_SINGLESEL |
  221. LVS_EDITLABELS |
  222. LVS_SHOWSELALWAYS |
  223. LVS_REPORT;
  224. return CListView::PreCreateWindow(cs);
  225. }
  226. int CAMCListView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  227. {
  228. DECLARE_SC(sc, TEXT("CAMCListView::OnCreate"));
  229. if (CListView::OnCreate(lpCreateStruct) == -1)
  230. return -1;
  231. // Get parent's CWnd for command routing
  232. m_pAMCView = ::GetAMCView (this);
  233. /*
  234. * add extended list view styles (these can't be handled in PreCreateWindow)
  235. */
  236. SetExtendedListViewStyle (LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP |
  237. LVS_EX_LABELTIP);
  238. sc = ScRegisterAsDropTarget(m_hWnd);
  239. if (sc)
  240. return (-1);
  241. AddObserver(static_cast<CListViewActivationObserver &>(*m_pAMCView));
  242. return 0;
  243. }
  244. void CAMCListView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  245. {
  246. if ((VK_CONTROL == nChar) || (VK_SHIFT == nChar))
  247. {
  248. ASSERT (m_pAMCView != NULL);
  249. m_pAMCView->SendMessage (WM_KEYUP, nChar, MAKELPARAM (nRepCnt, nFlags));
  250. return;
  251. }
  252. CListView::OnKeyUp(nChar, nRepCnt, nFlags);
  253. }
  254. //+-------------------------------------------------------------------
  255. //
  256. // Member: OnKeyDown
  257. //
  258. // Synopsis: Handle any non-system keys (Without ALT).
  259. // (Below handle Ctrl+A to multi-select
  260. // all items in list view).
  261. //
  262. // Arguments:
  263. //
  264. // Returns: None.
  265. //
  266. //
  267. //--------------------------------------------------------------------
  268. void CAMCListView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  269. {
  270. switch (nChar)
  271. {
  272. case 'A':
  273. {
  274. // Check if LV is multi-sel enabled.
  275. if (GetStyle() & LVS_SINGLESEL)
  276. break;
  277. SHORT nKeyState = GetKeyState(VK_CONTROL);
  278. // Key is down if higher order bits are set in nKeyState.
  279. nKeyState = nKeyState >> sizeof(SHORT) * 4;
  280. if (nKeyState == 0)
  281. break;
  282. // Ctrl+A --> Select all items in list view.
  283. LV_ITEM lvi;
  284. lvi.stateMask = lvi.state = LVIS_SELECTED;
  285. for (int i = 0; i < GetListCtrl().GetItemCount(); ++i)
  286. {
  287. // NOTE: do not use GetListCtrl().SetItemState - it uses SetItem which is not supported for virtual lists
  288. if (!GetListCtrl().SendMessage( LVM_SETITEMSTATE, WPARAM(i), (LPARAM)(LV_ITEM FAR *)&lvi))
  289. return;
  290. }
  291. return;
  292. }
  293. default:
  294. break;
  295. }
  296. CListView::OnKeyDown(nChar, nRepCnt, nFlags);
  297. }
  298. /*+-------------------------------------------------------------------------*
  299. *
  300. * CAMCListView::OnSysKeyDown
  301. *
  302. * PURPOSE: Handle the WM_SYSCHAR message.
  303. *
  304. * PARAMETERS:
  305. * UINT nChar :
  306. * UINT nRepCnt :
  307. * UINT nFlags :
  308. *
  309. * RETURNS:
  310. * void
  311. *
  312. *+-------------------------------------------------------------------------*/
  313. void CAMCListView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  314. {
  315. if ((VK_LEFT == nChar) || (VK_RIGHT == nChar))
  316. {
  317. ASSERT (m_pAMCView != NULL);
  318. m_pAMCView->SendMessage (WM_SYSKEYDOWN, nChar, MAKELPARAM (nRepCnt, nFlags));
  319. return;
  320. }
  321. CListView::OnSysKeyDown(nChar, nRepCnt, nFlags);
  322. }
  323. void CAMCListView::OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  324. {
  325. if (VK_RETURN == nChar)
  326. {
  327. return; // don't call base class, otherwise a beep occurs. Handled by LVN_KEYDOWN
  328. }
  329. CListView::OnSysChar(nChar, nRepCnt, nFlags);
  330. }
  331. /*+-------------------------------------------------------------------------*
  332. *
  333. * CAMCListView::OnPaint
  334. *
  335. * PURPOSE: Displays a default message when no items are present in the list.
  336. *
  337. * RETURNS:
  338. * void
  339. *
  340. *+-------------------------------------------------------------------------*/
  341. void
  342. CAMCListView::OnPaint()
  343. {
  344. Default();
  345. if (NeedsCustomPaint())
  346. {
  347. COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);
  348. COLORREF clrTextBk = ::GetSysColor(COLOR_WINDOW);
  349. CClientDC dc(this);
  350. // Save dc state
  351. int nSavedDC = dc.SaveDC();
  352. CRect rc;
  353. GetClientRect(&rc);
  354. CHeaderCtrl* pHC = GetHeaderCtrl();
  355. if (pHC != NULL && ((GetListCtrl().GetStyle() & (LVS_REPORT | LVS_LIST | LVS_SMALLICON | LVS_ICON)) ==LVS_REPORT) ) // make sure that the style is report
  356. {
  357. CRect rcH;
  358. pHC->GetItemRect(0, &rcH);
  359. rc.top += rcH.bottom;
  360. }
  361. rc.top += 10;
  362. CString strText;
  363. strText.LoadString(IDS_EMPTY_LIST_MESSAGE); // The message
  364. // create the font - we do not cache it.
  365. LOGFONT lf;
  366. CFont font;
  367. SystemParametersInfo (SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, false);
  368. font.CreateFontIndirect(&lf);
  369. dc.SelectObject(&font); // select the font
  370. dc.SetTextColor(clrText);
  371. dc.SetBkColor(clrTextBk);
  372. dc.FillRect(rc, &CBrush(clrTextBk));
  373. dc.DrawText(strText, -1, rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);
  374. // Restore dc
  375. dc.RestoreDC(nSavedDC);
  376. }
  377. // Do not call CListCtrl::OnPaint() for painting messages (Default was called above)
  378. }
  379. /*+-------------------------------------------------------------------------*
  380. * CAMCListView::OnSize
  381. *
  382. * WM_SIZE handler for CAMCListView.
  383. *--------------------------------------------------------------------------*/
  384. void CAMCListView::OnSize(UINT nType, int cx, int cy)
  385. {
  386. CListView::OnSize(nType, cx, cy);
  387. /*
  388. * if we're custom painting, we need to redraw the list
  389. * because we need to keep the text horizontally centered
  390. */
  391. if (NeedsCustomPaint())
  392. Invalidate ();
  393. }
  394. /*+-------------------------------------------------------------------------*
  395. * CAMCListView::NeedsCustomPaint
  396. *
  397. * Determines whether we want to draw "There are no items..." in the list
  398. * view.
  399. *--------------------------------------------------------------------------*/
  400. bool CAMCListView::NeedsCustomPaint()
  401. {
  402. CHeaderCtrl* pHC = GetHeaderCtrl();
  403. // we check the column counts because there is a transition state when no columns are
  404. // present during which we shouldn't draw anything.
  405. return (GetListCtrl().GetItemCount() <= 0 && (pHC != NULL) && pHC->GetItemCount()>0);
  406. }
  407. BOOL CAMCListView::OnCmdMsg( UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo )
  408. {
  409. // Do normal command routing
  410. if (CListView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  411. return TRUE;
  412. // if view did't handle it, give parent view a chance
  413. if (m_pAMCView != NULL)
  414. {
  415. // OnCmdMsg is public in CCmdTarget, but protected in CView
  416. // cast around it (arghhh!)
  417. return ((CWnd*)m_pAMCView)->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
  418. }
  419. return FALSE;
  420. }
  421. void CAMCListView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  422. {
  423. if (lHint == VIEW_UPDATE_DELETE_EMPTY_VIEW)
  424. m_pAMCView->OnDeleteEmptyView();
  425. }
  426. int CAMCListView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
  427. {
  428. // see CAMCTreeView::OnMouseActivate for an explanation of focus churn
  429. // avoidance.
  430. return (MA_ACTIVATE);
  431. }
  432. void CAMCListView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
  433. {
  434. DECLARE_SC(sc, TEXT("CAMCListView::OnActivateView"));
  435. #ifdef DBG
  436. Trace(tagList, _T("ListView::OnActivateView (%s, pAct=0x%08x, pDeact=0x%08x))\n"),
  437. (bActivate) ? _T("true") : _T("false"), pActivateView, pDeactiveView);
  438. #endif
  439. if ( (pActivateView != pDeactiveView) &&
  440. (bActivate) )
  441. {
  442. sc = ScFireEvent(CListViewActivationObserver::ScOnListViewActivated);
  443. if (sc)
  444. sc.TraceAndClear();
  445. }
  446. CListView::OnActivateView(bActivate, pActivateView, pDeactiveView);
  447. }
  448. void CAMCListView::OnSetFocus(CWnd* pOldWnd)
  449. {
  450. /*
  451. * if this view has the focus, it should be the active view
  452. */
  453. CFrameWnd *pParentFrame = GetParentFrame();
  454. if(pParentFrame != NULL)
  455. pParentFrame->SetActiveView (this);
  456. CListView::OnSetFocus(pOldWnd);
  457. // If we are currently reparented, then we need to send a setfocus notify
  458. // to our current parent. This is needed because the listview control caches its
  459. // parent window on creation and continues to sends all notifications to it.
  460. if (dynamic_cast<CAMCView*>(GetParent()) == NULL)
  461. {
  462. NMHDR nmhdr;
  463. nmhdr.hwndFrom = m_hWnd;
  464. nmhdr.idFrom = GetDlgCtrlID();
  465. nmhdr.code = NM_SETFOCUS;
  466. ::SendMessage(GetParent()->m_hWnd, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
  467. }
  468. }
  469. /*+-------------------------------------------------------------------------*
  470. *
  471. * CAMCListView::OnKeyboardFocus
  472. *
  473. * PURPOSE: Whenever the user switches focus using the TAB keys ONLY, to the
  474. * list view control, make sure that at least one item is highlighted.
  475. *
  476. * RETURNS:
  477. * void
  478. *
  479. *+-------------------------------------------------------------------------*/
  480. void
  481. CAMCListView::OnKeyboardFocus(UINT nState, UINT nStateMask)
  482. {
  483. CListCtrl &lc = GetListCtrl();
  484. // Make sure an item has the focus (unless the list is empty)
  485. if (lc.GetNextItem(-1,LVNI_FOCUSED) == -1 && lc.GetItemCount() > 0)
  486. {
  487. /*
  488. * It would be convenient to use
  489. *
  490. * CListCtrl::SetItemState (int nIndex, UINT nState, UINT nMask)
  491. *
  492. * here, but MFC uses LVM_SETITEM for that overload, which
  493. * doesn't work for virtual lists. For the overload we use
  494. * here, MFC uses LVM_SETITEMSTATE, which works fine for
  495. * virtual lists.
  496. */
  497. LV_ITEM lvi;
  498. lvi.stateMask = nStateMask;
  499. lvi.state = nState;
  500. lc.SetItemState (0, &lvi);
  501. }
  502. }
  503. //+-------------------------------------------------------------------
  504. //
  505. // Member: CAMCListView::OnBeginTrack
  506. //
  507. // Synopsis: HDN_BEGINTRACK handler, due to our improper message routing
  508. // (handling all messages to CAMCView) this message gets lost
  509. // (CAMCListView::OnCmdMsg passes it to underlying view which
  510. // handles it & so we handle it here separately.
  511. //
  512. // Arguments: [pNotifyStruct] -
  513. // [result] -
  514. //
  515. //--------------------------------------------------------------------
  516. void CAMCListView::OnBeginTrack(NMHDR * pNotifyStruct, LRESULT * result)
  517. {
  518. if (!pNotifyStruct || !result)
  519. return;
  520. *result = FALSE;
  521. NMHEADER* nmh = (NMHEADER*)pNotifyStruct;
  522. SC sc = ScOnColumnsAttributeChanged(nmh, HDN_BEGINTRACK);
  523. if (sc)
  524. {
  525. sc.TraceAndClear();
  526. return;
  527. }
  528. // S_FALSE : dont allow the change
  529. if (sc == SC(S_FALSE))
  530. *result = TRUE;
  531. return;
  532. }
  533. //+-------------------------------------------------------------------
  534. //
  535. // Member: CAMCListView::IsColumnHidden
  536. //
  537. // Synopsis: Get the LPARAM and check if given column is hidden.
  538. //
  539. // Arguments: [iCol] -
  540. //
  541. // Returns: bool
  542. //
  543. //--------------------------------------------------------------------
  544. bool CAMCListView::IsColumnHidden(int iCol) const
  545. {
  546. CAMCHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
  547. if (pHeaderCtrl)
  548. return pHeaderCtrl->IsColumnHidden(iCol);
  549. return false;
  550. }
  551. //+-------------------------------------------------------------------
  552. //
  553. // Member: CAMCListView::ScGetColumnInfoList
  554. //
  555. // Synopsis: Get the CColumnInfoList from current list-view.
  556. //
  557. // Arguments: [pColumnsList] - [out param], ptr to CColumnsInfoList*
  558. //
  559. // Returns: SC
  560. //
  561. //--------------------------------------------------------------------
  562. SC CAMCListView::ScGetColumnInfoList (CColumnInfoList *pColumnsList)
  563. {
  564. DECLARE_SC(sc, _T("CAMCListView::ScGetColumnInfoList"));
  565. sc = ScCheckPointers(pColumnsList);
  566. if (sc)
  567. return sc;
  568. pColumnsList->clear();
  569. CAMCHeaderCtrl *pHeader = GetHeaderCtrl();
  570. sc = ScCheckPointers(pHeader, E_UNEXPECTED);
  571. if (sc)
  572. return sc;
  573. int cColumns = pHeader->GetItemCount();
  574. typedef std::auto_ptr<int> IntArray;
  575. IntArray spColOrder = IntArray(new int[cColumns]);
  576. int *pColOrder = spColOrder.get(); // Use a non-smart ptr for ease of use.
  577. sc = ScCheckPointers(pColOrder, E_OUTOFMEMORY);
  578. if (sc)
  579. return sc;
  580. sc = pHeader->GetOrderArray(pColOrder, cColumns) ? S_OK : E_FAIL;
  581. if (sc)
  582. return sc;
  583. for (int i = 0; i < cColumns; i++)
  584. {
  585. // Get the data from header control.
  586. HDITEM hdItem;
  587. ZeroMemory(&hdItem, sizeof(hdItem));
  588. hdItem.mask = HDI_WIDTH | HDI_LPARAM;
  589. sc = pHeader->GetItem(pColOrder[i], &hdItem) ? S_OK : E_FAIL;
  590. if (sc)
  591. return sc;
  592. // Save the visual index of the ith col
  593. CColumnInfo colInfo;
  594. colInfo.SetColIndex(pColOrder[i]);
  595. // Save the width
  596. CHiddenColumnInfo hci (hdItem.lParam);
  597. if (hci.fHidden)
  598. {
  599. colInfo.SetColHidden();
  600. colInfo.SetColWidth(hci.cx);
  601. }
  602. else
  603. colInfo.SetColWidth(hdItem.cxy);
  604. pColumnsList->push_back(colInfo);
  605. }
  606. return (sc);
  607. }
  608. //+-------------------------------------------------------------------
  609. //
  610. // Member: CAMCListView::ScModifyColumns
  611. //
  612. // Synopsis: Modify the header-control columns with given CColumnsInfoList.
  613. //
  614. // Arguments: [colInfoList] -
  615. //
  616. // Returns: SC
  617. //
  618. //--------------------------------------------------------------------
  619. SC CAMCListView::ScModifyColumns (const CColumnInfoList& colInfoList)
  620. {
  621. DECLARE_SC(sc, _T("CAMCListView::ScModifyColumns"));
  622. CAMCHeaderCtrl *pHeader = GetHeaderCtrl();
  623. CAMCView *pAMCView = GetAMCView();
  624. sc = ScCheckPointers(pHeader, pAMCView, E_UNEXPECTED);
  625. if (sc)
  626. return sc;
  627. // This method is called due to following conditions:
  628. // 1. Just before inserting first item into list-view.
  629. // 2. If there are no items in list-view then it is empty LV,
  630. // in that case this method is called during OnPaint.
  631. // 3. The IHeaderCtrlPrivate on CNodeInitObject can also call this method.
  632. // Once a node is selected & result-pane is setup, case1 or case2 above
  633. // should happen only once. To avoid multiple calls we use below flag which
  634. // says that we have attempted to restore the columns from given data.
  635. // case1 & case2 use this to determine whether to call this method.
  636. SetColumnsNeedToBeRestored();
  637. // Check for column consistency. If persisted # of cols & actual # of cols
  638. // inserted are different then ask column-data to be deleted.
  639. int cColumns = pHeader->GetItemCount();
  640. if (colInfoList.size() != cColumns)
  641. {
  642. sc = pAMCView->ScDeletePersistedColumnData();
  643. return sc;
  644. }
  645. typedef std::auto_ptr<int> IntArray;
  646. IntArray spColOrder = IntArray(new int[cColumns]);
  647. int *pColOrder = spColOrder.get(); // Use a non-smart ptr for ease of use.
  648. sc = ScCheckPointers(pColOrder, E_OUTOFMEMORY);
  649. if (sc)
  650. return sc;
  651. // Now restore the headers.
  652. {
  653. m_bColumnsBeingRestored = true; // should set this false before leaving this funcion.
  654. CColumnInfoList::iterator itColInfo;
  655. int i = 0;
  656. // Get width/order of each column.
  657. for (itColInfo = colInfoList.begin(), i = 0;
  658. itColInfo != colInfoList.end();
  659. ++itColInfo, i++)
  660. {
  661. pColOrder[i] = itColInfo->GetColIndex();
  662. // First set/reset the lparam
  663. HDITEM hdItem;
  664. ZeroMemory(&hdItem, sizeof(hdItem));
  665. if (itColInfo->IsColHidden())
  666. {
  667. // We set the width first and then LPARAM because
  668. // If we set lparam first then when we set width
  669. // CAMCView::Notify HDN_ITEMCHANGING. Now we
  670. // examine the lparam of the item to see if it is hidden.
  671. // So setting lparam first and then setting width
  672. // for hiding columns will not work.
  673. hdItem.mask = HDI_WIDTH;
  674. hdItem.cxy = 0;
  675. sc = pHeader->SetItem(pColOrder[i], &hdItem) ? S_OK : E_FAIL;
  676. if (sc)
  677. goto Error;
  678. CHiddenColumnInfo hci (itColInfo->GetColWidth(), true);
  679. hdItem.mask = HDI_LPARAM;
  680. hdItem.lParam = hci.lParam;
  681. sc = pHeader->SetItem(pColOrder[i], &hdItem) ? S_OK : E_FAIL;
  682. if (sc)
  683. goto Error;
  684. }
  685. else
  686. {
  687. CHiddenColumnInfo hci (itColInfo->GetColWidth(), false);
  688. // Here we need to clear the hidden flag in lParam
  689. // before changing width So that hidden columns will be made visible.
  690. hdItem.mask = HDI_LPARAM;
  691. hdItem.lParam = hci.lParam;
  692. sc = pHeader->SetItem(pColOrder[i], &hdItem) ? S_OK : E_FAIL;
  693. if (sc)
  694. goto Error;
  695. if ( AUTO_WIDTH == itColInfo->GetColWidth())
  696. {
  697. // If the column is hidden and made visible we do not know its width.
  698. // With ListView_SetColumnWidth passing AUTO_WIDTH for width calculates
  699. // width automatically. Header_SetItem cannot do this.
  700. sc = ListView_SetColumnWidth(GetSafeHwnd(),
  701. pColOrder[i],
  702. LVSCW_AUTOSIZE_USEHEADER) ? S_OK : E_FAIL;
  703. if (sc)
  704. goto Error;
  705. }
  706. else
  707. {
  708. hdItem.mask = HDI_WIDTH;
  709. hdItem.cxy = itColInfo->GetColWidth();
  710. sc = pHeader->SetItem(pColOrder[i], &hdItem) ? S_OK : E_FAIL;
  711. if (sc)
  712. goto Error;
  713. }
  714. }
  715. }
  716. // Set the order
  717. sc = pHeader->SetOrderArray(cColumns, pColOrder) ? S_OK : E_FAIL;
  718. if (sc)
  719. goto Error;
  720. // Now redraw the list view
  721. InvalidateRect(NULL, TRUE);
  722. }
  723. Cleanup:
  724. m_bColumnsBeingRestored = false;
  725. return (sc);
  726. Error:
  727. goto Cleanup;
  728. }
  729. //+-------------------------------------------------------------------
  730. //
  731. // Member: CAMCListView::ScGetDefaultColumnInfoList
  732. //
  733. // Synopsis: Get the default column settings.
  734. //
  735. // Arguments: [columnInfoList] - [out]
  736. //
  737. // Returns: SC
  738. //
  739. //--------------------------------------------------------------------
  740. SC CAMCListView::ScGetDefaultColumnInfoList (CColumnInfoList& columnInfoList)
  741. {
  742. DECLARE_SC(sc, _T("CAMCListView::ScRestoreDefaultColumnSettings"));
  743. if (m_defaultColumnInfoList.size() <= 0)
  744. return (sc = E_UNEXPECTED);
  745. columnInfoList = m_defaultColumnInfoList;
  746. return (sc);
  747. }
  748. //+-------------------------------------------------------------------
  749. //
  750. // Member: CAMCListView::ScSaveColumnInfoList
  751. //
  752. // Synopsis:
  753. //
  754. // Arguments:
  755. //
  756. // Returns: SC
  757. //
  758. //--------------------------------------------------------------------
  759. SC CAMCListView::ScSaveColumnInfoList ()
  760. {
  761. DECLARE_SC(sc, _T("CAMCListView::ScSaveColumnInfoList"));
  762. CAMCHeaderCtrl *pHeader = GetHeaderCtrl();
  763. CAMCView *pAMCView = GetAMCView();
  764. sc = ScCheckPointers(pHeader, pAMCView, E_UNEXPECTED);
  765. if (sc)
  766. return sc;
  767. // Get the column data & give it to CAMCView so that it can
  768. // inform NodeMgr (thro NodeCallback) about new data.
  769. CColumnInfoList colInfoList;
  770. sc = ScGetColumnInfoList (&colInfoList);
  771. if (sc)
  772. return sc;
  773. sc = pAMCView->ScColumnInfoListChanged(colInfoList);
  774. if (sc)
  775. return sc;
  776. return (sc);
  777. }
  778. //+-------------------------------------------------------------------
  779. //
  780. // Member: CAMCListView::ScOnColumnsAttributeChanged
  781. //
  782. // Synopsis: Column width/order has changed so get the column data
  783. // and ask the nodemgr to persist it.
  784. //
  785. // Arguments: NMHEADER* - the header change information.
  786. // code - the HDN_* notification.
  787. //
  788. // Returns: SC, S_OK - allow the change.
  789. // S_FALSE - dont allow the change.
  790. //
  791. //--------------------------------------------------------------------
  792. SC CAMCListView::ScOnColumnsAttributeChanged (NMHEADER *pNMHeader, UINT code)
  793. {
  794. DECLARE_SC(sc, _T("CAMCListView::ScOnColumnsAttributeChanged"));
  795. Trace (tagColumn, _T("CAMCListView::ScOnColumnsAttributeChanged"));
  796. // If we are applying persisted column data to the header control
  797. // so allow those changes.
  798. if (m_bColumnsBeingRestored)
  799. return sc;
  800. sc = ScCheckPointers(pNMHeader, pNMHeader->pitem);
  801. if (sc)
  802. return sc;
  803. // User is trying to drag a column make sure it is not a hidden column.
  804. if ( (code == HDN_BEGINTRACK) && (pNMHeader->pitem->mask & HDI_WIDTH) )
  805. {
  806. sc = IsColumnHidden(pNMHeader->iItem) ? S_FALSE : S_OK;
  807. return sc;
  808. }
  809. /*
  810. * At this point the code is HDN_ENDTRACK (width change completed) or
  811. * during HDN_ENDDRAG (order changing but not completed).
  812. * During both these messages header-control has not updated internal
  813. * data, so we post a message & save on message handler.
  814. */
  815. if ((code == HDN_ENDDRAG) || (code == HDN_ENDTRACK))
  816. {
  817. PostMessage(m_nColumnPersistedDataChangedMsg);
  818. return sc;
  819. }
  820. // Too risky to return error instead at this point, enable this for Blackcomb Beta1.
  821. // sc = E_FAIL;
  822. return (sc);
  823. }
  824. //+-------------------------------------------------------------------
  825. //
  826. // Member: CAMCListView::OnColumnPersistedDataChanged
  827. //
  828. // Synopsis: CAMCListView::m_nColumnDataChangedMsg registered message handler.
  829. // Column width/order has changed so get the column data
  830. // and ask the nodemgr to persist it.
  831. //
  832. // Returns: LRESULT
  833. //
  834. //--------------------------------------------------------------------
  835. LRESULT CAMCListView::OnColumnPersistedDataChanged (WPARAM, LPARAM)
  836. {
  837. DECLARE_SC(sc, _T("CAMCListView::OnColumnPersistedDataChanged"));
  838. Trace (tagColumn, _T("CAMCListView::OnColumnPersistedDataChanged"));
  839. if (m_bColumnsBeingRestored)
  840. return 0;
  841. sc = ScSaveColumnInfoList();
  842. if (sc)
  843. return 0;
  844. return (0);
  845. }
  846. //+-------------------------------------------------------------------
  847. //
  848. // Member: CAMCListView::ScRestoreColumnsFromPersistedData
  849. //
  850. // Synopsis: Get the persisted data for current list-view headers
  851. // and apply them.
  852. //
  853. // Arguments:
  854. //
  855. // Returns: SC
  856. //
  857. //--------------------------------------------------------------------
  858. SC CAMCListView::ScRestoreColumnsFromPersistedData ()
  859. {
  860. DECLARE_SC(sc, _T("CAMCListView::ScRestoreColumnsFromPersistedData"));
  861. Trace (tagColumn, _T("CAMCListView::ScRestoreColumnsFromPersistedData"));
  862. if (! AreColumnsNeedToBeRestored())
  863. return sc;
  864. /*
  865. * When a node is selected the snapin initially inserts columns with
  866. * some initial settings which is the default settings. At this point
  867. * the list view has the default settings, save it before applying
  868. * the persisted data.
  869. */
  870. sc = ScGetColumnInfoList(&m_defaultColumnInfoList);
  871. if (sc)
  872. return sc;
  873. CAMCHeaderCtrl *pHeader = GetHeaderCtrl();
  874. CAMCView *pAMCView = GetAMCView();
  875. sc = ScCheckPointers(pHeader, pAMCView, E_UNEXPECTED);
  876. if (sc)
  877. return sc;
  878. // Get the column data.
  879. CColumnInfoList colInfoList;
  880. sc = pAMCView->ScGetPersistedColumnInfoList(&colInfoList);
  881. // Whether there is data or not we tried to restore columns.
  882. SetColumnsNeedToBeRestored();
  883. if (sc.IsError() || (sc == SC(S_FALSE)) )
  884. return sc;
  885. // Modify headers.
  886. sc = ScModifyColumns(colInfoList);
  887. if (sc)
  888. return sc;
  889. return (sc);
  890. }
  891. //+-------------------------------------------------------------------
  892. //
  893. // Member: CAMCListView::ScResetColumnStatusData
  894. //
  895. // Synopsis: Reset the data used to keep track of hidden column state,
  896. // columns-restored state.
  897. //
  898. // Returns: SC
  899. //
  900. //--------------------------------------------------------------------
  901. SC CAMCListView::ScResetColumnStatusData ()
  902. {
  903. DECLARE_SC(sc, _T("CAMCListView::ScResetColumnStatusData"));
  904. SetColumnsNeedToBeRestored(true);
  905. m_defaultColumnInfoList.clear();
  906. return (sc);
  907. }
  908. BOOL CAMCListView::ChangePane(AMCNavDir eDir)
  909. {
  910. /*
  911. * NOTE: We need to get the header control before we get the focus window.
  912. *
  913. * The first time GetHeaderCtrl is called, it will subclass the non-MFC
  914. * header window with an MFC class. Doing this will put an entry for the
  915. * header in the permanent window map. Before GetHeaderCtrl is called,
  916. * MFC will have never seen the header before, so GetFocus will put an
  917. * entry in the temporary map. Temporary CWnd pointers will never match
  918. * permanent CWnd pointers, even though they wrap the same HWND, so we
  919. * need to make sure the header is in the permanent map before we do
  920. * any comparisons.
  921. */
  922. CWnd* pwndHeader = GetHeaderCtrl();
  923. CWnd* pwndFocus = GetFocus();
  924. bool fFocusOnList = (pwndFocus == this);
  925. bool fFocusOnHeader = (pwndFocus == pwndHeader);
  926. /*
  927. * It can't be that both the list and the focus have the focus,
  928. * although it is possible that neither has the focus.
  929. */
  930. ASSERT (!(fFocusOnList && fFocusOnHeader));
  931. /*
  932. * If either the list or the header has the focus, then this had
  933. * better be the active view; if not, it had better not.
  934. */
  935. if(!fFocusOnList && !fFocusOnHeader)
  936. return FALSE;
  937. /*
  938. * Set the focus to the header if:
  939. *
  940. * 1. the focus is currently on the list, and
  941. * 2. we're moving forward (Tab), and
  942. * 3. we're in filter mode
  943. */
  944. if (fFocusOnList && (eDir == AMCNAV_NEXT) && IsInFilteredReportMode())
  945. {
  946. GetHeaderCtrl()->SetFocus();
  947. return TRUE;
  948. }
  949. /*
  950. * Otherwise, set the focus to the list if:
  951. *
  952. * 1. the focus is not currently on the list, and
  953. * 2. we're moving backward (Shift+Tab)
  954. */
  955. // if focus not on list and we're moving backward
  956. else if (!fFocusOnList && (eDir == AMCNAV_PREV))
  957. {
  958. ActivateSelf();
  959. return TRUE;
  960. }
  961. /*
  962. * didn't change the focus
  963. */
  964. return FALSE;
  965. }
  966. BOOL CAMCListView::TakeFocus(AMCNavDir eDir)
  967. {
  968. if ((eDir == AMCNAV_PREV) && IsInFilteredReportMode())
  969. GetHeaderCtrl()->SetFocus();
  970. else
  971. ActivateSelf();
  972. ASSERT (GetParentFrame()->GetActiveView() == this);
  973. return TRUE;
  974. }
  975. /*+-------------------------------------------------------------------------*
  976. * CAMCListView::ActivateSelf
  977. *
  978. * If this isn't currently the active view, then this function makes it the
  979. * active view; the focus will be set to the list implicitly.
  980. *
  981. * If it's already the active view, calling SetActiveView won't set the
  982. * focus, because it shorts out if the active view isn't changing. In
  983. * that case, we have to set the focus ourselves.
  984. *
  985. * This function returns true if the list view was made the active view,
  986. * false if it was already the active view.
  987. *--------------------------------------------------------------------------*/
  988. bool CAMCListView::ActivateSelf (bool fNotify /* =true */)
  989. {
  990. CFrameWnd* pwndFrame = GetParentFrame();
  991. ASSERT (pwndFrame != NULL);
  992. bool fChangeActiveView = (pwndFrame->GetActiveView() != this);
  993. if (fChangeActiveView)
  994. pwndFrame->SetActiveView (this, fNotify);
  995. else
  996. SetFocus();
  997. return (fChangeActiveView);
  998. }
  999. CAMCHeaderCtrl* CAMCListView::GetHeaderCtrl() const
  1000. {
  1001. // Is there a header ?
  1002. if (m_header.m_hWnd)
  1003. return (&m_header);
  1004. // if not, try getting it now
  1005. HWND hwndHdr = reinterpret_cast<HWND>(::SendMessage (m_hWnd, LVM_GETHEADER, 0, 0));
  1006. if (hwndHdr != NULL)
  1007. {
  1008. m_header.SubclassWindow(hwndHdr);
  1009. return (&m_header);
  1010. }
  1011. return (NULL);
  1012. }
  1013. void CAMCListView::SelectDropTarget(int iDropTarget)
  1014. {
  1015. if (m_iDropTarget == iDropTarget)
  1016. return;
  1017. CListCtrl& lc = GetListCtrl();
  1018. if (m_iDropTarget != -1)
  1019. {
  1020. // remove hiliting from all items
  1021. // do not use m_iDropTarget - item order and count may be changed already
  1022. int iIndex = -1;
  1023. while ( 0 <= ( iIndex = ListView_GetNextItem(lc, iIndex, LVIS_DROPHILITED) ) )
  1024. ListView_SetItemState(lc, iIndex, 0, LVIS_DROPHILITED);
  1025. }
  1026. if (iDropTarget != -1)
  1027. ListView_SetItemState(lc, iDropTarget, LVIS_DROPHILITED, LVIS_DROPHILITED);
  1028. m_iDropTarget = iDropTarget;
  1029. }
  1030. /////////////////////////////////////////////////////////////////////////////
  1031. // CCCListViewCtrl
  1032. DEBUG_DECLARE_INSTANCE_COUNTER(CCCListViewCtrl);
  1033. CCCListViewCtrl::CCCListViewCtrl() :
  1034. m_itemCount(0),
  1035. m_nScopeItems(0),
  1036. m_colCount(0),
  1037. m_headerIL (AfxGetResourceHandle(), IDB_SORT),
  1038. m_FontLinker (this)
  1039. {
  1040. DEBUG_INCREMENT_INSTANCE_COUNTER(CCCListViewCtrl);
  1041. // Sort Stuff
  1042. m_sortParams.bAscending = TRUE;
  1043. m_sortParams.nCol = 0;
  1044. m_sortParams.lpListView = this;
  1045. m_sortParams.spResultCompare = NULL;
  1046. m_sortParams.spResultCompareEx = NULL;
  1047. m_sortParams.lpUserParam = NULL;
  1048. m_sortParams.bLexicalSort = FALSE;
  1049. m_sortParams.hSelectedNode = NULL;
  1050. // Start as standard list
  1051. m_bVirtual = FALSE;
  1052. m_bFiltered = FALSE;
  1053. m_pStandardList = new CAMCListView;
  1054. m_pVirtualList = NULL;
  1055. m_bEnsureFocusVisible = FALSE;
  1056. m_bLoading = FALSE;
  1057. m_bDeferredSort = FALSE;
  1058. m_SavedHWND = NULL;
  1059. ZeroMemory (&m_wp, sizeof(WINDOWPLACEMENT));
  1060. m_pListView = m_pStandardList;
  1061. }
  1062. CCCListViewCtrl::~CCCListViewCtrl()
  1063. {
  1064. DEBUG_DECREMENT_INSTANCE_COUNTER(CCCListViewCtrl);
  1065. if (m_SavedHWND != NULL) {
  1066. // change back
  1067. ::SetParent (m_pListView->m_hWnd, m_SavedHWND);
  1068. if (m_wp.length != 0)
  1069. ::SetWindowPlacement (m_pListView->m_hWnd, &m_wp);
  1070. // clear saved window
  1071. m_SavedHWND = NULL;
  1072. }
  1073. }
  1074. /*+-------------------------------------------------------------------------*
  1075. *
  1076. * CCCListViewCtrl::ScInitialize
  1077. *
  1078. * PURPOSE:
  1079. *
  1080. * RETURNS:
  1081. * SC
  1082. *
  1083. *+-------------------------------------------------------------------------*/
  1084. SC
  1085. CCCListViewCtrl::ScInitialize()
  1086. {
  1087. DECLARE_SC(sc, _T("CCCListViewCtrl::ScInitialize"));
  1088. CAMCView* pAMCView = m_pListView->GetAMCView();
  1089. sc = ScCheckPointers(pAMCView, E_FAIL);
  1090. if (sc)
  1091. return sc;
  1092. AddObserver(static_cast<CListViewObserver&>(*pAMCView));
  1093. return sc;
  1094. }
  1095. //---------------------------------------------------- Utility functions
  1096. void CCCListViewCtrl::CutSelectedItems(BOOL bCut)
  1097. {
  1098. CListCtrl& lc = GetListCtrl();
  1099. int nSearchFlags = (bCut) ? LVNI_SELECTED : LVNI_CUT;
  1100. int nNewState = (bCut) ? LVIS_CUT : 0;
  1101. int nItem = -1;
  1102. while ((nItem = lc.GetNextItem (nItem, nSearchFlags)) >= 0)
  1103. {
  1104. lc.SetItemState (nItem, nNewState, LVIS_CUT);
  1105. }
  1106. }
  1107. /*+-------------------------------------------------------------------------*
  1108. * CCCListViewCtrl::IndexToResultItem
  1109. *
  1110. * Returns the CResultItem pointer for a given index.
  1111. *--------------------------------------------------------------------------*/
  1112. CResultItem* CCCListViewCtrl::IndexToResultItem (int nItem)
  1113. {
  1114. HRESULTITEM hri = GetListCtrl().GetItemData (nItem);
  1115. if (IS_SPECIAL_LVDATA (hri))
  1116. return (NULL);
  1117. return (CResultItem::FromHandle (hri));
  1118. }
  1119. /*+-------------------------------------------------------------------------*
  1120. * CCCListViewCtrl::ResultItemToIndex
  1121. *
  1122. * Returns the index of an item given its CResultItem pointer. This does a
  1123. * linear search. If the speed of this function needs to be improved,
  1124. * we'll need a separate CResultItem-to-index map.
  1125. *--------------------------------------------------------------------------*/
  1126. int CCCListViewCtrl::ResultItemToIndex (CResultItem* pri) const
  1127. {
  1128. /*
  1129. * if this is a virtual list, the CResultItem "pointer" is actually
  1130. * the item index, so convert it. Note that CResultItem::ToHandle is
  1131. * safe to call with a NULL pointer.
  1132. */
  1133. if (IsVirtual())
  1134. return (CResultItem::ToHandle(pri));
  1135. /*
  1136. * No items have NULL CResultItem pointers, don't bother looking.
  1137. */
  1138. if (pri == NULL)
  1139. return (-1);
  1140. /*
  1141. * Let the list find the matching item.
  1142. */
  1143. LV_FINDINFO lvfi;
  1144. lvfi.flags = LVFI_PARAM;
  1145. lvfi.lParam = CResultItem::ToHandle(pri);
  1146. return (GetListCtrl().FindItem (&lvfi, -1));
  1147. }
  1148. /////////////////////////////////////////////////////////////////////////////
  1149. // CCCListViewCtrl message handlers
  1150. HRESULT CCCListViewCtrl::InsertItem(
  1151. LPOLESTR str,
  1152. long iconNdx,
  1153. LPARAM lParam,
  1154. long state,
  1155. COMPONENTID ownerID,
  1156. long itemIndex,
  1157. CResultItem*& priInserted)
  1158. {
  1159. DECLARE_SC(sc, TEXT("CCCListViewCtrl::InsertItem"));
  1160. /*
  1161. * init the output parameter
  1162. */
  1163. priInserted = NULL;
  1164. if (IsVirtual())
  1165. return (sc = E_UNEXPECTED).ToHr();
  1166. if (str != MMC_TEXTCALLBACK)
  1167. return (sc = E_INVALIDARG).ToHr();
  1168. // Ask the CAMCListViewCtrl to setup headers.
  1169. sc = ScCheckPointers(m_pListView, E_UNEXPECTED);
  1170. if (! sc.IsError())
  1171. sc = m_pListView->ScRestoreColumnsFromPersistedData();
  1172. if (sc)
  1173. sc.TraceAndClear();
  1174. USES_CONVERSION;
  1175. LV_ITEM lvi;
  1176. lvi.iSubItem = 0;
  1177. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  1178. lvi.pszText = LPSTR_TEXTCALLBACK;
  1179. // If the user has specified an icon index, map it and put it in the LV_ITEM struct
  1180. int nMapping = 0;
  1181. if ((iconNdx != MMCLV_NOICON) &&
  1182. m_resultIM.Lookup(&CImageIndexMapKey(ownerID,iconNdx), nMapping))
  1183. {
  1184. lvi.iImage = nMapping;
  1185. }
  1186. else
  1187. {
  1188. lvi.iImage = MMCLV_NOICON;
  1189. iconNdx = MMCLV_NOICON;
  1190. }
  1191. /*
  1192. * allocate and initialize a CResultItem for this item
  1193. */
  1194. sc = ScAllocResultItem (priInserted, ownerID, lParam, iconNdx);
  1195. if (sc)
  1196. return (sc.ToHr());
  1197. sc = ScCheckPointers (priInserted, E_UNEXPECTED);
  1198. if (sc)
  1199. return (sc.ToHr());
  1200. // If the user has specified a state, put it in the LV_ITEM struct
  1201. if (state != MMCLV_NOPARAM)
  1202. {
  1203. lvi.mask |= LVIF_STATE;
  1204. lvi.state = state;
  1205. lvi.stateMask = 0xFFFFFFFF;
  1206. }
  1207. // if scope item
  1208. if (priInserted->IsScopeItem())
  1209. {
  1210. // if no index provided add to end of unsorted items
  1211. lvi.iItem = (itemIndex == -1) ? m_nScopeItems : itemIndex;
  1212. // if decending sort, offset from end instead of start
  1213. if (!m_sortParams.bAscending)
  1214. lvi.iItem += (m_itemCount - m_nScopeItems);
  1215. }
  1216. else
  1217. {
  1218. // Add sorted items to end of list (or before unsorted items, if reverse sorting)
  1219. lvi.iItem = m_sortParams.bAscending ? m_itemCount : m_itemCount - m_nScopeItems;
  1220. }
  1221. lvi.lParam = CResultItem::ToHandle(priInserted);
  1222. int nIndex = GetListCtrl().InsertItem (&lvi);
  1223. #if (defined(DBG) && defined(DEBUG_LIST_INSERTIONS))
  1224. static int cInserted = 0;
  1225. TRACE3 ("%4d:Inserted item: index=%d, lParam=0x%08x\n", ++cInserted, nIndex, lvi.lParam);
  1226. #endif
  1227. if (nIndex == -1 )
  1228. {
  1229. sc = E_FAIL;
  1230. ScFreeResultItem (priInserted); // ignore failures
  1231. priInserted = NULL;
  1232. }
  1233. else
  1234. {
  1235. // The insert succeeded, increase the internal item counts
  1236. m_itemCount++;
  1237. // we invalidate the rectangle when transitioning from zero to one item because otherwise the
  1238. // empty list message is not erased completely.
  1239. if(m_itemCount == 1)
  1240. GetListCtrl().InvalidateRect(NULL);
  1241. if (priInserted->IsScopeItem())
  1242. m_nScopeItems++;
  1243. // if ensure focus visible style and focus set, force item into view
  1244. if (m_bEnsureFocusVisible && state != MMCLV_NOPARAM && (state & LVIS_FOCUSED))
  1245. GetListCtrl().EnsureVisible(nIndex, FALSE);
  1246. }
  1247. if (sc)
  1248. return sc.ToHr();
  1249. // we have inserted an Item! - broadcast the good message to observers
  1250. sc = ScFireEvent(CListViewObserver::ScOnListViewItemInserted, nIndex);
  1251. if (sc)
  1252. return sc.ToHr();
  1253. return sc.ToHr();
  1254. }
  1255. HRESULT CCCListViewCtrl::DeleteItem(HRESULTITEM itemID, long nCol)
  1256. {
  1257. DECLARE_SC(sc, TEXT("CCCListViewCtrl::DeleteItem"));
  1258. if (nCol != 0)
  1259. return E_INVALIDARG;
  1260. CListCtrl& lc = GetListCtrl();
  1261. int nItem = IsVirtual() ? static_cast<int>(itemID)
  1262. : ResultItemToIndex( CResultItem::FromHandle(itemID) );
  1263. #if (defined(DBG) && defined(DEBUG_LIST_INSERTIONS))
  1264. static int cDeletes = 0;
  1265. TRACE3 ("%4d:Deleted item: index=%d, lParam=0x%08x", ++cDeletes, nItem, priDelete);
  1266. #endif
  1267. if (nItem < 0 || nItem >= m_itemCount)
  1268. {
  1269. ASSERT(FALSE);
  1270. #if (defined(DEBUG_LIST_INSERTIONS))
  1271. TRACE0 (" (failed)\n");
  1272. #endif
  1273. return E_INVALIDARG;
  1274. }
  1275. #if (defined(DEBUG_LIST_INSERTIONS))
  1276. TRACE0 ("\n");
  1277. #endif
  1278. if (!lc.DeleteItem (nItem))
  1279. {
  1280. sc = E_FAIL;
  1281. }
  1282. else
  1283. {
  1284. // Delete was successful, decrement the ItemCount
  1285. ASSERT(m_itemCount > 0);
  1286. m_itemCount--;
  1287. if (!IsVirtual())
  1288. {
  1289. CResultItem *priDelete = CResultItem::FromHandle(itemID);
  1290. sc = ScCheckPointers (priDelete, E_UNEXPECTED);
  1291. if (sc)
  1292. return (sc.ToHr());
  1293. if (priDelete->IsScopeItem())
  1294. m_nScopeItems--;
  1295. sc = ScFreeResultItem (priDelete);
  1296. if (sc)
  1297. return (sc.ToHr());
  1298. }
  1299. }
  1300. if (sc)
  1301. return sc.ToHr();
  1302. // select the focused item ( this will save a lot of snapins from the confusion
  1303. // since they are not prepared to handle 'no items selected' scenario.
  1304. // Note: we only guard single selection lists - for multiple selection the situation
  1305. // must be handled by snapin, since user can easily unselect the item.
  1306. if ( (::GetFocus() == lc.m_hWnd) && (lc.GetStyle() & LVS_SINGLESEL) )
  1307. {
  1308. // check if focused item is selected
  1309. int iMarkedItem = lc.GetSelectionMark();
  1310. if ( (iMarkedItem >= 0) && !( lc.GetItemState( iMarkedItem, LVIS_SELECTED ) & LVIS_SELECTED ) )
  1311. {
  1312. // NOTE: do not use lc.SetItemState - it uses SetItem which is not supported for virtual lists
  1313. LV_ITEM lvi;
  1314. lvi.stateMask = lvi.state = LVIS_SELECTED;
  1315. if (!lc.SendMessage( LVM_SETITEMSTATE, WPARAM(iMarkedItem), (LPARAM)(LV_ITEM FAR *)&lvi))
  1316. (sc = E_FAIL).TraceAndClear(); // trace is enough - ignore and continue
  1317. }
  1318. }
  1319. // we have deleted an Item! - broadcast the message to observers
  1320. sc = ScFireEvent(CListViewObserver::ScOnListViewItemDeleted, nItem);
  1321. if (sc)
  1322. return sc.ToHr();
  1323. return sc.ToHr();
  1324. }
  1325. //+-------------------------------------------------------------------
  1326. //
  1327. // Member: CCCListViewCtrl::UpdateItem
  1328. //
  1329. // Synopsis: Update the given item.
  1330. //
  1331. // Arguments: [itemID] -
  1332. //
  1333. // Returns: HRESULT
  1334. //
  1335. //--------------------------------------------------------------------
  1336. HRESULT CCCListViewCtrl::UpdateItem(HRESULTITEM itemID)
  1337. {
  1338. DECLARE_SC (sc, _T("CCCListViewCtrl::UpdateItem"));
  1339. int nIndex = -1;
  1340. sc = ScGetItemIndexFromHRESULTITEM(itemID, nIndex);
  1341. if (sc)
  1342. return sc.ToHr();
  1343. if(nIndex < 0 || nIndex >= m_itemCount)
  1344. return (sc = E_INVALIDARG).ToHr();
  1345. CListCtrl& lc = GetListCtrl();
  1346. /*
  1347. * Since Common Control does not hold any data about virtual list view
  1348. * items they would not know what to invalidate. So we need to invalidate
  1349. * for virtual list views.
  1350. */
  1351. if (IsVirtual())
  1352. {
  1353. RECT rc;
  1354. lc.GetItemRect(nIndex, &rc, LVIR_BOUNDS);
  1355. lc.InvalidateRect(&rc);
  1356. }
  1357. else
  1358. {
  1359. sc = ScRedrawItem(nIndex);
  1360. if (sc)
  1361. return (sc.ToHr());
  1362. }
  1363. lc.UpdateWindow();
  1364. // we have updated an item - broadcast the message to observers
  1365. sc = ScFireEvent(CListViewObserver::ScOnListViewItemUpdated, nIndex);
  1366. if (sc)
  1367. return sc.ToHr();
  1368. return sc.ToHr();
  1369. }
  1370. //+-------------------------------------------------------------------
  1371. //
  1372. // Member: CCCListViewCtrl::ScGetItemIndexFromHRESULTITEM
  1373. //
  1374. // Synopsis: Given HRESULTITEM get the index of that item.
  1375. // For virtual listview the itemid is the index.
  1376. //
  1377. // Arguments: [itemID] - [in param]
  1378. // [nIndex] - [out param]
  1379. //
  1380. // Returns: SC
  1381. //
  1382. //--------------------------------------------------------------------
  1383. SC CCCListViewCtrl::ScGetItemIndexFromHRESULTITEM (const HRESULTITEM& itemID, int& nIndex)
  1384. {
  1385. DECLARE_SC(sc, _T("CCCListViewCtrl::ScGetItemIndexFromHRESULTITEM"));
  1386. nIndex = -1;
  1387. if (IsVirtual())
  1388. {
  1389. nIndex = itemID;
  1390. return sc;
  1391. }
  1392. CResultItem *pri = CResultItem::FromHandle(itemID);
  1393. sc = ScCheckPointers(pri, E_UNEXPECTED);
  1394. if (sc)
  1395. return sc;
  1396. nIndex = ResultItemToIndex(pri);
  1397. return (sc);
  1398. }
  1399. //+-------------------------------------------------------------------
  1400. //
  1401. // Member: CCCListViewCtrl::ScRedrawItem
  1402. //
  1403. // Synopsis: Redraw the given item in listview.
  1404. //
  1405. // Arguments: [nIndex] -
  1406. //
  1407. // Returns: SC
  1408. //
  1409. //--------------------------------------------------------------------
  1410. SC CCCListViewCtrl::ScRedrawItem(int nIndex)
  1411. {
  1412. DECLARE_SC (sc, _T("CCCListViewCtrl::RedrawItem"));
  1413. if(nIndex < 0 || nIndex >= m_itemCount)
  1414. return (sc = E_INVALIDARG);
  1415. if (!GetListCtrl().RedrawItems (nIndex, nIndex))
  1416. return (sc = E_FAIL);
  1417. return (sc);
  1418. }
  1419. //+-------------------------------------------------------------------
  1420. //
  1421. // Member: Sort
  1422. //
  1423. // Synopsis: Sort the list view with given data.
  1424. //
  1425. // Arguments: [lpUserParam] - Snapin supplied user param.
  1426. // [lParms] - ptr to CCLVSortParams struct.
  1427. //
  1428. // Returns: HRESULT
  1429. //
  1430. //--------------------------------------------------------------------
  1431. HRESULT CCCListViewCtrl::Sort(LPARAM lUserParam, long* lParms)
  1432. {
  1433. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Sort"));
  1434. if (IsVirtual())
  1435. {
  1436. sc = E_UNEXPECTED;
  1437. return sc.ToHr();
  1438. }
  1439. BOOL bResult = FALSE;
  1440. CCLVSortParams* lpParams = reinterpret_cast<CCLVSortParams*>(lParms);
  1441. ASSERT(lpParams != NULL);
  1442. // Note: the hwnd should only be initialize in ::Create
  1443. m_sortParams.bAscending = lpParams->bAscending;
  1444. m_sortParams.nCol = lpParams->nCol;
  1445. m_sortParams.spResultCompare = lpParams->lpResultCompare;
  1446. m_sortParams.spResultCompareEx = lpParams->lpResultCompareEx;
  1447. m_sortParams.lpUserParam = lUserParam;
  1448. // Do not sort on hidden columns.
  1449. if (IsColumnHidden(m_sortParams.nCol))
  1450. return (sc.ToHr());
  1451. {
  1452. // Check view options for scope item sorting
  1453. CAMCView* pAMCView = m_pListView->GetAMCView();
  1454. sc = ScCheckPointers(pAMCView, E_FAIL);
  1455. if (sc)
  1456. return (sc.ToHr());
  1457. SViewData* pViewData = pAMCView->GetViewData();
  1458. sc = ScCheckPointers(pViewData, E_FAIL);
  1459. if (sc)
  1460. return (sc.ToHr());
  1461. m_sortParams.bLexicalSort = ((pViewData->GetListOptions() & RVTI_LIST_OPTIONS_LEXICAL_SORT) != 0);
  1462. LPNODECALLBACK pNodeCallback = pAMCView->GetNodeCallback();
  1463. sc = ScCheckPointers(pNodeCallback, E_FAIL);
  1464. if (sc)
  1465. return (sc.ToHr());
  1466. // Do not need to refcount this, because it is being passed to a method that returns.
  1467. m_sortParams.lpNodeCallback = pNodeCallback;
  1468. // Get component ID of node that owns the result view
  1469. HNODE hnodeOwner = pAMCView->GetSelectedNode();
  1470. sc = ScCheckPointers((LPVOID)hnodeOwner, E_FAIL);
  1471. if (sc)
  1472. return (sc.ToHr());
  1473. m_sortParams.hSelectedNode = hnodeOwner;
  1474. sc = pNodeCallback->GetNodeOwnerID(hnodeOwner, &m_sortParams.OwnerID);
  1475. if (sc)
  1476. return (sc.ToHr());
  1477. if (m_bLoading)
  1478. {
  1479. bResult = TRUE;
  1480. m_bDeferredSort = TRUE;
  1481. }
  1482. else
  1483. {
  1484. /*
  1485. * the sort could take awhile, so show a wait cursor
  1486. */
  1487. CWaitCursor wait;
  1488. // It is lexical sort if
  1489. // 1. LV option specifies lexical sort option or
  1490. // 2. Snapin does not implement IResultDataCompare
  1491. // or IResultDataCompareEx interfaces.
  1492. BOOL bLexicalSort = ( m_sortParams.bLexicalSort ||
  1493. ( (NULL == m_sortParams.spResultCompare) &&
  1494. (NULL == m_sortParams.spResultCompareEx) ) );
  1495. if (bLexicalSort)
  1496. {
  1497. bResult = GetListCtrl().SortItems (DefaultCompare, (DWORD_PTR)&m_sortParams);
  1498. }
  1499. else
  1500. {
  1501. bResult = GetListCtrl().SortItems (SortCompareFunc, (DWORD_PTR)&m_sortParams);
  1502. }
  1503. }
  1504. sc = (bResult == TRUE) ? S_OK : E_FAIL;
  1505. if (sc)
  1506. return (sc.ToHr());
  1507. // we have sorted Items! - cannot keep track of them currently
  1508. sc = ScFireEvent(CListViewObserver::ScOnListViewIndexesReset);
  1509. if (sc)
  1510. return (sc.ToHr());
  1511. }
  1512. return sc.ToHr();
  1513. }
  1514. HRESULT CCCListViewCtrl::FindItemByLParam(COMPONENTID ownerID, LPARAM lParam, CResultItem*& priFound)
  1515. {
  1516. DECLARE_SC (sc, _T("CCCListViewCtrl::FindItemByLParam"));
  1517. /*
  1518. * init output parameter
  1519. */
  1520. priFound = NULL;
  1521. if (IsVirtual())
  1522. return (sc = E_UNEXPECTED).ToHr();
  1523. /*
  1524. * find a CResultItem that matches the given owner and lParam.
  1525. */
  1526. for (int i = GetListCtrl().GetItemCount()-1; i >= 0; i--)
  1527. {
  1528. CResultItem* pri = IndexToResultItem (i);
  1529. if ((pri != NULL) &&
  1530. (pri->GetOwnerID() == ownerID) &&
  1531. (pri->GetSnapinData() == lParam))
  1532. {
  1533. priFound = pri;
  1534. break;
  1535. }
  1536. }
  1537. if (priFound == NULL)
  1538. return ((sc = E_FAIL).ToHr());
  1539. return sc.ToHr();
  1540. }
  1541. HRESULT CCCListViewCtrl::GetListStyle()
  1542. {
  1543. LONG result;
  1544. ASSERT(::IsWindow(GetListViewHWND()));
  1545. // return the Style masked by the List View Style mask.
  1546. result = ::GetWindowLong(GetListViewHWND(),GWL_STYLE) & 0xffff;
  1547. return result;
  1548. }
  1549. HRESULT CCCListViewCtrl::SetListStyle(long nNewValue)
  1550. {
  1551. ASSERT(::IsWindow(GetListViewHWND()));
  1552. // Protect style bits that shouldn't be changed
  1553. // Use SetViewMode to change the mode, so filtering is properly updated
  1554. const long PRESERVE_MASK = LVS_OWNERDATA | LVS_SHAREIMAGELISTS | 0xffff0000;
  1555. DWORD curStyle = ::GetWindowLong(GetListViewHWND(), GWL_STYLE);
  1556. DWORD newStyle = (curStyle & PRESERVE_MASK) | (nNewValue & ~PRESERVE_MASK);
  1557. // Verify not changing the view mode
  1558. ASSERT( ((curStyle ^ newStyle) & LVS_TYPEMASK) == 0);
  1559. // verify OWNERDATA style is what we think it is
  1560. ASSERT((curStyle & LVS_OWNERDATA) && m_bVirtual || !(curStyle & LVS_OWNERDATA) && !m_bVirtual);
  1561. // Save state of MMC defined "ensure focus visible" syle
  1562. m_bEnsureFocusVisible = (nNewValue & MMC_LVS_ENSUREFOCUSVISIBLE) != 0;
  1563. if (curStyle != newStyle)
  1564. {
  1565. // Apply style changes
  1566. ::SetWindowLong(GetListViewHWND(), GWL_STYLE, newStyle);
  1567. /*
  1568. * The list control does not pass changes to the LVS_NOSORTHEADER flag on to the
  1569. * HeaderCtrl. This section directly accesses the underlying HeaderCtrl and
  1570. * changes the HDS_BUTTONS flag which is the equivalent.
  1571. */
  1572. if ((nNewValue & LVS_NOSORTHEADER) ^ (curStyle & LVS_NOSORTHEADER) && GetHeaderCtrl())
  1573. {
  1574. if (nNewValue & LVS_NOSORTHEADER)
  1575. GetHeaderCtrl()->ModifyStyle (HDS_BUTTONS, 0); // Add the style
  1576. else
  1577. GetHeaderCtrl()->ModifyStyle (0, HDS_BUTTONS); // Remove the style
  1578. }
  1579. }
  1580. return S_OK;
  1581. }
  1582. HRESULT CCCListViewCtrl::GetViewMode()
  1583. {
  1584. ASSERT(::IsWindow(GetListViewHWND()));
  1585. long nViewMode;
  1586. if (m_bFiltered)
  1587. nViewMode = MMCLV_VIEWSTYLE_FILTERED;
  1588. else
  1589. nViewMode = ::GetWindowLong(GetListViewHWND(), GWL_STYLE) & LVS_TYPEMASK;
  1590. return nViewMode;
  1591. }
  1592. #include "histlist.h"
  1593. HRESULT CCCListViewCtrl::SetViewMode(long nViewMode)
  1594. {
  1595. ASSERT(nViewMode >= 0 && nViewMode <= MMCLV_VIEWSTYLE_FILTERED);
  1596. CListCtrl& lc = GetListCtrl();
  1597. if (nViewMode < 0 && nViewMode > MMCLV_VIEWSTYLE_FILTERED)
  1598. return E_INVALIDARG;
  1599. CAMCView* pAMCView = dynamic_cast<CAMCView*>(m_pParentWnd);
  1600. if (pAMCView)
  1601. pAMCView->GetHistoryList()->SetCurrentViewMode (nViewMode);
  1602. BOOL bFiltered = FALSE;
  1603. if (nViewMode == MMCLV_VIEWSTYLE_FILTERED)
  1604. {
  1605. bFiltered = TRUE;
  1606. nViewMode = LVS_REPORT;
  1607. }
  1608. lc.ModifyStyle (LVS_TYPEMASK, nViewMode);
  1609. HRESULT hr = S_OK;
  1610. // set filter style
  1611. CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
  1612. ASSERT(NULL != pHeaderCtrl);
  1613. if (bFiltered != m_bFiltered && pHeaderCtrl)
  1614. {
  1615. if (bFiltered)
  1616. pHeaderCtrl->ModifyStyle (0, HDS_FILTERBAR);
  1617. else
  1618. pHeaderCtrl->ModifyStyle (HDS_FILTERBAR, 0);
  1619. m_bFiltered = bFiltered;
  1620. // The header size has changed with the addition/removal of filter.
  1621. // We hide and show the header which will force the list
  1622. // control to recalculate the size, position of new header
  1623. // and list view and display it.
  1624. lc.ModifyStyle(0, LVS_NOCOLUMNHEADER, 0);
  1625. lc.ModifyStyle(LVS_NOCOLUMNHEADER, 0, 0);
  1626. }
  1627. return S_OK;
  1628. }
  1629. HRESULT CCCListViewCtrl::SetVirtualMode(BOOL bVirtual)
  1630. {
  1631. ASSERT(::IsWindow(GetListViewHWND()));
  1632. HRESULT hr = S_OK;
  1633. // force param to TRUE or FALSE
  1634. bVirtual = bVirtual ? TRUE : FALSE;
  1635. if (bVirtual != m_bVirtual)
  1636. {
  1637. do // false loop
  1638. {
  1639. // list must be empty to switch
  1640. if (m_itemCount != 0)
  1641. {
  1642. ASSERT(FALSE);
  1643. hr = E_FAIL;
  1644. break;
  1645. }
  1646. // get styles to copy to new control
  1647. long curStyle = ::GetWindowLong(GetListViewHWND(), GWL_STYLE) ^ LVS_OWNERDATA;
  1648. long curStyleEx = ::GetWindowLong(GetListViewHWND(), GWL_EXSTYLE);
  1649. long curHdrStyle = 0;
  1650. if (GetHeaderCtrl())
  1651. curHdrStyle = GetHeaderCtrl()->GetStyle();
  1652. if (bVirtual && !m_pVirtualList)
  1653. {
  1654. m_pVirtualList = new CAMCListView;
  1655. m_pVirtualList->SetVirtual();
  1656. }
  1657. CAMCListView* pNewList = bVirtual ? m_pVirtualList : m_pStandardList;
  1658. CAMCListView* pOldList = m_pListView;
  1659. // Make sure new control has been created
  1660. if (pNewList->m_hWnd == NULL)
  1661. {
  1662. /*
  1663. * MFC will issue a warning about creating a pane with
  1664. * no document. That's OK, since CAMCView::AttachListView-
  1665. * AsResultPane will patch thing up later.
  1666. */
  1667. ASSERT (pOldList != NULL);
  1668. if (!Create(curStyle, g_rectEmpty, m_pParentWnd, pOldList->GetDlgCtrlID()))
  1669. {
  1670. ASSERT(FALSE);
  1671. hr = E_FAIL;
  1672. break;
  1673. }
  1674. }
  1675. // update member variables (this switches to the new control)
  1676. m_bVirtual = bVirtual;
  1677. m_pListView = bVirtual ? m_pVirtualList : m_pStandardList;
  1678. // Set current styles on new control
  1679. ::SetWindowLong(GetListViewHWND(), GWL_STYLE, curStyle);
  1680. ::SetWindowLong(GetListViewHWND(), GWL_EXSTYLE, curStyleEx);
  1681. // Note we have switched to the other control by now so this is getting the
  1682. // header of the new list
  1683. if (GetHeaderCtrl())
  1684. ::SetWindowLong(GetHeaderCtrl()->m_hWnd, GWL_STYLE, curHdrStyle);
  1685. // hide the old list control and show the new one
  1686. ::ShowWindow(pOldList->m_hWnd, SW_HIDE);
  1687. ::ShowWindow(m_pListView->m_hWnd, SW_SHOWNA);
  1688. }
  1689. while (0);
  1690. }
  1691. return hr;
  1692. }
  1693. HRESULT CCCListViewCtrl::InsertColumn(int nCol, LPCOLESTR str, long nFormat, long width)
  1694. {
  1695. // Cannot change a column that is not in the list.
  1696. if(!str || !*str)
  1697. return E_INVALIDARG;
  1698. HRESULT hr = S_OK;
  1699. LV_COLUMN newCol;
  1700. void* pvoid = &newCol;
  1701. // Cannot insert a column with any items in the list.
  1702. if(m_itemCount)
  1703. {
  1704. hr = E_FAIL;
  1705. }
  1706. else
  1707. {
  1708. newCol.mask=0;
  1709. USES_CONVERSION;
  1710. // if the user specified a string, put it in the struct.
  1711. if(str!=MMCLV_NOPTR)
  1712. {
  1713. newCol.mask|=LVCF_TEXT;
  1714. newCol.pszText=OLE2T((LPOLESTR)str);
  1715. }
  1716. // if the user specified a format, put it in the struct.
  1717. if(nFormat!=MMCLV_NOPARAM)
  1718. {
  1719. newCol.mask|=LVCF_FMT;
  1720. newCol.fmt=nFormat;
  1721. }
  1722. // if the user specified a width, put it in the struct.
  1723. if(width!=MMCLV_NOPARAM)
  1724. {
  1725. newCol.mask|=LVCF_WIDTH;
  1726. // if the user requested auto-width, calculate the width.
  1727. // else just store the passed width.
  1728. if(width==MMCLV_AUTO)
  1729. {
  1730. // if the user did pass a string, calculate the width based off the string.
  1731. // else the width is 0.
  1732. if(str!=MMCLV_NOPTR)
  1733. {
  1734. CSize sz(0,0);
  1735. CClientDC dc( m_pListView );
  1736. dc.SelectObject( m_pListView->GetFont());
  1737. sz=dc.GetTextExtent(OLE2CT((LPOLESTR)str),_tcslen(OLE2T((LPOLESTR)
  1738. str)));
  1739. newCol.cx=sz.cx+CCLV_HEADERPAD;
  1740. }
  1741. else
  1742. {
  1743. newCol.cx=0;
  1744. }
  1745. }
  1746. else
  1747. {
  1748. newCol.cx=width;
  1749. }
  1750. }
  1751. int nRet = GetListCtrl().InsertColumn (nCol, &newCol);
  1752. if (-1 == nRet)
  1753. hr = E_FAIL;
  1754. else
  1755. {
  1756. // set lparam (HDI_HIDDEN flag) if the width is HIDE_COLUMN
  1757. if (HIDE_COLUMN == width)
  1758. {
  1759. CHiddenColumnInfo hci (0, true);
  1760. HDITEM hdItem;
  1761. ::ZeroMemory(&hdItem, sizeof(hdItem));
  1762. hdItem.mask = HDI_LPARAM;
  1763. hdItem.lParam = hci.lParam;
  1764. // We do not care if this call fails
  1765. if (GetHeaderCtrl())
  1766. GetHeaderCtrl()->SetItem(nRet, &hdItem);
  1767. }
  1768. else
  1769. {
  1770. CHiddenColumnInfo hci (newCol.cx, false);
  1771. // set lparam with the width.
  1772. HDITEM hdItem;
  1773. ::ZeroMemory(&hdItem, sizeof(hdItem));
  1774. hdItem.mask = HDI_LPARAM;
  1775. hdItem.lParam = hci.lParam;
  1776. // We do not care if this call fails
  1777. if (GetHeaderCtrl())
  1778. GetHeaderCtrl()->SetItem(nRet, &hdItem);
  1779. }
  1780. // insert was successful, increment the column count.
  1781. m_colCount++;
  1782. }
  1783. }
  1784. // we have inserted a column! - broadcast the message to observers
  1785. if (SUCCEEDED(hr))
  1786. {
  1787. SC sc = ScFireEvent(CListViewObserver::ScOnListViewColumnInserted, nCol);
  1788. if (sc)
  1789. return sc.ToHr();
  1790. }
  1791. return hr;
  1792. }
  1793. HRESULT CCCListViewCtrl::DeleteColumn(int nCol)
  1794. {
  1795. if (nCol < 0 || nCol >= m_colCount)
  1796. return E_INVALIDARG;
  1797. HRESULT hr = S_OK;
  1798. // Cannot delete a column if there are items in the list.
  1799. if(m_itemCount)
  1800. {
  1801. hr = E_FAIL;
  1802. }
  1803. else
  1804. {
  1805. if (!GetListCtrl().DeleteColumn (nCol))
  1806. hr = E_FAIL;
  1807. else
  1808. // Successful delete, decrement the column count.
  1809. m_colCount--;
  1810. }
  1811. // we have deleteded a column! - broadcast the message to observers
  1812. if (SUCCEEDED(hr))
  1813. {
  1814. SC sc = ScFireEvent(CListViewObserver::ScOnListViewColumnDeleted, nCol);
  1815. if (sc)
  1816. return sc.ToHr();
  1817. }
  1818. return hr;
  1819. }
  1820. HRESULT CCCListViewCtrl::GetColumnCount(int* pnColCnt)
  1821. {
  1822. *pnColCnt = m_colCount;
  1823. return S_OK;
  1824. }
  1825. HRESULT CCCListViewCtrl::DeleteAllItems(COMPONENTID ownerID)
  1826. {
  1827. DECLARE_SC(sc, TEXT("CCCListViewCtrl::DeleteAllItems"));
  1828. CListCtrl& lc = GetListCtrl();
  1829. const bool bHasItemsToDelete = (m_itemCount > 0);
  1830. // Nothing in the list -> nothing to do.
  1831. if (bHasItemsToDelete)
  1832. {
  1833. if (IsVirtual())
  1834. {
  1835. if (lc.DeleteAllItems ())
  1836. m_itemCount = 0;
  1837. else
  1838. sc = E_FAIL;
  1839. }
  1840. else if (ownerID == TVOWNED_MAGICWORD)
  1841. {
  1842. /*
  1843. * free all of the CResultItem objects
  1844. */
  1845. for (int i = m_itemCount - 1; i >= 0; i--)
  1846. {
  1847. CResultItem* pri = IndexToResultItem (i);
  1848. if (pri != NULL)
  1849. {
  1850. sc = ScFreeResultItem(pri);
  1851. if (sc)
  1852. return (sc.ToHr());
  1853. }
  1854. }
  1855. if (lc.DeleteAllItems ())
  1856. {
  1857. // Delete all succeded, ItemCount is now 0;
  1858. m_itemCount = 0;
  1859. m_nScopeItems = 0;
  1860. }
  1861. else
  1862. sc = E_FAIL;
  1863. }
  1864. else
  1865. {
  1866. for(int i = m_itemCount - 1; i >= 0; i--)
  1867. {
  1868. CResultItem* pri = IndexToResultItem (i);
  1869. if ((pri != NULL) && (pri->GetOwnerID() == ownerID))
  1870. {
  1871. if (lc.DeleteItem (i))
  1872. {
  1873. m_itemCount--;
  1874. sc = ScFreeResultItem(pri);
  1875. if (sc)
  1876. return (sc.ToHr());
  1877. }
  1878. else
  1879. sc = E_FAIL;
  1880. }
  1881. }
  1882. }
  1883. }
  1884. if (sc)
  1885. return sc.ToHr();
  1886. if (bHasItemsToDelete)
  1887. {
  1888. // we have deleted all Items! - broadcast the message to observers
  1889. sc = ScFireEvent(CListViewObserver::ScOnListViewIndexesReset);
  1890. if (sc)
  1891. return sc.ToHr();
  1892. }
  1893. return sc.ToHr();
  1894. }
  1895. HRESULT CCCListViewCtrl::SetColumn(long nCol, LPCOLESTR str, long nFormat, long width)
  1896. {
  1897. // Cannot change a column that is not in the list.
  1898. if((nCol + 1) > m_colCount)
  1899. return E_INVALIDARG;
  1900. HRESULT hr = S_OK;
  1901. LV_COLUMN newCol;
  1902. newCol.mask=0;
  1903. USES_CONVERSION;
  1904. // if the user specified a string, put it in the struct.
  1905. if(str!=MMCLV_NOPTR)
  1906. {
  1907. newCol.mask|=LVCF_TEXT;
  1908. newCol.pszText=OLE2T((LPOLESTR)str);
  1909. }
  1910. // if the user specified a format, put it in the struct.
  1911. if(nFormat!=MMCLV_NOPARAM)
  1912. {
  1913. newCol.mask|=LVCF_FMT;
  1914. newCol.fmt=nFormat;
  1915. }
  1916. // if the user specified a width, put it in the struct.
  1917. if(width!=MMCLV_NOPARAM)
  1918. {
  1919. newCol.mask|=LVCF_WIDTH;
  1920. // if the user requested auto-width, calculate the width.
  1921. // else just store the passed width.
  1922. if(width==MMCLV_AUTO)
  1923. {
  1924. // if the user did pass a string, calculate the width based off the string.
  1925. // else the width is 0.
  1926. if(str!=MMCLV_NOPTR)
  1927. {
  1928. CSize sz(0,0);
  1929. CClientDC dc( m_pListView );
  1930. dc.SelectObject( m_pListView->GetFont() );
  1931. sz=dc.GetTextExtent(OLE2T((LPOLESTR)str),_tcslen(OLE2T((LPOLESTR)str)));
  1932. newCol.cx=sz.cx+15;
  1933. }
  1934. else
  1935. {
  1936. newCol.cx=0;
  1937. }
  1938. }
  1939. else
  1940. {
  1941. newCol.cx=width;
  1942. }
  1943. // Get the lParam to see if this is a hidden column.
  1944. HDITEM hdItem;
  1945. ::ZeroMemory(&hdItem, sizeof(hdItem));
  1946. hdItem.mask = HDI_LPARAM;
  1947. ASSERT(GetHeaderCtrl());
  1948. BOOL bRet = GetHeaderCtrl()->GetItem(nCol, &hdItem);
  1949. ASSERT(bRet);
  1950. CHiddenColumnInfo hciOld (hdItem.lParam);
  1951. CHiddenColumnInfo hci (0);
  1952. ::ZeroMemory(&hdItem, sizeof(hdItem));
  1953. hdItem.mask = HDI_LPARAM;
  1954. // If the column is to be hidden then
  1955. // remember the (Old width) and (HIDDEN_FLAG).
  1956. if (HIDE_COLUMN == newCol.cx)
  1957. {
  1958. hci.cx = hciOld.cx;
  1959. hci.fHidden = true;
  1960. }
  1961. // If the column was hidden then
  1962. // remember the (New width supplied) and (HIDDEN_FLAG).
  1963. if (hciOld.fHidden)
  1964. {
  1965. hci.cx = newCol.cx;
  1966. hci.fHidden = true;
  1967. }
  1968. hdItem.lParam = hci.lParam;
  1969. // We do not care if this call fails
  1970. GetHeaderCtrl()->SetItem(nCol, &hdItem);
  1971. // Common control does not know anything about hidden
  1972. // columns, so if the column is hidden clear the
  1973. // width mask.
  1974. if (hci.fHidden)
  1975. {
  1976. newCol.mask = newCol.mask & (~LVCF_WIDTH);
  1977. }
  1978. }
  1979. if (!GetListCtrl().SetColumn (nCol, &newCol))
  1980. hr = E_FAIL;
  1981. return hr;
  1982. }
  1983. /*+-------------------------------------------------------------------------*
  1984. *
  1985. * CCCListViewCtrl::GetColumn
  1986. *
  1987. * PURPOSE: Returns information about the nCol'th column
  1988. *
  1989. * PARAMETERS:
  1990. * long nCol : the column index
  1991. * LPOLESTR* str : if non-NULL, points to column name on exit
  1992. * LPLONG nFormat : [out] the column format
  1993. * int * width: [out] the width of the column
  1994. *
  1995. * RETURNS:
  1996. * HRESULT
  1997. *
  1998. *+-------------------------------------------------------------------------*/
  1999. HRESULT
  2000. CCCListViewCtrl::GetColumn(long nCol, LPOLESTR* str, LPLONG nFormat, int FAR *width)
  2001. {
  2002. DECLARE_SC(sc, TEXT("CCCListViewCtrl::GetColumn"));
  2003. #ifdef DBG
  2004. if((nCol+1)>m_colCount)
  2005. return E_INVALIDARG;
  2006. #endif
  2007. LV_COLUMN col;
  2008. UINT cBufferSize = 25; // grows as needed. The size here is actually half the initially allocated size
  2009. CAutoArrayPtr<TCHAR> buffer; // we use CAutoArrayPtr because the destructor calls delete[]
  2010. // Set up the mask to select the values we are interested in.
  2011. UINT mask = (nFormat!=MMCLV_NOPTR?LVCF_FMT:0)|(width!=MMCLV_NOPTR?LVCF_WIDTH:0);
  2012. do
  2013. {
  2014. // If the user requested a string, reflect this in the struct.
  2015. if(str!=NULL)
  2016. {
  2017. buffer.Delete(); // get rid of the old buffer, if any
  2018. cBufferSize *= 2; // twice the previous size.
  2019. buffer.Attach(new TCHAR[cBufferSize]);
  2020. if(buffer==NULL)
  2021. return(sc = E_OUTOFMEMORY).ToHr();
  2022. mask|=LVCF_TEXT;
  2023. col.cchTextMax=cBufferSize;
  2024. col.pszText=buffer;
  2025. }
  2026. col.mask = mask;
  2027. sc = GetListCtrl().GetColumn (nCol, &col) ? S_OK : E_FAIL;
  2028. if(sc)
  2029. return sc.ToHr();
  2030. } while(str!=NULL && (cBufferSize == _tcslen(buffer) + 1) ); //loop if the string filled up the buffer.
  2031. // This is conservative - even if the buffer was just big enough, we loop again.
  2032. // Success! fill in the requested args and return.
  2033. USES_CONVERSION;
  2034. if(str!=MMCLV_NOPTR)
  2035. *str = ::CoTaskDupString(T2OLE(buffer));
  2036. if(nFormat!=MMCLV_NOPTR)
  2037. *nFormat=col.fmt;
  2038. if(width!=MMCLV_NOPTR)
  2039. *width=col.cx;
  2040. return sc.ToHr();
  2041. }
  2042. HRESULT CCCListViewCtrl::SetItem(int nItem,
  2043. CResultItem* pri,
  2044. long nCol,
  2045. LPOLESTR str,
  2046. long nImage,
  2047. LPARAM lParam,
  2048. long nState,
  2049. COMPONENTID ownerID)
  2050. {
  2051. DECLARE_SC (sc, _T("CCCListViewCtrl::SetItem"));
  2052. if (IsVirtual())
  2053. return (sc = E_UNEXPECTED).ToHr();
  2054. ASSERT(pri != NULL || nItem >= 0);
  2055. // if this is a debug build, perform validity checks on the args. else leave it to the user.
  2056. if (nCol<0 || nCol >= m_colCount || (str != MMCLV_NOPTR && str != MMC_TEXTCALLBACK))
  2057. return (sc = E_INVALIDARG).ToHr();
  2058. if (pri != NULL)
  2059. {
  2060. nItem = ResultItemToIndex(pri);
  2061. if (nItem == -1)
  2062. return (sc = E_INVALIDARG).ToHr();
  2063. }
  2064. LV_ITEM lvi;
  2065. ZeroMemory(&lvi, sizeof(lvi));
  2066. lvi.mask=0;
  2067. lvi.iItem = nItem;
  2068. USES_CONVERSION;
  2069. lvi.mask|=LVIF_TEXT;
  2070. lvi.pszText=LPSTR_TEXTCALLBACK;
  2071. // If the user has specified an icon index, put it in the LV_ITEM struct
  2072. if((nImage!=MMCLV_NOICON)&&(m_resultIM.Lookup(&CImageIndexMapKey((COMPONENTID)ownerID,nImage), lvi.iImage)))
  2073. lvi.mask|=LVIF_IMAGE;
  2074. // If the user requested a state. put it in the LV_ITEM struct.
  2075. if(nState!=MMCLV_NOPARAM)
  2076. {
  2077. lvi.mask|=LVIF_STATE;
  2078. lvi.stateMask=0xFFFFFFFF;
  2079. lvi.state=nState;
  2080. }
  2081. lvi.iSubItem=nCol;
  2082. CListCtrl& lc = GetListCtrl();
  2083. if (!lc.SetItem (&lvi))
  2084. sc = E_FAIL;
  2085. // If the user has specified an lParam or image, and the Set was succesful,
  2086. // put the lParam and the image's back index in the mapping.
  2087. if (!sc.IsError())
  2088. {
  2089. if ((pri == NULL) && ((pri = IndexToResultItem (nItem)) == NULL))
  2090. sc = E_FAIL;
  2091. if (!sc.IsError())
  2092. {
  2093. if (lParam != MMCLV_NOPARAM)
  2094. pri->SetSnapinData (lParam);
  2095. if (nImage != MMCLV_NOICON)
  2096. pri->SetImageIndex (nImage);
  2097. }
  2098. // if ensure focus visible style and focus set, force item into view
  2099. if (m_bEnsureFocusVisible && nState != MMCLV_NOPARAM && (nState & LVIS_FOCUSED))
  2100. lc.EnsureVisible(nItem, FALSE);
  2101. }
  2102. return (sc.ToHr());
  2103. }
  2104. HRESULT CCCListViewCtrl::GetNextItem(COMPONENTID ownerID, long nIndex,
  2105. UINT nState, CResultItem*& priNextItem, long& nIndexNextItem)
  2106. {
  2107. DECLARE_SC (sc, _T("CCCListViewCtrl::GetNextItem"));
  2108. CListCtrl& lc = GetListCtrl();
  2109. priNextItem = 0;
  2110. nIndexNextItem = -1;
  2111. while (1)
  2112. {
  2113. nIndex = lc.GetNextItem (nIndex, nState);
  2114. if (nIndex == -1)
  2115. break;
  2116. if (IsVirtual())
  2117. {
  2118. nIndexNextItem = nIndex;
  2119. break;
  2120. }
  2121. CResultItem* pri = IndexToResultItem (nIndex);
  2122. if ((pri != NULL) && ((pri->GetOwnerID() == ownerID) || (pri->IsScopeItem())))
  2123. {
  2124. priNextItem = pri;
  2125. nIndexNextItem = nIndex;
  2126. break;
  2127. }
  2128. }
  2129. return (sc = (nIndexNextItem != -1) ? S_OK : S_FALSE).ToHr();
  2130. }
  2131. HRESULT CCCListViewCtrl::GetItem(
  2132. int nItem,
  2133. CResultItem*& pri,
  2134. long nCol,
  2135. LPOLESTR* str,
  2136. int* pnImage,
  2137. LPARAM* pLParam,
  2138. UINT* pnState,
  2139. BOOL* pbScopeItem)
  2140. {
  2141. USES_CONVERSION;
  2142. if ((nCol < 0) || (nCol >= m_colCount))
  2143. return E_INVALIDARG;
  2144. HRESULT hr = S_OK;
  2145. CListCtrl& lc = GetListCtrl();
  2146. if (IsVirtual())
  2147. {
  2148. //Virtual list can only be queried for state
  2149. if ((pri != NULL) || (nItem < 0) || (nItem >= m_itemCount) ||
  2150. (str != MMCLV_NOPTR) || (pnImage != MMCLV_NOPTR) || (pLParam != MMCLV_NOPTR))
  2151. {
  2152. ASSERT(FALSE);
  2153. hr = E_INVALIDARG;
  2154. }
  2155. else if (pnState != MMCLV_NOPTR)
  2156. {
  2157. *pnState = lc.GetItemState (nItem, 0xFFFFFFFF);
  2158. // for virtual list, it's never a scope item
  2159. if (pbScopeItem != NULL)
  2160. *pbScopeItem = FALSE;
  2161. }
  2162. }
  2163. else
  2164. {
  2165. if (pri != 0)
  2166. nItem = ResultItemToIndex(pri);
  2167. if (nItem < 0 || nItem >= m_itemCount)
  2168. hr = E_INVALIDARG;
  2169. else
  2170. {
  2171. pri = IndexToResultItem (nItem);
  2172. if ( pri == NULL )
  2173. return E_UNEXPECTED;
  2174. // if the text was requested, get that seperatly so that we can use GETITEMTEXT to
  2175. // dynamically size the buffer.
  2176. if (str != MMCLV_NOPTR)
  2177. {
  2178. CString strText = lc.GetItemText (nItem, nCol);
  2179. *str = ::CoTaskDupString (T2COLE (strText));
  2180. }
  2181. // get the state if requested
  2182. if (pnState != MMCLV_NOPTR)
  2183. *pnState = lc.GetItemState (nItem, 0xFFFFFFFF);
  2184. // Nodemgr will unravel pri & get required data (lparam & image index).
  2185. if (pri->IsScopeItem())
  2186. return hr;
  2187. // get the image, pLParam, or scope item, if requested
  2188. if ((pnImage != MMCLV_NOPTR) ||
  2189. (pLParam != MMCLV_NOPTR) ||
  2190. (pbScopeItem != NULL))
  2191. {
  2192. if (pri != NULL)
  2193. {
  2194. if (pnImage != MMCLV_NOPTR)
  2195. *pnImage = pri->GetImageIndex();
  2196. if (pLParam != MMCLV_NOPTR)
  2197. *pLParam = pri->GetSnapinData();
  2198. // set the scope item flag
  2199. if (pbScopeItem != NULL)
  2200. *pbScopeItem = pri->IsScopeItem();
  2201. }
  2202. else
  2203. hr = E_FAIL;
  2204. }
  2205. }
  2206. }
  2207. return hr;
  2208. }
  2209. HRESULT CCCListViewCtrl::GetLParam(long nItem, CResultItem*& pri)
  2210. {
  2211. DECLARE_SC (sc, _T("CCCListViewCtrl::GetLParam"));
  2212. if (IsVirtual())
  2213. return (sc = E_UNEXPECTED).ToHr();
  2214. pri = IndexToResultItem (nItem);
  2215. if (pri == NULL)
  2216. sc = E_FAIL;
  2217. return (sc.ToHr());
  2218. }
  2219. HRESULT CCCListViewCtrl::ModifyItemState(long nItem, CResultItem* pri,
  2220. UINT add, UINT remove)
  2221. {
  2222. ASSERT(((pri != 0) && !IsVirtual()) || (nItem >= 0));
  2223. // Can only set focus and selected states for virtual item
  2224. if (IsVirtual() && ((add | remove) & ~(LVIS_FOCUSED | LVIS_SELECTED)))
  2225. {
  2226. ASSERT(FALSE);
  2227. return E_FAIL;
  2228. }
  2229. HRESULT hr = E_FAIL;
  2230. if (pri != 0 && !IsVirtual())
  2231. nItem = ResultItemToIndex(pri);
  2232. if (nItem >= 0)
  2233. {
  2234. LV_ITEM lvi;
  2235. ZeroMemory(&lvi, sizeof(lvi));
  2236. lvi.iItem = nItem;
  2237. lvi.mask = LVIF_STATE;
  2238. lvi.stateMask = add | remove;
  2239. lvi.state = add;
  2240. hr = (GetListCtrl().SetItemState (nItem, &lvi)) ? S_OK : E_FAIL;
  2241. // if ensure focus visible style and focus set, force item into view
  2242. if (m_bEnsureFocusVisible && (add & LVIS_FOCUSED))
  2243. GetListCtrl().EnsureVisible(nItem, FALSE);
  2244. }
  2245. return hr;
  2246. }
  2247. HRESULT CCCListViewCtrl::SetIcon(long ownerID, HICON hIcon, long nLoc)
  2248. {
  2249. ASSERT (m_smallIL.GetImageCount() == m_largeIL.GetImageCount());
  2250. /*
  2251. * pick the flags out of nLoc
  2252. */
  2253. bool fChangeLargeIcon = nLoc & ILSIF_LEAVE_SMALL_ICON;
  2254. bool fChangeSmallIcon = nLoc & ILSIF_LEAVE_LARGE_ICON;
  2255. nLoc &= ~ILSIF_LEAVE_MASK;
  2256. /*
  2257. * make sure the XOR below will work
  2258. */
  2259. ASSERT ((fChangeLargeIcon == 0) || (fChangeLargeIcon == 1));
  2260. ASSERT ((fChangeSmallIcon == 0) || (fChangeSmallIcon == 1));
  2261. CImageIndexMapKey searchKey((COMPONENTID)ownerID, nLoc);
  2262. int nNdx1;
  2263. int nNdx2;
  2264. HRESULT hr = S_OK;
  2265. BOOL fExists = m_resultIM.Lookup(&searchKey, nNdx1);
  2266. /*
  2267. * are we changing the large or small icon only?
  2268. */
  2269. if (fChangeSmallIcon ^ fChangeLargeIcon)
  2270. {
  2271. /*
  2272. * there must be an icon at nLoc already
  2273. */
  2274. if (!fExists)
  2275. hr = E_INVALIDARG;
  2276. /*
  2277. * changing the large icon?
  2278. */
  2279. else if (fChangeLargeIcon)
  2280. {
  2281. if (m_largeIL.Replace(nNdx1, hIcon) != nNdx1)
  2282. hr = E_FAIL;
  2283. }
  2284. /*
  2285. * otherwise, changing the small icon?
  2286. */
  2287. else
  2288. {
  2289. if (m_smallIL.Replace(nNdx1, hIcon) != nNdx1)
  2290. hr = E_FAIL;
  2291. }
  2292. }
  2293. else if (fExists)
  2294. {
  2295. nNdx2 = m_smallIL.Replace(nNdx1, hIcon);
  2296. if (nNdx2 == -1)
  2297. {
  2298. hr = E_FAIL;
  2299. }
  2300. else
  2301. {
  2302. if(nNdx2 != nNdx1)
  2303. {
  2304. hr = E_UNEXPECTED;
  2305. }
  2306. else
  2307. {
  2308. nNdx2 = m_largeIL.Replace(nNdx1, hIcon);
  2309. if(nNdx2 != nNdx1)
  2310. hr = E_UNEXPECTED;
  2311. }
  2312. }
  2313. }
  2314. else
  2315. {
  2316. // Insert items and store indices in large and small
  2317. nNdx1 = m_smallIL.Add(hIcon);
  2318. if (nNdx1 != -1)
  2319. nNdx2 = m_largeIL.Add(hIcon);
  2320. if (nNdx1 == -1)
  2321. {
  2322. hr = E_FAIL;
  2323. }
  2324. else if (nNdx2 == -1)
  2325. {
  2326. m_smallIL.Remove (nNdx1);
  2327. hr = E_FAIL;
  2328. }
  2329. else if(nNdx1 != nNdx2)
  2330. {
  2331. m_smallIL.Remove (nNdx1);
  2332. m_largeIL.Remove (nNdx2);
  2333. hr = E_UNEXPECTED;
  2334. }
  2335. else
  2336. {
  2337. // Generate a new key and store the values in the maps
  2338. PImageIndexMapKey pKey = new CImageIndexMapKey((COMPONENTID)ownerID, nLoc);
  2339. m_resultIM[pKey] = nNdx1;
  2340. }
  2341. }
  2342. #ifdef DBG
  2343. if (tagListImages.FAny())
  2344. {
  2345. DrawOnDesktop (m_smallIL, 0, 0);
  2346. DrawOnDesktop (m_largeIL, 0, 32);
  2347. }
  2348. #endif
  2349. ASSERT (m_smallIL.GetImageCount() == m_largeIL.GetImageCount());
  2350. return hr;
  2351. }
  2352. /*+-------------------------------------------------------------------------*
  2353. * CCCListViewCtrl::SetImageStrip
  2354. *
  2355. * Adds one or more images to the imagelist. Bitmaps are owned (and
  2356. * released) by the caller.
  2357. *--------------------------------------------------------------------------*/
  2358. HRESULT CCCListViewCtrl::SetImageStrip (
  2359. long ownerID,
  2360. HBITMAP hbmSmall,
  2361. HBITMAP hbmLarge,
  2362. long nStartLoc,
  2363. long cMask)
  2364. {
  2365. DECLARE_SC (sc, _T("CCCListViewCtrl::SetImageStrip"));
  2366. ASSERT (m_smallIL.GetImageCount() == m_largeIL.GetImageCount());
  2367. /*
  2368. * valid start index?
  2369. */
  2370. if (nStartLoc < 0)
  2371. return ((sc = E_INVALIDARG).ToHr());
  2372. /*
  2373. * valid bitmaps?
  2374. */
  2375. sc = ScCheckPointers (hbmSmall, hbmLarge);
  2376. if (sc)
  2377. return (sc.ToHr());
  2378. BITMAP bmSmall;
  2379. if (!GetObject (hbmSmall, sizeof(BITMAP), &bmSmall))
  2380. return (sc.FromLastError().ToHr());
  2381. BITMAP bmLarge;
  2382. if (!GetObject (hbmLarge, sizeof(BITMAP), &bmLarge))
  2383. return (sc.FromLastError().ToHr());
  2384. /*
  2385. * are the small and large bitmaps of the integral dimensions,
  2386. * and do they have the same number of images?
  2387. */
  2388. if ( (bmSmall.bmHeight != 16) || (bmLarge.bmHeight != 32) ||
  2389. (bmSmall.bmWidth % 16) || (bmLarge.bmWidth % 32) ||
  2390. ((bmSmall.bmWidth / 16) != (bmLarge.bmWidth / 32)))
  2391. {
  2392. return ((sc = E_INVALIDARG).ToHr());
  2393. }
  2394. const int cEntries = bmSmall.bmWidth / 16;
  2395. /*
  2396. * make copies of the input bitmaps because CImageList::Add (which calls
  2397. * ImageList_AddMasked) will screw up the background color
  2398. */
  2399. CBitmap bmpSmall, bmpLarge;
  2400. bmpSmall.Attach (CopyBitmap (hbmSmall));
  2401. bmpLarge.Attach (CopyBitmap (hbmLarge));
  2402. if ((bmpSmall.GetSafeHandle() == NULL) || (bmpLarge.GetSafeHandle() == NULL))
  2403. return (sc.FromLastError().ToHr());
  2404. /*
  2405. * add the small image
  2406. */
  2407. const int nFirstNewIndexSmall = m_smallIL.Add (&bmpSmall, cMask);
  2408. if (nFirstNewIndexSmall == -1)
  2409. return (sc.FromLastError().ToHr());
  2410. /*
  2411. * add the large image
  2412. */
  2413. const int nFirstNewIndexLarge = m_largeIL.Add (&bmpLarge, cMask);
  2414. if (nFirstNewIndexLarge == -1)
  2415. {
  2416. /*
  2417. * Images can be added many at a time, but only removed one at
  2418. * a time. Remove each entry we added.
  2419. */
  2420. for (int i = 0; i < cEntries; i++)
  2421. m_smallIL.Remove (nFirstNewIndexSmall);
  2422. ASSERT (m_smallIL.GetImageCount() == m_largeIL.GetImageCount());
  2423. return (sc.FromLastError().ToHr());
  2424. }
  2425. /*
  2426. * if the starting indices of the large and small images aren't
  2427. * the same, we screwed
  2428. */
  2429. if (nFirstNewIndexSmall != nFirstNewIndexLarge)
  2430. {
  2431. /*
  2432. * Images can be added many at a time, but only removed one at
  2433. * a time. Remove each entry we added.
  2434. */
  2435. for (int i = 0; i < cEntries; i++)
  2436. {
  2437. m_smallIL.Remove (nFirstNewIndexSmall);
  2438. m_largeIL.Remove (nFirstNewIndexLarge);
  2439. }
  2440. ASSERT (m_smallIL.GetImageCount() == m_largeIL.GetImageCount());
  2441. return ((sc = E_UNEXPECTED).ToHr());
  2442. }
  2443. // Keep the map updated for each newly inserted image.
  2444. for(int i=0; i < cEntries; i++)
  2445. {
  2446. CImageIndexMapKey searchKey((COMPONENTID)ownerID, nStartLoc+i);
  2447. // if the item exists in the map, replace the value, else create a new
  2448. // key and set the value.
  2449. int nIndex = nFirstNewIndexSmall;
  2450. // use copy of nFirstNewIndexSmall as Lookup modifies nIndex.
  2451. if(m_resultIM.Lookup(&searchKey, nIndex))
  2452. m_resultIM[&searchKey] = nFirstNewIndexSmall+i;
  2453. else
  2454. m_resultIM[new CImageIndexMapKey((COMPONENTID)ownerID, nStartLoc+i)] = nFirstNewIndexSmall+i;
  2455. }
  2456. #ifdef DBG
  2457. if (tagListImages.FAny())
  2458. {
  2459. DrawOnDesktop (m_smallIL, 0, 0);
  2460. DrawOnDesktop (m_largeIL, 0, 32);
  2461. }
  2462. #endif
  2463. ASSERT (m_smallIL.GetImageCount() == m_largeIL.GetImageCount());
  2464. return (sc.ToHr());
  2465. }
  2466. HRESULT CCCListViewCtrl::MapImage(long ownerID, long nLoc, int far *pResult)
  2467. {
  2468. CImageIndexMapKey searchKey((COMPONENTID)ownerID, nLoc);
  2469. HRESULT hr = S_OK;
  2470. ASSERT(pResult);
  2471. if(!(m_resultIM.Lookup(&searchKey, *((int *)pResult))))
  2472. hr = E_FAIL;
  2473. return hr;
  2474. }
  2475. HRESULT CCCListViewCtrl::Reset()
  2476. {
  2477. DECLARE_SC (sc, _T("CCCListViewCtrl::Reset"));
  2478. // Note: we must call this->DeleteAllItems(TVOWNED_MAGICWORD) & not
  2479. // GetListCtrl().DeleteAllItems() to ensure that all internal data
  2480. // is cleaned up.
  2481. DeleteAllItems(TVOWNED_MAGICWORD);
  2482. ASSERT(GetListCtrl().GetItemCount() == 0);
  2483. ASSERT(m_itemCount == 0);
  2484. ASSERT(m_nScopeItems == 0);
  2485. m_resultIM.RemoveAll();
  2486. m_smallIL.DeleteImageList();
  2487. m_largeIL.DeleteImageList();
  2488. sc = ScSetImageLists();
  2489. if (sc)
  2490. return (sc.ToHr());
  2491. // Delete all columns
  2492. while (SUCCEEDED (DeleteColumn(0))) {};
  2493. if (m_pListView)
  2494. sc = m_pListView->ScResetColumnStatusData();
  2495. if (sc)
  2496. sc.TraceAndClear();
  2497. // reset lexical sorting until Sort is called again
  2498. m_sortParams.bLexicalSort = FALSE;
  2499. // release the snap-in's compare interfaces
  2500. m_sortParams.spResultCompare = NULL;
  2501. m_sortParams.spResultCompareEx = NULL;
  2502. return (sc.ToHr());
  2503. }
  2504. //+-------------------------------------------------------------------
  2505. //
  2506. // Member: SortCompareFunc
  2507. //
  2508. // Synopsis: Compare two items, called by list control sort.
  2509. //
  2510. // Arguments: [lParam1] - Item1's lparam.
  2511. // [lParam2] - Item2's lparam.
  2512. // [pSortParams_] - ptr to SortParams.
  2513. //
  2514. // Note: If snapin wants lexical sort do default-compare.
  2515. // Else if snapin has IResultDataCompare[Ex] then call it
  2516. // Else do default-compare.
  2517. //
  2518. // Returns: -1 : item1 < item2
  2519. // 0 : item1 == item2
  2520. // +1 : item1 > item2
  2521. //
  2522. //--------------------------------------------------------------------
  2523. int CALLBACK CCCListViewCtrl::SortCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM pSortParams_)
  2524. {
  2525. SortParams* pSortParams = reinterpret_cast<SortParams*>(pSortParams_);
  2526. ASSERT (pSortParams != NULL);
  2527. CCCListViewCtrl* pListView = reinterpret_cast<CCCListViewCtrl*>(pSortParams->lpListView);
  2528. ASSERT (pListView != NULL);
  2529. CResultItem* pri1 = CResultItem::FromHandle (lParam1);
  2530. CResultItem* pri2 = CResultItem::FromHandle (lParam2);
  2531. if (pri1 == NULL || pri2 == NULL)
  2532. {
  2533. ASSERT(FALSE);
  2534. return 0;
  2535. }
  2536. BOOL bScope1 = pri1->IsScopeItem();
  2537. BOOL bScope2 = pri2->IsScopeItem();
  2538. int iResult;
  2539. // if snap-in provides extended compare method
  2540. if (pSortParams->spResultCompareEx != NULL)
  2541. {
  2542. ASSERT(pSortParams->lpNodeCallback);
  2543. if (NULL == pSortParams->lpNodeCallback)
  2544. return 0; // Error
  2545. COMPONENTID ItemID;
  2546. BOOL bOwned1 = !bScope1 ||
  2547. ((pSortParams->lpNodeCallback->GetNodeOwnerID(pri1->GetScopeNode(), &ItemID) == S_OK) &&
  2548. (ItemID == pSortParams->OwnerID));
  2549. BOOL bOwned2 = !bScope2 ||
  2550. ((pSortParams->lpNodeCallback->GetNodeOwnerID(pri2->GetScopeNode(), &ItemID) == S_OK) &&
  2551. (ItemID == pSortParams->OwnerID));
  2552. // let snap-in order all items that it owns (scope and result)
  2553. // put rest of items items after owned items
  2554. if (bOwned1 && bOwned2)
  2555. iResult = SnapinCompareEx(pSortParams, pri1, pri2);
  2556. else if (bOwned1 || bOwned2)
  2557. iResult = bOwned1 ? -1 : 1;
  2558. else
  2559. // DefaultCompare flips results depending on ascending or descending.
  2560. return DefaultCompare(lParam1, lParam2, pSortParams_);
  2561. }
  2562. // do default sorting
  2563. else
  2564. {
  2565. // pass result items to original compare method if provided, else to default sort
  2566. if (!bScope1 && !bScope2)
  2567. {
  2568. if (pSortParams->spResultCompare != NULL)
  2569. iResult = SnapinCompare(pSortParams, pri1, pri2);
  2570. else
  2571. // DefaultCompare flips results depending on ascending or descending.
  2572. return DefaultCompare(lParam1, lParam2, pSortParams_);
  2573. }
  2574. // do not order scope items, just put them ahead of result items
  2575. else
  2576. {
  2577. iResult = (bScope1 && bScope2) ? 0 : (bScope1 ? -1 : 1);
  2578. }
  2579. }
  2580. // flip order for descending sort
  2581. return pSortParams->bAscending ? iResult : -iResult;
  2582. }
  2583. //+-------------------------------------------------------------------
  2584. //
  2585. // Member: DefaultCompare
  2586. //
  2587. // Synopsis: Compare two items, called by list control sort.
  2588. // This is used if snapin wants default compare or
  2589. // if it does not implement IResultDataCompare or
  2590. // IResultDataCompareEx interfaces
  2591. //
  2592. // Arguments: [lParam1] - Item1's lparam.
  2593. // [lParam2] - Item2's lparam.
  2594. // [pSortParams] - ptr to SortParams.
  2595. //
  2596. // Note: If one is scope item and other is result item
  2597. // place scope item before result item.
  2598. // Else get the text for both items and do string compare.
  2599. //
  2600. // Returns: -1 : item1 < item2
  2601. // 0 : item1 == item2
  2602. // +1 : item1 > item2
  2603. //
  2604. //--------------------------------------------------------------------
  2605. int CALLBACK CCCListViewCtrl::DefaultCompare(LPARAM lParam1, LPARAM lParam2, LPARAM pSortParams_)
  2606. {
  2607. SortParams* pSortParams = reinterpret_cast<SortParams*>(pSortParams_);
  2608. ASSERT(NULL != pSortParams);
  2609. if (NULL == pSortParams)
  2610. return 0;
  2611. CResultItem* pri1 = CResultItem::FromHandle (lParam1);
  2612. CResultItem* pri2 = CResultItem::FromHandle (lParam2);
  2613. ASSERT( (NULL != pri1) && (NULL != pri2));
  2614. if ( (NULL == pri1) || (NULL == pri2) )
  2615. return 0;
  2616. bool bScope1 = pri1->IsScopeItem();
  2617. bool bScope2 = pri2->IsScopeItem();
  2618. // If one of the item is scope pane item
  2619. // scope item goes before result item.
  2620. if (bScope1 != bScope2)
  2621. {
  2622. int iResult = bScope1 ? -1 : 1;
  2623. return pSortParams->bAscending ? iResult : -iResult;
  2624. }
  2625. LPNODECALLBACK lpNodeCallback = pSortParams->lpNodeCallback;
  2626. ASSERT(lpNodeCallback);
  2627. if (NULL == lpNodeCallback)
  2628. return 0;
  2629. HRESULT hr = E_FAIL;
  2630. CString strText1;
  2631. CString strText2;
  2632. if (bScope1)
  2633. {
  2634. // Both scope items, get the text for each item.
  2635. HNODE hNode1 = pri1->GetScopeNode();
  2636. HNODE hNode2 = pri2->GetScopeNode();
  2637. USES_CONVERSION;
  2638. tstring strName;
  2639. // GetDisplayName uses a static array to return name so no need to free it.
  2640. hr = lpNodeCallback->GetDisplayName(hNode1, strName);
  2641. ASSERT(SUCCEEDED(hr));
  2642. if (SUCCEEDED(hr))
  2643. strText1 = strName.data();
  2644. hr = lpNodeCallback->GetDisplayName(hNode2, strName);
  2645. ASSERT(SUCCEEDED(hr));
  2646. if (SUCCEEDED(hr))
  2647. strText2 = strName.data();
  2648. }
  2649. else // both items are result items.
  2650. {
  2651. ASSERT(!bScope1 && ! bScope2);
  2652. CCCListViewCtrl* pListView = reinterpret_cast<CCCListViewCtrl*>(pSortParams->lpListView);
  2653. ASSERT (pListView != NULL);
  2654. ASSERT(pListView->IsVirtual() == FALSE); // Virtual list sort should not come here.
  2655. LV_ITEMW lvi;
  2656. ZeroMemory(&lvi, sizeof(LV_ITEMW));
  2657. lvi.mask = LVIF_TEXT;
  2658. lvi.iSubItem = pSortParams->nCol;
  2659. lvi.cchTextMax = MAX_PATH;
  2660. WCHAR szTemp[MAX_PATH+1];
  2661. lvi.pszText = szTemp;
  2662. ASSERT(NULL != pSortParams->hSelectedNode);
  2663. if (NULL != pSortParams->hSelectedNode)
  2664. {
  2665. lvi.lParam = lParam1;
  2666. hr = lpNodeCallback->GetDispInfo(pSortParams->hSelectedNode, &lvi);
  2667. ASSERT(SUCCEEDED(hr));
  2668. if (SUCCEEDED(hr))
  2669. strText1 = lvi.pszText;
  2670. lvi.lParam = lParam2;
  2671. hr = lpNodeCallback->GetDispInfo(pSortParams->hSelectedNode, &lvi);
  2672. ASSERT(SUCCEEDED(hr));
  2673. if (SUCCEEDED(hr))
  2674. strText2 = lvi.pszText;
  2675. }
  2676. }
  2677. if (strText1.IsEmpty() && strText2.IsEmpty())
  2678. return (0);
  2679. int rc = 0;
  2680. /*
  2681. * Bug 9595: Do locale-sensitive, case-insensitive comparison
  2682. */
  2683. switch (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, strText1, -1, strText2, -1))
  2684. {
  2685. case CSTR_LESS_THAN:
  2686. rc = -1;
  2687. break;
  2688. case CSTR_EQUAL:
  2689. rc = 0;
  2690. break;
  2691. case CSTR_GREATER_THAN:
  2692. rc = 1;
  2693. break;
  2694. default:
  2695. /*
  2696. * if an error occurred, fall back to locale-insensitive,
  2697. * case-insensitive comparison
  2698. */
  2699. rc = _tcsicmp (strText1, strText2);
  2700. break;
  2701. }
  2702. return pSortParams->bAscending ? rc: -rc;
  2703. }
  2704. int CCCListViewCtrl::SnapinCompare(SortParams* pSortParams, CResultItem* pri1, CResultItem* pri2)
  2705. {
  2706. ASSERT(pSortParams->spResultCompare != NULL);
  2707. // Set nResult to the current column
  2708. int nResult = pSortParams->nCol;
  2709. HRESULT hr = pSortParams->spResultCompare->Compare(pSortParams->lpUserParam, pri1->GetSnapinData(), pri2->GetSnapinData(), &nResult);
  2710. return SUCCEEDED(hr) ? nResult : 0;
  2711. }
  2712. int CCCListViewCtrl::SnapinCompareEx(SortParams* pSortParams, CResultItem* pri1, CResultItem* pri2)
  2713. {
  2714. ASSERT(pSortParams->spResultCompareEx != NULL);
  2715. RDITEMHDR rdch1;
  2716. RDITEMHDR rdch2;
  2717. if (pri1->IsScopeItem())
  2718. {
  2719. rdch1.dwFlags = RDCI_ScopeItem;
  2720. pSortParams->lpNodeCallback->GetNodeCookie(pri1->GetScopeNode(), &rdch1.cookie);
  2721. }
  2722. else
  2723. {
  2724. rdch1.dwFlags = 0;
  2725. rdch1.cookie = pri1->GetSnapinData();
  2726. }
  2727. if (pri2->IsScopeItem())
  2728. {
  2729. rdch2.dwFlags = RDCI_ScopeItem;
  2730. pSortParams->lpNodeCallback->GetNodeCookie(pri2->GetScopeNode(), &rdch2.cookie);
  2731. }
  2732. else
  2733. {
  2734. rdch2.dwFlags = 0;
  2735. rdch2.cookie = pri2->GetSnapinData();
  2736. }
  2737. rdch1.lpReserved = 0;
  2738. rdch2.lpReserved = 0;
  2739. RDCOMPARE rdc;
  2740. rdc.cbSize = sizeof(rdc);
  2741. rdc.dwFlags = 0;
  2742. rdc.nColumn = pSortParams->nCol;
  2743. rdc.lUserParam = pSortParams->lpUserParam;
  2744. rdc.prdch1 = &rdch1;
  2745. rdc.prdch2 = &rdch2;
  2746. int nResult = 0;
  2747. HRESULT hr = pSortParams->spResultCompareEx->Compare(&rdc, &nResult);
  2748. return SUCCEEDED(hr) ? nResult : 0;
  2749. }
  2750. HRESULT CCCListViewCtrl::Arrange(long style)
  2751. {
  2752. return ((GetListCtrl().Arrange (style)) ? S_OK : S_FALSE);
  2753. }
  2754. HRESULT CCCListViewCtrl::Repaint(BOOL bErase)
  2755. {
  2756. m_pListView->Invalidate(bErase);
  2757. return S_OK;
  2758. }
  2759. HRESULT CCCListViewCtrl::SetItemCount(int iItemCount, DWORD dwOptions)
  2760. {
  2761. DECLARE_SC(sc, TEXT("CCCListViewCtrl::SetItemCount"));
  2762. ASSERT(iItemCount >= 0);
  2763. ASSERT((dwOptions & ~(LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL)) == 0);
  2764. // Ask the CAMCListViewCtrl to setup headers & set the flag.
  2765. sc = ScCheckPointers(m_pListView, E_UNEXPECTED);
  2766. if (! sc.IsError())
  2767. sc = m_pListView->ScRestoreColumnsFromPersistedData();
  2768. if (sc)
  2769. sc.TraceAndClear();
  2770. int iTop = ListView_GetTopIndex(GetListCtrl());
  2771. if (ListView_SetItemCountEx (GetListCtrl(), iItemCount, dwOptions))
  2772. {
  2773. // if virtual list, update the item count
  2774. // if not virtual, SetItemCount just reserves space for new items
  2775. if (IsVirtual())
  2776. m_itemCount = iItemCount;
  2777. }
  2778. else
  2779. {
  2780. ASSERT(FALSE);
  2781. sc = E_FAIL;
  2782. }
  2783. iTop = ListView_GetTopIndex(GetListCtrl());
  2784. if (sc)
  2785. return sc.ToHr();
  2786. // we cannot track any items any more - broadcast the message to observers
  2787. sc = ScFireEvent(CListViewObserver::ScOnListViewIndexesReset);
  2788. if (sc)
  2789. return sc.ToHr();
  2790. return sc.ToHr();
  2791. }
  2792. HRESULT CCCListViewCtrl::SetChangeTimeOut(ULONG lTimeout)
  2793. {
  2794. BOOL bStat = FALSE;
  2795. if (GetHeaderCtrl())
  2796. bStat = ::SendMessage(GetHeaderCtrl()->m_hWnd, HDM_SETFILTERCHANGETIMEOUT, 0, (LPARAM)lTimeout);
  2797. return (bStat ? S_OK : E_FAIL);
  2798. }
  2799. HRESULT CCCListViewCtrl::SetColumnFilter(int nCol, DWORD dwType, MMC_FILTERDATA* pFilterData)
  2800. {
  2801. HRESULT hr = S_OK;
  2802. USES_CONVERSION;
  2803. HD_ITEM item;
  2804. do // not a loop
  2805. {
  2806. if (GetHeaderCtrl() == NULL)
  2807. {
  2808. hr = E_FAIL;
  2809. break;
  2810. }
  2811. DWORD dwTypeOnly = dwType & ~MMC_FILTER_NOVALUE;
  2812. BOOL bHasValue = !(dwType & MMC_FILTER_NOVALUE);
  2813. // Validate filter type
  2814. ASSERT(dwTypeOnly == MMC_INT_FILTER || dwTypeOnly == MMC_STRING_FILTER);
  2815. if (!(dwTypeOnly == MMC_INT_FILTER || dwTypeOnly == MMC_STRING_FILTER))
  2816. {
  2817. hr = E_INVALIDARG;
  2818. break;
  2819. }
  2820. // Check for non-null filterdata and pszText
  2821. if ( ((dwType == MMC_STRING_FILTER || bHasValue) && pFilterData == NULL) ||
  2822. (dwType == MMC_STRING_FILTER && bHasValue && pFilterData->pszText == NULL) )
  2823. {
  2824. ASSERT(FALSE);
  2825. hr = E_POINTER;
  2826. break;
  2827. }
  2828. ZeroMemory(&item, sizeof(item));
  2829. item.mask = HDI_FILTER;
  2830. item.type = dwType;
  2831. HD_TEXTFILTER textFilter;
  2832. switch (dwTypeOnly)
  2833. {
  2834. case MMC_INT_FILTER:
  2835. item.pvFilter = &pFilterData->lValue;
  2836. break;
  2837. case MMC_STRING_FILTER:
  2838. {
  2839. item.pvFilter = &textFilter;
  2840. textFilter.cchTextMax = pFilterData->cchTextMax;
  2841. if (bHasValue)
  2842. textFilter.pszText = OLE2T(pFilterData->pszText);
  2843. break;
  2844. }
  2845. default:
  2846. ASSERT(FALSE);
  2847. }
  2848. if (!GetHeaderCtrl()->SetItem(nCol, &item))
  2849. {
  2850. ASSERT(FALSE);
  2851. hr = E_FAIL;
  2852. }
  2853. }
  2854. while(0);
  2855. return hr;
  2856. }
  2857. HRESULT CCCListViewCtrl::GetColumnFilter(int nCol, DWORD* pdwType, MMC_FILTERDATA* pFilterData)
  2858. {
  2859. HRESULT hr = S_OK;
  2860. USES_CONVERSION;
  2861. HD_ITEM item;
  2862. do // not a loop
  2863. {
  2864. if (GetHeaderCtrl() == NULL)
  2865. {
  2866. hr = E_FAIL;
  2867. break;
  2868. }
  2869. ASSERT(pdwType != NULL);
  2870. if (pdwType == NULL)
  2871. {
  2872. hr = E_POINTER;
  2873. break;
  2874. }
  2875. ASSERT(*pdwType == MMC_INT_FILTER || *pdwType == MMC_STRING_FILTER);
  2876. if (!(*pdwType == MMC_INT_FILTER || *pdwType == MMC_STRING_FILTER))
  2877. {
  2878. hr = E_INVALIDARG;
  2879. break;
  2880. }
  2881. ASSERT(!(*pdwType == MMC_STRING_FILTER && pFilterData != NULL && pFilterData->pszText == NULL));
  2882. if ((*pdwType == MMC_STRING_FILTER && pFilterData != NULL && pFilterData->pszText == NULL))
  2883. {
  2884. hr = E_INVALIDARG;
  2885. break;
  2886. }
  2887. ZeroMemory(&item, sizeof(item));
  2888. item.mask = HDI_FILTER;
  2889. item.type = *pdwType;
  2890. HD_TEXTFILTER textFilter;
  2891. if (pFilterData != 0)
  2892. {
  2893. switch (*pdwType)
  2894. {
  2895. case MMC_INT_FILTER:
  2896. item.pvFilter = &pFilterData->lValue;
  2897. break;
  2898. case MMC_STRING_FILTER:
  2899. {
  2900. item.pvFilter = &textFilter;
  2901. textFilter.pszText = (LPTSTR)alloca((pFilterData->cchTextMax + 1) * sizeof(TCHAR));
  2902. textFilter.pszText[0] = 0;
  2903. textFilter.cchTextMax = pFilterData->cchTextMax;
  2904. break;
  2905. }
  2906. default:
  2907. ASSERT(FALSE);
  2908. }
  2909. }
  2910. BOOL bStat = GetHeaderCtrl()->GetItem(nCol, &item);
  2911. if (!bStat)
  2912. hr = E_FAIL;
  2913. // NOTE: GetHeaderCtrl()->GetItem() fails when a string filter is empty
  2914. // Until this is fixed, assume that the error is caused by this
  2915. // and fake an empty string result
  2916. if (hr == E_FAIL && item.type == MMC_STRING_FILTER)
  2917. {
  2918. item.type |= HDFT_HASNOVALUE;
  2919. hr = S_OK;
  2920. }
  2921. // if requested string filter value, convert to caller's buffer
  2922. if (hr == S_OK && item.type == MMC_STRING_FILTER && pFilterData != NULL)
  2923. {
  2924. ocscpy(pFilterData->pszText, T2OLE(textFilter.pszText));
  2925. }
  2926. *pdwType = item.type;
  2927. }
  2928. while(0);
  2929. return hr;
  2930. }
  2931. //+-------------------------------------------------------------------
  2932. //
  2933. // Member: SetColumnSortIcon
  2934. //
  2935. // Synopsis: Set sort arrow if needed.
  2936. //
  2937. // Arguments: [nNewCol] - The column for which arrow should be set.
  2938. // [nOldCol] - The previous column, remove sort arrow.
  2939. // [bAscending] - Ascending/Descending.
  2940. // [bSetSortIcon] - If arrow is needed or not.
  2941. //
  2942. // Returns: S_OK.
  2943. //
  2944. // History: 04-01-1998 AnandhaG Created
  2945. //
  2946. //--------------------------------------------------------------------
  2947. HRESULT CCCListViewCtrl::SetColumnSortIcon(int nNewCol, int nOldCol,
  2948. BOOL bAscending, BOOL bSetSortIcon)
  2949. {
  2950. DECLARE_SC(sc, TEXT("CCCListViewCtrl::SetColumnSortIcon"));
  2951. LVCOLUMN lvcol, lvOriginalCol;
  2952. ZeroMemory(&lvcol, sizeof(lvcol));
  2953. lvcol.mask = LVCF_FMT | LVCF_IMAGE;
  2954. ZeroMemory(&lvOriginalCol, sizeof(lvOriginalCol));
  2955. lvOriginalCol.mask = LVCF_FMT;
  2956. // update the old column
  2957. if ( nOldCol >= 0 )
  2958. {
  2959. // retrieve old frmt settings
  2960. if ( !GetListCtrl().GetColumn(nOldCol, &lvOriginalCol) )
  2961. return (sc = E_FAIL).ToHr();
  2962. // make the new format settings
  2963. // transfer old values such as LVCFMT_CENTER, which we do not want to change
  2964. // see windows bugs (ntbug09) #153029 10/09/00
  2965. lvcol.fmt = lvOriginalCol.fmt & ~(LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT);
  2966. // Reset the previous column's sort icon with blank icon.
  2967. lvcol.iImage = -1;
  2968. if ( !GetListCtrl().SetColumn(nOldCol, &lvcol) )
  2969. return (sc = E_FAIL).ToHr();
  2970. }
  2971. // We have to add sort icon only if LV items can be sorted.
  2972. // This is possible only if any of following condition is true.
  2973. // a. there are any result items in result pane OR
  2974. // b. snapin supports IResultDataCompare OR
  2975. // c. snapin supports IResultDataCompareEx OR
  2976. // d. snapin wants default lexical sort OR
  2977. // e. snapin has virtual list
  2978. BOOL bCanSortListView = (0 != (m_itemCount - m_nScopeItems)) ||
  2979. (NULL != m_sortParams.spResultCompare) ||
  2980. (NULL != m_sortParams.spResultCompareEx) ||
  2981. (TRUE == m_sortParams.bLexicalSort) ||
  2982. (IsVirtual());
  2983. if ( bCanSortListView && bSetSortIcon)
  2984. {
  2985. // retrieve old frmt settings
  2986. if ( !GetListCtrl().GetColumn(nNewCol, &lvOriginalCol) )
  2987. return (sc = E_FAIL).ToHr();
  2988. // make the new format settings
  2989. // transfer old values such as LVCFMT_CENTER, which we do not want to change
  2990. // see windows bugs (ntbug09) #153029 10/09/00
  2991. lvcol.fmt = lvOriginalCol.fmt | LVCFMT_IMAGE | LVCFMT_BITMAP_ON_RIGHT;
  2992. // Set the sort icon for new column.
  2993. lvcol.iImage = (bAscending) ? 0 : 1;
  2994. if ( !GetListCtrl().SetColumn(nNewCol, &lvcol) )
  2995. return (sc = E_FAIL).ToHr();
  2996. }
  2997. // De-select all the items in virtual list.
  2998. if (IsVirtual())
  2999. {
  3000. int nItem = -1;
  3001. LV_ITEM lvi;
  3002. lvi.stateMask = LVIS_SELECTED;
  3003. lvi.state = ~LVIS_SELECTED;
  3004. while ( (nItem = GetListCtrl().GetNextItem(nItem, LVNI_SELECTED)) != -1)
  3005. {
  3006. GetListCtrl().SetItemState(nItem, &lvi);
  3007. }
  3008. }
  3009. return S_OK;
  3010. }
  3011. //+-------------------------------------------------------------------
  3012. //
  3013. // Member: CCCListViewCtrl::ScRedrawHeader
  3014. //
  3015. // Synopsis: Need to send WM_SETREDRAW to headers to reduce flicker
  3016. // when persisted column data is applied.
  3017. // Turn it off before sending MMCN_SHOW to snapins and turn
  3018. // it on after MMCN_SHOW returns.
  3019. //
  3020. // Arguments: [bRedraw] -
  3021. //
  3022. // Returns: SC
  3023. //
  3024. //--------------------------------------------------------------------
  3025. SC CCCListViewCtrl::ScRedrawHeader (bool bRedraw)
  3026. {
  3027. DECLARE_SC(sc, _T("CCCListViewCtrl::ScRedrawHeader"));
  3028. CAMCHeaderCtrl* pHeader = GetHeaderCtrl();
  3029. sc = ScCheckPointers(pHeader, E_UNEXPECTED);
  3030. if (sc)
  3031. return sc;
  3032. int nViewMode = GetViewMode();
  3033. // Turn off/on the header only if it is report or filtered mode.
  3034. // If turned on in other modes comctl does not take care of different
  3035. // mode and will show headers (eg: in large icon mode).
  3036. if ( (nViewMode != MMCLV_VIEWSTYLE_REPORT) && (nViewMode != MMCLV_VIEWSTYLE_FILTERED) )
  3037. return sc;
  3038. pHeader->SetRedraw(bRedraw);
  3039. // If redraw is true then repaint the control.
  3040. if (bRedraw)
  3041. pHeader->InvalidateRect(NULL);
  3042. return (sc);
  3043. }
  3044. /*+-------------------------------------------------------------------------*
  3045. *
  3046. * CCCListViewCtrl::SetLoadMode
  3047. *
  3048. * PURPOSE: Turn on/off redraw on list control & header control when
  3049. * persisted list view settings (columns...) are applied.
  3050. *
  3051. * PARAMETERS:
  3052. * BOOL bState - load state, true -> turn-off redraw, false -> turn-on redraw
  3053. *
  3054. * RETURNS:
  3055. * HRESULT
  3056. *
  3057. *+-------------------------------------------------------------------------*/
  3058. HRESULT CCCListViewCtrl::SetLoadMode(BOOL bState)
  3059. {
  3060. DECLARE_SC(sc, TEXT("CCCListViewCtrl::SetLoadMode"));
  3061. if (bState == m_bLoading)
  3062. return (sc.ToHr());
  3063. if (bState)
  3064. {
  3065. // turn off drawing during loading
  3066. // 1. Turn off header.
  3067. sc = ScRedrawHeader(false);
  3068. if (sc)
  3069. sc.TraceAndClear();
  3070. // 2. Turn off the listcontrol.
  3071. GetListCtrl().SetRedraw(false);
  3072. }
  3073. else
  3074. {
  3075. sc = ScCheckPointers(m_pListView, E_UNEXPECTED);
  3076. if (sc)
  3077. sc.TraceAndClear();
  3078. else
  3079. {
  3080. sc = m_pListView->ScRestoreColumnsFromPersistedData();
  3081. if (sc)
  3082. sc.TraceAndClear();
  3083. }
  3084. // if sort requested while loading, sort the loaded items now
  3085. if (m_bDeferredSort)
  3086. {
  3087. /*
  3088. * the sort could take awhile, so show a wait cursor
  3089. */
  3090. CWaitCursor wait;
  3091. GetListCtrl().SortItems (SortCompareFunc, (DWORD_PTR)&m_sortParams);
  3092. m_bDeferredSort = FALSE;
  3093. }
  3094. // 1. Important, first turn on list and then header else header will not be redrawn.
  3095. GetListCtrl().SetRedraw(true);
  3096. // 2. Turn on the header.
  3097. sc = ScRedrawHeader(true);
  3098. if (sc)
  3099. sc.TraceAndClear();
  3100. }
  3101. m_bLoading = bState;
  3102. return (sc.ToHr());
  3103. }
  3104. //+-------------------------------------------------------------------
  3105. //
  3106. // Member: CCCListViewCtrl::GetColumnInfoList
  3107. //
  3108. // Synopsis: Get the current column settings.
  3109. //
  3110. // Arguments: [pColumnsList] - [out param], ptr to CColumnsInfoList.
  3111. //
  3112. // Returns: HRESULT
  3113. //
  3114. //--------------------------------------------------------------------
  3115. STDMETHODIMP CCCListViewCtrl::GetColumnInfoList (CColumnInfoList *pColumnsList)
  3116. {
  3117. DECLARE_SC(sc, _T("CCCListViewCtrl::GetColumnInfoList"));
  3118. sc = ScCheckPointers(pColumnsList);
  3119. if (sc)
  3120. return sc.ToHr();
  3121. CAMCListView *pAMCListView = GetListViewPtr();
  3122. sc = ScCheckPointers(pAMCListView, E_UNEXPECTED);
  3123. if (sc)
  3124. return sc.ToHr();
  3125. sc = pAMCListView->ScGetColumnInfoList(pColumnsList);
  3126. if (sc)
  3127. return sc.ToHr();
  3128. return (sc.ToHr());
  3129. }
  3130. //+-------------------------------------------------------------------
  3131. //
  3132. // Member: CCCListViewCtrl::ModifyColumns
  3133. //
  3134. // Synopsis: Modify the columns with given data.
  3135. //
  3136. // Arguments: [columnsList] -
  3137. //
  3138. // Returns: HRESULT
  3139. //
  3140. //--------------------------------------------------------------------
  3141. STDMETHODIMP CCCListViewCtrl::ModifyColumns (const CColumnInfoList& columnsList)
  3142. {
  3143. DECLARE_SC(sc, _T("CCCListViewCtrl::ModifyColumns"));
  3144. CAMCListView *pAMCListView = GetListViewPtr();
  3145. sc = ScCheckPointers(pAMCListView, E_UNEXPECTED);
  3146. if (sc)
  3147. return sc.ToHr();
  3148. sc = pAMCListView->ScModifyColumns(columnsList);
  3149. if (sc)
  3150. return sc.ToHr();
  3151. return (sc.ToHr());
  3152. }
  3153. //+-------------------------------------------------------------------
  3154. //
  3155. // Member: CCCListViewCtrl::GetDefaultColumnInfoList
  3156. //
  3157. // Synopsis: Get the default column settings
  3158. //
  3159. // Arguments: [columnInfoList] - [out]
  3160. //
  3161. // Returns: HRESULT
  3162. //
  3163. //--------------------------------------------------------------------
  3164. STDMETHODIMP CCCListViewCtrl::GetDefaultColumnInfoList (CColumnInfoList& columnInfoList)
  3165. {
  3166. DECLARE_SC(sc, _T("CNodeInitObject::GetDefaultColumnInfoList"));
  3167. CAMCListView *pAMCListView = GetListViewPtr();
  3168. sc = ScCheckPointers(pAMCListView, E_UNEXPECTED);
  3169. if (sc)
  3170. return sc.ToHr();
  3171. sc = pAMCListView->ScGetDefaultColumnInfoList(columnInfoList);
  3172. if (sc)
  3173. return sc.ToHr();
  3174. return (sc.ToHr());
  3175. }
  3176. /*+-------------------------------------------------------------------------*
  3177. *
  3178. * CCCListViewCtrl::RenameItem
  3179. *
  3180. * PURPOSE: Puts the specified result item into rename mode.
  3181. *
  3182. * PARAMETERS:
  3183. * CResultItem* pri :
  3184. *
  3185. * RETURNS:
  3186. * STDMETHODIMP
  3187. *
  3188. *+-------------------------------------------------------------------------*/
  3189. STDMETHODIMP
  3190. CCCListViewCtrl::RenameItem(HRESULTITEM itemID)
  3191. {
  3192. DECLARE_SC(sc, TEXT("CCCListViewCtrl::RenameItem"));
  3193. int nIndex = -1;
  3194. sc = ScGetItemIndexFromHRESULTITEM(itemID, nIndex);
  3195. if (sc)
  3196. return sc.ToHr();
  3197. if(nIndex < 0 || nIndex >= m_itemCount)
  3198. return (sc = E_INVALIDARG).ToHr();
  3199. // must have the focus to rename
  3200. if (::GetFocus()!= GetListCtrl())
  3201. SetFocus(GetListCtrl());
  3202. // if the rename failed, E_FAIL is returned.
  3203. if(NULL==GetListCtrl().EditLabel(nIndex))
  3204. return (sc=E_FAIL).ToHr();
  3205. return sc.ToHr();
  3206. }
  3207. HRESULT CCCListViewCtrl::OnModifyItem(CResultItem* pri)
  3208. {
  3209. HRESULT hr = S_OK;
  3210. int nItem = ResultItemToIndex(pri);
  3211. if(nItem < 0 || nItem >= m_itemCount)
  3212. {
  3213. ASSERT(FALSE);
  3214. return E_INVALIDARG;
  3215. }
  3216. LV_ITEM lvi;
  3217. ZeroMemory(&lvi, sizeof(lvi));
  3218. lvi.mask = LVIF_TEXT | LVIF_IMAGE;
  3219. lvi.iItem = nItem;
  3220. lvi.pszText = LPSTR_TEXTCALLBACK;
  3221. lvi.iImage = I_IMAGECALLBACK;
  3222. GetListCtrl().SetItem( &lvi );
  3223. if (!GetListCtrl().RedrawItems (nItem, nItem))
  3224. hr = E_FAIL;
  3225. CHECK_HRESULT(hr);
  3226. return hr;
  3227. }
  3228. //+-------------------------------------------------------------------
  3229. //
  3230. // Member: CCCListViewCtrl::ScSelectAll
  3231. //
  3232. // Synopsis: Select all the items in the list view.
  3233. //
  3234. // Arguments: None
  3235. //
  3236. // Returns: SC
  3237. //
  3238. //--------------------------------------------------------------------
  3239. SC CCCListViewCtrl::ScSelectAll ()
  3240. {
  3241. DECLARE_SC(sc, _T("CCCListViewCtrl::ScSelectAll"));
  3242. LV_ITEM lvi;
  3243. lvi.stateMask = lvi.state = LVIS_SELECTED;
  3244. for (int i = 0; i < GetListCtrl().GetItemCount(); ++i)
  3245. {
  3246. // NOTE: do not use GetListCtrl().SetItemState - it uses SetItem which is not supported for virtual lists
  3247. if (!GetListCtrl().SendMessage( LVM_SETITEMSTATE, WPARAM(i), (LPARAM)(LV_ITEM FAR *)&lvi))
  3248. return (sc = E_FAIL);
  3249. }
  3250. return (sc);
  3251. }
  3252. //-------------------------------------------------- Windows Hooks
  3253. BOOL CCCListViewCtrl::Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext /*=NULL*/ )
  3254. {
  3255. DECLARE_SC (sc, _T("CCCListViewCtrl::Create"));
  3256. ASSERT(pParentWnd != NULL && IsWindow(pParentWnd->m_hWnd));
  3257. BOOL bRet = FALSE;
  3258. // standard or virtual ?
  3259. CAMCListView* pListView = (dwStyle & LVS_OWNERDATA) ? m_pVirtualList : m_pStandardList;
  3260. ASSERT(pListView->m_hWnd == NULL);
  3261. if (pListView->Create(NULL, NULL, dwStyle, rect, pParentWnd, nID, pContext))
  3262. {
  3263. // Attach image lists
  3264. sc = ScSetImageLists ();
  3265. if (sc)
  3266. {
  3267. pListView->DestroyWindow();
  3268. return (false);
  3269. }
  3270. // update member variables
  3271. m_bVirtual = (dwStyle & LVS_OWNERDATA) ? TRUE : FALSE;
  3272. m_pListView = pListView;
  3273. m_pParentWnd = pParentWnd;
  3274. bRet = TRUE;
  3275. }
  3276. int iTop = ListView_GetTopIndex(GetListCtrl());
  3277. return bRet;
  3278. }
  3279. SC CCCListViewCtrl::ScSetImageLists ()
  3280. {
  3281. DECLARE_SC (sc, _T("CCCListViewCtrl::ScSetImageLists"));
  3282. CListCtrl& lc = GetListCtrl();
  3283. /*
  3284. * if we need to create one list, we should need to create both
  3285. */
  3286. ASSERT ((m_smallIL.GetSafeHandle() == NULL) == (m_largeIL.GetSafeHandle() == NULL));
  3287. /*
  3288. * create the image lists, if necessary
  3289. */
  3290. if (m_smallIL.GetSafeHandle() == NULL)
  3291. {
  3292. if (!m_smallIL.Create(16, 16, ILC_COLORDDB | ILC_MASK, 20, 10) ||
  3293. !m_largeIL.Create(32, 32, ILC_COLORDDB | ILC_MASK, 20, 10))
  3294. {
  3295. goto Error;
  3296. }
  3297. // Add standard MMC bitmaps
  3298. CBitmap bmSmall;
  3299. CBitmap bmLarge;
  3300. if (!bmSmall.LoadBitmap(IDB_AMC_NODES16) || !bmLarge.LoadBitmap(IDB_AMC_NODES32))
  3301. goto Error;
  3302. sc = SetImageStrip (TVOWNED_MAGICWORD, bmSmall, bmLarge, 0, RGB(255,0,255));
  3303. if (sc)
  3304. goto Error;
  3305. }
  3306. /*
  3307. * attach them to the list control
  3308. */
  3309. lc.SetImageList (&m_smallIL, LVSIL_SMALL);
  3310. lc.SetImageList (&m_largeIL, LVSIL_NORMAL);
  3311. /*
  3312. * setting the small image list for the list control overwrites
  3313. * the image list for the header control; fix it up
  3314. */
  3315. {
  3316. CWnd* pwndHeader = GetHeaderCtrl();
  3317. if (pwndHeader != NULL)
  3318. Header_SetImageList (*pwndHeader, (HIMAGELIST) m_headerIL);
  3319. }
  3320. return (sc);
  3321. Error:
  3322. /*
  3323. * DeleteImageList is safe to call on uncreated CImageLists
  3324. */
  3325. m_smallIL.DeleteImageList();
  3326. m_largeIL.DeleteImageList();
  3327. /*
  3328. * If we haven't filled in the SC with an error code, try last error.
  3329. * Some (many) APIs fail without setting the last error, so if we still
  3330. * don't have an error code, give it a generic E_FAIL.
  3331. */
  3332. if (!sc.IsError())
  3333. {
  3334. sc.FromLastError();
  3335. if (!sc.IsError())
  3336. sc = E_FAIL;
  3337. }
  3338. return (sc);
  3339. }
  3340. /*+-------------------------------------------------------------------------*
  3341. * CCCListViewCtrl::OnSysColorChange
  3342. *
  3343. * WM_SYSCOLORCHANGE handler for CCCListViewCtrl.
  3344. *--------------------------------------------------------------------------*/
  3345. void CCCListViewCtrl::OnSysColorChange()
  3346. {
  3347. m_headerIL.OnSysColorChange();
  3348. CWnd* pwndHeader = GetHeaderCtrl();
  3349. if (pwndHeader != NULL)
  3350. Header_SetImageList (*pwndHeader, (HIMAGELIST) m_headerIL);
  3351. }
  3352. /*+-------------------------------------------------------------------------*
  3353. *
  3354. * CCCListViewCtrl::ScAttachToListPad
  3355. *
  3356. * PURPOSE: Attaches/Detaches the list view to the listpad window. The listpad
  3357. * window is an IE frame. Attaching occurs by reparenting the list view.
  3358. *
  3359. * PARAMETERS:
  3360. * HWND hwnd : The new parent window, or NULL to detach
  3361. * HWND* phwnd : 1) non-NULL phwnd: The list view window handle is returned as
  3362. * an out parameter
  3363. * 2) NULL phwnd: Detaches the list view control from the list pad.
  3364. *
  3365. * RETURNS:
  3366. * HRESULT
  3367. *
  3368. *+-------------------------------------------------------------------------*/
  3369. SC
  3370. CCCListViewCtrl::ScAttachToListPad (HWND hwnd, HWND* phwnd)
  3371. {
  3372. DECLARE_SC (sc, TEXT("CCCListViewCtrl::ScAttachToListPad"));
  3373. CAMCView* pAMCView = dynamic_cast<CAMCView*>(m_pParentWnd); // pointer is checked before usage, no need to test here.
  3374. if (phwnd)
  3375. {
  3376. // attaching
  3377. // are we still attached?
  3378. if (m_SavedHWND)
  3379. {
  3380. //Attaching to ListPad when already attached - just make window exactly the same size as (new) parent
  3381. RECT r;
  3382. ::GetWindowRect (hwnd, &r);
  3383. m_pListView->SetWindowPos (NULL, 0, 0,
  3384. r.right-r.left,
  3385. r.bottom-r.top, SWP_NOZORDER | SWP_NOACTIVATE);
  3386. return sc;
  3387. }
  3388. else
  3389. {
  3390. // save current parent hwnd and its state
  3391. m_SavedHWND = ::GetParent (m_pListView->m_hWnd);
  3392. m_wp.length = sizeof(WINDOWPLACEMENT);
  3393. ::GetWindowPlacement (m_pListView->m_hWnd, &m_wp);
  3394. // switch to new one
  3395. ::SetParent (m_pListView->m_hWnd, hwnd);
  3396. m_pListView->ShowWindow (SW_SHOW);
  3397. // make window exactly the same size as (new) parent
  3398. RECT r;
  3399. ::GetWindowRect (hwnd, &r);
  3400. m_pListView->SetWindowPos (NULL, 0, 0,
  3401. r.right-r.left,
  3402. r.bottom-r.top, SWP_NOZORDER);
  3403. // return back my window
  3404. *phwnd = m_pListView->m_hWnd;
  3405. // notify snapin of attach
  3406. if (pAMCView)
  3407. pAMCView->NotifyListPad (phwnd != NULL);
  3408. }
  3409. }
  3410. else
  3411. {
  3412. // detaching
  3413. if (m_SavedHWND == NULL) // this may get called repeatedly...
  3414. return S_OK;
  3415. // notify snapin of detach
  3416. if (pAMCView)
  3417. pAMCView->NotifyListPad (phwnd != NULL);
  3418. // change back parent window and its state
  3419. HWND hWndNewParent = m_pListView->m_hWnd;
  3420. ::SetParent (m_pListView->m_hWnd, m_SavedHWND);
  3421. if (m_wp.length != 0)
  3422. {
  3423. m_wp.showCmd = SW_HIDE;
  3424. ::SetWindowPlacement (m_pListView->m_hWnd, &m_wp);
  3425. }
  3426. // clear saved window and state
  3427. m_SavedHWND = NULL;
  3428. ZeroMemory (&m_wp, sizeof(WINDOWPLACEMENT));
  3429. Reset();
  3430. }
  3431. return sc;
  3432. }
  3433. /*+-------------------------------------------------------------------------*
  3434. * CCCListViewCtrl::OnCustomDraw
  3435. *
  3436. * NM_CUSTOMDRAW handler for CCCListViewCtrl.
  3437. *--------------------------------------------------------------------------*/
  3438. LRESULT CCCListViewCtrl::OnCustomDraw (NMLVCUSTOMDRAW* plvcd)
  3439. {
  3440. ASSERT (CWnd::FromHandle (plvcd->nmcd.hdr.hwndFrom) == m_pListView);
  3441. return (m_FontLinker.OnCustomDraw (&plvcd->nmcd));
  3442. }
  3443. /*+-------------------------------------------------------------------------*
  3444. * CCCListViewCtrl::UseFontLinking
  3445. *
  3446. *
  3447. *--------------------------------------------------------------------------*/
  3448. bool CCCListViewCtrl::UseFontLinking () const
  3449. {
  3450. CAMCView* pAMCView = m_pListView->GetAMCView();
  3451. ASSERT (pAMCView != NULL);
  3452. DWORD dwListOptions = pAMCView->GetViewData()->GetListOptions();
  3453. return (dwListOptions & RVTI_LIST_OPTIONS_USEFONTLINKING);
  3454. }
  3455. /*+-------------------------------------------------------------------------*
  3456. * CListFontLinker::GetItemText
  3457. *
  3458. *
  3459. *--------------------------------------------------------------------------*/
  3460. std::wstring CListFontLinker::GetItemText (NMCUSTOMDRAW* pnmcd) const
  3461. {
  3462. NMLVCUSTOMDRAW* plvcd = reinterpret_cast<NMLVCUSTOMDRAW *>(pnmcd);
  3463. int iItem = pnmcd->dwItemSpec;
  3464. int iSubItem = (pnmcd->dwDrawStage & CDDS_SUBITEM) ? plvcd->iSubItem : 0;
  3465. CListCtrl& lc = m_pListCtrl->GetListViewPtr()->GetListCtrl();
  3466. USES_CONVERSION;
  3467. return (std::wstring (T2CW (lc.GetItemText (iItem, iSubItem))));
  3468. }
  3469. /*+-------------------------------------------------------------------------*
  3470. * CListFontLinker::IsAnyItemLocalizable
  3471. *
  3472. *
  3473. *--------------------------------------------------------------------------*/
  3474. bool CListFontLinker::IsAnyItemLocalizable () const
  3475. {
  3476. return (m_pListCtrl->UseFontLinking ());
  3477. }
  3478. //############################################################################
  3479. //############################################################################
  3480. class CMMCResultNode;
  3481. /*+-------------------------------------------------------------------------*
  3482. * class CNodes
  3483. *
  3484. *
  3485. * PURPOSE: base class for Nodes collections. Implements most of required methods
  3486. *
  3487. *+-------------------------------------------------------------------------*/
  3488. class CNodes :
  3489. public CMMCIDispatchImpl<Nodes>,
  3490. public CTiedComObject<CCCListViewCtrl>, // is tied to CCCListViewCtrl
  3491. public CTiedObject, // enumerators are tied to it
  3492. public CListViewObserver
  3493. {
  3494. protected:
  3495. typedef CCCListViewCtrl CMyTiedObject; // tied to CCCListViewCtrl
  3496. private:
  3497. // define collection type for cached Nodes
  3498. typedef std::pair<int /*index*/, CMMCResultNode * /*pNode*/> col_entry_t;
  3499. typedef std::vector<col_entry_t> col_t;
  3500. // define comparison functor for b-search in a collection
  3501. struct index_less : public std::binary_function<col_entry_t, int, bool>
  3502. {
  3503. bool operator()(const col_entry_t& x, const int& y) const { return (x.first < y); }
  3504. };
  3505. public:
  3506. BEGIN_MMC_COM_MAP(CNodes)
  3507. END_MMC_COM_MAP()
  3508. // returning self as tied object
  3509. // class implements enumerator methods itself, but it is used as a base
  3510. // we need to tell all node we are going down
  3511. virtual ~CNodes() { InvalidateConnectedNodes(); }
  3512. // Nodes interface
  3513. public:
  3514. // methods forwarded to the list control
  3515. STDMETHODIMP get_Count( PLONG pCount );
  3516. STDMETHODIMP Item( long Index, PPNODE ppNode );
  3517. public:
  3518. // observed events
  3519. virtual ::SC ScOnListViewIndexesReset();
  3520. virtual ::SC ScOnListViewItemInserted(int iIndex);
  3521. virtual ::SC ScOnListViewItemDeleted (int iIndex);
  3522. // Nodes enumeration impl
  3523. ::SC ScEnumReset (int &pos);
  3524. ::SC ScEnumNext (int &pos, PDISPATCH & pDispatch);
  3525. ::SC ScEnumSkip (unsigned long celt, unsigned long& celtSkipped, int &pos);
  3526. // node object helpers
  3527. ::SC ScGetDisplayName(int iItem, CComBSTR& bstrName);
  3528. ::SC ScUnadviseNodeObj(CMMCResultNode *node); // called from ~CMMCResultNode()
  3529. // asked by ListControl [forwarded by Node] to check if Node belongs to it.
  3530. // false if unconnected, else tries to match the owner
  3531. bool IsTiedToThisList(CCCListViewCtrl *pvc);
  3532. // returns Node representing the item (may reuse/create/forward-to-scope-tree)
  3533. ::SC ScGetNode (int iItem, PPNODE ppNode );
  3534. ::SC ScGetListCtrl(CCCListViewCtrl **ppListCtrl); // returns the tied list control
  3535. private: // implementation helpers
  3536. ::SC ScAdvancePosition( int& pos, unsigned nItems ); // returns S_FALSE if adv. less than req.
  3537. // initializators
  3538. void SetSelectedItemsOnly(bool bSelOnly) { m_bSelectedItemsOnly = bSelOnly; }
  3539. // breaks connection between Nodes and any Node object
  3540. void InvalidateConnectedNodes();
  3541. // data members
  3542. bool m_bSelectedItemsOnly;
  3543. col_t m_Nodes;
  3544. friend class CCCListViewCtrl;
  3545. };
  3546. // this typedefs the CNodesEnum class. Implements get__NewEnum using CMMCEnumerator and a _Positon object
  3547. typedef CMMCNewEnumImpl<CNodes, int, CNodes> CNodesEnum;
  3548. //############################################################################
  3549. //############################################################################
  3550. /*+-------------------------------------------------------------------------*
  3551. * class CMMCResultNode
  3552. *
  3553. *
  3554. * PURPOSE: Implements the Node automation interface, for a result node
  3555. *
  3556. *+-------------------------------------------------------------------------*/
  3557. class CMMCResultNode :
  3558. public CMMCIDispatchImpl<Node>
  3559. {
  3560. public:
  3561. BEGIN_MMC_COM_MAP(CMMCResultNode)
  3562. END_MMC_COM_MAP()
  3563. // Node methods
  3564. public:
  3565. STDMETHODIMP get_Name( PBSTR pbstrName);
  3566. STDMETHODIMP get_Property( BSTR PropertyName, PBSTR PropertyValue);
  3567. STDMETHODIMP get_Bookmark( PBSTR pbstrBookmark);
  3568. STDMETHODIMP IsScopeNode(PBOOL pbIsScopeNode);
  3569. STDMETHODIMP get_Nodetype(PBSTR Nodetype);
  3570. CMMCResultNode();
  3571. ~CMMCResultNode();
  3572. SC ScGetListCtrl(CCCListViewCtrl **ppListCtrl);
  3573. int GetIndex() { return m_iIndex; }
  3574. // asked by ListControl to check if Node belongs to it. false if orphan,
  3575. // forwarded to Nodes else
  3576. bool IsTiedToThisList(CCCListViewCtrl *pvc) { return (m_pNodes != NULL && m_pNodes->IsTiedToThisList(pvc)); }
  3577. private: // implementation
  3578. ::SC ScGetAMCView(CAMCView **ppAMCView);
  3579. void Invalidate() { m_iIndex = -1; m_pNodes = NULL; }
  3580. int m_iIndex;
  3581. CNodes *m_pNodes;
  3582. friend class CNodes;
  3583. };
  3584. //############################################################################
  3585. //############################################################################
  3586. //
  3587. // CCCListViewCtrl methods managing Node & Nodes objects
  3588. //
  3589. //############################################################################
  3590. //############################################################################
  3591. /***************************************************************************\
  3592. *
  3593. * METHOD: CCCListViewCtrl::ScFindResultItem
  3594. *
  3595. * PURPOSE: finds the index in ListView for item identified by Node [helper]
  3596. *
  3597. * PARAMETERS:
  3598. * PNODE pNode - node to examine
  3599. * int &iItem - storage for resulting index
  3600. *
  3601. * RETURNS:
  3602. * SC - result code
  3603. *
  3604. \***************************************************************************/
  3605. SC CCCListViewCtrl::ScFindResultItem( PNODE pNode, int &iItem )
  3606. {
  3607. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScSelect"));
  3608. // parameter check
  3609. sc = ScCheckPointers(pNode);
  3610. if (sc)
  3611. return sc;
  3612. iItem = -1;
  3613. // what type of node do we have
  3614. BOOL bScopeNode = FALSE;
  3615. sc = pNode->IsScopeNode(&bScopeNode);
  3616. if (sc)
  3617. return sc;
  3618. if (bScopeNode) // scope node
  3619. {
  3620. // we do not have scope items in virtual lists
  3621. if (IsVirtual())
  3622. return sc = ScFromMMC(MMC_E_RESULT_ITEM_NOT_FOUND);
  3623. // find the result item (with the help of the owner class)
  3624. // check for view
  3625. sc = ScCheckPointers( m_pListView, E_UNEXPECTED);
  3626. if (sc)
  3627. return sc;
  3628. // get AMCView
  3629. CAMCView* pAMCView = m_pListView->GetAMCView();
  3630. sc = ScCheckPointers( pAMCView, E_UNEXPECTED);
  3631. if (sc)
  3632. return sc;
  3633. // forward the request
  3634. HRESULTITEM itm;
  3635. sc = pAMCView->ScFindResultItemForScopeNode( pNode, itm );
  3636. if (sc)
  3637. return sc;
  3638. // get the index of item
  3639. iItem = ResultItemToIndex(CResultItem::FromHandle(itm));
  3640. if (iItem < 0)
  3641. return sc = E_UNEXPECTED; // shouldn't be so
  3642. }
  3643. else // result node
  3644. {
  3645. // convert the pointer
  3646. CMMCResultNode *pResNode = dynamic_cast<CMMCResultNode *>(pNode);
  3647. sc = ScCheckPointers(pResNode); // invalid param. isn't it ?
  3648. if (sc)
  3649. return sc;
  3650. // now check if it's actually comming from this list
  3651. if (!pResNode->IsTiedToThisList(this))
  3652. return sc = E_INVALIDARG;
  3653. iItem = pResNode->GetIndex();
  3654. }
  3655. return sc;
  3656. }
  3657. /***************************************************************************\
  3658. *
  3659. * METHOD: CCCListViewCtrl::ScSelect
  3660. *
  3661. * PURPOSE: selects item identified by node [implements View.Select()]
  3662. *
  3663. * PARAMETERS:
  3664. * PNODE pNode - node to select
  3665. *
  3666. * RETURNS:
  3667. * SC - result code
  3668. *
  3669. \***************************************************************************/
  3670. SC CCCListViewCtrl::ScSelect( PNODE pNode )
  3671. {
  3672. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScSelect"));
  3673. // parameter check
  3674. sc = ScCheckPointers(pNode);
  3675. if (sc)
  3676. return sc;
  3677. // find the result item
  3678. int nIdxToSelect = -1;
  3679. sc = ScFindResultItem( pNode, nIdxToSelect );
  3680. if (sc)
  3681. return sc;
  3682. // perform the action on list control
  3683. // NOTE: do not use GetListCtrl().SetItemState - it uses SetItem which is not supported for virtual lists
  3684. LV_ITEM lvi;
  3685. lvi.stateMask = lvi.state = LVIS_SELECTED;
  3686. if (!GetListCtrl().SendMessage( LVM_SETITEMSTATE, WPARAM(nIdxToSelect), (LPARAM)(LV_ITEM FAR *)&lvi))
  3687. return sc = E_FAIL;
  3688. return sc;
  3689. }
  3690. /***************************************************************************\
  3691. *
  3692. * METHOD: CCCListViewCtrl::ScDeselect
  3693. *
  3694. * PURPOSE: deselects item identified by node [implements View.Deselect()]
  3695. *
  3696. * PARAMETERS:
  3697. * PNODE pNode - node to deselect
  3698. *
  3699. * RETURNS:
  3700. * SC - result code
  3701. *
  3702. \***************************************************************************/
  3703. SC CCCListViewCtrl::ScDeselect( PNODE pNode)
  3704. {
  3705. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScDeselect"));
  3706. // parameter check
  3707. sc = ScCheckPointers(pNode);
  3708. if (sc)
  3709. return sc;
  3710. // find the result item
  3711. int nIdxToSelect = -1;
  3712. sc = ScFindResultItem( pNode, nIdxToSelect );
  3713. if (sc)
  3714. return sc;
  3715. // perform the action on list control
  3716. // NOTE: do not use GetListCtrl().SetItemState - it uses SetItem which is not supported for virtual lists
  3717. LV_ITEM lvi;
  3718. lvi.stateMask = LVIS_SELECTED;
  3719. lvi.state = 0;
  3720. if (!GetListCtrl().SendMessage( LVM_SETITEMSTATE, WPARAM(nIdxToSelect), (LPARAM)(LV_ITEM FAR *)&lvi))
  3721. return sc = E_FAIL;
  3722. return sc;
  3723. }
  3724. /***************************************************************************\
  3725. *
  3726. * METHOD: CCCListViewCtrl::ScIsSelected
  3727. *
  3728. * PURPOSE: checks the status of item identified by node [implements View.IsSelected]
  3729. *
  3730. * PARAMETERS:
  3731. * PNODE pNode - node to examine
  3732. * PBOOL pIsSelected - storage for result
  3733. *
  3734. * RETURNS:
  3735. * SC - result code
  3736. *
  3737. \***************************************************************************/
  3738. SC CCCListViewCtrl::ScIsSelected( PNODE pNode, PBOOL pIsSelected)
  3739. {
  3740. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScIsSelected"));
  3741. // parameter check
  3742. sc = ScCheckPointers(pNode, pIsSelected);
  3743. if (sc)
  3744. return sc;
  3745. *pIsSelected = FALSE;
  3746. // find the result item
  3747. int nIdxToSelect = -1;
  3748. sc = ScFindResultItem( pNode, nIdxToSelect );
  3749. if (sc)
  3750. return sc;
  3751. // perform the action on list control
  3752. if ( 0 != (GetListCtrl().GetItemState( nIdxToSelect, LVIS_SELECTED ) & LVIS_SELECTED ))
  3753. *pIsSelected = TRUE;
  3754. return sc;
  3755. }
  3756. /***************************************************************************\
  3757. *
  3758. * METHOD: CCCListViewCtrl::Scget_ListItems
  3759. *
  3760. * PURPOSE: returns Nodes enumeration including all list items
  3761. *
  3762. * PARAMETERS:
  3763. * PPNODES ppNodes - storage for result
  3764. *
  3765. * RETURNS:
  3766. * SC - result code
  3767. *
  3768. \***************************************************************************/
  3769. SC CCCListViewCtrl::Scget_ListItems( PPNODES ppNodes )
  3770. {
  3771. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_ListItems"));
  3772. // get proper enumeration
  3773. const bool bSelectedItemsOnly = false;
  3774. sc = ScGetNodesEnum(bSelectedItemsOnly, ppNodes);
  3775. if (sc)
  3776. return sc;
  3777. return sc;
  3778. }
  3779. /***************************************************************************\
  3780. *
  3781. * METHOD: CCCListViewCtrl::Scget_SelectedItems
  3782. *
  3783. * PURPOSE: returns Nodes enumeration including selected list items
  3784. *
  3785. * PARAMETERS:
  3786. * PPNODES ppNodes - storage for result
  3787. *
  3788. * RETURNS:
  3789. * SC - result code
  3790. *
  3791. \***************************************************************************/
  3792. SC CCCListViewCtrl::Scget_SelectedItems( PPNODES ppNodes)
  3793. {
  3794. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_SelectedItems"));
  3795. // get proper enumeration
  3796. const bool bSelectedItemsOnly = true;
  3797. sc = ScGetNodesEnum(bSelectedItemsOnly, ppNodes);
  3798. if (sc)
  3799. return sc;
  3800. return sc;
  3801. }
  3802. /***************************************************************************\
  3803. *
  3804. * METHOD: CCCListViewCtrl::ScValidateItem
  3805. *
  3806. * PURPOSE: helper function inspecting the index validity and node type
  3807. *
  3808. * PARAMETERS:
  3809. * int iItem - item to inspect
  3810. * bool &bScopeNode - result: is it a scope node
  3811. *
  3812. * RETURNS:
  3813. * SC - result code
  3814. *
  3815. \***************************************************************************/
  3816. SC CCCListViewCtrl::ScValidateItem( int iItem, bool &bScopeNode )
  3817. {
  3818. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScValidateItem"));
  3819. // check the index
  3820. if (iItem < 0 || iItem >= GetListCtrl().GetItemCount())
  3821. return sc = E_INVALIDARG;
  3822. bScopeNode = false; // its always false for virtual lists
  3823. if (!IsVirtual())
  3824. {
  3825. // now try to guess what kind of result item we have
  3826. CResultItem* pri = IndexToResultItem (iItem);
  3827. sc = ScCheckPointers(pri, E_UNEXPECTED);
  3828. if (sc)
  3829. return sc;
  3830. bScopeNode = pri->IsScopeItem();
  3831. }
  3832. return sc;
  3833. }
  3834. /***************************************************************************\
  3835. *
  3836. * METHOD: CCCListViewCtrl::ScGetNodesEnum
  3837. *
  3838. * PURPOSE: returns [creates if needed] com object Nodes
  3839. *
  3840. * PARAMETERS:
  3841. * EnumType enumType - type of enumeration requested [all items/selected items]
  3842. * PPNODES ppNodes - storage for the result (addref'ed for the caller)
  3843. *
  3844. * RETURNS:
  3845. * SC - result code
  3846. *
  3847. \***************************************************************************/
  3848. SC CCCListViewCtrl::ScGetNodesEnum(bool bSelectedItemsOnly, PPNODES ppNodes)
  3849. {
  3850. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScGetNodesEnum"));
  3851. // parameter check
  3852. sc = ScCheckPointers ( ppNodes );
  3853. if (sc)
  3854. return sc;
  3855. // result initialization
  3856. *ppNodes = NULL;
  3857. // get a reference to proper variable
  3858. NodesPtr& rspNodes = bSelectedItemsOnly ? m_spSelNodes : m_spAllNodes;
  3859. if (rspNodes == NULL) // don't we have it ready?
  3860. {
  3861. // create a CNodesEnum object
  3862. sc = CTiedComObjectCreator<CNodesEnum>::ScCreateAndConnect(*this, rspNodes);
  3863. if (sc)
  3864. return (sc);
  3865. // get the actual object
  3866. typedef CComObject<CNodesEnum> CNodesEnumObj;
  3867. CNodesEnumObj *pNodesEnum = dynamic_cast<CNodesEnumObj*>(rspNodes.GetInterfacePtr());
  3868. // check the pointer
  3869. sc = ScCheckPointers( pNodesEnum, E_UNEXPECTED );
  3870. if(sc)
  3871. return sc;
  3872. // update internal data
  3873. pNodesEnum->SetSelectedItemsOnly(bSelectedItemsOnly);
  3874. // add new object as an observer to the view
  3875. AddObserver(static_cast<CListViewObserver&>(*pNodesEnum));
  3876. }
  3877. // addref and return the pointer for the client.
  3878. *ppNodes = rspNodes;
  3879. (*ppNodes)->AddRef();
  3880. return sc;
  3881. }
  3882. /***************************************************************************\
  3883. *
  3884. * METHOD: CCCListViewCtrl::ScGetScopeNodeForItem
  3885. *
  3886. * PURPOSE: transit point for Scope Node request - comes from enumeration, forwarded
  3887. * to AMCView and further to ScopeTree
  3888. *
  3889. * PARAMETERS:
  3890. * int iItem - node index to retrieve
  3891. * PPNODE ppNode - result storage
  3892. *
  3893. * RETURNS:
  3894. * SC - result code
  3895. *
  3896. \***************************************************************************/
  3897. SC CCCListViewCtrl::ScGetScopeNodeForItem( int iItem, PPNODE ppNode )
  3898. {
  3899. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScGetScopeNodeForItem"));
  3900. // check the parameters
  3901. sc = ScCheckPointers(ppNode);
  3902. if (sc)
  3903. return sc;
  3904. // initialize the result
  3905. *ppNode = NULL;
  3906. // now try to guess what kind of result item we have
  3907. CResultItem* pri = IndexToResultItem(iItem);
  3908. sc = ScCheckPointers(pri, E_UNEXPECTED);
  3909. if (sc)
  3910. return sc;
  3911. // get the hNode
  3912. HNODE hNode = pri->GetScopeNode();
  3913. // check for view
  3914. sc = ScCheckPointers( m_pListView, E_UNEXPECTED);
  3915. if (sc)
  3916. return sc;
  3917. // get AMCView
  3918. CAMCView* pAMCView = m_pListView->GetAMCView();
  3919. sc = ScCheckPointers( pAMCView, E_UNEXPECTED);
  3920. if (sc)
  3921. return sc;
  3922. // forward the request
  3923. sc = pAMCView->ScGetScopeNode( hNode, ppNode );
  3924. if (sc)
  3925. return sc;
  3926. return sc;
  3927. }
  3928. /*+-------------------------------------------------------------------------*
  3929. *
  3930. * CCCListViewCtrl::ScGetAMCView
  3931. *
  3932. * PURPOSE: Returns a pointer to the parent CAMCView
  3933. *
  3934. * PARAMETERS:
  3935. * CAMCView ** ppAMCView :
  3936. *
  3937. * RETURNS:
  3938. * SC
  3939. *
  3940. *+-------------------------------------------------------------------------*/
  3941. SC
  3942. CCCListViewCtrl::ScGetAMCView(CAMCView **ppAMCView)
  3943. {
  3944. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScGetAMCView"));
  3945. sc = ScCheckPointers(ppAMCView);
  3946. if(sc)
  3947. return sc;
  3948. *ppAMCView = NULL;
  3949. // check for view
  3950. sc = ScCheckPointers( m_pListView, E_UNEXPECTED);
  3951. if (sc)
  3952. return sc;
  3953. // get AMCView
  3954. *ppAMCView = m_pListView->GetAMCView();
  3955. sc = ScCheckPointers(*ppAMCView, E_UNEXPECTED);
  3956. return sc;
  3957. }
  3958. //############################################################################
  3959. //############################################################################
  3960. //
  3961. // Implementation of class CNodes
  3962. //
  3963. //############################################################################
  3964. //############################################################################
  3965. /***************************************************************************\
  3966. *
  3967. * METHOD: CNodes::ScEnumReset
  3968. *
  3969. * PURPOSE: resets position for Nodes enumeration
  3970. *
  3971. * PARAMETERS:
  3972. * int &pos - position to reset
  3973. *
  3974. * RETURNS:
  3975. * SC - result code
  3976. *
  3977. \***************************************************************************/
  3978. SC CNodes::ScEnumReset(int &pos)
  3979. {
  3980. DECLARE_SC(sc, TEXT("CNodes::ScEnumReset"));
  3981. pos = -1;
  3982. return sc;
  3983. }
  3984. /*+-------------------------------------------------------------------------*
  3985. *
  3986. * CNodes::ScGetListCtrl
  3987. *
  3988. * PURPOSE: Returns a pointer to the list control
  3989. *
  3990. * GUARANTEE: if the function succeeds, the list control pointer is valid.
  3991. *
  3992. * PARAMETERS:
  3993. * CCCListViewCtrl ** ppListCtrl :
  3994. *
  3995. * RETURNS:
  3996. * SC
  3997. *
  3998. *+-------------------------------------------------------------------------*/
  3999. SC
  4000. CNodes::ScGetListCtrl(CCCListViewCtrl **ppListCtrl)
  4001. {
  4002. DECLARE_SC(sc, TEXT("CNodes::ScGetListCtrl"));
  4003. sc = ScCheckPointers(ppListCtrl, E_UNEXPECTED);
  4004. if(sc)
  4005. return sc;
  4006. *ppListCtrl = NULL;
  4007. sc = ScGetTiedObject(*ppListCtrl);
  4008. if(sc)
  4009. return sc;
  4010. // recheck the pointer
  4011. sc = ScCheckPointers(*ppListCtrl, E_UNEXPECTED);
  4012. if(sc)
  4013. return sc;
  4014. return sc;
  4015. }
  4016. /***************************************************************************\
  4017. *
  4018. * METHOD: CNodes::ScAdvancePosition
  4019. *
  4020. * PURPOSE: advances position (index) of item depending on collection type
  4021. *
  4022. * PARAMETERS:
  4023. * int& pos - position to update
  4024. * int nItems - count of items to skip
  4025. *
  4026. * RETURNS:
  4027. * SC - result code
  4028. *
  4029. \***************************************************************************/
  4030. SC CNodes::ScAdvancePosition( int& pos, unsigned nItems )
  4031. {
  4032. DECLARE_SC(sc, TEXT("CNodes::ScAdvancePosition"));
  4033. // get the tied object
  4034. CCCListViewCtrl *pListCtrl = NULL;
  4035. sc = ScGetTiedObject(pListCtrl);
  4036. if(sc)
  4037. return sc;
  4038. // recheck the pointer
  4039. sc = ScCheckPointers(pListCtrl, E_UNEXPECTED);
  4040. if(sc)
  4041. return sc;
  4042. // inspect if we aren't behind the end
  4043. int nCount = pListCtrl->GetListCtrl().GetItemCount();
  4044. if (pos >= nCount)
  4045. return sc = E_FAIL; // we did not got a valid position
  4046. // advance depending on collection type
  4047. if (m_bSelectedItemsOnly)
  4048. {
  4049. // we only can do it by iterating
  4050. for (int i = 0; i < nItems; i++)
  4051. {
  4052. int iItem = pListCtrl->GetListCtrl().GetNextItem( pos, LVNI_SELECTED );
  4053. if (iItem < 0)
  4054. return sc = S_FALSE; // we didn't advance as much as requested
  4055. pos = iItem;
  4056. }
  4057. }
  4058. else // all_items selection
  4059. {
  4060. pos += nItems;
  4061. if (pos >= nCount)
  4062. {
  4063. pos = nCount - 1;
  4064. return sc = S_FALSE; // we didn't advance as much as requested
  4065. }
  4066. }
  4067. return sc;
  4068. }
  4069. /***************************************************************************\
  4070. *
  4071. * METHOD: CNodes::ScEnumNext
  4072. *
  4073. * PURPOSE: Retrieves next item from enumeration [ Implements Nodes.Next ]
  4074. *
  4075. * PARAMETERS:
  4076. * int &pos - position to start from
  4077. * IDispatch * &pDispatch - resulting item
  4078. *
  4079. * RETURNS:
  4080. * SC - result code
  4081. *
  4082. \***************************************************************************/
  4083. SC CNodes::ScEnumNext(int &pos, IDispatch * &pDispatch)
  4084. {
  4085. DECLARE_SC(sc, TEXT("CNodes::ScEnumNext"));
  4086. // get the index of next item
  4087. sc = ScAdvancePosition( pos, 1 /*nItems*/ );
  4088. if (sc.IsError() || sc == SC(S_FALSE))
  4089. return sc;
  4090. // get the result node for the index
  4091. PNODE pNode = NULL;
  4092. sc = ScGetNode( pos, &pNode );
  4093. if (sc)
  4094. return sc;
  4095. // assign to result
  4096. pDispatch = pNode;
  4097. return sc;
  4098. }
  4099. /***************************************************************************\
  4100. *
  4101. * METHOD: CNodes::ScEnumSkip
  4102. *
  4103. * PURPOSE: skips items in enumeration [implements Nodes.Skip method]
  4104. *
  4105. * PARAMETERS:
  4106. * unsigned long celt - positions to skip
  4107. * unsigned long &celtSkipped - result: positions skiped
  4108. * int &pos - position to update
  4109. *
  4110. * RETURNS:
  4111. * SC - result code
  4112. *
  4113. \***************************************************************************/
  4114. SC CNodes::ScEnumSkip(unsigned long celt,unsigned long &celtSkipped, int &pos)
  4115. {
  4116. DECLARE_SC(sc, TEXT("CNodes::ScEnumSkip"));
  4117. // init val.
  4118. celtSkipped = 0;
  4119. // save the position for evaluation
  4120. int org_pos = pos;
  4121. // advance the position
  4122. sc = ScAdvancePosition( pos, celt );
  4123. if (sc)
  4124. return sc;
  4125. // calculate items skipped
  4126. celtSkipped = pos - org_pos;
  4127. return sc;
  4128. }
  4129. /***************************************************************************\
  4130. *
  4131. * METHOD: CNodes::get_Count
  4132. *
  4133. * PURPOSE: returns count of object in enumeration [Implements Nodes.Count]
  4134. *
  4135. * PARAMETERS:
  4136. * PLONG pCount - storage for result
  4137. *
  4138. * RETURNS:
  4139. * HRESULT - result code
  4140. *
  4141. \***************************************************************************/
  4142. STDMETHODIMP CNodes::get_Count( PLONG pCount )
  4143. {
  4144. DECLARE_SC(sc, TEXT("CNodes::get_Count"));
  4145. // parameter check
  4146. sc = ScCheckPointers ( pCount );
  4147. if (sc)
  4148. return sc.ToHr();
  4149. // get the tied object
  4150. CCCListViewCtrl *pListCtrl = NULL;
  4151. sc = ScGetTiedObject(pListCtrl);
  4152. if(sc)
  4153. return sc.ToHr();
  4154. // recheck the pointer
  4155. sc = ScCheckPointers(pListCtrl, E_UNEXPECTED);
  4156. if(sc)
  4157. return sc.ToHr();
  4158. // get count from the control
  4159. if (m_bSelectedItemsOnly)
  4160. *pCount = pListCtrl->GetListCtrl().GetSelectedCount();
  4161. else
  4162. *pCount = pListCtrl->GetListCtrl().GetItemCount();
  4163. return sc.ToHr();
  4164. }
  4165. /***************************************************************************\
  4166. *
  4167. * METHOD: CNodes::Item
  4168. *
  4169. * PURPOSE: - returns Item from enumeration [Implements Nodes.Item]
  4170. *
  4171. * PARAMETERS:
  4172. * long Index - Index of item to retrieve
  4173. * PPNODE ppNode - storage for resulting node ptr
  4174. *
  4175. * RETURNS:
  4176. * HRESULT - result code
  4177. *
  4178. \***************************************************************************/
  4179. STDMETHODIMP CNodes::Item( long Index, PPNODE ppNode )
  4180. {
  4181. DECLARE_SC(sc, TEXT("CNodes::Item"));
  4182. // parameter check
  4183. sc = ScCheckPointers ( ppNode );
  4184. if (sc)
  4185. return sc.ToHr();
  4186. *ppNode = NULL;
  4187. // check the index
  4188. if (Index <= 0)
  4189. {
  4190. sc = E_INVALIDARG;
  4191. return sc.ToHr();
  4192. }
  4193. int iPos = -1; // just before the first item at start
  4194. // get to the right item
  4195. sc = ScAdvancePosition(iPos, Index);
  4196. if (sc == SC(S_FALSE)) // didn't get far enough?
  4197. sc = E_INVALIDARG; // means we've got the wrong Index
  4198. if (sc) // got an error?
  4199. return sc.ToHr();
  4200. // now get the node
  4201. sc = ScGetNode( iPos, ppNode );
  4202. if (sc)
  4203. return sc.ToHr();
  4204. return sc.ToHr();
  4205. }
  4206. /***************************************************************************\
  4207. *
  4208. * METHOD: CNodes::ScGetNode
  4209. *
  4210. * PURPOSE: Retrieves cached or creates new Node object
  4211. *
  4212. * PARAMETERS:
  4213. * int iIndex - index of result item
  4214. * PPNODE ppNode - storage for resulting node
  4215. *
  4216. * RETURNS:
  4217. * SC - result code
  4218. *
  4219. \***************************************************************************/
  4220. SC CNodes::ScGetNode(int iItem, PPNODE ppNode)
  4221. {
  4222. DECLARE_SC(sc, TEXT("CNodes::ScGetNode"));
  4223. // parameter check
  4224. sc = ScCheckPointers(ppNode);
  4225. if (sc)
  4226. return sc;
  4227. // initial return value
  4228. *ppNode = NULL;
  4229. // get the tied object
  4230. CCCListViewCtrl *pListCtrl = NULL;
  4231. sc = ScGetTiedObject(pListCtrl);
  4232. if(sc)
  4233. return sc;
  4234. // recheck the pointer
  4235. sc = ScCheckPointers(pListCtrl, E_UNEXPECTED);
  4236. if(sc)
  4237. return sc;
  4238. // inspect what kind of item we have
  4239. bool bScopeNode;
  4240. sc = pListCtrl->ScValidateItem( iItem, bScopeNode );
  4241. if (sc)
  4242. return sc;
  4243. if (bScopeNode)
  4244. {
  4245. // do not handle this - pass to the owner
  4246. sc = pListCtrl->ScGetScopeNodeForItem ( iItem, ppNode );
  4247. if (sc)
  4248. return sc;
  4249. return sc;
  4250. }
  4251. // "normal" list item (not a scope node) - we can handle ourselves
  4252. // find either the entry or the place to insert
  4253. col_t::iterator it = std::lower_bound(m_Nodes.begin(), m_Nodes.end(), iItem, index_less());
  4254. if (it!= m_Nodes.end() && it->first == iItem)
  4255. {
  4256. // we already have it!!! , recheck!
  4257. sc = ScCheckPointers(it->second, E_UNEXPECTED);
  4258. if (sc)
  4259. return sc;
  4260. // return it!
  4261. *ppNode = it->second;
  4262. (*ppNode)->AddRef();
  4263. return sc;
  4264. }
  4265. // doesn't exist - need to create one
  4266. typedef CComObject<CMMCResultNode> CResultNode;
  4267. CResultNode *pResultNode = NULL;
  4268. CResultNode::CreateInstance(&pResultNode);
  4269. sc = ScCheckPointers(pResultNode, E_OUTOFMEMORY);
  4270. if(sc)
  4271. return sc;
  4272. // update the information on the node
  4273. pResultNode->m_iIndex = iItem;
  4274. pResultNode->m_pNodes = this;
  4275. m_Nodes.insert(it, col_entry_t(iItem, pResultNode));
  4276. // return it!
  4277. *ppNode = pResultNode;
  4278. (*ppNode)->AddRef();
  4279. return sc;
  4280. }
  4281. /***************************************************************************\
  4282. *
  4283. * METHOD: CNodes::ScGetDisplayName
  4284. *
  4285. * PURPOSE: retrievs the display name of the Node
  4286. *
  4287. * PARAMETERS:
  4288. * int iIndex - index of the result item
  4289. * CComBSTR& bstrName - storage for resulting text
  4290. *
  4291. * RETURNS:
  4292. * SC - result code
  4293. *
  4294. \***************************************************************************/
  4295. SC CNodes::ScGetDisplayName(int iItem, CComBSTR& bstrName)
  4296. {
  4297. DECLARE_SC(sc, TEXT("CNodes::ScGetDisplayName"));
  4298. // get the tied object
  4299. CCCListViewCtrl *pListCtrl = NULL;
  4300. sc = ScGetTiedObject(pListCtrl);
  4301. if(sc)
  4302. return sc;
  4303. // recheck the pointer
  4304. sc = ScCheckPointers(pListCtrl, E_UNEXPECTED);
  4305. if(sc)
  4306. return sc;
  4307. // check the index
  4308. if (iItem < 0 || iItem >= pListCtrl->GetListCtrl().GetItemCount())
  4309. return sc = E_INVALIDARG;
  4310. // get the text
  4311. bstrName = pListCtrl->GetListCtrl().GetItemText( iItem, 0 /*column*/);
  4312. return sc;
  4313. }
  4314. /***************************************************************************\
  4315. *
  4316. * METHOD: CNodes::ScUnadviseNodeObj
  4317. *
  4318. * PURPOSE: Remove Node from collection. called from ~CMMCResultNode()
  4319. *
  4320. * PARAMETERS:
  4321. * CMMCResultNode *node - node to remove
  4322. *
  4323. * RETURNS:
  4324. * SC - result code
  4325. *
  4326. \***************************************************************************/
  4327. SC CNodes::ScUnadviseNodeObj(CMMCResultNode *node)
  4328. {
  4329. DECLARE_SC(sc, TEXT("CNodes::ScUnadviseNodeObj"));
  4330. // parameter check
  4331. sc = ScCheckPointers(node);
  4332. if (sc)
  4333. return sc;
  4334. // index of the node
  4335. int iIndex = node->m_iIndex;
  4336. // find the entry by index
  4337. col_t::iterator it = std::lower_bound(m_Nodes.begin(), m_Nodes.end(), iIndex, index_less());
  4338. if (it== m_Nodes.end() || it->first != iIndex)
  4339. {
  4340. // we do not have it ???
  4341. sc = E_UNEXPECTED;
  4342. return sc;
  4343. }
  4344. // remove from collection
  4345. m_Nodes.erase(it);
  4346. return sc;
  4347. }
  4348. /***************************************************************************\
  4349. *
  4350. * METHOD: CNodes::ScOnListViewIndexesReset
  4351. *
  4352. * PURPOSE: Fired Event handler. Wipes the cached info
  4353. *
  4354. * PARAMETERS:
  4355. *
  4356. * RETURNS:
  4357. * SC - result code
  4358. *
  4359. \***************************************************************************/
  4360. SC CNodes::ScOnListViewIndexesReset()
  4361. {
  4362. DECLARE_SC(sc, TEXT("CNodes::ScOnListViewIndexesReset"));
  4363. InvalidateConnectedNodes();
  4364. return sc;
  4365. }
  4366. /***************************************************************************\
  4367. *
  4368. * METHOD: CNodes::InvalidateConnectedNodes
  4369. *
  4370. * PURPOSE: wipes out the cache. invalidates alive nodes
  4371. *
  4372. * PARAMETERS:
  4373. *
  4374. * RETURNS:
  4375. * SC - result code
  4376. *
  4377. \***************************************************************************/
  4378. void CNodes::InvalidateConnectedNodes()
  4379. {
  4380. DECLARE_SC(sc, TEXT("CNodes::ScOnListViewIndexesReset"));
  4381. // orphan all alive nodes - we do not keep pointers
  4382. col_t::iterator it;
  4383. for (it = m_Nodes.begin(); it != m_Nodes.end(); ++it)
  4384. {
  4385. // get the pointer to com object
  4386. CMMCResultNode * const pNode = it->second;
  4387. sc = ScCheckPointers(pNode, E_POINTER);
  4388. if (sc)
  4389. {
  4390. sc.TraceAndClear();
  4391. continue;
  4392. }
  4393. // reset the container info
  4394. pNode->Invalidate();
  4395. }
  4396. // clear the collection;
  4397. m_Nodes.clear();
  4398. }
  4399. /***************************************************************************\
  4400. *
  4401. * METHOD: CNodes::ScOnListViewItemInserted
  4402. *
  4403. * PURPOSE: Fired Event handler. shifts index info
  4404. *
  4405. * PARAMETERS:
  4406. * int iIndex - index of newly inserted item
  4407. *
  4408. * RETURNS:
  4409. * SC - result code
  4410. *
  4411. \***************************************************************************/
  4412. SC CNodes::ScOnListViewItemInserted(int iIndex)
  4413. {
  4414. DECLARE_SC(sc, TEXT("CNodes::ScOnListViewItemInserted"));
  4415. // find the insertion point
  4416. col_t::iterator it = std::lower_bound(m_Nodes.begin(), m_Nodes.end(), iIndex, index_less());
  4417. // increment all the entries following it
  4418. while (it != m_Nodes.end())
  4419. {
  4420. // increment index in own collection
  4421. ++(it->first);
  4422. // get the pointer to com object
  4423. CMMCResultNode * const pNode = it->second;
  4424. sc = ScCheckPointers(pNode, E_UNEXPECTED);
  4425. if (sc)
  4426. return sc;
  4427. // increment member on com object
  4428. ++(pNode->m_iIndex);
  4429. // get to the next item
  4430. ++it;
  4431. }
  4432. return sc;
  4433. }
  4434. /***************************************************************************\
  4435. *
  4436. * METHOD: CNodes::ScOnListViewItemDeleted
  4437. *
  4438. * PURPOSE: Fired Event handler. shifts index info
  4439. *
  4440. * PARAMETERS:
  4441. * int iIndex - index of removed item
  4442. *
  4443. * RETURNS:
  4444. * SC - result code
  4445. *
  4446. \***************************************************************************/
  4447. SC CNodes::ScOnListViewItemDeleted (int iIndex)
  4448. {
  4449. DECLARE_SC(sc, TEXT("CNodes::ScOnlistViewItemDeleted"));
  4450. // find the insertion point
  4451. col_t::iterator it = std::lower_bound(m_Nodes.begin(), m_Nodes.end(), iIndex, index_less());
  4452. // if we have an object at the position, get rid of it!
  4453. if (it != m_Nodes.end() && it->first == iIndex)
  4454. {
  4455. // get pointer to the object
  4456. CMMCResultNode * const pNode = it->second;
  4457. sc = ScCheckPointers(pNode, E_UNEXPECTED);
  4458. if (sc)
  4459. return sc;
  4460. // reset the container info
  4461. pNode->Invalidate();
  4462. it = m_Nodes.erase(it);
  4463. }
  4464. // decrement all the entries following it
  4465. while (it != m_Nodes.end())
  4466. {
  4467. // decrement index in own collection
  4468. --(it->first);
  4469. // get the pointer to com object
  4470. CMMCResultNode * const pNode = it->second;
  4471. sc = ScCheckPointers(pNode, E_UNEXPECTED);
  4472. if (sc)
  4473. return sc;
  4474. // decrement member on com object
  4475. --(pNode->m_iIndex);
  4476. // get to the next item
  4477. ++it;
  4478. }
  4479. return sc;
  4480. }
  4481. /***************************************************************************\
  4482. *
  4483. * METHOD: CNodes::IsTiedToThisList
  4484. *
  4485. * PURPOSE: this method is called from node which needs to know if it
  4486. * belongs to the the this list (as a result item on it)
  4487. *
  4488. * PARAMETERS:
  4489. * CCCListViewCtrl *pvc
  4490. *
  4491. * RETURNS:
  4492. * false if unconnected or belongs to other list
  4493. *
  4494. \***************************************************************************/
  4495. bool CNodes::IsTiedToThisList(CCCListViewCtrl *pvc)
  4496. {
  4497. DECLARE_SC(sc, TEXT("CNodes::IsTiedToThisList"));
  4498. // get the tied object
  4499. CCCListViewCtrl *pListCtrl = NULL;
  4500. sc = ScGetTiedObject(pListCtrl);
  4501. if(sc)
  4502. return false;
  4503. // recheck the pointer
  4504. sc = ScCheckPointers(pListCtrl, E_UNEXPECTED);
  4505. if(sc)
  4506. return false;
  4507. return (pListCtrl == pvc);
  4508. }
  4509. //############################################################################
  4510. //############################################################################
  4511. //
  4512. // Implementation of class CMMCResultNode
  4513. //
  4514. //############################################################################
  4515. //############################################################################
  4516. /***************************************************************************\
  4517. *
  4518. * METHOD: CMMCResultNode::CMMCResultNode
  4519. *
  4520. * PURPOSE: default constructor
  4521. *
  4522. * PARAMETERS:
  4523. *
  4524. \***************************************************************************/
  4525. CMMCResultNode::CMMCResultNode() : m_pNodes(NULL), m_iIndex(-1)
  4526. {
  4527. DECLARE_SC(sc, TEXT("CMMCResultNode::CMMCResultNode"));
  4528. Invalidate();
  4529. }
  4530. /***************************************************************************\
  4531. *
  4532. * METHOD: CMMCResultNode::~CMMCResultNode
  4533. *
  4534. * PURPOSE: Destructor
  4535. *
  4536. * PARAMETERS:
  4537. *
  4538. \***************************************************************************/
  4539. CMMCResultNode::~CMMCResultNode()
  4540. {
  4541. DECLARE_SC(sc, TEXT("CMMCResultNode::~CMMCResultNode"));
  4542. // informing container about desruction
  4543. if (m_pNodes)
  4544. {
  4545. sc = m_pNodes->ScUnadviseNodeObj(this);
  4546. if (sc)
  4547. sc.TraceAndClear();
  4548. }
  4549. }
  4550. /***************************************************************************\
  4551. *
  4552. * METHOD: CMMCResultNode::get_Name
  4553. *
  4554. * PURPOSE: Returns the display name of the node.
  4555. *
  4556. * PARAMETERS:
  4557. * PBSTR pbstrName - result (name)
  4558. *
  4559. * RETURNS:
  4560. * HRESULT - result code
  4561. *
  4562. \***************************************************************************/
  4563. STDMETHODIMP
  4564. CMMCResultNode::get_Name( PBSTR pbstrName)
  4565. {
  4566. DECLARE_SC(sc, TEXT("CMMCResultNode::get_Name"));
  4567. // check the parameters
  4568. sc = ScCheckPointers( pbstrName );
  4569. if (sc)
  4570. return sc.ToHr();
  4571. // initialize output
  4572. *pbstrName = NULL;
  4573. // check the container
  4574. sc = ScCheckPointers( m_pNodes, E_FAIL );
  4575. if (sc)
  4576. return sc.ToHr();
  4577. // ask owner about the name
  4578. CComBSTR bstrResult;
  4579. sc = m_pNodes->ScGetDisplayName(m_iIndex, bstrResult);
  4580. if (sc)
  4581. return sc.ToHr();
  4582. // return the result result
  4583. *pbstrName = bstrResult.Detach();
  4584. // recheck pointer before return
  4585. sc = ScCheckPointers( *pbstrName, E_UNEXPECTED );
  4586. if (sc)
  4587. return sc.ToHr();
  4588. return sc.ToHr();
  4589. }
  4590. /*+-------------------------------------------------------------------------*
  4591. *
  4592. * CMMCResultNode::ScGetAMCView
  4593. *
  4594. * PURPOSE: Returns a pointer to the view.
  4595. *
  4596. * PARAMETERS:
  4597. * CAMCView ** ppAMCView :
  4598. *
  4599. * RETURNS:
  4600. * SC
  4601. *
  4602. *+-------------------------------------------------------------------------*/
  4603. SC
  4604. CMMCResultNode::ScGetAMCView(CAMCView **ppAMCView)
  4605. {
  4606. DECLARE_SC(sc, TEXT("CMMCResultNode::ScGetAMCView"));
  4607. // check parameters
  4608. sc = ScCheckPointers(ppAMCView);
  4609. if(sc)
  4610. return sc;
  4611. // init out parameter
  4612. *ppAMCView = NULL;
  4613. // check the container
  4614. sc = ScCheckPointers( m_pNodes, E_FAIL );
  4615. if (sc)
  4616. return sc;
  4617. CCCListViewCtrl *pListCtrl = NULL;
  4618. sc = m_pNodes->ScGetListCtrl(& pListCtrl);
  4619. if(sc)
  4620. return sc;
  4621. sc = ScCheckPointers(pListCtrl, E_UNEXPECTED);
  4622. if(sc)
  4623. return sc;
  4624. sc = pListCtrl->ScGetAMCView(ppAMCView);
  4625. return sc;
  4626. }
  4627. /*+-------------------------------------------------------------------------*
  4628. *
  4629. * CMMCResultNode::get_Property
  4630. *
  4631. * PURPOSE: Returns the specified clipboard format data (must be a text
  4632. * format) for the node.
  4633. *
  4634. * PARAMETERS:
  4635. * BSTR PropertyName :
  4636. * PBSTR PropertyValue :
  4637. *
  4638. * RETURNS:
  4639. * STDMETHODIMP
  4640. *
  4641. *+-------------------------------------------------------------------------*/
  4642. STDMETHODIMP
  4643. CMMCResultNode::get_Property( BSTR PropertyName, PBSTR PropertyValue)
  4644. {
  4645. DECLARE_SC(sc, TEXT("CMMCResultNode::get_Property"));
  4646. CAMCView *pAMCView = NULL;
  4647. sc = ScGetAMCView(&pAMCView);
  4648. if(sc)
  4649. return sc.ToHr();
  4650. sc = ScCheckPointers(pAMCView, E_UNEXPECTED);
  4651. if(sc)
  4652. return sc.ToHr();
  4653. sc = pAMCView->ScGetProperty(m_iIndex, PropertyName, PropertyValue);
  4654. return sc.ToHr();
  4655. }
  4656. /*+-------------------------------------------------------------------------*
  4657. *
  4658. * CMMCResultNode::get_Nodetype
  4659. *
  4660. * PURPOSE: Returns the GUID nodetype identifier for the node.
  4661. *
  4662. * PARAMETERS:
  4663. * PBSTR Nodetype : [out] the nodetype identifier.
  4664. *
  4665. * RETURNS:
  4666. * STDMETHODIMP
  4667. *
  4668. *+-------------------------------------------------------------------------*/
  4669. STDMETHODIMP
  4670. CMMCResultNode::get_Nodetype(PBSTR Nodetype)
  4671. {
  4672. DECLARE_SC(sc, TEXT("CMMCResultNode::get_Nodetype"));
  4673. CAMCView *pAMCView = NULL;
  4674. sc = ScGetAMCView(&pAMCView);
  4675. if(sc)
  4676. return sc.ToHr();
  4677. sc = ScCheckPointers(pAMCView, E_UNEXPECTED);
  4678. if(sc)
  4679. return sc.ToHr();
  4680. sc = pAMCView->ScGetNodetype(m_iIndex, Nodetype);
  4681. return sc.ToHr();
  4682. }
  4683. /***************************************************************************\
  4684. *
  4685. * METHOD: CMMCResultNode::get_Bookmark
  4686. *
  4687. * PURPOSE: Returns error always - not valid for result items
  4688. *
  4689. * PARAMETERS:
  4690. * PBSTR pbstrBookmark
  4691. *
  4692. * RETURNS:
  4693. * HRESULT - result code
  4694. *
  4695. \***************************************************************************/
  4696. STDMETHODIMP
  4697. CMMCResultNode::get_Bookmark( PBSTR pbstrBookmark )
  4698. {
  4699. DECLARE_SC(sc, TEXT("CMMCResultNode::get_Bookmark"));
  4700. // check the parameters
  4701. sc = ScCheckPointers( pbstrBookmark );
  4702. if (sc)
  4703. return sc.ToHr();
  4704. // initialize output
  4705. *pbstrBookmark = NULL;
  4706. // report the error - always
  4707. sc = ScFromMMC( MMC_E_NO_BOOKMARK );
  4708. return sc.ToHr();
  4709. }
  4710. /***************************************************************************\
  4711. *
  4712. * METHOD: CMMCResultNode::IsScopeNode
  4713. *
  4714. * PURPOSE: returns TRUE if it's a scope node ( i.e. always returns FALSE)
  4715. *
  4716. * PARAMETERS:
  4717. * PBOOL pbIsScopeNode
  4718. *
  4719. * RETURNS:
  4720. * HRESULT - result code
  4721. *
  4722. \***************************************************************************/
  4723. STDMETHODIMP
  4724. CMMCResultNode::IsScopeNode(PBOOL pbIsScopeNode)
  4725. {
  4726. DECLARE_SC(sc, TEXT("CMMCResultNode::IsScopeNode"));
  4727. sc = ScCheckPointers( pbIsScopeNode );
  4728. if(sc)
  4729. return sc.ToHr();
  4730. // if it's here it's for sure not a scope node
  4731. *pbIsScopeNode = FALSE;
  4732. return sc.ToHr();
  4733. }
  4734. /*+-------------------------------------------------------------------------*
  4735. * CCCListViewCtrl::ScAllocResultItem
  4736. *
  4737. * Allocates a CResultItem for a list control item.
  4738. *--------------------------------------------------------------------------*/
  4739. SC CCCListViewCtrl::ScAllocResultItem (
  4740. CResultItem*& pri, /* O:new list item */
  4741. COMPONENTID id, /* I:owning component ID */
  4742. LPARAM lSnapinData, /* I:snap-in's data for this item */
  4743. int nImage) /* I:image index */
  4744. {
  4745. DECLARE_SC (sc, _T("CCCListViewCtrl::ScAllocResultItem"));
  4746. pri = new CResultItem (id, lSnapinData, nImage);
  4747. sc = ScCheckPointers (pri, E_OUTOFMEMORY);
  4748. if (sc)
  4749. return (sc);
  4750. return (sc);
  4751. }
  4752. /*+-------------------------------------------------------------------------*
  4753. * CCCListViewCtrl::ScFreeResultItem
  4754. *
  4755. * Frees a CResultItem that was allocated with ScAllocResultItem.
  4756. *--------------------------------------------------------------------------*/
  4757. SC CCCListViewCtrl::ScFreeResultItem (
  4758. CResultItem* priFree) /* I:list item to free */
  4759. {
  4760. DECLARE_SC (sc, _T("CCCListViewCtrl::ScFreeResultItem"));
  4761. sc = ScCheckPointers (priFree, E_UNEXPECTED);
  4762. if (sc)
  4763. return (sc);
  4764. delete priFree;
  4765. return (sc);
  4766. }
  4767. /***************************************************************************\
  4768. *
  4769. * METHOD: CCCListViewCtrl::Scget_Columns
  4770. *
  4771. * PURPOSE: returns pointer to Columns object; create one if required
  4772. *
  4773. * PARAMETERS:
  4774. * PPCOLUMNS ppColumns - resulting pointer
  4775. *
  4776. * RETURNS:
  4777. * SC - result code
  4778. *
  4779. \***************************************************************************/
  4780. SC CCCListViewCtrl::Scget_Columns(PPCOLUMNS ppColumns)
  4781. {
  4782. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_Columns"));
  4783. // Check received parameters
  4784. sc = ScCheckPointers(ppColumns);
  4785. if (sc)
  4786. return sc;
  4787. // initialize
  4788. *ppColumns = NULL;
  4789. // create the object when required
  4790. sc = CTiedComObjectCreator<CColumns>::ScCreateAndConnect(*this, m_spColumns);
  4791. if (sc)
  4792. return sc;
  4793. // recheck the pointer
  4794. sc = ScCheckPointers(m_spColumns, E_UNEXPECTED);
  4795. if (sc)
  4796. return sc;
  4797. // return the pointer
  4798. *ppColumns = m_spColumns;
  4799. (*ppColumns)->AddRef();
  4800. return sc;
  4801. }
  4802. /***************************************************************************\
  4803. *
  4804. * METHOD: CCCListViewCtrl::Scget_Count
  4805. *
  4806. * PURPOSE: returns the count of columns in LV
  4807. *
  4808. * PARAMETERS:
  4809. * PLONG pCount
  4810. *
  4811. * RETURNS:
  4812. * SC - result code
  4813. *
  4814. \***************************************************************************/
  4815. SC CCCListViewCtrl::Scget_Count( PLONG pCount )
  4816. {
  4817. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_Count"));
  4818. // Check received parameters
  4819. sc = ScCheckPointers(pCount);
  4820. if (sc)
  4821. return sc;
  4822. // return the result
  4823. *pCount = GetColCount();
  4824. return sc;
  4825. }
  4826. /***************************************************************************\
  4827. *
  4828. * METHOD: CCCListViewCtrl::ScEnumNext
  4829. *
  4830. * PURPOSE: advances position pointer for Columns enum. returns the object at the pos
  4831. *
  4832. * PARAMETERS:
  4833. * int &iZeroBasedPos - position to modify
  4834. * PDISPATCH & pDispatch - resulting pointer
  4835. *
  4836. * RETURNS:
  4837. * SC - result code
  4838. *
  4839. \***************************************************************************/
  4840. SC CCCListViewCtrl::ScEnumNext(int &iZeroBasedPos, PDISPATCH & pDispatch)
  4841. {
  4842. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScEnumNext"));
  4843. // initialize
  4844. pDispatch = NULL;
  4845. // advance;
  4846. iZeroBasedPos++;
  4847. // recheck the pos
  4848. if (iZeroBasedPos < 0)
  4849. return sc = E_UNEXPECTED;
  4850. // no more columns?
  4851. if (iZeroBasedPos >= GetColCount())
  4852. return sc = S_FALSE;
  4853. // retrieve the column
  4854. ColumnPtr spColumn;
  4855. // ScItem accepts 1-based index
  4856. sc = ScItem( iZeroBasedPos + 1, &spColumn );
  4857. if (sc)
  4858. return sc;
  4859. //return the interface.
  4860. pDispatch = spColumn.Detach();
  4861. return sc;
  4862. }
  4863. /***************************************************************************\
  4864. *
  4865. * METHOD: CCCListViewCtrl::ScEnumSkip
  4866. *
  4867. * PURPOSE: skips several items for Columns enum
  4868. *
  4869. * PARAMETERS:
  4870. * unsigned long celt
  4871. * unsigned long& celtSkipped
  4872. * int &iZeroBasedPos
  4873. *
  4874. * RETURNS:
  4875. * SC - result code
  4876. *
  4877. \***************************************************************************/
  4878. SC CCCListViewCtrl::ScEnumSkip(unsigned long celt, unsigned long& celtSkipped, int &iZeroBasedPos)
  4879. {
  4880. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScEnumSkip"));
  4881. // init [out] param
  4882. celtSkipped = 0;
  4883. // recheck the pos
  4884. if (iZeroBasedPos < -1)
  4885. return sc = E_UNEXPECTED;
  4886. // already past the end?
  4887. if (iZeroBasedPos >= GetColCount())
  4888. return sc = S_FALSE;
  4889. // how far can we advance ?;
  4890. celtSkipped = GetColCount() - iZeroBasedPos;
  4891. if (celtSkipped > celt)
  4892. celtSkipped = celt;
  4893. // advance
  4894. iZeroBasedPos += celtSkipped;
  4895. return sc = ((celtSkipped == celt) ? S_OK : S_FALSE);
  4896. }
  4897. /***************************************************************************\
  4898. *
  4899. * METHOD: CCCListViewCtrl::ScEnumReset
  4900. *
  4901. * PURPOSE: resets position index for Columns enum
  4902. *
  4903. * PARAMETERS:
  4904. * int &iZeroBasedPos position to modify
  4905. *
  4906. * RETURNS:
  4907. * SC - result code
  4908. *
  4909. \***************************************************************************/
  4910. SC CCCListViewCtrl::ScEnumReset(int &iZeroBasedPos)
  4911. {
  4912. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScEnumReset"));
  4913. iZeroBasedPos = -1;
  4914. return sc;
  4915. }
  4916. /***************************************************************************\
  4917. *
  4918. * METHOD: CCCListViewCtrl::ScItem
  4919. *
  4920. * PURPOSE: returns Column com object from Columns collection
  4921. *
  4922. * PARAMETERS:
  4923. * long lOneBasedIndex - [in] - column index (1 based)
  4924. * PPCOLUMN ppColumn - [out] - resulting object
  4925. *
  4926. * RETURNS:
  4927. * SC - result code
  4928. *
  4929. \***************************************************************************/
  4930. SC CCCListViewCtrl::ScItem( long lOneBasedIndex, PPCOLUMN ppColumn )
  4931. {
  4932. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScItem"));
  4933. // Check received parameters
  4934. sc = ScCheckPointers(ppColumn);
  4935. if (sc)
  4936. return sc;
  4937. // initialize output
  4938. *ppColumn = NULL;
  4939. // check the index
  4940. int iZeroBasedIndex = lOneBasedIndex - 1;
  4941. if (iZeroBasedIndex < 0 || iZeroBasedIndex >= GetColCount())
  4942. return sc = ::ScFromMMC(MMC_E_INVALID_COLUMN_INDEX);
  4943. // construct the object
  4944. typedef CComObject<CColumn> CComColumn;
  4945. ColumnPtr /*CComPtr<CComColumn>*/ spColumn;
  4946. // create the object when required
  4947. sc = CTiedComObjectCreator<CColumn>::ScCreateAndConnect(*this, spColumn);
  4948. if (sc)
  4949. return sc;
  4950. // get 'raw' pointer
  4951. CComColumn *pColumn = dynamic_cast<CComColumn *>(spColumn.GetInterfacePtr());
  4952. // recheck the pointer
  4953. sc = ScCheckPointers(pColumn, E_UNEXPECTED);
  4954. if (sc)
  4955. return sc;
  4956. // initialize the object
  4957. pColumn->SetIndex(iZeroBasedIndex);
  4958. // let it observe what's going on and manage its own index
  4959. AddObserver(static_cast<CListViewObserver&>(*pColumn));
  4960. // return the pointer
  4961. *ppColumn = spColumn;
  4962. (*ppColumn)->AddRef();
  4963. return sc;
  4964. }
  4965. /***************************************************************************\
  4966. *
  4967. * METHOD: CCCListViewCtrl::ScName
  4968. *
  4969. * PURPOSE: Returns column name. Implements Column.Name property
  4970. *
  4971. * PARAMETERS:
  4972. * BSTR *Name - the returned name
  4973. * int iZeroBasedColIndex - index of column of interest
  4974. *
  4975. * RETURNS:
  4976. * SC - result code
  4977. *
  4978. \***************************************************************************/
  4979. SC CCCListViewCtrl::ScName( /*[out, retval]*/ BSTR *Name, int iZeroBasedColIndex )
  4980. {
  4981. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScName"));
  4982. // Check received parameters
  4983. sc = ScCheckPointers(Name);
  4984. if (sc)
  4985. return sc;
  4986. // initialize output
  4987. *Name = NULL;
  4988. // recheck the column index
  4989. // (it's not something the script sent - it's internal data)
  4990. if (iZeroBasedColIndex < 0 || iZeroBasedColIndex >= GetColCount())
  4991. return sc = E_UNEXPECTED;
  4992. LPOLESTR pstrName = NULL;
  4993. sc = GetColumn(iZeroBasedColIndex, &pstrName, MMCLV_NOPTR, MMCLV_NOPTR);
  4994. if (sc)
  4995. return sc;
  4996. // recheck the pointer
  4997. sc = ScCheckPointers(pstrName, E_UNEXPECTED);
  4998. if (sc)
  4999. return sc;
  5000. *Name = ::SysAllocString(pstrName);
  5001. ::CoTaskMemFree(pstrName);
  5002. // recheck the result
  5003. sc = ScCheckPointers(*Name, E_OUTOFMEMORY);
  5004. if (sc)
  5005. return sc;
  5006. return sc;
  5007. }
  5008. /***************************************************************************\
  5009. *
  5010. * METHOD: CCCListViewCtrl::ScGetColumnData
  5011. *
  5012. * PURPOSE: helper for Column com object implementation
  5013. * - checks column index
  5014. * - retrieves information about the column
  5015. *
  5016. * PARAMETERS:
  5017. * int iZeroBasedColIndex - column index
  5018. * ColumnData *pColData - storage for resulting data
  5019. *
  5020. * RETURNS:
  5021. * SC - result code
  5022. *
  5023. \***************************************************************************/
  5024. SC CCCListViewCtrl::ScGetColumnData( int iZeroBasedColIndex, ColumnData *pColData )
  5025. {
  5026. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScGetColumnData"));
  5027. // Check received parameters (its internal function, so it's unexpected if the params are bad)
  5028. sc = ScCheckPointers(pColData, E_UNEXPECTED);
  5029. if (sc)
  5030. return sc;
  5031. // init the structure;
  5032. pColData->Init();
  5033. // recheck the column index
  5034. // (it's not something the script sent - it's internal data)
  5035. if (iZeroBasedColIndex < 0 || iZeroBasedColIndex >= GetColCount())
  5036. return sc = E_UNEXPECTED;
  5037. // need to get the header control for managing columns
  5038. CAMCHeaderCtrl* pHeader = GetHeaderCtrl();
  5039. // check!
  5040. sc = ScCheckPointers(pHeader, E_UNEXPECTED);
  5041. if (sc)
  5042. return sc;
  5043. // get the lParam
  5044. HDITEM hdItem;
  5045. ::ZeroMemory(&hdItem, sizeof(hdItem));
  5046. hdItem.mask = HDI_LPARAM | HDI_WIDTH | HDI_ORDER;
  5047. BOOL bRet = pHeader->GetItem(iZeroBasedColIndex, &hdItem);
  5048. if (!bRet)
  5049. return sc = E_FAIL;
  5050. CHiddenColumnInfo hci (hdItem.lParam);
  5051. pColData->iColumnOrder = hdItem.iOrder;
  5052. pColData->bIsHidden = hci.fHidden;
  5053. pColData->iColumnWidth = hdItem.cxy;
  5054. if (pColData->bIsHidden) // special case for hidden columns
  5055. pColData->iColumnWidth = hci.cx;
  5056. return sc;
  5057. }
  5058. /***************************************************************************\
  5059. *
  5060. * METHOD: CCCListViewCtrl::ScSetColumnData
  5061. *
  5062. * PURPOSE: helper for Column com object implementation
  5063. * - modifies column
  5064. * NOTE - not to be used for SHOW/HIDE operations
  5065. *
  5066. * PARAMETERS:
  5067. * int iZeroBasedColIndex - column index
  5068. * const ColumnData& rColData - modified column data
  5069. *
  5070. * RETURNS:
  5071. * SC - result code
  5072. *
  5073. \***************************************************************************/
  5074. SC CCCListViewCtrl::ScSetColumnData( int iZeroBasedColIndex, const ColumnData& rColData )
  5075. {
  5076. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScSetColumnData"));
  5077. ColumnData oldColData;
  5078. sc = ScGetColumnData( iZeroBasedColIndex, &oldColData );
  5079. if (sc)
  5080. return sc;
  5081. // check if anything has changed
  5082. if (oldColData == rColData)
  5083. return sc;
  5084. // the visibility of column cannot be changed directly
  5085. // the snapin has be notified about that.
  5086. // the request should never come here
  5087. if (rColData.bIsHidden != oldColData.bIsHidden)
  5088. return sc = E_UNEXPECTED;
  5089. // need to get the header control for managing columns
  5090. CAMCHeaderCtrl* pHeader = GetHeaderCtrl();
  5091. // check!
  5092. sc = ScCheckPointers(pHeader, E_UNEXPECTED);
  5093. if (sc)
  5094. return sc;
  5095. // now set the new data
  5096. HDITEM hdItem;
  5097. ::ZeroMemory(&hdItem, sizeof(hdItem));
  5098. // set the width properly (no mater if colum is hidden)
  5099. if (rColData.bIsHidden)
  5100. {
  5101. CHiddenColumnInfo hci (rColData.iColumnWidth, true);
  5102. hdItem.lParam = hci.lParam;
  5103. hdItem.mask = HDI_LPARAM;
  5104. }
  5105. else
  5106. {
  5107. hdItem.mask = HDI_WIDTH;
  5108. hdItem.cxy = rColData.iColumnWidth;
  5109. }
  5110. // set the order info
  5111. hdItem.mask |= HDI_ORDER;
  5112. hdItem.iOrder = rColData.iColumnOrder;
  5113. // set the column data
  5114. BOOL bRet = pHeader->SetItem(iZeroBasedColIndex, &hdItem);
  5115. if (!bRet)
  5116. return sc = E_FAIL;
  5117. return sc;
  5118. }
  5119. /***************************************************************************\
  5120. *
  5121. * METHOD: CCCListViewCtrl::Scget_Width
  5122. *
  5123. * PURPOSE: Returns width of column. Implements get for Column.Width
  5124. *
  5125. * PARAMETERS:
  5126. * PLONG Width - resulting width
  5127. * int iZeroBasedColIndex - index of column
  5128. *
  5129. * RETURNS:
  5130. * SC - result code
  5131. *
  5132. \***************************************************************************/
  5133. SC CCCListViewCtrl::Scget_Width( /*[out, retval]*/ PLONG Width, int iZeroBasedColIndex )
  5134. {
  5135. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_Width"));
  5136. // Check received parameters
  5137. sc = ScCheckPointers(Width);
  5138. if (sc)
  5139. return sc;
  5140. // initialize output
  5141. *Width = 0;
  5142. // retrieve data for column (this also checks the index)
  5143. ColumnData strColData;
  5144. sc = ScGetColumnData( iZeroBasedColIndex, &strColData );
  5145. if (sc)
  5146. return sc;
  5147. *Width = strColData.iColumnWidth;
  5148. return sc;
  5149. }
  5150. /***************************************************************************\
  5151. *
  5152. * METHOD: CCCListViewCtrl::Scput_Width
  5153. *
  5154. * PURPOSE: Sets width of column. Implements put for Column.Width
  5155. *
  5156. * PARAMETERS:
  5157. * LONG Width - new width
  5158. * int iZeroBasedColIndex - index of column
  5159. *
  5160. * RETURNS:
  5161. * SC - result code
  5162. *
  5163. \***************************************************************************/
  5164. SC CCCListViewCtrl::Scput_Width( /*[in]*/ long Width, int iZeroBasedColIndex )
  5165. {
  5166. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scput_Width"));
  5167. ColumnData strColData;
  5168. // retrieve current column data
  5169. sc = ScGetColumnData( iZeroBasedColIndex, &strColData );
  5170. if (sc)
  5171. return sc;
  5172. // change the width
  5173. strColData.iColumnWidth = Width;
  5174. // set modified column data
  5175. sc = ScSetColumnData( iZeroBasedColIndex, strColData );
  5176. if (sc)
  5177. return sc;
  5178. return sc;
  5179. }
  5180. /***************************************************************************\
  5181. *
  5182. * METHOD: CCCListViewCtrl::Scget_DisplayPosition
  5183. *
  5184. * PURPOSE: Returns display position of column. Imnplements get for Column.DisplayPosition
  5185. *
  5186. * PARAMETERS:
  5187. * PLONG DisplayPosition - display position ( 1 based )
  5188. * int iZeroBasedColIndex - index of column
  5189. *
  5190. * RETURNS:
  5191. * SC - result code
  5192. *
  5193. \***************************************************************************/
  5194. SC CCCListViewCtrl::Scget_DisplayPosition( /*[out, retval]*/ PLONG DisplayPosition, int iZeroBasedColIndex )
  5195. {
  5196. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_DisplayPosition"));
  5197. // Check received parameters
  5198. sc = ScCheckPointers(DisplayPosition);
  5199. if (sc)
  5200. return sc;
  5201. // initialize
  5202. *DisplayPosition = 0;
  5203. // retrieve data for column (this also checks the index)
  5204. ColumnData strColData;
  5205. sc = ScGetColumnData( iZeroBasedColIndex, &strColData );
  5206. if (sc)
  5207. return sc;
  5208. // it's not legal for hidden columns ( or unfair at least :-)
  5209. if (strColData.bIsHidden)
  5210. return sc = E_UNEXPECTED;
  5211. int iColumnOrder = strColData.iColumnOrder;
  5212. int iDisplayPosition = iColumnOrder + 1;
  5213. // that would be it. BUT we may have hidden columns with smaller order numbers
  5214. // we need ti iteratre to find it out
  5215. int nColumnCount = GetColCount();
  5216. for (int i = 0; i <nColumnCount; i++)
  5217. {
  5218. // retrieve data for column (this also checks the index)
  5219. sc = ScGetColumnData( i, &strColData );
  5220. if (sc)
  5221. return sc;
  5222. // we will not take into account any hidden column
  5223. if (strColData.iColumnOrder < iColumnOrder && strColData.bIsHidden)
  5224. {
  5225. // decrement position, since hidden columns do not affect visual position
  5226. iDisplayPosition --;
  5227. }
  5228. }
  5229. // return the display position
  5230. *DisplayPosition = iDisplayPosition;
  5231. return sc;
  5232. }
  5233. /***************************************************************************\
  5234. *
  5235. * METHOD: CCCListViewCtrl::Scput_DisplayPosition
  5236. *
  5237. * PURPOSE: Moves column (visually) to specified position
  5238. * Implements put for Column.DisplayPosition
  5239. *
  5240. * PARAMETERS:
  5241. * long lVisualPosition - Position to move to (1 based)
  5242. * int iZeroBasedColIndex - column index to move
  5243. *
  5244. * RETURNS:
  5245. * SC - result code
  5246. *
  5247. \***************************************************************************/
  5248. SC CCCListViewCtrl::Scput_DisplayPosition( /*[in]*/ long lVisualPosition, int iZeroBasedColIndex )
  5249. {
  5250. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scput_DisplayPosition"));
  5251. // check the params
  5252. if (lVisualPosition < 1)
  5253. return sc = E_INVALIDARG;
  5254. // retrieve current column data (this will check the index)
  5255. ColumnData strColData;
  5256. sc = ScGetColumnData( iZeroBasedColIndex, &strColData );
  5257. if (sc)
  5258. return sc;
  5259. // we need to iterate and see what index and iOrder represents the requested position
  5260. int nColumnCount = GetColCount();
  5261. // will create a map from iOrder to visual status to make life easier
  5262. // and benefit from the fact that items get sorted when inserting
  5263. std::map<int,bool> mapColumnsByDisplayPos;
  5264. for (int i = 0; i <nColumnCount; i++)
  5265. {
  5266. ColumnData strCurrColData;
  5267. sc = ScGetColumnData( i, &strCurrColData );
  5268. if (sc)
  5269. return sc;
  5270. // insert to the map
  5271. mapColumnsByDisplayPos[strCurrColData.iColumnOrder] = strCurrColData.bIsHidden;
  5272. }
  5273. // now find out the right iOrder for the new position
  5274. std::map<int,bool>::iterator it;
  5275. int iNewOrder = 1;
  5276. int nCurrPos = 0;
  5277. for (it = mapColumnsByDisplayPos.begin(); it != mapColumnsByDisplayPos.end(); ++it)
  5278. {
  5279. iNewOrder = it->first;
  5280. bool bHidden = it->second;
  5281. // olny visible items are counted when it comes to display position
  5282. if (!bHidden)
  5283. ++nCurrPos;
  5284. if (nCurrPos == lVisualPosition)
  5285. break; // we've found the good place to move in
  5286. }
  5287. // note - if position is not found - iNewOrder will mark the last column.
  5288. // good - that's a reasonable place for insertion to default to.
  5289. // that means column will go to the end if given index was bigger than count
  5290. // of visible columns
  5291. strColData.iColumnOrder = iNewOrder;
  5292. sc = ScSetColumnData( iZeroBasedColIndex, strColData );
  5293. if (sc)
  5294. return sc;
  5295. // Now redraw the list view
  5296. InvalidateRect(GetListCtrl(), NULL, TRUE);
  5297. return sc;
  5298. }
  5299. /***************************************************************************\
  5300. *
  5301. * METHOD: CCCListViewCtrl::Scget_Hidden
  5302. *
  5303. * PURPOSE: Returns hidden status for collumn. Implements get for Column.Hidden
  5304. *
  5305. * PARAMETERS:
  5306. * PBOOL Hidden - resulting status
  5307. * int iZeroBasedColIndex - index of the column
  5308. *
  5309. * RETURNS:
  5310. * SC - result code
  5311. *
  5312. \***************************************************************************/
  5313. SC CCCListViewCtrl::Scget_Hidden( /*[out, retval]*/ PBOOL pHidden, int iZeroBasedColIndex )
  5314. {
  5315. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scget_Hidden"));
  5316. // check parameters
  5317. sc = ScCheckPointers(pHidden);
  5318. if (sc)
  5319. return sc;
  5320. // initialize
  5321. *pHidden = FALSE;
  5322. // retrieve current column data (this will check the index)
  5323. ColumnData strColData;
  5324. sc = ScGetColumnData( iZeroBasedColIndex, &strColData );
  5325. if (sc)
  5326. return sc;
  5327. // return the hidden status
  5328. *pHidden = strColData.bIsHidden;
  5329. return sc;
  5330. }
  5331. /***************************************************************************\
  5332. *
  5333. * METHOD: CCCListViewCtrl::Scput_Hidden
  5334. *
  5335. * PURPOSE: Hides or shows the column. Implements put for Column.Hidden
  5336. *
  5337. * PARAMETERS:
  5338. * BOOL Hidden - new status for column
  5339. * int iZeroBasedColIndex - index of column
  5340. *
  5341. * RETURNS:
  5342. * SC - result code
  5343. *
  5344. \***************************************************************************/
  5345. SC CCCListViewCtrl::Scput_Hidden( /*[in]*/ BOOL Hidden , int iZeroBasedColIndex )
  5346. {
  5347. DECLARE_SC(sc, TEXT("CCCListViewCtrl::Scput_Hidden"));
  5348. // retrieve current column data (this will check the index)
  5349. ColumnData strColData;
  5350. sc = ScGetColumnData( iZeroBasedColIndex, &strColData );
  5351. if (sc)
  5352. return sc;
  5353. // check if we do have a change in status
  5354. if (strColData.bIsHidden == (bool)Hidden)
  5355. return sc;
  5356. // will never hide the 0 column!!!
  5357. if (Hidden && iZeroBasedColIndex == 0)
  5358. return sc = ::ScFromMMC(MMC_E_ZERO_COLUMN_INVISIBLE);
  5359. // check for view
  5360. sc = ScCheckPointers( m_pListView, E_UNEXPECTED);
  5361. if (sc)
  5362. return sc;
  5363. // get AMCView
  5364. CAMCView* pAMCView = m_pListView->GetAMCView();
  5365. sc = ScCheckPointers( pAMCView, E_UNEXPECTED);
  5366. if (sc)
  5367. return sc;
  5368. // Get component node that owns the result view
  5369. HNODE hnodeOwner = pAMCView->GetSelectedNode();
  5370. sc = ScCheckPointers((LPVOID)hnodeOwner, E_FAIL);
  5371. if (sc)
  5372. return sc.ToHr();
  5373. LPNODECALLBACK pNodeCallback = pAMCView->GetNodeCallback();
  5374. sc = ScCheckPointers(pNodeCallback, E_UNEXPECTED);
  5375. if (sc)
  5376. return sc.ToHr();
  5377. // forward the request to CEnumeratedNode - owner of the view
  5378. sc = pNodeCallback->ShowColumn(hnodeOwner, iZeroBasedColIndex, !Hidden);
  5379. if (sc)
  5380. return sc.ToHr();
  5381. return sc;
  5382. }
  5383. /***************************************************************************\
  5384. *
  5385. * METHOD: CCCListViewCtrl::ScSetAsSortColumn
  5386. *
  5387. * PURPOSE: Sorts LV by specified column. Implements Column.SetAsSortColumn
  5388. *
  5389. * PARAMETERS:
  5390. * ColumnSortOrder SortOrder - sort order requested
  5391. * int iZeroBasedColIndex - index of sort column
  5392. *
  5393. * RETURNS:
  5394. * SC - result code
  5395. *
  5396. \***************************************************************************/
  5397. SC CCCListViewCtrl::ScSetAsSortColumn( /*[in]*/ ColumnSortOrder SortOrder, int iZeroBasedColIndex )
  5398. {
  5399. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScSetAsSortColumn"));
  5400. // recheck the column index
  5401. // (it's not something the script sent - it's internal data)
  5402. if (iZeroBasedColIndex < 0 || iZeroBasedColIndex >= GetColCount())
  5403. return sc = E_UNEXPECTED;
  5404. // get AMCView
  5405. CAMCView* pAMCView = m_pListView->GetAMCView();
  5406. sc = ScCheckPointers( pAMCView, E_UNEXPECTED);
  5407. if (sc)
  5408. return sc;
  5409. // Get component node that owns the result view
  5410. HNODE hnodeOwner = pAMCView->GetSelectedNode();
  5411. sc = ScCheckPointers((LPVOID)hnodeOwner, E_FAIL);
  5412. if (sc)
  5413. return sc.ToHr();
  5414. LPNODECALLBACK pNodeCallback = pAMCView->GetNodeCallback();
  5415. sc = ScCheckPointers(pNodeCallback, E_UNEXPECTED);
  5416. if (sc)
  5417. return sc.ToHr();
  5418. // forward the request to CEnumeratedNode - owner of the view
  5419. sc = pNodeCallback->SetSortColumn(hnodeOwner, iZeroBasedColIndex, SortOrder == SortOrder_Ascending);
  5420. if (sc)
  5421. return sc.ToHr();
  5422. return sc;
  5423. }
  5424. /***************************************************************************\
  5425. *
  5426. * METHOD: CCCListViewCtrl::ScIsSortColumn
  5427. *
  5428. * PURPOSE: Checks if the column is the one LV is sorted by
  5429. * Implements Column.IsSortColumn
  5430. *
  5431. * PARAMETERS:
  5432. * PBOOL IsSortColumn - result (TRUE/FALSE)
  5433. * int iZeroBasedColIndex - column index
  5434. *
  5435. * RETURNS:
  5436. * SC - result code
  5437. *
  5438. \***************************************************************************/
  5439. SC CCCListViewCtrl::ScIsSortColumn( PBOOL IsSortColumn, int iZeroBasedColIndex )
  5440. {
  5441. DECLARE_SC(sc, TEXT("CCCListViewCtrl::ScIsSortColumn"));
  5442. // check the param
  5443. sc = ScCheckPointers(IsSortColumn);
  5444. if (sc)
  5445. return sc;
  5446. // initialize
  5447. *IsSortColumn = FALSE;
  5448. // recheck the column index
  5449. // (it's not something the script sent - it's internal data)
  5450. if (iZeroBasedColIndex < 0 || iZeroBasedColIndex >= GetColCount())
  5451. return sc = E_UNEXPECTED;
  5452. // get AMCView
  5453. CAMCView* pAMCView = m_pListView->GetAMCView();
  5454. sc = ScCheckPointers( pAMCView, E_UNEXPECTED);
  5455. if (sc)
  5456. return sc;
  5457. // Get component node that owns the result view
  5458. HNODE hnodeOwner = pAMCView->GetSelectedNode();
  5459. sc = ScCheckPointers((LPVOID)hnodeOwner, E_FAIL);
  5460. if (sc)
  5461. return sc.ToHr();
  5462. LPNODECALLBACK pNodeCallback = pAMCView->GetNodeCallback();
  5463. sc = ScCheckPointers(pNodeCallback, E_UNEXPECTED);
  5464. if (sc)
  5465. return sc.ToHr();
  5466. // forward the request to CEnumeratedNode - owner of the view
  5467. int iSortCol = -1;
  5468. sc = pNodeCallback->GetSortColumn(hnodeOwner, &iSortCol);
  5469. if (sc)
  5470. return sc.ToHr();
  5471. // see if this column is the one LV is sorted by
  5472. *IsSortColumn = (iSortCol == iZeroBasedColIndex);
  5473. return sc;
  5474. }
  5475. /***************************************************************************\
  5476. *
  5477. * METHOD: CColumn::ScOnListViewColumnInserted
  5478. *
  5479. * PURPOSE: Handler for event fired by LV, informing that new column was inserted
  5480. *
  5481. * PARAMETERS:
  5482. * int nIndex - index of newly inserted column
  5483. *
  5484. * RETURNS:
  5485. * SC - result code
  5486. *
  5487. \***************************************************************************/
  5488. SC CColumn::ScOnListViewColumnInserted (int nIndex)
  5489. {
  5490. DECLARE_SC(sc, TEXT("CColumn::ScOnListViewColumnInserted "));
  5491. // increment own index if column inserted ahead
  5492. if (m_iIndex >= nIndex)
  5493. m_iIndex++;
  5494. return sc;
  5495. }
  5496. /***************************************************************************\
  5497. *
  5498. * METHOD: CColumn::ScOnListViewColumnDeleted
  5499. *
  5500. * PURPOSE: Handler for event fired by LV, informing that new column was deleted
  5501. *
  5502. * PARAMETERS:
  5503. * int nIndex - index of deleted column
  5504. *
  5505. * RETURNS:
  5506. * SC - result code
  5507. *
  5508. \***************************************************************************/
  5509. SC CColumn::ScOnListViewColumnDeleted (int nIndex)
  5510. {
  5511. DECLARE_SC(sc, TEXT("CColumn::ScOnListViewColumnDeleted "));
  5512. // decrement own index if column deleted ahead
  5513. if (m_iIndex > nIndex)
  5514. m_iIndex--;
  5515. // disconnect from world if it's me who just died
  5516. else if (m_iIndex == nIndex)
  5517. {
  5518. // I'm hit. I'm hit. I'm hit.
  5519. m_iIndex = -1;
  5520. // disconnect from the tied object
  5521. if (IsTied())
  5522. {
  5523. CMyTiedObject *pTied = NULL;
  5524. sc = ScGetTiedObject(pTied);
  5525. if (sc)
  5526. return sc;
  5527. sc = ScCheckPointers(pTied, E_UNEXPECTED);
  5528. if (sc)
  5529. return sc;
  5530. // break the connection
  5531. pTied->RemoveFromList(this);
  5532. Unadvise();
  5533. }
  5534. }
  5535. return sc;
  5536. }