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

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