summaryrefslogtreecommitdiff
path: root/configmgr/source/api/confevents.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'configmgr/source/api/confevents.cxx')
-rw-r--r--configmgr/source/api/confevents.cxx299
1 files changed, 223 insertions, 76 deletions
diff --git a/configmgr/source/api/confevents.cxx b/configmgr/source/api/confevents.cxx
index a1e4e59537..b99cd9b1f7 100644
--- a/configmgr/source/api/confevents.cxx
+++ b/configmgr/source/api/confevents.cxx
@@ -34,123 +34,270 @@
#include <stdio.h>
#include <string.h>
#include "confevents.hxx"
-#include "confeventhelpers.hxx"
+#include "configexcept.hxx"
#include "treechangelist.hxx"
#include <osl/diagnose.h>
namespace configmgr
{
/////////////////////////////////////////////////////////////////////////
- using internal::ConfigChangesBroadcasterImpl;
-
- /////////////////////////////////////////////////////////////////////////
- class ConfigChangeBroadcastHelper // broadcasts changes for a given set of options
- {
- ConfigChangesBroadcasterImpl m_changes;
- public:
- ConfigChangeBroadcastHelper();
- ~ConfigChangeBroadcastHelper();
-
- void broadcast(TreeChangeList const& anUpdate, sal_Bool bError, IConfigBroadcaster* pSource);
-
- public:
- // IConfigBroadcaster implementation helper
- void addListener(AbsolutePath const& aName, INodeListenerRef const& );
- void removeListener(INodeListenerRef const&);
-
- void dispose(IConfigBroadcaster* pSource);
- };
-
- /////////////////////////////////////////////////////////////////////////
- ConfigChangeBroadcaster::ConfigChangeBroadcaster()
- {
- }
-
- ConfigChangeBroadcaster::~ConfigChangeBroadcaster()
- {
- }
-
- /////////////////////////////////////////////////////////////////////////
ConfigChangeBroadcastHelper::ConfigChangeBroadcastHelper()
- : m_changes()
{
}
ConfigChangeBroadcastHelper::~ConfigChangeBroadcastHelper()
{
+ OSL_ENSURE(m_aListeners.begin() == m_aListeners.end(), "Remaining listeners found - forgot to dispose ?");
+ OSL_ENSURE(m_aPathMap.empty(), "Spurious mappings found");
}
/////////////////////////////////////////////////////////////////////////
- void ConfigChangeBroadcastHelper::dispose(IConfigBroadcaster* pSource)
+ void ConfigChangeBroadcastHelper::dispose(TreeManager * pSource)
{
- m_changes.disposing(pSource);
+ disposing(pSource);
}
/////////////////////////////////////////////////////////////////////////
- // IConfigBroadcaster implementation
- void ConfigChangeBroadcaster::addListener(AbsolutePath const& aName, RequestOptions const & _aOptions, INodeListenerRef const& pHandler)
+ void ConfigChangeBroadcastHelper::addListener(configuration::AbsolutePath const& aName, rtl::Reference<INodeListener> const& pHandler)
{
- if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(_aOptions,true))
- {
- pHelper->addListener(aName, pHandler);
- }
- else
- OSL_ASSERT(false);
+ add(aName, pHandler);
}
- void ConfigChangeBroadcaster::removeListener(RequestOptions const & _aOptions, INodeListenerRef const& pHandler)
+ void ConfigChangeBroadcastHelper::removeListener(rtl::Reference<INodeListener> const& pHandler)
{
- if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(_aOptions,false))
- {
- pHelper->removeListener( pHandler);
- }
+ remove(pHandler);
}
/////////////////////////////////////////////////////////////////////////
- void ConfigChangeBroadcaster::fireChanges(TreeChangeList const& rList_, sal_Bool bError_)
+ void ConfigChangeBroadcastHelper::broadcast(TreeChangeList const& anUpdate, sal_Bool bError, TreeManager * pSource)
+ {
+ dispatch(anUpdate, bError, pSource);
+ }
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::add(configuration::AbsolutePath const& aName, rtl::Reference<INodeListener> const& pListener)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ internal::BroadcastImplHelper<internal::NodeListenerInfo>::Interfaces::iterator aAdded = m_aListeners.addListener(internal::NodeListenerInfo(pListener));
+ aAdded->addPath(aName);
+ m_aPathMap.insert(PathMap::value_type(aName,aAdded));
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::remove(rtl::Reference<INodeListener> const& pListener)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ internal::BroadcastImplHelper<internal::NodeListenerInfo>::Interfaces::const_iterator const iter = m_aListeners.find(pListener);
+ if (iter != m_aListeners.end())
{
- if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(rList_.getOptions(),false))
+ internal::NodeListenerInfo::Pathes const& pathes = iter->pathList();
+
+ // first clear the Path Map
+ for(internal::NodeListenerInfo::Pathes::iterator itPath = pathes.begin(); itPath != pathes.end(); ++itPath)
{
- pHelper->broadcast(rList_, bError_, this);
+ std::pair<PathMap::iterator, PathMap::iterator> aRange = m_aPathMap.equal_range(*itPath);
+ while (aRange.first != aRange.second)
+ {
+ PathMap::iterator cur = aRange.first++;
+ if (cur->second == iter)
+ m_aPathMap.erase(cur);
+ }
}
+
+ // the remove the broadcast helper entry
+ m_aListeners.removeListener(pListener);
}
+}
- /////////////////////////////////////////////////////////////////////////
- ConfigChangeBroadcastHelper* ConfigChangeBroadcaster::newBroadcastHelper()
+/////////////////////////////////////////////////////////////////////////
+// This should actually be available from the TreeChangeList
+/////////////////////////////////////////////////////////////////////////
+
+static Change const* resolvePath(Change const& rChange, configuration::RelativePath& aRelativePath, RemoveNode const*& pRemoveNode)
+{
+ std::vector<configuration::Path::Component>::const_reverse_iterator aIter;
+
+ OSL_ASSERT(pRemoveNode == NULL);
+ pRemoveNode = NULL;
+
+ Change const* pChange = &rChange;
+ pRemoveNode = dynamic_cast<RemoveNode const*>(pChange);
+
+ std::vector<configuration::Path::Component>::const_reverse_iterator const aEnd(aRelativePath.end());
+
+ for( aIter = aRelativePath.begin();
+ aIter != aEnd;
+ ++aIter)
{
- return new ConfigChangeBroadcastHelper();
+ OSL_ASSERT( pChange != NULL );
+
+ pChange = pChange->getSubChange(aIter->getName());
+
+ if (pChange == NULL) break;
+
+ OSL_ASSERT(pRemoveNode == NULL);
+ OSL_ASSERT(aIter->getName() == pChange->getNodeName());
+
+ pRemoveNode = dynamic_cast<RemoveNode const*>(pChange);
}
- /////////////////////////////////////////////////////////////////////////
- void ConfigChangeBroadcaster::disposeBroadcastHelper(ConfigChangeBroadcastHelper* pHelper)
+
+ if (pRemoveNode)
{
- if (pHelper)
- {
- pHelper->dispose(this);
- delete pHelper;
- }
- }
- /////////////////////////////////////////////////////////////////////////
- // IConfigBroadcaster implementation help
- void ConfigChangeBroadcastHelper::addListener(AbsolutePath const& aName, INodeListenerRef const& pHandler)
- {
- m_changes.add(aName, pHandler);
+ aRelativePath = configuration::RelativePath( configuration::Path::Rep(aRelativePath.begin(),aIter) );
+ OSL_ASSERT( aRelativePath.getLocalName().getName() == pRemoveNode->getNodeName());
}
+ else
+ OSL_ASSERT( pChange == 0 || configuration::matches(aRelativePath, configuration::RelativePath( configuration::Path::Rep(aRelativePath.begin(),aIter) )) );
+
+ return pChange;
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::dispatchInner
+(
+ rtl::Reference<INodeListener> const& pTarget,
+ configuration::AbsolutePath const& _aTargetPath,
+ Change const& rBaseChange,
+ configuration::AbsolutePath const& _aChangeLocation,
+ sal_Bool , //_bError,
+ TreeManager * pSource
+)
+{
+ try
+ {
+ OSL_ASSERT(pTarget.is());
+ OSL_ASSERT( configuration::Path::hasPrefix( _aTargetPath, _aChangeLocation ) );
+
+ configuration::RelativePath aLocalPath = configuration::Path::stripPrefix( _aTargetPath, _aChangeLocation );
+
+ 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);
- void ConfigChangeBroadcastHelper::removeListener(INodeListenerRef const& pHandler)
- {
- m_changes.remove(pHandler);
}
+ catch (configuration::InvalidName& )
+ {
+ OSL_ENSURE(false,"ConfigChangeBroadcastHelper: Could not dispatch notification: context path mismatch");
+ }
+}
-/* void ConfigChangeBroadcastHelper::removeNode(OUString const& aPath, bool bRemovedFromModel, IConfigBroadcaster* pSource)
- {
- m_changes.removed(aPath, bRemovedFromModel,pSource);
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::dispatchOuter
+(
+ rtl::Reference<INodeListener> const& pTarget,
+ configuration::AbsolutePath const& _aTargetPath,
+ Change const& rBaseChange,
+ configuration::AbsolutePath const& _aChangeLocation,
+ sal_Bool , //_bError,
+ TreeManager * pSource
+)
+{
+ { (void)_aTargetPath; }
+ OSL_ASSERT(pTarget.is());
+ OSL_ASSERT( configuration::Path::hasPrefix( _aChangeLocation, _aTargetPath) );
+
+ pTarget->nodeChanged(rBaseChange, _aChangeLocation, pSource);
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::dispatch(TreeChangeList const& rList_, sal_Bool _bError, TreeManager * pSource)
+{
+ dispatch(rList_.root, rList_.getRootNodePath(),_bError, pSource);
+}
+
+/////////////////////////////////////////////////////////////////////////
+namespace
+{
+ struct DispatchTarget
+ {
+ DispatchTarget(rtl::Reference<INodeListener> _pTarget, configuration::AbsolutePath const* _pDispatchPath)
+ : pTarget(_pTarget), pDispatchPath( _pDispatchPath) {}
+
+ rtl::Reference<INodeListener> pTarget;
+ configuration::AbsolutePath const* pDispatchPath;
+ };
+}
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::dispatch
+(
+ Change const& rBaseChange,
+ configuration::AbsolutePath const& _aChangeLocation,
+ sal_Bool _bError,
+ TreeManager * pSource
+)
+{
+ OSL_ENSURE(!_aChangeLocation.isRoot(),"Cannot dispatch changes directly to the root node");
+
+ // listeners registered under multiple sub-pathes will be called multiple times !
+
+ // Collect the targets
+ osl::ClearableMutexGuard aGuard(m_aListeners.mutex);
+
+ // Dispatch listeners to ancestors of the change root
+ std::vector<DispatchTarget> aOuterTargets;
+ if (_aChangeLocation.getDepth() > 1)
+ {
+ configuration::AbsolutePath const aModulePath( configuration::Path::Rep(*_aChangeLocation.begin()) );
+
+ PathMap::const_iterator itOuter = m_aPathMap.lower_bound( aModulePath );
+ PathMap::const_iterator const endOuter = m_aPathMap.upper_bound(_aChangeLocation.getParentPath());
+
+ // 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() );
+
+ // check whether this should be dispatched at all
+ if ( configuration::Path::hasPrefix(_aChangeLocation,itOuter->first) )
+ {
+ aOuterTargets.push_back( DispatchTarget(itOuter->second->get(), &itOuter->first) );
+ }
+ ++itOuter;
+ }
}
-*/
- /////////////////////////////////////////////////////////////////////////
- void ConfigChangeBroadcastHelper::broadcast(TreeChangeList const& anUpdate, sal_Bool bError, IConfigBroadcaster* pSource)
+
+ // Dispatch listeners to descendants of the change root
+ std::vector<DispatchTarget> aInnerTargets;
{
- m_changes.dispatch(anUpdate, bError, pSource);
+ PathMap::const_iterator itInner = m_aPathMap.lower_bound(_aChangeLocation);
+
+ while( itInner != m_aPathMap.end() && configuration::Path::hasPrefix(itInner->first,_aChangeLocation) )
+ {
+ OSL_ASSERT( m_aListeners.find(itInner->second->get()) != m_aListeners.end() );
+
+ aInnerTargets.push_back( DispatchTarget(itInner->second->get(), &itInner->first) );
+
+ ++itInner;
+ }
}
+ aGuard.clear();
+
+ {for (std::vector<DispatchTarget>::const_iterator it = aOuterTargets.begin(); it != aOuterTargets.end(); ++it){
+ this->dispatchOuter(it->pTarget, *it->pDispatchPath, rBaseChange, _aChangeLocation, _bError, pSource);
+ }}
+ {for (std::vector<DispatchTarget>::const_iterator it = aInnerTargets.begin(); it != aInnerTargets.end(); ++it){
+ this->dispatchInner(it->pTarget, *it->pDispatchPath, rBaseChange, _aChangeLocation, _bError, pSource);
+ }}
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangeBroadcastHelper::disposing(TreeManager * pSource)
+{
+ osl::ClearableMutexGuard aGuard(m_aListeners.mutex);
+ m_aPathMap.clear();
+
+ aGuard.clear();
+ m_aListeners.disposing(pSource);
+}
} // namespace