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