1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "PresenterScreen.hxx"
21 #include "PresenterConfigurationAccess.hxx"
22 #include "PresenterController.hxx"
23 #include "PresenterFrameworkObserver.hxx"
24 #include "PresenterHelper.hxx"
25 #include "PresenterPaneContainer.hxx"
26 #include "PresenterPaneFactory.hxx"
27 #include "PresenterViewFactory.hxx"
28 #include "PresenterWindowManager.hxx"
29 #include <com/sun/star/frame/XController.hpp>
30 #include <com/sun/star/lang/XServiceInfo.hpp>
31 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
32 #include <com/sun/star/drawing/framework/ResourceId.hpp>
33 #include <com/sun/star/drawing/framework/ResourceActivationMode.hpp>
34 #include <com/sun/star/presentation/XPresentation2.hpp>
35 #include <com/sun/star/presentation/XPresentationSupplier.hpp>
36 #include <com/sun/star/document/XEventBroadcaster.hpp>
37 #include <cppuhelper/compbase.hxx>
38 #include <cppuhelper/supportsservice.hxx>
39 
40 #include <vcl/svapp.hxx>
41 #include <sal/log.hxx>
42 
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45 using namespace ::com::sun::star::lang;
46 using namespace ::com::sun::star::presentation;
47 using namespace ::com::sun::star::drawing::framework;
48 
49 namespace sdext::presenter {
50 
51 namespace {
52     typedef ::cppu::WeakComponentImplHelper <
53         css::document::XEventListener
54         > PresenterScreenListenerInterfaceBase;
55 
56     /** One instance of a PresenterScreenListener is registered per Impress
57         document and waits for the full screen slide show to start and to
58         end.
59     */
60     class PresenterScreenListener
61         : private ::cppu::BaseMutex,
62           public PresenterScreenListenerInterfaceBase
63     {
64     public:
65         PresenterScreenListener (
66             const css::uno::Reference<css::uno::XComponentContext>& rxContext,
67             const css::uno::Reference<css::frame::XModel2>& rxModel);
68         PresenterScreenListener(const PresenterScreenListener&) = delete;
69         PresenterScreenListener& operator=(const PresenterScreenListener&) = delete;
70 
71         void Initialize();
72         virtual void SAL_CALL disposing() override;
73 
74         // document::XEventListener
75 
76         virtual void SAL_CALL notifyEvent( const css::document::EventObject& Event ) override;
77 
78         // XEventListener
79 
80         virtual void SAL_CALL disposing ( const css::lang::EventObject& rEvent) override;
81 
82     private:
83         css::uno::Reference<css::frame::XModel2 > mxModel;
84         css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
85         rtl::Reference<PresenterScreen> mpPresenterScreen;
86     };
87 }
88 
89 //----- XServiceInfo ---------------------------------------------------------------
90 
getSupportedServiceNames()91 Sequence< OUString > SAL_CALL PresenterScreenJob::getSupportedServiceNames()
92 {
93     return {  };
94 }
95 
getImplementationName()96 OUString SAL_CALL PresenterScreenJob::getImplementationName()
97 {
98     return "org.libreoffice.comp.PresenterScreenJob";
99 }
100 
supportsService(const OUString & aServiceName)101 sal_Bool SAL_CALL PresenterScreenJob::supportsService(const OUString& aServiceName)
102 {
103     return cppu::supportsService(this, aServiceName);
104 }
105 
106 
107 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
sdext_PresenterScreenJob_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)108 sdext_PresenterScreenJob_get_implementation(
109     css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
110 {
111     return cppu::acquire(new PresenterScreenJob(context));
112 }
113 
114 
115 //===== PresenterScreenJob ====================================================
116 
PresenterScreenJob(const Reference<XComponentContext> & rxContext)117 PresenterScreenJob::PresenterScreenJob (const Reference<XComponentContext>& rxContext)
118     : PresenterScreenJobInterfaceBase(m_aMutex),
119       mxComponentContext(rxContext)
120 {
121 }
122 
~PresenterScreenJob()123 PresenterScreenJob::~PresenterScreenJob()
124 {
125 }
126 
disposing()127 void SAL_CALL PresenterScreenJob::disposing()
128 {
129     mxComponentContext = nullptr;
130 }
131 
132 //----- XJob -----------------------------------------------------------
133 
execute(const Sequence<beans::NamedValue> & Arguments)134 Any SAL_CALL PresenterScreenJob::execute(
135     const Sequence< beans::NamedValue >& Arguments )
136 {
137     Sequence< beans::NamedValue > lEnv;
138     auto pArg = std::find_if(Arguments.begin(), Arguments.end(),
139         [](const beans::NamedValue& rArg) { return rArg.Name == "Environment"; });
140     if (pArg != Arguments.end())
141         pArg->Value >>= lEnv;
142 
143     Reference<frame::XModel2> xModel;
144     auto pProp = std::find_if(lEnv.begin(), lEnv.end(),
145         [](const beans::NamedValue& rProp) { return rProp.Name == "Model"; });
146     if (pProp != lEnv.end())
147         pProp->Value >>= xModel;
148 
149     Reference< XServiceInfo > xInfo( xModel, UNO_QUERY );
150     if( xInfo.is() && xInfo->supportsService("com.sun.star.presentation.PresentationDocument") )
151     {
152         // Create a new listener that waits for the full screen presentation
153         // to start and to end.  It takes care of its own lifetime.
154         ::rtl::Reference<PresenterScreenListener> pListener (
155             new PresenterScreenListener(mxComponentContext, xModel));
156         pListener->Initialize();
157     }
158 
159     return Any();
160 }
161 
162 //===== PresenterScreenListener ===============================================
163 
164 namespace {
165 
PresenterScreenListener(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::frame::XModel2> & rxModel)166 PresenterScreenListener::PresenterScreenListener (
167     const css::uno::Reference<css::uno::XComponentContext>& rxContext,
168     const css::uno::Reference<css::frame::XModel2>& rxModel)
169     : PresenterScreenListenerInterfaceBase(m_aMutex),
170       mxModel(rxModel),
171       mxComponentContext(rxContext),
172       mpPresenterScreen()
173 {
174 }
175 
Initialize()176 void PresenterScreenListener::Initialize()
177 {
178     Reference< document::XEventListener > xDocListener(
179         static_cast< document::XEventListener* >(this), UNO_QUERY);
180     Reference< document::XEventBroadcaster > xDocBroadcaster( mxModel, UNO_QUERY );
181     if( xDocBroadcaster.is() )
182         xDocBroadcaster->addEventListener(xDocListener);
183 }
184 
disposing()185 void SAL_CALL PresenterScreenListener::disposing()
186 {
187     Reference< document::XEventBroadcaster > xDocBroadcaster( mxModel, UNO_QUERY );
188     if( xDocBroadcaster.is() )
189         xDocBroadcaster->removeEventListener(
190             Reference<document::XEventListener>(
191                 static_cast<document::XEventListener*>(this), UNO_QUERY));
192 
193     if (mpPresenterScreen.is())
194     {
195         mpPresenterScreen->RequestShutdownPresenterScreen();
196         mpPresenterScreen = nullptr;
197     }
198 }
199 
200 // document::XEventListener
201 
notifyEvent(const css::document::EventObject & Event)202 void SAL_CALL PresenterScreenListener::notifyEvent( const css::document::EventObject& Event )
203 {
204     if (rBHelper.bDisposed || rBHelper.bInDispose)
205     {
206         throw lang::DisposedException (
207             "PresenterScreenListener object has already been disposed",
208             static_cast<uno::XWeak*>(this));
209     }
210 
211     if ( Event.EventName == "OnStartPresentation" )
212     {
213         mpPresenterScreen = new PresenterScreen(mxComponentContext, mxModel);
214         if(PresenterScreen::isPresenterScreenEnabled(mxComponentContext))
215             mpPresenterScreen->InitializePresenterScreen();
216     }
217     else if ( Event.EventName == "OnEndPresentation" )
218     {
219         if (mpPresenterScreen.is())
220         {
221             mpPresenterScreen->RequestShutdownPresenterScreen();
222             mpPresenterScreen = nullptr;
223         }
224     }
225 }
226 
227 // XEventListener
228 
disposing(const css::lang::EventObject &)229 void SAL_CALL PresenterScreenListener::disposing (const css::lang::EventObject&)
230 {
231     if (mpPresenterScreen.is())
232     {
233         mpPresenterScreen->RequestShutdownPresenterScreen();
234         mpPresenterScreen = nullptr;
235     }
236 }
237 
238 } // end of anonymous namespace
239 
240 //===== PresenterScreen =======================================================
241 
PresenterScreen(const Reference<XComponentContext> & rxContext,const css::uno::Reference<css::frame::XModel2> & rxModel)242 PresenterScreen::PresenterScreen (
243     const Reference<XComponentContext>& rxContext,
244     const css::uno::Reference<css::frame::XModel2>& rxModel)
245     : PresenterScreenInterfaceBase(m_aMutex),
246       mxModel(rxModel),
247       mxController(),
248       mxConfigurationControllerWeak(),
249       mxContextWeak(rxContext),
250       mpPresenterController(),
251       mxSavedConfiguration(),
252       mpPaneContainer(),
253       mxPaneFactory(),
254       mxViewFactory(),
255       maViewDescriptors()
256 {
257 }
258 
~PresenterScreen()259 PresenterScreen::~PresenterScreen()
260 {
261 }
262 
isPresenterScreenEnabled(const css::uno::Reference<css::uno::XComponentContext> & rxContext)263 bool PresenterScreen::isPresenterScreenEnabled(const css::uno::Reference<css::uno::XComponentContext>& rxContext)
264 {
265         bool dEnablePresenterScreen=true;
266         PresenterConfigurationAccess aConfiguration (
267             rxContext,
268             "/org.openoffice.Office.Impress/",
269             PresenterConfigurationAccess::READ_ONLY);
270         aConfiguration.GetConfigurationNode("Misc/Start/EnablePresenterScreen")
271             >>= dEnablePresenterScreen;
272         return dEnablePresenterScreen;
273 }
disposing()274 void SAL_CALL PresenterScreen::disposing()
275 {
276     Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
277     if (xCC.is() && mxSavedConfiguration.is())
278     {
279         xCC->restoreConfiguration(mxSavedConfiguration);
280     }
281     mxConfigurationControllerWeak = Reference<XConfigurationController>(nullptr);
282 
283     Reference<lang::XComponent> xViewFactoryComponent (mxViewFactory, UNO_QUERY);
284     if (xViewFactoryComponent.is())
285        xViewFactoryComponent->dispose();
286     Reference<lang::XComponent> xPaneFactoryComponent (mxPaneFactory, UNO_QUERY);
287     if (xPaneFactoryComponent.is())
288         xPaneFactoryComponent->dispose();
289 
290     mxModel = nullptr;
291 }
292 
293 //----- XEventListener --------------------------------------------------------
294 
disposing(const lang::EventObject &)295 void SAL_CALL PresenterScreen::disposing (const lang::EventObject& /*rEvent*/)
296 {
297     RequestShutdownPresenterScreen();
298 }
299 
300 
InitializePresenterScreen()301 void PresenterScreen::InitializePresenterScreen()
302 {
303     try
304     {
305         Reference<XComponentContext> xContext (mxContextWeak);
306         mpPaneContainer = new PresenterPaneContainer(xContext);
307 
308         Reference<XPresentationSupplier> xPS ( mxModel, UNO_QUERY_THROW);
309         Reference<XPresentation2> xPresentation(xPS->getPresentation(), UNO_QUERY_THROW);
310         Reference<presentation::XSlideShowController> xSlideShowController( xPresentation->getController() );
311 
312         if( !xSlideShowController.is() || !xSlideShowController->isFullScreen() )
313             return;
314 
315         // find first controller that is not the current controller (the one with the slideshow
316         mxController = mxModel->getCurrentController();
317         Reference< container::XEnumeration > xEnum( mxModel->getControllers() );
318         if( xEnum.is() )
319         {
320             while( xEnum->hasMoreElements() )
321             {
322                 Reference< frame::XController > xC( xEnum->nextElement(), UNO_QUERY );
323                 if( xC.is() && (xC != mxController) )
324                 {
325                     mxController = xC;
326                     break;
327                 }
328             }
329         }
330         // Get the XController from the first argument.
331         Reference<XControllerManager> xCM(mxController, UNO_QUERY_THROW);
332 
333         Reference<XConfigurationController> xCC( xCM->getConfigurationController());
334         mxConfigurationControllerWeak = xCC;
335 
336         Reference<drawing::framework::XResourceId> xMainPaneId(
337             GetMainPaneId(xPresentation));
338         // An empty reference means that the presenter screen can
339         // not or must not be displayed.
340         if ( ! xMainPaneId.is())
341             return;
342 
343         if (xCC.is() && xContext.is())
344         {
345             // Store the current configuration so that we can restore it when
346             // the presenter view is deactivated.
347             mxSavedConfiguration = xCC->getRequestedConfiguration();
348             xCC->lock();
349 
350             try
351             {
352                 // At the moment the presenter controller is displayed in its
353                 // own full screen window that is controlled by the same
354                 // configuration controller as the Impress document from
355                 // which the presentation was started.  Therefore the main
356                 // pane is activated additionally to the already existing
357                 // panes and does not replace them.
358                 xCC->requestResourceActivation(
359                     xMainPaneId,
360                     ResourceActivationMode_ADD);
361                 SetupConfiguration(xContext, xMainPaneId);
362 
363                 mpPresenterController = new PresenterController(
364                     css::uno::WeakReference<css::lang::XEventListener>(this),
365                     xContext,
366                     mxController,
367                     xSlideShowController,
368                     mpPaneContainer,
369                     xMainPaneId);
370 
371                 // Create pane and view factories and integrate them into the
372                 // drawing framework.
373                 SetupPaneFactory(xContext);
374                 SetupViewFactory(xContext);
375 
376                 mpPresenterController->GetWindowManager()->RestoreViewMode();
377             }
378             catch (const RuntimeException&)
379             {
380                 xCC->restoreConfiguration(mxSavedConfiguration);
381             }
382             xCC->unlock();
383         }
384     }
385     catch (const Exception&)
386     {
387     }
388 }
389 
SwitchMonitors()390 void PresenterScreen::SwitchMonitors()
391 {
392     try {
393         Reference<XPresentationSupplier> xPS ( mxModel, UNO_QUERY_THROW);
394         Reference<XPresentation2> xPresentation(xPS->getPresentation(), UNO_QUERY_THROW);
395 
396         // Get the existing presenter console screen, we want to switch the
397         // presentation to use that instead.
398         sal_Int32 nNewScreen = GetPresenterScreenNumber (xPresentation);
399         if (nNewScreen < 0)
400             return;
401 
402         // Adapt that display number to be the 'default' setting of 0 if it matches
403         sal_Int32 nExternalDisplay = Application::GetDisplayExternalScreen();
404 
405         if (nNewScreen == nExternalDisplay)
406             nNewScreen = 0; // screen zero is best == the primary display
407         else
408             nNewScreen++; // otherwise we store screens offset by one.
409 
410         // Set the new presentation display
411         Reference<beans::XPropertySet> xProperties (xPresentation, UNO_QUERY_THROW);
412         xProperties->setPropertyValue("Display", Any(nNewScreen));
413     } catch (const uno::Exception &) {
414     }
415 }
416 
417 /**
418  * Return the real VCL screen number to show the presenter console
419  * on or -1 to not show anything.
420  */
GetPresenterScreenNumber(const Reference<presentation::XPresentation2> & rxPresentation) const421 sal_Int32 PresenterScreen::GetPresenterScreenNumber (
422     const Reference<presentation::XPresentation2>& rxPresentation) const
423 {
424     sal_Int32 nScreenNumber (0);
425     try
426     {
427         if ( ! rxPresentation.is())
428             return -1;
429 
430         // Determine the screen on which the full screen presentation is being
431         // displayed.
432         sal_Int32 nDisplayNumber (-1);
433         if ( ! (rxPresentation->getPropertyValue("Display") >>= nDisplayNumber))
434             return -1;
435         if (nDisplayNumber == -1)
436         {
437             // The special value -1 indicates that the slide show
438             // spans all available displays.  That leaves no room for
439             // the presenter screen.
440             return -1;
441         }
442 
443         SAL_INFO("sdext.presenter", "Display number is " << nDisplayNumber);
444 
445         if (nDisplayNumber > 0)
446         {
447             nScreenNumber = nDisplayNumber - 1;
448         }
449         else if (nDisplayNumber == 0)
450         {
451             // A display number value of 0 indicates the primary screen.
452             // Find out which screen number that is.
453             nScreenNumber = Application::GetDisplayExternalScreen();
454         }
455 
456         // We still have to determine the number of screens to decide
457         // whether the presenter screen may be shown at all.
458         sal_Int32 nScreenCount = Application::GetScreenCount();
459 
460         if (nScreenCount < 2 || nDisplayNumber > nScreenCount)
461         {
462             // There is either only one screen or the full screen
463             // presentation spans all available screens.  The presenter
464             // screen is shown only when a special flag in the configuration
465             // is set.
466             Reference<XComponentContext> xContext (mxContextWeak);
467             PresenterConfigurationAccess aConfiguration (
468                 xContext,
469                 "/org.openoffice.Office.PresenterScreen/",
470                 PresenterConfigurationAccess::READ_ONLY);
471             bool bStartAlways (false);
472             if (aConfiguration.GetConfigurationNode(
473                 "Presenter/StartAlways") >>= bStartAlways)
474             {
475                 if (bStartAlways)
476                     return GetPresenterScreenFromScreen(nScreenNumber);
477             }
478             return -1;
479         }
480     }
481     catch (const beans::UnknownPropertyException&)
482     {
483         OSL_ASSERT(false);
484         // For some reason we can not access the screen number.  Use
485         // the default instead.
486     }
487     SAL_INFO("sdext.presenter", "Get presenter screen for screen " << nScreenNumber);
488     return GetPresenterScreenFromScreen(nScreenNumber);
489 }
490 
GetPresenterScreenFromScreen(sal_Int32 nPresentationScreen)491 sal_Int32 PresenterScreen::GetPresenterScreenFromScreen( sal_Int32 nPresentationScreen )
492 {
493     // Setup the resource id of the full screen background pane so that
494     // it is displayed on another screen than the presentation.
495     sal_Int32 nPresenterScreenNumber (1);
496     switch (nPresentationScreen)
497     {
498         case 0:
499             nPresenterScreenNumber = 1;
500             break;
501 
502         case 1:
503             nPresenterScreenNumber = 0;
504             break;
505 
506         default:
507             SAL_INFO("sdext.presenter", "Warning unexpected, out of bound screen "
508                      "mapped to 0" << nPresentationScreen);
509             // When the full screen presentation is displayed on a screen
510             // other than 0 or 1 then place the presenter on the first
511             // available screen.
512             nPresenterScreenNumber = 0;
513             break;
514     }
515     return nPresenterScreenNumber;
516 }
517 
GetMainPaneId(const Reference<presentation::XPresentation2> & rxPresentation) const518 Reference<drawing::framework::XResourceId> PresenterScreen::GetMainPaneId (
519     const Reference<presentation::XPresentation2>& rxPresentation) const
520 {
521     // A negative value means that the presentation spans all available
522     // displays.  That leaves no room for the presenter.
523     const sal_Int32 nScreen(GetPresenterScreenNumber(rxPresentation));
524     if (nScreen < 0)
525         return nullptr;
526 
527     return ResourceId::create(
528         Reference<XComponentContext>(mxContextWeak),
529         PresenterHelper::msFullScreenPaneURL
530                 + "?FullScreen=true&ScreenNumber="
531                 + OUString::number(nScreen));
532 }
533 
RequestShutdownPresenterScreen()534 void PresenterScreen::RequestShutdownPresenterScreen()
535 {
536     // Restore the configuration that was active before the presenter screen
537     // has been activated.  Now, that the presenter screen is displayed in
538     // its own top level window this probably not necessary, but one never knows.
539     Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
540     if (xCC.is() && mxSavedConfiguration.is())
541     {
542         xCC->restoreConfiguration(mxSavedConfiguration);
543         mxSavedConfiguration = nullptr;
544     }
545 
546     if (xCC.is())
547     {
548         // The actual restoration of the configuration takes place
549         // asynchronously.  The view and pane factories can only by disposed
550         // after that.  Therefore, set up a listener and wait for the
551         // restoration.
552         rtl::Reference<PresenterScreen> pSelf (this);
553         PresenterFrameworkObserver::RunOnUpdateEnd(
554             xCC,
555             [pSelf](bool){ return pSelf->ShutdownPresenterScreen(); });
556         xCC->update();
557     }
558 }
559 
ShutdownPresenterScreen()560 void PresenterScreen::ShutdownPresenterScreen()
561 {
562     Reference<lang::XComponent> xViewFactoryComponent (mxViewFactory, UNO_QUERY);
563     if (xViewFactoryComponent.is())
564         xViewFactoryComponent->dispose();
565     mxViewFactory = nullptr;
566 
567     Reference<lang::XComponent> xPaneFactoryComponent (mxPaneFactory, UNO_QUERY);
568     if (xPaneFactoryComponent.is())
569         xPaneFactoryComponent->dispose();
570     mxPaneFactory = nullptr;
571 
572     if (mpPresenterController)
573     {
574         mpPresenterController->dispose();
575         mpPresenterController.clear();
576     }
577     mpPaneContainer = new PresenterPaneContainer(Reference<XComponentContext>(mxContextWeak));
578 }
579 
SetupPaneFactory(const Reference<XComponentContext> & rxContext)580 void PresenterScreen::SetupPaneFactory (const Reference<XComponentContext>& rxContext)
581 {
582     try
583     {
584         if ( ! mxPaneFactory.is())
585             mxPaneFactory = PresenterPaneFactory::Create(
586                 rxContext,
587                 mxController,
588                 mpPresenterController);
589     }
590     catch (const RuntimeException&)
591     {
592         OSL_ASSERT(false);
593     }
594 }
595 
SetupViewFactory(const Reference<XComponentContext> & rxContext)596 void PresenterScreen::SetupViewFactory (const Reference<XComponentContext>& rxContext)
597 {
598     try
599     {
600         if ( ! mxViewFactory.is())
601             mxViewFactory = PresenterViewFactory::Create(
602                 rxContext,
603                 mxController,
604                 mpPresenterController);
605     }
606     catch (const RuntimeException&)
607     {
608         OSL_ASSERT(false);
609     }
610 }
611 
SetupConfiguration(const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxAnchorId)612 void PresenterScreen::SetupConfiguration (
613     const Reference<XComponentContext>& rxContext,
614     const Reference<XResourceId>& rxAnchorId)
615 {
616     try
617     {
618         PresenterConfigurationAccess aConfiguration (
619             rxContext,
620             "org.openoffice.Office.PresenterScreen",
621             PresenterConfigurationAccess::READ_ONLY);
622         maViewDescriptors.clear();
623         ProcessViewDescriptions(aConfiguration);
624         OUString sLayoutName ("DefaultLayout");
625         aConfiguration.GetConfigurationNode(
626             "Presenter/CurrentLayout") >>= sLayoutName;
627         ProcessLayout(aConfiguration, sLayoutName, rxContext, rxAnchorId);
628     }
629     catch (const RuntimeException&)
630     {
631     }
632 }
633 
ProcessLayout(PresenterConfigurationAccess & rConfiguration,std::u16string_view rsLayoutName,const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxAnchorId)634 void PresenterScreen::ProcessLayout (
635     PresenterConfigurationAccess& rConfiguration,
636     std::u16string_view rsLayoutName,
637     const Reference<XComponentContext>& rxContext,
638     const Reference<XResourceId>& rxAnchorId)
639 {
640     try
641     {
642         Reference<container::XHierarchicalNameAccess> xLayoutNode (
643             rConfiguration.GetConfigurationNode(
644                 OUString::Concat("Presenter/Layouts/")+rsLayoutName),
645             UNO_QUERY_THROW);
646 
647         // Read the parent layout first, if one is referenced.
648         OUString sParentLayout;
649         PresenterConfigurationAccess::GetConfigurationNode(
650             xLayoutNode,
651             "ParentLayout") >>= sParentLayout;
652         if (!sParentLayout.isEmpty())
653         {
654             // Prevent infinite recursion.
655             if (rsLayoutName != sParentLayout)
656                 ProcessLayout(rConfiguration, sParentLayout, rxContext, rxAnchorId);
657         }
658 
659         // Process the actual layout list.
660         Reference<container::XNameAccess> xList (
661             PresenterConfigurationAccess::GetConfigurationNode(
662                 xLayoutNode,
663                 "Layout"),
664             UNO_QUERY_THROW);
665 
666         ::std::vector<OUString> aProperties
667         {
668             "PaneURL",
669             "ViewURL",
670             "RelativeX",
671             "RelativeY",
672             "RelativeWidth",
673             "RelativeHeight"
674         };
675         PresenterConfigurationAccess::ForAll(
676             xList,
677             aProperties,
678             [this, rxContext, rxAnchorId](std::vector<uno::Any> const& rArgs)
679             {
680                 this->ProcessComponent(rArgs, rxContext, rxAnchorId);
681             });
682     }
683     catch (const RuntimeException&)
684     {
685     }
686 }
687 
ProcessViewDescriptions(PresenterConfigurationAccess & rConfiguration)688 void PresenterScreen::ProcessViewDescriptions (
689     PresenterConfigurationAccess& rConfiguration)
690 {
691     try
692     {
693         Reference<container::XNameAccess> xViewDescriptionsNode (
694             rConfiguration.GetConfigurationNode("Presenter/Views"),
695             UNO_QUERY_THROW);
696 
697         ::std::vector<OUString> aProperties
698         {
699             "ViewURL",
700             "Title",
701             "AccessibleTitle",
702             "IsOpaque"
703         };
704         PresenterConfigurationAccess::ForAll(
705             xViewDescriptionsNode,
706             aProperties,
707             [this](std::vector<uno::Any> const& rArgs)
708             {
709                 return this->ProcessViewDescription(rArgs);
710             });
711     }
712     catch (const RuntimeException&)
713     {
714         OSL_ASSERT(false);
715     }
716 }
717 
ProcessComponent(const::std::vector<Any> & rValues,const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxAnchorId)718 void PresenterScreen::ProcessComponent (
719     const ::std::vector<Any>& rValues,
720     const Reference<XComponentContext>& rxContext,
721     const Reference<XResourceId>& rxAnchorId)
722 {
723     if (rValues.size() != 6)
724         return;
725 
726     try
727     {
728         OUString sPaneURL;
729         OUString sViewURL;
730         double nX = 0;
731         double nY = 0;
732         double nWidth = 0;
733         double nHeight = 0;
734         rValues[0] >>= sPaneURL;
735         rValues[1] >>= sViewURL;
736         rValues[2] >>= nX;
737         rValues[3] >>= nY;
738         rValues[4] >>= nWidth;
739         rValues[5] >>= nHeight;
740 
741         if (nX>=0 && nY>=0 && nWidth>0 && nHeight>0)
742         {
743             SetupView(
744                 rxContext,
745                 rxAnchorId,
746                 sPaneURL,
747                 sViewURL,
748                 PresenterPaneContainer::ViewInitializationFunction());
749         }
750        }
751     catch (const Exception&)
752     {
753         OSL_ASSERT(false);
754     }
755 }
756 
ProcessViewDescription(const::std::vector<Any> & rValues)757 void PresenterScreen::ProcessViewDescription (
758     const ::std::vector<Any>& rValues)
759 {
760     if (rValues.size() != 4)
761         return;
762 
763     try
764     {
765         ViewDescriptor aViewDescriptor;
766         OUString sViewURL;
767         rValues[0] >>= sViewURL;
768         rValues[1] >>= aViewDescriptor.msTitle;
769         rValues[2] >>= aViewDescriptor.msAccessibleTitle;
770         rValues[3] >>= aViewDescriptor.mbIsOpaque;
771         if (aViewDescriptor.msAccessibleTitle.isEmpty())
772             aViewDescriptor.msAccessibleTitle = aViewDescriptor.msTitle;
773         maViewDescriptors[sViewURL] = aViewDescriptor;
774     }
775     catch (const Exception&)
776     {
777         OSL_ASSERT(false);
778     }
779 }
780 
SetupView(const Reference<XComponentContext> & rxContext,const Reference<XResourceId> & rxAnchorId,const OUString & rsPaneURL,const OUString & rsViewURL,const PresenterPaneContainer::ViewInitializationFunction & rViewInitialization)781 void PresenterScreen::SetupView(
782     const Reference<XComponentContext>& rxContext,
783     const Reference<XResourceId>& rxAnchorId,
784     const OUString& rsPaneURL,
785     const OUString& rsViewURL,
786     const PresenterPaneContainer::ViewInitializationFunction& rViewInitialization)
787 {
788     Reference<XConfigurationController> xCC (mxConfigurationControllerWeak);
789     if (!xCC.is())
790         return;
791 
792     Reference<XResourceId> xPaneId (ResourceId::createWithAnchor(rxContext,rsPaneURL,rxAnchorId));
793     // Look up the view descriptor.
794     ViewDescriptor aViewDescriptor;
795     ViewDescriptorContainer::const_iterator iDescriptor (maViewDescriptors.find(rsViewURL));
796     if (iDescriptor != maViewDescriptors.end())
797         aViewDescriptor = iDescriptor->second;
798 
799     // Prepare the pane.
800     OSL_ASSERT(mpPaneContainer);
801     mpPaneContainer->PreparePane(
802         xPaneId,
803         rsViewURL,
804         aViewDescriptor.msTitle,
805         aViewDescriptor.msAccessibleTitle,
806         aViewDescriptor.mbIsOpaque,
807         rViewInitialization);
808 }
809 
810 } // end of namespace ::sdext::presenter
811 
812 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
813