Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

705 lines
17 KiB

/******************************************************************************
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<IPCHQueryResult> 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<CPCHQueryResultCollection> 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<CPCHQueryResultCollection> 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<lCount; lPos++)
{
CComPtr<CPCHQueryResult> 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<IPCHTaxonomyDatabase>( 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);
}