merge the formfield patch from ooo-build
[ooovba.git] / configmgr / source / api / confevents.cxx
blobb99cd9b1f754f3be5bc9817d90f777316a7e83ef
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: confevents.cxx,v $
10 * $Revision: 1.11 $
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"
34 #include <stdio.h>
35 #include <string.h>
36 #include "confevents.hxx"
37 #include "configexcept.hxx"
38 #include "treechangelist.hxx"
39 #include <osl/diagnose.h>
40 namespace configmgr
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)
56 disposing(pSource);
59 /////////////////////////////////////////////////////////////////////////
60 void ConfigChangeBroadcastHelper::addListener(configuration::AbsolutePath const& aName, rtl::Reference<INodeListener> const& pHandler)
62 add(aName, pHandler);
65 void ConfigChangeBroadcastHelper::removeListener(rtl::Reference<INodeListener> const& pHandler)
67 remove(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);
122 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();
130 aIter != aEnd;
131 ++aIter)
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);
145 if (pRemoveNode)
147 aRelativePath = configuration::RelativePath( configuration::Path::Rep(aRelativePath.begin(),aIter) );
148 OSL_ASSERT( aRelativePath.getLocalName().getName() == pRemoveNode->getNodeName());
150 else
151 OSL_ASSERT( pChange == 0 || configuration::matches(aRelativePath, configuration::RelativePath( configuration::Path::Rep(aRelativePath.begin(),aIter) )) );
153 return pChange;
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) );
179 if (pRemoved)
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 /////////////////////////////////////////////////////////////////////////
217 namespace
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,
233 sal_Bool _bError,
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) );
263 ++itOuter;
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) );
278 ++itInner;
282 aGuard.clear();
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);
296 m_aPathMap.clear();
298 aGuard.clear();
299 m_aListeners.disposing(pSource);
302 } // namespace