merge the formfield patch from ooo-build
[ooovba.git] / sd / source / ui / framework / configuration / ConfigurationUpdater.cxx
blobc2922eb5b8823e85d83553c5e31735caf96ad746
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: ConfigurationUpdater.cxx,v $
10 * $Revision: 1.6 $
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 #include "precompiled_sd.hxx"
33 #include "ConfigurationUpdater.hxx"
34 #include "ConfigurationTracer.hxx"
35 #include "ConfigurationClassifier.hxx"
36 #include "ConfigurationControllerBroadcaster.hxx"
37 #include "framework/Configuration.hxx"
38 #include "framework/FrameworkHelper.hxx"
40 #include <comphelper/scopeguard.hxx>
42 #include <boost/bind.hpp>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::drawing::framework;
47 using ::sd::framework::FrameworkHelper;
48 using ::rtl::OUString;
49 using ::std::vector;
51 #undef VERBOSE
52 #define VERBOSE 2
54 namespace {
55 static const sal_Int32 snShortTimeout (100);
56 static const sal_Int32 snNormalTimeout (1000);
57 static const sal_Int32 snLongTimeout (10000);
58 static const sal_Int32 snShortTimeoutCountThreshold (1);
59 static const sal_Int32 snNormalTimeoutCountThreshold (5);
62 namespace sd { namespace framework {
65 //===== ConfigurationUpdaterLock ==============================================
67 class ConfigurationUpdaterLock
69 public:
70 ConfigurationUpdaterLock (ConfigurationUpdater& rUpdater)
71 : mrUpdater(rUpdater) { mrUpdater.LockUpdates(); }
72 ~ConfigurationUpdaterLock(void) { mrUpdater.UnlockUpdates(); }
73 private:
74 ConfigurationUpdater& mrUpdater;
80 //===== ConfigurationUpdater ==================================================
82 ConfigurationUpdater::ConfigurationUpdater (
83 const ::boost::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster,
84 const ::boost::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager,
85 const Reference<XControllerManager>& rxControllerManager)
86 : mxControllerManager(),
87 mpBroadcaster(rpBroadcaster),
88 mxCurrentConfiguration(Reference<XConfiguration>(new Configuration(NULL, false))),
89 mxRequestedConfiguration(),
90 mbUpdatePending(false),
91 mbUpdateBeingProcessed(false),
92 mnLockCount(0),
93 maUpdateTimer(),
94 mnFailedUpdateCount(0),
95 mpResourceManager(rpResourceManager)
97 // Prepare the timer that is started when after an update the current
98 // and the requested configuration differ. With the timer we try
99 // updates until the two configurations are the same.
100 maUpdateTimer.SetTimeout(snNormalTimeout);
101 maUpdateTimer.SetTimeoutHdl(LINK(this,ConfigurationUpdater,TimeoutHandler));
102 SetControllerManager(rxControllerManager);
108 ConfigurationUpdater::~ConfigurationUpdater (void)
110 maUpdateTimer.Stop();
116 void ConfigurationUpdater::SetControllerManager(
117 const Reference<XControllerManager>& rxControllerManager)
119 mxControllerManager = rxControllerManager;
125 void ConfigurationUpdater::RequestUpdate (
126 const Reference<XConfiguration>& rxRequestedConfiguration)
128 mxRequestedConfiguration = rxRequestedConfiguration;
130 // Find out whether we really can update the configuration.
131 if (IsUpdatePossible())
133 #if defined VERBOSE && VERBOSE>=1
134 OSL_TRACE("UpdateConfiguration start\n");
135 #endif
137 // Call UpdateConfiguration while that is possible and while someone
138 // set mbUpdatePending to true in the middle of it.
141 UpdateConfiguration();
143 if (mbUpdatePending && IsUpdatePossible())
144 continue;
146 while (false);
148 else
150 mbUpdatePending = true;
151 #if defined VERBOSE && VERBOSE>=1
152 OSL_TRACE("scheduling update for later\n");
153 #endif
160 Reference<XConfiguration> ConfigurationUpdater::GetCurrentConfiguration (void) const
162 return mxCurrentConfiguration;
168 Reference<XConfiguration> ConfigurationUpdater::GetRequestedConfiguration (void) const
170 return mxRequestedConfiguration;
176 bool ConfigurationUpdater::IsUpdatePossible (void)
178 return ! mbUpdateBeingProcessed
179 && mxControllerManager.is()
180 && mnLockCount==0
181 && mxRequestedConfiguration.is()
182 && mxCurrentConfiguration.is();
188 void ConfigurationUpdater::UpdateConfiguration (void)
190 #if defined VERBOSE && VERBOSE>=1
191 OSL_TRACE("UpdateConfiguration update\n");
192 #endif
193 SetUpdateBeingProcessed(true);
194 comphelper::ScopeGuard aScopeGuard (
195 ::boost::bind(&ConfigurationUpdater::SetUpdateBeingProcessed, this, false));
199 mbUpdatePending = false;
201 CleanRequestedConfiguration();
202 ConfigurationClassifier aClassifier(mxRequestedConfiguration, mxCurrentConfiguration);
203 if (aClassifier.Partition())
205 #if defined VERBOSE && VERBOSE>=2
206 OSL_TRACE("ConfigurationUpdater::UpdateConfiguration(\n");
207 ConfigurationTracer::TraceConfiguration(
208 mxRequestedConfiguration, "requested configuration");
209 ConfigurationTracer::TraceConfiguration(
210 mxCurrentConfiguration, "current configuration");
211 #endif
212 // Notify the begining of the update.
213 ConfigurationChangeEvent aEvent;
214 aEvent.Type = FrameworkHelper::msConfigurationUpdateStartEvent;
215 aEvent.Configuration = mxRequestedConfiguration;
216 mpBroadcaster->NotifyListeners(aEvent);
218 // Do the actual update. All exceptions are caught and ignored,
219 // so that the the end of the update is notified always.
222 if (mnLockCount == 0)
223 UpdateCore(aClassifier);
225 catch(RuntimeException)
229 // Notify the end of the update.
230 aEvent.Type = FrameworkHelper::msConfigurationUpdateEndEvent;
231 mpBroadcaster->NotifyListeners(aEvent);
233 CheckUpdateSuccess();
235 else
237 #if defined VERBOSE && VERBOSE>0
238 OSL_TRACE("nothing to do\n");
239 #if defined VERBOSE && VERBOSE>=2
240 ConfigurationTracer::TraceConfiguration(
241 mxRequestedConfiguration, "requested configuration");
242 ConfigurationTracer::TraceConfiguration(
243 mxCurrentConfiguration, "current configuration");
244 #endif
245 #endif
248 catch (RuntimeException e)
250 OSL_TRACE("caught exception while updating the current configuration");
251 DBG_ASSERT(false, "caught exception while updating the current configuration");
254 #if defined VERBOSE && VERBOSE>0
255 OSL_TRACE("ConfigurationUpdater::UpdateConfiguration)");
256 OSL_TRACE("UpdateConfiguration end");
257 #endif
263 void ConfigurationUpdater::CleanRequestedConfiguration (void)
265 if (mxControllerManager.is())
267 // Request the deactivation of pure anchors that have no child.
268 vector<Reference<XResourceId> > aResourcesToDeactivate;
269 CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate);
270 if (aResourcesToDeactivate.size() > 0)
272 Reference<XConfigurationController> xCC (
273 mxControllerManager->getConfigurationController());
274 vector<Reference<XResourceId> >::iterator iId;
275 for (iId=aResourcesToDeactivate.begin(); iId!=aResourcesToDeactivate.end(); ++iId)
276 if (iId->is())
277 xCC->requestResourceDeactivation(*iId);
285 void ConfigurationUpdater::CheckUpdateSuccess (void)
287 // When the two configurations differ then start the timer to call
288 // another update later.
289 if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
291 if (mnFailedUpdateCount <= snShortTimeoutCountThreshold)
292 maUpdateTimer.SetTimeout(snShortTimeout);
293 else if (mnFailedUpdateCount < snNormalTimeoutCountThreshold)
294 maUpdateTimer.SetTimeout(snNormalTimeout);
295 else
296 maUpdateTimer.SetTimeout(snLongTimeout);
297 ++mnFailedUpdateCount;
298 maUpdateTimer.Start();
300 else
302 // Update was successfull. Reset the failed update count.
303 mnFailedUpdateCount = 0;
310 void ConfigurationUpdater::UpdateCore (const ConfigurationClassifier& rClassifier)
314 #if defined VERBOSE && VERBOSE>=2
315 rClassifier.TraceResourceIdVector(
316 "requested but not current resources:\n", rClassifier.GetC1minusC2());
317 rClassifier.TraceResourceIdVector(
318 "current but not requested resources:\n", rClassifier.GetC2minusC1());
319 rClassifier.TraceResourceIdVector(
320 "requested and current resources:\n", rClassifier.GetC1andC2());
321 #endif
323 // Updating of the sub controllers is done in two steps. In the
324 // first the sub controllers typically shut down resources that are
325 // not requested anymore. In the second the sub controllers
326 // typically set up resources that have been newly requested.
327 mpResourceManager->DeactivateResources(rClassifier.GetC2minusC1(), mxCurrentConfiguration);
328 mpResourceManager->ActivateResources(rClassifier.GetC1minusC2(), mxCurrentConfiguration);
330 #if defined VERBOSE && VERBOSE>=2
331 OSL_TRACE("ConfigurationController::UpdateConfiguration)\n");
332 ConfigurationTracer::TraceConfiguration(
333 mxRequestedConfiguration, "requested configuration\n");
334 ConfigurationTracer::TraceConfiguration(
335 mxCurrentConfiguration, "current configuration\n");
336 #endif
338 // Deactivate pure anchors that have no child.
339 vector<Reference<XResourceId> > aResourcesToDeactivate;
340 CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate);
341 if (aResourcesToDeactivate.size() > 0)
342 mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration);
344 catch(RuntimeException)
346 OSL_ASSERT(false);
353 void ConfigurationUpdater::CheckPureAnchors (
354 const Reference<XConfiguration>& rxConfiguration,
355 vector<Reference<XResourceId> >& rResourcesToDeactivate)
357 if ( ! rxConfiguration.is())
358 return;
360 // Get a list of all resources in the configuration.
361 Sequence<Reference<XResourceId> > aResources(
362 rxConfiguration->getResources(
363 NULL, OUString(), AnchorBindingMode_INDIRECT));
364 sal_Int32 nCount (aResources.getLength());
366 // Prepare the list of pure anchors that have to be deactivated.
367 rResourcesToDeactivate.clear();
369 // Iterate over the list in reverse order because when there is a chain
370 // of pure anchors with only the last one having no child then the whole
371 // list has to be deactivated.
372 sal_Int32 nIndex (nCount-1);
373 while (nIndex >= 0)
375 const Reference<XResourceId> xResourceId (aResources[nIndex]);
376 const Reference<XResource> xResource (
377 mpResourceManager->GetResource(xResourceId).mxResource);
378 bool bDeactiveCurrentResource (false);
380 // Skip all resources that are no pure anchors.
381 if (xResource.is() && xResource->isAnchorOnly())
383 // When xResource is not an anchor of the the next resource in
384 // the list then it is the anchor of no resource at all.
385 if (nIndex == nCount-1)
387 // No following anchors, deactivate this one, then remove it
388 // from the list.
389 bDeactiveCurrentResource = true;
391 else
393 const Reference<XResourceId> xPrevResourceId (aResources[nIndex+1]);
394 if ( ! xPrevResourceId.is()
395 || ! xPrevResourceId->isBoundTo(xResourceId, AnchorBindingMode_DIRECT))
397 // The previous resource (id) does not exist or is not bound to
398 // the current anchor.
399 bDeactiveCurrentResource = true;
404 if (bDeactiveCurrentResource)
406 #if defined VERBOSE && VERBOSE>=2
407 OSL_TRACE("deactiving pure anchor %s because it has no children\n",
408 OUStringToOString(
409 FrameworkHelper::ResourceIdToString(xResourceId),
410 RTL_TEXTENCODING_UTF8).getStr());
411 #endif
412 // Erase element from current configuration.
413 for (sal_Int32 nI=nIndex; nI<nCount-2; ++nI)
414 aResources[nI] = aResources[nI+1];
415 nCount -= 1;
417 rResourcesToDeactivate.push_back(xResourceId);
419 nIndex -= 1;
426 void ConfigurationUpdater::LockUpdates (void)
428 ++mnLockCount;
434 void ConfigurationUpdater::UnlockUpdates (void)
436 --mnLockCount;
437 if (mnLockCount == 0 && mbUpdatePending)
439 RequestUpdate(mxRequestedConfiguration);
446 ::boost::shared_ptr<ConfigurationUpdaterLock> ConfigurationUpdater::GetLock (void)
448 return ::boost::shared_ptr<ConfigurationUpdaterLock>(new ConfigurationUpdaterLock(*this));
454 void ConfigurationUpdater::SetUpdateBeingProcessed (bool bValue)
456 mbUpdateBeingProcessed = bValue;
462 IMPL_LINK(ConfigurationUpdater, TimeoutHandler, Timer*, EMPTYARG)
464 OSL_TRACE("configuration update timer\n");
465 if ( ! mbUpdateBeingProcessed
466 && mxCurrentConfiguration.is()
467 && mxRequestedConfiguration.is())
469 if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
471 OSL_TRACE("configurations differ, requesting update\n");
472 RequestUpdate(mxRequestedConfiguration);
475 return 0;
479 } } // end of namespace sd::framework