Files
libreoffice/configmgr/source/api/confeventhelpers.cxx

383 lines
12 KiB
C++
Raw Normal View History

2000-09-18 15:18:56 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
2000-09-18 15:18:56 +00:00
*
* $RCSfile: confeventhelpers.cxx,v $
2000-09-18 15:18:56 +00:00
*
* $Revision: 1.15 $
2000-09-18 15:18:56 +00:00
*
* last change: $Author: ihi $ $Date: 2007-11-23 14:00:46 $
2000-09-18 15:18:56 +00:00
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
2000-09-18 15:18:56 +00:00
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
2000-09-18 15:18:56 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
2000-09-18 15:18:56 +00:00
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2000-09-18 15:18:56 +00:00
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
2000-09-18 15:18:56 +00:00
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"
2000-09-18 15:18:56 +00:00
#include <stdio.h>
2002-02-21 13:11:15 +00:00
#include <string.h>
2000-09-18 15:18:56 +00:00
#include "confeventhelpers.hxx"
#ifndef CONFIGMGR_CONFIGEXCEPT_HXX_
#include "configexcept.hxx"
#endif
#ifndef CONFIGMGR_CHANGE_HXX
#include "change.hxx"
#endif
#ifndef CONFIGMGR_TREECHANGELIST_HXX
#include "treechangelist.hxx"
2000-09-18 15:18:56 +00:00
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef INCLUDED_ALGORITHM
#include <algorithm>
#define INCLUDED_ALGORITHM
#endif
2000-09-18 15:18:56 +00:00
namespace configmgr
{
namespace internal
{
void throwDispatchIllegalSequenceException()
{
2001-03-21 11:06:54 +00:00
OSL_ENSURE( 0, "Illegal Call to brodcaster while dispatching" );
2000-09-18 15:18:56 +00:00
}
////////////////////////////////////////////////////////////////////////
using namespace configuration;
namespace Path = configuration::Path;
2000-09-18 15:18:56 +00:00
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
ConfigChangesBroadcasterImpl::ConfigChangesBroadcasterImpl()
{
}
/////////////////////////////////////////////////////////////////////////
ConfigChangesBroadcasterImpl::~ConfigChangesBroadcasterImpl()
{
OSL_ENSURE(m_aListeners.begin() == m_aListeners.end(), "Remaining listeners found - forgot to dispose ?");
OSL_ENSURE(m_aPathMap.empty(), "Spurious mappings found");
}
/////////////////////////////////////////////////////////////////////////
void ConfigChangesBroadcasterImpl::add(AbsolutePath const& aName, INodeListenerRef const& pListener)
2000-09-18 15:18:56 +00:00
{
osl::MutexGuard aGuard(m_aListeners.mutex);
InfoRef aAdded = m_aListeners.addListener(NodeListenerInfo(pListener));
aAdded->addPath(aName);
m_aPathMap.insert(PathMap::value_type(aName,aAdded));
}
/////////////////////////////////////////////////////////////////////////
void ConfigChangesBroadcasterImpl::remove(INodeListenerRef const& pListener)
2000-09-18 15:18:56 +00:00
{
osl::MutexGuard aGuard(m_aListeners.mutex);
Listeners::Iterator const iter = m_aListeners.find(pListener);
if (iter != m_aListeners.end())
{
typedef NodeListenerInfo::Pathes Pathes;
Pathes const& pathes = iter->pathList();
// first clear the Path Map
for(Pathes::iterator itPath = pathes.begin(); itPath != pathes.end(); ++itPath)
{
typedef PathMap::iterator PMIter;
typedef std::pair<PMIter, PMIter> PMRange;
PMRange aRange = m_aPathMap.equal_range(*itPath);
while (aRange.first != aRange.second)
{
PMIter cur = aRange.first++;
if (cur->second == iter)
m_aPathMap.erase(cur);
}
}
// the remove the broadcast helper entry
m_aListeners.removeListener(pListener);
}
}
/////////////////////////////////////////////////////////////////////////
// This should actually be available from the TreeChangeList
/////////////////////////////////////////////////////////////////////////
static Change const* resolvePath(Change const& rChange, RelativePath& aRelativePath, RemoveNode const*& pRemoveNode)
2000-09-18 15:18:56 +00:00
{
RelativePath::Iterator aIter;
OSL_ASSERT(pRemoveNode == NULL);
pRemoveNode = NULL;
2000-09-18 15:18:56 +00:00
Change const* pChange = &rChange;
if (rChange.ISA(RemoveNode))
pRemoveNode = static_cast<RemoveNode const*>(pChange);
2000-09-18 15:18:56 +00:00
RelativePath::Iterator const aEnd(aRelativePath.end());
2000-09-18 15:18:56 +00:00
for( aIter = aRelativePath.begin();
aIter != aEnd;
++aIter)
2000-09-18 15:18:56 +00:00
{
OSL_ASSERT( pChange != NULL );
pChange = pChange->getSubChange(aIter->getName().toString());
2000-09-18 15:18:56 +00:00
if (pChange == NULL) break;
2000-09-18 15:18:56 +00:00
OSL_ASSERT(pRemoveNode == NULL);
OSL_ASSERT(aIter->getName().toString() == pChange->getNodeName());
2000-09-18 15:18:56 +00:00
if (pChange->ISA(RemoveNode))
pRemoveNode = static_cast<RemoveNode const*>(pChange);
2000-09-18 15:18:56 +00:00
}
2000-09-18 15:18:56 +00:00
if (pRemoveNode)
{
aRelativePath = RelativePath( Path::Rep(aRelativePath.begin(),aIter) );
OSL_ASSERT( aRelativePath.getLocalName().getName().toString() == pRemoveNode->getNodeName());
2000-09-18 15:18:56 +00:00
}
else
OSL_ASSERT( pChange == 0 || configuration::matches(aRelativePath, RelativePath( Path::Rep(aRelativePath.begin(),aIter) )) );
2000-09-18 15:18:56 +00:00
return pChange;
}
/////////////////////////////////////////////////////////////////////////
void ConfigChangesBroadcasterImpl::dispatchInner
(
INodeListenerRef const& pTarget,
AbsolutePath const& _aTargetPath,
2000-09-18 15:18:56 +00:00
Change const& rBaseChange,
AbsolutePath const& _aChangeLocation,
2000-09-18 15:18:56 +00:00
sal_Bool , //_bError,
IConfigBroadcaster* pSource
)
{
using namespace configuration;
try
{
OSL_ASSERT(pTarget.is());
OSL_ASSERT( Path::hasPrefix( _aTargetPath, _aChangeLocation ) );
2000-09-18 15:18:56 +00:00
RelativePath aLocalPath = Path::stripPrefix( _aTargetPath, _aChangeLocation );
2000-09-18 15:18:56 +00:00
RemoveNode const* pRemoved = 0;
Change const* pTargetChange = resolvePath(rBaseChange, aLocalPath, pRemoved );
OSL_ASSERT( !pTargetChange || matches(_aChangeLocation.compose(aLocalPath),_aTargetPath) );
if (pRemoved)
pTarget->nodeDeleted(_aChangeLocation.compose(aLocalPath), pSource);
else if (pTargetChange)
pTarget->nodeChanged(*pTargetChange, _aTargetPath, pSource);
2000-09-18 15:18:56 +00:00
}
catch (InvalidName& )
2000-09-18 15:18:56 +00:00
{
OSL_ENSURE(false,"ConfigChangesBroadcasterImpl: Could not dispatch notification: context path mismatch");
2000-09-18 15:18:56 +00:00
}
}
/////////////////////////////////////////////////////////////////////////
void ConfigChangesBroadcasterImpl::dispatchOuter
(
INodeListenerRef const& pTarget,
AbsolutePath const& _aTargetPath,
2000-09-18 15:18:56 +00:00
Change const& rBaseChange,
AbsolutePath const& _aChangeLocation,
2000-09-18 15:18:56 +00:00
sal_Bool , //_bError,
IConfigBroadcaster* pSource
)
{
{ (void)_aTargetPath; }
OSL_ASSERT(pTarget.is());
OSL_ASSERT( Path::hasPrefix( _aChangeLocation, _aTargetPath) );
2000-09-18 15:18:56 +00:00
pTarget->nodeChanged(rBaseChange, _aChangeLocation, pSource);
2000-09-18 15:18:56 +00:00
}
/////////////////////////////////////////////////////////////////////////
void ConfigChangesBroadcasterImpl::dispatch(TreeChangeList const& rList_, sal_Bool _bError, IConfigBroadcaster* pSource)
2000-09-18 15:18:56 +00:00
{
dispatch(rList_.root, rList_.getRootNodePath(),_bError, pSource);
2000-09-18 15:18:56 +00:00
}
/////////////////////////////////////////////////////////////////////////
namespace
{
struct DispatchTarget
{
DispatchTarget(INodeListenerRef _pTarget, AbsolutePath const* _pDispatchPath)
: pTarget(_pTarget), pDispatchPath( _pDispatchPath) {}
INodeListenerRef pTarget;
AbsolutePath const* pDispatchPath;
};
typedef std::vector<DispatchTarget> DispatchTargets;
}
/////////////////////////////////////////////////////////////////////////
2000-09-18 15:18:56 +00:00
void ConfigChangesBroadcasterImpl::dispatch
(
Change const& rBaseChange,
AbsolutePath const& _aChangeLocation,
2000-09-18 15:18:56 +00:00
sal_Bool _bError,
IConfigBroadcaster* pSource
)
{
OSL_ENSURE(!_aChangeLocation.isRoot(),"Cannot dispatch changes directly to the root node");
2000-09-18 15:18:56 +00:00
// listeners registered under multiple sub-pathes will be called multiple times !
2000-09-18 15:18:56 +00:00
// Collect the targets
osl::ClearableMutexGuard aGuard(m_aListeners.mutex);
2000-09-18 15:18:56 +00:00
// Dispatch listeners to ancestors of the change root
DispatchTargets aOuterTargets;
if (_aChangeLocation.getDepth() > 1)
2000-09-18 15:18:56 +00:00
{
AbsolutePath const aModulePath( Path::Rep(*_aChangeLocation.begin()) );
2000-09-18 15:18:56 +00:00
PathMap::const_iterator itOuter = m_aPathMap.lower_bound( aModulePath );
PathMap::const_iterator const endOuter = m_aPathMap.upper_bound(_aChangeLocation.getParentPath());
2000-09-18 15:18:56 +00:00
// TODO: Both loops are so similar - they should be a single function
while (itOuter != endOuter)
{
OSL_ASSERT( m_aListeners.find(itOuter->second->get()) != m_aListeners.end() );
2000-09-18 15:18:56 +00:00
// check whether this should be dispatched at all
if ( Path::hasPrefix(_aChangeLocation,itOuter->first) )
{
aOuterTargets.push_back( DispatchTarget(itOuter->second->get(), &itOuter->first) );
}
++itOuter;
2000-09-18 15:18:56 +00:00
}
}
// Dispatch listeners to descendants of the change root
DispatchTargets aInnerTargets;
2000-09-18 15:18:56 +00:00
{
PathMap::const_iterator itInner = m_aPathMap.lower_bound(_aChangeLocation);
2000-09-18 15:18:56 +00:00
while( itInner != m_aPathMap.end() && Path::hasPrefix(itInner->first,_aChangeLocation) )
{
OSL_ASSERT( m_aListeners.find(itInner->second->get()) != m_aListeners.end() );
2000-09-18 15:18:56 +00:00
aInnerTargets.push_back( DispatchTarget(itInner->second->get(), &itInner->first) );
2000-09-18 15:18:56 +00:00
++itInner;
}
2000-09-18 15:18:56 +00:00
}
aGuard.clear();
{for (DispatchTargets::const_iterator it = aOuterTargets.begin(); it != aOuterTargets.end(); ++it){
this->dispatchOuter(it->pTarget, *it->pDispatchPath, rBaseChange, _aChangeLocation, _bError, pSource);
}}
{for (DispatchTargets::const_iterator it = aInnerTargets.begin(); it != aInnerTargets.end(); ++it){
this->dispatchInner(it->pTarget, *it->pDispatchPath, rBaseChange, _aChangeLocation, _bError, pSource);
}}
2000-09-18 15:18:56 +00:00
}
/////////////////////////////////////////////////////////////////////////
void ConfigChangesBroadcasterImpl::disposing(IConfigBroadcaster* pSource)
{
osl::ClearableMutexGuard aGuard(m_aListeners.mutex);
2000-09-18 15:18:56 +00:00
m_aPathMap.clear();
aGuard.clear();
2000-09-18 15:18:56 +00:00
m_aListeners.disposing(pSource);
}
/////////////////////////////////////////////////////////////////////////
/* class ConfigMessageBroadcasterImpl
{
public:
private:
typedef BroadcastImplHelper<INodeListener*> Listeners;
Listeners m_aListeners;
};
*/
/////////////////////////////////////////////////////////////////////////
/*void ConfigMessageBroadcasterImpl::add(IMessageHandler* pListener)
2000-09-18 15:18:56 +00:00
{
osl::MutexGuard aGuard(m_aListeners.mutex);
m_aListeners.addListener(pListener);
}
/////////////////////////////////////////////////////////////////////////
void ConfigMessageBroadcasterImpl::remove(IMessageHandler* pListener)
{
osl::MutexGuard aGuard(m_aListeners.mutex);
m_aListeners.removeListener(pListener);
}
/////////////////////////////////////////////////////////////////////////
void ConfigMessageBroadcasterImpl::dispatch(OUString const& _rNotifyReason, sal_Int32 _nNotificationId, IConfigBroadcaster* pSource)
{
osl::MutexGuard aGuard(m_aListeners.mutex);
for (Listeners::Iterator it = m_aListeners.begin(); it != m_aListeners.end(); )
{
// incrementing here allows a listener to remove itself from within the callback
// it is illegal to cause removal of another listener from the callback
// if this occurs (dereferencing, incrementing or comparing 'it' fails)
// we need to explicitly guard against that (which is really too expensive)
IMessageHandler* pHandler = *it;
++it;
if (pHandler)
pHandler->message(_rNotifyReason,_nNotificationId,pSource);
}
}
/////////////////////////////////////////////////////////////////////////
void ConfigMessageBroadcasterImpl::disposing(IConfigBroadcaster* pSource)
{
osl::MutexGuard aGuard(m_aListeners.mutex);
m_aListeners.disposing(pSource);
}
*/
2000-09-18 15:18:56 +00:00
/////////////////////////////////////////////////////////////////////////
} // namespace
} // namespace