LibreOffice Module sd (master) 1
ConfigurationUpdater.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
27#include <DrawController.hxx>
28
29#include <com/sun/star/drawing/framework/XControllerManager.hpp>
32#include <sal/log.hxx>
33#include <utility>
34
35
36using namespace ::com::sun::star;
37using namespace ::com::sun::star::uno;
39using ::sd::framework::FrameworkHelper;
40using ::std::vector;
41
42namespace {
43const sal_Int32 snShortTimeout (100);
44const sal_Int32 snNormalTimeout (1000);
45const sal_Int32 snLongTimeout (10000);
46const sal_Int32 snShortTimeoutCountThreshold (1);
47const sal_Int32 snNormalTimeoutCountThreshold (5);
48}
49
50namespace sd::framework {
51
52//===== ConfigurationUpdaterLock ==============================================
53
55{
56public:
58 : mrUpdater(rUpdater) { mrUpdater.LockUpdates(); }
60private:
62};
63
64//===== ConfigurationUpdater ==================================================
65
67 std::shared_ptr<ConfigurationControllerBroadcaster> pBroadcaster,
68 std::shared_ptr<ConfigurationControllerResourceManager> pResourceManager,
69 const rtl::Reference<::sd::DrawController>& rxControllerManager)
70 : mpBroadcaster(std::move(pBroadcaster)),
71 mxCurrentConfiguration(Reference<XConfiguration>(new Configuration(nullptr, false))),
72 mbUpdatePending(false),
73 mbUpdateBeingProcessed(false),
74 mnLockCount(0),
75 maUpdateTimer("sd::ConfigurationUpdater maUpdateTimer"),
76 mnFailedUpdateCount(0),
77 mpResourceManager(std::move(pResourceManager))
78{
79 // Prepare the timer that is started when after an update the current
80 // and the requested configuration differ. With the timer we try
81 // updates until the two configurations are the same.
82 maUpdateTimer.SetTimeout(snNormalTimeout);
84 mxControllerManager = rxControllerManager;
85}
86
88{
90}
91
93 const Reference<XConfiguration>& rxRequestedConfiguration)
94{
95 mxRequestedConfiguration = rxRequestedConfiguration;
96
97 // Find out whether we really can update the configuration.
98 if (IsUpdatePossible())
99 {
100 SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration start");
101
102 // Call UpdateConfiguration while that is possible and while someone
103 // set mbUpdatePending to true in the middle of it.
104 do
105 {
107 }
109 }
110 else
111 {
112 mbUpdatePending = true;
113 SAL_INFO("sd.fwk", __func__ << ": scheduling update for later");
114 }
115}
116
118{
120 && mxControllerManager.is()
121 && mnLockCount==0
124}
125
127{
128 SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration update");
130 comphelper::ScopeGuard aScopeGuard (
131 [this] () { return this->SetUpdateBeingProcessed(false); });
132
133 try
134 {
135 mbUpdatePending = false;
136
139 if (aClassifier.Partition())
140 {
141#if DEBUG_SD_CONFIGURATION_TRACE
142 SAL_INFO("sd.fwk", __func__ << ": ConfigurationUpdater::UpdateConfiguration(");
144 mxRequestedConfiguration, "requested configuration");
146 mxCurrentConfiguration, "current configuration");
147#endif
148 // Notify the beginning of the update.
149 ConfigurationChangeEvent aEvent;
151 aEvent.Configuration = mxRequestedConfiguration;
152 mpBroadcaster->NotifyListeners(aEvent);
153
154 // Do the actual update. All exceptions are caught and ignored,
155 // so that the end of the update is notified always.
156 try
157 {
158 if (mnLockCount == 0)
159 UpdateCore(aClassifier);
160 }
161 catch(const RuntimeException&)
162 {
163 }
164
165 // Notify the end of the update.
167 mpBroadcaster->NotifyListeners(aEvent);
168
170 }
171 else
172 {
173 SAL_INFO("sd.fwk", __func__ << ": nothing to do");
174#if DEBUG_SD_CONFIGURATION_TRACE
176 mxRequestedConfiguration, "requested configuration");
178 mxCurrentConfiguration, "current configuration");
179#endif
180 }
181 }
182 catch(const RuntimeException &)
183 {
185 }
186
187 SAL_INFO("sd.fwk", __func__ << ": ConfigurationUpdater::UpdateConfiguration)");
188 SAL_INFO("sd.fwk", __func__ << ": UpdateConfiguration end");
189}
190
192{
193 if (!mxControllerManager.is())
194 return;
195
196 // Request the deactivation of pure anchors that have no child.
197 vector<Reference<XResourceId> > aResourcesToDeactivate;
198 CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate);
199 if (!aResourcesToDeactivate.empty())
200 {
201 Reference<XConfigurationController> xCC (
202 mxControllerManager->getConfigurationController());
203 for (const auto& rxId : aResourcesToDeactivate)
204 if (rxId.is())
205 xCC->requestResourceDeactivation(rxId);
206 }
207}
208
210{
211 // When the two configurations differ then start the timer to call
212 // another update later.
214 {
215 if (mnFailedUpdateCount <= snShortTimeoutCountThreshold)
216 maUpdateTimer.SetTimeout(snShortTimeout);
217 else if (mnFailedUpdateCount < snNormalTimeoutCountThreshold)
218 maUpdateTimer.SetTimeout(snNormalTimeout);
219 else
220 maUpdateTimer.SetTimeout(snLongTimeout);
223 }
224 else
225 {
226 // Update was successful. Reset the failed update count.
228 }
229}
230
232{
233 try
234 {
235#if DEBUG_SD_CONFIGURATION_TRACE
236 rClassifier.TraceResourceIdVector(
237 "requested but not current resources:", rClassifier.GetC1minusC2());
238 rClassifier.TraceResourceIdVector(
239 "current but not requested resources:", rClassifier.GetC2minusC1());
240 rClassifier.TraceResourceIdVector(
241 "requested and current resources:", rClassifier.GetC1andC2());
242#endif
243
244 // Updating of the sub controllers is done in two steps. In the
245 // first the sub controllers typically shut down resources that are
246 // not requested anymore. In the second the sub controllers
247 // typically set up resources that have been newly requested.
248 mpResourceManager->DeactivateResources(rClassifier.GetC2minusC1(), mxCurrentConfiguration);
249 mpResourceManager->ActivateResources(rClassifier.GetC1minusC2(), mxCurrentConfiguration);
250
251#if DEBUG_SD_CONFIGURATION_TRACE
252 SAL_INFO("sd.fwk", __func__ << ": ConfigurationController::UpdateConfiguration)");
254 mxRequestedConfiguration, "requested configuration");
256 mxCurrentConfiguration, "current configuration");
257#endif
258
259 // Deactivate pure anchors that have no child.
260 vector<Reference<XResourceId> > aResourcesToDeactivate;
261 CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate);
262 if (!aResourcesToDeactivate.empty())
263 mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration);
264 }
265 catch(const RuntimeException&)
266 {
268 }
269}
270
272 const Reference<XConfiguration>& rxConfiguration,
273 vector<Reference<XResourceId> >& rResourcesToDeactivate)
274{
275 if ( ! rxConfiguration.is())
276 return;
277
278 // Get a list of all resources in the configuration.
279 Sequence<Reference<XResourceId> > aResources(
280 rxConfiguration->getResources(
281 nullptr, OUString(), AnchorBindingMode_INDIRECT));
282 auto aResourcesRange = asNonConstRange(aResources);
283 sal_Int32 nCount (aResources.getLength());
284
285 // Prepare the list of pure anchors that have to be deactivated.
286 rResourcesToDeactivate.clear();
287
288 // Iterate over the list in reverse order because when there is a chain
289 // of pure anchors with only the last one having no child then the whole
290 // list has to be deactivated.
291 sal_Int32 nIndex (nCount-1);
292 while (nIndex >= 0)
293 {
294 const Reference<XResourceId> xResourceId (aResources[nIndex]);
295 const Reference<XResource> xResource (
296 mpResourceManager->GetResource(xResourceId).mxResource);
297 bool bDeactiveCurrentResource (false);
298
299 // Skip all resources that are no pure anchors.
300 if (xResource.is() && xResource->isAnchorOnly())
301 {
302 // When xResource is not an anchor of the next resource in
303 // the list then it is the anchor of no resource at all.
304 if (nIndex == nCount-1)
305 {
306 // No following anchors, deactivate this one, then remove it
307 // from the list.
308 bDeactiveCurrentResource = true;
309 }
310 else
311 {
312 const Reference<XResourceId> xPrevResourceId (aResources[nIndex+1]);
313 if ( ! xPrevResourceId.is()
314 || ! xPrevResourceId->isBoundTo(xResourceId, AnchorBindingMode_DIRECT))
315 {
316 // The previous resource (id) does not exist or is not bound to
317 // the current anchor.
318 bDeactiveCurrentResource = true;
319 }
320 }
321 }
322
323 if (bDeactiveCurrentResource)
324 {
325 SAL_INFO("sd.fwk", __func__ << ": deactivating pure anchor " <<
327 "because it has no children");
328 // Erase element from current configuration.
329 for (sal_Int32 nI=nIndex; nI<nCount-2; ++nI)
330 aResourcesRange[nI] = aResources[nI+1];
331 nCount -= 1;
332
333 rResourcesToDeactivate.push_back(xResourceId);
334 }
335 nIndex -= 1;
336 }
337}
338
340{
341 ++mnLockCount;
342}
343
345{
346 --mnLockCount;
347 if (mnLockCount == 0 && mbUpdatePending)
348 {
350 }
351}
352
353std::shared_ptr<ConfigurationUpdaterLock> ConfigurationUpdater::GetLock()
354{
355 return std::make_shared<ConfigurationUpdaterLock>(*this);
356}
357
359{
360 mbUpdateBeingProcessed = bValue;
361}
362
364{
365 if ( ! mbUpdateBeingProcessed
366 && mxCurrentConfiguration.is()
367 && mxRequestedConfiguration.is())
368 {
369 if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
370 {
371 RequestUpdate(mxRequestedConfiguration);
372 }
373 }
374}
375
376} // end of namespace sd::framework
377
378/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AnyEventRef aEvent
void Stop()
void SetTimeout(sal_uInt64 nTimeoutMs)
void SetInvokeHandler(const Link< Timer *, void > &rLink)
virtual void Start(bool bStartTimer=true) override
A ConfigurationClassifier object compares two configurations of resources and gives access to the dif...
const ResourceIdVector & GetC2minusC1() const
Return the resources that belong to the configuration given as rxConfiguration2 to the constructor bu...
const ResourceIdVector & GetC1minusC2() const
Return the resources that belong to the configuration given as rxConfiguration1 to the constructor bu...
bool Partition()
Calculate three lists of resource ids.
static void TraceConfiguration(const css::uno::Reference< css::drawing::framework::XConfiguration > &rxConfiguration, const char *pMessage)
ConfigurationUpdaterLock(ConfigurationUpdater &rUpdater)
This is a helper class for the ConfigurationController.
ConfigurationUpdater(std::shared_ptr< ConfigurationControllerBroadcaster > pBroadcaster, std::shared_ptr< ConfigurationControllerResourceManager > pResourceManager, const rtl::Reference<::sd::DrawController > &xControllerManager)
Create a new ConfigurationUpdater object that notifies configuration changes and the start and end of...
Timer maUpdateTimer
This timer is used to check from time to time whether the requested configuration and the current con...
void RequestUpdate(const css::uno::Reference< css::drawing::framework::XConfiguration > &rxRequestedConfiguration)
Request an update of the current configuration so that it looks like the given requested configuratio...
void UnlockUpdates()
When an update was requested since the last LockUpdates() call then RequestUpdate() is called.
bool IsUpdatePossible() const
Return whether it is possible to do an update of the configuration.
std::shared_ptr< ConfigurationUpdaterLock > GetLock()
Return a lock of the called ConfigurationUpdater.
void UpdateCore(const ConfigurationClassifier &rClassifier)
Basically calls UpdaterStart() andUpdateEnd() and makes some debug output.
sal_Int32 mnLockCount
The ConfigurationController is locked when this count has a value larger then zero.
void UpdateConfiguration()
This method does the main work of an update.
bool mbUpdatePending
This flag is set to </sal_True> when an update of the current configuration was requested (because th...
rtl::Reference<::sd::DrawController > mxControllerManager
A reference to the XControllerManager is kept so that UpdateConfiguration() has access to the other s...
css::uno::Reference< css::drawing::framework::XConfiguration > mxRequestedConfiguration
The requested configuration holds the resources that have been requested to activate or to deactivate...
void CheckPureAnchors(const css::uno::Reference< css::drawing::framework::XConfiguration > &rxConfiguration, ::std::vector< css::uno::Reference< css::drawing::framework::XResourceId > > &rResourcesToDeactivate)
Check for all pure anchors if they have at least one child.
std::shared_ptr< ConfigurationControllerResourceManager > mpResourceManager
bool mbUpdateBeingProcessed
This flag is set to </sal_True> while the UpdateConfiguration() method is running.
void LockUpdates()
Lock updates of the current configuration.
void SetUpdateBeingProcessed(bool bValue)
This method sets the mbUpdateBeingProcessed member that is used to prevent reentrance problems.
void CleanRequestedConfiguration()
Remove from the requested configuration all pure anchors that have no child.
css::uno::Reference< css::drawing::framework::XConfiguration > mxCurrentConfiguration
The current configuration holds the resources that are currently active.
sal_Int32 mnFailedUpdateCount
The number of failed updates (those after which the current configuration is not equivalent to the re...
std::shared_ptr< ConfigurationControllerBroadcaster > mpBroadcaster
void CheckUpdateSuccess()
Check the success of a recently executed configuration update.
A configuration describes the resources of an application like panes, views, and tool bars and their ...
static constexpr OUStringLiteral msConfigurationUpdateStartEvent
static constexpr OUStringLiteral msConfigurationUpdateEndEvent
static OUString ResourceIdToString(const css::uno::Reference< css::drawing::framework::XResourceId > &rxResourceId)
Return a string representation of the given XResourceId object.
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
sal_Int32 nIndex
#define SAL_INFO(area, stream)
Reference
IMPL_LINK_NOARG(ChangeRequestQueueProcessor, ProcessEvent, void *, void)
bool AreConfigurationsEquivalent(const Reference< XConfiguration > &rxConfiguration1, const Reference< XConfiguration > &rxConfiguration2)