| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| /* |
| * This file is part of the Collabora Office 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 . |
| */ |
| |
| #include <sal/config.h> |
| |
| #include <algorithm> |
| |
| #include <config_features.h> |
| |
| #include <com/sun/star/frame/theAutoRecovery.hpp> |
| #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> |
| #include <com/sun/star/document/XEventsSupplier.hpp> |
| #include <com/sun/star/drawing/XMasterPageTarget.hpp> |
| #include <com/sun/star/beans/PropertyValue.hpp> |
| #include <com/sun/star/beans/XPropertySetInfo.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/awt/SystemPointer.hpp> |
| #include <com/sun/star/util/URLTransformer.hpp> |
| #include <com/sun/star/util/XURLTransformer.hpp> |
| #include <com/sun/star/frame/XDispatch.hpp> |
| #include <com/sun/star/frame/XLayoutManager.hpp> |
| #include <com/sun/star/presentation/SlideShow.hpp> |
| #include <com/sun/star/media/XPlayer.hpp> |
| #include <officecfg/Office/Impress.hxx> |
| #include <officecfg/Office/Recovery.hxx> |
| #include <svl/stritem.hxx> |
| #include <svl/urihelper.hxx> |
| #include <basic/sbstar.hxx> |
| |
| #include <toolkit/helper/vclunohelper.hxx> |
| #include <comphelper/diagnose_ex.hxx> |
| #include <comphelper/sequence.hxx> |
| |
| #include <sfx2/infobar.hxx> |
| #include <sfx2/dispatch.hxx> |
| #include <sfx2/docfile.hxx> |
| #include <sfx2/app.hxx> |
| #include <sfx2/viewfrm.hxx> |
| #include <svx/svdoole2.hxx> |
| #include <svx/f3dchild.hxx> |
| #include <svx/imapdlg.hxx> |
| #include <svx/fontwork.hxx> |
| #include <svx/SvxColorChildWindow.hxx> |
| #include <svx/bmpmask.hxx> |
| #include <svx/srchdlg.hxx> |
| #include <svx/hyperdlg.hxx> |
| #include <svx/svxids.hrc> |
| #include <svx/unoapi.hxx> |
| #include <AnimationChildWindow.hxx> |
| #include <notifydocumentevent.hxx> |
| #include "slideshowimpl.hxx" |
| #include "slideshowviewimpl.hxx" |
| #include "PaneHider.hxx" |
| |
| #include <bitmaps.hlst> |
| #include <strings.hrc> |
| #include <sdresid.hxx> |
| #include <utility> |
| #include <vcl/ColorDialog.hxx> |
| #include <vcl/canvastools.hxx> |
| #include <vcl/commandevent.hxx> |
| #include <vcl/weldutils.hxx> |
| |
| #include <vcl/settings.hxx> |
| #include <vcl/svapp.hxx> |
| #include <vcl/help.hxx> |
| #include <comphelper/processfactory.hxx> |
| #include <comphelper/propertyvalue.hxx> |
| #include <rtl/ref.hxx> |
| #include <o3tl/safeint.hxx> |
| #include <o3tl/string_view.hxx> |
| #include <avmedia/mediawindow.hxx> |
| #include <DrawDocShell.hxx> |
| #include <ViewShellBase.hxx> |
| #include <PresentationViewShell.hxx> |
| #include <RemoteServer.hxx> |
| #include <customshowlist.hxx> |
| #include <unopage.hxx> |
| #include <sdpage.hxx> |
| #include <sdmod.hxx> |
| #include <app.hrc> |
| #include <cusshow.hxx> |
| #include <optsitem.hxx> |
| #include <unomodel.hxx> |
| |
| #define CM_SLIDES 21 |
| |
| using ::com::sun::star::animations::XAnimationNode; |
| using ::com::sun::star::animations::XAnimationListener; |
| using ::com::sun::star::awt::XWindow; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::drawing; |
| using namespace ::com::sun::star::container; |
| using namespace ::com::sun::star::presentation; |
| using namespace ::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 }; |
| |
| public: |
| AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode ); |
| |
| void setStartSlideNumber( sal_Int32 nSlideNumber ) { mnStartSlideNumber = nSlideNumber; } |
| sal_Int32 getStartSlideIndex() const; |
| |
| sal_Int32 getCurrentSlideNumber() const; |
| sal_Int32 getCurrentSlideIndex() const; |
| |
| sal_Int32 getSlideIndexCount() const { return maSlideNumbers.size(); } |
| sal_Int32 getSlideNumberCount() const { return mnSlideCount; } |
| |
| sal_Int32 getSlideNumber( sal_Int32 nSlideIndex ) const; |
| |
| void insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible = true ); |
| void setPreviewNode( const Reference< XAnimationNode >& xPreviewNode ); |
| |
| bool jumpToSlideIndex( sal_Int32 nNewSlideIndex ); |
| bool jumpToSlideNumber( sal_Int32 nNewSlideIndex ); |
| |
| bool nextSlide(); |
| bool previousSlide(); |
| |
| void displayCurrentSlide( const Reference< XSlideShow >& xShow, |
| const Reference< XDrawPagesSupplier>& xDrawPages, |
| const bool bSkipAllMainSequenceEffects ); |
| |
| sal_Int32 getNextSlideIndex() const; |
| sal_Int32 getPreviousSlideIndex() const; |
| |
| bool isVisibleSlideNumber( sal_Int32 nSlideNumber ) const; |
| |
| Reference< XDrawPage > getSlideByNumber( sal_Int32 nSlideNumber ) const; |
| |
| sal_Int32 getNextSlideNumber() const; |
| |
| bool hasSlides() const { return !maSlideNumbers.empty(); } |
| |
| // 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; |
| |
| bool isValidIndex( sal_Int32 nIndex ) const { return (nIndex >= 0) && (o3tl::make_unsigned(nIndex) < maSlideNumbers.size()); } |
| bool isValidSlideNumber( sal_Int32 nSlideNumber ) const { return (nSlideNumber >= 0) && (nSlideNumber < mnSlideCount); } |
| |
| private: |
| Mode meMode; |
| sal_Int32 mnStartSlideNumber; |
| std::vector< sal_Int32 > maSlideNumbers; |
| std::vector< bool > maSlideVisible; |
| std::vector< bool > maSlideVisited; |
| Reference< XAnimationNode > mxPreviewNode; |
| sal_Int32 mnSlideCount; |
| sal_Int32 mnCurrentSlideIndex; |
| sal_Int32 mnHiddenSlideNumber; |
| Reference< XIndexAccess > mxSlides; |
| |
| // IASS data for push/pop |
| std::vector< sal_Int32 > maSlideNumbers2; |
| std::vector< bool > maSlideVisible2; |
| std::vector< bool > maSlideVisited2; |
| Reference< XAnimationNode > mxPreviewNode2; |
| Mode meMode2; |
| }; |
| |
| void AnimationSlideController::pushForPreview() |
| { |
| maSlideNumbers2 = maSlideNumbers; |
| maSlideVisible2 = maSlideVisible; |
| maSlideVisited2 = maSlideVisited; |
| maSlideNumbers.clear(); |
| maSlideVisible.clear(); |
| maSlideVisited.clear(); |
| mxPreviewNode2 = mxPreviewNode; |
| meMode2 = meMode; |
| meMode = AnimationSlideController::PREVIEW; |
| } |
| |
| void AnimationSlideController::popFromPreview() |
| { |
| maSlideNumbers = maSlideNumbers2; |
| maSlideVisible = maSlideVisible2; |
| maSlideVisited = maSlideVisited2; |
| maSlideNumbers2.clear(); |
| maSlideVisible2.clear(); |
| maSlideVisited2.clear(); |
| mxPreviewNode = mxPreviewNode2; |
| meMode = meMode2; |
| } |
| |
| Reference< XDrawPage > AnimationSlideController::getSlideByNumber( sal_Int32 nSlideNumber ) const |
| { |
| Reference< XDrawPage > xSlide; |
| if( mxSlides.is() && (nSlideNumber >= 0) && (nSlideNumber < mxSlides->getCount()) ) |
| mxSlides->getByIndex( nSlideNumber ) >>= xSlide; |
| return xSlide; |
| } |
| |
| bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber ) const |
| { |
| sal_Int32 nIndex = findSlideIndex( nSlideNumber ); |
| |
| if( nIndex != -1 ) |
| return maSlideVisible[ nIndex ]; |
| else |
| return false; |
| } |
| |
| void AnimationSlideController::setPreviewNode( const Reference< XAnimationNode >& xPreviewNode ) |
| { |
| mxPreviewNode = xPreviewNode; |
| } |
| |
| AnimationSlideController::AnimationSlideController( Reference< XIndexAccess > const & xSlides, Mode eMode ) |
| : meMode( eMode ) |
| , mnStartSlideNumber(-1) |
| , mnSlideCount( 0 ) |
| , mnCurrentSlideIndex(0) |
| , mnHiddenSlideNumber( -1 ) |
| , mxSlides( xSlides ) |
| , meMode2( eMode ) |
| { |
| if( mxSlides.is() ) |
| mnSlideCount = xSlides->getCount(); |
| } |
| |
| sal_Int32 AnimationSlideController::getStartSlideIndex() const |
| { |
| if( mnStartSlideNumber >= 0 ) |
| { |
| sal_Int32 nIndex; |
| const sal_Int32 nCount = maSlideNumbers.size(); |
| |
| for( nIndex = 0; nIndex < nCount; nIndex++ ) |
| { |
| if( maSlideNumbers[nIndex] == mnStartSlideNumber ) |
| return nIndex; |
| } |
| } |
| |
| return 0; |
| } |
| |
| sal_Int32 AnimationSlideController::getCurrentSlideNumber() const |
| { |
| if( mnHiddenSlideNumber != -1 ) |
| return mnHiddenSlideNumber; |
| else if( !maSlideNumbers.empty() ) |
| return maSlideNumbers[mnCurrentSlideIndex]; |
| else |
| return 0; |
| } |
| |
| sal_Int32 AnimationSlideController::getCurrentSlideIndex() const |
| { |
| if( mnHiddenSlideNumber != -1 ) |
| return -1; |
| else |
| return mnCurrentSlideIndex; |
| } |
| |
| bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex ) |
| { |
| if( isValidIndex( nNewSlideIndex ) ) |
| { |
| mnCurrentSlideIndex = nNewSlideIndex; |
| mnHiddenSlideNumber = -1; |
| maSlideVisited[mnCurrentSlideIndex] = true; |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber ) |
| { |
| sal_Int32 nIndex = findSlideIndex( nNewSlideNumber ); |
| if( isValidIndex( nIndex ) ) |
| { |
| return jumpToSlideIndex( nIndex ); |
| } |
| else if( (nNewSlideNumber >= 0) && (nNewSlideNumber < mnSlideCount) ) |
| { |
| // jump to a hidden slide |
| mnHiddenSlideNumber = nNewSlideNumber; |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| sal_Int32 AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex ) const |
| { |
| if( isValidIndex( nSlideIndex ) ) |
| return maSlideNumbers[nSlideIndex]; |
| else |
| return -1; |
| } |
| |
| void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible /* = true */ ) |
| { |
| DBG_ASSERT( isValidSlideNumber( nSlideNumber ), "sd::AnimationSlideController::insertSlideNumber(), illegal index" ); |
| if( isValidSlideNumber( nSlideNumber ) ) |
| { |
| maSlideNumbers.push_back( nSlideNumber ); |
| maSlideVisible.push_back( bVisible ); |
| maSlideVisited.push_back( false ); |
| } |
| } |
| |
| bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode ) |
| { |
| if( isValidSlideNumber( nSlideNumber ) ) try |
| { |
| xSlide.set( mxSlides->getByIndex(nSlideNumber), UNO_QUERY_THROW ); |
| |
| if( meMode == PREVIEW ) |
| { |
| xAnimNode = mxPreviewNode; |
| } |
| else |
| { |
| Reference< animations::XAnimationNodeSupplier > xAnimNodeSupplier( xSlide, UNO_QUERY_THROW ); |
| xAnimNode = xAnimNodeSupplier->getAnimationNode(); |
| } |
| |
| return true; |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::AnimationSlideController::getSlideAPI()" ); |
| } |
| |
| return false; |
| } |
| |
| sal_Int32 AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber ) const |
| { |
| sal_Int32 nIndex; |
| const sal_Int32 nCount = maSlideNumbers.size(); |
| |
| for( nIndex = 0; nIndex < nCount; nIndex++ ) |
| { |
| if( maSlideNumbers[nIndex] == nSlideNumber ) |
| return nIndex; |
| } |
| |
| return -1; |
| } |
| |
| 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; |
| |
| nNewSlideIndex++; |
| } |
| } |
| } |
| return isValidIndex( nNewSlideIndex ) ? nNewSlideIndex : -1; |
| } |
| |
| case FROM: |
| case CUSTOM: |
| return mnHiddenSlideNumber == -1 ? mnCurrentSlideIndex + 1 : mnCurrentSlideIndex; |
| |
| default: |
| case PREVIEW: |
| return -1; |
| |
| } |
| } |
| |
| sal_Int32 AnimationSlideController::getNextSlideNumber() const |
| { |
| sal_Int32 nNextSlideIndex = getNextSlideIndex(); |
| if( isValidIndex( nNextSlideIndex ) ) |
| { |
| return maSlideNumbers[nNextSlideIndex]; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| bool AnimationSlideController::nextSlide() |
| { |
| return jumpToSlideIndex( getNextSlideIndex() ); |
| } |
| |
| sal_Int32 AnimationSlideController::getPreviousSlideIndex() const |
| { |
| sal_Int32 nNewSlideIndex = mnCurrentSlideIndex - 1; |
| |
| switch( meMode ) |
| { |
| case ALL: |
| { |
| // make sure the previous slide is visible |
| // or was already visited |
| while( isValidIndex( nNewSlideIndex ) ) |
| { |
| if( maSlideVisible[nNewSlideIndex] || maSlideVisited[nNewSlideIndex] ) |
| break; |
| |
| nNewSlideIndex--; |
| } |
| |
| break; |
| } |
| |
| case PREVIEW: |
| return -1; |
| |
| default: |
| break; |
| } |
| |
| return nNewSlideIndex; |
| } |
| |
| bool AnimationSlideController::previousSlide() |
| { |
| return jumpToSlideIndex( getPreviousSlideIndex() ); |
| } |
| |
| void AnimationSlideController::displayCurrentSlide( const Reference< XSlideShow >& xShow, |
| const Reference< XDrawPagesSupplier>& xDrawPages, |
| const bool bSkipAllMainSequenceEffects ) |
| { |
| const sal_Int32 nCurrentSlideNumber = getCurrentSlideNumber(); |
| |
| if( !(xShow.is() && (nCurrentSlideNumber != -1 )) ) |
| return; |
| |
| Reference< XDrawPage > xSlide; |
| Reference< XAnimationNode > xAnimNode; |
| ::std::vector<PropertyValue> aProperties; |
| |
| 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); |
| } |
| |
| if( getSlideAPI( nCurrentSlideNumber, xSlide, xAnimNode ) ) |
| xShow->displaySlide( xSlide, xDrawPages, xAnimNode, comphelper::containerToSequence(aProperties) ); |
| } |
| |
| constexpr OUString gsOnClick( u"OnClick"_ustr ); |
| constexpr OUString gsBookmark( u"Bookmark"_ustr ); |
| constexpr OUString gsVerb( u"Verb"_ustr ); |
| |
| SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation, ViewShell* pViewSh, ::sd::View* pView, SdDrawDocument* pDoc, vcl::Window* pParentWindow ) |
| : mxShow() |
| , mxView() |
| , mxModel(pDoc->getUnoModel()) |
| , maUpdateTimer("SlideShowImpl maUpdateTimer") |
| , maInputFreezeTimer("SlideShowImpl maInputFreezeTimer") |
| , maDeactivateTimer("SlideShowImpl maDeactivateTimer") |
| , mpView(pView) |
| , mpViewShell(pViewSh) |
| , mpDocSh(pDoc->GetDocSh()) |
| , mpDoc(pDoc) |
| , mpParentWindow(pParentWindow) |
| , mpShowWindow(nullptr) |
| , mpSlideController() |
| , mnRestoreSlide(0) |
| , maPopupMousePos() |
| , maPresSize( -1, -1 ) |
| , meAnimationMode(ANIMATIONMODE_SHOW) |
| , maCharBuffer() |
| , mpOldActiveWindow(nullptr) |
| , maStarBASICGlobalErrorHdl() |
| , mnChildMask( 0 ) |
| , mbDisposed(false) |
| , mbAutoSaveWasOn(false) |
| , mbRehearseTimings(false) |
| , mbIsPaused(false) |
| , mbWasPaused(false) |
| , mbInputFreeze(false) |
| , mbActive(false) |
| , maPresSettings( pDoc->getPresentationSettings() ) |
| , mnUserPaintColor( 0x80ff0000L ) |
| , mbUsePen(false) |
| , mdUserPaintStrokeWidth ( 150.0 ) |
| , maShapeEventMap() |
| , mxPreviewDrawPage() |
| , mxPreviewAnimationNode() |
| , mxPlayer() |
| , mpPaneHider() |
| , mnEndShowEvent(nullptr) |
| , mnContextMenuEvent(nullptr) |
| , mnEventObjectChange(nullptr) |
| , mnEventObjectInserted(nullptr) |
| , mnEventObjectRemoved(nullptr) |
| , mnEventPageOrderChange(nullptr) |
| , mxPresentation( xPresentation ) |
| , mxListenerProxy() |
| , mxShow2() |
| , mxView2() |
| , meAnimationMode2() |
| , mbInterActiveSetup(false) |
| , maPresSettings2() |
| , mxPreviewDrawPage2() |
| , mxPreviewAnimationNode2() |
| , mnSlideIndex(0) |
| { |
| if( mpViewShell ) |
| mpOldActiveWindow = mpViewShell->GetActiveWindow(); |
| |
| maUpdateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, updateHdl)); |
| // Priority must not be too high or we'll starve input handling etc. |
| maUpdateTimer.SetPriority(TaskPriority::REPAINT); |
| |
| maDeactivateTimer.SetInvokeHandler(LINK(this, SlideshowImpl, deactivateHdl)); |
| maDeactivateTimer.SetTimeout( 20 ); |
| |
| maInputFreezeTimer.SetInvokeHandler( LINK( this, SlideshowImpl, ReadyForNextInputHdl ) ); |
| maInputFreezeTimer.SetTimeout( 20 ); |
| |
| // no autosave during show |
| if (officecfg::Office::Recovery::AutoSave::Enabled::get()) |
| mbAutoSaveWasOn = true; |
| |
| Application::AddEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) ); |
| |
| mbUsePen = maPresSettings.mbMouseAsPen; |
| |
| SdOptions* pOptions = SdModule::get()->GetSdOptions(DocumentType::Impress); |
| if( pOptions ) |
| { |
| mnUserPaintColor = pOptions->GetPresentationPenColor(); |
| mdUserPaintStrokeWidth = pOptions->GetPresentationPenWidth(); |
| } |
| |
| // 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); |
| |
| SdModule* pModule = SdModule::get(); |
| //rhbz#806663 SlideshowImpl can outlive SdModule |
| SdOptions* pOptions = pModule ? |
| pModule->GetSdOptions(DocumentType::Impress) : nullptr; |
| if( pOptions ) |
| { |
| pOptions->SetPresentationPenColor(mnUserPaintColor); |
| pOptions->SetPresentationPenWidth(mdUserPaintStrokeWidth); |
| } |
| |
| Application::RemoveEventListener( LINK( this, SlideshowImpl, EventListenerHdl ) ); |
| |
| maDeactivateTimer.Stop(); |
| |
| 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 ); |
| |
| if( mbAutoSaveWasOn ) |
| setAutoSaveState( true ); |
| |
| if( mnEndShowEvent ) |
| Application::RemoveUserEvent( mnEndShowEvent ); |
| if( mnContextMenuEvent ) |
| Application::RemoveUserEvent( mnContextMenuEvent ); |
| if( mnEventObjectChange ) |
| Application::RemoveUserEvent( mnEventObjectChange ); |
| if( mnEventObjectInserted ) |
| Application::RemoveUserEvent( mnEventObjectInserted ); |
| if( mnEventObjectRemoved ) |
| Application::RemoveUserEvent( mnEventObjectRemoved ); |
| if( mnEventPageOrderChange ) |
| Application::RemoveUserEvent( mnEventPageOrderChange ); |
| |
| maInputFreezeTimer.Stop(); |
| |
| SolarMutexGuard aSolarGuard; |
| |
| if( !mxShow.is() ) |
| return; |
| |
| if( mxPresentation.is() ) |
| mxPresentation->end(); |
| |
| maUpdateTimer.Stop(); |
| |
| removeShapeEvents(); |
| |
| if( mxListenerProxy.is() ) |
| mxListenerProxy->removeAsSlideShowListener(); |
| |
| try |
| { |
| if( mxView.is() ) |
| mxShow->removeView( mxView ); |
| |
| Reference< XComponent > xComponent( mxShow, UNO_QUERY ); |
| if( xComponent.is() ) |
| xComponent->dispose(); |
| |
| if( mxView.is() ) |
| mxView->dispose(); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" ); |
| } |
| |
| mxShow.clear(); |
| mxView.clear(); |
| mxListenerProxy.clear(); |
| mpSlideController.reset(); |
| |
| // take DrawView from presentation window, but give the old window back |
| if( mpShowWindow && mpView ) |
| mpView->DeleteDeviceFromPaintView( *mpShowWindow->GetOutDev() ); |
| |
| if( mpView ) |
| mpView->SetAnimationPause( false ); |
| |
| if( mpViewShell ) |
| { |
| mpViewShell->SetActiveWindow(mpOldActiveWindow); |
| if (mpShowWindow) |
| mpShowWindow->SetViewShell( nullptr ); |
| } |
| |
| if( mpView ) |
| mpView->InvalidateAllWin(); |
| |
| if( maPresSettings.mbFullScreen ) |
| { |
| #if HAVE_FEATURE_SCRIPTING |
| // restore StarBASICErrorHdl |
| StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl); |
| maStarBASICGlobalErrorHdl = Link<StarBASIC*,bool>(); |
| #endif |
| } |
| else |
| { |
| if( mpShowWindow ) |
| mpShowWindow->Hide(); |
| } |
| |
| if( meAnimationMode == ANIMATIONMODE_SHOW ) |
| { |
| mpDocSh->SetSlotFilter(); |
| mpDocSh->ApplySlotFilter(); |
| |
| Help::EnableContextHelp(); |
| Help::EnableExtHelp(); |
| |
| showChildWindows(); |
| mnChildMask = 0; |
| } |
| |
| // show current window again |
| if( mpViewShell && dynamic_cast< PresentationViewShell *>( mpViewShell ) == nullptr) |
| { |
| if( meAnimationMode == ANIMATIONMODE_SHOW ) |
| { |
| mpViewShell->GetViewShellBase().ShowUIControls (true); |
| mpPaneHider.reset(); |
| } |
| else if( meAnimationMode == ANIMATIONMODE_PREVIEW ) |
| { |
| mpViewShell->ShowUIControls(true); |
| } |
| } |
| |
| if( mpShowWindow ) |
| mpShowWindow->Hide(); |
| mpShowWindow.disposeAndClear(); |
| |
| if ( mpViewShell ) |
| { |
| if( meAnimationMode == ANIMATIONMODE_SHOW ) |
| { |
| ::sd::Window* pActWin = mpViewShell->GetActiveWindow(); |
| |
| if (pActWin) |
| { |
| Size aVisSizePixel = pActWin->GetOutputSizePixel(); |
| ::tools::Rectangle aVisAreaWin = pActWin->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); |
| mpViewShell->VisAreaChanged(aVisAreaWin); |
| if (mpView) |
| mpView->VisAreaChanged(pActWin->GetOutDev()); |
| pActWin->GrabFocus(); |
| } |
| } |
| |
| // 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 ); |
| } |
| |
| mpViewShell->GetViewShellBase().UpdateBorder(true); |
| } |
| |
| if( mpShowWindow ) |
| { |
| mpShowWindow.disposeAndClear(); |
| } |
| |
| setActiveXToolbarsVisible( true ); |
| |
| mbDisposed = true; |
| } |
| |
| bool SlideshowImpl::isInteractiveSetup() const |
| { |
| return mbInterActiveSetup; |
| } |
| |
| 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(); |
| |
| // set DrawPage/AnimationNode |
| mxPreviewDrawPage = xDrawPage; |
| mxPreviewAnimationNode = xAnimationNode; |
| meAnimationMode = ANIMATIONMODE_PREVIEW; |
| |
| // set PresSettings for preview |
| maPresSettings.mbAll = false; |
| maPresSettings.mbEndless = false; |
| maPresSettings.mbCustomShow = false; |
| maPresSettings.mbManual = false; |
| maPresSettings.mbMouseVisible = false; |
| maPresSettings.mbMouseAsPen = false; |
| maPresSettings.mbLockedPages = false; |
| maPresSettings.mbAlwaysOnTop = false; |
| maPresSettings.mbFullScreen = false; |
| maPresSettings.mbAnimationAllowed = true; |
| maPresSettings.mnPauseTimeout = 0; |
| maPresSettings.mbShowPauseLogo = false; |
| |
| // create a new temporary AnimationSlideController |
| mpSlideController->pushForPreview(); |
| // Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW ); |
| // Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW ); |
| // mpSlideController = std::make_shared<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW ); |
| sal_Int32 nSlideNumber = 0; |
| Reference< XPropertySet > xSet( xDrawPage, UNO_QUERY_THROW ); |
| xSet->getPropertyValue( u"Number"_ustr ) >>= nSlideNumber; |
| mpSlideController->insertSlideNumber( nSlideNumber-1 ); |
| mpSlideController->setPreviewNode( xAnimationNode ); |
| |
| // prepare properties |
| sal_Int32 nPropertyCount = 1; |
| if( xAnimationNode.is() ) |
| nPropertyCount++; |
| Sequence< beans::PropertyValue > aProperties(nPropertyCount); |
| auto pProperties = aProperties.getArray(); |
| pProperties[0].Name = "AutomaticAdvancement"; |
| pProperties[0].Value <<= 1.0; // one second timeout |
| |
| if( xAnimationNode.is() ) |
| { |
| pProperties[1].Name = "NoSlideTransitions"; |
| pProperties[1].Value <<= true; |
| } |
| |
| // start preview |
| startShowImpl( aProperties ); |
| } |
| |
| void SlideshowImpl::endInteractivePreview() |
| { |
| if (!mbInterActiveSetup) |
| // not in use, nothing to do |
| return; |
| |
| // cleanup Show/View |
| try |
| { |
| if( mxView.is() ) |
| mxShow->removeView( mxView ); |
| |
| Reference< XComponent > xComponent( mxShow, UNO_QUERY ); |
| if( xComponent.is() ) |
| xComponent->dispose(); |
| |
| if( mxView.is() ) |
| mxView->dispose(); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stop()" ); |
| } |
| mxShow.clear(); |
| mxView.clear(); |
| mxView = mxView2; |
| mxShow = mxShow2; |
| |
| // restore SlideController |
| mpSlideController->popFromPreview(); |
| |
| // restore other settings and cleanup temporary incarnations |
| maPresSettings = maPresSettings2; |
| meAnimationMode = meAnimationMode2; |
| mxPreviewAnimationNode = mxPreviewAnimationNode2; |
| mxPreviewAnimationNode2.clear(); |
| mxPreviewDrawPage = mxPreviewDrawPage2; |
| mxPreviewDrawPage2.clear(); |
| |
| // go back to slide shown before preview |
| gotoSlideIndex(mnSlideIndex); |
| |
| // reset IASS mode flag |
| mbInterActiveSetup = false; |
| } |
| |
| bool SlideshowImpl::startPreview( |
| const Reference< XDrawPage >& xDrawPage, |
| const Reference< XAnimationNode >& xAnimationNode, |
| vcl::Window * pParent ) |
| { |
| bool bRet = false; |
| |
| try |
| { |
| const Reference<lang::XServiceInfo> xServiceInfo( xDrawPage, UNO_QUERY ); |
| if (xServiceInfo.is()) { |
| const Sequence<OUString> supportedServices( |
| xServiceInfo->getSupportedServiceNames() ); |
| if (comphelper::findValue(supportedServices, "com.sun.star.drawing.MasterPage") != -1) { |
| OSL_FAIL("sd::SlideshowImpl::startPreview() " |
| "not allowed on master page!"); |
| return false; |
| } |
| } |
| |
| mxPreviewDrawPage = xDrawPage; |
| mxPreviewAnimationNode = xAnimationNode; |
| meAnimationMode = ANIMATIONMODE_PREVIEW; |
| |
| maPresSettings.mbAll = false; |
| maPresSettings.mbEndless = false; |
| maPresSettings.mbCustomShow = false; |
| maPresSettings.mbManual = false; |
| maPresSettings.mbMouseVisible = false; |
| maPresSettings.mbMouseAsPen = false; |
| maPresSettings.mbLockedPages = false; |
| maPresSettings.mbAlwaysOnTop = false; |
| maPresSettings.mbFullScreen = false; |
| maPresSettings.mbAnimationAllowed = true; |
| maPresSettings.mnPauseTimeout = 0; |
| maPresSettings.mbShowPauseLogo = false; |
| |
| rtl::Reference< SdXImpressDocument > xDrawPages( mpDoc->getUnoModel() ); |
| Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW ); |
| mpSlideController = std::make_unique<AnimationSlideController>( xSlides, AnimationSlideController::PREVIEW ); |
| |
| sal_Int32 nSlideNumber = 0; |
| Reference< XPropertySet > xSet( mxPreviewDrawPage, UNO_QUERY_THROW ); |
| xSet->getPropertyValue( u"Number"_ustr ) >>= nSlideNumber; |
| mpSlideController->insertSlideNumber( nSlideNumber-1 ); |
| mpSlideController->setPreviewNode( xAnimationNode ); |
| |
| mpShowWindow = VclPtr<ShowWindow>::Create( this, ((pParent == nullptr) && mpViewShell) ? mpParentWindow.get() : pParent ); |
| if( mpViewShell ) |
| { |
| mpViewShell->SetActiveWindow( mpShowWindow ); |
| mpShowWindow->SetViewShell (mpViewShell); |
| mpViewShell->ShowUIControls (false); |
| } |
| |
| if( mpView ) |
| { |
| mpView->AddDeviceToPaintView( *mpShowWindow->GetOutDev() ); |
| mpView->SetAnimationPause( true ); |
| } |
| |
| // call resize handler |
| if( pParent ) |
| { |
| maPresSize = pParent->GetSizePixel(); |
| } |
| else if( mpViewShell ) |
| { |
| ::tools::Rectangle aContentRect (mpViewShell->GetViewShellBase().getClientRectangle()); |
| if (AllSettings::GetLayoutRTL()) |
| { |
| aContentRect.SetLeft( aContentRect.Right() ); |
| aContentRect.AdjustRight(aContentRect.Right() ); |
| } |
| maPresSize = aContentRect.GetSize(); |
| mpShowWindow->SetPosPixel( aContentRect.TopLeft() ); |
| } |
| else |
| { |
| OSL_FAIL("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!"); |
| } |
| resize( maPresSize ); |
| |
| sal_Int32 nPropertyCount = 1; |
| if( mxPreviewAnimationNode.is() ) |
| nPropertyCount++; |
| |
| Sequence< beans::PropertyValue > aProperties(nPropertyCount); |
| auto pProperties = aProperties.getArray(); |
| pProperties[0].Name = "AutomaticAdvancement"; |
| pProperties[0].Value <<= 1.0; // one second timeout |
| |
| if( mxPreviewAnimationNode.is() ) |
| { |
| pProperties[1].Name = "NoSlideTransitions"; |
| pProperties[1].Value <<= true; |
| } |
| |
| bRet = startShowImpl( aProperties ); |
| |
| if( mpShowWindow != nullptr && meAnimationMode == ANIMATIONMODE_PREVIEW ) |
| mpShowWindow->SetPreviewMode(); |
| |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startPreview()" ); |
| bRet = false; |
| } |
| |
| return bRet; |
| } |
| |
| bool SlideshowImpl::startShow( PresentationSettingsEx const * pPresSettings ) |
| { |
| const rtl::Reference<SlideshowImpl> xKeepAlive(this); |
| |
| DBG_ASSERT( !mxShow.is(), "sd::SlideshowImpl::startShow(), called twice!" ); |
| if( mxShow.is() ) |
| return true; |
| DBG_ASSERT( mpParentWindow!=nullptr, "sd::SlideshowImpl::startShow() called without parent window" ); |
| if (mpParentWindow == nullptr) |
| return false; |
| |
| // Autoplay (pps/ppsx) |
| if (mpViewShell->GetDoc()->GetStartWithPresentation()) |
| { |
| mpViewShell->GetDoc()->SetExitAfterPresenting(true); |
| } |
| |
| bool bRet = false; |
| |
| try |
| { |
| if( pPresSettings ) |
| { |
| maPresSettings = *pPresSettings; |
| mbRehearseTimings = pPresSettings->mbRehearseTimings; |
| } |
| |
| OUString aPresSlide( maPresSettings.maPresPage ); |
| SdPage* pStartPage = mpViewShell->GetActualPage(); |
| bool bStartWithActualSlide = pStartPage; |
| |
| // 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(); |
| } |
| |
| if( meAnimationMode != ANIMATIONMODE_SHOW ) |
| { |
| if( pStartPage->GetPageKind() == PageKind::Standard ) |
| { |
| maPresSettings.mbAll = false; |
| } |
| } |
| } |
| |
| // 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(); |
| } |
| |
| Help::DisableContextHelp(); |
| Help::DisableExtHelp(); |
| |
| if( maPresSettings.mbFullScreen ) |
| { |
| #if HAVE_FEATURE_SCRIPTING |
| // disable basic ide error handling |
| maStarBASICGlobalErrorHdl = StarBASIC::GetGlobalErrorHdl(); |
| StarBASIC::SetGlobalErrorHdl( Link<StarBASIC*,bool>() ); |
| #endif |
| } |
| |
| // call resize handler |
| maPresSize = mpParentWindow->GetSizePixel(); |
| if (!maPresSettings.mbFullScreen) |
| { |
| const ::tools::Rectangle& aClientRect = mpViewShell->GetViewShellBase().getClientRectangle(); |
| maPresSize = aClientRect.GetSize(); |
| mpShowWindow->SetPosPixel( aClientRect.TopLeft() ); |
| resize( maPresSize ); |
| } |
| |
| // #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( mpView ) |
| { |
| mpView->AddDeviceToPaintView( *mpShowWindow->GetOutDev() ); |
| mpView->SetAnimationPause( true ); |
| } |
| |
| SfxBindings* pBindings = getBindings(); |
| if( pBindings ) |
| { |
| pBindings->Invalidate( SID_PRESENTATION ); |
| pBindings->Invalidate( SID_REHEARSE_TIMINGS ); |
| } |
| |
| // Defer the sd::ShowWindow's GrabFocus to SlideShow::activate. so that the accessible event can be fired correctly. |
| //mpShowWindow->GrabFocus(); |
| |
| std::vector<beans::PropertyValue> aProperties; |
| aProperties.reserve( 4 ); |
| |
| aProperties.emplace_back( "AdvanceOnClick" , |
| -1, Any( !maPresSettings.mbLockedPages ), |
| beans::PropertyState_DIRECT_VALUE ); |
| |
| aProperties.emplace_back( "ImageAnimationsAllowed" , |
| -1, Any( maPresSettings.mbAnimationAllowed ), |
| beans::PropertyState_DIRECT_VALUE ); |
| |
| const bool bZOrderEnabled( |
| SdModule::get()->GetSdOptions( mpDoc->GetDocumentType() )->IsSlideshowRespectZOrder() ); |
| aProperties.emplace_back( "DisableAnimationZOrder" , |
| -1, Any( !bZOrderEnabled ), |
| beans::PropertyState_DIRECT_VALUE ); |
| |
| aProperties.emplace_back( "ForceManualAdvance" , |
| -1, Any( maPresSettings.mbManual ), |
| beans::PropertyState_DIRECT_VALUE ); |
| |
| 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 ); |
| } |
| |
| if (mbRehearseTimings) { |
| aProperties.emplace_back( "RehearseTimings" , |
| -1, Any(true), beans::PropertyState_DIRECT_VALUE ); |
| } |
| |
| bRet = startShowImpl( Sequence<beans::PropertyValue>( |
| aProperties.data(), aProperties.size() ) ); |
| |
| } |
| |
| setActiveXToolbarsVisible( false ); |
| } |
| catch (const Exception&) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShow()" ); |
| bRet = false; |
| } |
| |
| return bRet; |
| } |
| |
| bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProperties ) |
| { |
| try |
| { |
| mxShow.set( createSlideShow(), UNO_SET_THROW ); |
| |
| mxView = new SlideShowView( |
| *mpShowWindow, |
| mpDoc, |
| meAnimationMode, |
| this, |
| maPresSettings.mbFullScreen); |
| |
| // try add wait symbol to properties: |
| const Reference<rendering::XSpriteCanvas> xSpriteCanvas( |
| mxView->getCanvas() ); |
| if (xSpriteCanvas.is()) |
| { |
| Bitmap waitSymbolBitmap(BMP_WAIT_ICON); |
| const Reference<rendering::XBitmap> xBitmap( |
| vcl::unotools::xBitmapFromBitmap( waitSymbolBitmap ) ); |
| if (xBitmap.is()) |
| { |
| mxShow->setProperty( |
| beans::PropertyValue( u"WaitSymbolBitmap"_ustr , |
| -1, |
| Any( xBitmap ), |
| beans::PropertyState_DIRECT_VALUE ) ); |
| } |
| |
| Bitmap pointerSymbolBitmap(BMP_POINTER_ICON); |
| const Reference<rendering::XBitmap> xPointerBitmap( |
| vcl::unotools::xBitmapFromBitmap( pointerSymbolBitmap ) ); |
| if (xPointerBitmap.is()) |
| { |
| mxShow->setProperty( |
| beans::PropertyValue( u"PointerSymbolBitmap"_ustr , |
| -1, |
| Any( xPointerBitmap ), |
| beans::PropertyState_DIRECT_VALUE ) ); |
| } |
| if (officecfg::Office::Impress::Misc::Start::ShowNavigationPanel::get()) |
| { |
| NavbarButtonSize btnScale = static_cast<NavbarButtonSize>(officecfg::Office::Impress::Layout::Display::NavigationBtnScale::get()); |
| OUString prevSlidePath = u""_ustr; |
| OUString nextSlidePath = u""_ustr; |
| OUString menuPath = u""_ustr; |
| switch (btnScale) |
| { |
| case NavbarButtonSize::Large: |
| { |
| prevSlidePath = BMP_PREV_SLIDE_LARGE; |
| nextSlidePath = BMP_NEXT_SLIDE_LARGE; |
| menuPath = BMP_MENU_SLIDE_LARGE; |
| break; |
| } |
| case NavbarButtonSize::XLarge: |
| { |
| prevSlidePath = BMP_PREV_SLIDE_EXTRALARGE; |
| nextSlidePath = BMP_NEXT_SLIDE_EXTRALARGE; |
| menuPath = BMP_MENU_SLIDE_EXTRALARGE; |
| break; |
| } |
| case NavbarButtonSize::Auto: |
| case NavbarButtonSize::Small: |
| default: |
| { |
| prevSlidePath = BMP_PREV_SLIDE_SMALL; |
| nextSlidePath = BMP_NEXT_SLIDE_SMALL; |
| menuPath = BMP_MENU_SLIDE_SMALL; |
| break; |
| } |
| } |
| Bitmap prevSlideBm(prevSlidePath); |
| const Reference<rendering::XBitmap> xPrevSBitmap( |
| vcl::unotools::xBitmapFromBitmap(prevSlideBm)); |
| if (xPrevSBitmap.is()) |
| { |
| mxShow->setProperty(beans::PropertyValue(u"NavigationSlidePrev"_ustr, -1, |
| Any(xPrevSBitmap), |
| beans::PropertyState_DIRECT_VALUE)); |
| } |
| Bitmap menuSlideBm(menuPath); |
| const Reference<rendering::XBitmap> xMenuSBitmap( |
| vcl::unotools::xBitmapFromBitmap(menuSlideBm)); |
| if (xMenuSBitmap.is()) |
| { |
| mxShow->setProperty(beans::PropertyValue(u"NavigationSlideMenu"_ustr, -1, |
| Any(xMenuSBitmap), |
| beans::PropertyState_DIRECT_VALUE)); |
| } |
| Bitmap nextSlideBm(nextSlidePath); |
| const Reference<rendering::XBitmap> xNextSBitmap( |
| vcl::unotools::xBitmapFromBitmap(nextSlideBm)); |
| if (xNextSBitmap.is()) |
| { |
| mxShow->setProperty(beans::PropertyValue(u"NavigationSlideNext"_ustr, -1, |
| Any(xNextSBitmap), |
| beans::PropertyState_DIRECT_VALUE)); |
| } |
| } |
| } |
| |
| for( const auto& rProp : aProperties ) |
| mxShow->setProperty( rProp ); |
| |
| mxShow->addView( mxView ); |
| |
| 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); |
| } |
| |
| displaySlideIndex( mpSlideController->getStartSlideIndex() ); |
| |
| return true; |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::startShowImpl()" ); |
| return false; |
| } |
| } |
| |
| /** 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(); |
| */ |
| } |
| |
| SolarMutexGuard aSolarGuard; |
| maUpdateTimer.SetTimeout( sal_uLong(100) ); |
| maUpdateTimer.Start(); |
| } |
| |
| void SlideshowImpl::paint() |
| { |
| if( mxView.is() ) try |
| { |
| awt::PaintEvent aEvt; |
| // aEvt.UpdateRect = TODO |
| mxView->paint( aEvt ); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::paint()" ); |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::addSlideShowListener( const Reference< XSlideShowListener >& xListener ) |
| { |
| if( mxListenerProxy.is() ) |
| mxListenerProxy->addSlideShowListener( xListener ); |
| } |
| |
| void SAL_CALL SlideshowImpl::removeSlideShowListener( const Reference< XSlideShowListener >& xListener ) |
| { |
| if( mxListenerProxy.is() ) |
| mxListenerProxy->removeSlideShowListener( xListener ); |
| } |
| |
| void SlideshowImpl::slideEnded(const bool bReverse) |
| { |
| if (bReverse) |
| gotoPreviousSlide(true); |
| else |
| gotoNextSlide(); |
| } |
| |
| bool SlideshowImpl::swipe(const CommandGestureSwipeData &rSwipeData) |
| { |
| if (mbUsePen || mnContextMenuEvent) |
| return false; |
| double nVelocityX = rSwipeData.getVelocityX(); |
| // tdf#108475 make it swipe only if some reasonable movement was involved |
| if (fabs(nVelocityX) < 50) |
| return false; |
| 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(); |
| return true; |
| } |
| |
| bool SlideshowImpl::longpress(const CommandGestureLongPressData &rLongPressData) |
| { |
| if (mnContextMenuEvent) |
| return false; |
| |
| maPopupMousePos = Point(rLongPressData.getX(), rLongPressData.getY()); |
| mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) ); |
| |
| return true; |
| } |
| |
| void SlideshowImpl::removeShapeEvents() |
| { |
| if( !(mxShow.is() && mxListenerProxy.is()) ) |
| return; |
| |
| try |
| { |
| for( const auto& rEntry : maShapeEventMap ) |
| { |
| mxListenerProxy->removeShapeEventListener( rEntry.first ); |
| mxShow->setShapeCursor( rEntry.first, awt::SystemPointer::ARROW ); |
| } |
| |
| maShapeEventMap.clear(); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::removeShapeEvents()" ); |
| } |
| } |
| |
| void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber) |
| { |
| if( nSlideNumber < 0 ) |
| return; |
| |
| try |
| { |
| Reference< XIndexAccess > xPages( mxModel->getDrawPages(), UNO_QUERY_THROW ); |
| |
| Reference< XShapes > xDrawPage; |
| xPages->getByIndex(nSlideNumber) >>= xDrawPage; |
| |
| if( xDrawPage.is() ) |
| { |
| Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY ); |
| if( xMasterPageTarget.is() ) |
| { |
| Reference< XShapes > xMasterPage = xMasterPageTarget->getMasterPage(); |
| if( xMasterPage.is() ) |
| registerShapeEvents( xMasterPage ); |
| } |
| registerShapeEvents( xDrawPage ); |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" ); |
| } |
| } |
| |
| void SlideshowImpl::registerShapeEvents( Reference< XShapes > const & xShapes ) |
| { |
| try |
| { |
| const sal_Int32 nShapeCount = xShapes->getCount(); |
| sal_Int32 nShape; |
| for( nShape = 0; nShape < nShapeCount; nShape++ ) |
| { |
| Reference< XShape > xShape; |
| xShapes->getByIndex( nShape ) >>= xShape; |
| |
| if( xShape.is() && xShape->getShapeType() == "com.sun.star.drawing.GroupShape" ) |
| { |
| Reference< XShapes > xSubShapes( xShape, UNO_QUERY ); |
| if( xSubShapes.is() ) |
| registerShapeEvents( xSubShapes ); |
| } |
| |
| Reference< XPropertySet > xSet( xShape, UNO_QUERY ); |
| if( !xSet.is() ) |
| continue; |
| |
| Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() ); |
| if( !xSetInfo.is() || !xSetInfo->hasPropertyByName( gsOnClick ) ) |
| continue; |
| |
| WrappedShapeEventImpl aEvent; |
| xSet->getPropertyValue( gsOnClick ) >>= aEvent.meClickAction; |
| |
| switch( aEvent.meClickAction ) |
| { |
| case ClickAction_PREVPAGE: |
| case ClickAction_NEXTPAGE: |
| case ClickAction_FIRSTPAGE: |
| case ClickAction_LASTPAGE: |
| case ClickAction_STOPPRESENTATION: |
| break; |
| case ClickAction_BOOKMARK: |
| if( xSetInfo->hasPropertyByName( gsBookmark ) ) |
| xSet->getPropertyValue( gsBookmark ) >>= aEvent.maStrBookmark; |
| if( getSlideNumberForBookmark( aEvent.maStrBookmark ) == -1 ) |
| continue; |
| break; |
| case ClickAction_DOCUMENT: |
| case ClickAction_SOUND: |
| case ClickAction_PROGRAM: |
| case ClickAction_MACRO: |
| if( xSetInfo->hasPropertyByName( gsBookmark ) ) |
| xSet->getPropertyValue( gsBookmark ) >>= aEvent.maStrBookmark; |
| break; |
| case ClickAction_VERB: |
| if( xSetInfo->hasPropertyByName( gsVerb ) ) |
| xSet->getPropertyValue( gsVerb ) >>= aEvent.mnVerb; |
| break; |
| default: |
| continue; // skip all others |
| } |
| |
| maShapeEventMap[ xShape ] = std::move(aEvent); |
| |
| if( mxListenerProxy.is() ) |
| mxListenerProxy->addShapeEventListener( xShape ); |
| mxShow->setShapeCursor( xShape, awt::SystemPointer::REFHAND ); |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::registerShapeEvents()" ); |
| } |
| } |
| |
| void SlideshowImpl::displayCurrentSlide (const bool bSkipAllMainSequenceEffects) |
| { |
| stopSound(); |
| removeShapeEvents(); |
| |
| if( mpSlideController && mxShow.is() ) |
| { |
| rtl::Reference< SdXImpressDocument > xDrawPages( mpDoc->getUnoModel() ); |
| mpSlideController->displayCurrentSlide( mxShow, xDrawPages, bSkipAllMainSequenceEffects ); |
| registerShapeEvents(mpSlideController->getCurrentSlideNumber()); |
| update(); |
| |
| } |
| // 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(); |
| } |
| } |
| |
| void SlideshowImpl::endPresentation() |
| { |
| if( maPresSettings.mbMouseAsPen) |
| { |
| rtl::Reference< SdXImpressDocument > xDocFactory(mpDoc->getUnoModel() ); |
| if( xDocFactory.is() ) |
| mxShow->registerUserPaintPolygons(xDocFactory); |
| } |
| |
| if( !mnEndShowEvent ) |
| mnEndShowEvent = Application::PostUserEvent( LINK(this, SlideshowImpl, endPresentationHdl) ); |
| } |
| |
| IMPL_LINK_NOARG(SlideshowImpl, endPresentationHdl, void*, void) |
| { |
| mnEndShowEvent = nullptr; |
| |
| stopSound(); |
| |
| if( mxPresentation.is() ) |
| mxPresentation->end(); |
| } |
| |
| void SAL_CALL SlideshowImpl::pause() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mbIsPaused ) |
| return; |
| |
| try |
| { |
| mbIsPaused = true; |
| if( mxShow.is() ) |
| { |
| mxShow->pause(true); |
| |
| if( mxListenerProxy.is() ) |
| mxListenerProxy->paused(); |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::pause()" ); |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::resume() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mbIsPaused ) try |
| { |
| if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK || mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END ) |
| { |
| mpShowWindow->RestartShow(); |
| } |
| else |
| { |
| mbIsPaused = false; |
| if( mxShow.is() ) |
| { |
| mxShow->pause(false); |
| update(); |
| |
| if( mxListenerProxy.is() ) |
| mxListenerProxy->resumed(); |
| } |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resume()" ); |
| } |
| #ifdef ENABLE_SDREMOTE |
| RemoteServer::presentationStarted( this ); |
| #endif |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::isPaused() |
| { |
| SolarMutexGuard aSolarGuard; |
| return mbIsPaused; |
| } |
| |
| void SAL_CALL SlideshowImpl::blankScreen( sal_Int32 nColor ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mpShowWindow && mpSlideController ) |
| { |
| if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), Color(ColorTransparency, nColor) ) ) |
| { |
| pause(); |
| } |
| } |
| } |
| |
| // XShapeEventListener |
| |
| void SlideshowImpl::click( const Reference< XShape >& xShape ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| auto it = maShapeEventMap.find(xShape); |
| if (it == maShapeEventMap.end()) |
| return; |
| WrappedShapeEventImpl* pEvent = &it->second; |
| |
| switch( pEvent->meClickAction ) |
| { |
| case ClickAction_PREVPAGE: gotoPreviousSlide(); break; |
| case ClickAction_NEXTPAGE: gotoNextSlide(); break; |
| case ClickAction_FIRSTPAGE: gotoFirstSlide(); break; |
| case ClickAction_LASTPAGE: gotoLastSlide(); break; |
| case ClickAction_STOPPRESENTATION: endPresentation(); break; |
| case ClickAction_BOOKMARK: |
| { |
| gotoBookmark( pEvent->maStrBookmark ); |
| } |
| break; |
| case ClickAction_SOUND: |
| { |
| #if HAVE_FEATURE_AVMEDIA |
| try |
| { |
| mxPlayer.set(avmedia::MediaWindow::createPlayer(pEvent->maStrBookmark, u""_ustr/*TODO?*/), uno::UNO_SET_THROW ); |
| mxPlayer->start(); |
| } |
| catch( uno::Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::click()" ); |
| } |
| #endif |
| } |
| break; |
| |
| case ClickAction_DOCUMENT: |
| { |
| OUString aBookmark( pEvent->maStrBookmark ); |
| |
| sal_Int32 nPos = aBookmark.indexOf( '#' ); |
| if( nPos >= 0 ) |
| { |
| OUString aURL( aBookmark.copy( 0, nPos+1 ) ); |
| OUString aName( aBookmark.copy( nPos+1 ) ); |
| aURL += getUiNameFromPageApiNameImpl( aName ); |
| aBookmark = aURL; |
| } |
| |
| mpDocSh->OpenBookmark( aBookmark ); |
| } |
| break; |
| |
| case ClickAction_PROGRAM: |
| { |
| INetURLObject aURL( |
| ::URIHelper::SmartRel2Abs( |
| INetURLObject(mpDocSh->GetMedium()->GetBaseURL()), |
| pEvent->maStrBookmark, ::URIHelper::GetMaybeFileHdl(), true, |
| false, INetURLObject::EncodeMechanism::WasEncoded, |
| INetURLObject::DecodeMechanism::Unambiguous ) ); |
| |
| if( INetProtocol::File == aURL.GetProtocol() ) |
| { |
| SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); |
| SfxBoolItem aBrowsing( SID_BROWSE, true ); |
| |
| if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) |
| { |
| SfxUnoFrameItem aDocFrame(SID_FILLFRAME, pViewFrm->GetFrame().GetFrameInterface()); |
| pViewFrm->GetDispatcher()->ExecuteList( SID_OPENDOC, |
| SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, |
| { &aUrl, &aBrowsing }, { &aDocFrame } ); |
| } |
| } |
| } |
| break; |
| |
| #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; |
| } |
| } |
| |
| sal_Int32 SlideshowImpl::getSlideNumberForBookmark( const OUString& rStrBookmark ) |
| { |
| bool bIsMasterPage; |
| OUString aBookmark = getUiNameFromPageApiNameImpl( rStrBookmark ); |
| sal_uInt16 nPgNum = mpDoc->GetPageByName( aBookmark, bIsMasterPage ); |
| |
| if( nPgNum == SDRPAGE_NOTFOUND ) |
| { |
| // Is the bookmark an object? |
| SdrObject* pObj = mpDoc->GetObj( aBookmark ); |
| |
| if( pObj ) |
| { |
| nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum(); |
| bIsMasterPage = pObj->getSdrPageFromSdrObject()->IsMasterPage(); |
| } |
| } |
| |
| if( (nPgNum == SDRPAGE_NOTFOUND) || bIsMasterPage || static_cast<SdPage*>(mpDoc->GetPage(nPgNum))->GetPageKind() != PageKind::Standard ) |
| return -1; |
| |
| return ( nPgNum - 1) >> 1; |
| } |
| |
| void SlideshowImpl::contextMenuShow(const css::awt::Point& point) |
| { |
| maPopupMousePos = { point.X, point.Y }; |
| mnContextMenuEvent = Application::PostUserEvent(LINK(this, SlideshowImpl, ContextMenuHdl)); |
| } |
| |
| void SlideshowImpl::hyperLinkClicked( OUString const& aHyperLink ) |
| { |
| OUString aBookmark( aHyperLink ); |
| |
| sal_Int32 nPos = aBookmark.indexOf( '#' ); |
| if( nPos >= 0 ) |
| { |
| OUString aURL( aBookmark.copy( 0, nPos+1 ) ); |
| OUString aName( aBookmark.copy( nPos+1 ) ); |
| aURL += getUiNameFromPageApiNameImpl( aName ); |
| aBookmark = aURL; |
| } |
| |
| mpDocSh->OpenBookmark( aBookmark ); |
| } |
| |
| void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber ) |
| { |
| if( mpSlideController ) |
| { |
| if( mpSlideController->jumpToSlideNumber( nSlideNumber ) ) |
| { |
| displayCurrentSlide(); |
| } |
| } |
| } |
| |
| /** nSlideIndex == -1 displays current slide again */ |
| void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex ) |
| { |
| if( mpSlideController ) |
| { |
| if( (nSlideIndex == -1) || mpSlideController->jumpToSlideIndex( nSlideIndex ) ) |
| { |
| displayCurrentSlide(); |
| } |
| } |
| } |
| |
| void SlideshowImpl::jumpToBookmark( const OUString& sBookmark ) |
| { |
| sal_Int32 nSlideNumber = getSlideNumberForBookmark( sBookmark ); |
| if( nSlideNumber != -1 ) |
| displaySlideNumber( nSlideNumber ); |
| } |
| |
| sal_Int32 SlideshowImpl::getCurrentSlideNumber() const |
| { |
| return mpSlideController ? mpSlideController->getCurrentSlideNumber() : -1; |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::isEndless() |
| { |
| SolarMutexGuard aSolarGuard; |
| return maPresSettings.mbEndless; |
| } |
| |
| void SlideshowImpl::update() |
| { |
| startUpdateTimer(); |
| } |
| |
| void SlideshowImpl::startUpdateTimer() |
| { |
| SolarMutexGuard aSolarGuard; |
| maUpdateTimer.SetTimeout( 0 ); |
| maUpdateTimer.Start(); |
| } |
| |
| /** 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); |
| |
| Reference< XSlideShow > xShow( mxShow ); |
| if ( ! xShow.is()) |
| return; |
| |
| try |
| { |
| double fUpdate = 0.0; |
| if( !xShow->update(fUpdate) ) |
| fUpdate = -1.0; |
| |
| 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. |
| const static sal_Int32 nMaximumFrameCount (60); |
| const static double nMinimumTimeout (1.0 / nMaximumFrameCount); |
| const static double 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()" ); |
| } |
| } |
| |
| bool SlideshowImpl::keyInput(const KeyEvent& rKEvt) |
| { |
| if( !mxShow.is() || mbInputFreeze ) |
| return false; |
| |
| bool bRet = true; |
| |
| try |
| { |
| const int nKeyCode = rKEvt.GetKeyCode().GetCode(); |
| switch( nKeyCode ) |
| { |
| case awt::Key::CONTEXTMENU: |
| if( !mnContextMenuEvent ) |
| { |
| if( mpShowWindow ) |
| maPopupMousePos = mpShowWindow->GetPointerState().maPos; |
| mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) ); |
| } |
| break; |
| |
| // 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; |
| |
| case KEY_RETURN: |
| { |
| if( !maCharBuffer.isEmpty() ) |
| { |
| if( mpSlideController ) |
| { |
| if( mpSlideController->jumpToSlideNumber( maCharBuffer.toInt32() - 1 ) ) |
| displayCurrentSlide(); |
| } |
| maCharBuffer.clear(); |
| } |
| else |
| { |
| gotoNextEffect(); |
| } |
| } |
| break; |
| |
| // numeric: add to buffer |
| case KEY_0: |
| case KEY_1: |
| case KEY_2: |
| case KEY_3: |
| case KEY_4: |
| case KEY_5: |
| case KEY_6: |
| case KEY_7: |
| case KEY_8: |
| case KEY_9: |
| maCharBuffer += OUStringChar( rKEvt.GetCharCode() ); |
| break; |
| |
| case KEY_PAGEUP: |
| if(rKEvt.GetKeyCode().IsMod2()) |
| { |
| gotoPreviousSlide(); |
| break; |
| } |
| [[fallthrough]]; |
| case KEY_LEFT: |
| case KEY_UP: |
| case KEY_BACKSPACE: |
| case KEY_XF86BACK: |
| gotoPreviousEffect(); |
| break; |
| |
| case KEY_P: |
| setUsePen( !mbUsePen ); |
| break; |
| |
| // tdf#149351 Ctrl+A disables pointer as pen mode |
| case KEY_A: |
| if(rKEvt.GetKeyCode().IsMod1()) |
| { |
| setUsePen( false ); |
| break; |
| } |
| break; |
| |
| case KEY_E: |
| setEraseAllInk( true ); |
| updateSlideShow(); |
| break; |
| |
| case KEY_HOME: |
| gotoFirstSlide(); |
| break; |
| |
| case KEY_END: |
| gotoLastSlide(); |
| break; |
| |
| case KEY_B: |
| case KEY_W: |
| case KEY_POINT: |
| case KEY_COMMA: |
| { |
| blankScreen( ((nKeyCode == KEY_W ) || (nKeyCode == KEY_COMMA)) ? 0x00ffffff : 0x00000000 ); |
| } |
| break; |
| |
| default: |
| bRet = false; |
| break; |
| } |
| } |
| catch( Exception& ) |
| { |
| bRet = false; |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::keyInput()" ); |
| } |
| |
| return bRet; |
| } |
| |
| IMPL_LINK( SlideshowImpl, EventListenerHdl, VclSimpleEvent&, rSimpleEvent, void ) |
| { |
| if( !mxShow.is() || mbInputFreeze ) |
| return; |
| |
| if( !((rSimpleEvent.GetId() == VclEventId::WindowCommand) && static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()) ) |
| return; |
| |
| const CommandEvent& rEvent = *static_cast<const CommandEvent*>(static_cast<VclWindowEvent*>(&rSimpleEvent)->GetData()); |
| |
| if( rEvent.GetCommand() != CommandEventId::Media ) |
| return; |
| |
| CommandMediaData* pMediaData = rEvent.GetMediaData(); |
| pMediaData->SetPassThroughToOS(false); |
| switch (pMediaData->GetMediaId()) |
| { |
| #if defined( MACOSX ) |
| case MediaCommand::Menu: |
| if( !mnContextMenuEvent ) |
| { |
| if( mpShowWindow ) |
| maPopupMousePos = mpShowWindow->GetPointerState().maPos; |
| mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) ); |
| } |
| break; |
| case MediaCommand::VolumeDown: |
| gotoPreviousSlide(); |
| break; |
| case MediaCommand::VolumeUp: |
| gotoNextEffect(); |
| break; |
| #endif |
| case MediaCommand::NextTrack: |
| gotoNextEffect(); |
| break; |
| case MediaCommand::Pause: |
| if( !mbIsPaused ) |
| blankScreen(0); |
| break; |
| case MediaCommand::Play: |
| if( mbIsPaused ) |
| resume(); |
| break; |
| |
| case MediaCommand::PlayPause: |
| if( mbIsPaused ) |
| resume(); |
| else |
| blankScreen(0); |
| break; |
| case MediaCommand::PreviousTrack: |
| gotoPreviousSlide(); |
| break; |
| case MediaCommand::NextTrackHold: |
| gotoLastSlide(); |
| break; |
| |
| case MediaCommand::Rewind: |
| gotoFirstSlide(); |
| break; |
| case MediaCommand::Stop: |
| // 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; |
| default: |
| pMediaData->SetPassThroughToOS(true); |
| break; |
| } |
| } |
| |
| void SlideshowImpl::mouseButtonUp(const MouseEvent& rMEvt) |
| { |
| if( rMEvt.IsRight() && !mnContextMenuEvent ) |
| { |
| maPopupMousePos = rMEvt.GetPosPixel(); |
| mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) ); |
| } |
| } |
| |
| IMPL_LINK_NOARG(SlideshowImpl, ContextMenuHdl, void*, void) |
| { |
| mnContextMenuEvent = nullptr; |
| |
| if (mpSlideController == nullptr) |
| return; |
| |
| mbWasPaused = mbIsPaused; |
| if( !mbWasPaused ) |
| pause(); |
| |
| std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, u"modules/simpress/ui/slidecontextmenu.ui"_ustr)); |
| std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"menu"_ustr)); |
| OUString sNextImage(BMP_MENU_NEXT), sPrevImage(BMP_MENU_PREV); |
| xMenu->insert(0, u"next"_ustr, SdResId(RID_SVXSTR_MENU_NEXT), &sNextImage, nullptr, nullptr, TRISTATE_INDET); |
| xMenu->insert(1, u"prev"_ustr, SdResId(RID_SVXSTR_MENU_PREV), &sPrevImage, nullptr, nullptr, TRISTATE_INDET); |
| |
| // Adding button to display if in Pen mode |
| xMenu->set_active(u"pen"_ustr, mbUsePen); |
| |
| const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode(); |
| xMenu->set_visible(u"next"_ustr, mpSlideController->getNextSlideIndex() != -1); |
| xMenu->set_visible(u"prev"_ustr, (mpSlideController->getPreviousSlideIndex() != -1 ) || (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK)); |
| xMenu->set_visible(u"edit"_ustr, mpViewShell->GetDoc()->GetStartWithPresentation() != 0); |
| |
| std::unique_ptr<weld::Menu> xPageMenu(xBuilder->weld_menu(u"gotomenu"_ustr)); |
| OUString sFirstImage(BMP_MENU_FIRST), sLastImage(BMP_MENU_LAST); |
| xPageMenu->insert(0, u"first"_ustr, SdResId(RID_SVXSTR_MENU_FIRST), &sFirstImage, nullptr, nullptr, TRISTATE_INDET); |
| xPageMenu->insert(1, u"last"_ustr, SdResId(RID_SVXSTR_MENU_LAST), &sLastImage, nullptr, nullptr, TRISTATE_INDET); |
| |
| // populate slide goto list |
| const sal_Int32 nPageNumberCount = mpSlideController->getSlideNumberCount(); |
| if( nPageNumberCount <= 1 ) |
| { |
| xMenu->set_visible(u"goto"_ustr, false); |
| } |
| else |
| { |
| sal_Int32 nCurrentSlideNumber = mpSlideController->getCurrentSlideNumber(); |
| if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) ) |
| nCurrentSlideNumber = -1; |
| |
| xPageMenu->set_visible(u"first"_ustr, mpSlideController->getSlideNumber(0) != nCurrentSlideNumber); |
| xPageMenu->set_visible(u"last"_ustr, mpSlideController->getSlideNumber(mpSlideController->getSlideIndexCount() - 1) != nCurrentSlideNumber); |
| |
| sal_Int32 nPageNumber; |
| |
| for( nPageNumber = 0; nPageNumber < nPageNumberCount; nPageNumber++ ) |
| { |
| if( mpSlideController->isVisibleSlideNumber( nPageNumber ) ) |
| { |
| SdPage* pPage = mpDoc->GetSdPage(static_cast<sal_uInt16>(nPageNumber), PageKind::Standard); |
| if (pPage) |
| { |
| OUString sId(OUString::number(CM_SLIDES + nPageNumber)); |
| xPageMenu->append_check(sId, pPage->GetName()); |
| if (nPageNumber == nCurrentSlideNumber) |
| xPageMenu->set_active(sId, true); |
| } |
| } |
| } |
| } |
| |
| std::unique_ptr<weld::Menu> xBlankMenu(xBuilder->weld_menu(u"screenmenu"_ustr)); |
| |
| if (mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK) |
| { |
| xBlankMenu->set_active((mpShowWindow->GetBlankColor() == COL_WHITE) ? "white" : "black", true); |
| } |
| |
| std::unique_ptr<weld::Menu> xWidthMenu(xBuilder->weld_menu(u"widthmenu"_ustr)); |
| |
| // populate color width list |
| sal_Int32 nIterator; |
| double nWidth; |
| |
| nWidth = 4.0; |
| for( nIterator = 1; nIterator < 6; nIterator++) |
| { |
| switch(nIterator) |
| { |
| case 1: |
| nWidth = 4.0; |
| break; |
| case 2: |
| nWidth = 100.0; |
| break; |
| case 3: |
| nWidth = 150.0; |
| break; |
| case 4: |
| nWidth = 200.0; |
| break; |
| case 5: |
| nWidth = 400.0; |
| break; |
| default: |
| break; |
| } |
| |
| if (nWidth == mdUserPaintStrokeWidth) |
| xWidthMenu->set_active(OUString::number(nWidth), true); |
| } |
| |
| ::tools::Rectangle aRect(maPopupMousePos, Size(1,1)); |
| weld::Window* pParent = weld::GetPopupParent(*mpShowWindow, aRect); |
| ContextMenuSelectHdl(xMenu->popup_at_rect(pParent, aRect)); |
| |
| if( mxView.is() ) |
| mxView->ignoreNextMouseReleased(); |
| |
| if( !mbWasPaused ) |
| resume(); |
| } |
| |
| void SlideshowImpl::ContextMenuSelectHdl(std::u16string_view rMenuId) |
| { |
| if (rMenuId == u"prev") |
| { |
| gotoPreviousSlide(); |
| mbWasPaused = false; |
| } |
| else if(rMenuId == u"next") |
| { |
| gotoNextSlide(); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"first") |
| { |
| gotoFirstSlide(); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"last") |
| { |
| gotoLastSlide(); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"black" || rMenuId == u"white") |
| { |
| const Color aBlankColor(rMenuId == u"white" ? COL_WHITE : COL_BLACK); |
| if( mbWasPaused ) |
| { |
| if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK ) |
| { |
| if( mpShowWindow->GetBlankColor() == aBlankColor ) |
| { |
| mbWasPaused = false; |
| mpShowWindow->RestartShow(); |
| return; |
| } |
| } |
| mpShowWindow->RestartShow(); |
| } |
| if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) ) |
| { |
| pause(); |
| mbWasPaused = true; |
| } |
| } |
| else if (rMenuId == u"color") |
| { |
| //Open a color picker based on SvColorDialog |
| ::Color aColor( ColorTransparency, mnUserPaintColor ); |
| ColorDialog aColorDlg(mpShowWindow->GetFrameWeld()); |
| aColorDlg.SetColor( aColor ); |
| |
| if (aColorDlg.Execute()) |
| { |
| aColor = aColorDlg.GetColor(); |
| setPenColor(sal_Int32(aColor)); |
| } |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"4") |
| { |
| setPenWidth(4.0); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"100") |
| { |
| setPenWidth(100.0); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"150") |
| { |
| setPenWidth(150.0); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"200") |
| { |
| setPenWidth(200.0); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"400") |
| { |
| setPenWidth(400.0); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"erase") |
| { |
| setEraseAllInk(true); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"pen") |
| { |
| setUsePen(!mbUsePen); |
| mbWasPaused = false; |
| } |
| else if (rMenuId == u"edit") |
| { |
| // When in autoplay mode (pps/ppsx), offer editing of the presentation |
| // Turn autostart off, else Impress will close when exiting the Presentation |
| mpViewShell->GetDoc()->SetExitAfterPresenting(false); |
| if( mpSlideController && (ANIMATIONMODE_SHOW == meAnimationMode) ) |
| { |
| if( mpSlideController->getCurrentSlideNumber() != -1 ) |
| { |
| mnRestoreSlide = mpSlideController->getCurrentSlideNumber(); |
| } |
| } |
| endPresentation(); |
| } |
| else if (rMenuId == u"end") |
| { |
| // 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(); |
| } |
| else if (!rMenuId.empty()) |
| { |
| sal_Int32 nPageNumber = o3tl::toInt32(rMenuId) - CM_SLIDES; |
| const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode(); |
| if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) ) |
| { |
| mpShowWindow->RestartShow( nPageNumber ); |
| } |
| else if( nPageNumber != mpSlideController->getCurrentSlideNumber() ) |
| { |
| displaySlideNumber( nPageNumber ); |
| } |
| mbWasPaused = false; |
| } |
| } |
| |
| Reference< XSlideShow > SlideshowImpl::createSlideShow() |
| { |
| Reference< XSlideShow > xShow; |
| |
| try |
| { |
| const Reference< uno::XComponentContext >& xContext = |
| ::comphelper::getProcessComponentContext(); |
| |
| xShow.set( presentation::SlideShow::create(xContext), UNO_SET_THROW ); |
| } |
| catch( uno::Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::createSlideShow()" ); |
| } |
| |
| return xShow; |
| } |
| |
| void SlideshowImpl::createSlideList( bool bAll, std::u16string_view rPresSlide ) |
| { |
| const sal_uInt16 nSlideCount = mpDoc->GetSdPageCount( PageKind::Standard ); |
| |
| if( !nSlideCount ) |
| return; |
| |
| SdCustomShow* pCustomShow; |
| |
| if( mpDoc->GetCustomShowList() && maPresSettings.mbCustomShow ) |
| pCustomShow = mpDoc->GetCustomShowList()->GetCurObject(); |
| else |
| pCustomShow = nullptr; |
| |
| // create animation slide controller |
| AnimationSlideController::Mode eMode = |
| ( pCustomShow && !pCustomShow->PagesVector().empty() ) ? AnimationSlideController::CUSTOM : |
| (bAll ? AnimationSlideController::ALL : AnimationSlideController::FROM); |
| |
| rtl::Reference< SdXImpressDocument > xDrawPages( mpDoc->getUnoModel() ); |
| Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW ); |
| mpSlideController = std::make_unique<AnimationSlideController>( xSlides, eMode ); |
| |
| if( eMode != AnimationSlideController::CUSTOM ) |
| { |
| sal_Int32 nFirstVisibleSlide = 0; |
| |
| // normal presentation |
| if( !rPresSlide.empty() ) |
| { |
| sal_Int32 nSlide; |
| bool bTakeNextAvailable = false; |
| |
| for( nSlide = 0, nFirstVisibleSlide = -1; |
| ( nSlide < nSlideCount ) && ( -1 == nFirstVisibleSlide ); nSlide++ ) |
| { |
| SdPage* pTestSlide = mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard ); |
| |
| if( pTestSlide->GetName() == rPresSlide ) |
| { |
| if( pTestSlide->IsExcluded() ) |
| bTakeNextAvailable = true; |
| else |
| nFirstVisibleSlide = nSlide; |
| } |
| else if( bTakeNextAvailable && !pTestSlide->IsExcluded() ) |
| nFirstVisibleSlide = nSlide; |
| } |
| |
| if( -1 == nFirstVisibleSlide ) |
| nFirstVisibleSlide = 0; |
| } |
| |
| for( sal_Int32 i = 0; i < nSlideCount; i++ ) |
| { |
| bool bVisible = ! mpDoc->GetSdPage( static_cast<sal_uInt16>(i), PageKind::Standard )->IsExcluded(); |
| if( bVisible || (eMode == AnimationSlideController::ALL) ) |
| mpSlideController->insertSlideNumber( i, bVisible ); |
| } |
| |
| mpSlideController->setStartSlideNumber( nFirstVisibleSlide ); |
| } |
| else |
| { |
| if( meAnimationMode != ANIMATIONMODE_SHOW && !rPresSlide.empty() ) |
| { |
| sal_Int32 nSlide; |
| for( nSlide = 0; nSlide < nSlideCount; nSlide++ ) |
| if( rPresSlide == mpDoc->GetSdPage( static_cast<sal_uInt16>(nSlide), PageKind::Standard )->GetName() ) |
| break; |
| |
| if( nSlide < nSlideCount ) |
| mpSlideController->insertSlideNumber( static_cast<sal_uInt16>(nSlide) ); |
| } |
| |
| for( const auto& rpPage : pCustomShow->PagesVector() ) |
| { |
| const sal_uInt16 nSdSlide = ( rpPage->GetPageNum() - 1 ) / 2; |
| |
| if( ! mpDoc->GetSdPage( nSdSlide, PageKind::Standard )->IsExcluded()) |
| mpSlideController->insertSlideNumber( nSdSlide ); |
| } |
| } |
| } |
| |
| typedef sal_uInt16 (*FncGetChildWindowId)(); |
| |
| const FncGetChildWindowId aShowChildren[] = |
| { |
| &AnimationChildWindow::GetChildWindowId, |
| &Svx3DChildWindow::GetChildWindowId, |
| &SvxFontWorkChildWindow::GetChildWindowId, |
| &SvxColorChildWindow::GetChildWindowId, |
| &SvxSearchDialogWrapper::GetChildWindowId, |
| &SvxBmpMaskChildWindow::GetChildWindowId, |
| &SvxIMapDlgChildWindow::GetChildWindowId, |
| &SvxHlinkDlgWrapper::GetChildWindowId, |
| &SfxInfoBarContainerChild::GetChildWindowId |
| }; |
| |
| void SlideshowImpl::hideChildWindows() |
| { |
| mnChildMask = 0; |
| |
| if( ANIMATIONMODE_SHOW != meAnimationMode ) |
| return; |
| |
| SfxViewFrame* pViewFrame = getViewFrame(); |
| |
| if( !pViewFrame ) |
| return; |
| |
| for( sal_uLong i = 0; i < SAL_N_ELEMENTS( aShowChildren ); i++ ) |
| { |
| const sal_uInt16 nId = ( *aShowChildren[ i ] )(); |
| |
| if( pViewFrame->GetChildWindow( nId ) ) |
| { |
| pViewFrame->SetChildWindow( nId, false ); |
| mnChildMask |= ::tools::ULong(1) << i; |
| } |
| } |
| } |
| |
| void SlideshowImpl::showChildWindows() |
| { |
| if( ANIMATIONMODE_SHOW == meAnimationMode ) |
| { |
| SfxViewFrame* pViewFrame = getViewFrame(); |
| if( pViewFrame ) |
| { |
| for( sal_uLong i = 0; i < SAL_N_ELEMENTS(aShowChildren); i++ ) |
| { |
| if( mnChildMask & ( ::tools::ULong(1) << i ) ) |
| pViewFrame->SetChildWindow( ( *aShowChildren[ i ] )(), true ); |
| } |
| } |
| } |
| } |
| |
| SfxViewFrame* SlideshowImpl::getViewFrame() const |
| { |
| return mpViewShell ? mpViewShell->GetViewFrame() : nullptr; |
| } |
| |
| SfxDispatcher* SlideshowImpl::getDispatcher() const |
| { |
| return (mpViewShell && mpViewShell->GetViewFrame()) ? mpViewShell->GetViewFrame()->GetDispatcher() : nullptr; |
| } |
| |
| SfxBindings* SlideshowImpl::getBindings() const |
| { |
| return (mpViewShell && mpViewShell->GetViewFrame()) ? &mpViewShell->GetViewFrame()->GetBindings() : nullptr; |
| } |
| |
| void SlideshowImpl::resize( const Size& rSize ) |
| { |
| maPresSize = rSize; |
| |
| if(mpShowWindow) |
| { |
| mpShowWindow->SetSizePixel( maPresSize ); |
| mpShowWindow->Show(); |
| } |
| |
| if( mxView.is() ) try |
| { |
| awt::WindowEvent aEvt; |
| mxView->windowResized(aEvt); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::resize()" ); |
| } |
| } |
| |
| void SlideshowImpl::setActiveXToolbarsVisible( bool bVisible ) |
| { |
| // in case of ActiveX control the toolbars should not be visible if slide show runs in window mode |
| // actually it runs always in window mode in case of ActiveX control |
| if ( !(!maPresSettings.mbFullScreen && mpDocSh && mpDocSh->GetMedium()) ) |
| return; |
| |
| const SfxBoolItem* pItem = mpDocSh->GetMedium()->GetItemSet().GetItem(SID_VIEWONLY, false); |
| if ( !(pItem && pItem->GetValue()) ) |
| return; |
| |
| // this is a plugin/activex mode, no toolbars should be visible during slide show |
| // after the end of slide show they should be visible again |
| SfxViewFrame* pViewFrame = getViewFrame(); |
| if( !pViewFrame ) |
| return; |
| |
| try |
| { |
| Reference< frame::XLayoutManager > xLayoutManager; |
| Reference< beans::XPropertySet > xFrameProps( pViewFrame->GetFrame().GetFrameInterface(), UNO_QUERY_THROW ); |
| if ( ( xFrameProps->getPropertyValue( u"LayoutManager"_ustr ) |
| >>= xLayoutManager ) |
| && xLayoutManager.is() ) |
| { |
| xLayoutManager->setVisible( bVisible ); |
| } |
| } |
| catch( uno::Exception& ) |
| {} |
| } |
| |
| void SAL_CALL SlideshowImpl::activate() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| maDeactivateTimer.Stop(); |
| |
| if( mbActive || !mxShow.is() ) |
| return; |
| |
| mbActive = true; |
| |
| if( ANIMATIONMODE_SHOW == meAnimationMode ) |
| { |
| if( mbAutoSaveWasOn ) |
| setAutoSaveState( false ); |
| |
| if( mpShowWindow ) |
| { |
| SfxViewFrame* pViewFrame = getViewFrame(); |
| SfxDispatcher* pDispatcher = pViewFrame ? pViewFrame->GetDispatcher() : nullptr; |
| |
| hideChildWindows(); |
| |
| if( pDispatcher ) |
| { |
| // filter all forbidden slots |
| pDispatcher->SetSlotFilter( SfxSlotFilterState::ENABLED, pAllowed ); |
| } |
| |
| if( getBindings() ) |
| getBindings()->InvalidateAll(true); |
| |
| mpShowWindow->GrabFocus(); |
| } |
| } |
| |
| resume(); |
| } |
| |
| void SAL_CALL SlideshowImpl::deactivate() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mbActive && mxShow.is() ) |
| { |
| maDeactivateTimer.Start(); |
| } |
| } |
| |
| IMPL_LINK_NOARG(SlideshowImpl, deactivateHdl, Timer *, void) |
| { |
| if( !(mbActive && mxShow.is()) ) |
| return; |
| |
| mbActive = false; |
| |
| pause(); |
| |
| if( ANIMATIONMODE_SHOW == meAnimationMode ) |
| { |
| if( mbAutoSaveWasOn ) |
| setAutoSaveState( true ); |
| |
| if( mpShowWindow ) |
| { |
| showChildWindows(); |
| } |
| } |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::isActive() |
| { |
| SolarMutexGuard aSolarGuard; |
| return mbActive; |
| } |
| |
| void SlideshowImpl::setAutoSaveState( bool bOn) |
| { |
| try |
| { |
| const uno::Reference<uno::XComponentContext>& xContext( ::comphelper::getProcessComponentContext() ); |
| |
| uno::Reference< util::XURLTransformer > xParser(util::URLTransformer::create(xContext)); |
| util::URL aURL; |
| aURL.Complete = "vnd.sun.star.autorecovery:/setAutoSaveState"; |
| xParser->parseStrict(aURL); |
| |
| Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue(u"AutoSaveState"_ustr, bOn) }; |
| |
| uno::Reference< frame::XDispatch > xAutoSave = frame::theAutoRecovery::get(xContext); |
| xAutoSave->dispatch(aURL, aArgs); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setAutoSaveState()"); |
| } |
| } |
| |
| Reference< XDrawPage > SAL_CALL SlideshowImpl::getCurrentSlide() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| Reference< XDrawPage > xSlide; |
| if( mxShow.is() && mpSlideController ) |
| { |
| sal_Int32 nSlide = getCurrentSlideNumber(); |
| if( (nSlide >= 0) && (nSlide < mpSlideController->getSlideNumberCount() ) ) |
| xSlide = mpSlideController->getSlideByNumber( nSlide ); |
| } |
| |
| return xSlide; |
| } |
| |
| sal_Int32 SAL_CALL SlideshowImpl::getNextSlideIndex() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mxShow.is() ) |
| { |
| return mpSlideController->getNextSlideIndex(); |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| sal_Int32 SAL_CALL SlideshowImpl::getCurrentSlideIndex() |
| { |
| return mpSlideController ? mpSlideController->getCurrentSlideIndex() : -1; |
| } |
| |
| // css::presentation::XSlideShowController: |
| |
| ::sal_Int32 SAL_CALL SlideshowImpl::getSlideCount() |
| { |
| return mpSlideController ? mpSlideController->getSlideIndexCount() : 0; |
| } |
| |
| Reference< XDrawPage > SAL_CALL SlideshowImpl::getSlideByIndex(::sal_Int32 Index) |
| { |
| if ((mpSlideController == nullptr) || (Index < 0) |
| || (Index >= mpSlideController->getSlideIndexCount())) |
| throw IndexOutOfBoundsException(); |
| |
| return mpSlideController->getSlideByNumber( mpSlideController->getSlideNumber( Index ) ); |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::getAlwaysOnTop() |
| { |
| SolarMutexGuard aSolarGuard; |
| return maPresSettings.mbAlwaysOnTop; |
| } |
| |
| void SAL_CALL SlideshowImpl::setAlwaysOnTop( sal_Bool bAlways ) |
| { |
| SolarMutexGuard aSolarGuard; |
| if( maPresSettings.mbAlwaysOnTop != bool(bAlways) ) |
| { |
| maPresSettings.mbAlwaysOnTop = bAlways; |
| // todo, can this be changed while running? |
| } |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::isFullScreen() |
| { |
| SolarMutexGuard aSolarGuard; |
| return maPresSettings.mbFullScreen; |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::getMouseVisible() |
| { |
| SolarMutexGuard aSolarGuard; |
| return maPresSettings.mbMouseVisible; |
| } |
| |
| void SAL_CALL SlideshowImpl::setMouseVisible( sal_Bool bVisible ) |
| { |
| SolarMutexGuard aSolarGuard; |
| if( maPresSettings.mbMouseVisible != bool(bVisible) ) |
| { |
| maPresSettings.mbMouseVisible = bVisible; |
| if( mpShowWindow ) |
| mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible ); |
| } |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::getUsePen() |
| { |
| SolarMutexGuard aSolarGuard; |
| return mbUsePen; |
| } |
| |
| void SAL_CALL SlideshowImpl::setUsePen( sal_Bool bMouseAsPen ) |
| { |
| SolarMutexGuard aSolarGuard; |
| mbUsePen = bMouseAsPen; |
| if( !mxShow.is() ) |
| return; |
| |
| try |
| { |
| // For Pencolor; |
| beans::PropertyValue aPenProp; |
| aPenProp.Name = "UserPaintColor"; |
| if( mbUsePen ) |
| aPenProp.Value <<= mnUserPaintColor; |
| mxShow->setProperty( aPenProp ); |
| |
| //for StrokeWidth : |
| if( mbUsePen ) |
| { |
| beans::PropertyValue aPenPropWidth; |
| aPenPropWidth.Name = "UserPaintStrokeWidth"; |
| aPenPropWidth.Value <<= mdUserPaintStrokeWidth; |
| mxShow->setProperty( aPenPropWidth ); |
| |
| // for Pen Mode |
| beans::PropertyValue aPenPropSwitchPenMode; |
| aPenPropSwitchPenMode.Name = "SwitchPenMode"; |
| aPenPropSwitchPenMode.Value <<= true; |
| mxShow->setProperty( aPenPropSwitchPenMode ); |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::setUsePen()" ); |
| } |
| } |
| |
| double SAL_CALL SlideshowImpl::getPenWidth() |
| { |
| SolarMutexGuard aSolarGuard; |
| return mdUserPaintStrokeWidth; |
| } |
| |
| void SAL_CALL SlideshowImpl::setPenWidth( double dStrokeWidth ) |
| { |
| SolarMutexGuard aSolarGuard; |
| mdUserPaintStrokeWidth = dStrokeWidth; |
| setUsePen( true ); // enable pen mode, update color and width |
| } |
| |
| sal_Int32 SAL_CALL SlideshowImpl::getPenColor() |
| { |
| SolarMutexGuard aSolarGuard; |
| return mnUserPaintColor; |
| } |
| |
| void SAL_CALL SlideshowImpl::setPenColor( sal_Int32 nColor ) |
| { |
| SolarMutexGuard aSolarGuard; |
| mnUserPaintColor = nColor; |
| setUsePen( true ); // enable pen mode, update color |
| } |
| |
| void SAL_CALL SlideshowImpl::setEraseAllInk(sal_Bool bEraseAllInk) |
| { |
| if( !bEraseAllInk ) |
| return; |
| |
| SolarMutexGuard aSolarGuard; |
| if( !mxShow.is() ) |
| return; |
| |
| try |
| { |
| beans::PropertyValue aPenPropEraseAllInk; |
| aPenPropEraseAllInk.Name = "EraseAllInk"; |
| aPenPropEraseAllInk.Value <<= bEraseAllInk; |
| mxShow->setProperty( aPenPropEraseAllInk ); |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd.slideshow", "sd::SlideshowImpl::setEraseAllInk()" ); |
| } |
| } |
| |
| // XSlideShowController Methods |
| sal_Bool SAL_CALL SlideshowImpl::isRunning( ) |
| { |
| SolarMutexGuard aSolarGuard; |
| return mxShow.is(); |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoNextEffect( ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( !(mxShow.is() && mpSlideController && mpShowWindow) ) |
| return; |
| |
| if( mbIsPaused && mpShowWindow->GetShowWindowMode() != SHOWWINDOWMODE_END ) |
| resume(); |
| |
| const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode(); |
| if( eMode == SHOWWINDOWMODE_END ) |
| { |
| endPresentation(); |
| } |
| else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) ) |
| { |
| mpShowWindow->RestartShow(); |
| } |
| else |
| { |
| mxShow->nextEffect(); |
| update(); |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoPreviousEffect( ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( !(mxShow.is() && mpSlideController && mpShowWindow) ) |
| return; |
| |
| const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode(); |
| if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) || mbIsPaused ) |
| { |
| resume(); |
| } |
| else |
| { |
| mxShow->previousEffect(); |
| update(); |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoFirstSlide( ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( !(mpShowWindow && mpSlideController) ) |
| return; |
| |
| if( mbIsPaused ) |
| resume(); |
| |
| if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END ) |
| { |
| if( mpSlideController->getSlideIndexCount() ) |
| mpShowWindow->RestartShow( 0); |
| } |
| else |
| { |
| displaySlideIndex( 0 ); |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoNextSlide( ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mbIsPaused ) |
| resume(); |
| |
| const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode(); |
| if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) ) |
| { |
| mpShowWindow->RestartShow(); |
| } |
| else |
| { |
| // if this is a show, ignore user inputs and |
| // start 20ms timer to reenable inputs to filter |
| // buffered inputs during slide transition |
| if( meAnimationMode == ANIMATIONMODE_SHOW ) |
| { |
| mbInputFreeze = true; |
| maInputFreezeTimer.Start(); |
| } |
| |
| if( mpSlideController ) |
| { |
| if( mpSlideController->nextSlide() ) |
| { |
| displayCurrentSlide(); |
| } |
| else |
| { |
| stopSound(); |
| |
| if( meAnimationMode == ANIMATIONMODE_PREVIEW ) |
| { |
| endPresentation(); |
| } |
| else if( maPresSettings.mbEndless ) |
| { |
| if( maPresSettings.mnPauseTimeout ) |
| { |
| if( mpShowWindow ) |
| { |
| if ( maPresSettings.mbShowPauseLogo ) |
| { |
| Graphic aGraphic(SfxApplication::GetApplicationLogo(360)); |
| mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout, &aGraphic ); |
| } |
| else |
| mpShowWindow->SetPauseMode( maPresSettings.mnPauseTimeout ); |
| } |
| } |
| else |
| { |
| displaySlideIndex( 0 ); |
| } |
| } |
| else |
| { |
| if( mpShowWindow ) |
| { |
| mpShowWindow->SetEndMode(); |
| if (!mpViewShell->GetDoc()->GetStartWithPresentation()) |
| pause(); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoPreviousSlide( ) |
| { |
| gotoPreviousSlide(false); |
| } |
| |
| void SlideshowImpl::gotoPreviousSlide (const bool bSkipAllMainSequenceEffects) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( !(mxShow.is() && mpSlideController) ) |
| return; |
| |
| try |
| { |
| if( mbIsPaused ) |
| resume(); |
| |
| const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode(); |
| if( eMode == SHOWWINDOWMODE_END ) |
| { |
| mpShowWindow->RestartShow( mpSlideController->getCurrentSlideIndex() ); |
| } |
| else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) ) |
| { |
| mpShowWindow->RestartShow(); |
| } |
| else |
| { |
| if( mpSlideController->previousSlide()) |
| displayCurrentSlide(bSkipAllMainSequenceEffects); |
| else if (bSkipAllMainSequenceEffects) |
| { |
| // We could not go to the previous slide (probably because |
| // the current slide is already the first one). We still |
| // have to call displayCurrentSlide because the calling |
| // slideshow can not determine whether there is a previous |
| // slide or not and has already prepared for a slide change. |
| // This slide change has to be completed now, even when |
| // changing to the same slide. |
| // Note that in this special case we do NOT pass |
| // bSkipAllMainSequenceEffects because we display the same |
| // slide as before and do not want to show all its effects. |
| displayCurrentSlide(); |
| } |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::gotoPreviousSlide()" ); |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoLastSlide() |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( !mpSlideController ) |
| return; |
| |
| if( mbIsPaused ) |
| resume(); |
| |
| const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1; |
| if( nLastSlideIndex >= 0 ) |
| { |
| if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END ) |
| { |
| mpShowWindow->RestartShow( nLastSlideIndex ); |
| } |
| else |
| { |
| displaySlideIndex( nLastSlideIndex ); |
| } |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoBookmark( const OUString& rBookmark ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mbIsPaused ) |
| resume(); |
| |
| sal_Int32 nSlideNumber = getSlideNumberForBookmark( rBookmark ); |
| if( nSlideNumber != -1 ) |
| displaySlideNumber( nSlideNumber ); |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoSlide( const Reference< XDrawPage >& xSlide ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( !(mpSlideController && xSlide.is()) ) |
| return; |
| |
| if( mbIsPaused ) |
| resume(); |
| |
| const sal_Int32 nSlideCount = mpSlideController->getSlideNumberCount(); |
| for( sal_Int32 nSlide = 0; nSlide < nSlideCount; nSlide++ ) |
| { |
| if( mpSlideController->getSlideByNumber( nSlide ) == xSlide ) |
| { |
| displaySlideNumber( nSlide ); |
| } |
| } |
| } |
| |
| void SAL_CALL SlideshowImpl::gotoSlideIndex( sal_Int32 nIndex ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| if( mbIsPaused ) |
| resume(); |
| |
| displaySlideIndex( nIndex ); |
| } |
| |
| void SAL_CALL SlideshowImpl::stopSound( ) |
| { |
| SolarMutexGuard aSolarGuard; |
| |
| try |
| { |
| if( mxPlayer.is() ) |
| { |
| mxPlayer->stop(); |
| mxPlayer.clear(); |
| } |
| } |
| catch( Exception& ) |
| { |
| TOOLS_WARN_EXCEPTION( "sd", "sd::SlideshowImpl::stopSound()" ); |
| } |
| } |
| |
| // XIndexAccess |
| |
| ::sal_Int32 SAL_CALL SlideshowImpl::getCount( ) |
| { |
| return getSlideCount(); |
| } |
| |
| css::uno::Any SAL_CALL SlideshowImpl::getByIndex( ::sal_Int32 Index ) |
| { |
| return Any( getSlideByIndex( Index ) ); |
| } |
| |
| css::uno::Type SAL_CALL SlideshowImpl::getElementType( ) |
| { |
| return cppu::UnoType<XDrawPage>::get(); |
| } |
| |
| sal_Bool SAL_CALL SlideshowImpl::hasElements( ) |
| { |
| return getSlideCount() != 0; |
| } |
| |
| namespace |
| { |
| class AsyncUpdateSlideshow_Impl |
| { |
| public: |
| struct AsyncUpdateSlideshowData |
| { |
| SlideshowImpl* pSlideshowImpl; |
| uno::Reference< css::drawing::XDrawPage > XCurrentSlide; |
| SdrHintKind eHintKind; |
| }; |
| |
| static ImplSVEvent* AsyncUpdateSlideshow( |
| SlideshowImpl* pSlideshowImpl, |
| const uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide, |
| SdrHintKind eHintKind) |
| { |
| AsyncUpdateSlideshowData* pNew(new AsyncUpdateSlideshowData); |
| pNew->pSlideshowImpl = pSlideshowImpl; |
| pNew->XCurrentSlide = rXCurrentSlide; |
| pNew->eHintKind = eHintKind; |
| return Application::PostUserEvent(LINK(nullptr, AsyncUpdateSlideshow_Impl, Update), pNew); |
| // coverity[leaked_storage] - pDisruptor takes care of its own destruction at idle time |
| } |
| |
| DECL_STATIC_LINK(AsyncUpdateSlideshow_Impl, Update, void*, void); |
| }; |
| |
| IMPL_STATIC_LINK(AsyncUpdateSlideshow_Impl, Update, void*, pData, void) |
| { |
| AsyncUpdateSlideshowData* pSlideData(static_cast<AsyncUpdateSlideshowData*>(pData)); |
| pSlideData->pSlideshowImpl->AsyncNotifyEvent(pSlideData->XCurrentSlide, pSlideData->eHintKind); |
| delete pSlideData; |
| } |
| } |
| |
| void SlideshowImpl::AsyncNotifyEvent( |
| const uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide, |
| const SdrHintKind eHintKind) |
| { |
| switch (eHintKind) |
| { |
| case SdrHintKind::ObjectInserted: |
| { |
| mnEventObjectInserted = nullptr; |
| |
| // refresh single slide |
| gotoSlide(rXCurrentSlide); |
| break; |
| } |
| case SdrHintKind::ObjectRemoved: |
| { |
| mnEventObjectRemoved = nullptr; |
| |
| // refresh single slide |
| gotoSlide(rXCurrentSlide); |
| break; |
| } |
| case SdrHintKind::ObjectChange: |
| { |
| mnEventObjectChange = nullptr; |
| |
| // refresh single slide |
| gotoSlide(rXCurrentSlide); |
| break; |
| } |
| case SdrHintKind::PageOrderChange: |
| { |
| mnEventPageOrderChange = nullptr; |
| |
| // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos) |
| // rXCurrentSlide is the current slide before the change. |
| rtl::Reference< SdXImpressDocument > xDrawPages( mpDoc->getUnoModel() ); |
| Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW ); |
| const sal_Int32 nNewSlideCount(xSlides.is() ? xSlides->getCount() : 0); |
| |
| if (nNewSlideCount != mpSlideController->getSlideNumberCount()) |
| { |
| // need to reinitialize AnimationSlideController |
| OUString aPresSlide( maPresSettings.maPresPage ); |
| createSlideList( maPresSettings.mbAll, aPresSlide ); |
| } |
| |
| // Check if current slide before change is still valid (maybe removed) |
| const sal_Int32 nSlideCount(mpSlideController->getSlideNumberCount()); |
| bool bSlideStillValid(false); |
| |
| for (sal_Int32 nSlide(0); !bSlideStillValid && nSlide < nSlideCount; nSlide++) |
| { |
| if (rXCurrentSlide == mpSlideController->getSlideByNumber(nSlide)) |
| { |
| bSlideStillValid = true; |
| } |
| } |
| |
| if(bSlideStillValid) |
| { |
| // stay on that slide |
| gotoSlide(rXCurrentSlide); |
| } |
| else |
| { |
| // not possible to stay on that slide, go to 1st slide (kinda restart) |
| gotoFirstSlide(); |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| bool SlideshowImpl::isCurrentSlideInvolved(const SdrHint& rHint) |
| { |
| // get current slide |
| uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide()); |
| if (!XCurrentSlide.is()) |
| return false; |
| |
| SdrPage* pCurrentSlide(GetSdrPageFromXDrawPage(XCurrentSlide)); |
| if (nullptr == pCurrentSlide) |
| return false; |
| |
| const SdrPage* pHintPage(rHint.GetPage()); |
| if (nullptr == pHintPage) |
| return false; |
| |
| if (pHintPage->IsMasterPage()) |
| { |
| if (pCurrentSlide->TRG_HasMasterPage()) |
| { |
| // current slide uses MasterPage on which the change happened |
| return pHintPage == &pCurrentSlide->TRG_GetMasterPage(); |
| } |
| } |
| |
| // object on current slide was changed |
| return pHintPage == pCurrentSlide; |
| } |
| |
| void SlideshowImpl::sendHintSlideChanged(const SdrPage* pChangedPage) const |
| { |
| if (nullptr == pChangedPage) |
| return; |
| |
| if (!mxShow.is()) |
| return; |
| |
| mxShow->setProperty( |
| beans::PropertyValue( u"HintSlideChanged"_ustr , |
| -1, |
| Any( GetXDrawPageForSdrPage(const_cast<SdrPage*>(pChangedPage)) ), |
| beans::PropertyState_DIRECT_VALUE ) ); |
| } |
| |
| void SlideshowImpl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) |
| { |
| if (SfxHintId::ThisIsAnSdrHint != rHint.GetId()) |
| // nothing to do for non-SdrHints |
| return; |
| |
| if (nullptr == mpDoc) |
| // better do nothing when no DrawModel (should not happen) |
| return; |
| |
| // tdf#158664 I am surprised, but the 'this' instance keeps incarnated |
| // when the slideshow was running once, so need to check for |
| // SlideShow instance/running to be safe. |
| // NOTE: isRunning() checks mxShow.is(), that is what we want |
| if (!isRunning()) |
| // no SlideShow instance or not running, nothing to do |
| return; |
| |
| const SdrHint& rSdrHint(static_cast<const SdrHint&>(rHint)); |
| const SdrHintKind eHintKind(rSdrHint.GetKind()); |
| |
| switch (eHintKind) |
| { |
| case SdrHintKind::ObjectInserted: |
| { |
| if (nullptr != mnEventObjectInserted) |
| // avoid multiple events |
| return; |
| |
| // tdf#160669 IASS: inform about ALL changed slides due to prefetch |
| sendHintSlideChanged(rSdrHint.GetPage()); |
| |
| if (!isCurrentSlideInvolved(rSdrHint)) |
| // nothing to do when current slide is not involved |
| return; |
| |
| // Refresh current slide |
| uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide()); |
| mnEventObjectInserted = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind); |
| break; |
| } |
| case SdrHintKind::ObjectRemoved: |
| { |
| if (nullptr != mnEventObjectRemoved) |
| // avoid multiple events |
| return; |
| |
| // tdf#160669 IASS: inform about ALL changed slides due to prefetch |
| sendHintSlideChanged(rSdrHint.GetPage()); |
| |
| if (!isCurrentSlideInvolved(rSdrHint)) |
| // nothing to do when current slide is not involved |
| return; |
| |
| // Refresh current slide |
| uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide()); |
| mnEventObjectRemoved = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind); |
| break; |
| } |
| case SdrHintKind::ObjectChange: |
| { |
| if (nullptr != mnEventObjectChange) |
| // avoid multiple events |
| return; |
| |
| // tdf#160669 IASS: inform about ALL changed slides due to prefetch |
| sendHintSlideChanged(rSdrHint.GetPage()); |
| |
| if (!isCurrentSlideInvolved(rSdrHint)) |
| // nothing to do when current slide is not involved |
| return; |
| |
| // Refresh current slide. Need to do that asynchronous, else e.g. |
| // text edit changes EditEngine/Outliner are not progressed far |
| // enough (ObjectChanged broadcast which we are in here seems |
| // too early for some cases) |
| uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide()); |
| mnEventObjectChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind); |
| break; |
| } |
| case SdrHintKind::PageOrderChange: |
| { |
| // Unfortunately we get multiple events, e.g. when drag/drop position change in |
| // slide sorter on left side of EditView. This includes some with page number +1, |
| // then again -1 (it's a position change). Problem is that in-between already |
| // a re-schedule seems to happen, so indeed AsyncNotifyEvent will change to +1/-1 |
| // already. Since we get even more, at least try to take the last one. I found no |
| // good solution yet for this. |
| if (nullptr != mnEventPageOrderChange) |
| Application::RemoveUserEvent( mnEventPageOrderChange ); |
| |
| // tdf#160669 IASS: inform about ALL changed slides due to prefetch |
| sendHintSlideChanged(rSdrHint.GetPage()); |
| |
| // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos) |
| uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide()); |
| mnEventPageOrderChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind); |
| break; |
| } |
| case SdrHintKind::ModelCleared: |
| { |
| // immediately end presentation |
| endPresentation(); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| Reference< XSlideShow > SAL_CALL SlideshowImpl::getSlideShow() |
| { |
| return mxShow; |
| } |
| |
| PresentationSettingsEx::PresentationSettingsEx( const PresentationSettingsEx& r ) |
| : PresentationSettings( r ) |
| , mbRehearseTimings(r.mbRehearseTimings) |
| , mbPreview(r.mbPreview) |
| , mpParentWindow( nullptr ) |
| { |
| } |
| |
| PresentationSettingsEx::PresentationSettingsEx( PresentationSettings const & r ) |
| : PresentationSettings( r ) |
| , mbRehearseTimings(false) |
| , mbPreview(false) |
| , mpParentWindow(nullptr) |
| { |
| } |
| |
| void PresentationSettingsEx::SetArguments( const Sequence< PropertyValue >& rArguments ) |
| { |
| for( const PropertyValue& rValue : rArguments ) |
| { |
| SetPropertyValue( rValue.Name, rValue.Value ); |
| } |
| } |
| |
| void PresentationSettingsEx::SetPropertyValue( std::u16string_view rProperty, const Any& rValue ) |
| { |
| if ( rProperty == u"RehearseTimings" ) |
| { |
| if( rValue >>= mbRehearseTimings ) |
| return; |
| } |
| else if ( rProperty == u"Preview" ) |
| { |
| if( rValue >>= mbPreview ) |
| return; |
| } |
| else if ( rProperty == u"AnimationNode" ) |
| { |
| if( rValue >>= mxAnimationNode ) |
| return; |
| } |
| else if ( rProperty == u"ParentWindow" ) |
| { |
| Reference< XWindow > xWindow; |
| if( rValue >>= xWindow ) |
| { |
| mpParentWindow = xWindow.is() ? VCLUnoHelper::GetWindow( xWindow ) |
| : nullptr; |
| return; |
| } |
| } |
| else if ( rProperty == u"AllowAnimations" ) |
| { |
| if( rValue >>= mbAnimationAllowed ) |
| return; |
| } |
| else if ( rProperty == u"FirstPage" ) |
| { |
| OUString aPresPage; |
| if( rValue >>= aPresPage ) |
| { |
| maPresPage = getUiNameFromPageApiNameImpl(aPresPage); |
| mbCustomShow = false; |
| mbAll = false; |
| return; |
| } |
| else |
| { |
| if( rValue >>= mxStartPage ) |
| return; |
| } |
| } |
| else if ( rProperty == u"IsAlwaysOnTop" ) |
| { |
| if( rValue >>= mbAlwaysOnTop ) |
| return; |
| } |
| else if ( rProperty == u"IsAutomatic" ) |
| { |
| if( rValue >>= mbManual ) |
| return; |
| } |
| else if ( rProperty == u"IsEndless" ) |
| { |
| if( rValue >>= mbEndless ) |
| return; |
| } |
| else if ( rProperty == u"IsFullScreen" ) |
| { |
| if( rValue >>= mbFullScreen ) |
| return; |
| } |
| else if ( rProperty == u"IsMouseVisible" ) |
| { |
| if( rValue >>= mbMouseVisible ) |
| return; |
| } |
| else if ( rProperty == u"Pause" ) |
| { |
| sal_Int32 nPause = -1; |
| if( (rValue >>= nPause) && (nPause >= 0) ) |
| { |
| mnPauseTimeout = nPause; |
| return; |
| } |
| } |
| else if ( rProperty == u"UsePen" ) |
| { |
| if( rValue >>= mbMouseAsPen ) |
| return; |
| } |
| throw IllegalArgumentException(); |
| } |
| |
| // XAnimationListener |
| |
| SlideShowListenerProxy::SlideShowListenerProxy( rtl::Reference< SlideshowImpl > xController, css::uno::Reference< css::presentation::XSlideShow > xSlideShow ) |
| : mxController(std::move( xController )) |
| , mxSlideShow(std::move( xSlideShow )) |
| { |
| } |
| |
| SlideShowListenerProxy::~SlideShowListenerProxy() |
| { |
| } |
| |
| void SlideShowListenerProxy::addAsSlideShowListener() |
| { |
| if( mxSlideShow.is() ) |
| { |
| Reference< XSlideShowListener > xSlideShowListener( this ); |
| mxSlideShow->addSlideShowListener( xSlideShowListener ); |
| } |
| } |
| |
| void SlideShowListenerProxy::removeAsSlideShowListener() |
| { |
| if( mxSlideShow.is() ) |
| { |
| Reference< XSlideShowListener > xSlideShowListener( this ); |
| mxSlideShow->removeSlideShowListener( xSlideShowListener ); |
| } |
| } |
| |
| void SlideShowListenerProxy::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape ) |
| { |
| if( mxSlideShow.is() ) |
| { |
| Reference< XShapeEventListener > xListener( this ); |
| mxSlideShow->addShapeEventListener( xListener, xShape ); |
| } |
| } |
| |
| void SlideShowListenerProxy::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape ) |
| { |
| if( mxSlideShow.is() ) |
| { |
| Reference< XShapeEventListener > xListener( this ); |
| mxSlideShow->removeShapeEventListener( xListener, xShape ); |
| } |
| } |
| |
| void SlideShowListenerProxy::addSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener ) |
| { |
| std::unique_lock g(m_aMutex); |
| maListeners.addInterface(g, xListener); |
| } |
| |
| void SlideShowListenerProxy::removeSlideShowListener( const css::uno::Reference< css::presentation::XSlideShowListener >& xListener ) |
| { |
| std::unique_lock g(m_aMutex); |
| maListeners.removeInterface(g, xListener); |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::beginEvent( const Reference< XAnimationNode >& xNode ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| if( maListeners.getLength(aGuard) >= 0 ) |
| { |
| maListeners.forEach(aGuard, |
| [&] (Reference<XAnimationListener> const& xListener) { |
| return xListener->beginEvent(xNode); |
| } ); |
| } |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::endEvent( const Reference< XAnimationNode >& xNode ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| if( maListeners.getLength(aGuard) >= 0 ) |
| { |
| maListeners.forEach(aGuard, |
| [&] (Reference<XAnimationListener> const& xListener) { |
| return xListener->endEvent(xNode); |
| } ); |
| } |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::repeat( const Reference< XAnimationNode >& xNode, ::sal_Int32 nRepeat ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| if( maListeners.getLength(aGuard) >= 0 ) |
| { |
| maListeners.forEach(aGuard, |
| [&] (Reference<XAnimationListener> const& xListener) { |
| return xListener->repeat(xNode, nRepeat); |
| } ); |
| } |
| } |
| |
| // css::presentation::XSlideShowListener: |
| |
| void SAL_CALL SlideShowListenerProxy::paused( ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| maListeners.forEach(aGuard, |
| [](uno::Reference<presentation::XSlideShowListener> const& xListener) |
| { |
| xListener->paused(); |
| }); |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::resumed( ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| maListeners.forEach(aGuard, |
| [](uno::Reference<presentation::XSlideShowListener> const& xListener) |
| { |
| xListener->resumed(); |
| }); |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::slideTransitionStarted( ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| maListeners.forEach(aGuard, |
| [](uno::Reference<presentation::XSlideShowListener> const& xListener) |
| { |
| xListener->slideTransitionStarted(); |
| }); |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::slideTransitionEnded( ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| maListeners.forEach(aGuard, |
| [](uno::Reference<presentation::XSlideShowListener> const& xListener) |
| { |
| xListener->slideTransitionEnded (); |
| }); |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::slideAnimationsEnded( ) |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| maListeners.forEach(aGuard, |
| [](uno::Reference<presentation::XSlideShowListener> const& xListener) |
| { |
| xListener->slideAnimationsEnded (); |
| }); |
| } |
| |
| void SlideShowListenerProxy::slideEnded(sal_Bool bReverse) |
| { |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| if( maListeners.getLength(aGuard) >= 0 ) |
| { |
| maListeners.forEach(aGuard, |
| [&] (Reference<XSlideShowListener> const& xListener) { |
| return xListener->slideEnded(bReverse); |
| } ); |
| } |
| } |
| |
| { |
| SolarMutexGuard aSolarGuard; |
| if( mxController.is() ) |
| mxController->slideEnded(bReverse); |
| } |
| } |
| |
| void SlideShowListenerProxy::hyperLinkClicked( OUString const& aHyperLink ) |
| { |
| { |
| std::unique_lock aGuard( m_aMutex ); |
| |
| if( maListeners.getLength(aGuard) >= 0 ) |
| { |
| maListeners.forEach(aGuard, |
| [&] (Reference<XSlideShowListener> const& xListener) { |
| return xListener->hyperLinkClicked(aHyperLink); |
| } ); |
| } |
| } |
| |
| { |
| SolarMutexGuard aSolarGuard; |
| if( mxController.is() ) |
| mxController->hyperLinkClicked(aHyperLink); |
| } |
| } |
| |
| // XEventListener |
| |
| void SAL_CALL SlideShowListenerProxy::disposing( const css::lang::EventObject& aDisposeEvent ) |
| { |
| std::unique_lock g(m_aMutex); |
| maListeners.disposeAndClear( g, aDisposeEvent ); |
| mxController.clear(); |
| mxSlideShow.clear(); |
| } |
| |
| // XShapeEventListener |
| |
| void SAL_CALL SlideShowListenerProxy::click( const Reference< XShape >& xShape, const css::awt::MouseEvent& /*aOriginalEvent*/ ) |
| { |
| SolarMutexGuard aSolarGuard; |
| if( mxController.is() ) |
| mxController->click(xShape ); |
| } |
| |
| void SAL_CALL SlideShowListenerProxy::contextMenuShow(const css::awt::Point& point) |
| { |
| SolarMutexGuard aSolarGuard; |
| if (mxController.is()) |
| mxController->contextMenuShow(point); |
| } |
| |
| } // namespace ::sd |
| |
| /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |