/****************************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: Behav_SUBSITE.cpp Abstract: This file contains the implementation of the CPCHBehavior_SUBSITE class. Revision History: Davide Massarenti (dmassare) 08/15/2000 created ******************************************************************************/ #include "stdafx.h" //////////////////////////////////////////////////////////////////////////////// CPCHBehavior_SUBSITE::QueryNode::QueryNode() { // CComPtr m_qrNode; m_fQueryDone = false; // bool m_fQueryDone; m_fTopic = false; // bool m_fTopic; }; CPCHBehavior_SUBSITE::QueryNode::~QueryNode() { ; } HRESULT CPCHBehavior_SUBSITE::QueryNode::Init( /*[in]*/ LPCWSTR szNode , /*[in]*/ NodeType iType , /*[in]*/ CPCHQueryResult* qr , /*[in]*/ bool fTopic ) { m_fTopic = fTopic; if(qr) { m_qrNode = qr; m_fQueryDone = true; m_fLoaded_Self = true; if(fTopic) { m_fLoaded_Children = true; } } return Node::Init( szNode, iType ); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_SUBSITE::QueryNode::ProcessRefreshRequest() { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::ProcessRefreshRequest" ); HRESULT hr; bool fNotify = false; NodeToSelect* nts; if(m_fLoaded_Self && m_fLoaded_Children && (nts = m_owner->GetNodeToSelect())) { bool fSelect = false; if(m_fTopic) { if(nts->m_bstrURL && MPC::StrICmp( m_bstrNode, nts->m_bstrURL ) == 0) { nts->m_bstrURL .Empty(); nts->m_bstrNode.Empty(); fSelect = true; } } else { if(nts->m_bstrNode && m_bstrNode) { int iSize = m_bstrNode.Length(); if(_wcsnicmp( m_bstrNode, nts->m_bstrNode, iSize ) == 0) { switch(nts->m_bstrNode[iSize]) { case 0: // Full match. nts->m_bstrNode.Empty(); m_fExpanded = true; fSelect = true; break; case '/': // Partial match, expand node. if(m_fExpanded == false) { m_fExpanded = true; fNotify = true; } break; } } } } if(fSelect) { Node* node = m_parent; // // Reset all the NEXTACTIVE flags for the parents, also expanding them. // while(node) { if(node->m_iSelection == SELECTION__NEXTACTIVE || node->m_iSelection == SELECTION__NEXTACTIVE_NOTIFY ) { node->m_iSelection = SELECTION__NONE; } node->m_fExpanded = true; node->NotifyMainThread(); node = node->m_parent; } m_iSelection = nts->m_fNotify ? SELECTION__NEXTACTIVE_NOTIFY : SELECTION__NEXTACTIVE; fNotify = true; } } __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior_BasicTree::Node::ProcessRefreshRequest()); hr = S_OK; __HCP_FUNC_CLEANUP; if(fNotify) NotifyMainThread(); __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_SUBSITE::QueryNode::CreateInstance( /*[in]*/ CPCHBehavior_BasicTree* owner, /*[in]*/ Node* parent, /*[out]*/ Node*& subnode ) { return CreateInstance_QueryNode( owner, parent, subnode ); } HRESULT CPCHBehavior_SUBSITE::QueryNode::CreateInstance_QueryNode( /*[in]*/ CPCHBehavior_BasicTree* owner, /*[in]*/ Node* parent, /*[out]*/ Node*& subnode ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::CreateInstance_QueryNode" ); HRESULT hr; QueryNode* node; __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &node )); node->m_owner = owner; node->m_parent = parent; hr = S_OK; __HCP_FUNC_CLEANUP; subnode = node; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_SUBSITE::QueryNode::PopulateSelf() { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::PopulateSelf" ); HRESULT hr; CPCHProxy_IPCHTaxonomyDatabase* db = (m_owner ? ((CPCHBehavior_SUBSITE*)m_owner)->m_db : NULL); if(m_fLoaded_Self == false && db) { // // Load self. // if(m_fTopic == false) { CComPtr pColl; if(SUCCEEDED(db->ExecuteQuery( OfflineCache::ET_NODE, m_bstrNode, &pColl ))) { m_qrNode.Release(); if(SUCCEEDED(pColl->GetItem( 0, &m_qrNode ))) { if(m_parent == NULL) { m_owner->SetNavModel( m_qrNode->GetData().m_lNavModel ); } } } m_fQueryDone = true; } else { m_fLoaded_Children = true; } m_fLoaded_Self = true; } hr = S_OK; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_SUBSITE::QueryNode::PopulateChildren() { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::PopulateChildren" ); HRESULT hr; CPCHProxy_IPCHTaxonomyDatabase* db = (m_owner ? ((CPCHBehavior_SUBSITE*)m_owner)->m_db : NULL); if(m_fLoaded_Children == false && db) { // // Load sub nodes. // if(m_fTopic == false) { CComPtr pColl; int iType; iType = (m_owner->GetNavModel() == QR_DESKTOP ? OfflineCache::ET_SUBNODES_VISIBLE : OfflineCache::ET_NODESANDTOPICS_VISIBLE); if(SUCCEEDED(db->ExecuteQuery( iType, m_bstrNode, &pColl ))) { long lPos; long lCount; MPC_SCRIPTHELPER_GET__DIRECT(lCount, pColl, Count); for(lPos=0; lPos qr; CComBSTR bstrNode; CComBSTR bstrEntry; QueryNode* node; bool fTopic; __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->GetItem( lPos, &qr )); { const CPCHQueryResult::Payload& pl = qr->GetData(); __MPC_EXIT_IF_METHOD_FAILS(hr, CreateInstance_QueryNode( m_owner, this, (Node*&)node )); m_lstSubnodes.push_back( node ); if(pl.m_bstrEntry.Length() > 0) // It's a node. { MPC_SCRIPTHELPER_GET__DIRECT(bstrNode, qr, FullPath); fTopic = false; } else { bstrNode = pl.m_bstrTopicURL; fTopic = true; } } __MPC_EXIT_IF_METHOD_FAILS(hr, node->Init( bstrNode, fTopic ? NODETYPE__EXPANDO_TOPIC : NODETYPE__EXPANDO, qr, fTopic )); } } } m_fLoaded_Children = true; } hr = S_OK; __HCP_FUNC_CLEANUP; if(FAILED(hr)) { MPC::CallDestructorForAll( m_lstSubnodes ); m_fInvalid = true; m_fLoaded_Children = true; hr = S_OK; } __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_SUBSITE::QueryNode::GenerateSelf() { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::GenerateSelf" ); HRESULT hr; if(!m_fInvalid) { if(!m_fLoaded_Self || !m_fLoaded_Children || !m_fQueryDone) { m_owner->Thread_Signal(); // Tell the worker thread to process something... } if(!m_fLoaded_Self || !m_fQueryDone) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_NOT_READY); } } //////////////////// if(m_qrNode) { const CPCHQueryResult::Payload& pl = m_qrNode->GetData(); LPCWSTR szTitle = pl.m_bstrTitle ? pl.m_bstrTitle : pl.m_bstrCategory; LPCWSTR szDesc = pl.m_bstrDescription; LPCWSTR szIcon = pl.m_bstrIconURL; LPCWSTR szURL = pl.m_bstrTopicURL; __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateHTML( szTitle, szDesc, szIcon, szURL )); } else { MPC::wstring strTitle; MPC::LocalizeString( IDS_HELPCTR_TAXO_UNKNOWN_NODE, strTitle ); __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateHTML( strTitle.c_str(), NULL, NULL, NULL )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_SUBSITE::QueryNode::Load( /*[in]*/ MPC::Serializer& stream ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::Load" ); HRESULT hr; bool fSavedNode; __MPC_EXIT_IF_METHOD_FAILS(hr, Node::Load( stream )); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fLoaded_Self); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fTopic ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> fSavedNode ); if(fSavedNode) { m_qrNode.Release(); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &m_qrNode )); __MPC_EXIT_IF_METHOD_FAILS(hr, m_qrNode->Load( stream )); m_fQueryDone = true; } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_SUBSITE::QueryNode::Save( /*[in]*/ MPC::Serializer& stream, /*[in]*/ bool fSaveChildren ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::QueryNode::Save" ); HRESULT hr; bool fSaveNode = (m_fLoaded_Self && m_qrNode); if(m_fExpanded == false) fSaveChildren = false; __MPC_EXIT_IF_METHOD_FAILS(hr, Node::Save( stream, fSaveChildren )); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fLoaded_Self); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fTopic ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << fSaveNode ); if(fSaveNode) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_qrNode->Save( stream )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// CPCHBehavior_SUBSITE::CPCHBehavior_SUBSITE() { m_db = NULL; // CPCHProxy_IPCHTaxonomyDatabase* m_db; // CComBSTR m_bstrRoot; m_fExpand = false; // bool m_fExpand; } HRESULT CPCHBehavior_SUBSITE::RefreshThread_Enter() { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::RefreshThread_Enter" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Utility()->GetDatabase( &m_db )); if(m_nTopNode == NULL) { // // Generate the outer UI. // __MPC_EXIT_IF_METHOD_FAILS(hr, QueryNode::CreateInstance_QueryNode( this, NULL, m_nTopNode )); { QueryNode* node = (QueryNode*)m_nTopNode; __MPC_EXIT_IF_METHOD_FAILS(hr, node->Init ( m_bstrRoot, m_fExpand ? NODETYPE__FRAME1_EXPAND : NODETYPE__FRAME2, NULL, /*fTopic*/false )); __MPC_EXIT_IF_METHOD_FAILS(hr, node->PopulateSelf ( )); __MPC_EXIT_IF_METHOD_FAILS(hr, node->PopulateChildren( )); node->m_parentElement = m_elem; } } m_nTopNode->NotifyMainThread(); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } void CPCHBehavior_SUBSITE::RefreshThread_Leave() { MPC::Release2( m_db ); } //////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHBehavior_SUBSITE::Invoke( DISPID dispidMember , REFIID riid , LCID lcid , WORD wFlags , DISPPARAMS* pdispparams , VARIANT* pvarResult , EXCEPINFO* pexcepinfo , UINT* puArgErr ) { if(SUCCEEDED(InterceptInvoke( dispidMember, pdispparams ))) return S_OK; return CPCHBehavior__IDispatch_SubSite::Invoke( dispidMember , riid , lcid , wFlags , pdispparams , pvarResult , pexcepinfo , puArgErr ); } STDMETHODIMP CPCHBehavior_SUBSITE::Init( /*[in]*/ IElementBehaviorSite* pBehaviorSite ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Init" ); HRESULT hr; CComVariant v; __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior_BasicTree::Init( pBehaviorSite )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::GetPropertyByName( m_elem, L"expand", v )); if(SUCCEEDED(v.ChangeType( VT_BOOL )) && v.boolVal == VARIANT_TRUE) m_fExpand = true; __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::GetPropertyByName( m_elem, L"root", m_bstrRoot )); if(m_bstrRoot.Length()) { __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, RefreshThread, this )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } ///////////////////////////////////////////////////////////////////////////// HRESULT CPCHBehavior_SUBSITE::Load( /*[in]*/ MPC::Serializer& stream ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Load" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_bstrRoot ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_lNavModel); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fExpand ); // // Create top level node. // __MPC_EXIT_IF_METHOD_FAILS(hr, QueryNode::CreateInstance_QueryNode( this, NULL, m_nTopNode )); { QueryNode* node = (QueryNode*)m_nTopNode; __MPC_EXIT_IF_METHOD_FAILS(hr, node->Init( m_bstrRoot, m_fExpand ? NODETYPE__FRAME1_EXPAND : NODETYPE__FRAME2, NULL, /*fTopic*/false )); node->m_parentElement = m_elem; } __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior_BasicTree::Load( stream )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHBehavior_SUBSITE::Save( /*[in]*/ MPC::Serializer& stream ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Save" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_bstrRoot ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_lNavModel); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fExpand ); __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHBehavior_BasicTree::Save( stream )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHBehavior_SUBSITE::get_data( /*[out, retval]*/ VARIANT *pVal ) { MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); QueryNode* node = (QueryNode*)(m_nCurrent ? m_nCurrent : m_nSelected); return GetAsVARIANT( node ? node->m_qrNode : NULL, pVal ); } STDMETHODIMP CPCHBehavior_SUBSITE::get_element( /*[out, retval]*/ IDispatch* *pVal ) { MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); QueryNode* node = (QueryNode*)(m_nCurrent ? m_nCurrent : m_nSelected); return GetAsIDISPATCH( node ? node->m_DIV : NULL, pVal ); } STDMETHODIMP CPCHBehavior_SUBSITE::Load( /*[in]*/ BSTR newVal ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Load" ); HRESULT hr; Thread_Wait(); __MPC_EXIT_IF_METHOD_FAILS(hr, Persist_Load( newVal )); __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, RefreshThread, this )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHBehavior_SUBSITE::Save( /*[out, retval]*/ BSTR *pVal ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Save" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, Persist_Save( pVal )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHBehavior_SUBSITE::Locate( /*[in ]*/ BSTR bstrKey , /*[out, retval]*/ VARIANT *pVal ) { MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); QueryNode* node = (QueryNode*)NodeFromKey( bstrKey ); return GetAsVARIANT( node ? node->m_qrNode : NULL, pVal ); } STDMETHODIMP CPCHBehavior_SUBSITE::Unselect() { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Unselect" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); __MPC_EXIT_IF_METHOD_FAILS(hr, ChangeSelection( NULL, /*fNotify*/true )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHBehavior_SUBSITE::get_root( /*[out, retval]*/ BSTR *pVal ) { return MPC::GetBSTR( m_bstrRoot, pVal ); } STDMETHODIMP CPCHBehavior_SUBSITE::put_root( /*[in]*/ BSTR pVal ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::put_root" ); HRESULT hr; Thread_Wait(); Empty(); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( m_bstrRoot, pVal )); __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, RefreshThread, this )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHBehavior_SUBSITE::Select( /*[in]*/ BSTR bstrNode , /*[in]*/ BSTR bstrURL , /*[in]*/ VARIANT_BOOL fNotify ) { __HCP_FUNC_ENTRY( "CPCHBehavior_SUBSITE::Select" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); WaitForRefreshing( lock ); delete m_nToSelect; __MPC_EXIT_IF_ALLOC_FAILS(hr, m_nToSelect, new NodeToSelect); m_nToSelect->m_bstrNode = bstrNode; m_nToSelect->m_bstrURL = bstrURL; m_nToSelect->m_fNotify = fNotify == VARIANT_TRUE; Thread_Signal(); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); }