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 { namespace 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(new 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  {
232  static_cast<XWeak*>(mpPaneBorderPainter.get()), UNO_QUERY);
233  mpPaneBorderPainter = nullptr;
234  if (xComponent.is())
235  xComponent->dispose();
236  }
237  mpCanvasHelper.reset();
238  {
240  mxPresenterHelper = nullptr;
241  if (xComponent.is())
242  xComponent->dispose();
243  }
244  mpPaintManager.reset();
246  {
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  sal_Int32 nSlideIndex = -1;
277  try
278  {
279  nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
280  if (mxSlideShowController->isPaused())
281  nSlideIndex = -1;
282 
283  if (xIndexAccess.is() && nSlideIndex>=0)
284  {
285  if (nSlideIndex < xIndexAccess->getCount())
286  {
287  mnCurrentSlideIndex = nSlideIndex;
288  mxCurrentSlide.set( xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
289  }
290  }
291  }
292  catch (RuntimeException&)
293  {
294  }
295 
296  // Get the next slide.
297  mxNextSlide = nullptr;
298  try
299  {
300  const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
301  if (nNextSlideIndex >= 0)
302  {
303  if (xIndexAccess.is())
304  {
305  if (nNextSlideIndex < xIndexAccess->getCount())
306  mxNextSlide.set( xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
307  }
308  }
309  }
310  catch (RuntimeException&)
311  {
312  }
313 }
314 
316 {
317  if ( ! mxSlideShowController.is())
318  return;
319 
320  // Get placeholders and their values.
321  const OUString sCurrentSlideNumberPlaceholder ("CURRENT_SLIDE_NUMBER");
322  const OUString sCurrentSlideNamePlaceholder ("CURRENT_SLIDE_NAME");
323  const OUString sSlideCountPlaceholder ("SLIDE_COUNT");
324 
325  // Get string for slide count.
326  OUString sSlideCount ("---");
327  Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
328  if (xIndexAccess.is())
329  sSlideCount = OUString::number(xIndexAccess->getCount());
330 
331  // Get string for current slide index.
332  OUString sCurrentSlideNumber (OUString::number(mnCurrentSlideIndex + 1));
333 
334  // Get name of the current slide.
335  OUString sCurrentSlideName;
336  Reference<container::XNamed> xNamedSlide (mxCurrentSlide, UNO_QUERY);
337  if (xNamedSlide.is())
338  sCurrentSlideName = xNamedSlide->getName();
339  Reference<beans::XPropertySet> xSlideProperties (mxCurrentSlide, UNO_QUERY);
340  if (xSlideProperties.is())
341  {
342  try
343  {
344  OUString sName;
345  if (xSlideProperties->getPropertyValue("LinkDisplayName") >>= sName)
346  {
347  // Find out whether the name of the current slide has been
348  // automatically created or has been set by the user.
349  if (sName != sCurrentSlideName)
350  sCurrentSlideName = sName;
351  }
352  }
353  catch (const beans::UnknownPropertyException&)
354  {
355  }
356  }
357 
358  // Replace the placeholders with their current values.
359  for (auto& rxPane : mpPaneContainer->maPanes)
360  {
361  OSL_ASSERT(rxPane != nullptr);
362 
363  OUString sTemplate (IsAccessibilityActive()
364  ? rxPane->msAccessibleTitleTemplate
365  : rxPane->msTitleTemplate);
366  if (sTemplate.isEmpty())
367  continue;
368 
369  OUStringBuffer sResult;
370  sResult.ensureCapacity(sTemplate.getLength());
371 
372  sal_Int32 nIndex (0);
373  while (true)
374  {
375  sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
376  if (nStartIndex < 0)
377  {
378  // Add the remaining part of the string.
379  sResult.append(std::u16string_view(sTemplate).substr(nIndex));
380  break;
381  }
382  else
383  {
384  // Add the part preceding the next %.
385  sResult.append(std::u16string_view(sTemplate).substr(nIndex, nStartIndex-nIndex));
386 
387  // Get the placeholder
388  ++nStartIndex;
389  const sal_Int32 nEndIndex (sTemplate.indexOf('%', nStartIndex+1));
390  const OUString sPlaceholder (sTemplate.copy(nStartIndex, nEndIndex-nStartIndex));
391  nIndex = nEndIndex+1;
392 
393  // Replace the placeholder with its current value.
394  if (sPlaceholder == sCurrentSlideNumberPlaceholder)
395  sResult.append(sCurrentSlideNumber);
396  else if (sPlaceholder == sCurrentSlideNamePlaceholder)
397  sResult.append(sCurrentSlideName);
398  else if (sPlaceholder == sSlideCountPlaceholder)
399  sResult.append(sSlideCount);
400  }
401  }
402 
403  rxPane->msTitle = sResult.makeStringAndClear();
404  if (rxPane->mxPane.is())
405  rxPane->mxPane->SetTitle(rxPane->msTitle);
406  }
407 }
408 
410 {
411  // Tell all views about the slides they should display.
412  for (const auto& rxPane : mpPaneContainer->maPanes)
413  {
414  Reference<drawing::XDrawView> xDrawView (rxPane->mxView, UNO_QUERY);
415  if (xDrawView.is())
416  xDrawView->setCurrentPage(mxCurrentSlide);
417  }
418 }
419 
421  PresenterController::GetViewBackground (const OUString& rsViewURL) const
422 {
423  if (mpTheme != nullptr)
424  {
425  const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
426  return mpTheme->GetBitmap(sStyleName, "Background");
427  }
428  return SharedBitmapDescriptor();
429 }
430 
432  PresenterController::GetViewFont (const OUString& rsViewURL) const
433 {
434  if (mpTheme != nullptr)
435  {
436  const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
437  return mpTheme->GetFont(sStyleName);
438  }
440 }
441 
442 const std::shared_ptr<PresenterTheme>& PresenterController::GetTheme() const
443 {
444  return mpTheme;
445 }
446 
447 const ::rtl::Reference<PresenterWindowManager>& PresenterController::GetWindowManager() const
448 {
449  return mpWindowManager;
450 }
451 
452 const Reference<presentation::XSlideShowController>&
454 {
455  return mxSlideShowController;
456 }
457 
459 {
460  return mpPaneContainer;
461 }
462 
463 const ::rtl::Reference<PresenterPaneBorderPainter>& PresenterController::GetPaneBorderPainter() const
464 {
465  return mpPaneBorderPainter;
466 }
467 
468 const std::shared_ptr<PresenterCanvasHelper>& PresenterController::GetCanvasHelper() const
469 {
470  return mpCanvasHelper;
471 }
472 
473 const Reference<drawing::XPresenterHelper>& PresenterController::GetPresenterHelper() const
474 {
475  return mxPresenterHelper;
476 }
477 
478 const std::shared_ptr<PresenterPaintManager>& PresenterController::GetPaintManager() const
479 {
480  return mpPaintManager;
481 }
482 
483 void PresenterController::ShowView (const OUString& rsViewURL)
484 {
486  mpPaneContainer->FindViewURL(rsViewURL));
487  if (pDescriptor.get() == nullptr)
488  return;
489 
490  pDescriptor->mbIsActive = true;
491  mxConfigurationController->requestResourceActivation(
492  pDescriptor->mxPaneId,
493  ResourceActivationMode_ADD);
494  mxConfigurationController->requestResourceActivation(
495  ResourceId::createWithAnchor(
497  rsViewURL,
498  pDescriptor->mxPaneId),
499  ResourceActivationMode_REPLACE);
500 }
501 
502 void PresenterController::HideView (const OUString& rsViewURL)
503 {
505  mpPaneContainer->FindViewURL(rsViewURL));
506  if (pDescriptor.get() != nullptr)
507  {
508  mxConfigurationController->requestResourceDeactivation(
509  ResourceId::createWithAnchor(
511  rsViewURL,
512  pDescriptor->mxPaneId));
513  }
514 }
515 
516 void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
517 {
518  if ( ! mxUrlTransformer.is())
519  return;
520 
521  util::URL aURL;
522  aURL.Complete = rsCommand;
523  mxUrlTransformer->parseStrict(aURL);
524 
526  if ( ! xDispatch.is())
527  return;
528 
529  xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
530 }
531 
532 Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
533 {
534  if ( ! mxController.is())
535  return nullptr;
536 
537  Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
538  if ( ! xDispatchProvider.is())
539  return nullptr;
540 
541  return xDispatchProvider->queryDispatch(
542  rURL,
543  OUString(),
544  frame::FrameSearchFlag::SELF);
545 }
546 
547 util::URL PresenterController::CreateURLFromString (const OUString& rsURL) const
548 {
549  util::URL aURL;
550 
551  if (mxUrlTransformer.is())
552  {
553  aURL.Complete = rsURL;
554  mxUrlTransformer->parseStrict(aURL);
555  }
556 
557  return aURL;
558 }
559 
560 const Reference<drawing::framework::XConfigurationController>&
562 {
564 }
565 
567 {
568  return mxCurrentSlide;
569 }
570 
572 {
573  bool bTransition = false;
574  sal_uInt16 aTransitionType = 0;
575  if( rxPage.is() )
576  {
577  Reference<beans::XPropertySet> xSlidePropertySet (rxPage, UNO_QUERY);
578  try
579  {
580  xSlidePropertySet->getPropertyValue("TransitionType") >>= aTransitionType;
581  if (aTransitionType > 0)
582  {
583  bTransition = true;
584  }
585  }
586  catch (const beans::UnknownPropertyException&)
587  {
588  }
589  }
590  return bTransition;
591 }
592 
594 {
595  bool bCustomAnimation = false;
596  if( rxPage.is() )
597  {
598  sal_uInt32 i, nCount = rxPage->getCount();
599  for ( i = 0; i < nCount; i++ )
600  {
601  Reference<drawing::XShape> xShape(rxPage->getByIndex(i), UNO_QUERY);
602  Reference<beans::XPropertySet> xShapePropertySet(xShape, UNO_QUERY);
603  presentation::AnimationEffect aEffect = presentation::AnimationEffect_NONE;
604  presentation::AnimationEffect aTextEffect = presentation::AnimationEffect_NONE;
605  try
606  {
607  xShapePropertySet->getPropertyValue("Effect") >>= aEffect;
608  xShapePropertySet->getPropertyValue("TextEffect") >>= aTextEffect;
609  }
610  catch (const beans::UnknownPropertyException&)
611  {
612  }
613  if( aEffect != presentation::AnimationEffect_NONE ||
614  aTextEffect != presentation::AnimationEffect_NONE )
615  {
616  bCustomAnimation = true;
617  break;
618  }
619  }
620  }
621  return bCustomAnimation;
622 }
623 
625 {
626  if ( mbIsAccessibilityActive != bIsActive)
627  {
628  mbIsAccessibilityActive = bIsActive;
630  }
631 }
632 
633 
634 void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
635 {
636  if (!mxSlideShowController.is())
637  return;
638 
639  switch (rEvent.Buttons)
640  {
641  case awt::MouseButton::LEFT:
642  if (rEvent.Modifiers == awt::KeyModifier::MOD2)
643  mxSlideShowController->gotoNextSlide();
644  else
645  mxSlideShowController->gotoNextEffect();
646  break;
647 
648  case awt::MouseButton::RIGHT:
649  mxSlideShowController->gotoPreviousSlide();
650  break;
651 
652  default:
653  // Other or multiple buttons.
654  break;
655  }
656 }
657 
659  const bool bIsSlideSorterActive,
660  const bool bIsNotesViewActive,
661  const bool bIsHelpViewActive)
662 {
663  for (const auto& rxPane : mpPaneContainer->maPanes)
664  {
665  bool bActivate (true);
666  const OUString sViewURL (rxPane->msViewURL);
667  if (sViewURL == PresenterViewFactory::msNotesViewURL)
668  {
669  bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
670  }
671  else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
672  {
673  bActivate = bIsSlideSorterActive;
674  }
677  {
678  bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
679  }
680  else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
681  {
682  bActivate = true;
683  }
684  else if (sViewURL == PresenterViewFactory::msHelpViewURL)
685  {
686  bActivate = bIsHelpViewActive;
687  }
688 
689  if (bActivate)
690  ShowView(sViewURL);
691  else
692  HideView(sViewURL);
693  }
694 }
695 
697 {
698  mpPresentationTime = pPresentationTime;
699 }
700 
702 {
703  return mpPresentationTime;
704 }
705 
706 //----- XConfigurationChangeListener ------------------------------------------
707 
709  const ConfigurationChangeEvent& rEvent)
710 {
711  if (rBHelper.bDisposed || rBHelper.bInDispose)
712  {
713  throw lang::DisposedException (
714  "PresenterController object has already been disposed",
715  static_cast<uno::XWeak*>(this));
716  }
717 
718  sal_Int32 nType (0);
719  if ( ! (rEvent.UserData >>= nType))
720  return;
721 
722  switch (nType)
723  {
724  case ResourceActivationEventType:
725  if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
726  {
727  InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
728  }
729  else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
730  {
731  // A pane bound to the main pane has been created and is
732  // stored in the pane container.
733  Reference<XPane> xPane (rEvent.ResourceObject,UNO_QUERY);
734  if (xPane.is())
735  {
737  mpPaneContainer->FindPaneId(xPane->getResourceId()));
738  }
739  }
740  else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
741  {
742  // A view bound to one of the panes has been created and is
743  // stored in the pane container along with its pane.
744  Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
745  if (xView.is())
746  {
747  mpPaneContainer->StoreView(xView);
748  UpdateViews();
749  mpWindowManager->NotifyViewCreation(xView);
750  }
751  }
752  break;
753 
754  case ResourceDeactivationEventType:
755  if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
756  {
757  // If this is a view then remove it from the pane container.
758  Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
759  if (xView.is())
760  {
762  mpPaneContainer->RemoveView(xView));
763 
764  // A possibly opaque view has been removed. Update()
765  // updates the clip polygon.
766  mpWindowManager->Update();
767  // Request the repainting of the area previously
768  // occupied by the view.
769  if (pDescriptor.get() != nullptr)
770  GetPaintManager()->Invalidate(pDescriptor->mxBorderWindow);
771  }
772  }
773  break;
774 
775  case ConfigurationUpdateEndEventType:
776  if (IsAccessibilityActive())
777  {
778  mpAccessibleObject->UpdateAccessibilityHierarchy();
780  }
781  break;
782  }
783 }
784 
785 //----- XEventListener --------------------------------------------------------
786 
787 void SAL_CALL PresenterController::disposing (
788  const lang::EventObject& rEvent)
789 {
790  if (rEvent.Source == mxController)
791  mxController = nullptr;
792  else if (rEvent.Source == mxConfigurationController)
793  mxConfigurationController = nullptr;
794  else if (rEvent.Source == mxSlideShowController)
795  mxSlideShowController = nullptr;
796  else if (rEvent.Source == mxMainWindow)
797  mxMainWindow = nullptr;
798 }
799 
800 //----- XFrameActionListener --------------------------------------------------
801 
803  const frame::FrameActionEvent& rEvent)
804 {
805  if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
806  {
807  if (mxSlideShowController.is())
808  mxSlideShowController->activate();
809  }
810 }
811 
812 //----- XKeyListener ----------------------------------------------------------
813 
814 void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
815 {
816  // Tell all views about the unhandled key event.
817  for (const auto& rxPane : mpPaneContainer->maPanes)
818  {
819  if ( ! rxPane->mbIsActive)
820  continue;
821 
822  Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
823  if (xKeyListener.is())
824  xKeyListener->keyPressed(rEvent);
825  }
826 }
827 
828 void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
829 {
830  if (rEvent.Source != mxMainWindow)
831  return;
832 
833  switch (rEvent.KeyCode)
834  {
835  case awt::Key::ESCAPE:
836  case awt::Key::SUBTRACT:
837  {
838  if( mxController.is() )
839  {
840  Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
841  if( xPS.is() )
842  {
843  Reference< XPresentation > xP( xPS->getPresentation() );
844  if( xP.is() )
845  xP->end();
846  }
847  }
848  }
849  break;
850 
851  case awt::Key::PAGEDOWN:
852  if (mxSlideShowController.is())
853  {
854  if (rEvent.Modifiers == awt::KeyModifier::MOD2)
855  mxSlideShowController->gotoNextSlide();
856  else
857  mxSlideShowController->gotoNextEffect();
858  }
859  break;
860 
861  case awt::Key::RIGHT:
862  case awt::Key::SPACE:
863  case awt::Key::DOWN:
864  case awt::Key::N:
865  if (mxSlideShowController.is())
866  {
867  mxSlideShowController->gotoNextEffect();
868  }
869  break;
870 
871  case awt::Key::PAGEUP:
872  if (mxSlideShowController.is())
873  {
874  if (rEvent.Modifiers == awt::KeyModifier::MOD2)
875  mxSlideShowController->gotoPreviousSlide();
876  else
877  mxSlideShowController->gotoPreviousEffect();
878  }
879  break;
880 
881  case awt::Key::LEFT:
882  case awt::Key::UP:
883  case awt::Key::P:
884  case awt::Key::BACKSPACE:
885  if (mxSlideShowController.is())
886  {
887  mxSlideShowController->gotoPreviousEffect();
888  }
889  break;
890 
891  case awt::Key::HOME:
892  if (mxSlideShowController.is())
893  {
894  mxSlideShowController->gotoFirstSlide();
895  }
896  break;
897 
898  case awt::Key::END:
899  if (mxSlideShowController.is())
900  {
901  mxSlideShowController->gotoLastSlide();
902  }
903  break;
904 
905  case awt::Key::W:
906  case awt::Key::COMMA:
907  if (mxSlideShowController.is())
908  {
909  if (mxSlideShowController->isPaused())
910  mxSlideShowController->resume();
911  else
912  mxSlideShowController->blankScreen(0x00ffffff);
913  }
914  break;
915 
916  case awt::Key::B:
917  case awt::Key::POINT:
918  if (mxSlideShowController.is())
919  {
920  if (mxSlideShowController->isPaused())
921  mxSlideShowController->resume();
922  else
923  mxSlideShowController->blankScreen(0x00000000);
924  }
925  break;
926 
927  case awt::Key::NUM0:
928  case awt::Key::NUM1:
929  case awt::Key::NUM2:
930  case awt::Key::NUM3:
931  case awt::Key::NUM4:
932  case awt::Key::NUM5:
933  case awt::Key::NUM6:
934  case awt::Key::NUM7:
935  case awt::Key::NUM8:
936  case awt::Key::NUM9:
937  HandleNumericKeyPress(rEvent.KeyCode-awt::Key::NUM0, rEvent.Modifiers);
938  break;
939 
940  case awt::Key::RETURN:
941  if (mnPendingSlideNumber > 0)
942  {
943  if (mxSlideShowController.is())
944  mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
946  }
947  else
948  {
949  if (mxSlideShowController.is())
950  mxSlideShowController->gotoNextEffect();
951  }
952 
953  break;
954 
955  case awt::Key::F1:
956  // Toggle the help view.
957  if (mpWindowManager.get() != nullptr)
958  {
959  if (mpWindowManager->GetViewMode() != PresenterWindowManager::VM_Help)
961  else
962  mpWindowManager->SetHelpViewState(false);
963  }
964 
965  break;
966 
967  default:
968  // Tell all views about the unhandled key event.
969  for (const auto& rxPane : mpPaneContainer->maPanes)
970  {
971  if ( ! rxPane->mbIsActive)
972  continue;
973 
974  Reference<awt::XKeyListener> xKeyListener (rxPane->mxView, UNO_QUERY);
975  if (xKeyListener.is())
976  xKeyListener->keyReleased(rEvent);
977  }
978  break;
979  }
980 }
981 
983  const sal_Int32 nKey,
984  const sal_Int32 nModifiers)
985 {
986  switch (nModifiers)
987  {
988  case 0:
989  if (mnPendingSlideNumber == -1)
992  break;
993 
994  case awt::KeyModifier::MOD1:
995  // Ctrl-1, Ctrl-2, and Ctrl-3 are used to switch between views
996  // (slide view, notes view, normal). Ctrl-4 switches monitors
998  if (mpWindowManager.get() == nullptr)
999  return;
1000  switch(nKey)
1001  {
1002  case 1:
1004  break;
1005  case 2:
1007  break;
1008  case 3:
1010  break;
1011  case 4:
1012  SwitchMonitors();
1013  break;
1014  default:
1015  // Ignore unsupported key.
1016  break;
1017  }
1018  break;
1019 
1020  default:
1021  // Ignore unsupported modifiers.
1022  break;
1023  }
1024 }
1025 
1026 //----- XMouseListener --------------------------------------------------------
1027 
1028 void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent&)
1029 {
1030  if (mxMainWindow.is())
1031  mxMainWindow->setFocus();
1032 }
1033 
1034 void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent&) {}
1035 
1036 void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent&) {}
1037 
1038 void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent&) {}
1039 
1040 void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1041 {
1042  if ( ! rxPane.is())
1043  return;
1044 
1047  this,
1048  rxPane);
1049 
1050  LoadTheme(rxPane);
1051 
1052  // Main pane has been created and is now observed by the window
1053  // manager.
1054  mpWindowManager->SetParentPane(rxPane);
1055  mpWindowManager->SetTheme(mpTheme);
1056 
1057  if (mpPaneBorderPainter.get() != nullptr)
1058  mpPaneBorderPainter->SetTheme(mpTheme);
1059 
1060  // Add key listener
1061  mxMainWindow = rxPane->getWindow();
1062  if (mxMainWindow.is())
1063  {
1064  mxMainWindow->addKeyListener(this);
1065  mxMainWindow->addMouseListener(this);
1066  }
1067  Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1068  if (xPane2.is())
1069  xPane2->setVisible(true);
1070 
1072 
1073  mxCanvas.set(rxPane->getCanvas(), UNO_QUERY);
1074 
1075  if (mxSlideShowController.is())
1076  mxSlideShowController->activate();
1077 
1078  UpdateCurrentSlide(0);
1079 }
1080 
1081 void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1082 {
1083  // Create (load) the current theme.
1084  if (rxPane.is())
1085  mpTheme.reset(new PresenterTheme(mxComponentContext, rxPane->getCanvas()));
1086 }
1087 
1089 {
1090  double nSlideAspectRatio (28.0/21.0);
1091 
1092  try
1093  {
1094  if (mxController.is())
1095  {
1096  Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
1097  mxController->getModel(), UNO_QUERY_THROW);
1098  Reference<drawing::XDrawPages> xSlides (xSlideSupplier->getDrawPages());
1099  if (xSlides.is() && xSlides->getCount()>0)
1100  {
1101  Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
1102  sal_Int32 nWidth (28000);
1103  sal_Int32 nHeight (21000);
1104  if ((xProperties->getPropertyValue("Width") >>= nWidth)
1105  && (xProperties->getPropertyValue("Height") >>= nHeight)
1106  && nHeight > 0)
1107  {
1108  nSlideAspectRatio = double(nWidth) / double(nHeight);
1109  }
1110  }
1111  }
1112  }
1113  catch (RuntimeException&)
1114  {
1115  OSL_ASSERT(false);
1116  }
1117 
1118  return nSlideAspectRatio;
1119 }
1120 
1121 void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1122 {
1123  mnPendingSlideNumber = nPendingSlideNumber;
1124 
1125  if (mpTheme == nullptr)
1126  return;
1127 
1128  if ( ! mxMainWindow.is())
1129  return;
1130 
1132  mpTheme->GetFont("PendingSlideNumberFont"));
1133  if (pFont.get() == nullptr)
1134  return;
1135 
1136  pFont->PrepareFont(mxCanvas);
1137  if ( ! pFont->mxFont.is())
1138  return;
1139 
1140  const OUString sText (OUString::number(mnPendingSlideNumber));
1141  rendering::StringContext aContext (sText, 0, sText.getLength());
1142  pFont->mxFont->createTextLayout(
1143  aContext,
1144  rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1145  0);
1146 }
1147 
1149 {
1150  Reference<lang::XEventListener> xScreen( mxScreen );
1151  if (!xScreen.is())
1152  return;
1153 
1154  PresenterScreen *pScreen = dynamic_cast<PresenterScreen *>(xScreen.get());
1155  if (!pScreen)
1156  return;
1157 
1158  pScreen->SwitchMonitors();
1159 }
1160 
1161 } } // end of namespace ::sdext::presenter
1162 
1163 /* 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
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
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
Reference< drawing::XPresenterHelper > mxPresenterHelper
Synchronize painting of windows and canvases.
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
A theme is a set of properties describing fonts, colors, and bitmaps to be used to draw background...
virtual void SAL_CALL disposing() override
::rtl::Reference< PresenterPaneBorderPainter > mpPaneBorderPainter
virtual void SAL_CALL keyReleased(const css::awt::KeyEvent &rEvent) override
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
css::uno::Reference< css::lang::XComponent > xComponent
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
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
int i
QPRO_FUNC_TYPE const nType
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
css::uno::Reference< css::drawing::XDrawPage > mxNextSlide
const rtl::Reference< PresenterPaneContainer > & GetPaneContainer() const
css::uno::Reference< css::drawing::framework::XConfigurationController > mxConfigurationController
This is the bootstrap class of the presenter screen.
css::uno::Reference< css::drawing::XPresenterHelper > mxPresenterHelper
Reference< XSingleServiceFactory > xFactory
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
::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