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 #include "precompiled_slideshow.hxx" 25 26 #include "effectrewinder.hxx" 27 #include "eventqueue.hxx" 28 #include "usereventqueue.hxx" 29 #include "mouseeventhandler.hxx" 30 #include "animationnodes/basecontainernode.hxx" 31 #include "delayevent.hxx" 32 33 #include <com/sun/star/awt/MouseEvent.hpp> 34 #include <com/sun/star/animations/Event.hpp> 35 #include <com/sun/star/animations/EventTrigger.hpp> 36 #include <com/sun/star/container/XEnumerationAccess.hpp> 37 #include <boost/function.hpp> 38 #include <boost/bind.hpp> 39 #include <boost/enable_shared_from_this.hpp> 40 41 using ::com::sun::star::uno::Reference; 42 using namespace ::com::sun::star; 43 44 namespace slideshow { namespace internal { 45 46 47 namespace { 48 49 class RewinderEventHandler : public EventHandler 50 { 51 public: 52 typedef ::boost::function<bool(void)> Action; 53 RewinderEventHandler (const Action& rAction) : maAction(rAction) {} 54 virtual ~RewinderEventHandler (void) {} 55 private: 56 const Action maAction; 57 virtual bool handleEvent (void) { return maAction(); } 58 }; 59 60 61 62 class RewinderAnimationEventHandler : public AnimationEventHandler 63 { 64 public: 65 typedef ::boost::function<bool(const AnimationNodeSharedPtr& rpNode)> Action; 66 RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {} 67 virtual ~RewinderAnimationEventHandler (void) {} 68 private: 69 const Action maAction; 70 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode) 71 { return maAction(rpNode); } 72 }; 73 74 75 76 } // end of anonymous namespace 77 78 79 //----- EffectRewinder -------------------------------------------------------------- 80 81 EffectRewinder::EffectRewinder ( 82 EventMultiplexer& rEventMultiplexer, 83 EventQueue& rEventQueue, 84 UserEventQueue& rUserEventQueue) 85 : mrEventMultiplexer(rEventMultiplexer), 86 mrEventQueue(rEventQueue), 87 mrUserEventQueue(rUserEventQueue), 88 mpSlideStartHandler(), 89 mpSlideEndHandler(), 90 mpAnimationStartHandler(), 91 mnMainSequenceEffectCount(0), 92 mpAsynchronousRewindEvent(), 93 mxCurrentAnimationRootNode(), 94 mbNonUserTriggeredMainSequenceEffectSeen(false) 95 { 96 initialize(); 97 } 98 99 100 101 102 void EffectRewinder::initialize (void) 103 { 104 // Add some event handlers so that we are informed when 105 // a) an animation is started (we then check whether that belongs to a 106 // main sequence effect and if so, increase the respective counter), 107 // b,c) a slide was started or ended (in which case the effect counter 108 // is reset. 109 110 mpAnimationStartHandler.reset( 111 new RewinderAnimationEventHandler( 112 ::boost::bind(&EffectRewinder::notifyAnimationStart, this, _1))); 113 mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler); 114 115 mpSlideStartHandler.reset( 116 new RewinderEventHandler( 117 ::boost::bind(&EffectRewinder::resetEffectCount, this))); 118 mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler); 119 120 mpSlideEndHandler.reset( 121 new RewinderEventHandler( 122 ::boost::bind(&EffectRewinder::resetEffectCount, this))); 123 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler); 124 } 125 126 127 128 129 EffectRewinder::~EffectRewinder (void) 130 { 131 dispose(); 132 } 133 134 135 136 137 void EffectRewinder::dispose (void) 138 { 139 if (mpAsynchronousRewindEvent) 140 { 141 mpAsynchronousRewindEvent->dispose(); 142 mpAsynchronousRewindEvent.reset(); 143 } 144 145 if (mpAnimationStartHandler) 146 { 147 mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler); 148 mpAnimationStartHandler.reset(); 149 } 150 151 if (mpSlideStartHandler) 152 { 153 mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler); 154 mpSlideStartHandler.reset(); 155 } 156 157 if (mpSlideEndHandler) 158 { 159 mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler); 160 mpSlideEndHandler.reset(); 161 } 162 } 163 164 165 166 167 void EffectRewinder::setRootAnimationNode ( 168 const uno::Reference<animations::XAnimationNode>& xRootNode) 169 { 170 mxCurrentAnimationRootNode = xRootNode; 171 } 172 173 174 175 176 bool EffectRewinder::rewind ( 177 const ::boost::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock, 178 const ::boost::function<void(void)>& rSlideRewindFunctor, 179 const ::boost::function<void(void)>& rPreviousSlideFunctor) 180 { 181 mpPaintLock = rpPaintLock; 182 183 // Do not allow nested rewinds. 184 if (mpAsynchronousRewindEvent) 185 { 186 OSL_ASSERT( ! mpAsynchronousRewindEvent); 187 return false; 188 } 189 190 // Abort (and skip over the rest of) any currently active animation. 191 mrUserEventQueue.callSkipEffectEventHandler(); 192 mrEventQueue.forceEmpty(); 193 194 const int nSkipCount (mnMainSequenceEffectCount - 1); 195 if (nSkipCount < 0) 196 { 197 if ( ! rPreviousSlideFunctor) 198 { 199 OSL_ASSERT(rPreviousSlideFunctor); 200 return false; 201 } 202 203 // No main sequence effects to rewind on the current slide. 204 // Go back to the previous slide. 205 mpAsynchronousRewindEvent = makeEvent( 206 ::boost::bind( 207 &EffectRewinder::asynchronousRewindToPreviousSlide, 208 this, 209 rPreviousSlideFunctor), 210 "EffectRewinder::asynchronousRewindToPreviousSlide"); 211 } 212 else 213 { 214 // The actual rewinding is done asynchronously so that we can safely 215 // call other methods. 216 mpAsynchronousRewindEvent = makeEvent( 217 ::boost::bind( 218 &EffectRewinder::asynchronousRewind, 219 this, 220 nSkipCount, 221 true, 222 rSlideRewindFunctor), 223 "EffectRewinder::asynchronousRewind"); 224 } 225 226 if (mpAsynchronousRewindEvent) 227 mrEventQueue.addEvent(mpAsynchronousRewindEvent); 228 229 return mpAsynchronousRewindEvent.get()!=NULL; 230 } 231 232 233 234 235 void EffectRewinder::skipAllMainSequenceEffects (void) 236 { 237 // Do not allow nested rewinds. 238 if (mpAsynchronousRewindEvent) 239 { 240 OSL_ASSERT(!mpAsynchronousRewindEvent); 241 return; 242 } 243 244 const int nTotalMainSequenceEffectCount (countMainSequenceEffects()); 245 mpAsynchronousRewindEvent = makeEvent( 246 ::boost::bind( 247 &EffectRewinder::asynchronousRewind, 248 this, 249 nTotalMainSequenceEffectCount, 250 false, 251 ::boost::function<void(void)>()), 252 "EffectRewinder::asynchronousRewind"); 253 mrEventQueue.addEvent(mpAsynchronousRewindEvent); 254 } 255 256 257 258 259 sal_Int32 EffectRewinder::countMainSequenceEffects (void) 260 { 261 // Determine the number of main sequence effects. 262 sal_Int32 nMainSequenceNodeCount (0); 263 264 ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue; 265 aNodeQueue.push(mxCurrentAnimationRootNode); 266 while ( ! aNodeQueue.empty()) 267 { 268 const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front()); 269 aNodeQueue.pop(); 270 271 // Does the current node belong to the main sequence? 272 if (xNode.is()) 273 { 274 animations::Event aEvent; 275 if (xNode->getBegin() >>= aEvent) 276 if (aEvent.Trigger == animations::EventTrigger::ON_NEXT) 277 ++nMainSequenceNodeCount; 278 } 279 280 // If the current node is a container then prepare its children for investigation. 281 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY); 282 if (xEnumerationAccess.is()) 283 { 284 uno::Reference<container::XEnumeration> xEnumeration ( 285 xEnumerationAccess->createEnumeration()); 286 if (xEnumeration.is()) 287 while (xEnumeration->hasMoreElements()) 288 { 289 aNodeQueue.push( 290 uno::Reference<animations::XAnimationNode>( 291 xEnumeration->nextElement(), uno::UNO_QUERY)); 292 } 293 } 294 } 295 296 return nMainSequenceNodeCount; 297 298 // // Skip all main sequence nodes. 299 // SkipSomeMainSequenceEffects(nMainSequenceNodeCount); 300 } 301 302 303 304 305 void EffectRewinder::skipSomeMainSequenceEffects (sal_Int32 nSkipCount) 306 { 307 while (--nSkipCount >= 0) 308 skipSingleMainSequenceEffects(); 309 } 310 311 312 313 314 void EffectRewinder::skipSingleMainSequenceEffects (void) 315 { 316 // This basically just starts the next effect and then skips over its 317 // animation. 318 mrEventMultiplexer.notifyNextEffect(); 319 mrEventQueue.forceEmpty(); 320 mrUserEventQueue.callSkipEffectEventHandler(); 321 mrEventQueue.forceEmpty(); 322 } 323 324 325 326 327 bool EffectRewinder::resetEffectCount (void) 328 { 329 mnMainSequenceEffectCount = 0; 330 return false; 331 } 332 333 334 335 336 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode) 337 { 338 // This notification is only relevant for us when the rpNode belongs to 339 // the main sequence. 340 BaseNodeSharedPtr pBaseNode (::boost::dynamic_pointer_cast<BaseNode>(rpNode)); 341 if ( ! pBaseNode) 342 return false; 343 344 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode()); 345 if ( ! (pParent && pParent->isMainSequenceRootNode())) 346 return false; 347 348 // This notification is only relevant for us when the effect is user 349 // triggered. 350 bool bIsUserTriggered (false); 351 352 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode()); 353 if (xNode.is()) 354 { 355 animations::Event aEvent; 356 if ((xNode->getBegin() >>= aEvent)) 357 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT); 358 } 359 360 if (bIsUserTriggered) 361 ++mnMainSequenceEffectCount; 362 else 363 mbNonUserTriggeredMainSequenceEffectSeen = true; 364 365 return false; 366 } 367 368 369 370 371 void EffectRewinder::asynchronousRewind ( 372 sal_Int32 nEffectCount, 373 const bool bRedisplayCurrentSlide, 374 const boost::function<void(void)>& rSlideRewindFunctor) 375 { 376 OSL_ASSERT(mpAsynchronousRewindEvent); 377 378 if (bRedisplayCurrentSlide) 379 { 380 mpPaintLock->Activate(); 381 // Re-display the current slide. 382 if (rSlideRewindFunctor) 383 rSlideRewindFunctor(); 384 mpAsynchronousRewindEvent = makeEvent( 385 ::boost::bind( 386 &EffectRewinder::asynchronousRewind, 387 this, 388 nEffectCount, 389 false, 390 rSlideRewindFunctor), 391 "EffectRewinder::asynchronousRewind"); 392 mrEventQueue.addEvent(mpAsynchronousRewindEvent); 393 } 394 else 395 { 396 // Process initial events and skip any animations that are started 397 // when the slide is shown. 398 mbNonUserTriggeredMainSequenceEffectSeen = false; 399 mrEventQueue.forceEmpty(); 400 if (mbNonUserTriggeredMainSequenceEffectSeen) 401 { 402 mrUserEventQueue.callSkipEffectEventHandler(); 403 mrEventQueue.forceEmpty(); 404 } 405 406 while (--nEffectCount >= 0) 407 skipSingleMainSequenceEffects(); 408 409 mpAsynchronousRewindEvent.reset(); 410 mpPaintLock.reset(); 411 } 412 } 413 414 415 416 417 void EffectRewinder::asynchronousRewindToPreviousSlide ( 418 const ::boost::function<void(void)>& rSlideRewindFunctor) 419 { 420 OSL_ASSERT(mpAsynchronousRewindEvent); 421 422 mpAsynchronousRewindEvent.reset(); 423 rSlideRewindFunctor(); 424 } 425 426 427 428 429 } } // end of namespace ::slideshow::internal 430