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