LibreOffice Module sdext (master)  1
PresenterController.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 
22 #include <string_view>
23 
24 #include "PresenterController.hxx"
25 
29 #include "PresenterScreen.hxx"
31 #include "PresenterPaneBase.hxx"
34 #include "PresenterTheme.hxx"
35 #include "PresenterViewFactory.hxx"
37 
38 #include <com/sun/star/awt/Key.hpp>
39 #include <com/sun/star/awt/KeyModifier.hpp>
40 #include <com/sun/star/awt/MouseButton.hpp>
41 #include <com/sun/star/container/XNamed.hpp>
42 #include <com/sun/star/drawing/XDrawView.hpp>
43 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
44 #include <com/sun/star/drawing/framework/ResourceActivationMode.hpp>
45 #include <com/sun/star/drawing/framework/ResourceId.hpp>
46 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
47 #include <com/sun/star/frame/FrameSearchFlag.hpp>
48 #include <com/sun/star/frame/XDispatchProvider.hpp>
49 #include <com/sun/star/presentation/AnimationEffect.hpp>
50 #include <com/sun/star/presentation/XPresentation.hpp>
51 #include <com/sun/star/presentation/XPresentationSupplier.hpp>
52 #include <com/sun/star/rendering/TextDirection.hpp>
53 #include <com/sun/star/util/URLTransformer.hpp>
54 
55 #include <rtl/ustrbuf.hxx>
56 
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::presentation;
60 using namespace ::com::sun::star::drawing::framework;
61 
62 namespace {
63  const sal_Int32 ResourceActivationEventType = 0;
64  const sal_Int32 ResourceDeactivationEventType = 1;
65  const sal_Int32 ConfigurationUpdateEndEventType = 2;
66 }
67 
68 namespace sdext::presenter {
69 
71 {
72 }
73 
75 
77  const css::uno::Reference<css::frame::XFrame>& rxFrame)
78 {
79  InstanceContainer::const_iterator iInstance (maInstances.find(rxFrame));
80  if (iInstance != maInstances.end())
81  return iInstance->second;
82  else
83  return ::rtl::Reference<PresenterController>();
84 }
85 
87  const css::uno::WeakReference<css::lang::XEventListener> &rxScreen,
88  const Reference<XComponentContext>& rxContext,
89  const Reference<frame::XController>& rxController,
90  const Reference<presentation::XSlideShowController>& rxSlideShowController,
91  const rtl::Reference<PresenterPaneContainer>& rpPaneContainer,
92  const Reference<XResourceId>& rxMainPaneId)
94  mxScreen(rxScreen),
95  mxComponentContext(rxContext),
96  mxController(rxController),
97  mxSlideShowController(rxSlideShowController),
98  mxMainPaneId(rxMainPaneId),
99  mpPaneContainer(rpPaneContainer),
100  mnCurrentSlideIndex(-1),
101  mpWindowManager(new PresenterWindowManager(rxContext,mpPaneContainer,this)),
102  mpCanvasHelper(std::make_shared<PresenterCanvasHelper>()),
103  mnPendingSlideNumber(-1),
104  mbIsAccessibilityActive(false)
105 {
106  OSL_ASSERT(mxController.is());
107 
108  if ( ! mxSlideShowController.is())
109  throw lang::IllegalArgumentException(
110  "missing slide show controller",
111  static_cast<XWeak*>(this),
112  2);
113 
114  new PresenterCurrentSlideObserver(this,rxSlideShowController);
115 
116  // Listen for configuration changes.
117  Reference<XControllerManager> xCM (mxController, UNO_QUERY_THROW);
118  mxConfigurationController = xCM->getConfigurationController();
119  if (mxConfigurationController.is())
120  {
121  mxConfigurationController->addConfigurationChangeListener(
122  this,
123  "ResourceActivation",
124  Any(ResourceActivationEventType));
125  mxConfigurationController->addConfigurationChangeListener(
126  this,
127  "ResourceDeactivation",
128  Any(ResourceDeactivationEventType));
129  mxConfigurationController->addConfigurationChangeListener(
130  this,
131  "ConfigurationUpdateEnd",
132  Any(ConfigurationUpdateEndEventType));
133  }
134 
135  // Listen for the frame being activated.
136  Reference<frame::XFrame> xFrame (mxController->getFrame());
137  if (xFrame.is())
138  xFrame->addFrameActionListener(this);
139 
140  // Create the border painter.
142  mpWindowManager->SetPaneBorderPainter(mpPaneBorderPainter);
143 
144  // Create an object that is able to load the bitmaps in a format that is
145  // supported by the canvas.
146  Reference<lang::XMultiComponentFactory> xFactory =
147  rxContext->getServiceManager();
148  if ( ! xFactory.is())
149  return;
150  mxPresenterHelper.set(
151  xFactory->createInstanceWithContext(
152  "com.sun.star.drawing.PresenterHelper",
153  rxContext),
154  UNO_QUERY_THROW);
155 
156  if (mxSlideShowController.is())
157  {
158  mxSlideShowController->activate();
159  Reference<beans::XPropertySet> xProperties (mxSlideShowController, UNO_QUERY);
160  if (xProperties.is())
161  {
162  Reference<awt::XWindow> xWindow (
163  xProperties->getPropertyValue("ParentWindow"), UNO_QUERY);
164  if (xWindow.is())
165  xWindow->addKeyListener(this);
166  }
167  }
168 
170 
171  maInstances[mxController->getFrame()] = this;
172 
173  // Create a URLTransformer.
174  if (xFactory.is())
175  {
176  mxUrlTransformer.set(util::URLTransformer::create(mxComponentContext));
177  }
178 }
179 
181 {
182 }
183 
185 {
186  maInstances.erase(mxController->getFrame());
187 
188  if (mxMainWindow.is())
189  {
190  mxMainWindow->removeKeyListener(this);
191  mxMainWindow->removeMouseListener(this);
192  mxMainWindow = nullptr;
193  }
194  if (mxConfigurationController.is())
195  mxConfigurationController->removeConfigurationChangeListener(this);
196 
197  if (mxController.is())
198  {
199  Reference<frame::XFrame> xFrame (mxController->getFrame());
200  if (xFrame.is())
201  xFrame->removeFrameActionListener(this);
202  mxController = nullptr;
203  }
204 
205  Reference<XComponent> xWindowManagerComponent = mpWindowManager;
206  mpWindowManager = nullptr;
207  if (xWindowManagerComponent.is())
208  xWindowManagerComponent->dispose();
209 
210  mxComponentContext = nullptr;
211  mxConfigurationController = nullptr;
212  mxSlideShowController = nullptr;
213  mxMainPaneId = nullptr;
214  mpPaneContainer = nullptr;
215  mnCurrentSlideIndex = -1;
216  mxCurrentSlide = nullptr;
217  mxNextSlide = nullptr;
218  mpTheme.reset();
219  {
221  mpPaneBorderPainter = nullptr;
222  if (xComponent.is())
223  xComponent->dispose();
224  }
225  mpCanvasHelper.reset();
226  {
227  Reference<lang::XComponent> xComponent (mxPresenterHelper, UNO_QUERY);
228  mxPresenterHelper = nullptr;
229  if (xComponent.is())
230  xComponent->dispose();
231  }
232  mpPaintManager.reset();
234  {
235  Reference<lang::XComponent> xComponent (mxUrlTransformer, UNO_QUERY);
236  mxUrlTransformer = nullptr;
237  if (xComponent.is())
238  xComponent->dispose();
239  }
240 }
241 
242 void PresenterController::UpdateCurrentSlide (const sal_Int32 nOffset)
243 {
244  // std::cerr << "Updating current Slide to " << nOffset << std::endl;
245  GetSlides(nOffset);
247  UpdateViews();
248 
249  // Update the accessibility object.
250  if (IsAccessibilityActive())
251  {
252  mpAccessibleObject->NotifyCurrentSlideChange();
253  }
254 }
255 
256 void PresenterController::GetSlides (const sal_Int32 nOffset)
257 {
258  if ( ! mxSlideShowController.is())
259  return;
260 
261  // Get the current slide from the slide show controller.
262  mxCurrentSlide = nullptr;
263  Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
264  try
265  {
266  sal_Int32 nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
267  if (mxSlideShowController->isPaused())
268  nSlideIndex = -1;
269 
270  if (xIndexAccess.is() && nSlideIndex>=0)
271  {
272  if (nSlideIndex < xIndexAccess->getCount())
273  {
274  mnCurrentSlideIndex = nSlideIndex;
275  mxCurrentSlide.set( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
276  }
277  }
278  }
279  catch (RuntimeException&)
280  {
281  }
282 
283  // Get the next slide.
284  mxNextSlide = nullptr;
285  try
286  {
287  const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
288  if (nNextSlideIndex >= 0)
289  {
290  if (xIndexAccess.is())
291  {
292  if (nNextSlideIndex < xIndexAccess->getCount())
293  mxNextSlide.set( xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
294  }
295  }
296  }
297  catch (RuntimeException&)
298  {
299  }
300 }
301 
303 {
304  if ( ! mxSlideShowController.is())
305  return;
306 
307  // Get placeholders and their values.
308  static const OUStringLiteral sCurrentSlideNumberPlaceholder (u"CURRENT_SLIDE_NUMBER");
309  static const OUStringLiteral sCurrentSlideNamePlaceholder (u"CURRENT_SLIDE_NAME");
310  static const OUStringLiteral sSlideCountPlaceholder (u"SLIDE_COUNT");
311 
312  // Get string for slide count.
313  OUString sSlideCount ("---");
314  Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
315  if (xIndexAccess.is())
316  sSlideCount = OUString::number(xIndexAccess->getCount());
317 
318  // Get string for current slide index.
319  OUString sCurrentSlideNumber (OUString::number(mnCurrentSlideIndex + 1));
320 
321  // Get name of the current slide.
322  OUString sCurrentSlideName;
323  Reference<container::XNamed> xNamedSlide (mxCurrentSlide, UNO_QUERY);
324  if (xNamedSlide.is())
325  sCurrentSlideName = xNamedSlide->getName();
326  Reference<beans::XPropertySet> xSlideProperties (mxCurrentSlide, UNO_QUERY);
327  if (xSlideProperties.is())
328  {
329  try
330  {
331  OUString sName;
332  if (xSlideProperties->getPropertyValue("LinkDisplayName") >>= sName)
333  {
334  // Find out whether the name of the current slide has been
335  // automatically created or has been set by the user.
336  if (sName != sCurrentSlideName)
337  sCurrentSlideName = sName;
338  }
339  }
340  catch (const beans::UnknownPropertyException&)
341  {
342  }
343  }
344 
345  // Replace the placeholders with their current values.
346  for (auto& rxPane : mpPaneContainer->maPanes)
347  {
348  OSL_ASSERT(rxPane != nullptr);
349 
350  OUString sTemplate (IsAccessibilityActive()
351  ? rxPane->msAccessibleTitleTemplate
352  : rxPane->msTitleTemplate);
353  if (sTemplate.isEmpty())
354  continue;
355 
356  OUStringBuffer sResult;
357  sResult.ensureCapacity(sTemplate.getLength());
358 
359  sal_Int32 nIndex (0);
360  while (true)
361  {
362  sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
363  if (nStartIndex < 0)
364  {
365  // Add the remaining part of the string.
366  sResult.append(sTemplate.subView(nIndex));
367  break;
368  }
369  else
370  {
371  // Add the part preceding the next %.
372  sResult.append(sTemplate.subView(nIndex, nStartIndex-nIndex));
373 
374  // Get the placeholder
375  ++nStartIndex;
376  const sal_Int32 nEndIndex (sTemplate.indexOf('%', nStartIndex+1));
377  const OUString sPlaceholder (sTemplate.copy(nStartIndex, nEndIndex-nStartIndex));
378  nIndex = nEndIndex+1;
379 
380  // Replace the placeholder with its current value.
381  if (sPlaceholder == sCurrentSlideNumberPlaceholder)
382  sResult.append(sCurrentSlideNumber);
383  else if (sPlaceholder == sCurrentSlideNamePlaceholder)
384  sResult.append(sCurrentSlideName);
385  else if (sPlaceholder == sSlideCountPlaceholder)
386  sResult.append(sSlideCount);
387  }
388  }
389 
390  rxPane->msTitle = sResult.makeStringAndClear();
391  if (rxPane->mxPane.is())
392  rxPane->mxPane->SetTitle(rxPane->msTitle);
393  }
394 }
395 
397 {
398  // Tell all views about the slides they should display.
399  for (const auto& rxPane : mpPaneContainer->maPanes)
400  {
401  Reference<drawing::XDrawView> xDrawView (rxPane->mxView, UNO_QUERY);
402  if (xDrawView.is())
403  xDrawView->setCurrentPage(mxCurrentSlide);
404  }
405 }
406 
408  PresenterController::GetViewBackground (const OUString& rsViewURL) const
409 {
410  if (mpTheme != nullptr)
411  {
412  const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
413  return mpTheme->GetBitmap(sStyleName, "Background");
414  }
415  return SharedBitmapDescriptor();
416 }
417 
419  PresenterController::GetViewFont (const OUString& rsViewURL) const
420 {
421  if (mpTheme != nullptr)
422  {
423  const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
424  return mpTheme->GetFont(sStyleName);
425  }
427 }
428 
429 const std::shared_ptr<PresenterTheme>& PresenterController::GetTheme() const
430 {
431  return mpTheme;
432 }
433 
434 const ::rtl::Reference<PresenterWindowManager>& PresenterController::GetWindowManager() const
435 {
436  return mpWindowManager;
437 }
438 
439 const Reference<presentation::XSlideShowController>&
441 {
442  return mxSlideShowController;
443 }
444 
446 {
447  return mpPaneContainer;
448 }
449 
450 const ::rtl::Reference<PresenterPaneBorderPainter>& PresenterController::GetPaneBorderPainter() const
451 {
452  return mpPaneBorderPainter;
453 }
454 
455 const std::shared_ptr<PresenterCanvasHelper>& PresenterController::GetCanvasHelper() const
456 {
457  return mpCanvasHelper;
458 }
459 
460 const Reference<drawing::XPresenterHelper>& PresenterController::GetPresenterHelper() const
461 {
462  return mxPresenterHelper;
463 }
464 
465 const std::shared_ptr<PresenterPaintManager>& PresenterController::GetPaintManager() const
466 {
467  return mpPaintManager;
468 }
469 
470 void PresenterController::ShowView (const OUString& rsViewURL)
471 {
473  mpPaneContainer->FindViewURL(rsViewURL));
474  if (!pDescriptor)
475  return;
476 
477  pDescriptor->mbIsActive = true;
478  mxConfigurationController->requestResourceActivation(
479  pDescriptor->mxPaneId,
480  ResourceActivationMode_ADD);
481  mxConfigurationController->requestResourceActivation(
482  ResourceId::createWithAnchor(
484  rsViewURL,
485  pDescriptor->mxPaneId),
486  ResourceActivationMode_REPLACE);
487 }
488 
489 void PresenterController::HideView (const OUString& rsViewURL)
490 {
492  mpPaneContainer->FindViewURL(rsViewURL));
493  if (pDescriptor)
494  {
495  mxConfigurationController->requestResourceDeactivation(
496  ResourceId::createWithAnchor(
498  rsViewURL,
499  pDescriptor->mxPaneId));
500  }
501 }
502 
503 void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
504 {
505  if ( ! mxUrlTransformer.is())
506  return;
507 
508  util::URL aURL;
509  aURL.Complete = rsCommand;
510  mxUrlTransformer->parseStrict(aURL);
511 
513  if ( ! xDispatch.is())
514  return;
515 
516  xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
517 }
518 
519 Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
520 {
521  if ( ! mxController.is())
522  return nullptr;
523 
524  Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
525  if ( ! xDispatchProvider.is())
526  return nullptr;
527 
528  return xDispatchProvider->queryDispatch(
529  rURL,
530  OUString(),
531  frame::FrameSearchFlag::SELF);
532 }
533 
534 util::URL PresenterController::CreateURLFromString (const OUString& rsURL) const
535 {
536  util::URL aURL;
537 
538  if (mxUrlTransformer.is())
539  {
540  aURL.Complete = rsURL;
541  mxUrlTransformer->parseStrict(aURL);
542  }
543 
544  return aURL;
545 }
546 
547 const Reference<drawing::framework::XConfigurationController>&
549 {
551 }
552 
554 {
555  return mxCurrentSlide;
556 }
557 
559 {
560  bool bTransition = false;
561  if( rxPage.is() )
562  {
563  Reference<beans::XPropertySet> xSlidePropertySet (rxPage, UNO_QUERY);
564  try
565  {
566  sal_uInt16 aTransitionType = 0;
567  xSlidePropertySet->getPropertyValue("TransitionType") >>= aTransitionType;
568  if (aTransitionType > 0)
569  {
570  bTransition = true;
571  }
572  }
573  catch (const beans::UnknownPropertyException&)
574  {
575  }
576  }
577  return bTransition;
578 }
579 
581 {
582  bool bCustomAnimation = false;
583  if( rxPage.is() )
584  {
585  sal_uInt32 i, nCount = rxPage->getCount();
586  for ( i = 0; i < nCount; i++ )
587  {
588  Reference<drawing::XShape> xShape(rxPage->getByIndex(i), UNO_QUERY);
589  Reference<beans::XPropertySet> xShapePropertySet(xShape, UNO_QUERY);
590  presentation::AnimationEffect aEffect = presentation::AnimationEffect_NONE;
591  presentation::AnimationEffect aTextEffect = presentation::AnimationEffect_NONE;
592  try
593  {
594  xShapePropertySet->getPropertyValue("Effect") >>= aEffect;
595  xShapePropertySet->getPropertyValue("TextEffect") >>= aTextEffect;
596  }
597  catch (const beans::UnknownPropertyException&)
598  {
599  }
600  if( aEffect != presentation::AnimationEffect_NONE ||
601  aTextEffect != presentation::AnimationEffect_NONE )
602  {
603  bCustomAnimation = true;
604  break;
605  }
606  }
607  }
608  return bCustomAnimation;
609 }
610 
612 {
613  if ( mbIsAccessibilityActive != bIsActive)
614  {
615  mbIsAccessibilityActive = bIsActive;
617  }
618 }
619 
620 
621 void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
622 {
623  if (!mxSlideShowController.is())
624  return;
625 
626  switch (rEvent.Buttons)
627  {
628  case awt::MouseButton::LEFT:
629  if (rEvent.Modifiers == awt::KeyModifier::MOD2)
630  mxSlideShowController->gotoNextSlide();
631  else
632  mxSlideShowController->gotoNextEffect();
633  break;
634 
635  case awt::MouseButton::RIGHT:
636  mxSlideShowController->gotoPreviousSlide();
637  break;
638 
639  default:
640  // Other or multiple buttons.
641  break;
642  }
643 }
644 
646  const bool bIsSlideSorterActive,
647  const bool bIsNotesViewActive,
648  const bool bIsHelpViewActive)
649 {
650  for (const auto& rxPane : mpPaneContainer->maPanes)
651  {
652  bool bActivate (true);
653  const OUString sViewURL (rxPane->msViewURL);
654  if (sViewURL == PresenterViewFactory::msNotesViewURL)
655  {
656  bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
657  }
658  else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
659  {
660  bActivate = bIsSlideSorterActive;
661  }
664  {
665  bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
666  }
667  else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
668  {
669  bActivate = true;
670  }
671  else if (sViewURL == PresenterViewFactory::msHelpViewURL)
672  {
673  bActivate = bIsHelpViewActive;
674  }
675 
676  if (bActivate)
677  ShowView(sViewURL);
678  else
679  HideView(sViewURL);
680  }
681 }
682 
684 {
685  mpPresentationTime = pPresentationTime;
686 }
687 
689 {
690  return mpPresentationTime;
691 }
692 
693 //----- XConfigurationChangeListener ------------------------------------------
694 
696  const ConfigurationChangeEvent& rEvent)
697 {
698  if (rBHelper.bDisposed || rBHelper.bInDispose)
699  {
700  throw lang::DisposedException (
701  "PresenterController object has already been disposed",
702  static_cast<uno::XWeak*>(this));
703  }
704 
705  sal_Int32 nType (0);
706  if ( ! (rEvent.UserData >>= nType))
707  return;
708 
709  switch (nType)
710  {
711  case ResourceActivationEventType:
712  if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
713  {
714  InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
715  }
716  else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
717  {
718  // A pane bound to the main pane has been created and is
719  // stored in the pane container.
720  Reference<XPane> xPane (rEvent.ResourceObject,UNO_QUERY);
721  if (xPane.is())
722  {
723  mpPaneContainer->FindPaneId(xPane->getResourceId());
724  }
725  }
726  else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
727  {
728  // A view bound to one of the panes has been created and is
729  // stored in the pane container along with its pane.
730  Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
731  if (xView.is())
732  {
733  mpPaneContainer->StoreView(xView);
734  UpdateViews();
735  mpWindowManager->NotifyViewCreation(xView);
736  }
737  }
738  break;
739 
740  case ResourceDeactivationEventType:
741  if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
742  {
743  // If this is a view then remove it from the pane container.
744  Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
745  if (xView.is())
746  {
748  mpPaneContainer->RemoveView(xView));
749 
750  // A possibly opaque view has been removed. Update()
751  // updates the clip polygon.
752  mpWindowManager->Update();
753  // Request the repainting of the area previously
754  // occupied by the view.
755  if (pDescriptor)
756  GetPaintManager()->Invalidate(pDescriptor->mxBorderWindow);
757  }
758  }
759  break;
760 
761  case ConfigurationUpdateEndEventType:
762  if (IsAccessibilityActive())
763  {
764  mpAccessibleObject->UpdateAccessibilityHierarchy();
766  }
767  break;
768  }
769 }
770 
771 //----- XEventListener --------------------------------------------------------
772 
773 void SAL_CALL PresenterController::disposing (
774  const lang::EventObject& rEvent)
775 {
776  if (rEvent.Source == mxController)
777  mxController = nullptr;
778  else if (rEvent.Source == mxConfigurationController)
779  mxConfigurationController = nullptr;
780  else if (rEvent.Source == mxSlideShowController)
781  mxSlideShowController = nullptr;
782  else if (rEvent.Source == mxMainWindow)
783  mxMainWindow = nullptr;
784 }
785 
786 //----- XFrameActionListener --------------------------------------------------
787 
789  const frame::FrameActionEvent& rEvent)
790 {
791  if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
792  {
793  if (mxSlideShowController.is())
794  mxSlideShowController->activate();
795  }
796 }
797 
798 //----- XKeyListener ----------------------------------------------------------
799 
800 void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
801 {
802  // Tell all views about the unhandled key event.
803  for (const auto& rxPane : mpPaneContainer->maPanes)
804  {
805  if ( ! rxPane->mbIsActive)
806  continue;
807 
808  Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
809  if (xKeyListener.is())
810  xKeyListener->keyPressed(rEvent);
811  }
812 }
813 
814 void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
815 {
816  if (rEvent.Source != mxMainWindow)
817  return;
818 
819  switch (rEvent.KeyCode)
820  {
821  case awt::Key::ESCAPE:
822  case awt::Key::SUBTRACT:
823  {
824  if( mxController.is() )
825  {
826  Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
827  if( xPS.is() )
828  {
829  Reference< XPresentation > xP( xPS->getPresentation() );
830  if( xP.is() )
831  xP->end();
832  }
833  }
834  }
835  break;
836 
837  case awt::Key::PAGEDOWN:
838  if (mxSlideShowController.is())
839  {
840  if (rEvent.Modifiers == awt::KeyModifier::MOD2)
841  mxSlideShowController->gotoNextSlide();
842  else
843  mxSlideShowController->gotoNextEffect();
844  }
845  break;
846 
847  case awt::Key::RIGHT:
848  case awt::Key::SPACE:
849  case awt::Key::DOWN:
850  if (mxSlideShowController.is())
851  {
852  mxSlideShowController->gotoNextEffect();
853  }
854  break;
855 
856  case awt::Key::PAGEUP:
857  if (mxSlideShowController.is())
858  {
859  if (rEvent.Modifiers == awt::KeyModifier::MOD2)
860  mxSlideShowController->gotoPreviousSlide();
861  else
862  mxSlideShowController->gotoPreviousEffect();
863  }
864  break;
865 
866  case awt::Key::LEFT:
867  case awt::Key::UP:
868  case awt::Key::BACKSPACE:
869  if (mxSlideShowController.is())
870  {
871  mxSlideShowController->gotoPreviousEffect();
872  }
873  break;
874 
875  case awt::Key::P:
876  if (mxSlideShowController.is())
877  {
878  bool bPenEnabled = mxSlideShowController->getUsePen();
879  mxSlideShowController->setUsePen( !bPenEnabled );
880  }
881  break;
882 
883  case awt::Key::E:
884  if (mxSlideShowController.is())
885  {
886  mxSlideShowController->setEraseAllInk( true );
887  }
888  break;
889 
890  case awt::Key::HOME:
891  if (mxSlideShowController.is())
892  {
893  mxSlideShowController->gotoFirstSlide();
894  }
895  break;
896 
897  case awt::Key::END:
898  if (mxSlideShowController.is())
899  {
900  mxSlideShowController->gotoLastSlide();
901  }
902  break;
903 
904  case awt::Key::W:
905  case awt::Key::COMMA:
906  if (mxSlideShowController.is())
907  {
908  if (mxSlideShowController->isPaused())
909  mxSlideShowController->resume();
910  else
911  mxSlideShowController->blankScreen(0x00ffffff);
912  }
913  break;
914 
915  case awt::Key::B:
916  case awt::Key::POINT:
917  if (mxSlideShowController.is())
918  {
919  if (mxSlideShowController->isPaused())
920  mxSlideShowController->resume();
921  else
922  mxSlideShowController->blankScreen(0x00000000);
923  }
924  break;
925 
926  case awt::Key::NUM0:
927  case awt::Key::NUM1:
928  case awt::Key::NUM2:
929  case awt::Key::NUM3:
930  case awt::Key::NUM4:
931  case awt::Key::NUM5:
932  case awt::Key::NUM6:
933  case awt::Key::NUM7:
934  case awt::Key::NUM8:
935  case awt::Key::NUM9:
936  HandleNumericKeyPress(rEvent.KeyCode-awt::Key::NUM0, rEvent.Modifiers);
937  break;
938 
939  case awt::Key::RETURN:
940  if (mnPendingSlideNumber > 0)
941  {
942  if (mxSlideShowController.is())
943  mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
945  }
946  else
947  {
948  if (mxSlideShowController.is())
949  mxSlideShowController->gotoNextEffect();
950  }
951 
952  break;
953 
954  case awt::Key::F1:
955  // Toggle the help view.
956  if (mpWindowManager)
957  {
958  if (mpWindowManager->GetViewMode() != PresenterWindowManager::VM_Help)
960  else
961  mpWindowManager->SetHelpViewState(false);
962  }
963 
964  break;
965 
966  default:
967  // Tell all views about the unhandled key event.
968  for (const auto& rxPane : mpPaneContainer->maPanes)
969  {
970  if ( ! rxPane->mbIsActive)
971  continue;
972 
973  Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
974  if (xKeyListener.is())
975  xKeyListener->keyReleased(rEvent);
976  }
977  break;
978  }
979 }
980 
982  const sal_Int32 nKey,
983  const sal_Int32 nModifiers)
984 {
985  switch (nModifiers)
986  {
987  case 0:
988  if (mnPendingSlideNumber == -1)
991  break;
992 
993  case awt::KeyModifier::MOD1:
994  // Ctrl-1, Ctrl-2, and Ctrl-3 are used to switch between views
995  // (slide view, notes view, normal). Ctrl-4 switches monitors
997  if (!mpWindowManager)
998  return;
999  switch(nKey)
1000  {
1001  case 1:
1003  break;
1004  case 2:
1006  break;
1007  case 3:
1009  break;
1010  case 4:
1011  SwitchMonitors();
1012  break;
1013  default:
1014  // Ignore unsupported key.
1015  break;
1016  }
1017  break;
1018 
1019  default:
1020  // Ignore unsupported modifiers.
1021  break;
1022  }
1023 }
1024 
1025 //----- XMouseListener --------------------------------------------------------
1026 
1027 void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent&)
1028 {
1029  if (mxMainWindow.is())
1030  mxMainWindow->setFocus();
1031 }
1032 
1033 void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent&) {}
1034 
1035 void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent&) {}
1036 
1037 void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent&) {}
1038 
1039 void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1040 {
1041  if ( ! rxPane.is())
1042  return;
1043 
1046  this,
1047  rxPane);
1048 
1049  LoadTheme(rxPane);
1050 
1051  // Main pane has been created and is now observed by the window
1052  // manager.
1053  mpWindowManager->SetParentPane(rxPane);
1054  mpWindowManager->SetTheme(mpTheme);
1055 
1056  if (mpPaneBorderPainter)
1057  mpPaneBorderPainter->SetTheme(mpTheme);
1058 
1059  // Add key listener
1060  mxMainWindow = rxPane->getWindow();
1061  if (mxMainWindow.is())
1062  {
1063  mxMainWindow->addKeyListener(this);
1064  mxMainWindow->addMouseListener(this);
1065  }
1066  Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1067  if (xPane2.is())
1068  xPane2->setVisible(true);
1069 
1070  mpPaintManager = std::make_shared<PresenterPaintManager>(mxMainWindow, mxPresenterHelper, mpPaneContainer);
1071 
1072  mxCanvas.set(rxPane->getCanvas(), UNO_QUERY);
1073 
1074  if (mxSlideShowController.is())
1075  mxSlideShowController->activate();
1076 
1077  UpdateCurrentSlide(0);
1078 }
1079 
1080 void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1081 {
1082  // Create (load) the current theme.
1083  if (rxPane.is())
1084  mpTheme = std::make_shared<PresenterTheme>(mxComponentContext, rxPane->getCanvas());
1085 }
1086 
1088 {
1089  double nSlideAspectRatio (28.0/21.0);
1090 
1091  try
1092  {
1093  if (mxController.is())
1094  {
1095  Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
1096  mxController->getModel(), UNO_QUERY_THROW);
1097  Reference<drawing::XDrawPages> xSlides (xSlideSupplier->getDrawPages());
1098  if (xSlides.is() && xSlides->getCount()>0)
1099  {
1100  Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
1101  sal_Int32 nWidth (28000);
1102  sal_Int32 nHeight (21000);
1103  if ((xProperties->getPropertyValue("Width") >>= nWidth)
1104  && (xProperties->getPropertyValue("Height") >>= nHeight)
1105  && nHeight > 0)
1106  {
1107  nSlideAspectRatio = double(nWidth) / double(nHeight);
1108  }
1109  }
1110  }
1111  }
1112  catch (RuntimeException&)
1113  {
1114  OSL_ASSERT(false);
1115  }
1116 
1117  return nSlideAspectRatio;
1118 }
1119 
1120 void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1121 {
1122  mnPendingSlideNumber = nPendingSlideNumber;
1123 
1124  if (mpTheme == nullptr)
1125  return;
1126 
1127  if ( ! mxMainWindow.is())
1128  return;
1129 
1131  mpTheme->GetFont("PendingSlideNumberFont"));
1132  if (!pFont)
1133  return;
1134 
1135  pFont->PrepareFont(mxCanvas);
1136  if ( ! pFont->mxFont.is())
1137  return;
1138 
1139  const OUString sText (OUString::number(mnPendingSlideNumber));
1140  rendering::StringContext aContext (sText, 0, sText.getLength());
1141  pFont->mxFont->createTextLayout(
1142  aContext,
1143  rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1144  0);
1145 }
1146 
1148 {
1149  Reference<lang::XEventListener> xScreen( mxScreen );
1150  if (!xScreen.is())
1151  return;
1152 
1153  PresenterScreen *pScreen = dynamic_cast<PresenterScreen *>(xScreen.get());
1154  if (!pScreen)
1155  return;
1156 
1157  pScreen->SwitchMonitors();
1158 }
1159 
1161 {
1162  if( mxController.is() )
1163  {
1164  Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
1165  if( xPS.is() )
1166  {
1167  Reference< XPresentation > xP( xPS->getPresentation() );
1168  if( xP.is() )
1169  xP->end();
1170  }
1171  }
1172 }
1173 
1174 } // end of namespace ::sdext::presenter
1175 
1176 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static::rtl::Reference< PresenterController > Instance(const css::uno::Reference< css::frame::XFrame > &rxFrame)
const std::shared_ptr< PresenterPaintManager > & GetPaintManager() const
URL aURL
std::shared_ptr< FontDescriptor > SharedFontDescriptor
sal_Int32 nIndex
static constexpr OUStringLiteral msCurrentSlidePreviewViewURL
std::shared_ptr< PresenterCanvasHelper > mpCanvasHelper
css::uno::Reference< css::util::XURLTransformer > mxUrlTransformer
void DispatchUnoCommand(const OUString &rsCommand) const
Represents an element in the toolbar that shows the time elapsed since the presentation started...
css::uno::WeakReference< css::lang::XEventListener > mxScreen
const std::shared_ptr< PresenterTheme > & GetTheme() const
void HideView(const OUString &rsViewURL)
Reference< XFrame > xFrame
::rtl::Reference< PresenterAccessible > mpAccessibleObject
virtual void SAL_CALL frameAction(const css::frame::FrameActionEvent &rEvent) override
void InitializeMainPane(const css::uno::Reference< css::drawing::framework::XPane > &rxPane)
static bool HasCustomAnimation(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
css::util::URL CreateURLFromString(const OUString &rsURL) const
const ::rtl::Reference< PresenterPaneBorderPainter > & GetPaneBorderPainter() const
static constexpr OUStringLiteral msNotesViewURL
std::shared_ptr< T > make_shared(Args &&...args)
virtual void SAL_CALL keyPressed(const css::awt::KeyEvent &rEvent) override
const css::uno::Reference< css::drawing::XPresenterHelper > & GetPresenterHelper() const
std::shared_ptr< PresenterPaintManager > mpPaintManager
PresenterController(const css::uno::WeakReference< css::lang::XEventListener > &rxScreen, const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::frame::XController > &rxController, const css::uno::Reference< css::presentation::XSlideShowController > &rxSlideShowController, const rtl::Reference< PresenterPaneContainer > &rpPaneContainer, const css::uno::Reference< css::drawing::framework::XResourceId > &rxMainPaneId)
std::shared_ptr< PresenterBitmapContainer::BitmapDescriptor > SharedBitmapDescriptor
static constexpr OUStringLiteral msNextSlidePreviewViewURL
css::uno::Reference< css::presentation::XSlideShowController > mxSlideShowController
Collection of functions to ease the life of a canvas user.
int nCount
void GetSlides(const sal_Int32 nOffset)
std::mutex m_aMutex
virtual void SAL_CALL mouseEntered(const css::awt::MouseEvent &rEvent) override
virtual void SAL_CALL disposing() override
::rtl::Reference< PresenterPaneBorderPainter > mpPaneBorderPainter
virtual void SAL_CALL keyReleased(const css::awt::KeyEvent &rEvent) override
static constexpr OUStringLiteral msToolBarViewURL
const char * sName
void SwitchMonitors()
Switch / converse monitors between presenter view and slide output.
virtual void SAL_CALL mouseExited(const css::awt::MouseEvent &rEvent) override
::cppu::WeakComponentImplHelper< css::drawing::framework::XConfigurationChangeListener, css::frame::XFrameActionListener, css::awt::XKeyListener, css::awt::XMouseListener > PresenterControllerInterfaceBase
void UpdateCurrentSlide(const sal_Int32 nOffset)
SharedBitmapDescriptor GetViewBackground(const OUString &rsViewURL) const
css::uno::Reference< css::rendering::XSpriteCanvas > mxCanvas
void SetPresentationTime(IPresentationTime *pPresentationTime)
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
int i
void RequestViews(const bool bIsSlideSorterActive, const bool bIsNotesViewActive, const bool bIsHelpViewActive)
Request activation or deactivation of (some of) the views according to the given parameters.
virtual void SAL_CALL mousePressed(const css::awt::MouseEvent &rEvent) override
PresenterTheme::SharedFontDescriptor GetViewFont(const OUString &rsViewURL) const
::std::map< css::uno::Reference< css::frame::XFrame >, rtl::Reference< PresenterController > > InstanceContainer
void ShowView(const OUString &rsViewURL)
float u
A simple manager of the positions of the panes of the presenter screen.
rtl::Reference< PresenterPaneContainer > mpPaneContainer
const css::uno::Reference< css::presentation::XSlideShowController > & GetSlideShowController() const
void LoadTheme(const css::uno::Reference< css::drawing::framework::XPane > &rxPane)
virtual void SAL_CALL mouseReleased(const css::awt::MouseEvent &rEvent) override
const css::uno::Reference< css::drawing::XDrawPage > & GetCurrentSlide() const
css::uno::Reference< css::frame::XController > mxController
css::uno::Reference< css::frame::XDispatch > GetDispatch(const css::util::URL &rURL) const
css::uno::Reference< css::drawing::XDrawPage > mxCurrentSlide
const std::shared_ptr< PresenterCanvasHelper > & GetCanvasHelper() const
void UpdatePendingSlideNumber(const sal_Int32 nPendingSlideNumber)
Reference< XDispatch > xDispatch
void SetAccessibilityActiveState(const bool bIsActive)
const ::rtl::Reference< PresenterWindowManager > & GetWindowManager() const
std::shared_ptr< PaneDescriptor > SharedPaneDescriptor
Check periodically the slide show controller and the frame::XController whether the current slide has...
const css::uno::Reference< css::drawing::framework::XConfigurationController > & GetConfigurationController() const
QPRO_FUNC_TYPE nType
css::uno::Reference< css::drawing::XDrawPage > mxNextSlide
const rtl::Reference< PresenterPaneContainer > & GetPaneContainer() const
css::uno::Reference< css::drawing::framework::XConfigurationController > mxConfigurationController
css::uno::Reference< css::drawing::XPresenterHelper > mxPresenterHelper
Reference< XSingleServiceFactory > xFactory
static constexpr OUStringLiteral msHelpViewURL
virtual void SAL_CALL notifyConfigurationChange(const css::drawing::framework::ConfigurationChangeEvent &rEvent) override
std::shared_ptr< PresenterTheme > mpTheme
This class is responsible for painting window borders of PresenterPane objects.
css::uno::Reference< css::uno::XComponentContext > mxComponentContext
static constexpr OUStringLiteral msSlideSorterURL
::rtl::Reference< PresenterWindowManager > mpWindowManager
void HandleNumericKeyPress(const sal_Int32 nKey, const sal_Int32 nModifiers)
This method is called when the user pressed one of the numerical keys.
void HandleMouseClick(const css::awt::MouseEvent &rEvent)
static bool HasTransition(css::uno::Reference< css::drawing::XDrawPage > const &rxPage)
css::uno::Reference< css::awt::XWindow > mxMainWindow
css::uno::Reference< css::drawing::framework::XResourceId > mxMainPaneId