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
20 #include "MasterPageContainerQueue.hxx"
21 #include "MasterPageContainerProviders.hxx"
22
23 #include <tools/IdleDetection.hxx>
24
25 #include <set>
26
27 namespace sd { namespace sidebar {
28
29 const sal_Int32 MasterPageContainerQueue::snDelayedCreationTimeout (15);
30 const sal_Int32 MasterPageContainerQueue::snDelayedCreationTimeoutWhenNotIdle (100);
31 const sal_Int32 MasterPageContainerQueue::snMasterPagePriorityBoost (5);
32 const sal_Int32 MasterPageContainerQueue::snWaitForMoreRequestsPriorityThreshold (-10);
33 sal_uInt32 MasterPageContainerQueue::snWaitForMoreRequestsCount(15);
34
35 //===== MasterPageContainerQueue::PreviewCreationRequest ======================
36
37 class MasterPageContainerQueue::PreviewCreationRequest
38 {
39 public:
PreviewCreationRequest(const SharedMasterPageDescriptor & rpDescriptor,int nPriority)40 PreviewCreationRequest (const SharedMasterPageDescriptor& rpDescriptor, int nPriority)
41 : mpDescriptor(rpDescriptor),
42 mnPriority(nPriority)
43 {}
44 SharedMasterPageDescriptor const mpDescriptor;
45 int const mnPriority;
46 class Compare
47 {
48 public:
operator ()(const PreviewCreationRequest & r1,const PreviewCreationRequest & r2) const49 bool operator() (const PreviewCreationRequest& r1,const PreviewCreationRequest& r2) const
50 {
51 if (r1.mnPriority != r2.mnPriority)
52 {
53 // Prefer requests with higher priority.
54 return r1.mnPriority > r2.mnPriority;
55 }
56 else
57 {
58 // Prefer tokens that have been earlier created (those with lower
59 // value).
60 return r1.mpDescriptor->maToken < r2.mpDescriptor->maToken;
61 }
62 }
63 };
64 class CompareToken
65 {
66 public:
67 MasterPageContainer::Token const maToken;
CompareToken(MasterPageContainer::Token aToken)68 explicit CompareToken(MasterPageContainer::Token aToken) : maToken(aToken) {}
operator ()(const PreviewCreationRequest & rRequest) const69 bool operator() (const PreviewCreationRequest& rRequest) const
70 { return maToken==rRequest.mpDescriptor->maToken; }
71 };
72 };
73
74 //===== MasterPageContainerQueue::RequestQueue ================================
75
76 class MasterPageContainerQueue::RequestQueue
77 : public ::std::set<PreviewCreationRequest,PreviewCreationRequest::Compare>
78 {
79 public:
RequestQueue()80 RequestQueue() {}
81 };
82
83 //===== MasterPageContainerQueue ==============================================
84
Create(const std::weak_ptr<ContainerAdapter> & rpContainer)85 MasterPageContainerQueue* MasterPageContainerQueue::Create (
86 const std::weak_ptr<ContainerAdapter>& rpContainer)
87 {
88 MasterPageContainerQueue* pQueue = new MasterPageContainerQueue(rpContainer);
89 pQueue->LateInit();
90 return pQueue;
91 }
92
MasterPageContainerQueue(const std::weak_ptr<ContainerAdapter> & rpContainer)93 MasterPageContainerQueue::MasterPageContainerQueue (
94 const std::weak_ptr<ContainerAdapter>& rpContainer)
95 : mpWeakContainer(rpContainer),
96 mpRequestQueue(new RequestQueue()),
97 maDelayedPreviewCreationTimer(),
98 mnRequestsServedCount(0)
99 {
100 }
101
~MasterPageContainerQueue()102 MasterPageContainerQueue::~MasterPageContainerQueue()
103 {
104 maDelayedPreviewCreationTimer.Stop();
105 while ( ! mpRequestQueue->empty())
106 mpRequestQueue->erase(mpRequestQueue->begin());
107 }
108
LateInit()109 void MasterPageContainerQueue::LateInit()
110 {
111 // Set up the timer for the delayed creation of preview bitmaps.
112 maDelayedPreviewCreationTimer.SetTimeout (snDelayedCreationTimeout);
113 maDelayedPreviewCreationTimer.SetInvokeHandler(
114 LINK(this,MasterPageContainerQueue,DelayedPreviewCreation) );
115 }
116
RequestPreview(const SharedMasterPageDescriptor & rpDescriptor)117 bool MasterPageContainerQueue::RequestPreview (const SharedMasterPageDescriptor& rpDescriptor)
118 {
119 bool bSuccess (false);
120 if (rpDescriptor.get() != nullptr
121 && rpDescriptor->maLargePreview.GetSizePixel().Width() == 0)
122 {
123 sal_Int32 nPriority (CalculatePriority(rpDescriptor));
124
125 // Add a new or replace an existing request.
126 RequestQueue::iterator iRequest (::std::find_if(
127 mpRequestQueue->begin(),
128 mpRequestQueue->end(),
129 PreviewCreationRequest::CompareToken(rpDescriptor->maToken)));
130 // When a request for the same token exists then the lowest of the
131 // two priorities is used.
132 if (iRequest != mpRequestQueue->end())
133 if (iRequest->mnPriority < nPriority)
134 {
135 mpRequestQueue->erase(iRequest);
136 iRequest = mpRequestQueue->end();
137 }
138
139 // Add a new request when none exists (or has just been erased).
140 if (iRequest == mpRequestQueue->end())
141 {
142 mpRequestQueue->insert(PreviewCreationRequest(rpDescriptor,nPriority));
143 maDelayedPreviewCreationTimer.Start();
144 bSuccess = true;
145 }
146 }
147 return bSuccess;
148 }
149
CalculatePriority(const SharedMasterPageDescriptor & rpDescriptor)150 sal_Int32 MasterPageContainerQueue::CalculatePriority (
151 const SharedMasterPageDescriptor& rpDescriptor)
152 {
153 sal_Int32 nPriority;
154
155 // The cost is used as a starting value.
156 int nCost (0);
157 if (rpDescriptor->mpPreviewProvider != nullptr)
158 {
159 nCost = rpDescriptor->mpPreviewProvider->GetCostIndex();
160 if (rpDescriptor->mpPreviewProvider->NeedsPageObject())
161 if (rpDescriptor->mpPageObjectProvider != nullptr)
162 nCost += rpDescriptor->mpPageObjectProvider->GetCostIndex();
163 }
164
165 // Its negative value is used so that requests with a low cost are
166 // preferred over those with high costs.
167 nPriority = -nCost;
168
169 // Add a term that introduces an order based on the appearance in the
170 // AllMasterPagesSelector.
171 nPriority -= rpDescriptor->maToken / 3;
172
173 // Process requests for the CurrentMasterPagesSelector first.
174 if (rpDescriptor->meOrigin == MasterPageContainer::MASTERPAGE)
175 nPriority += snMasterPagePriorityBoost;
176
177 return nPriority;
178 }
179
IMPL_LINK(MasterPageContainerQueue,DelayedPreviewCreation,Timer *,pTimer,void)180 IMPL_LINK(MasterPageContainerQueue, DelayedPreviewCreation, Timer*, pTimer, void)
181 {
182 bool bIsShowingFullScreenShow (false);
183 bool bWaitForMoreRequests (false);
184
185 do
186 {
187 if (mpRequestQueue->empty())
188 break;
189
190 // First check whether the system is idle.
191 tools::IdleState nIdleState (tools::IdleDetection::GetIdleState(nullptr));
192 if (nIdleState != tools::IdleState::Idle)
193 {
194 if (nIdleState & tools::IdleState::FullScreenShowActive)
195 bIsShowingFullScreenShow = true;
196 break;
197 }
198
199 PreviewCreationRequest aRequest (*mpRequestQueue->begin());
200
201 // Check if the request should really be processed right now.
202 // Reasons to not do it are when its cost is high and not many other
203 // requests have been inserted into the queue that would otherwise
204 // be processed first.
205 if (aRequest.mnPriority < snWaitForMoreRequestsPriorityThreshold
206 && (mnRequestsServedCount+mpRequestQueue->size() < snWaitForMoreRequestsCount))
207 {
208 // Wait for more requests before this one is processed. Note
209 // that the queue processing is not started anew when this
210 // method is left. That is done when the next request is
211 // inserted.
212 bWaitForMoreRequests = true;
213 break;
214 }
215
216 mpRequestQueue->erase(mpRequestQueue->begin());
217
218 if (aRequest.mpDescriptor.get() != nullptr)
219 {
220 mnRequestsServedCount += 1;
221 if ( ! mpWeakContainer.expired())
222 {
223 std::shared_ptr<ContainerAdapter> pContainer (mpWeakContainer);
224 if (pContainer != nullptr)
225 pContainer->UpdateDescriptor(aRequest.mpDescriptor,false,true,true);
226 }
227 }
228 }
229 while (false);
230
231 if (!mpRequestQueue->empty() && ! bWaitForMoreRequests)
232 {
233 int nTimeout (snDelayedCreationTimeout);
234 if (bIsShowingFullScreenShow)
235 nTimeout = snDelayedCreationTimeoutWhenNotIdle;
236 maDelayedPreviewCreationTimer.SetTimeout(nTimeout);
237 pTimer->Start();
238 }
239 }
240
HasRequest(MasterPageContainer::Token aToken) const241 bool MasterPageContainerQueue::HasRequest (MasterPageContainer::Token aToken) const
242 {
243 return std::any_of(
244 mpRequestQueue->begin(),
245 mpRequestQueue->end(),
246 PreviewCreationRequest::CompareToken(aToken));
247 }
248
IsEmpty() const249 bool MasterPageContainerQueue::IsEmpty() const
250 {
251 return mpRequestQueue->empty();
252 }
253
ProcessAllRequests()254 void MasterPageContainerQueue::ProcessAllRequests()
255 {
256 snWaitForMoreRequestsCount = 0;
257 if (!mpRequestQueue->empty())
258 maDelayedPreviewCreationTimer.Start();
259 }
260
261 } } // end of namespace sd::sidebar
262
263 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
264