/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
using ::com::sun::star::animations::XAnimationNode; using ::com::sun::star::animations::XAnimationListener; using ::com::sun::star::awt::XWindow; usingnamespace ::com::sun::star; usingnamespace ::com::sun::star::lang; usingnamespace ::com::sun::star::uno; usingnamespace ::com::sun::star::drawing; usingnamespace ::com::sun::star::container; usingnamespace ::com::sun::star::presentation; usingnamespace ::com::sun::star::beans;
namespace sd
{ /** Slots, which will be disabled in the slide show and are managed by Sfx.
Have to be sorted in the order of the SIDs */
sal_uInt16 const pAllowed[] =
{
SID_OPENDOC , // 5501 ///< that internally jumps work
SID_JUMPTOMARK , // 5598
SID_OPENHYPERLINK , // 6676
SID_PRESENTATION_END // 27218
};
class AnimationSlideController
{ public: enum Mode { ALL, FROM, CUSTOM, PREVIEW };
// for InteractiveSlideShow we need to temporarily change the program // and mode, so allow save/restore that settings void pushForPreview(); void popFromPreview(); private: bool getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode );
sal_Int32 findSlideIndex( sal_Int32 nSlideNumber ) const;
sal_Int32 AnimationSlideController::getNextSlideIndex() const
{ switch( meMode )
{ case ALL:
{
sal_Int32 nNewSlideIndex = mnCurrentSlideIndex + 1; if( isValidIndex( nNewSlideIndex ) )
{ // if the current slide is not excluded, make sure the // next slide is also not excluded. // if the current slide is excluded, we want to go // to the next slide, even if this is also excluded. if( maSlideVisible[mnCurrentSlideIndex] )
{ while( isValidIndex( nNewSlideIndex ) )
{ if( maSlideVisible[nNewSlideIndex] ) break;
const sal_Int32 nNextSlideNumber = getNextSlideNumber(); if( getSlideAPI( nNextSlideNumber, xSlide, xAnimNode ) )
{
Sequence< Any > aValue{ Any(xSlide), Any(xAnimNode) };
aProperties.emplace_back( "Prefetch" ,
-1,
Any(aValue),
PropertyState_DIRECT_VALUE);
} if (bSkipAllMainSequenceEffects)
{ // Add one property that prevents the slide transition from being // shown (to speed up the transition to the previous slide) and // one to show all main sequence effects so that the user can // continue to undo effects.
aProperties.emplace_back( "SkipAllMainSequenceEffects",
-1,
Any(true),
PropertyState_DIRECT_VALUE);
aProperties.emplace_back("SkipSlideTransition",
-1,
Any(true),
PropertyState_DIRECT_VALUE);
}
maUpdateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, updateHdl)); // Priority must not be too high or we'll starve input handling etc.
maUpdateTimer.SetPriority(TaskPriority::REPAINT);
// to be able to react on various changes in the DrawModel, this class // is now derived from SfxListener and registers itself at the DrawModel if (nullptr != mpDoc)
StartListening(*mpDoc);
}
SlideshowImpl::~SlideshowImpl()
{ // stop listening to DrawModel (see above) if (nullptr != mpDoc)
EndListening(*mpDoc);
if( !mbDisposed )
{
OSL_FAIL("SlideshowImpl::~SlideshowImpl(), component was not disposed!");
std::unique_lock g(m_aMutex);
disposing(g);
}
}
void SlideshowImpl::disposing(std::unique_lock<std::mutex>&)
{ #ifdef ENABLE_SDREMOTE
RemoteServer::presentationStopped(); #endif // IASS: This is the central methodology to 'steer' the // PresenterConsole - in this case, to shut it down if( mxShow.is() && mpDoc )
NotifyDocumentEvent(
*mpDoc,
u"OnEndPresentation"_ustr );
// take DrawView from presentation window, but give the old window back if( mpShowWindow && mpView )
mpView->DeleteDeviceFromPaintView( *mpShowWindow->GetOutDev() );
// restart the custom show dialog if he started us if( mpViewShell->IsStartShowWithDialog() && getDispatcher() )
{
mpViewShell->SetStartShowWithDialog( false );
getDispatcher()->Execute( SID_CUSTOMSHOW_DLG, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
}
void SlideshowImpl::startInteractivePreview( const Reference< XDrawPage >& xDrawPage, const Reference< XAnimationNode >& xAnimationNode )
{ // set flag that we are in IASS mode
mbInterActiveSetup = true;
// save stuff that will be replaced temporarily
mxShow2 = mxShow;
mxView2 = mxView;
mxPreviewDrawPage2 = mxPreviewDrawPage;
mxPreviewAnimationNode2 = mxPreviewAnimationNode;
meAnimationMode2 = meAnimationMode;
maPresSettings2 = maPresSettings;
// remember slide shown before preview
mnSlideIndex = getCurrentSlideIndex();
// times should be measured? if( mbRehearseTimings )
{
maPresSettings.mbEndless = false;
maPresSettings.mbManual = true;
maPresSettings.mbMouseVisible = true;
maPresSettings.mbMouseAsPen = false;
maPresSettings.mnPauseTimeout = 0;
maPresSettings.mbShowPauseLogo = false;
}
if( pStartPage )
{ if( pStartPage->GetPageKind() == PageKind::Notes )
{ // we are in notes page mode, so get // the corresponding draw page const sal_uInt16 nNotePgNum = pStartPage->GetPageNum();
assert(nNotePgNum >= 2); const sal_uInt16 nPgNum = ( nNotePgNum - 2 ) >> 1;
pStartPage = mpDoc->GetSdPage( nPgNum, PageKind::Standard );
}
}
if( bStartWithActualSlide )
{ if ( aPresSlide.isEmpty())
{ // no preset slide yet, so pick current on one
aPresSlide = pStartPage->GetName(); // if the starting slide is hidden, we can't set slide controller to ALL mode
maPresSettings.mbAll = !pStartPage->IsExcluded();
}
// build page list
createSlideList( maPresSettings.mbAll, aPresSlide );
// remember Slide number from where the show was started if( pStartPage )
mnRestoreSlide = ( pStartPage->GetPageNum() - 1 ) / 2;
if( mpSlideController->hasSlides() )
{ // hide child windows
hideChildWindows();
mpShowWindow = VclPtr<ShowWindow>::Create( this, mpParentWindow );
mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
mpViewShell->SetActiveWindow( mpShowWindow );
mpShowWindow->SetViewShell (mpViewShell);
mpViewShell->GetViewShellBase().ShowUIControls (false); // Hide the side panes for in-place presentations. if ( ! maPresSettings.mbFullScreen)
mpPaneHider.reset(new PaneHider(*mpViewShell,this));
// these Slots are forbidden in other views for this document if( mpDocSh && pPresSettings && !pPresSettings->mbInteractive) // IASS
{
mpDocSh->SetSlotFilter( true, pAllowed );
mpDocSh->ApplySlotFilter();
}
// #i41824# // Note: In FullScreen Mode the OS (window manager) sends a resize to // the WorkWindow once it actually resized it to full size. The // WorkWindow propagates the resize to the DrawViewShell which calls // resize() at the SlideShow (this). Calling resize here results in a // temporary display of a black window in the window's default size
if( mbUsePen )
{
aProperties.emplace_back( "UserPaintColor" , // User paint color is black by default.
-1, Any( mnUserPaintColor ),
beans::PropertyState_DIRECT_VALUE );
aProperties.emplace_back( "UserPaintStrokeWidth" , // User paint color is black by default.
-1, Any( mdUserPaintStrokeWidth ),
beans::PropertyState_DIRECT_VALUE );
}
mxListenerProxy.set( new SlideShowListenerProxy( this, mxShow ) );
mxListenerProxy->addAsSlideShowListener();
// IASS: Do only startup the PresenterConsole if this is not // the SlideShow Preview mode (else would be double) if (!mbInterActiveSetup)
{ // IASS: This is the central methodology to 'steer' the // PresenterConsole - in this case, to start it up and make // it visible (if activated)
NotifyDocumentEvent(
*mpDoc,
u"OnStartPresentation"_ustr);
}
/** called only by the slideshow view when the first paint event occurs.
This actually starts the slideshow. */ void SlideshowImpl::onFirstPaint()
{ if( mpShowWindow )
{ /* mpShowWindow->SetBackground( Wallpaper( COL_BLACK ) ); mpShowWindow->Erase(); mpShowWindow->SetBackground();
*/
}
void SlideshowImpl::slideEnded(constbool bReverse)
{ if (bReverse)
gotoPreviousSlide(true); else
gotoNextSlide();
}
bool SlideshowImpl::swipe(const CommandGestureSwipeData &rSwipeData)
{ if (mbUsePen || mnContextMenuEvent) returnfalse; double nVelocityX = rSwipeData.getVelocityX(); // tdf#108475 make it swipe only if some reasonable movement was involved if (fabs(nVelocityX) < 50) returnfalse; if (nVelocityX > 0)
{
gotoPreviousSlide();
} else
{
gotoNextEffect();
} //a swipe is followed by a mouse up, tell the view to ignore that mouse up as we've reacted //to the swipe instead
mxView->ignoreNextMouseReleased(); returntrue;
}
bool SlideshowImpl::longpress(const CommandGestureLongPressData &rLongPressData)
{ if (mnContextMenuEvent) returnfalse;
} // send out page change event and notify to update all acc info for current page if (mpViewShell)
{
sal_Int32 currentPageIndex = getCurrentSlideIndex();
mpViewShell->fireSwitchCurrentPage(currentPageIndex);
mpViewShell->NotifyAccUpdate();
}
}
#if HAVE_FEATURE_SCRIPTING case presentation::ClickAction_MACRO:
{ const OUString aMacro( pEvent->maStrBookmark );
if ( SfxApplication::IsXScriptURL( aMacro ) )
{
Any aRet;
Sequence< sal_Int16 > aOutArgsIndex;
Sequence< Any > aOutArgs;
Sequence< Any >* pInArgs = new Sequence< Any >(0);
mpDocSh->CallXScript( aMacro, *pInArgs, aRet, aOutArgsIndex, aOutArgs);
} else
{ // aMacro has the following syntax: // "Macroname.Modulname.Libname.Documentname" or // "Macroname.Modulname.Libname.Applicationname"
sal_Int32 nIdx{ 0 }; const std::u16string_view aMacroName = o3tl::getToken(aMacro, 0, '.', nIdx); const std::u16string_view aModulName = o3tl::getToken(aMacro, 0, '.', nIdx);
// todo: is the limitation still given that only // Modulname+Macroname can be used here?
OUString aExecMacro = OUString::Concat(aModulName) + "." + aMacroName;
mpDocSh->GetBasic()->Call(aExecMacro);
}
} break; #endif
case ClickAction_VERB:
{ // todo, better do it async?
SdrObject* pObj = SdrObject::getSdrObjectFromXShape(xShape);
SdrOle2Obj* pOleObject = dynamic_cast< SdrOle2Obj* >(pObj); if (pOleObject && mpViewShell )
mpViewShell->ActivateObject(pOleObject, pEvent->mnVerb);
} break; default: break;
}
}
/** this timer is called 20ms after a new slide was displayed. This is used to unfreeze user input that was disabled after slide change to skip input that was buffered during slide
transition preparation */
IMPL_LINK_NOARG(SlideshowImpl, ReadyForNextInputHdl, Timer *, void)
{
mbInputFreeze = false;
}
/** if I catch someone someday who calls this method by hand and not by using the timer, I will personally punish this person seriously, even if this person is me.
*/
IMPL_LINK_NOARG(SlideshowImpl, updateHdl, Timer *, void)
{
updateSlideShow();
}
void SlideshowImpl::updateSlideShow()
{ // prevent me from deletion when recursing (App::EnableYieldMode does) const rtl::Reference<SlideshowImpl> xKeepAlive(this);
if (mxShow.is() && (fUpdate >= 0.0))
{ if (::basegfx::fTools::equalZero(fUpdate))
{ // Make sure idle tasks don't starve when we don't have to wait. // Don't process any events generated after invoking the function.
Application::Reschedule(/*bHandleAllCurrentEvents=*/true);
} else
{ // Avoid busy loop when the previous call to update() // returns a small positive number but not 0 (which is // handled above). Also, make sure that calls to update() // have a minimum frequency. // => Allow up to 60 frames per second. Call at least once // every 4 seconds. conststatic sal_Int32 nMaximumFrameCount (60); conststaticdouble nMinimumTimeout (1.0 / nMaximumFrameCount); conststaticdouble nMaximumTimeout (4.0);
fUpdate = std::clamp(fUpdate, nMinimumTimeout, nMaximumTimeout);
// Make sure that the maximum frame count has not been set // too high (only then conversion to milliseconds and long // integer may lead to zero value.)
OSL_ASSERT(static_cast<sal_uLong>(fUpdate * 1000.0) > 0);
}
// Use our high resolution timers for the asynchronous callback.
maUpdateTimer.SetTimeout(static_cast<sal_uLong>(fUpdate * 1000.0));
maUpdateTimer.Start();
}
} catch( Exception& )
{
TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::updateSlideShow()" );
}
}
// cancel show case KEY_ESCAPE: case KEY_SUBTRACT: // in case the user cancels the presentation, switch to current slide // in edit mode if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) )
{ if( mpSlideController->getCurrentSlideNumber() != -1 )
mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
}
endPresentation(); break;
// advance show case KEY_PAGEDOWN: if(rKEvt.GetKeyCode().IsMod2())
{
gotoNextSlide(); break;
}
[[fallthrough]]; case KEY_SPACE: case KEY_RIGHT: case KEY_DOWN: case KEY_XF86FORWARD:
gotoNextEffect(); break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.