/****************************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: Behav_BasicTree.cpp Abstract: This file contains the implementation of the CPCHBehavior_BasicTree class. Revision History: Davide Massarenti (dmassare) 08/15/2000 created ******************************************************************************/ #include "stdafx.h" //////////////////////////////////////////////////////////////////////////////// static const LPCWSTR s_icons_Expand[] = { L"hcp://system/images/Expando/collapsed.gif", ////L"hcp://system/images/Expando/expand_rest.gif" , ////L"hcp://system/images/Expando/expand_mouseover.gif" , ////L"hcp://system/images/Expando/expand_mousedown.gif" , }; static const LPCWSTR s_icons_Collapse[] = { L"hcp://system/images/Expando/expanded.gif", ////L"hcp://system/images/Expando/collapse_rest.gif" , ////L"hcp://system/images/Expando/collapse_mouseover.gif" , ////L"hcp://system/images/Expando/collapse_mousedown.gif" , }; static const LPCWSTR s_icons_Empty[] = { L"hcp://system/images/Expando/endnode.gif", ////L"hcp://system/images/Expando/empty_rest.gif" , ////L"hcp://system/images/Expando/empty_mouseover.gif" , ////L"hcp://system/images/Expando/empty_mousedown.gif" , }; static const WCHAR s_icons_Bullet[] = L"hcp://system/images/Expando/helpdoc.gif"; static const WCHAR s_prefix_APP[] = L"app:"; static CComBSTR s_event_onContextSelect( L"onContextSelect" ); static CComBSTR s_event_onSelect ( L"onSelect" ); static CComBSTR s_event_onUnselect ( L"onUnselect" ); static CComBSTR s_style_None ( L"None" ); static const DWORD l_dwVersion = 0x04005442; // BT 04 //////////////////////////////////////////////////////////////////////////////// static const CPCHBehavior::EventDescription s_events[] = { { L"onselectstart", DISPID_HTMLELEMENTEVENTS_ONSELECTSTART }, { L"onclick" , DISPID_HTMLELEMENTEVENTS_ONCLICK }, { L"onkeydown" , DISPID_HTMLELEMENTEVENTS_ONKEYDOWN }, { L"onkeypress" , DISPID_HTMLELEMENTEVENTS_ONKEYPRESS }, { L"onmousedown" , DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN }, { L"onmouseup" , DISPID_HTMLELEMENTEVENTS_ONMOUSEUP }, { L"oncontextmenu", DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU }, { L"onmouseout" , DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT }, { L"onmouseover" , DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER }, { NULL }, }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// CPCHBehavior_BasicTree::Node::Node() { m_owner = NULL; // CPCHBehavior_BasicTree* m_owner; m_parent = NULL; // Node* m_parent; // CComBSTR m_bstrNode; // NodeType m_iType; m_iSelection = SELECTION__NONE; // SelectionMode m_iSelection; // m_fLoaded_Self = false; // bool m_fLoaded_Self; m_fLoaded_Children = false; // bool m_fLoaded_Children; m_fDisplayed_Self = false; // bool m_fDisplayed_Self; m_fDisplayed_Children = false; // bool m_fDisplayed_Children; m_fInvalid = false; // bool m_fInvalid; m_fRefreshNotification = false; // bool m_fRefreshNotification; // m_fExpanded = false; // bool m_fExpanded; m_fMouseOver = false; // bool m_fMouseOver; m_fMouseDown = false; // bool m_fMouseDown; // // CComPtr m_parentElement; // CComBSTR m_bstrID; // // CComPtr m_DIV; // CComPtr m_IMG; // CComPtr m_DIV_children; // // List m_lstSubnodes; }; CPCHBehavior_BasicTree::Node::~Node() { MPC::ReleaseAll( m_lstSubnodes ); } HRESULT CPCHBehavior_BasicTree::Node::Init( /*[in]*/ LPCWSTR szNode , /*[in]*/ NodeType iType ) { m_bstrNode = szNode; m_iType = iType; switch(m_iType) { case NODETYPE__FRAME1 : case NODETYPE__FRAME2 : case NODETYPE__FRAME3 : case NODETYPE__FRAME1_EXPAND: case NODETYPE__FRAME2_EXPAND: case NODETYPE__FRAME3_EXPAND: case NODETYPE__GROUP : m_fExpanded = true; break; case NODETYPE__LINK : case NODETYPE__SPACER : m_fExpanded = false; break; } return S_OK; } HRESULT CPCHBehavior_BasicTree::Node::NotifyMainThread() { if(m_fRefreshNotification) return S_OK; // Already done... m_fRefreshNotification = true; return m_owner->NotifyMainThread( this ); } CPCHBehavior_BasicTree::Node* CPCHBehavior_BasicTree::Node::FindNode( /*[in]*/ LPCWSTR szNode, /*[in]*/ bool fUseID ) { Node* node = NULL; if((!fUseID && MPC::StrICmp( szNode, m_bstrNode ) == 0) || ( fUseID && MPC::StrCmp ( szNode, m_bstrID ) == 0) ) { node = this; } else { Iter it; for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++) { if((node = (*it)->FindNode( szNode, fUseID ))) break; } } return node; } //////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHBehavior_BasicTree::Node::QueryInterface( /*[in]*/ REFIID riid, /*[iid_is][out]*/ void** ppvObject ) { return E_NOTIMPL; } HRESULT CPCHBehavior_BasicTree::Node::Passivate() { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Passivate" ); HRESULT hr; // CPCHBehavior_BasicTree* m_owner; // Node* m_parent; // CComBSTR m_bstrNode; // NodeType m_iType; // SelectionMode m_iSelection; // // bool m_fLoaded_Self; // bool m_fLoaded_Children; // bool m_fDisplayed_Self; // bool m_fDisplayed_Children; // bool m_fInvalid; // bool m_fRefreshNotification; // // bool m_fExpanded; // bool m_fMouseOver; // bool m_fMouseDown; // m_parentElement.Release(); // CComPtr m_parentElement; // CComBSTR m_bstrID; // m_DIV .Release(); // CComPtr m_DIV; m_IMG .Release(); // CComPtr m_IMG; m_DIV_children .Release(); // CComPtr m_DIV_children; // // List m_lstSubnodes; for(Iter it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++) { __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->Passivate()); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Node::ProcessRefreshRequest() { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::ProcessRefreshRequest" ); HRESULT hr; bool fNotify = true; if(!m_fLoaded_Self) { __MPC_EXIT_IF_METHOD_FAILS(hr, PopulateSelf()); fNotify = true; } if(!m_fLoaded_Children) { __MPC_EXIT_IF_METHOD_FAILS(hr, PopulateChildren()); fNotify = true; } if(m_fDisplayed_Self == false) { fNotify = true; } if(IsParentDisplayingUs()) { Iter it; for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++) { __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->ProcessRefreshRequest()); } } hr = S_OK; __HCP_FUNC_CLEANUP; if(fNotify) NotifyMainThread(); __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Node::LoadHTML( /*[in]*/ LPCWSTR szHTML ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::LoadHTML" ); HRESULT hr; if(!m_parentElement) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY); } //////////////////// // ::MessageBoxW( NULL, szHTML, L"HTML", MB_OK ); __MPC_EXIT_IF_METHOD_FAILS(hr, m_parentElement->put_innerHTML( CComBSTR( szHTML ) )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::FindElement( m_DIV , m_parentElement, L"tree_Title" )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::FindElement( m_IMG , m_parentElement, L"tree_Img" )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::FindElement( m_DIV_children, m_parentElement, L"tree_Children" )); if(m_DIV) { __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::GetUniqueID( m_bstrID, m_DIV )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Node::GenerateHTML( /*[in]*/ LPCWSTR szTitle, /*[in]*/ LPCWSTR szDescription, /*[in]*/ LPCWSTR szIcon, /*[in]*/ LPCWSTR szURL ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::GenerateHTML" ); const int F_TABLE = 0x00000001; const int F_TOPPANE = 0x00000002; const int F_BOTTOMPANE = 0x00000004; const int F_NOPANE = 0x00000008; const int F_EXPANDO = 0x00000010; const int F_GROUP = 0x00000020; HRESULT hr; MPC::wstring strHTML; INCREASESIZE(strHTML); bool fValid_Title = (STRINGISPRESENT(szTitle)); bool fValid_Icon = (STRINGISPRESENT(szIcon ) && wcschr( szIcon, '"' ) == NULL); // Quote is not allowed in a URL!! bool fValid_URL = (STRINGISPRESENT(szURL ) && wcschr( szURL , '"' ) == NULL); bool fTitleDefined = false; int iFlags = 0; if(!m_fLoaded_Self) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY); } //////////////////// if(m_owner->GetNavModel() == QR_SERVER) { if(!STRINGISPRESENT(szDescription)) szDescription = szTitle; } switch(m_iType) { case NODETYPE__FRAME1 : iFlags = F_TOPPANE ; fValid_Icon = false; break; case NODETYPE__FRAME2 : iFlags = F_BOTTOMPANE ; fValid_Icon = false; break; case NODETYPE__FRAME3 : iFlags = F_NOPANE ; fValid_Icon = false; break; case NODETYPE__FRAME1_EXPAND: iFlags = F_TABLE | F_TOPPANE ; fValid_Icon = false; break; case NODETYPE__FRAME2_EXPAND: iFlags = F_TABLE | F_BOTTOMPANE ; fValid_Icon = false; break; case NODETYPE__FRAME3_EXPAND: iFlags = F_TABLE | F_NOPANE ; fValid_Icon = false; break; case NODETYPE__EXPANDO : iFlags = F_EXPANDO ; fValid_Icon = false; fValid_URL = false; break; case NODETYPE__EXPANDO_LINK : iFlags = F_EXPANDO ; fValid_Icon = false; break; case NODETYPE__EXPANDO_TOPIC: iFlags = F_EXPANDO ; fValid_Icon = false; break; case NODETYPE__GROUP : iFlags = F_GROUP; fValid_Icon = false; fValid_URL = false; break; case NODETYPE__LINK : break; case NODETYPE__SPACER : fValid_Icon = false; fValid_URL = false; break; } //////////////////// if(iFlags & F_TABLE) { strHTML += L"
"; } if(iFlags & (F_TOPPANE | F_BOTTOMPANE)) { static const LPCWSTR c_TopPane [] = { L"sys-toppane-color-border sys-toppane-header-color sys-toppane-header-bgcolor" }; static const LPCWSTR c_BottomPane[] = { L"sys-bottompane-color-border sys-bottompane-header-color sys-bottompane-header-bgcolor" }; const LPCWSTR* c_Pane = (iFlags & F_TOPPANE) ? c_TopPane : c_BottomPane; //; text-overflow: ellipsis; overflow: hidden strHTML += L"
"; fTitleDefined = true; } if(iFlags & F_NOPANE) { strHTML += L"
"; strHTML += L"
"; fTitleDefined = true; } if(iFlags & F_EXPANDO) { if(m_iType == NODETYPE__EXPANDO) { if(m_lstSubnodes.size()) { szIcon = (m_fExpanded ? s_icons_Collapse[0] : s_icons_Expand[0]); } else { szIcon = s_icons_Empty[0]; } } else { szIcon = s_icons_Bullet; } strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"
IsRTL() ? L"\" style='margin-left : 0.5em'>" : L"\" style='margin-right: 0.5em'>"; fTitleDefined = true; if(!fValid_URL) { fValid_URL = true; szURL = L"about:blank"; } } if(iFlags & F_GROUP) { strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"
"; fTitleDefined = true; } //////////////////// if(!fTitleDefined) { strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L""; } //////////////////// if(iFlags & F_GROUP) { //; border: 1pt solid pink strHTML += L"
"; strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"
"; } if(iFlags & F_EXPANDO) { strHTML += L"
"; strHTML += (m_owner->GetNavModel() == QR_SERVER) ? L"
IsRTL() ? L" ID=tree_Children style='padding-right: 1.0em; display: none'>
" : //; border: 1pt solid pink L" ID=tree_Children style='padding-left : 1.0em; display: none'>
" ; } if(iFlags & (F_TOPPANE | F_BOTTOMPANE | F_NOPANE)) { strHTML += L"
"; } if(iFlags & F_TABLE) { strHTML += L"
"; } if(iFlags & (F_TOPPANE | F_BOTTOMPANE)) { static const LPCWSTR c_TopPane [] = { L"sys-toppane-color-border sys-toppane-bgcolor" }; static const LPCWSTR c_BottomPane[] = { L"sys-bottompane-color-border sys-bottompane-bgcolor" }; const LPCWSTR* c_Pane = (iFlags & F_TOPPANE) ? c_TopPane : c_BottomPane; strHTML += L"
"; } if(iFlags & F_NOPANE) { strHTML += L"
"; } if(iFlags & F_TABLE) { strHTML += L"
"; } //////////////////// __MPC_EXIT_IF_METHOD_FAILS(hr, LoadHTML( strHTML.c_str() )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } void CPCHBehavior_BasicTree::Node::InsertOptionalTarget( /*[in/out]*/ MPC::wstring& strHTML ) { BSTR bstrTargetFrame = m_owner->m_bstrTargetFrame; if(STRINGISPRESENT(bstrTargetFrame)) { strHTML += L"\" target=\""; strHTML += bstrTargetFrame; } } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_BasicTree::Node::GenerateChildren() { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::GenerateChildren" ); HRESULT hr; if(!m_fLoaded_Children) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY); } //////////////////// if(m_lstSubnodes.size() && m_DIV_children) { MPC::wstring strHTML; Iter it; for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++) { INCREASESIZE(strHTML); strHTML += L"
"; } __MPC_EXIT_IF_METHOD_FAILS(hr, m_DIV_children->put_innerHTML( CComBSTR( strHTML.c_str() ) )); //////////////////// { MPC::HTML::IHTMLElementList lstDIV; MPC::HTML::IHTMLElementIter itDIV; __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::HTML::EnumerateElements( lstDIV, m_DIV_children, L"m_parentElement = *itDIV++; (void)node->Display(); } MPC::ReleaseAll( lstDIV ); } } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Node::Display() { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Display" ); HRESULT hr; bool fNotify = false; m_fRefreshNotification = false; if(m_fInvalid) { __MPC_SET_ERROR_AND_EXIT(hr, S_OK); } if(m_fDisplayed_Self == false) { if(SUCCEEDED(GenerateSelf())) { m_fDisplayed_Self = true; fNotify = true; } } if(m_fDisplayed_Self && !m_fDisplayed_Children) { if(SUCCEEDED(GenerateChildren())) { m_fDisplayed_Children = true; fNotify = true; } } if(m_fDisplayed_Self) { if(m_iSelection == SELECTION__NEXTACTIVE || m_iSelection == SELECTION__NEXTACTIVE_NOTIFY ) { Node* node = m_parent; // // Reset all the NEXTACTIVE flags for the parents. // while(node) { if(node->m_iSelection == SELECTION__NEXTACTIVE || node->m_iSelection == SELECTION__NEXTACTIVE_NOTIFY ) { node->m_iSelection = SELECTION__NONE; } node = node->m_parent; } __MPC_EXIT_IF_METHOD_FAILS(hr, m_owner->ChangeSelection( this, /*fNotify*/(m_iSelection == SELECTION__NEXTACTIVE_NOTIFY) )); } } if(m_iSelection == SELECTION__ACTIVE && m_owner->m_nSelected != this) { MPC::Attach( m_owner->m_nSelected, this ); } //////////////////// if((m_iType == NODETYPE__EXPANDO || m_iType == NODETYPE__EXPANDO_LINK ) && m_IMG && m_DIV_children) { const LPCWSTR* rgIcons; if(m_lstSubnodes.size()) { CComPtr pStyle; CComBSTR bstrDisplay; bool fFlip = false; MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(pStyle , m_DIV_children, style ); MPC_SCRIPTHELPER_GET__DIRECT (bstrDisplay, pStyle , display); if(MPC::StrICmp( bstrDisplay, s_style_None ) == 0) { if(m_fExpanded) fFlip = true; } else { if(!m_fExpanded) fFlip = true; } if(fFlip) { MPC_SCRIPTHELPER_PUT__DIRECT(pStyle, display, m_fExpanded ? NULL : s_style_None ); if(m_fExpanded) { fNotify = true; } else { // // If the currently selected node is a child of ours, grab the selection. // Node* selected = m_owner->m_nSelected; while(selected) { if(selected == this) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_owner->ChangeSelection( this, /*fNotify*/true )); break; } selected = selected->m_parent; } // // On desktop SKUs, we close the subnodes. // if(m_owner->GetNavModel() == QR_DESKTOP) { Iter it; for(it = m_lstSubnodes.begin(); it != m_lstSubnodes.end(); it++) { Node* node = *it; if(node->m_iType == NODETYPE__EXPANDO && node->m_fExpanded == true ) { node->m_fExpanded = false; node->NotifyMainThread(); } } } } } rgIcons = (m_fExpanded ? s_icons_Collapse : s_icons_Expand); } else { rgIcons = s_icons_Empty; } { CComQIPtr img = m_IMG; CComBSTR bstrIcon; int i = 0; //// if (m_fMouseDown) i = 2; //// else if(m_fMouseOver) i = 1; //// else i = 0; MPC_SCRIPTHELPER_GET__DIRECT(bstrIcon, img, src); if(MPC::StrICmp( bstrIcon, rgIcons[i] )) { bstrIcon = rgIcons[i]; MPC_SCRIPTHELPER_PUT__DIRECT(img, src, bstrIcon ); } } } if((m_iType == NODETYPE__EXPANDO || m_iType == NODETYPE__EXPANDO_LINK || m_iType == NODETYPE__EXPANDO_TOPIC || m_iType == NODETYPE__LINK ) && m_DIV) { // // Update styles to reflect current state. // MPC::wstring strClass; strClass.reserve( 1024 ); CComBSTR bstrClass; if(m_iSelection == SELECTION__ACTIVE) strClass += L"sys-toppane-selection"; //// if (m_fMouseDown) strClass += L" Tree-Selectable-MouseDown"; //// else if(m_fMouseOver) strClass += L" Tree-Selectable-MouseOver"; //// else strClass += L" Tree-Selectable-Normal"; MPC_SCRIPTHELPER_GET__DIRECT(bstrClass, m_DIV, className); if(MPC::StrICmp( strClass, bstrClass )) { bstrClass = strClass.c_str(); MPC_SCRIPTHELPER_PUT__DIRECT(m_DIV, className, bstrClass); } } hr = S_OK; __HCP_FUNC_CLEANUP; if(fNotify) m_owner->Thread_Signal(); __HCP_FUNC_EXIT(hr); } bool CPCHBehavior_BasicTree::Node::IsParentDisplayingUs() { if(m_parent == NULL) return true; // No parent, we are displayed for sure. switch(m_parent->m_iType) { case NODETYPE__FRAME1 : return true; case NODETYPE__FRAME2 : return true; case NODETYPE__FRAME3 : return true; case NODETYPE__FRAME1_EXPAND: return true; case NODETYPE__FRAME2_EXPAND: return true; case NODETYPE__FRAME3_EXPAND: return true; case NODETYPE__EXPANDO : return m_parent->m_fExpanded; case NODETYPE__EXPANDO_LINK : return m_parent->m_fExpanded; case NODETYPE__EXPANDO_TOPIC: return m_parent->m_fExpanded; case NODETYPE__GROUP : return true; case NODETYPE__LINK : return false; case NODETYPE__SPACER : return false; } return false; } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_BasicTree::Node::Load( /*[in]*/ MPC::Serializer& stream ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Load" ); HRESULT hr; int iCount; int iType; int iSelection; // CPCHBehavior_BasicTree* m_owner; // Node* m_parent; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_bstrNode ); // CComBSTR m_bstrNode; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> iType ); // NodeType m_iType; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> iSelection ); // SelectionMode m_iSelection; // // bool m_fLoaded_Self; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fLoaded_Children); // bool m_fLoaded_Children; // bool m_fDisplayed_Self; // bool m_fDisplayed_Children; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fInvalid ); // bool m_fInvalid; // bool m_fRefreshNotification; // __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fExpanded ); // bool m_fExpanded; // bool m_fMouseOver; // bool m_fMouseDown; // // CComPtr m_parentElement; // CComBSTR m_bstrID; // // CComPtr m_DIV; // CComPtr m_IMG; // CComPtr m_DIV_children; // __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> iCount ); // List m_lstSubnodes; m_iType = (NodeType )iType; m_iSelection = (SelectionMode)iSelection; if(m_fLoaded_Children) { while(iCount-- > 0) { Node* subnode; __MPC_EXIT_IF_METHOD_FAILS(hr, CreateInstance( m_owner, this, subnode )); m_lstSubnodes.push_back( subnode ); __MPC_EXIT_IF_METHOD_FAILS(hr, subnode->Load( stream )); } } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Node::Save( /*[in]*/ MPC::Serializer& stream, /*[in]*/ bool fSaveChildren ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::Save" ); HRESULT hr; Iter it = m_lstSubnodes.begin(); int iCount = m_lstSubnodes.size(); int iType = m_iType; int iSelection = m_iSelection; if( fSaveChildren) fSaveChildren = m_fLoaded_Children; if(!fSaveChildren) iCount = 0; // CPCHBehavior_BasicTree* m_owner; // Node* m_parent; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_bstrNode ); // CComBSTR m_bstrNode; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << iType ); // NodeType m_iType; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << iSelection ); // SelectionMode m_iSelection // // bool m_fLoaded_Self; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << fSaveChildren); // bool m_fLoaded_Children; // bool m_fDisplayed_Self; // bool m_fDisplayed_Children; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fInvalid ); // bool m_fInvalid; // bool m_fRefreshNotification; // __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fExpanded ); // bool m_fExpanded; // bool m_fMouseOver; // bool m_fMouseDown; // // CComPtr m_parentElement; // CComBSTR m_bstrID; // // CComPtr m_DIV; // CComPtr m_IMG; // CComPtr m_DIV_children; // __MPC_EXIT_IF_METHOD_FAILS(hr, stream << iCount ); // List m_lstSubnodes; while(iCount-- > 0) { __MPC_EXIT_IF_METHOD_FAILS(hr, (*it++)->Save( stream, fSaveChildren )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_BasicTree::Node::OnMouse( /*[in]*/ DISPID id , /*[in]*/ long lButton , /*[in]*/ long lKey , /*[in]*/ bool fIsImage ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Node::OnMouse" ); HRESULT hr; if(m_iType == NODETYPE__EXPANDO || m_iType == NODETYPE__EXPANDO_TOPIC || m_iType == NODETYPE__EXPANDO_LINK || m_iType == NODETYPE__LINK ) { bool fMouseDown = m_fMouseDown; switch(id) { case DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN: m_fMouseDown = true ; break; case DISPID_HTMLELEMENTEVENTS_ONMOUSEUP : m_fMouseDown = false; break; case DISPID_HTMLELEMENTEVENTS_ONMOUSEOVER: m_fMouseOver = true ; break; case DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT : m_fMouseDown = false; m_fMouseOver = false; break; } if(m_iType == NODETYPE__EXPANDO || m_iType == NODETYPE__EXPANDO_LINK ) { if(fIsImage) { if(m_lstSubnodes.size()) { if(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN && lButton == 1) { m_fExpanded = !m_fExpanded; } else { if(m_owner->GetNavModel() == QR_SERVER) { id = 0; // Ignore the event down the road... } } } } else { if(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN && lButton == 1) { // // On Desktop, keep the node always open. // On Server, toggle its state. // if(m_owner->GetNavModel() == QR_DESKTOP) { m_fExpanded = true; } else { m_fExpanded = !m_fExpanded; } } } if(id == DISPID_HTMLELEMENTEVENTS_ONKEYDOWN) { switch(lKey) { case VK_RIGHT: m_fExpanded = m_owner->IsRTL() ? false : true ; break; case VK_LEFT : m_fExpanded = m_owner->IsRTL() ? true : false; break; } } if(id == DISPID_HTMLELEMENTEVENTS_ONKEYPRESS) { switch(lKey) { case VK_RETURN: m_fExpanded = true ; break; } } } //BUG 531001 (IAccessibility Default ACtions do not work) //ONCLICK event needs to be handled. It was being intercepted but not handled. //Replaced ONMOUSEUP handling with ONCLICK. if((id == DISPID_HTMLELEMENTEVENTS_ONCLICK ) || //(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEUP && lButton == 1 && fMouseDown) || (id == DISPID_HTMLELEMENTEVENTS_ONKEYPRESS && lKey == VK_RETURN )) { if(m_owner->m_nToSelect) { delete m_owner->m_nToSelect; m_owner->m_nToSelect = NULL; } __MPC_EXIT_IF_METHOD_FAILS(hr, m_owner->ChangeSelection( this, /*fNotify*/true )); } __MPC_EXIT_IF_METHOD_FAILS(hr, Display()); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// CPCHBehavior_BasicTree::CPCHBehavior_BasicTree() { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::CPCHBehavior_BasicTree" ); // CComBSTR m_bstrTargetFrame; // m_lCookie_onContextSelect = 0; // long m_lCookie_onContextSelect; m_lCookie_onSelect = 0; // long m_lCookie_onSelect; m_lCookie_onUnselect = 0; // long m_lCookie_onUnselect; // m_nTopNode = NULL; // Node* m_nTopNode; m_nSelected = NULL; // Node* m_nSelected; m_nCurrent = NULL; // Node* m_nCurrent; m_nToSelect = NULL; // NodeToSelect* m_nToSelect; // CPCHTimerHandle m_Timer; // m_fRefreshing = true; // bool m_fRefreshing; m_lNavModel = QR_DEFAULT; // long m_lNavModel; } CPCHBehavior_BasicTree::~CPCHBehavior_BasicTree() { (void)Empty(); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_BasicTree::RefreshThread() { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::RefreshThread" ); HRESULT hr; if(m_lNavModel == QR_DEFAULT) m_lNavModel = (m_parent->UserSettings()->IsDesktopSKU() ? QR_DESKTOP : QR_SERVER); __MPC_EXIT_IF_METHOD_FAILS(hr, RefreshThread_Enter()); // // Process database request. // while(Thread_IsAborted() == false) { SetRefreshingFlag( false ); Thread_WaitForEvents( NULL, INFINITE ); if(Thread_IsAborted()) break; SetRefreshingFlag( true ); if(m_nTopNode) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_nTopNode->ProcessRefreshRequest()); } } hr = S_OK; __HCP_FUNC_CLEANUP; SetRefreshingFlag( false ); RefreshThread_Leave(); Thread_Abort(); // Kill the thread. __HCP_FUNC_EXIT(hr); } void CPCHBehavior_BasicTree::SetRefreshingFlag( /*[in]*/ bool fVal ) { MPC::SmartLock<_ThreadModel> lock( this ); m_fRefreshing = fVal; } void CPCHBehavior_BasicTree::WaitForRefreshing( /*[in]*/ MPC::SmartLock<_ThreadModel>& lock , /*[in]*/ bool fYield ) { if(fYield) { lock = NULL; Thread_Signal(); ::Sleep( 0 ); // Yield processor. lock = this; } while(m_fRefreshing) { lock = NULL; if(Thread_IsRunning() == false) break; MPC::SleepWithMessagePump( 10 ); lock = this; } } HRESULT CPCHBehavior_BasicTree::NotifyMainThread( /*[in]*/ Node* node ) { CComQIPtr self = Thread_Self(); CComVariant v = node ? node->m_bstrNode : L""; return MPC::AsyncInvoke( self, DISPID_PCH_BEHAVIORS_PRIV__NEWDATAAVAILABLE, &v, 1 ); } HRESULT CPCHBehavior_BasicTree::ChangeSelection( /*[in]*/ Node* node , /*[in]*/ bool fNotify ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::ChangeSelection" ); HRESULT hr; if(m_nSelected) { m_nSelected->m_iSelection = SELECTION__NONE; __MPC_EXIT_IF_METHOD_FAILS(hr, m_nSelected->Display()); if(fNotify) { __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent( m_lCookie_onUnselect )); } } MPC::Attach( m_nSelected, node ); if(m_nSelected) { m_nSelected->m_iSelection = SELECTION__ACTIVE; __MPC_EXIT_IF_METHOD_FAILS(hr, m_nSelected->Display()); if(fNotify) { __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent( m_lCookie_onSelect )); } else { m_Timer.Start( this, TimerCallback_ScrollIntoView, 100 ); } } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } CPCHBehavior_BasicTree::Node* CPCHBehavior_BasicTree::NodeFromElement( /*[in]*/ IHTMLElement* elem ) { CComPtr elemDIV; if(SUCCEEDED(MPC::HTML::FindFirstParentWithThisTag( elemDIV, elem, L"DIV" )) && elemDIV) { CComBSTR bstrID; if(SUCCEEDED(MPC::HTML::GetUniqueID( bstrID, elemDIV ))) { return NodeFromKey( bstrID, true ); } } return NULL; } CPCHBehavior_BasicTree::Node* CPCHBehavior_BasicTree::NodeFromKey( /*[in]*/ LPCWSTR szNode, /*[in]*/ bool fUseID ) { return m_nTopNode ? m_nTopNode->FindNode( szNode, fUseID ) : NULL; } HRESULT CPCHBehavior_BasicTree::InterceptInvoke( /*[in]*/ DISPID dispidMember, /*[in]*/ DISPPARAMS* pdispparams ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::InterceptInvoke" ); HRESULT hr; if(dispidMember == DISPID_PCH_BEHAVIORS_PRIV__NEWDATAAVAILABLE && pdispparams->cArgs == 1 && pdispparams->rgvarg[0].vt == VT_BSTR ) { MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); Node* node; node = NodeFromKey( pdispparams->rgvarg[0].bstrVal ); if(node) { __MPC_EXIT_IF_METHOD_FAILS(hr, node->Display()); } hr = S_OK; } else { hr = E_INVALIDARG; } __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::TimerCallback_ScrollIntoView( /*[in]*/ VARIANT ) { if(m_nSelected && m_nSelected->m_DIV) { CComVariant v( VARIANT_TRUE ); (void)m_nSelected->m_DIV->scrollIntoView( v ); } return S_OK; } ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHBehavior_BasicTree::Init( /*[in]*/ IElementBehaviorSite* pBehaviorSite ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Init" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior::Init( pBehaviorSite )); m_Timer.Initialize( m_parent->Timer() ); __MPC_EXIT_IF_METHOD_FAILS(hr, AttachToEvents( s_events, (CLASS_METHOD)onMouse )); __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEvent( s_event_onContextSelect, m_lCookie_onContextSelect )); __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEvent( s_event_onSelect , m_lCookie_onSelect )); __MPC_EXIT_IF_METHOD_FAILS(hr, CreateEvent( s_event_onUnselect , m_lCookie_onUnselect )); //////////////////////////////////////////////////////////////////////////////// __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::GetPropertyByName( m_elem, L"target", m_bstrTargetFrame )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHBehavior_BasicTree::Detach() { Thread_Wait(); if(m_nTopNode) m_nTopNode->Passivate(); m_lCookie_onContextSelect = 0; m_lCookie_onSelect = 0; m_lCookie_onUnselect = 0; return CPCHBehavior::Detach(); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_BasicTree::Load( /*[in]*/ MPC::Serializer& stream ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Load" ); HRESULT hr; bool fNodePresent; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> fNodePresent); if(fNodePresent) { if(!m_nTopNode) { __MPC_EXIT_IF_METHOD_FAILS(hr, E_FAIL); } __MPC_EXIT_IF_METHOD_FAILS(hr, m_nTopNode->Load( stream )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Save( /*[in]*/ MPC::Serializer& stream ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Save" ); HRESULT hr; bool fNodePresent = (m_nTopNode != NULL); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << fNodePresent); if(m_nTopNode) __MPC_EXIT_IF_METHOD_FAILS(hr, m_nTopNode->Save( stream, /*fSaveChildren*/true )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// HRESULT CPCHBehavior_BasicTree::Persist_Load( /*[in]*/ BSTR newVal ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Persist_Load" ); HRESULT hr; CComPtr stream; HGLOBAL hg = NULL; Empty(); // // Convert BSTR to IStream. // { __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertHexToHGlobal( newVal, hg )); __MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateStreamOnHGlobal( hg, FALSE, &stream )); } // // Unserialize state from IStream. // { MPC::Serializer_IStream streamReal( stream ); MPC::Serializer_Buffering streamBuf ( streamReal ); DWORD dwVer; __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); __MPC_EXIT_IF_METHOD_FAILS(hr, Load( streamBuf )); } hr = S_OK; __HCP_FUNC_CLEANUP; if(hg) ::GlobalFree( hg ); __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_BasicTree::Persist_Save( /*[out, retval]*/ BSTR *pVal ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::Persist_Save" ); HRESULT hr; CComPtr streamResult; CComBSTR bstr; HGLOBAL hg; // // Serialize state to IStream. // { MPC::Serializer_IStream streamReal; MPC::Serializer_Buffering streamBuf( streamReal ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion ); __MPC_EXIT_IF_METHOD_FAILS(hr, Save( streamBuf )); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf .Flush ( )); // Flush buffering stream. __MPC_EXIT_IF_METHOD_FAILS(hr, streamReal.Reset ( )); // Rewind real stream. __MPC_EXIT_IF_METHOD_FAILS(hr, streamReal.GetStream( &streamResult )); // Extract pointer to IStream. } // // Convert IStream to BSTR. // { __MPC_EXIT_IF_METHOD_FAILS(hr, ::GetHGlobalFromStream( streamResult, &hg )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertHGlobalToHex( hg, bstr )); } *pVal = bstr.Detach(); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// void CPCHBehavior_BasicTree::Empty() { // CComBSTR m_bstrTargetFrame; // // long m_lCookie_onContextSelect; // long m_lCookie_onSelect; // long m_lCookie_onUnselect; // MPC::Release( m_nTopNode ); // Node* m_nTopNode; MPC::Release( m_nSelected ); // Node* m_nSelected; MPC::Release( m_nCurrent ); // Node* m_nCurrent; // NodeToSelect* m_nToSelect; // CPCHTimerHandle m_Timer; // // bool m_fRefreshing; m_lNavModel = QR_DEFAULT; // long m_lNavModel; if(m_nToSelect) { delete m_nToSelect; m_nToSelect = NULL; } } HRESULT CPCHBehavior_BasicTree::onMouse( DISPID id, DISPPARAMS*, VARIANT* ) { __HCP_FUNC_ENTRY( "CPCHBehavior_BasicTree::onMouse" ); HRESULT hr; CComPtr ev; CComPtr elemSrc; CComPtr elemTo; CComBSTR bstrTagName; long lButton; long lKey; bool fIsImage = false; bool fClicked = false; bool fContextMenu = false; bool fFocusEnter = false; bool fFocusLeave = false; Node* node = NULL; Node* nodeTo = NULL; AddRef(); // To protect against early deletion. __MPC_EXIT_IF_METHOD_FAILS(hr, GetEventObject( ev )); MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(elemSrc , ev , srcElement ); MPC_SCRIPTHELPER_GET__DIRECT (elemTo , ev , toElement ); MPC_SCRIPTHELPER_GET__DIRECT (lButton , ev , button ); MPC_SCRIPTHELPER_GET__DIRECT (lKey , ev , keyCode ); MPC_SCRIPTHELPER_GET__DIRECT (bstrTagName, elemSrc, tagName ); fIsImage = (MPC::StrICmp( bstrTagName, L"IMG" ) == 0); // // Find the node associated with the element. // node = NodeFromElement( elemSrc ); nodeTo = NodeFromElement( elemTo ); //////////////////////////////////////// if(g_Debug_CONTEXTMENU) { if(id == DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU) { VARIANT_BOOL fCtrlKey; MPC_SCRIPTHELPER_GET__DIRECT(fCtrlKey, ev, ctrlKey); if(fCtrlKey == VARIANT_TRUE) { id = 0; // Ignore event... } } } switch(id) { case DISPID_HTMLELEMENTEVENTS_ONCLICK : case DISPID_HTMLELEMENTEVENTS_ONMOUSEDOWN: case DISPID_HTMLELEMENTEVENTS_ONMOUSEUP : if(node) { bool fCancel = true; switch(node->m_iType) { case NODETYPE__FRAME1 : case NODETYPE__FRAME2 : case NODETYPE__FRAME3 : case NODETYPE__FRAME1_EXPAND: case NODETYPE__FRAME2_EXPAND: case NODETYPE__FRAME3_EXPAND: case NODETYPE__LINK : fCancel = false; // Let IE handle the navigation for these nodes... break; } if(!fCancel) break; } case DISPID_HTMLELEMENTEVENTS_ONSELECTSTART: case DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU: __MPC_EXIT_IF_METHOD_FAILS(hr, CancelEvent( ev )); break; } if(node) { if(id == DISPID_HTMLELEMENTEVENTS_ONMOUSEOUT && node == nodeTo) // We are moving within the node... { __MPC_EXIT_IF_METHOD_FAILS(hr, S_OK); } __MPC_EXIT_IF_METHOD_FAILS(hr, node->OnMouse( id, lButton, lKey, fIsImage )); if(id == DISPID_HTMLELEMENTEVENTS_ONCONTEXTMENU) { MPC::Attach( m_nCurrent, node ); __MPC_EXIT_IF_METHOD_FAILS(hr, FireEvent( m_lCookie_onContextSelect )); MPC::Release( m_nCurrent ); } } hr = S_OK; __HCP_FUNC_CLEANUP; Release(); // To protect against early deletion. __HCP_FUNC_EXIT(hr); }