1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26 
27 // must be first
28 #include <canvas/debug.hxx>
29 #include <canvas/verbosetrace.hxx>
30 
31 #include <comphelper/anytostring.hxx>
32 #include <cppuhelper/exc_hlp.hxx>
33 
34 #include "slideshowexceptions.hxx"
35 #include "activity.hxx"
36 #include "activitiesqueue.hxx"
37 
38 #include <boost/bind.hpp>
39 #include <algorithm>
40 
41 
42 using namespace ::com::sun::star;
43 
44 namespace slideshow
45 {
46     namespace internal
47     {
48         ActivitiesQueue::ActivitiesQueue(
49           const ::boost::shared_ptr< ::canvas::tools::ElapsedTime >& pPresTimer ) :
50             mpTimer( pPresTimer ),
51             maCurrentActivitiesWaiting(),
52             maCurrentActivitiesReinsert(),
53             maDequeuedActivities()
54         {
55         }
56 
57         ActivitiesQueue::~ActivitiesQueue()
58         {
59             // dispose all queue entries
60             try
61             {
62                 std::for_each( maCurrentActivitiesWaiting.begin(),
63                                maCurrentActivitiesWaiting.end(),
64                                boost::mem_fn( &Disposable::dispose ) );
65                 std::for_each( maCurrentActivitiesReinsert.begin(),
66                                maCurrentActivitiesReinsert.end(),
67                                boost::mem_fn( &Disposable::dispose ) );
68             }
69             catch (uno::Exception &)
70             {
71                 OSL_ENSURE( false, rtl::OUStringToOString(
72                                 comphelper::anyToString(
73                                     cppu::getCaughtException() ),
74                                 RTL_TEXTENCODING_UTF8 ).getStr() );
75             }
76         }
77 
78         bool ActivitiesQueue::addActivity( const ActivitySharedPtr& pActivity )
79         {
80             OSL_ENSURE( pActivity, "ActivitiesQueue::addActivity: activity ptr NULL" );
81 
82             if( !pActivity )
83                 return false;
84 
85             // add entry to waiting list
86             maCurrentActivitiesWaiting.push_back( pActivity );
87 
88             return true;
89         }
90 
91         void ActivitiesQueue::process()
92         {
93             VERBOSE_TRACE( "ActivitiesQueue: outer loop heartbeat" );
94 
95             // accumulate time lag for all activities, and lag time
96             // base if necessary:
97             ActivityQueue::const_iterator iPos(
98                 maCurrentActivitiesWaiting.begin() );
99             const ActivityQueue::const_iterator iEnd(
100                 maCurrentActivitiesWaiting.end() );
101             double fLag = 0.0;
102             for ( ; iPos != iEnd; ++iPos )
103                 fLag = std::max<double>( fLag, (*iPos)->calcTimeLag() );
104             if (fLag > 0.0)
105             {
106                 mpTimer->adjustTimer( -fLag );
107             }
108 
109             // process list of activities
110             while( !maCurrentActivitiesWaiting.empty() )
111             {
112                 // process topmost activity
113                 ActivitySharedPtr pActivity( maCurrentActivitiesWaiting.front() );
114                 maCurrentActivitiesWaiting.pop_front();
115 
116                 bool bReinsert( false );
117 
118                 try
119                 {
120                     // fire up activity
121                     bReinsert = pActivity->perform();
122                 }
123                 catch( uno::RuntimeException& )
124                 {
125                     throw;
126                 }
127                 catch( uno::Exception& )
128                 {
129                     // catch anything here, we don't want
130                     // to leave this scope under _any_
131                     // circumstance. Although, do _not_
132                     // reinsert an activity that threw
133                     // once.
134 
135                     // NOTE: we explicitely don't catch(...) here,
136                     // since this will also capture segmentation
137                     // violations and the like. In such a case, we
138                     // still better let our clients now...
139                     OSL_ENSURE( false,
140                                 rtl::OUStringToOString(
141                                     comphelper::anyToString( cppu::getCaughtException() ),
142                                     RTL_TEXTENCODING_UTF8 ).getStr() );
143                 }
144                 catch( SlideShowException& )
145                 {
146                     // catch anything here, we don't want
147                     // to leave this scope under _any_
148                     // circumstance. Although, do _not_
149                     // reinsert an activity that threw
150                     // once.
151 
152                     // NOTE: we explicitely don't catch(...) here,
153                     // since this will also capture segmentation
154                     // violations and the like. In such a case, we
155                     // still better let our clients now...
156                     OSL_TRACE( "::presentation::internal::ActivitiesQueue: Activity threw a SlideShowException, removing from ring" );
157                 }
158 
159                 if( bReinsert )
160                     maCurrentActivitiesReinsert.push_back( pActivity );
161                 else
162                     maDequeuedActivities.push_back( pActivity );
163 
164                 VERBOSE_TRACE( "ActivitiesQueue: inner loop heartbeat" );
165             }
166 
167             if( !maCurrentActivitiesReinsert.empty() )
168             {
169                 // reinsert all processed, but not finished
170                 // activities back to waiting queue. With swap(),
171                 // we kill two birds with one stone: we reuse the
172                 // list nodes, and we clear the
173                 // maCurrentActivitiesReinsert list
174                 maCurrentActivitiesWaiting.swap( maCurrentActivitiesReinsert );
175             }
176         }
177 
178         void ActivitiesQueue::processDequeued()
179         {
180             // notify all dequeued activities from last round
181             ::std::for_each( maDequeuedActivities.begin(),
182                              maDequeuedActivities.end(),
183                              ::boost::mem_fn( &Activity::dequeued ) );
184             maDequeuedActivities.clear();
185         }
186 
187         bool ActivitiesQueue::isEmpty() const
188         {
189             return maCurrentActivitiesWaiting.empty() && maCurrentActivitiesReinsert.empty();
190         }
191 
192         void ActivitiesQueue::clear()
193         {
194             // dequeue all entries:
195             std::for_each( maCurrentActivitiesWaiting.begin(),
196                            maCurrentActivitiesWaiting.end(),
197                            boost::mem_fn( &Activity::dequeued ) );
198             ActivityQueue().swap( maCurrentActivitiesWaiting );
199 
200             std::for_each( maCurrentActivitiesReinsert.begin(),
201                            maCurrentActivitiesReinsert.end(),
202                            boost::mem_fn( &Activity::dequeued ) );
203             ActivityQueue().swap( maCurrentActivitiesReinsert );
204         }
205     }
206 }
207