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.

1656 lines
54 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Behav_BasicTree.cpp
  5. Abstract:
  6. This file contains the implementation of the CPCHBehavior_BasicTree class.
  7. Revision History:
  8. Davide Massarenti (dmassare) 08/15/2000
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. ////////////////////////////////////////////////////////////////////////////////
  13. static const LPCWSTR s_icons_Expand[] =
  14. {
  15. L"hcp://system/images/Expando/collapsed.gif",
  16. ////L"hcp://system/images/Expando/expand_rest.gif" ,
  17. ////L"hcp://system/images/Expando/expand_mouseover.gif" ,
  18. ////L"hcp://system/images/Expando/expand_mousedown.gif" ,
  19. };
  20. static const LPCWSTR s_icons_Collapse[] =
  21. {
  22. L"hcp://system/images/Expando/expanded.gif",
  23. ////L"hcp://system/images/Expando/collapse_rest.gif" ,
  24. ////L"hcp://system/images/Expando/collapse_mouseover.gif" ,
  25. ////L"hcp://system/images/Expando/collapse_mousedown.gif" ,
  26. };
  27. static const LPCWSTR s_icons_Empty[] =
  28. {
  29. L"hcp://system/images/Expando/endnode.gif",
  30. ////L"hcp://system/images/Expando/empty_rest.gif" ,
  31. ////L"hcp://system/images/Expando/empty_mouseover.gif" ,
  32. ////L"hcp://system/images/Expando/empty_mousedown.gif" ,
  33. };
  34. static const WCHAR s_icons_Bullet[] = L"hcp://system/images/Expando/helpdoc.gif";
  35. static const WCHAR s_prefix_APP[] = L"app:";
  36. static CComBSTR s_event_onContextSelect( L"onContextSelect" );
  37. static CComBSTR s_event_onSelect ( L"onSelect" );
  38. static CComBSTR s_event_onUnselect ( L"onUnselect" );
  39. static CComBSTR s_style_None ( L"None" );
  40. static const DWORD l_dwVersion = 0x04005442; // BT 04
  41. ////////////////////////////////////////////////////////////////////////////////
  42. static const CPCHBehavior::EventDescription s_events[] =
  43. {
  44. { L"onselectstart", DISPID_HTMLELEMENTEVENTS_ONSELECTSTART },
  45. { L"onclick" , DISPID_HTMLELEMENTEVENTS_ONCLICK },
  46. { L"onkeydown" , DISPID_HTMLELEMENTEVENTS_ONKEYDOWN },
  47. { L"onkeypress" , DISPID_HTMLELEMENTEVENTS_ONKEYPRESS },
  48. { L"onmousedown" , DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN },
  49. { L"onmouseup" , DISPID_HTMLELEMENTEVENTS_ONMOUSEUP },
  50. { L"oncontextmenu", DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU },
  51. { L"onmouseout" , DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT },
  52. { L"onmouseover" , DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER },
  53. { NULL },
  54. };
  55. ////////////////////////////////////////////////////////////////////////////////
  56. ////////////////////////////////////////////////////////////////////////////////
  57. CPCHBehavior_BasicTree::Node::Node()
  58. {
  59. m_owner = NULL; // CPCHBehavior_BasicTree* m_owner;
  60. m_parent = NULL; // Node* m_parent;
  61. // CComBSTR m_bstrNode;
  62. // NodeType m_iType;
  63. m_iSelection = SELECTION__NONE; // SelectionMode m_iSelection;
  64. //
  65. m_fLoaded_Self = false; // bool m_fLoaded_Self;
  66. m_fLoaded_Children = false; // bool m_fLoaded_Children;
  67. m_fDisplayed_Self = false; // bool m_fDisplayed_Self;
  68. m_fDisplayed_Children = false; // bool m_fDisplayed_Children;
  69. m_fInvalid = false; // bool m_fInvalid;
  70. m_fRefreshNotification = false; // bool m_fRefreshNotification;
  71. //
  72. m_fExpanded = false; // bool m_fExpanded;
  73. m_fMouseOver = false; // bool m_fMouseOver;
  74. m_fMouseDown = false; // bool m_fMouseDown;
  75. //
  76. // CComPtr<IHTMLElement> m_parentElement;
  77. // CComBSTR m_bstrID;
  78. //
  79. // CComPtr<IHTMLElement> m_DIV;
  80. // CComPtr<IHTMLElement> m_IMG;
  81. // CComPtr<IHTMLElement> m_DIV_children;
  82. //
  83. // List m_lstSubnodes;
  84. };
  85. CPCHBehavior_BasicTree::Node::~Node()
  86. {
  87. MPC::ReleaseAll( m_lstSubnodes );
  88. }
  89. HRESULT CPCHBehavior_BasicTree::Node::Init( /*[in]*/ LPCWSTR szNode ,
  90. /*[in]*/ NodeType iType )
  91. {
  92. m_bstrNode = szNode;
  93. m_iType = iType;
  94. switch(m_iType)
  95. {
  96. case NODETYPE__FRAME1 :
  97. case NODETYPE__FRAME2 :
  98. case NODETYPE__FRAME3 :
  99. case NODETYPE__FRAME1_EXPAND:
  100. case NODETYPE__FRAME2_EXPAND:
  101. case NODETYPE__FRAME3_EXPAND:
  102. case NODETYPE__GROUP : m_fExpanded = true; break;
  103. case NODETYPE__LINK :
  104. case NODETYPE__SPACER : m_fExpanded = false; break;
  105. }
  106. return S_OK;
  107. }
  108. HRESULT CPCHBehavior_BasicTree::Node::NotifyMainThread()
  109. {
  110. if(m_fRefreshNotification) return S_OK; // Already done...
  111. m_fRefreshNotification = true;
  112. return m_owner->NotifyMainThread( this );
  113. }
  114. CPCHBehavior_BasicTree::Node* CPCHBehavior_BasicTree::Node::FindNode( /*[in]*/ LPCWSTR szNode, /*[in]*/ bool fUseID )
  115. {
  116. Node* node = NULL;
  117. if((!fUseID && MPC::StrICmp( szNode, m_bstrNode ) == 0) ||
  118. ( fUseID && MPC::StrCmp ( szNode, m_bstrID ) == 0) )
  119. {
  120. node = this;
  121. }
  122. else
  123. {
  124. Iter it;
  125. for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++)
  126. {
  127. if((node = (*it)->FindNode( szNode, fUseID ))) break;
  128. }
  129. }
  130. return node;
  131. }
  132. ////////////////////////////////////////////////////////////////////////////////
  133. STDMETHODIMP CPCHBehavior_BasicTree::Node::QueryInterface( /*[in]*/ REFIID riid, /*[iid_is][out]*/ void** ppvObject )
  134. {
  135. return E_NOTIMPL;
  136. }
  137. HRESULT CPCHBehavior_BasicTree::Node::Passivate()
  138. {
  139. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Passivate" );
  140. HRESULT hr;
  141. // CPCHBehavior_BasicTree* m_owner;
  142. // Node* m_parent;
  143. // CComBSTR m_bstrNode;
  144. // NodeType m_iType;
  145. // SelectionMode m_iSelection;
  146. //
  147. // bool m_fLoaded_Self;
  148. // bool m_fLoaded_Children;
  149. // bool m_fDisplayed_Self;
  150. // bool m_fDisplayed_Children;
  151. // bool m_fInvalid;
  152. // bool m_fRefreshNotification;
  153. //
  154. // bool m_fExpanded;
  155. // bool m_fMouseOver;
  156. // bool m_fMouseDown;
  157. //
  158. m_parentElement.Release(); // CComPtr<IHTMLElement> m_parentElement;
  159. // CComBSTR m_bstrID;
  160. //
  161. m_DIV .Release(); // CComPtr<IHTMLElement> m_DIV;
  162. m_IMG .Release(); // CComPtr<IHTMLElement> m_IMG;
  163. m_DIV_children .Release(); // CComPtr<IHTMLElement> m_DIV_children;
  164. //
  165. // List m_lstSubnodes;
  166. for(Iter it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++)
  167. {
  168. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->Passivate());
  169. }
  170. hr = S_OK;
  171. __HCP_FUNC_CLEANUP;
  172. __HCP_FUNC_EXIT(hr);
  173. }
  174. HRESULT CPCHBehavior_BasicTree::Node::ProcessRefreshRequest()
  175. {
  176. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::ProcessRefreshRequest" );
  177. HRESULT hr;
  178. bool fNotify = true;
  179. if(!m_fLoaded_Self)
  180. {
  181. __MPC_EXIT_IF_METHOD_FAILS(hr, PopulateSelf());
  182. fNotify = true;
  183. }
  184. if(!m_fLoaded_Children)
  185. {
  186. __MPC_EXIT_IF_METHOD_FAILS(hr, PopulateChildren());
  187. fNotify = true;
  188. }
  189. if(m_fDisplayed_Self == false)
  190. {
  191. fNotify = true;
  192. }
  193. if(IsParentDisplayingUs())
  194. {
  195. Iter it;
  196. for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++)
  197. {
  198. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->ProcessRefreshRequest());
  199. }
  200. }
  201. hr = S_OK;
  202. __HCP_FUNC_CLEANUP;
  203. if(fNotify) NotifyMainThread();
  204. __HCP_FUNC_EXIT(hr);
  205. }
  206. HRESULT CPCHBehavior_BasicTree::Node::LoadHTML( /*[in]*/ LPCWSTR szHTML )
  207. {
  208. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::LoadHTML" );
  209. HRESULT hr;
  210. if(!m_parentElement)
  211. {
  212. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY);
  213. }
  214. ////////////////////
  215. // ::MessageBoxW( NULL, szHTML, L"HTML", MB_OK );
  216. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parentElement->put_innerHTML( CComBSTR( szHTML ) ));
  217. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::FindElement( m_DIV , m_parentElement, L"tree_Title" ));
  218. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::FindElement( m_IMG , m_parentElement, L"tree_Img" ));
  219. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::FindElement( m_DIV_children, m_parentElement, L"tree_Children" ));
  220. if(m_DIV)
  221. {
  222. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::GetUniqueID( m_bstrID, m_DIV ));
  223. }
  224. hr = S_OK;
  225. __HCP_FUNC_CLEANUP;
  226. __HCP_FUNC_EXIT(hr);
  227. }
  228. HRESULT CPCHBehavior_BasicTree::Node::GenerateHTML( /*[in]*/ LPCWSTR szTitle, /*[in]*/ LPCWSTR szDescription, /*[in]*/ LPCWSTR szIcon, /*[in]*/ LPCWSTR szURL )
  229. {
  230. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::GenerateHTML" );
  231. const int F_TABLE = 0x00000001;
  232. const int F_TOPPANE = 0x00000002;
  233. const int F_BOTTOMPANE = 0x00000004;
  234. const int F_NOPANE = 0x00000008;
  235. const int F_EXPANDO = 0x00000010;
  236. const int F_GROUP = 0x00000020;
  237. HRESULT hr;
  238. MPC::wstring strHTML; INCREASESIZE(strHTML);
  239. bool fValid_Title = (STRINGISPRESENT(szTitle));
  240. bool fValid_Icon = (STRINGISPRESENT(szIcon ) && wcschr( szIcon, '"' ) == NULL); // Quote is not allowed in a URL!!
  241. bool fValid_URL = (STRINGISPRESENT(szURL ) && wcschr( szURL , '"' ) == NULL);
  242. bool fTitleDefined = false;
  243. int iFlags = 0;
  244. if(!m_fLoaded_Self)
  245. {
  246. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY);
  247. }
  248. ////////////////////
  249. if(m_owner->GetNavModel() == QR_SERVER)
  250. {
  251. if(!STRINGISPRESENT(szDescription)) szDescription = szTitle;
  252. }
  253. switch(m_iType)
  254. {
  255. case NODETYPE__FRAME1 : iFlags = F_TOPPANE ; fValid_Icon = false; break;
  256. case NODETYPE__FRAME2 : iFlags = F_BOTTOMPANE ; fValid_Icon = false; break;
  257. case NODETYPE__FRAME3 : iFlags = F_NOPANE ; fValid_Icon = false; break;
  258. case NODETYPE__FRAME1_EXPAND: iFlags = F_TABLE | F_TOPPANE ; fValid_Icon = false; break;
  259. case NODETYPE__FRAME2_EXPAND: iFlags = F_TABLE | F_BOTTOMPANE ; fValid_Icon = false; break;
  260. case NODETYPE__FRAME3_EXPAND: iFlags = F_TABLE | F_NOPANE ; fValid_Icon = false; break;
  261. case NODETYPE__EXPANDO : iFlags = F_EXPANDO ; fValid_Icon = false; fValid_URL = false; break;
  262. case NODETYPE__EXPANDO_LINK : iFlags = F_EXPANDO ; fValid_Icon = false; break;
  263. case NODETYPE__EXPANDO_TOPIC: iFlags = F_EXPANDO ; fValid_Icon = false; break;
  264. case NODETYPE__GROUP : iFlags = F_GROUP; fValid_Icon = false; fValid_URL = false; break;
  265. case NODETYPE__LINK : break;
  266. case NODETYPE__SPACER : fValid_Icon = false; fValid_URL = false; break;
  267. }
  268. ////////////////////
  269. if(iFlags & F_TABLE)
  270. {
  271. strHTML += L"<TABLE border=0 cellPadding=0 cellSpacing=0 WIDTH=100% HEIGHT=100% style='table-layout: fixed'><TR WIDTH=100%><TD>";
  272. }
  273. if(iFlags & (F_TOPPANE | F_BOTTOMPANE))
  274. {
  275. static const LPCWSTR c_TopPane [] = { L"sys-toppane-color-border sys-toppane-header-color sys-toppane-header-bgcolor" };
  276. static const LPCWSTR c_BottomPane[] = { L"sys-bottompane-color-border sys-bottompane-header-color sys-bottompane-header-bgcolor" };
  277. const LPCWSTR* c_Pane = (iFlags & F_TOPPANE) ? c_TopPane : c_BottomPane;
  278. //; text-overflow: ellipsis; overflow: hidden
  279. strHTML += L"<DIV style='width: 100%; border : 1pt solid' class='sys-font-body-bold ";
  280. strHTML += c_Pane[0];
  281. strHTML += L"'><DIV ID=tree_Title style='padding: 0.5em 11px' TITLE=\""; MPC::HTML::HTMLEscape( strHTML, szDescription ); //; border: 1pt solid red
  282. strHTML += L"\">";
  283. fTitleDefined = true;
  284. }
  285. if(iFlags & F_NOPANE)
  286. {
  287. strHTML += L"<DIV style='width: 100%' class='sys-font-heading2 sys-rhp-color-title'>";
  288. strHTML += L"<DIV ID=tree_Title style='padding: 0.5em 11px 0.5em 6px' TITLE=\""; MPC::HTML::HTMLEscape( strHTML, szDescription ); //; border: 1pt solid red
  289. strHTML += L"\">";
  290. fTitleDefined = true;
  291. }
  292. if(iFlags & F_EXPANDO)
  293. {
  294. if(m_iType == NODETYPE__EXPANDO)
  295. {
  296. if(m_lstSubnodes.size())
  297. {
  298. szIcon = (m_fExpanded ? s_icons_Collapse[0] : s_icons_Expand[0]);
  299. }
  300. else
  301. {
  302. szIcon = s_icons_Empty[0];
  303. }
  304. }
  305. else
  306. {
  307. szIcon = s_icons_Bullet;
  308. }
  309. strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"<DIV NOWRAP" : L"<DIV";
  310. strHTML += L" ID=tree_Title style='padding: 0.5em; cursor: hand' TITLE=\""; MPC::HTML::HTMLEscape( strHTML, szDescription );//; border: 1pt solid green
  311. strHTML += L"\"><IMG ID=tree_Img ALIGN=absmiddle src=\""; strHTML += szIcon;
  312. strHTML += m_owner->IsRTL() ? L"\" style='margin-left : 0.5em'>" :
  313. L"\" style='margin-right: 0.5em'>";
  314. fTitleDefined = true;
  315. if(!fValid_URL)
  316. {
  317. fValid_URL = true;
  318. szURL = L"about:blank";
  319. }
  320. }
  321. if(iFlags & F_GROUP)
  322. {
  323. strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"<DIV NOWRAP" : L"<DIV";
  324. strHTML += L" ID=tree_Title CLASS='sys-color-body sys-font-body-bold' style='padding: 0.5em 11px 0.5em 6px' TITLE=\""; MPC::HTML::HTMLEscape( strHTML, szDescription );//; border: 1pt solid navy
  325. strHTML += L"\">";
  326. fTitleDefined = true;
  327. }
  328. ////////////////////
  329. if(!fTitleDefined)
  330. {
  331. strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"<DIV NOWRAP" : L"<DIV";
  332. strHTML += L" ID=tree_Title style='padding: 0.5em 11px' TITLE=\""; MPC::HTML::HTMLEscape( strHTML, szDescription );//; border: 1pt solid navy
  333. strHTML += L"\">";
  334. }
  335. if(fValid_URL)
  336. {
  337. LPCWSTR szClass = (iFlags & (F_TOPPANE | F_BOTTOMPANE)) ? L"sys-link-header" : L"sys-link-normal";
  338. strHTML += L"<A class='"; strHTML += szClass; strHTML += L"' tabIndex=1 href=\""; strHTML += szURL; InsertOptionalTarget( strHTML );
  339. strHTML += L"\">";
  340. }
  341. if(fValid_Icon)
  342. {
  343. LPCWSTR szExt = wcsrchr( szIcon, '.' );
  344. bool fBMP = false;
  345. if(szExt && !_wcsicmp( szExt, L".BMP" )) fBMP = true;
  346. if(fBMP)
  347. {
  348. strHTML += L"<helpcenter:bitmap style='position: relative; width: 12px; height: 12px' SRCNORMAL=\"";
  349. }
  350. else
  351. {
  352. strHTML += L"<IMG BORDER=0 ALIGN=absmiddle SRC=\"";
  353. }
  354. strHTML += szIcon;
  355. strHTML += m_owner->IsRTL() ? L"\" style='margin-left : 0.5em'>" :
  356. L"\" style='margin-right: 0.5em'>";
  357. if(fBMP)
  358. {
  359. strHTML += L"</helpcenter:bitmap>";
  360. }
  361. }
  362. MPC::HTML::HTMLEscape( strHTML, szTitle );
  363. if(fValid_URL)
  364. {
  365. // Removed because of bug 434589
  366. // if(_wcsnicmp( szURL, s_prefix_APP, MAXSTRLEN(s_prefix_APP) ) == 0)
  367. // {
  368. // strHTML += L"&nbsp;<helpcenter:bitmap style='position: relative; top: 1px; width: 12px; height: 12px' SRCNORMAL='hcp://system/images/icon_newwindow_12x.bmp'></helpcenter:bitmap>";
  369. // }
  370. strHTML += L"</A>";
  371. }
  372. if(!fTitleDefined)
  373. {
  374. strHTML += L"</DIV>";
  375. }
  376. ////////////////////
  377. if(iFlags & F_GROUP)
  378. {
  379. //; border: 1pt solid pink
  380. strHTML += L"</DIV>";
  381. strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"<DIV NOWRAP" : L"<DIV";
  382. strHTML += L" ID=tree_Children></DIV>";
  383. }
  384. if(iFlags & F_EXPANDO)
  385. {
  386. strHTML += L"</DIV>";
  387. strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"<DIV NOWRAP" : L"<DIV";
  388. strHTML += m_owner->IsRTL() ? L" ID=tree_Children style='padding-right: 1.0em; display: none'></DIV>" : //; border: 1pt solid pink
  389. L" ID=tree_Children style='padding-left : 1.0em; display: none'></DIV>" ;
  390. }
  391. if(iFlags & (F_TOPPANE | F_BOTTOMPANE | F_NOPANE))
  392. {
  393. strHTML += L"</DIV></DIV>";
  394. }
  395. if(iFlags & F_TABLE)
  396. {
  397. strHTML += L"</TD></TR><TR><TD HEIGHT=100%>";
  398. }
  399. if(iFlags & (F_TOPPANE | F_BOTTOMPANE))
  400. {
  401. static const LPCWSTR c_TopPane [] = { L"sys-toppane-color-border sys-toppane-bgcolor" };
  402. static const LPCWSTR c_BottomPane[] = { L"sys-bottompane-color-border sys-bottompane-bgcolor" };
  403. const LPCWSTR* c_Pane = (iFlags & F_TOPPANE) ? c_TopPane : c_BottomPane;
  404. strHTML += L"<DIV ID=tree_Children class='sys-font-body ";
  405. strHTML += c_Pane[0];
  406. strHTML += L"' style='width: 100%; ";
  407. if(iFlags & F_TABLE)
  408. {
  409. strHTML += L"height: 100%; ";
  410. }
  411. //// if(m_owner->GetNavModel() == QR_SERVER)
  412. //// {
  413. //// strHTML += L"text-overflow: ellipsis; overflow-x: hidden; overflow-y: auto; ";
  414. //// }
  415. //// else
  416. //// {
  417. //// strHTML += L"overflow: auto; ";
  418. //// }
  419. strHTML += L"overflow: auto; ";
  420. strHTML += L"border : 1pt solid; border-top : 0; padding: 11px'></DIV>";
  421. }
  422. if(iFlags & F_NOPANE)
  423. {
  424. strHTML += L"<DIV ID=tree_Children class='sys-font-body' style='width: 100%; ";
  425. if(iFlags & F_TABLE)
  426. {
  427. strHTML += L"height: 100%; ";
  428. }
  429. //// if(m_owner->GetNavModel() == QR_SERVER)
  430. //// {
  431. //// strHTML += L"text-overflow: ellipsis; overflow-x: hidden; overflow-y: auto; ";
  432. //// }
  433. strHTML += L"'></DIV>";
  434. }
  435. if(iFlags & F_TABLE)
  436. {
  437. strHTML += L"</TD></TR></TABLE>";
  438. }
  439. ////////////////////
  440. __MPC_EXIT_IF_METHOD_FAILS(hr, LoadHTML( strHTML.c_str() ));
  441. hr = S_OK;
  442. __HCP_FUNC_CLEANUP;
  443. __HCP_FUNC_EXIT(hr);
  444. }
  445. void CPCHBehavior_BasicTree::Node::InsertOptionalTarget( /*[in/out]*/ MPC::wstring& strHTML )
  446. {
  447. BSTR bstrTargetFrame = m_owner->m_bstrTargetFrame;
  448. if(STRINGISPRESENT(bstrTargetFrame))
  449. {
  450. strHTML += L"\" target=\""; strHTML += bstrTargetFrame;
  451. }
  452. }
  453. ////////////////////////////////////////////////////////////////////////////////
  454. HRESULT CPCHBehavior_BasicTree::Node::GenerateChildren()
  455. {
  456. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::GenerateChildren" );
  457. HRESULT hr;
  458. if(!m_fLoaded_Children)
  459. {
  460. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY);
  461. }
  462. ////////////////////
  463. if(m_lstSubnodes.size() && m_DIV_children)
  464. {
  465. MPC::wstring strHTML;
  466. Iter it;
  467. for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++)
  468. {
  469. INCREASESIZE(strHTML);
  470. strHTML += L"<DIV></DIV>";
  471. }
  472. __MPC_EXIT_IF_METHOD_FAILS(hr, m_DIV_children->put_innerHTML( CComBSTR( strHTML.c_str() ) ));
  473. ////////////////////
  474. {
  475. MPC::HTML::IHTMLElementList lstDIV;
  476. MPC::HTML::IHTMLElementIter itDIV;
  477. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::EnumerateElements( lstDIV, m_DIV_children, L"<DIV" ));
  478. itDIV = lstDIV .begin();
  479. it = m_lstSubnodes.begin();
  480. while(itDIV != lstDIV .end() &&
  481. it != m_lstSubnodes.end() )
  482. {
  483. Node* node = *it++;
  484. node->m_parentElement = *itDIV++;
  485. (void)node->Display();
  486. }
  487. MPC::ReleaseAll( lstDIV );
  488. }
  489. }
  490. hr = S_OK;
  491. __HCP_FUNC_CLEANUP;
  492. __HCP_FUNC_EXIT(hr);
  493. }
  494. HRESULT CPCHBehavior_BasicTree::Node::Display()
  495. {
  496. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Display" );
  497. HRESULT hr;
  498. bool fNotify = false;
  499. m_fRefreshNotification = false;
  500. if(m_fInvalid)
  501. {
  502. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  503. }
  504. if(m_fDisplayed_Self == false)
  505. {
  506. if(SUCCEEDED(GenerateSelf()))
  507. {
  508. m_fDisplayed_Self = true;
  509. fNotify = true;
  510. }
  511. }
  512. if(m_fDisplayed_Self && !m_fDisplayed_Children)
  513. {
  514. if(SUCCEEDED(GenerateChildren()))
  515. {
  516. m_fDisplayed_Children = true;
  517. fNotify = true;
  518. }
  519. }
  520. if(m_fDisplayed_Self)
  521. {
  522. if(m_iSelection == SELECTION__NEXTACTIVE ||
  523. m_iSelection == SELECTION__NEXTACTIVE_NOTIFY )
  524. {
  525. Node* node = m_parent;
  526. //
  527. // Reset all the NEXTACTIVE flags for the parents.
  528. //
  529. while(node)
  530. {
  531. if(node->m_iSelection == SELECTION__NEXTACTIVE ||
  532. node->m_iSelection == SELECTION__NEXTACTIVE_NOTIFY )
  533. {
  534. node->m_iSelection = SELECTION__NONE;
  535. }
  536. node = node->m_parent;
  537. }
  538. __MPC_EXIT_IF_METHOD_FAILS(hr, m_owner->ChangeSelection( this, /*fNotify*/(m_iSelection == SELECTION__NEXTACTIVE_NOTIFY) ));
  539. }
  540. }
  541. if(m_iSelection == SELECTION__ACTIVE && m_owner->m_nSelected != this)
  542. {
  543. MPC::Attach( m_owner->m_nSelected, this );
  544. }
  545. ////////////////////
  546. if((m_iType == NODETYPE__EXPANDO ||
  547. m_iType == NODETYPE__EXPANDO_LINK ) && m_IMG && m_DIV_children)
  548. {
  549. const LPCWSTR* rgIcons;
  550. if(m_lstSubnodes.size())
  551. {
  552. CComPtr<IHTMLStyle> pStyle;
  553. CComBSTR bstrDisplay;
  554. bool fFlip = false;
  555. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(pStyle , m_DIV_children, style );
  556. MPC_SCRIPTHELPER_GET__DIRECT (bstrDisplay, pStyle , display);
  557. if(MPC::StrICmp( bstrDisplay, s_style_None ) == 0)
  558. {
  559. if(m_fExpanded) fFlip = true;
  560. }
  561. else
  562. {
  563. if(!m_fExpanded) fFlip = true;
  564. }
  565. if(fFlip)
  566. {
  567. MPC_SCRIPTHELPER_PUT__DIRECT(pStyle, display, m_fExpanded ? NULL : s_style_None );
  568. if(m_fExpanded)
  569. {
  570. fNotify = true;
  571. }
  572. else
  573. {
  574. //
  575. // If the currently selected node is a child of ours, grab the selection.
  576. //
  577. Node* selected = m_owner->m_nSelected;
  578. while(selected)
  579. {
  580. if(selected == this)
  581. {
  582. __MPC_EXIT_IF_METHOD_FAILS(hr, m_owner->ChangeSelection( this, /*fNotify*/true ));
  583. break;
  584. }
  585. selected = selected->m_parent;
  586. }
  587. //
  588. // On desktop SKUs, we close the subnodes.
  589. //
  590. if(m_owner->GetNavModel() == QR_DESKTOP)
  591. {
  592. Iter it;
  593. for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++)
  594. {
  595. Node* node = *it;
  596. if(node->m_iType == NODETYPE__EXPANDO &&
  597. node->m_fExpanded == true )
  598. {
  599. node->m_fExpanded = false;
  600. node->NotifyMainThread();
  601. }
  602. }
  603. }
  604. }
  605. }
  606. rgIcons = (m_fExpanded ? s_icons_Collapse : s_icons_Expand);
  607. }
  608. else
  609. {
  610. rgIcons = s_icons_Empty;
  611. }
  612. {
  613. CComQIPtr<IHTMLImgElement> img = m_IMG;
  614. CComBSTR bstrIcon;
  615. int i = 0;
  616. //// if (m_fMouseDown) i = 2;
  617. //// else if(m_fMouseOver) i = 1;
  618. //// else i = 0;
  619. MPC_SCRIPTHELPER_GET__DIRECT(bstrIcon, img, src);
  620. if(MPC::StrICmp( bstrIcon, rgIcons[i] ))
  621. {
  622. bstrIcon = rgIcons[i];
  623. MPC_SCRIPTHELPER_PUT__DIRECT(img, src, bstrIcon );
  624. }
  625. }
  626. }
  627. if((m_iType == NODETYPE__EXPANDO ||
  628. m_iType == NODETYPE__EXPANDO_LINK ||
  629. m_iType == NODETYPE__EXPANDO_TOPIC ||
  630. m_iType == NODETYPE__LINK ) && m_DIV)
  631. {
  632. //
  633. // Update styles to reflect current state.
  634. //
  635. MPC::wstring strClass; strClass.reserve( 1024 );
  636. CComBSTR bstrClass;
  637. if(m_iSelection == SELECTION__ACTIVE) strClass += L"sys-toppane-selection";
  638. //// if (m_fMouseDown) strClass += L" Tree-Selectable-MouseDown";
  639. //// else if(m_fMouseOver) strClass += L" Tree-Selectable-MouseOver";
  640. //// else strClass += L" Tree-Selectable-Normal";
  641. MPC_SCRIPTHELPER_GET__DIRECT(bstrClass, m_DIV, className);
  642. if(MPC::StrICmp( strClass, bstrClass ))
  643. {
  644. bstrClass = strClass.c_str();
  645. MPC_SCRIPTHELPER_PUT__DIRECT(m_DIV, className, bstrClass);
  646. }
  647. }
  648. hr = S_OK;
  649. __HCP_FUNC_CLEANUP;
  650. if(fNotify) m_owner->Thread_Signal();
  651. __HCP_FUNC_EXIT(hr);
  652. }
  653. bool CPCHBehavior_BasicTree::Node::IsParentDisplayingUs()
  654. {
  655. if(m_parent == NULL) return true; // No parent, we are displayed for sure.
  656. switch(m_parent->m_iType)
  657. {
  658. case NODETYPE__FRAME1 : return true;
  659. case NODETYPE__FRAME2 : return true;
  660. case NODETYPE__FRAME3 : return true;
  661. case NODETYPE__FRAME1_EXPAND: return true;
  662. case NODETYPE__FRAME2_EXPAND: return true;
  663. case NODETYPE__FRAME3_EXPAND: return true;
  664. case NODETYPE__EXPANDO : return m_parent->m_fExpanded;
  665. case NODETYPE__EXPANDO_LINK : return m_parent->m_fExpanded;
  666. case NODETYPE__EXPANDO_TOPIC: return m_parent->m_fExpanded;
  667. case NODETYPE__GROUP : return true;
  668. case NODETYPE__LINK : return false;
  669. case NODETYPE__SPACER : return false;
  670. }
  671. return false;
  672. }
  673. ////////////////////////////////////////////////////////////////////////////////
  674. HRESULT CPCHBehavior_BasicTree::Node::Load( /*[in]*/ MPC::Serializer& stream )
  675. {
  676. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Load" );
  677. HRESULT hr;
  678. int iCount;
  679. int iType;
  680. int iSelection;
  681. // CPCHBehavior_BasicTree* m_owner;
  682. // Node* m_parent;
  683. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_bstrNode ); // CComBSTR m_bstrNode;
  684. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> iType ); // NodeType m_iType;
  685. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> iSelection ); // SelectionMode m_iSelection;
  686. //
  687. // bool m_fLoaded_Self;
  688. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fLoaded_Children); // bool m_fLoaded_Children;
  689. // bool m_fDisplayed_Self;
  690. // bool m_fDisplayed_Children;
  691. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fInvalid ); // bool m_fInvalid;
  692. // bool m_fRefreshNotification;
  693. //
  694. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fExpanded ); // bool m_fExpanded;
  695. // bool m_fMouseOver;
  696. // bool m_fMouseDown;
  697. //
  698. // CComPtr<IHTMLElement> m_parentElement;
  699. // CComBSTR m_bstrID;
  700. //
  701. // CComPtr<IHTMLElement> m_DIV;
  702. // CComPtr<IHTMLElement> m_IMG;
  703. // CComPtr<IHTMLElement> m_DIV_children;
  704. //
  705. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> iCount ); // List m_lstSubnodes;
  706. m_iType = (NodeType )iType;
  707. m_iSelection = (SelectionMode)iSelection;
  708. if(m_fLoaded_Children)
  709. {
  710. while(iCount-- > 0)
  711. {
  712. Node* subnode;
  713. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateInstance( m_owner, this, subnode ));
  714. m_lstSubnodes.push_back( subnode );
  715. __MPC_EXIT_IF_METHOD_FAILS(hr, subnode->Load( stream ));
  716. }
  717. }
  718. hr = S_OK;
  719. __HCP_FUNC_CLEANUP;
  720. __HCP_FUNC_EXIT(hr);
  721. }
  722. HRESULT CPCHBehavior_BasicTree::Node::Save( /*[in]*/ MPC::Serializer& stream, /*[in]*/ bool fSaveChildren )
  723. {
  724. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Save" );
  725. HRESULT hr;
  726. Iter it = m_lstSubnodes.begin();
  727. int iCount = m_lstSubnodes.size();
  728. int iType = m_iType;
  729. int iSelection = m_iSelection;
  730. if( fSaveChildren) fSaveChildren = m_fLoaded_Children;
  731. if(!fSaveChildren) iCount = 0;
  732. // CPCHBehavior_BasicTree* m_owner;
  733. // Node* m_parent;
  734. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_bstrNode ); // CComBSTR m_bstrNode;
  735. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << iType ); // NodeType m_iType;
  736. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << iSelection ); // SelectionMode m_iSelection
  737. //
  738. // bool m_fLoaded_Self;
  739. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << fSaveChildren); // bool m_fLoaded_Children;
  740. // bool m_fDisplayed_Self;
  741. // bool m_fDisplayed_Children;
  742. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fInvalid ); // bool m_fInvalid;
  743. // bool m_fRefreshNotification;
  744. //
  745. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fExpanded ); // bool m_fExpanded;
  746. // bool m_fMouseOver;
  747. // bool m_fMouseDown;
  748. //
  749. // CComPtr<IHTMLElement> m_parentElement;
  750. // CComBSTR m_bstrID;
  751. //
  752. // CComPtr<IHTMLElement> m_DIV;
  753. // CComPtr<IHTMLElement> m_IMG;
  754. // CComPtr<IHTMLElement> m_DIV_children;
  755. //
  756. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << iCount ); // List m_lstSubnodes;
  757. while(iCount-- > 0)
  758. {
  759. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it++)->Save( stream, fSaveChildren ));
  760. }
  761. hr = S_OK;
  762. __HCP_FUNC_CLEANUP;
  763. __HCP_FUNC_EXIT(hr);
  764. }
  765. ////////////////////////////////////////////////////////////////////////////////
  766. HRESULT CPCHBehavior_BasicTree::Node::OnMouse( /*[in]*/ DISPID id ,
  767. /*[in]*/ long lButton ,
  768. /*[in]*/ long lKey ,
  769. /*[in]*/ bool fIsImage )
  770. {
  771. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::OnMouse" );
  772. HRESULT hr;
  773. if(m_iType == NODETYPE__EXPANDO ||
  774. m_iType == NODETYPE__EXPANDO_TOPIC ||
  775. m_iType == NODETYPE__EXPANDO_LINK ||
  776. m_iType == NODETYPE__LINK )
  777. {
  778. bool fMouseDown = m_fMouseDown;
  779. switch(id)
  780. {
  781. case DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN: m_fMouseDown = true ; break;
  782. case DISPID_HTMLELEMENTEVENTS_ONMOUSEUP : m_fMouseDown = false; break;
  783. case DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER: m_fMouseOver = true ; break;
  784. case DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT : m_fMouseDown = false; m_fMouseOver = false; break;
  785. }
  786. if(m_iType == NODETYPE__EXPANDO ||
  787. m_iType == NODETYPE__EXPANDO_LINK )
  788. {
  789. if(fIsImage)
  790. {
  791. if(m_lstSubnodes.size())
  792. {
  793. if(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN && lButton == 1)
  794. {
  795. m_fExpanded = !m_fExpanded;
  796. }
  797. else
  798. {
  799. if(m_owner->GetNavModel() == QR_SERVER)
  800. {
  801. id = 0; // Ignore the event down the road...
  802. }
  803. }
  804. }
  805. }
  806. else
  807. {
  808. if(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN && lButton == 1)
  809. {
  810. //
  811. // On Desktop, keep the node always open.
  812. // On Server, toggle its state.
  813. //
  814. if(m_owner->GetNavModel() == QR_DESKTOP)
  815. {
  816. m_fExpanded = true;
  817. }
  818. else
  819. {
  820. m_fExpanded = !m_fExpanded;
  821. }
  822. }
  823. }
  824. if(id == DISPID_HTMLELEMENTEVENTS_ONKEYDOWN)
  825. {
  826. switch(lKey)
  827. {
  828. case VK_RIGHT: m_fExpanded = m_owner->IsRTL() ? false : true ; break;
  829. case VK_LEFT : m_fExpanded = m_owner->IsRTL() ? true : false; break;
  830. }
  831. }
  832. if(id == DISPID_HTMLELEMENTEVENTS_ONKEYPRESS)
  833. {
  834. switch(lKey)
  835. {
  836. case VK_RETURN: m_fExpanded = true ; break;
  837. }
  838. }
  839. }
  840. //BUG 531001 (IAccessibility Default ACtions do not work)
  841. //ONCLICK event needs to be handled. It was being intercepted but not handled.
  842. //Replaced ONMOUSEUP handling with ONCLICK.
  843. if((id == DISPID_HTMLELEMENTEVENTS_ONCLICK ) || //(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEUP && lButton == 1 && fMouseDown) ||
  844. (id == DISPID_HTMLELEMENTEVENTS_ONKEYPRESS && lKey == VK_RETURN ))
  845. {
  846. if(m_owner->m_nToSelect)
  847. {
  848. delete m_owner->m_nToSelect; m_owner->m_nToSelect = NULL;
  849. }
  850. __MPC_EXIT_IF_METHOD_FAILS(hr, m_owner->ChangeSelection( this, /*fNotify*/true ));
  851. }
  852. __MPC_EXIT_IF_METHOD_FAILS(hr, Display());
  853. }
  854. hr = S_OK;
  855. __HCP_FUNC_CLEANUP;
  856. __HCP_FUNC_EXIT(hr);
  857. }
  858. ////////////////////////////////////////////////////////////////////////////////
  859. ////////////////////////////////////////////////////////////////////////////////
  860. CPCHBehavior_BasicTree::CPCHBehavior_BasicTree()
  861. {
  862. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::CPCHBehavior_BasicTree" );
  863. // CComBSTR m_bstrTargetFrame;
  864. //
  865. m_lCookie_onContextSelect = 0; // long m_lCookie_onContextSelect;
  866. m_lCookie_onSelect = 0; // long m_lCookie_onSelect;
  867. m_lCookie_onUnselect = 0; // long m_lCookie_onUnselect;
  868. //
  869. m_nTopNode = NULL; // Node* m_nTopNode;
  870. m_nSelected = NULL; // Node* m_nSelected;
  871. m_nCurrent = NULL; // Node* m_nCurrent;
  872. m_nToSelect = NULL; // NodeToSelect* m_nToSelect;
  873. // CPCHTimerHandle m_Timer;
  874. //
  875. m_fRefreshing = true; // bool m_fRefreshing;
  876. m_lNavModel = QR_DEFAULT; // long m_lNavModel;
  877. }
  878. CPCHBehavior_BasicTree::~CPCHBehavior_BasicTree()
  879. {
  880. (void)Empty();
  881. }
  882. ////////////////////////////////////////////////////////////////////////////////
  883. HRESULT CPCHBehavior_BasicTree::RefreshThread()
  884. {
  885. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::RefreshThread" );
  886. HRESULT hr;
  887. if(m_lNavModel == QR_DEFAULT) m_lNavModel = (m_parent->UserSettings()->IsDesktopSKU() ? QR_DESKTOP : QR_SERVER);
  888. __MPC_EXIT_IF_METHOD_FAILS(hr, RefreshThread_Enter());
  889. //
  890. // Process database request.
  891. //
  892. while(Thread_IsAborted() == false)
  893. {
  894. SetRefreshingFlag( false );
  895. Thread_WaitForEvents( NULL, INFINITE );
  896. if(Thread_IsAborted()) break;
  897. SetRefreshingFlag( true );
  898. if(m_nTopNode)
  899. {
  900. __MPC_EXIT_IF_METHOD_FAILS(hr, m_nTopNode->ProcessRefreshRequest());
  901. }
  902. }
  903. hr = S_OK;
  904. __HCP_FUNC_CLEANUP;
  905. SetRefreshingFlag( false );
  906. RefreshThread_Leave();
  907. Thread_Abort(); // Kill the thread.
  908. __HCP_FUNC_EXIT(hr);
  909. }
  910. void CPCHBehavior_BasicTree::SetRefreshingFlag( /*[in]*/ bool fVal )
  911. {
  912. MPC::SmartLock<_ThreadModel> lock( this );
  913. m_fRefreshing = fVal;
  914. }
  915. void CPCHBehavior_BasicTree::WaitForRefreshing( /*[in]*/ MPC::SmartLock<_ThreadModel>& lock ,
  916. /*[in]*/ bool fYield )
  917. {
  918. if(fYield)
  919. {
  920. lock = NULL;
  921. Thread_Signal();
  922. ::Sleep( 0 ); // Yield processor.
  923. lock = this;
  924. }
  925. while(m_fRefreshing)
  926. {
  927. lock = NULL;
  928. if(Thread_IsRunning() == false) break;
  929. MPC::SleepWithMessagePump( 10 );
  930. lock = this;
  931. }
  932. }
  933. HRESULT CPCHBehavior_BasicTree::NotifyMainThread( /*[in]*/ Node* node )
  934. {
  935. CComQIPtr<IDispatch> self = Thread_Self();
  936. CComVariant v = node ? node->m_bstrNode : L"";
  937. return MPC::AsyncInvoke( self, DISPID_PCH_BEHAVIORS_PRIV__NEWDATAAVAILABLE, &v, 1 );
  938. }
  939. HRESULT CPCHBehavior_BasicTree::ChangeSelection( /*[in]*/ Node* node ,
  940. /*[in]*/ bool fNotify )
  941. {
  942. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::ChangeSelection" );
  943. HRESULT hr;
  944. if(m_nSelected)
  945. {
  946. m_nSelected->m_iSelection = SELECTION__NONE;
  947. __MPC_EXIT_IF_METHOD_FAILS(hr, m_nSelected->Display());
  948. if(fNotify)
  949. {
  950. __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent( m_lCookie_onUnselect ));
  951. }
  952. }
  953. MPC::Attach( m_nSelected, node );
  954. if(m_nSelected)
  955. {
  956. m_nSelected->m_iSelection = SELECTION__ACTIVE;
  957. __MPC_EXIT_IF_METHOD_FAILS(hr, m_nSelected->Display());
  958. if(fNotify)
  959. {
  960. __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent( m_lCookie_onSelect ));
  961. }
  962. else
  963. {
  964. m_Timer.Start( this, TimerCallback_ScrollIntoView, 100 );
  965. }
  966. }
  967. hr = S_OK;
  968. __HCP_FUNC_CLEANUP;
  969. __HCP_FUNC_EXIT(hr);
  970. }
  971. CPCHBehavior_BasicTree::Node* CPCHBehavior_BasicTree::NodeFromElement( /*[in]*/ IHTMLElement* elem )
  972. {
  973. CComPtr<IHTMLElement> elemDIV;
  974. if(SUCCEEDED(MPC::HTML::FindFirstParentWithThisTag( elemDIV, elem, L"DIV" )) && elemDIV)
  975. {
  976. CComBSTR bstrID;
  977. if(SUCCEEDED(MPC::HTML::GetUniqueID( bstrID, elemDIV )))
  978. {
  979. return NodeFromKey( bstrID, true );
  980. }
  981. }
  982. return NULL;
  983. }
  984. CPCHBehavior_BasicTree::Node* CPCHBehavior_BasicTree::NodeFromKey( /*[in]*/ LPCWSTR szNode, /*[in]*/ bool fUseID )
  985. {
  986. return m_nTopNode ? m_nTopNode->FindNode( szNode, fUseID ) : NULL;
  987. }
  988. HRESULT CPCHBehavior_BasicTree::InterceptInvoke( /*[in]*/ DISPID dispidMember, /*[in]*/ DISPPARAMS* pdispparams )
  989. {
  990. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::InterceptInvoke" );
  991. HRESULT hr;
  992. if(dispidMember == DISPID_PCH_BEHAVIORS_PRIV__NEWDATAAVAILABLE &&
  993. pdispparams->cArgs == 1 &&
  994. pdispparams->rgvarg[0].vt == VT_BSTR )
  995. {
  996. MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock );
  997. Node* node;
  998. node = NodeFromKey( pdispparams->rgvarg[0].bstrVal );
  999. if(node)
  1000. {
  1001. __MPC_EXIT_IF_METHOD_FAILS(hr, node->Display());
  1002. }
  1003. hr = S_OK;
  1004. }
  1005. else
  1006. {
  1007. hr = E_INVALIDARG;
  1008. }
  1009. __HCP_FUNC_CLEANUP;
  1010. __HCP_FUNC_EXIT(hr);
  1011. }
  1012. HRESULT CPCHBehavior_BasicTree::TimerCallback_ScrollIntoView( /*[in]*/ VARIANT )
  1013. {
  1014. if(m_nSelected && m_nSelected->m_DIV)
  1015. {
  1016. CComVariant v( VARIANT_TRUE );
  1017. (void)m_nSelected->m_DIV->scrollIntoView( v );
  1018. }
  1019. return S_OK;
  1020. }
  1021. /////////////////////////////////////////////////////////////////////////////
  1022. STDMETHODIMP CPCHBehavior_BasicTree::Init( /*[in]*/ IElementBehaviorSite* pBehaviorSite )
  1023. {
  1024. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Init" );
  1025. HRESULT hr;
  1026. __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior::Init( pBehaviorSite ));
  1027. m_Timer.Initialize( m_parent->Timer() );
  1028. __MPC_EXIT_IF_METHOD_FAILS(hr, AttachToEvents( s_events, (CLASS_METHOD)onMouse ));
  1029. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEvent( s_event_onContextSelect, m_lCookie_onContextSelect ));
  1030. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEvent( s_event_onSelect , m_lCookie_onSelect ));
  1031. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEvent( s_event_onUnselect , m_lCookie_onUnselect ));
  1032. ////////////////////////////////////////////////////////////////////////////////
  1033. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::GetPropertyByName( m_elem, L"target", m_bstrTargetFrame ));
  1034. hr = S_OK;
  1035. __HCP_FUNC_CLEANUP;
  1036. __HCP_FUNC_EXIT(hr);
  1037. }
  1038. STDMETHODIMP CPCHBehavior_BasicTree::Detach()
  1039. {
  1040. Thread_Wait();
  1041. if(m_nTopNode) m_nTopNode->Passivate();
  1042. m_lCookie_onContextSelect = 0;
  1043. m_lCookie_onSelect = 0;
  1044. m_lCookie_onUnselect = 0;
  1045. return CPCHBehavior::Detach();
  1046. }
  1047. ////////////////////////////////////////////////////////////////////////////////
  1048. HRESULT CPCHBehavior_BasicTree::Load( /*[in]*/ MPC::Serializer& stream )
  1049. {
  1050. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Load" );
  1051. HRESULT hr;
  1052. bool fNodePresent;
  1053. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> fNodePresent);
  1054. if(fNodePresent)
  1055. {
  1056. if(!m_nTopNode)
  1057. {
  1058. __MPC_EXIT_IF_METHOD_FAILS(hr, E_FAIL);
  1059. }
  1060. __MPC_EXIT_IF_METHOD_FAILS(hr, m_nTopNode->Load( stream ));
  1061. }
  1062. hr = S_OK;
  1063. __HCP_FUNC_CLEANUP;
  1064. __HCP_FUNC_EXIT(hr);
  1065. }
  1066. HRESULT CPCHBehavior_BasicTree::Save( /*[in]*/ MPC::Serializer& stream )
  1067. {
  1068. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Save" );
  1069. HRESULT hr;
  1070. bool fNodePresent = (m_nTopNode != NULL);
  1071. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << fNodePresent);
  1072. if(m_nTopNode) __MPC_EXIT_IF_METHOD_FAILS(hr, m_nTopNode->Save( stream, /*fSaveChildren*/true ));
  1073. hr = S_OK;
  1074. __HCP_FUNC_CLEANUP;
  1075. __HCP_FUNC_EXIT(hr);
  1076. }
  1077. ////////////////////
  1078. HRESULT CPCHBehavior_BasicTree::Persist_Load( /*[in]*/ BSTR newVal )
  1079. {
  1080. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Persist_Load" );
  1081. HRESULT hr;
  1082. CComPtr<IStream> stream;
  1083. HGLOBAL hg = NULL;
  1084. Empty();
  1085. //
  1086. // Convert BSTR to IStream.
  1087. //
  1088. {
  1089. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertHexToHGlobal( newVal, hg ));
  1090. __MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateStreamOnHGlobal( hg, FALSE, &stream ));
  1091. }
  1092. //
  1093. // Unserialize state from IStream.
  1094. //
  1095. {
  1096. MPC::Serializer_IStream streamReal( stream );
  1097. MPC::Serializer_Buffering streamBuf ( streamReal );
  1098. DWORD dwVer;
  1099. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  1100. __MPC_EXIT_IF_METHOD_FAILS(hr, Load( streamBuf ));
  1101. }
  1102. hr = S_OK;
  1103. __HCP_FUNC_CLEANUP;
  1104. if(hg) ::GlobalFree( hg );
  1105. __HCP_FUNC_EXIT(hr);
  1106. }
  1107. HRESULT CPCHBehavior_BasicTree::Persist_Save( /*[out, retval]*/ BSTR *pVal )
  1108. {
  1109. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Persist_Save" );
  1110. HRESULT hr;
  1111. CComPtr<IStream> streamResult;
  1112. CComBSTR bstr;
  1113. HGLOBAL hg;
  1114. //
  1115. // Serialize state to IStream.
  1116. //
  1117. {
  1118. MPC::Serializer_IStream streamReal;
  1119. MPC::Serializer_Buffering streamBuf( streamReal );
  1120. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion );
  1121. __MPC_EXIT_IF_METHOD_FAILS(hr, Save( streamBuf ));
  1122. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf .Flush ( )); // Flush buffering stream.
  1123. __MPC_EXIT_IF_METHOD_FAILS(hr, streamReal.Reset ( )); // Rewind real stream.
  1124. __MPC_EXIT_IF_METHOD_FAILS(hr, streamReal.GetStream( &streamResult )); // Extract pointer to IStream.
  1125. }
  1126. //
  1127. // Convert IStream to BSTR.
  1128. //
  1129. {
  1130. __MPC_EXIT_IF_METHOD_FAILS(hr, ::GetHGlobalFromStream( streamResult, &hg ));
  1131. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertHGlobalToHex( hg, bstr ));
  1132. }
  1133. *pVal = bstr.Detach();
  1134. hr = S_OK;
  1135. __HCP_FUNC_CLEANUP;
  1136. __HCP_FUNC_EXIT(hr);
  1137. }
  1138. ////////////////////////////////////////////////////////////////////////////////
  1139. void CPCHBehavior_BasicTree::Empty()
  1140. {
  1141. // CComBSTR m_bstrTargetFrame;
  1142. //
  1143. // long m_lCookie_onContextSelect;
  1144. // long m_lCookie_onSelect;
  1145. // long m_lCookie_onUnselect;
  1146. //
  1147. MPC::Release( m_nTopNode ); // Node* m_nTopNode;
  1148. MPC::Release( m_nSelected ); // Node* m_nSelected;
  1149. MPC::Release( m_nCurrent ); // Node* m_nCurrent;
  1150. // NodeToSelect* m_nToSelect;
  1151. // CPCHTimerHandle m_Timer;
  1152. //
  1153. // bool m_fRefreshing;
  1154. m_lNavModel = QR_DEFAULT; // long m_lNavModel;
  1155. if(m_nToSelect)
  1156. {
  1157. delete m_nToSelect;
  1158. m_nToSelect = NULL;
  1159. }
  1160. }
  1161. HRESULT CPCHBehavior_BasicTree::onMouse( DISPID id, DISPPARAMS*, VARIANT* )
  1162. {
  1163. __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::onMouse" );
  1164. HRESULT hr;
  1165. CComPtr<IHTMLEventObj> ev;
  1166. CComPtr<IHTMLElement> elemSrc;
  1167. CComPtr<IHTMLElement> elemTo;
  1168. CComBSTR bstrTagName;
  1169. long lButton;
  1170. long lKey;
  1171. bool fIsImage = false;
  1172. bool fClicked = false;
  1173. bool fContextMenu = false;
  1174. bool fFocusEnter = false;
  1175. bool fFocusLeave = false;
  1176. Node* node = NULL;
  1177. Node* nodeTo = NULL;
  1178. AddRef(); // To protect against early deletion.
  1179. __MPC_EXIT_IF_METHOD_FAILS(hr, GetEventObject( ev ));
  1180. MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(elemSrc , ev , srcElement );
  1181. MPC_SCRIPTHELPER_GET__DIRECT (elemTo , ev , toElement );
  1182. MPC_SCRIPTHELPER_GET__DIRECT (lButton , ev , button );
  1183. MPC_SCRIPTHELPER_GET__DIRECT (lKey , ev , keyCode );
  1184. MPC_SCRIPTHELPER_GET__DIRECT (bstrTagName, elemSrc, tagName ); fIsImage = (MPC::StrICmp( bstrTagName, L"IMG" ) == 0);
  1185. //
  1186. // Find the node associated with the element.
  1187. //
  1188. node = NodeFromElement( elemSrc );
  1189. nodeTo = NodeFromElement( elemTo );
  1190. ////////////////////////////////////////
  1191. if(g_Debug_CONTEXTMENU)
  1192. {
  1193. if(id == DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU)
  1194. {
  1195. VARIANT_BOOL fCtrlKey;
  1196. MPC_SCRIPTHELPER_GET__DIRECT(fCtrlKey, ev, ctrlKey);
  1197. if(fCtrlKey == VARIANT_TRUE)
  1198. {
  1199. id = 0; // Ignore event...
  1200. }
  1201. }
  1202. }
  1203. switch(id)
  1204. {
  1205. case DISPID_HTMLELEMENTEVENTS_ONCLICK :
  1206. case DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN:
  1207. case DISPID_HTMLELEMENTEVENTS_ONMOUSEUP :
  1208. if(node)
  1209. {
  1210. bool fCancel = true;
  1211. switch(node->m_iType)
  1212. {
  1213. case NODETYPE__FRAME1 :
  1214. case NODETYPE__FRAME2 :
  1215. case NODETYPE__FRAME3 :
  1216. case NODETYPE__FRAME1_EXPAND:
  1217. case NODETYPE__FRAME2_EXPAND:
  1218. case NODETYPE__FRAME3_EXPAND:
  1219. case NODETYPE__LINK :
  1220. fCancel = false; // Let IE handle the navigation for these nodes...
  1221. break;
  1222. }
  1223. if(!fCancel) break;
  1224. }
  1225. case DISPID_HTMLELEMENTEVENTS_ONSELECTSTART:
  1226. case DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU:
  1227. __MPC_EXIT_IF_METHOD_FAILS(hr, CancelEvent( ev ));
  1228. break;
  1229. }
  1230. if(node)
  1231. {
  1232. if(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT && node == nodeTo) // We are moving within the node...
  1233. {
  1234. __MPC_EXIT_IF_METHOD_FAILS(hr, S_OK);
  1235. }
  1236. __MPC_EXIT_IF_METHOD_FAILS(hr, node->OnMouse( id, lButton, lKey, fIsImage ));
  1237. if(id == DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU)
  1238. {
  1239. MPC::Attach( m_nCurrent, node );
  1240. __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent( m_lCookie_onContextSelect ));
  1241. MPC::Release( m_nCurrent );
  1242. }
  1243. }
  1244. hr = S_OK;
  1245. __HCP_FUNC_CLEANUP;
  1246. Release(); // To protect against early deletion.
  1247. __HCP_FUNC_EXIT(hr);
  1248. }