1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: confevents.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
36 #include "confevents.hxx"
37 #include "configexcept.hxx"
38 #include "treechangelist.hxx"
39 #include <osl/diagnose.h>
42 /////////////////////////////////////////////////////////////////////////
43 ConfigChangeBroadcastHelper::ConfigChangeBroadcastHelper()
47 ConfigChangeBroadcastHelper::~ConfigChangeBroadcastHelper()
49 OSL_ENSURE(m_aListeners
.begin() == m_aListeners
.end(), "Remaining listeners found - forgot to dispose ?");
50 OSL_ENSURE(m_aPathMap
.empty(), "Spurious mappings found");
53 /////////////////////////////////////////////////////////////////////////
54 void ConfigChangeBroadcastHelper::dispose(TreeManager
* pSource
)
59 /////////////////////////////////////////////////////////////////////////
60 void ConfigChangeBroadcastHelper::addListener(configuration::AbsolutePath
const& aName
, rtl::Reference
<INodeListener
> const& pHandler
)
65 void ConfigChangeBroadcastHelper::removeListener(rtl::Reference
<INodeListener
> const& pHandler
)
70 /////////////////////////////////////////////////////////////////////////
71 void ConfigChangeBroadcastHelper::broadcast(TreeChangeList
const& anUpdate
, sal_Bool bError
, TreeManager
* pSource
)
73 dispatch(anUpdate
, bError
, pSource
);
76 /////////////////////////////////////////////////////////////////////////
77 void ConfigChangeBroadcastHelper::add(configuration::AbsolutePath
const& aName
, rtl::Reference
<INodeListener
> const& pListener
)
79 osl::MutexGuard
aGuard(m_aListeners
.mutex
);
81 internal::BroadcastImplHelper
<internal::NodeListenerInfo
>::Interfaces::iterator aAdded
= m_aListeners
.addListener(internal::NodeListenerInfo(pListener
));
82 aAdded
->addPath(aName
);
83 m_aPathMap
.insert(PathMap::value_type(aName
,aAdded
));
86 /////////////////////////////////////////////////////////////////////////
87 void ConfigChangeBroadcastHelper::remove(rtl::Reference
<INodeListener
> const& pListener
)
89 osl::MutexGuard
aGuard(m_aListeners
.mutex
);
91 internal::BroadcastImplHelper
<internal::NodeListenerInfo
>::Interfaces::const_iterator
const iter
= m_aListeners
.find(pListener
);
92 if (iter
!= m_aListeners
.end())
94 internal::NodeListenerInfo::Pathes
const& pathes
= iter
->pathList();
96 // first clear the Path Map
97 for(internal::NodeListenerInfo::Pathes::iterator itPath
= pathes
.begin(); itPath
!= pathes
.end(); ++itPath
)
99 std::pair
<PathMap::iterator
, PathMap::iterator
> aRange
= m_aPathMap
.equal_range(*itPath
);
100 while (aRange
.first
!= aRange
.second
)
102 PathMap::iterator cur
= aRange
.first
++;
103 if (cur
->second
== iter
)
104 m_aPathMap
.erase(cur
);
108 // the remove the broadcast helper entry
109 m_aListeners
.removeListener(pListener
);
113 /////////////////////////////////////////////////////////////////////////
114 // This should actually be available from the TreeChangeList
115 /////////////////////////////////////////////////////////////////////////
117 static Change
const* resolvePath(Change
const& rChange
, configuration::RelativePath
& aRelativePath
, RemoveNode
const*& pRemoveNode
)
119 std::vector
<configuration::Path::Component
>::const_reverse_iterator aIter
;
121 OSL_ASSERT(pRemoveNode
== NULL
);
124 Change
const* pChange
= &rChange
;
125 pRemoveNode
= dynamic_cast<RemoveNode
const*>(pChange
);
127 std::vector
<configuration::Path::Component
>::const_reverse_iterator
const aEnd(aRelativePath
.end());
129 for( aIter
= aRelativePath
.begin();
133 OSL_ASSERT( pChange
!= NULL
);
135 pChange
= pChange
->getSubChange(aIter
->getName());
137 if (pChange
== NULL
) break;
139 OSL_ASSERT(pRemoveNode
== NULL
);
140 OSL_ASSERT(aIter
->getName() == pChange
->getNodeName());
142 pRemoveNode
= dynamic_cast<RemoveNode
const*>(pChange
);
147 aRelativePath
= configuration::RelativePath( configuration::Path::Rep(aRelativePath
.begin(),aIter
) );
148 OSL_ASSERT( aRelativePath
.getLocalName().getName() == pRemoveNode
->getNodeName());
151 OSL_ASSERT( pChange
== 0 || configuration::matches(aRelativePath
, configuration::RelativePath( configuration::Path::Rep(aRelativePath
.begin(),aIter
) )) );
156 /////////////////////////////////////////////////////////////////////////
157 void ConfigChangeBroadcastHelper::dispatchInner
159 rtl::Reference
<INodeListener
> const& pTarget
,
160 configuration::AbsolutePath
const& _aTargetPath
,
161 Change
const& rBaseChange
,
162 configuration::AbsolutePath
const& _aChangeLocation
,
163 sal_Bool
, //_bError,
164 TreeManager
* pSource
169 OSL_ASSERT(pTarget
.is());
170 OSL_ASSERT( configuration::Path::hasPrefix( _aTargetPath
, _aChangeLocation
) );
172 configuration::RelativePath aLocalPath
= configuration::Path::stripPrefix( _aTargetPath
, _aChangeLocation
);
174 RemoveNode
const* pRemoved
= 0;
175 Change
const* pTargetChange
= resolvePath(rBaseChange
, aLocalPath
, pRemoved
);
177 OSL_ASSERT( !pTargetChange
|| matches(_aChangeLocation
.compose(aLocalPath
),_aTargetPath
) );
180 pTarget
->nodeDeleted(_aChangeLocation
.compose(aLocalPath
), pSource
);
182 else if (pTargetChange
)
183 pTarget
->nodeChanged(*pTargetChange
, _aTargetPath
, pSource
);
186 catch (configuration::InvalidName
& )
188 OSL_ENSURE(false,"ConfigChangeBroadcastHelper: Could not dispatch notification: context path mismatch");
192 /////////////////////////////////////////////////////////////////////////
193 void ConfigChangeBroadcastHelper::dispatchOuter
195 rtl::Reference
<INodeListener
> const& pTarget
,
196 configuration::AbsolutePath
const& _aTargetPath
,
197 Change
const& rBaseChange
,
198 configuration::AbsolutePath
const& _aChangeLocation
,
199 sal_Bool
, //_bError,
200 TreeManager
* pSource
203 { (void)_aTargetPath
; }
204 OSL_ASSERT(pTarget
.is());
205 OSL_ASSERT( configuration::Path::hasPrefix( _aChangeLocation
, _aTargetPath
) );
207 pTarget
->nodeChanged(rBaseChange
, _aChangeLocation
, pSource
);
210 /////////////////////////////////////////////////////////////////////////
211 void ConfigChangeBroadcastHelper::dispatch(TreeChangeList
const& rList_
, sal_Bool _bError
, TreeManager
* pSource
)
213 dispatch(rList_
.root
, rList_
.getRootNodePath(),_bError
, pSource
);
216 /////////////////////////////////////////////////////////////////////////
219 struct DispatchTarget
221 DispatchTarget(rtl::Reference
<INodeListener
> _pTarget
, configuration::AbsolutePath
const* _pDispatchPath
)
222 : pTarget(_pTarget
), pDispatchPath( _pDispatchPath
) {}
224 rtl::Reference
<INodeListener
> pTarget
;
225 configuration::AbsolutePath
const* pDispatchPath
;
228 /////////////////////////////////////////////////////////////////////////
229 void ConfigChangeBroadcastHelper::dispatch
231 Change
const& rBaseChange
,
232 configuration::AbsolutePath
const& _aChangeLocation
,
234 TreeManager
* pSource
237 OSL_ENSURE(!_aChangeLocation
.isRoot(),"Cannot dispatch changes directly to the root node");
239 // listeners registered under multiple sub-pathes will be called multiple times !
241 // Collect the targets
242 osl::ClearableMutexGuard
aGuard(m_aListeners
.mutex
);
244 // Dispatch listeners to ancestors of the change root
245 std::vector
<DispatchTarget
> aOuterTargets
;
246 if (_aChangeLocation
.getDepth() > 1)
248 configuration::AbsolutePath
const aModulePath( configuration::Path::Rep(*_aChangeLocation
.begin()) );
250 PathMap::const_iterator itOuter
= m_aPathMap
.lower_bound( aModulePath
);
251 PathMap::const_iterator
const endOuter
= m_aPathMap
.upper_bound(_aChangeLocation
.getParentPath());
253 // TODO: Both loops are so similar - they should be a single function
254 while (itOuter
!= endOuter
)
256 OSL_ASSERT( m_aListeners
.find(itOuter
->second
->get()) != m_aListeners
.end() );
258 // check whether this should be dispatched at all
259 if ( configuration::Path::hasPrefix(_aChangeLocation
,itOuter
->first
) )
261 aOuterTargets
.push_back( DispatchTarget(itOuter
->second
->get(), &itOuter
->first
) );
267 // Dispatch listeners to descendants of the change root
268 std::vector
<DispatchTarget
> aInnerTargets
;
270 PathMap::const_iterator itInner
= m_aPathMap
.lower_bound(_aChangeLocation
);
272 while( itInner
!= m_aPathMap
.end() && configuration::Path::hasPrefix(itInner
->first
,_aChangeLocation
) )
274 OSL_ASSERT( m_aListeners
.find(itInner
->second
->get()) != m_aListeners
.end() );
276 aInnerTargets
.push_back( DispatchTarget(itInner
->second
->get(), &itInner
->first
) );
284 {for (std::vector
<DispatchTarget
>::const_iterator it
= aOuterTargets
.begin(); it
!= aOuterTargets
.end(); ++it
){
285 this->dispatchOuter(it
->pTarget
, *it
->pDispatchPath
, rBaseChange
, _aChangeLocation
, _bError
, pSource
);
287 {for (std::vector
<DispatchTarget
>::const_iterator it
= aInnerTargets
.begin(); it
!= aInnerTargets
.end(); ++it
){
288 this->dispatchInner(it
->pTarget
, *it
->pDispatchPath
, rBaseChange
, _aChangeLocation
, _bError
, pSource
);
292 /////////////////////////////////////////////////////////////////////////
293 void ConfigChangeBroadcastHelper::disposing(TreeManager
* pSource
)
295 osl::ClearableMutexGuard
aGuard(m_aListeners
.mutex
);
299 m_aListeners
.disposing(pSource
);