/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include "PresenterProtocolHandler.hxx" #include "PresenterController.hxx" #include "PresenterNotesView.hxx" #include "PresenterPaneContainer.hxx" #include "PresenterViewFactory.hxx" #include "PresenterWindowManager.hxx" #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::drawing::framework; namespace sdext::presenter { namespace { class Command { public: virtual ~Command() {} virtual void Execute() = 0; virtual bool IsEnabled() const { return true; } virtual Any GetState() const { return Any(false); } }; class GotoPreviousSlideCommand : public Command { public: explicit GotoPreviousSlideCommand ( const rtl::Reference& rpPresenterController); virtual void Execute() override; virtual bool IsEnabled() const override; private: rtl::Reference mpPresenterController; }; class GotoNextSlideCommand : public Command { public: explicit GotoNextSlideCommand ( const rtl::Reference& rpPresenterController); virtual void Execute() override; // The next slide command is always enabled, even when the current slide // is the last slide: from the last slide it goes to the pause slide, // and from there it ends the slide show. virtual bool IsEnabled() const override { return true; } private: rtl::Reference mpPresenterController; }; class GotoNextEffectCommand : public Command { public: explicit GotoNextEffectCommand ( const rtl::Reference& rpPresenterController); virtual void Execute() override; virtual bool IsEnabled() const override; private: rtl::Reference mpPresenterController; }; class SwitchMonitorCommand : public Command { public: explicit SwitchMonitorCommand ( const rtl::Reference& rpPresenterController); virtual void Execute() override; private: rtl::Reference mpPresenterController; }; class PauseResumeCommand : public Command { public: explicit PauseResumeCommand(const rtl::Reference& rpPresenterController); virtual void Execute() override; virtual Any GetState() const override; private: rtl::Reference mpPresenterController; }; /// This command restarts the presentation timer. class RestartTimerCommand : public Command { public: explicit RestartTimerCommand(const rtl::Reference& rpPresenterController); virtual void Execute() override; private: rtl::Reference mpPresenterController; }; class SetNotesViewCommand : public Command { public: SetNotesViewCommand ( const bool bOn, const rtl::Reference& rpPresenterController); virtual void Execute() override; virtual Any GetState() const override; private: bool mbOn; rtl::Reference mpPresenterController; }; class SetSlideSorterCommand : public Command { public: SetSlideSorterCommand ( const bool bOn, const rtl::Reference& rpPresenterController); virtual void Execute() override; virtual Any GetState() const override; private: bool mbOn; rtl::Reference mpPresenterController; }; class SetHelpViewCommand : public Command { public: SetHelpViewCommand ( const bool bOn, const rtl::Reference& rpPresenterController); virtual void Execute() override; virtual Any GetState() const override; private: bool mbOn; rtl::Reference mpPresenterController; }; class NotesFontSizeCommand : public Command { public: NotesFontSizeCommand( const rtl::Reference& rpPresenterController, const sal_Int32 nSizeChange); virtual void Execute() override; virtual Any GetState() const override; protected: ::rtl::Reference GetNotesView() const; private: rtl::Reference mpPresenterController; const sal_Int32 mnSizeChange; }; class ExitPresenterCommand : public Command { public: explicit ExitPresenterCommand(const rtl::Reference& rpPresenterController); virtual void Execute() override; private: rtl::Reference mpPresenterController; }; } // end of anonymous namespace namespace { typedef ::cppu::WeakComponentImplHelper < css::frame::XDispatch, css::document::XEventListener > PresenterDispatchInterfaceBase; } class PresenterProtocolHandler::Dispatch : protected ::cppu::BaseMutex, public PresenterDispatchInterfaceBase { public: /** Create a new Dispatch object. When the given command name (rsURLPath) is not known then an empty reference is returned. */ static Reference Create ( const OUString& rsURLPath, const ::rtl::Reference& rpPresenterController); void SAL_CALL disposing() override; static Command* CreateCommand ( const OUString& rsURLPath, const ::rtl::Reference& rpPresenterController); // XDispatch virtual void SAL_CALL dispatch( const css::util::URL& aURL, const css::uno::Sequence& rArguments) override; virtual void SAL_CALL addStatusListener( const css::uno::Reference& rxListener, const css::util::URL& rURL) override; virtual void SAL_CALL removeStatusListener ( const css::uno::Reference& rxListener, const css::util::URL& rURL) override; // document::XEventListener virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override; // lang::XEventListener virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override; private: OUString msURLPath; std::unique_ptr mpCommand; ::rtl::Reference mpPresenterController; typedef ::std::vector > StatusListenerContainer; StatusListenerContainer maStatusListenerContainer; bool mbIsListeningToWindowManager; Dispatch ( const OUString& rsURLPath, const ::rtl::Reference& rpPresenterController); virtual ~Dispatch() override; }; //===== PresenterProtocolHandler ========================================================= PresenterProtocolHandler::PresenterProtocolHandler () : PresenterProtocolHandlerInterfaceBase(m_aMutex) { } PresenterProtocolHandler::~PresenterProtocolHandler() { } void SAL_CALL PresenterProtocolHandler::disposing() { } //----- XInitialize ----------------------------------------------------------- void SAL_CALL PresenterProtocolHandler::initialize (const Sequence& aArguments) { ThrowIfDisposed(); if (aArguments.getLength() <= 0) return; try { Reference xFrame; if (aArguments[0] >>= xFrame) { mpPresenterController = PresenterController::Instance(xFrame); } } catch (RuntimeException&) { OSL_ASSERT(false); } } OUString PresenterProtocolHandler::getImplementationName() { return "org.libreoffice.comp.PresenterScreenProtocolHandler"; } sal_Bool PresenterProtocolHandler::supportsService(OUString const & ServiceName) { return cppu::supportsService(this, ServiceName); } css::uno::Sequence PresenterProtocolHandler::getSupportedServiceNames() { return { "com.sun.star.frame.ProtocolHandler" }; } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* sdext_PresenterProtocolHandler_get_implementation( css::uno::XComponentContext* , css::uno::Sequence const&) { return cppu::acquire(new PresenterProtocolHandler()); } //----- XDispatchProvider ----------------------------------------------------- Reference SAL_CALL PresenterProtocolHandler::queryDispatch ( const css::util::URL& rURL, const OUString&, sal_Int32) { ThrowIfDisposed(); Reference xDispatch; // tdf#154546 skip dispatch when presenter controller is not set // mpPresenterController is sometimes unset and this will cause a // crash when pressing the presenter console's Exchange button. if (rURL.Protocol == "vnd.org.libreoffice.presenterscreen:" && mpPresenterController.is()) { xDispatch.set(Dispatch::Create(rURL.Path, mpPresenterController)); } return xDispatch; } Sequence > SAL_CALL PresenterProtocolHandler::queryDispatches( const Sequence&) { ThrowIfDisposed(); return Sequence >(); } void PresenterProtocolHandler::ThrowIfDisposed() const { if (rBHelper.bDisposed || rBHelper.bInDispose) { throw lang::DisposedException ( "PresenterProtocolHandler object has already been disposed", const_cast(static_cast(this))); } } //===== PresenterProtocolHandler::Dispatch ==================================== Reference PresenterProtocolHandler::Dispatch::Create ( const OUString& rsURLPath, const ::rtl::Reference& rpPresenterController) { ::rtl::Reference pDispatch (new Dispatch (rsURLPath, rpPresenterController)); if (pDispatch->mpCommand != nullptr) return pDispatch; else return nullptr; } PresenterProtocolHandler::Dispatch::Dispatch ( const OUString& rsURLPath, const ::rtl::Reference& rpPresenterController) : PresenterDispatchInterfaceBase(m_aMutex), msURLPath(rsURLPath), mpCommand(CreateCommand(rsURLPath, rpPresenterController)), mpPresenterController(rpPresenterController), mbIsListeningToWindowManager(false) { if (mpCommand != nullptr) { mpPresenterController->GetWindowManager()->AddLayoutListener(this); mbIsListeningToWindowManager = true; } } Command* PresenterProtocolHandler::Dispatch::CreateCommand ( const OUString& rsURLPath, const ::rtl::Reference& rpPresenterController) { if (rsURLPath.getLength() <= 5) return nullptr; if (rsURLPath == "CloseNotes") return new SetNotesViewCommand(false, rpPresenterController); if (rsURLPath == "CloseSlideSorter") return new SetSlideSorterCommand(false, rpPresenterController); if (rsURLPath == "CloseHelp") return new SetHelpViewCommand(false, rpPresenterController); if (rsURLPath == "GrowNotesFont") return new NotesFontSizeCommand(rpPresenterController, +1); if (rsURLPath == "NextEffect") return new GotoNextEffectCommand(rpPresenterController); if (rsURLPath == "NextSlide") return new GotoNextSlideCommand(rpPresenterController); if (rsURLPath == "PrevSlide") return new GotoPreviousSlideCommand(rpPresenterController); if (rsURLPath == "SwitchMonitor") return new SwitchMonitorCommand(rpPresenterController); if (rsURLPath == "PauseResumeTimer") return new PauseResumeCommand(rpPresenterController); if (rsURLPath == "RestartTimer") return new RestartTimerCommand(rpPresenterController); if (rsURLPath == "ShowNotes") return new SetNotesViewCommand(true, rpPresenterController); if (rsURLPath == "ShowSlideSorter") return new SetSlideSorterCommand(true, rpPresenterController); if (rsURLPath == "ShowHelp") return new SetHelpViewCommand(true, rpPresenterController); if (rsURLPath == "ShrinkNotesFont") return new NotesFontSizeCommand(rpPresenterController, -1); if (rsURLPath == "ExitPresenter") return new ExitPresenterCommand(rpPresenterController); return nullptr; } PresenterProtocolHandler::Dispatch::~Dispatch() { } void PresenterProtocolHandler::Dispatch::disposing() { if (mbIsListeningToWindowManager) { if (mpPresenterController) mpPresenterController->GetWindowManager()->RemoveLayoutListener(this); mbIsListeningToWindowManager = false; } msURLPath.clear(); mpCommand.reset(); } //----- XDispatch ------------------------------------------------------------- void SAL_CALL PresenterProtocolHandler::Dispatch::dispatch( const css::util::URL& rURL, const css::uno::Sequence& /*rArguments*/) { if (rBHelper.bDisposed || rBHelper.bInDispose) { throw lang::DisposedException ( "PresenterProtocolHandler::Dispatch object has already been disposed", static_cast(this)); } if (rURL.Protocol != "vnd.org.libreoffice.presenterscreen:" || rURL.Path != msURLPath) { // We can not throw an IllegalArgumentException throw RuntimeException(); } if (mpCommand != nullptr) mpCommand->Execute(); } void SAL_CALL PresenterProtocolHandler::Dispatch::addStatusListener( const css::uno::Reference& rxListener, const css::util::URL& rURL) { if (rURL.Path != msURLPath) throw RuntimeException(); maStatusListenerContainer.push_back(rxListener); frame::FeatureStateEvent aEvent; aEvent.FeatureURL = rURL; aEvent.IsEnabled = mpCommand->IsEnabled(); aEvent.Requery = false; aEvent.State = mpCommand->GetState(); rxListener->statusChanged(aEvent); } void SAL_CALL PresenterProtocolHandler::Dispatch::removeStatusListener ( const css::uno::Reference& rxListener, const css::util::URL& rURL) { if (rURL.Path != msURLPath) throw RuntimeException(); StatusListenerContainer::iterator iListener ( ::std::find( maStatusListenerContainer.begin(), maStatusListenerContainer.end(), rxListener)); if (iListener != maStatusListenerContainer.end()) maStatusListenerContainer.erase(iListener); } //----- document::XEventListener ---------------------------------------------- void SAL_CALL PresenterProtocolHandler::Dispatch::notifyEvent ( const css::document::EventObject&) { mpCommand->GetState(); } //----- lang::XEventListener -------------------------------------------------- void SAL_CALL PresenterProtocolHandler::Dispatch::disposing (const css::lang::EventObject&) { mbIsListeningToWindowManager = false; } //===== GotoPreviousSlideCommand ============================================== GotoPreviousSlideCommand::GotoPreviousSlideCommand ( const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void GotoPreviousSlideCommand::Execute() { if ( ! mpPresenterController.is()) return; if ( ! mpPresenterController->GetSlideShowController().is()) return; mpPresenterController->GetSlideShowController()->gotoPreviousSlide(); } bool GotoPreviousSlideCommand::IsEnabled() const { if ( ! mpPresenterController.is()) return false; if ( ! mpPresenterController->GetSlideShowController().is()) return false; return mpPresenterController->GetSlideShowController()->getCurrentSlideIndex()>0; } //===== GotoNextEffect ======================================================== GotoNextEffectCommand::GotoNextEffectCommand ( const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void GotoNextEffectCommand::Execute() { if ( ! mpPresenterController.is()) return; if ( ! mpPresenterController->GetSlideShowController().is()) return; mpPresenterController->GetSlideShowController()->gotoNextEffect(); } bool GotoNextEffectCommand::IsEnabled() const { if ( ! mpPresenterController.is()) return false; if ( ! mpPresenterController->GetSlideShowController().is()) return false; return ( mpPresenterController->GetSlideShowController()->getNextSlideIndex() < mpPresenterController->GetSlideShowController()->getSlideCount() ); } //===== GotoNextSlide ========================================================= GotoNextSlideCommand::GotoNextSlideCommand ( const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void GotoNextSlideCommand::Execute() { if ( ! mpPresenterController.is()) return; if ( ! mpPresenterController->GetSlideShowController().is()) return; mpPresenterController->GetSlideShowController()->gotoNextSlide(); } //===== SwitchMonitorCommand ============================================== SwitchMonitorCommand::SwitchMonitorCommand ( const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void SwitchMonitorCommand::Execute() { mpPresenterController->SwitchMonitors(); } //===== PauseResumeCommand ============================================== PauseResumeCommand::PauseResumeCommand (const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void PauseResumeCommand::Execute() { if ( ! mpPresenterController.is()) return; ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return; IPresentationTime* pPresentationTime = mpPresenterController->GetPresentationTime(); if (!pPresentationTime) return; if(pPresentationTime->isPaused()) { pPresentationTime->setPauseStatus(false); pWindowManager->SetPauseState(false); } else { pPresentationTime->setPauseStatus(true); pWindowManager->SetPauseState(true); } } Any PauseResumeCommand::GetState() const { if ( ! mpPresenterController.is()) return Any(false); ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return Any(false); if (IPresentationTime* pPresentationTime = mpPresenterController->GetPresentationTime()) { return Any(pPresentationTime->isPaused()); } else return Any(false); } RestartTimerCommand::RestartTimerCommand (const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void RestartTimerCommand::Execute() { if ( ! mpPresenterController.is()) return; ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return; if (IPresentationTime* pPresentationTime = mpPresenterController->GetPresentationTime()) { //Resets the pause status and restarts the timer pPresentationTime->setPauseStatus(false); pWindowManager->SetPauseState(false); pPresentationTime->restart(); } } //===== SetNotesViewCommand =================================================== SetNotesViewCommand::SetNotesViewCommand ( const bool bOn, const rtl::Reference& rpPresenterController) : mbOn(bOn), mpPresenterController(rpPresenterController) { } void SetNotesViewCommand::Execute() { if ( ! mpPresenterController.is()) return; ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return; if (mbOn) pWindowManager->SetViewMode(PresenterWindowManager::VM_Notes); else pWindowManager->SetViewMode(PresenterWindowManager::VM_Standard); } Any SetNotesViewCommand::GetState() const { if ( ! mpPresenterController.is()) return Any(false); ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return Any(false); return Any(pWindowManager->GetViewMode() == PresenterWindowManager::VM_Notes); } //===== SetSlideSorterCommand ================================================= SetSlideSorterCommand::SetSlideSorterCommand ( const bool bOn, const rtl::Reference& rpPresenterController) : mbOn(bOn), mpPresenterController(rpPresenterController) { } void SetSlideSorterCommand::Execute() { if ( ! mpPresenterController.is()) return; ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return; pWindowManager->SetSlideSorterState(mbOn); } Any SetSlideSorterCommand::GetState() const { if ( ! mpPresenterController.is()) return Any(false); ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return Any(false); return Any(pWindowManager->GetViewMode()==PresenterWindowManager::VM_SlideOverview); } //===== SetHelpViewCommand =================================================== SetHelpViewCommand::SetHelpViewCommand ( const bool bOn, const rtl::Reference& rpPresenterController) : mbOn(bOn), mpPresenterController(rpPresenterController) { } void SetHelpViewCommand::Execute() { if ( ! mpPresenterController.is()) return; ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return; pWindowManager->SetHelpViewState(mbOn); } Any SetHelpViewCommand::GetState() const { if ( ! mpPresenterController.is()) return Any(false); ::rtl::Reference pWindowManager ( mpPresenterController->GetWindowManager()); if ( ! pWindowManager.is()) return Any(false); return Any(pWindowManager->GetViewMode()==PresenterWindowManager::VM_Help); } //===== NotesFontSizeCommand ================================================== NotesFontSizeCommand::NotesFontSizeCommand( const rtl::Reference& rpPresenterController, const sal_Int32 nSizeChange) : mpPresenterController(rpPresenterController), mnSizeChange(nSizeChange) { } ::rtl::Reference NotesFontSizeCommand::GetNotesView() const { if (!mpPresenterController) return nullptr; PresenterPaneContainer::SharedPaneDescriptor pDescriptor ( mpPresenterController->GetPaneContainer()->FindViewURL( PresenterViewFactory::msNotesViewURL)); if (!pDescriptor) return nullptr; return dynamic_cast(pDescriptor->mxView.get()); } void NotesFontSizeCommand::Execute() { ::rtl::Reference pView (GetNotesView()); if (pView.is()) pView->ChangeFontSize(mnSizeChange); } Any NotesFontSizeCommand::GetState() const { return Any(); } //===== ExitPresenterCommand ================================================== ExitPresenterCommand::ExitPresenterCommand (const rtl::Reference& rpPresenterController) : mpPresenterController(rpPresenterController) { } void ExitPresenterCommand::Execute() { if ( ! mpPresenterController.is()) return; mpPresenterController->ExitPresenter(); } } // end of namespace ::sdext::presenter /* vim:set shiftwidth=4 softtabstop=4 expandtab: */