1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #include "precompiled_slideshow.hxx"
28 
29 #include "screenupdater.hxx"
30 #include "listenercontainer.hxx"
31 
32 #include <boost/bind.hpp>
33 #include <vector>
34 #include <algorithm>
35 
36 namespace {
37     class UpdateLock : public ::slideshow::internal::ScreenUpdater::UpdateLock
38     {
39     public:
40         UpdateLock (::slideshow::internal::ScreenUpdater& rUpdater, const bool bStartLocked);
41         virtual ~UpdateLock (void);
42         virtual void Activate (void);
43     private:
44         ::slideshow::internal::ScreenUpdater& mrUpdater;
45         bool mbIsActivated;
46     };
47 }
48 
49 namespace slideshow
50 {
51 namespace internal
52 {
53     typedef std::vector<
54         std::pair<UnoViewSharedPtr,bool> > UpdateRequestVector;
55 
56     struct ScreenUpdater::ImplScreenUpdater
57     {
58         /** List of registered ViewUpdaters, to consult for necessary
59             updates
60         */
61         ThreadUnsafeListenerContainer<
62             ViewUpdateSharedPtr,
63             std::vector<ViewUpdateSharedPtr> > maUpdaters;
64 
65         /// Views that have been notified for update
66         UpdateRequestVector                    maViewUpdateRequests;
67 
68         /// List of View. Used to issue screen updates on.
69         UnoViewContainer const&                mrViewContainer;
70 
71         /// True, if a notifyUpdate() for all views has been issued.
72         bool                                   mbUpdateAllRequest;
73 
74         /// True, if at least one notifyUpdate() call had bViewClobbered set
75         bool                                   mbViewClobbered;
76 
77         /// The screen is updated only when mnLockCount==0
78         sal_Int32 mnLockCount;
79 
80         explicit ImplScreenUpdater( UnoViewContainer const& rViewContainer ) :
81             maUpdaters(),
82             maViewUpdateRequests(),
83             mrViewContainer(rViewContainer),
84             mbUpdateAllRequest(false),
85             mbViewClobbered(false),
86             mnLockCount(0)
87         {}
88     };
89 
90     ScreenUpdater::ScreenUpdater( UnoViewContainer const& rViewContainer ) :
91         mpImpl(new ImplScreenUpdater(rViewContainer) )
92     {
93     }
94 
95     ScreenUpdater::~ScreenUpdater()
96     {
97         // outline because of pimpl
98     }
99 
100     void ScreenUpdater::notifyUpdate()
101     {
102         mpImpl->mbUpdateAllRequest = true;
103     }
104 
105     void ScreenUpdater::notifyUpdate( const UnoViewSharedPtr& rView,
106                                       bool                    bViewClobbered )
107     {
108         mpImpl->maViewUpdateRequests.push_back(
109             std::make_pair(rView, bViewClobbered) );
110 
111         if( bViewClobbered )
112             mpImpl->mbViewClobbered = true;
113     }
114 
115     void ScreenUpdater::commitUpdates()
116     {
117         if (mpImpl->mnLockCount > 0)
118             return;
119 
120         // cases:
121         //
122         // (a) no update necessary at all
123         //
124         // (b) no ViewUpdate-generated update
125         //     I. update all views requested -> for_each( mrViewContainer )
126         //    II. update some views requested -> for_each( maViewUpdateRequests )
127         //
128         // (c) ViewUpdate-triggered update - update all views
129         //
130 
131         // any ViewUpdate-triggered updates?
132         const bool bViewUpdatesNeeded(
133             mpImpl->maUpdaters.apply(
134                 boost::mem_fn(&ViewUpdate::needsUpdate)) );
135 
136         if( bViewUpdatesNeeded )
137         {
138             mpImpl->maUpdaters.applyAll(
139                 boost::mem_fn((bool (ViewUpdate::*)())&ViewUpdate::update) );
140         }
141 
142         if( bViewUpdatesNeeded ||
143             mpImpl->mbUpdateAllRequest )
144         {
145             // unconditionally update all views
146             std::for_each( mpImpl->mrViewContainer.begin(),
147                            mpImpl->mrViewContainer.end(),
148                            mpImpl->mbViewClobbered ?
149                            boost::mem_fn(&View::paintScreen) :
150                            boost::mem_fn(&View::updateScreen) );
151         }
152         else if( !mpImpl->maViewUpdateRequests.empty() )
153         {
154             // update notified views only
155             UpdateRequestVector::const_iterator aIter(
156                 mpImpl->maViewUpdateRequests.begin() );
157             const UpdateRequestVector::const_iterator aEnd(
158                 mpImpl->maViewUpdateRequests.end() );
159             while( aIter != aEnd )
160             {
161                 // TODO(P1): this is O(n^2) in the number of views, if
162                 // lots of views notify updates.
163                 const UnoViewVector::const_iterator aEndOfViews(
164                     mpImpl->mrViewContainer.end() );
165                 UnoViewVector::const_iterator aFoundView;
166                 if( (aFoundView=std::find(mpImpl->mrViewContainer.begin(),
167                                           aEndOfViews,
168                                           aIter->first)) != aEndOfViews )
169                 {
170                     if( aIter->second )
171                         (*aFoundView)->paintScreen(); // force-paint
172                     else
173                         (*aFoundView)->updateScreen(); // update changes only
174                 }
175 
176                 ++aIter;
177             }
178         }
179 
180         // done - clear requests
181         mpImpl->mbViewClobbered = false;
182         mpImpl->mbUpdateAllRequest = false;
183         UpdateRequestVector().swap( mpImpl->maViewUpdateRequests );
184     }
185 
186     void ScreenUpdater::addViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
187     {
188         mpImpl->maUpdaters.add( rViewUpdate );
189     }
190 
191     void ScreenUpdater::removeViewUpdate( ViewUpdateSharedPtr const& rViewUpdate )
192     {
193         mpImpl->maUpdaters.remove( rViewUpdate );
194     }
195 
196     void ScreenUpdater::requestImmediateUpdate()
197     {
198         if (mpImpl->mnLockCount > 0)
199             return;
200 
201         // TODO(F2): This will interfere with other updates, since it
202         // happens out-of-sync with main animation loop. Might cause
203         // artifacts.
204         std::for_each( mpImpl->mrViewContainer.begin(),
205                        mpImpl->mrViewContainer.end(),
206                        boost::mem_fn(&View::updateScreen) );
207     }
208 
209     void ScreenUpdater::lockUpdates (void)
210     {
211         ++mpImpl->mnLockCount;
212         OSL_ASSERT(mpImpl->mnLockCount>0);
213     }
214 
215     void ScreenUpdater::unlockUpdates (void)
216     {
217         OSL_ASSERT(mpImpl->mnLockCount>0);
218         if (mpImpl->mnLockCount > 0)
219         {
220             --mpImpl->mnLockCount;
221             if (mpImpl->mnLockCount)
222                 commitUpdates();
223         }
224     }
225 
226     ::boost::shared_ptr<ScreenUpdater::UpdateLock> ScreenUpdater::createLock (const bool bStartLocked)
227     {
228         return ::boost::shared_ptr<ScreenUpdater::UpdateLock>(new ::UpdateLock(*this, bStartLocked));
229     }
230 
231 
232 } // namespace internal
233 } // namespace slideshow
234 
235 namespace {
236 
237 UpdateLock::UpdateLock (
238     ::slideshow::internal::ScreenUpdater& rUpdater,
239     const bool bStartLocked)
240     : mrUpdater(rUpdater),
241       mbIsActivated(false)
242 {
243     if (bStartLocked)
244         Activate();
245 }
246 
247 
248 
249 
250 UpdateLock::~UpdateLock (void)
251 {
252     if (mbIsActivated)
253         mrUpdater.unlockUpdates();
254 }
255 
256 
257 
258 
259 void UpdateLock::Activate (void)
260 {
261     if ( ! mbIsActivated)
262     {
263         mbIsActivated = true;
264         mrUpdater.lockUpdates();
265     }
266 }
267 
268 }
269