/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sdext.hxx" #include "PresenterScreen.hxx" #include "PresenterConfigurationAccess.hxx" #include "PresenterController.hxx" #include "PresenterFrameworkObserver.hxx" #include "PresenterHelper.hxx" #include "PresenterPaneContainer.hxx" #include "PresenterPaneFactory.hxx" #include "PresenterViewFactory.hxx" #include "PresenterWindowManager.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::presentation; using namespace ::com::sun::star::drawing::framework; using ::rtl::OUString; #define A2S(s) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))) namespace sdext { namespace presenter { namespace { typedef ::cppu::WeakComponentImplHelper1 < css::document::XEventListener > PresenterScreenListenerInterfaceBase; /** One instance of a PresenterScreenListener is registered per Impress document and waits for the full screen slide show to start and to end. */ class PresenterScreenListener : private ::boost::noncopyable, private ::cppu::BaseMutex, public PresenterScreenListenerInterfaceBase { public: PresenterScreenListener ( const css::uno::Reference& rxContext, const css::uno::Reference& rxModel); virtual ~PresenterScreenListener (void); void Initialize (void); virtual void SAL_CALL disposing (void); // document::XEventListener virtual void SAL_CALL notifyEvent( const css::document::EventObject& Event ) throw (css::uno::RuntimeException); // XEventListener virtual void SAL_CALL disposing ( const css::lang::EventObject& rEvent) throw (css::uno::RuntimeException); private: css::uno::Reference mxModel; css::uno::Reference mxComponentContext; rtl::Reference mpPresenterScreen; void ThrowIfDisposed (void) const throw (::com::sun::star::lang::DisposedException); }; } //----- Service --------------------------------------------------------------- OUString PresenterScreenJob::getImplementationName_static (void) { return A2S("com.sun.star.comp.Draw.framework.PresenterScreenJob"); } Sequence PresenterScreenJob::getSupportedServiceNames_static (void) { static const ::rtl::OUString sServiceName( A2S("com.sun.star.drawing.framework.PresenterScreenJob")); return Sequence(&sServiceName, 1); } Reference PresenterScreenJob::Create (const Reference& rxContext) SAL_THROW((css::uno::Exception)) { return Reference(static_cast(new PresenterScreenJob(rxContext))); } //===== PresenterScreenJob ==================================================== PresenterScreenJob::PresenterScreenJob (const Reference& rxContext) : PresenterScreenJobInterfaceBase(m_aMutex), mxComponentContext(rxContext) { } PresenterScreenJob::~PresenterScreenJob (void) { } void SAL_CALL PresenterScreenJob::disposing (void) { mxComponentContext = NULL; } //----- XJob ----------------------------------------------------------- Any SAL_CALL PresenterScreenJob::execute( const Sequence< beans::NamedValue >& Arguments ) throw (lang::IllegalArgumentException, Exception, RuntimeException) { Sequence< beans::NamedValue > lEnv; sal_Int32 i = 0; sal_Int32 c = Arguments.getLength(); const beans::NamedValue* p = Arguments.getConstArray(); for (i=0; i>= lEnv; break; } } Reference xModel; c = lEnv.getLength(); p = lEnv.getConstArray(); for (i=0; i>= xModel; break; } } Reference< XServiceInfo > xInfo( xModel, UNO_QUERY ); if( xInfo.is() && xInfo->supportsService( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.presentation.PresentationDocument" ) ) ) ) { // Create a new listener that waits for the full screen presentation // to start and to end. It takes care of its own lifetime. ::rtl::Reference pListener ( new PresenterScreenListener(mxComponentContext, xModel)); pListener->Initialize(); } return Any(); } //===== PresenterScreenListener =============================================== namespace { PresenterScreenListener::PresenterScreenListener ( const css::uno::Reference& rxContext, const css::uno::Reference& rxModel) : PresenterScreenListenerInterfaceBase(m_aMutex), mxModel(rxModel), mxComponentContext(rxContext), mpPresenterScreen() { } void PresenterScreenListener::Initialize (void) { Reference< document::XEventListener > xDocListener( static_cast< document::XEventListener* >(this), UNO_QUERY); Reference< document::XEventBroadcaster > xDocBroadcaster( mxModel, UNO_QUERY ); if( xDocBroadcaster.is() ) xDocBroadcaster->addEventListener(xDocListener); } PresenterScreenListener::~PresenterScreenListener (void) { } void SAL_CALL PresenterScreenListener::disposing (void) { Reference< document::XEventBroadcaster > xDocBroadcaster( mxModel, UNO_QUERY ); if( xDocBroadcaster.is() ) xDocBroadcaster->removeEventListener( Reference( static_cast(this), UNO_QUERY)); if (mpPresenterScreen.is()) { mpPresenterScreen->RequestShutdownPresenterScreen(); mpPresenterScreen = NULL; } } // document::XEventListener void SAL_CALL PresenterScreenListener::notifyEvent( const css::document::EventObject& Event ) throw (css::uno::RuntimeException) { ThrowIfDisposed(); if( Event.EventName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "OnStartPresentation" ) ) ) { mpPresenterScreen = new PresenterScreen(mxComponentContext, mxModel); mpPresenterScreen->InitializePresenterScreen(); } else if( Event.EventName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "OnEndPresentation" ) ) ) { if (mpPresenterScreen.is()) { mpPresenterScreen->RequestShutdownPresenterScreen(); mpPresenterScreen = NULL; } } } // XEventListener void SAL_CALL PresenterScreenListener::disposing (const css::lang::EventObject& rEvent) throw (css::uno::RuntimeException) { (void)rEvent; if (mpPresenterScreen.is()) { mpPresenterScreen->RequestShutdownPresenterScreen(); mpPresenterScreen = NULL; } } void PresenterScreenListener::ThrowIfDisposed (void) const throw ( ::com::sun::star::lang::DisposedException) { if (rBHelper.bDisposed || rBHelper.bInDispose) { throw lang::DisposedException ( OUString(RTL_CONSTASCII_USTRINGPARAM( "PresenterScreenListener object has already been disposed")), const_cast(static_cast(this))); } } } // end of anonymous namespace //===== PresenterScreen ======================================================= PresenterScreen::PresenterScreen ( const Reference& rxContext, const css::uno::Reference& rxModel) : PresenterScreenInterfaceBase(m_aMutex), mxModel(rxModel), mxController(), mxConfigurationControllerWeak(), mxContextWeak(rxContext), mxSlideShowControllerWeak(), mpPresenterController(), mxSlideShowViewId(), mxSavedConfiguration(), mpPaneContainer(), mnComponentIndex(0), mxPaneFactory(), mxViewFactory(), maViewDescriptors() { } PresenterScreen::~PresenterScreen (void) { } void SAL_CALL PresenterScreen::disposing (void) { Reference xCC (mxConfigurationControllerWeak); if (xCC.is() && mxSavedConfiguration.is()) { xCC->restoreConfiguration(mxSavedConfiguration); } mxConfigurationControllerWeak = Reference(NULL); Reference xViewFactoryComponent (mxViewFactory, UNO_QUERY); if (xViewFactoryComponent.is()) xViewFactoryComponent->dispose(); Reference xPaneFactoryComponent (mxPaneFactory, UNO_QUERY); if (xPaneFactoryComponent.is()) xPaneFactoryComponent->dispose(); mxModel = NULL; } //----- XEventListener -------------------------------------------------------- void SAL_CALL PresenterScreen::disposing (const lang::EventObject& /*rEvent*/) throw (RuntimeException) { mxSlideShowControllerWeak = WeakReference(); RequestShutdownPresenterScreen(); } //----------------------------------------------------------------------------- void PresenterScreen::InitializePresenterScreen (void) { try { Reference xContext (mxContextWeak); mpPaneContainer = new PresenterPaneContainer(Reference(xContext)); Reference xPS ( mxModel, UNO_QUERY_THROW); Reference xPresentation(xPS->getPresentation(), UNO_QUERY_THROW); Reference xSlideShowController( xPresentation->getController() ); mxSlideShowControllerWeak = xSlideShowController; if( !xSlideShowController.is() || !xSlideShowController->isFullScreen() ) return; // find first controller that is not the current controller (the one with the slideshow mxController = mxModel->getCurrentController(); Reference< container::XEnumeration > xEnum( mxModel->getControllers() ); if( xEnum.is() ) { while( xEnum->hasMoreElements() ) { Reference< frame::XController > xC( xEnum->nextElement(), UNO_QUERY ); if( xC.is() && (xC != mxController) ) { mxController = xC; break; } } } // Get the XController from the first argument. Reference xCM(mxController, UNO_QUERY_THROW); Reference xCC( xCM->getConfigurationController()); mxConfigurationControllerWeak = xCC; Reference xMainPaneId( GetMainPaneId(xPresentation)); // An empty reference means that the presenter screen can // not or must not be displayed. if ( ! xMainPaneId.is()) return; if (xCC.is() && xContext.is()) { // Store the current configuration so that we can restore it when // the presenter view is deactivated. mxSavedConfiguration = xCC->getRequestedConfiguration(); xCC->lock(); try { // At the moment the presenter controller is displayed in its // own full screen window that is controlled by the same // configuration controller as the Impress document from // which the presentation was started. Therefore the main // pane is actived additionally to the already existing // panes and does not replace them. xCC->requestResourceActivation( xMainPaneId, ResourceActivationMode_ADD); SetupConfiguration(xContext, xMainPaneId); mpPresenterController = new PresenterController( xContext, mxController, xSlideShowController, mpPaneContainer, xMainPaneId); // Create pane and view factories and integrate them into the // drawing framework. SetupPaneFactory(xContext); SetupViewFactory(xContext); mpPresenterController->GetWindowManager()->RestoreViewMode(); } catch (RuntimeException&) { xCC->restoreConfiguration(mxSavedConfiguration); } xCC->unlock(); } } catch (Exception&) { } } sal_Int32 PresenterScreen::GetScreenNumber ( const Reference& rxPresentation) const { // Determine the screen on which the full screen presentation is being // displayed. sal_Int32 nScreenNumber (0); sal_Int32 nScreenCount (1); try { Reference xProperties (rxPresentation, UNO_QUERY); if ( ! xProperties.is()) return -1; sal_Int32 nDisplayNumber (-1); if ( ! (xProperties->getPropertyValue(A2S("Display")) >>= nDisplayNumber)) return -1; Reference xContext (mxContextWeak); if ( ! xContext.is()) return -1; Reference xFactory ( xContext->getServiceManager(), UNO_QUERY); if ( ! xFactory.is()) return -1; Reference xDisplayProperties ( xFactory->createInstanceWithContext(A2S("com.sun.star.awt.DisplayAccess"),xContext), UNO_QUERY); if ( ! xDisplayProperties.is()) return -1; if (nDisplayNumber > 0) { nScreenNumber = nDisplayNumber - 1; } else if (nDisplayNumber == 0) { // A display number value of 0 indicates the primary screen. // Instantiate the DisplayAccess service to find out which // screen number that is. if (nDisplayNumber <= 0 && xDisplayProperties.is()) xDisplayProperties->getPropertyValue(A2S("DefaultDisplay")) >>= nScreenNumber; } // We still have to determine the number of screens to decide // whether the presenter screen may be shown at all. Reference xIndexAccess (xDisplayProperties, UNO_QUERY); if ( ! xIndexAccess.is()) return -1; nScreenCount = xIndexAccess->getCount(); if (nScreenCount < 2 || nDisplayNumber > nScreenCount) { // There is either only one screen or the full screen // presentation spans all available screens. The presenter // screen is shown only when a special flag in the configuration // is set. PresenterConfigurationAccess aConfiguration ( xContext, OUString(RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.extension.PresenterScreen/")), PresenterConfigurationAccess::READ_ONLY); bool bStartAlways (false); if (aConfiguration.GetConfigurationNode( OUString(RTL_CONSTASCII_USTRINGPARAM("Presenter/StartAlways"))) >>= bStartAlways) { if (bStartAlways) return nScreenNumber; } return -1; } } catch (beans::UnknownPropertyException&) { OSL_ASSERT(false); // For some reason we can not access the screen number. Use // the default instead. } return nScreenNumber; } Reference PresenterScreen::GetMainPaneId ( const Reference& rxPresentation) const { // A negative value means that the presentation spans all available // displays. That leaves no room for the presenter. const sal_Int32 nScreenNumber(GetScreenNumber(rxPresentation)); if (nScreenNumber < 0) return NULL; // Setup the resource id of the full screen background pane so that // it is displayed on another screen than the presentation. sal_Int32 nPresenterScreenNumber (1); switch (nScreenNumber) { case 0: nPresenterScreenNumber = 1; break; case 1: nPresenterScreenNumber = 0; break; default: // When the full screen presentation is displayed on a screen // other than 0 or 1 then place the presenter on the first // available screen. nPresenterScreenNumber = 0; break; } return ResourceId::create( Reference(mxContextWeak), PresenterHelper::msFullScreenPaneURL +A2S("?FullScreen=true&ScreenNumber=") + OUString::valueOf(nPresenterScreenNumber)); } void PresenterScreen::RequestShutdownPresenterScreen (void) { // Restore the configuration that was active before the presenter screen // has been activated. Now, that the presenter screen is displayed in // its own top level window this probably not necessary, but one never knows. Reference xCC (mxConfigurationControllerWeak); if (xCC.is() && mxSavedConfiguration.is()) { xCC->restoreConfiguration(mxSavedConfiguration); mxSavedConfiguration = NULL; } if (xCC.is()) { // The actual restoration of the configuration takes place // asynchronously. The view and pane factories can only by disposed // after that. Therefore, set up a listener and wait for the // restoration. rtl::Reference pSelf (this); PresenterFrameworkObserver::RunOnUpdateEnd( xCC, ::boost::bind(&PresenterScreen::ShutdownPresenterScreen, pSelf)); xCC->update(); } } void PresenterScreen::ShutdownPresenterScreen (void) { Reference xViewFactoryComponent (mxViewFactory, UNO_QUERY); if (xViewFactoryComponent.is()) xViewFactoryComponent->dispose(); mxViewFactory = NULL; Reference xPaneFactoryComponent (mxPaneFactory, UNO_QUERY); if (xPaneFactoryComponent.is()) xPaneFactoryComponent->dispose(); mxPaneFactory = NULL; if (mpPresenterController.get() != NULL) { mpPresenterController->dispose(); mpPresenterController = rtl::Reference(); } mpPaneContainer = new PresenterPaneContainer(Reference(mxContextWeak)); } void PresenterScreen::SetupPaneFactory (const Reference& rxContext) { try { if ( ! mxPaneFactory.is()) mxPaneFactory = PresenterPaneFactory::Create( rxContext, mxController, mpPresenterController); } catch (RuntimeException&) { OSL_ASSERT(false); } } void PresenterScreen::SetupViewFactory (const Reference& rxContext) { try { if ( ! mxViewFactory.is()) mxViewFactory = PresenterViewFactory::Create( rxContext, mxController, mpPresenterController); } catch (RuntimeException&) { OSL_ASSERT(false); } } void PresenterScreen::SetupConfiguration ( const Reference& rxContext, const Reference& rxAnchorId) { try { PresenterConfigurationAccess aConfiguration ( rxContext, OUString(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.extension.PresenterScreen")), PresenterConfigurationAccess::READ_ONLY); maViewDescriptors.clear(); ProcessViewDescriptions(aConfiguration); OUString sLayoutName (RTL_CONSTASCII_USTRINGPARAM("DefaultLayout")); aConfiguration.GetConfigurationNode( OUString(RTL_CONSTASCII_USTRINGPARAM("Presenter/CurrentLayout"))) >>= sLayoutName; ProcessLayout(aConfiguration, sLayoutName, rxContext, rxAnchorId); } catch (RuntimeException&) { } } void PresenterScreen::ProcessLayout ( PresenterConfigurationAccess& rConfiguration, const OUString& rsLayoutName, const Reference& rxContext, const Reference& rxAnchorId) { try { Reference xLayoutNode ( rConfiguration.GetConfigurationNode( OUString(RTL_CONSTASCII_USTRINGPARAM("Presenter/Layouts/"))+rsLayoutName), UNO_QUERY_THROW); // Read the parent layout first, if one is referenced. OUString sParentLayout; rConfiguration.GetConfigurationNode( xLayoutNode, OUString(RTL_CONSTASCII_USTRINGPARAM("ParentLayout"))) >>= sParentLayout; if (sParentLayout.getLength() > 0) { // Prevent infinite recursion. if (rsLayoutName != sParentLayout) ProcessLayout(rConfiguration, sParentLayout, rxContext, rxAnchorId); } // Process the actual layout list. Reference xList ( rConfiguration.GetConfigurationNode( xLayoutNode, OUString(RTL_CONSTASCII_USTRINGPARAM("Layout"))), UNO_QUERY_THROW); ::std::vector aProperties (6); aProperties[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("PaneURL")); aProperties[1] = OUString(RTL_CONSTASCII_USTRINGPARAM("ViewURL")); aProperties[2] = OUString(RTL_CONSTASCII_USTRINGPARAM("RelativeX")); aProperties[3] = OUString(RTL_CONSTASCII_USTRINGPARAM("RelativeY")); aProperties[4] = OUString(RTL_CONSTASCII_USTRINGPARAM("RelativeWidth")); aProperties[5] = OUString(RTL_CONSTASCII_USTRINGPARAM("RelativeHeight")); mnComponentIndex = 1; PresenterConfigurationAccess::ForAll( xList, aProperties, ::boost::bind(&PresenterScreen::ProcessComponent, this, _1, _2, rxContext, rxAnchorId)); } catch (RuntimeException&) { } } void PresenterScreen::ProcessViewDescriptions ( PresenterConfigurationAccess& rConfiguration) { try { Reference xViewDescriptionsNode ( rConfiguration.GetConfigurationNode(A2S("Presenter/Views")), UNO_QUERY_THROW); ::std::vector aProperties (4); aProperties[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("ViewURL")); aProperties[1] = OUString(RTL_CONSTASCII_USTRINGPARAM("Title")); aProperties[2] = OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleTitle")); aProperties[3] = OUString(RTL_CONSTASCII_USTRINGPARAM("IsOpaque")); mnComponentIndex = 1; PresenterConfigurationAccess::ForAll( xViewDescriptionsNode, aProperties, ::boost::bind(&PresenterScreen::ProcessViewDescription, this, _1, _2)); } catch (RuntimeException&) { OSL_ASSERT(false); } } void PresenterScreen::ProcessComponent ( const OUString& rsKey, const ::std::vector& rValues, const Reference& rxContext, const Reference& rxAnchorId) { (void)rsKey; if (rValues.size() != 6) return; try { OUString sPaneURL; OUString sViewURL; double nX = 0; double nY = 0; double nWidth = 0; double nHeight = 0; rValues[0] >>= sPaneURL; rValues[1] >>= sViewURL; rValues[2] >>= nX; rValues[3] >>= nY; rValues[4] >>= nWidth; rValues[5] >>= nHeight; if (nX>=0 && nY>=0 && nWidth>0 && nHeight>0) { SetupView( rxContext, rxAnchorId, sPaneURL, sViewURL, PresenterPaneContainer::ViewInitializationFunction(), nX, nY, nX+nWidth, nY+nHeight); } } catch (Exception& e) { (void)e; OSL_ASSERT(false); } } void PresenterScreen::ProcessViewDescription ( const OUString& rsKey, const ::std::vector& rValues) { (void)rsKey; if (rValues.size() != 4) return; try { ViewDescriptor aViewDescriptor; OUString sViewURL; rValues[0] >>= sViewURL; rValues[1] >>= aViewDescriptor.msTitle; rValues[2] >>= aViewDescriptor.msAccessibleTitle; rValues[3] >>= aViewDescriptor.mbIsOpaque; if (aViewDescriptor.msAccessibleTitle.getLength()==0) aViewDescriptor.msAccessibleTitle = aViewDescriptor.msTitle; maViewDescriptors[sViewURL] = aViewDescriptor; } catch (Exception&) { OSL_ASSERT(false); } } void PresenterScreen::SetupView( const Reference& rxContext, const Reference& rxAnchorId, const OUString& rsPaneURL, const OUString& rsViewURL, const PresenterPaneContainer::ViewInitializationFunction& rViewInitialization, const double nLeft, const double nTop, const double nRight, const double nBottom) { Reference xCC (mxConfigurationControllerWeak); if (xCC.is()) { Reference xPaneId (ResourceId::createWithAnchor(rxContext,rsPaneURL,rxAnchorId)); // Look up the view descriptor. ViewDescriptor aViewDescriptor; ViewDescriptorContainer::const_iterator iDescriptor (maViewDescriptors.find(rsViewURL)); if (iDescriptor != maViewDescriptors.end()) aViewDescriptor = iDescriptor->second; // Prepare the pane. OSL_ASSERT(mpPaneContainer.get() != NULL); mpPaneContainer->PreparePane( xPaneId, rsViewURL, aViewDescriptor.msTitle, aViewDescriptor.msAccessibleTitle, aViewDescriptor.mbIsOpaque, rViewInitialization, nLeft, nTop, nRight, nBottom); } } } } // end of namespace ::sdext::presenter /* vim:set shiftwidth=4 softtabstop=4 expandtab: */