1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sdext.hxx"
30 
31 #include "PresenterController.hxx"
32 
33 #include "PresenterAccessibility.hxx"
34 #include "PresenterAnimator.hxx"
35 #include "PresenterCanvasHelper.hxx"
36 #include "PresenterCurrentSlideObserver.hxx"
37 #include "PresenterFrameworkObserver.hxx"
38 #include "PresenterHelper.hxx"
39 #include "PresenterNotesView.hxx"
40 #include "PresenterPaintManager.hxx"
41 #include "PresenterPaneAnimator.hxx"
42 #include "PresenterPaneBase.hxx"
43 #include "PresenterPaneContainer.hxx"
44 #include "PresenterPaneBorderPainter.hxx"
45 #include "PresenterTheme.hxx"
46 #include "PresenterViewFactory.hxx"
47 #include "PresenterWindowManager.hxx"
48 
49 #include <com/sun/star/accessibility/AccessibleRole.hpp>
50 #include <com/sun/star/accessibility/XAccessible.hpp>
51 #include <com/sun/star/awt/Key.hpp>
52 #include <com/sun/star/awt/KeyModifier.hpp>
53 #include <com/sun/star/awt/MouseButton.hpp>
54 #include <com/sun/star/awt/XWindowPeer.hpp>
55 #include <com/sun/star/container/XNamed.hpp>
56 #include <com/sun/star/drawing/XDrawView.hpp>
57 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
58 #include <com/sun/star/drawing/framework/ResourceActivationMode.hpp>
59 #include <com/sun/star/drawing/framework/ResourceId.hpp>
60 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
61 #include <com/sun/star/frame/FrameSearchFlag.hpp>
62 #include <com/sun/star/frame/XDispatchProvider.hpp>
63 #include <com/sun/star/presentation/XPresentation.hpp>
64 #include <com/sun/star/presentation/XPresentationSupplier.hpp>
65 #include <com/sun/star/rendering/CompositeOperation.hpp>
66 #include <com/sun/star/rendering/TextDirection.hpp>
67 
68 #include <rtl/ustrbuf.hxx>
69 #include <boost/bind.hpp>
70 
71 using namespace ::com::sun::star;
72 using namespace ::com::sun::star::uno;
73 using namespace ::com::sun::star::presentation;
74 using namespace ::com::sun::star::drawing::framework;
75 using ::rtl::OUString;
76 using ::rtl::OUStringBuffer;
77 
78 namespace {
79     const sal_Int32 ResourceActivationEventType = 0;
80     const sal_Int32 ResourceDeactivationEventType = 1;
81     const sal_Int32 ConfigurationUpdateEndEventType = 2;
82 }
83 
84 
85 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
86 
87 
88 namespace sdext { namespace presenter {
89 
90 PresenterController::InstanceContainer PresenterController::maInstances;
91 
92 ::rtl::Reference<PresenterController> PresenterController::Instance (
93     const css::uno::Reference<css::frame::XFrame>& rxFrame)
94 {
95     InstanceContainer::const_iterator iInstance (maInstances.find(rxFrame));
96     if (iInstance != maInstances.end())
97         return iInstance->second;
98     else
99         return ::rtl::Reference<PresenterController>();
100 }
101 
102 
103 
104 
105 PresenterController::PresenterController (
106     const Reference<XComponentContext>& rxContext,
107     const Reference<frame::XController>& rxController,
108     const Reference<presentation::XSlideShowController>& rxSlideShowController,
109     const rtl::Reference<PresenterPaneContainer>& rpPaneContainer,
110     const Reference<XResourceId>& rxMainPaneId)
111     : PresenterControllerInterfaceBase(m_aMutex),
112       mxComponentContext(rxContext),
113       mxController(rxController),
114       mxConfigurationController(),
115       mxSlideShowController(rxSlideShowController),
116       mxMainPaneId(rxMainPaneId),
117       mpPaneContainer(rpPaneContainer),
118       mnCurrentSlideIndex(-1),
119       mxCurrentSlide(),
120       mxNextSlide(),
121       mpWindowManager(new PresenterWindowManager(rxContext,mpPaneContainer,this)),
122       mpCurrentPaneAnimation(),
123       mnWindowBackgroundColor(0x00ffffff),
124       mpTheme(),
125       mxMainWindow(),
126       mpPaneBorderPainter(),
127       mpAnimator(new PresenterAnimator()),
128       mpCanvasHelper(new PresenterCanvasHelper()),
129       mxPresenterHelper(),
130       mpPaintManager(),
131       mnPendingSlideNumber(-1),
132       mxUrlTransformer(),
133       mpAccessibleObject(),
134       mbIsAccessibilityActive(false)
135 {
136     OSL_ASSERT(mxController.is());
137 
138     if ( ! mxSlideShowController.is())
139         throw new lang::IllegalArgumentException(
140             A2S("missing slide show controller"),
141             static_cast<XWeak*>(this),
142             2);
143 
144     new PresenterCurrentSlideObserver(this,rxSlideShowController);
145 
146     // Listen for configuration changes.
147     Reference<XControllerManager> xCM (mxController, UNO_QUERY_THROW);
148     mxConfigurationController = xCM->getConfigurationController();
149     if (mxConfigurationController.is())
150     {
151         mxConfigurationController->addConfigurationChangeListener(
152             this,
153             A2S("ResourceActivation"),
154             Any(ResourceActivationEventType));
155         mxConfigurationController->addConfigurationChangeListener(
156             this,
157             A2S("ResourceDeactivation"),
158             Any(ResourceDeactivationEventType));
159         mxConfigurationController->addConfigurationChangeListener(
160             this,
161             A2S("ConfigurationUpdateEnd"),
162             Any(ConfigurationUpdateEndEventType));
163     }
164 
165     // Listen for the frame being activated.
166     Reference<frame::XFrame> xFrame (mxController->getFrame());
167     if (xFrame.is())
168         xFrame->addFrameActionListener(this);
169 
170     // Create the border painter.
171     mpPaneBorderPainter = new PresenterPaneBorderPainter(rxContext);
172     mpWindowManager->SetPaneBorderPainter(mpPaneBorderPainter);
173 
174     // Create an object that is able to load the bitmaps in a format that is
175     // supported by the canvas.
176     Reference<lang::XMultiComponentFactory> xFactory (
177         rxContext->getServiceManager(), UNO_QUERY);
178     if ( ! xFactory.is())
179         return;
180     mxPresenterHelper = Reference<drawing::XPresenterHelper>(
181         xFactory->createInstanceWithContext(
182             A2S("com.sun.star.drawing.PresenterHelper"),
183             rxContext),
184         UNO_QUERY_THROW);
185 
186     if (mxSlideShowController.is())
187     {
188         mxSlideShowController->activate();
189         Reference<beans::XPropertySet> xProperties (mxSlideShowController, UNO_QUERY);
190         if (xProperties.is())
191         {
192             Reference<awt::XWindow> xWindow (
193                 xProperties->getPropertyValue(A2S("ParentWindow")), UNO_QUERY);
194             if (xWindow.is())
195                 xWindow->addKeyListener(this);
196         }
197     }
198 
199     UpdateCurrentSlide(0);
200 
201     maInstances[mxController->getFrame()] = this;
202 
203     // Create a URLTransformer.
204     if (xFactory.is())
205     {
206         mxUrlTransformer = Reference<util::XURLTransformer>(
207             xFactory->createInstanceWithContext(
208                 A2S("com.sun.star.util.URLTransformer"),
209                 mxComponentContext),
210             UNO_QUERY);
211     }
212 }
213 
214 
215 
216 
217 PresenterController::~PresenterController (void)
218 {
219 }
220 
221 
222 
223 
224 void PresenterController::disposing (void)
225 {
226     maInstances.erase(mxController->getFrame());
227 
228     if (mxMainWindow.is())
229     {
230         mxMainWindow->removeKeyListener(this);
231         mxMainWindow->removeFocusListener(this);
232         mxMainWindow->removeMouseListener(this);
233         mxMainWindow->removeMouseMotionListener(this);
234         mxMainWindow = NULL;
235     }
236     if (mxConfigurationController.is())
237         mxConfigurationController->removeConfigurationChangeListener(this);
238 
239     Reference<XComponent> xWindowManagerComponent (
240         static_cast<XWeak*>(mpWindowManager.get()), UNO_QUERY);
241     mpWindowManager = NULL;
242     if (xWindowManagerComponent.is())
243         xWindowManagerComponent->dispose();
244 
245     if (mxController.is())
246     {
247         Reference<frame::XFrame> xFrame (mxController->getFrame());
248         if (xFrame.is())
249             xFrame->removeFrameActionListener(this);
250         mxController = NULL;
251     }
252 
253     mxComponentContext = NULL;
254     mxConfigurationController = NULL;
255     mxSlideShowController = NULL;
256     mxMainPaneId = NULL;
257     mpPaneContainer = NULL;
258     mnCurrentSlideIndex = -1;
259     mxCurrentSlide = NULL;
260     mxNextSlide = NULL;
261     mpCurrentPaneAnimation.reset();
262     mpTheme.reset();
263     {
264         Reference<lang::XComponent> xComponent (
265             static_cast<XWeak*>(mpPaneBorderPainter.get()), UNO_QUERY);
266         mpPaneBorderPainter = NULL;
267         if (xComponent.is())
268             xComponent->dispose();
269     }
270     mpAnimator.reset();
271     mpCanvasHelper.reset();
272     {
273         Reference<lang::XComponent> xComponent (mxPresenterHelper, UNO_QUERY);
274         mxPresenterHelper = NULL;
275         if (xComponent.is())
276             xComponent->dispose();
277     }
278     mpPaintManager.reset();
279     mnPendingSlideNumber = -1;
280     {
281         Reference<lang::XComponent> xComponent (mxUrlTransformer, UNO_QUERY);
282         mxUrlTransformer = NULL;
283         if (xComponent.is())
284             xComponent->dispose();
285     }
286 }
287 
288 
289 
290 
291 void PresenterController::UpdateCurrentSlide (const sal_Int32 nOffset)
292 {
293     GetSlides(nOffset);
294     UpdatePaneTitles();
295     UpdateViews();
296 
297     // Update the accessibility object.
298     if (IsAccessibilityActive())
299     {
300         sal_Int32 nSlideCount (0);
301         Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
302         if (xIndexAccess.is())
303             nSlideCount = xIndexAccess->getCount();
304         mpAccessibleObject->NotifyCurrentSlideChange(mnCurrentSlideIndex, nSlideCount);
305     }
306 }
307 
308 
309 
310 
311 void PresenterController::GetSlides (const sal_Int32 nOffset)
312 {
313     if ( ! mxSlideShowController.is())
314         return;
315 
316     // Get the current slide from the slide show controller.
317     mxCurrentSlide = NULL;
318     Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
319     sal_Int32 nSlideIndex = -1;
320     try
321     {
322         nSlideIndex = mxSlideShowController->getCurrentSlideIndex() + nOffset;
323         if (mxSlideShowController->isPaused())
324             nSlideIndex = -1;
325 
326         if (xIndexAccess.is() && nSlideIndex>=0)
327         {
328             if (nSlideIndex < xIndexAccess->getCount())
329             {
330                 mnCurrentSlideIndex = nSlideIndex;
331                 mxCurrentSlide = Reference<drawing::XDrawPage>(
332                     xIndexAccess->getByIndex(nSlideIndex), UNO_QUERY);
333             }
334         }
335     }
336     catch (RuntimeException&)
337     {
338     }
339 
340     // Get the next slide.
341     mxNextSlide = NULL;
342     try
343     {
344         const sal_Int32 nNextSlideIndex (mxSlideShowController->getNextSlideIndex()+nOffset);
345         if (nNextSlideIndex >= 0)
346         {
347             if (xIndexAccess.is())
348             {
349                 if (nNextSlideIndex < xIndexAccess->getCount())
350                     mxNextSlide = Reference<drawing::XDrawPage>(
351                         xIndexAccess->getByIndex(nNextSlideIndex), UNO_QUERY);
352             }
353         }
354     }
355     catch (RuntimeException&)
356     {
357     }
358 }
359 
360 
361 
362 
363 void PresenterController::UpdatePaneTitles (void)
364 {
365     if ( ! mxSlideShowController.is())
366         return;
367 
368     // Get placeholders and their values.
369     const OUString sCurrentSlideNumberPlaceholder (A2S("CURRENT_SLIDE_NUMBER"));
370     const OUString sCurrentSlideNamePlaceholder (A2S("CURRENT_SLIDE_NAME"));
371     const OUString sSlideCountPlaceholder (A2S("SLIDE_COUNT"));
372 
373     // Get string for slide count.
374     OUString sSlideCount (A2S("---"));
375     Reference<container::XIndexAccess> xIndexAccess(mxSlideShowController, UNO_QUERY);
376     if (xIndexAccess.is())
377         sSlideCount = OUString::valueOf(xIndexAccess->getCount());
378 
379     // Get string for current slide index.
380     OUString sCurrentSlideNumber (OUString::valueOf(mnCurrentSlideIndex + 1));
381 
382     // Get name of the current slide.
383     OUString sCurrentSlideName;
384     Reference<container::XNamed> xNamedSlide (mxCurrentSlide, UNO_QUERY);
385     if (xNamedSlide.is())
386         sCurrentSlideName = xNamedSlide->getName();
387     Reference<beans::XPropertySet> xSlideProperties (mxCurrentSlide, UNO_QUERY);
388     if (xSlideProperties.is())
389     {
390         try
391         {
392             OUString sName;
393             if (xSlideProperties->getPropertyValue(A2S("LinkDisplayName")) >>= sName)
394             {
395                 // Find out whether the name of the current slide has been
396                 // automatically created or has been set by the user.
397                 if (sName != sCurrentSlideName)
398                     sCurrentSlideName = sName;
399             }
400         }
401         catch (beans::UnknownPropertyException&)
402         {
403         }
404     }
405 
406     // Replace the placeholders with their current values.
407     PresenterPaneContainer::PaneList::const_iterator iPane;
408     for (iPane=mpPaneContainer->maPanes.begin(); iPane!=mpPaneContainer->maPanes.end(); ++iPane)
409     {
410         OSL_ASSERT((*iPane).get() != NULL);
411 
412         OUString sTemplate (IsAccessibilityActive()
413             ? (*iPane)->msAccessibleTitleTemplate
414             : (*iPane)->msTitleTemplate);
415         if (sTemplate.getLength() <= 0)
416             continue;
417 
418         OUStringBuffer sResult;
419         sResult.ensureCapacity(sTemplate.getLength());
420 
421         sal_Int32 nIndex (0);
422         while (true)
423         {
424             sal_Int32 nStartIndex = sTemplate.indexOf('%', nIndex);
425             if (nStartIndex < 0)
426             {
427                 // Add the remaining part of the string.
428                 sResult.append(sTemplate.copy(nIndex, sTemplate.getLength()-nIndex));
429                 break;
430             }
431             else
432             {
433                 // Add the part preceding the next %.
434                 sResult.append(sTemplate.copy(nIndex, nStartIndex-nIndex));
435 
436                 // Get the placeholder
437                 ++nIndex;
438                 ++nStartIndex;
439                 const sal_Int32 nEndIndex (sTemplate.indexOf('%', nStartIndex+1));
440                 const OUString sPlaceholder (sTemplate.copy(nStartIndex, nEndIndex-nStartIndex));
441                 nIndex = nEndIndex+1;
442 
443                 // Replace the placeholder with its current value.
444                 if (sPlaceholder == sCurrentSlideNumberPlaceholder)
445                     sResult.append(sCurrentSlideNumber);
446                 else if (sPlaceholder == sCurrentSlideNamePlaceholder)
447                     sResult.append(sCurrentSlideName);
448                 else if (sPlaceholder == sSlideCountPlaceholder)
449                     sResult.append(sSlideCount);
450             }
451         }
452 
453         (*iPane)->msTitle = sResult.makeStringAndClear();
454         if ((*iPane)->mxPane.is())
455             (*iPane)->mxPane->SetTitle((*iPane)->msTitle);
456     }
457 }
458 
459 
460 
461 
462 void PresenterController::UpdateViews (void)
463 {
464     // Tell all views about the slides they should display.
465     PresenterPaneContainer::PaneList::const_iterator iPane;
466     for (iPane=mpPaneContainer->maPanes.begin(); iPane!=mpPaneContainer->maPanes.end(); ++iPane)
467     {
468         Reference<drawing::XDrawView> xDrawView ((*iPane)->mxView, UNO_QUERY);
469         if (xDrawView.is())
470             xDrawView->setCurrentPage(mxCurrentSlide);
471     }
472 }
473 
474 
475 
476 
477 SharedBitmapDescriptor
478     PresenterController::GetViewBackground (const ::rtl::OUString& rsViewURL) const
479 {
480     if (mpTheme.get() != NULL)
481     {
482         const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
483         return mpTheme->GetBitmap(sStyleName, A2S("Background"));
484     }
485     return SharedBitmapDescriptor();
486 }
487 
488 
489 
490 
491 PresenterTheme::SharedFontDescriptor
492     PresenterController::GetViewFont (const ::rtl::OUString& rsViewURL) const
493 {
494     if (mpTheme.get() != NULL)
495     {
496         const OUString sStyleName (mpTheme->GetStyleName(rsViewURL));
497         return mpTheme->GetFont(sStyleName);
498     }
499     return PresenterTheme::SharedFontDescriptor();
500 }
501 
502 
503 
504 
505 ::boost::shared_ptr<PresenterTheme> PresenterController::GetTheme (void) const
506 {
507     return mpTheme;
508 }
509 
510 
511 
512 
513 ::rtl::Reference<PresenterWindowManager> PresenterController::GetWindowManager (void) const
514 {
515     return mpWindowManager;
516 }
517 
518 
519 
520 
521 Reference<presentation::XSlideShowController>
522     PresenterController::GetSlideShowController(void) const
523 {
524     return mxSlideShowController;
525 }
526 
527 
528 
529 
530 rtl::Reference<PresenterPaneContainer> PresenterController::GetPaneContainer (void) const
531 {
532     return mpPaneContainer;
533 }
534 
535 
536 
537 
538 ::rtl::Reference<PresenterPaneBorderPainter> PresenterController::GetPaneBorderPainter (void) const
539 {
540     return mpPaneBorderPainter;
541 }
542 
543 
544 
545 
546 ::boost::shared_ptr<PresenterAnimator> PresenterController::GetAnimator (void) const
547 {
548     return mpAnimator;
549 }
550 
551 
552 
553 
554 ::boost::shared_ptr<PresenterCanvasHelper> PresenterController::GetCanvasHelper (void) const
555 {
556     return mpCanvasHelper;
557 }
558 
559 
560 
561 
562 Reference<drawing::XPresenterHelper> PresenterController::GetPresenterHelper (void) const
563 {
564     return mxPresenterHelper;
565 }
566 
567 
568 
569 
570 ::boost::shared_ptr<PresenterPaintManager> PresenterController::GetPaintManager (void) const
571 {
572     return mpPaintManager;
573 }
574 
575 
576 
577 
578 void PresenterController::HideSlideSorter (void)
579 {
580     if (mpCurrentPaneAnimation.get() != NULL)
581     {
582         mpCurrentPaneAnimation->HidePane();
583         mpCurrentPaneAnimation.reset();
584     }
585 }
586 
587 
588 
589 
590 void PresenterController::ShowView (const OUString& rsViewURL)
591 {
592     PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
593         mpPaneContainer->FindViewURL(rsViewURL));
594     if (pDescriptor.get() != NULL)
595     {
596         pDescriptor->mbIsActive = true;
597         mxConfigurationController->requestResourceActivation(
598             pDescriptor->mxPaneId,
599             ResourceActivationMode_ADD);
600         mxConfigurationController->requestResourceActivation(
601             ResourceId::createWithAnchor(
602                 mxComponentContext,
603                 rsViewURL,
604                 pDescriptor->mxPaneId),
605             ResourceActivationMode_REPLACE);
606     }
607 }
608 
609 
610 
611 
612 void PresenterController::HideView (const OUString& rsViewURL)
613 {
614     PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
615         mpPaneContainer->FindViewURL(rsViewURL));
616     if (pDescriptor.get() != NULL)
617     {
618         mxConfigurationController->requestResourceDeactivation(
619             ResourceId::createWithAnchor(
620                 mxComponentContext,
621                 rsViewURL,
622                 pDescriptor->mxPaneId));
623     }
624 }
625 
626 
627 
628 
629 bool PresenterController::IsViewVisible (const OUString& rsViewURL) const
630 {
631    PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
632         mpPaneContainer->FindViewURL(rsViewURL));
633     if (pDescriptor.get() != NULL)
634     {
635         return mxConfigurationController->getResource(
636             ResourceId::createWithAnchor(
637                 mxComponentContext,
638                 rsViewURL,
639                 pDescriptor->mxPaneId)).is();
640     }
641     return false;
642 }
643 
644 
645 
646 
647 void PresenterController::DispatchUnoCommand (const OUString& rsCommand) const
648 {
649     if ( ! mxUrlTransformer.is())
650         return;
651 
652     util::URL aURL;
653     aURL.Complete = rsCommand;
654     mxUrlTransformer->parseStrict(aURL);
655 
656     Reference<frame::XDispatch> xDispatch (GetDispatch(aURL));
657     if ( ! xDispatch.is())
658         return;
659 
660     xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>());
661 }
662 
663 
664 
665 
666 Reference<css::frame::XDispatch> PresenterController::GetDispatch (const util::URL& rURL) const
667 {
668     if ( ! mxController.is())
669         return NULL;
670 
671     Reference<frame::XDispatchProvider> xDispatchProvider (mxController->getFrame(), UNO_QUERY);
672     if ( ! xDispatchProvider.is())
673         return NULL;
674 
675     return xDispatchProvider->queryDispatch(
676         rURL,
677         OUString(),
678         frame::FrameSearchFlag::SELF);
679 }
680 
681 
682 
683 
684 util::URL PresenterController::CreateURLFromString (const ::rtl::OUString& rsURL) const
685 {
686     util::URL aURL;
687 
688     if (mxUrlTransformer.is())
689     {
690         aURL.Complete = rsURL;
691         mxUrlTransformer->parseStrict(aURL);
692     }
693 
694     return aURL;
695 }
696 
697 
698 
699 
700 Reference<drawing::framework::XConfigurationController>
701     PresenterController::GetConfigurationController (void) const
702 {
703     return mxConfigurationController;
704 }
705 
706 
707 
708 
709 Reference<drawing::XDrawPage> PresenterController::GetCurrentSlide (void) const
710 {
711     return mxCurrentSlide;
712 }
713 
714 
715 
716 
717 ::rtl::Reference<PresenterAccessible> PresenterController::GetAccessible (void) const
718 {
719     return mpAccessibleObject;
720 }
721 
722 
723 
724 
725 void PresenterController::SetAccessibilityActiveState (const bool bIsActive)
726 {
727     if ( mbIsAccessibilityActive != bIsActive)
728     {
729         mbIsAccessibilityActive = bIsActive;
730         UpdatePaneTitles();
731     }
732 }
733 
734 
735 
736 
737 bool PresenterController::IsAccessibilityActive (void) const
738 {
739     return mbIsAccessibilityActive;
740 }
741 
742 
743 
744 
745 void PresenterController::HandleMouseClick (const awt::MouseEvent& rEvent)
746 {
747     if (mxSlideShowController.is())
748     {
749         switch (rEvent.Buttons)
750         {
751             case awt::MouseButton::LEFT:
752                 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
753                     mxSlideShowController->gotoNextSlide();
754                 else
755                     mxSlideShowController->gotoNextEffect();
756                 break;
757 
758             case awt::MouseButton::RIGHT:
759                 mxSlideShowController->gotoPreviousSlide();
760                 break;
761 
762             default:
763                 // Other or multiple buttons.
764                 break;
765         }
766     }
767 }
768 
769 
770 
771 
772 void PresenterController::RequestViews (
773     const bool bIsSlideSorterActive,
774     const bool bIsNotesViewActive,
775     const bool bIsHelpViewActive)
776 {
777     PresenterPaneContainer::PaneList::const_iterator iPane;
778     PresenterPaneContainer::PaneList::const_iterator iEnd (mpPaneContainer->maPanes.end());
779     for (iPane=mpPaneContainer->maPanes.begin(); iPane!=iEnd; ++iPane)
780     {
781         bool bActivate (true);
782         const OUString sViewURL ((*iPane)->msViewURL);
783         if (sViewURL == PresenterViewFactory::msNotesViewURL)
784         {
785             bActivate = bIsNotesViewActive && !bIsSlideSorterActive && !bIsHelpViewActive;
786         }
787         else if (sViewURL == PresenterViewFactory::msSlideSorterURL)
788         {
789             bActivate = bIsSlideSorterActive;
790         }
791         else if (sViewURL == PresenterViewFactory::msCurrentSlidePreviewViewURL
792             || sViewURL == PresenterViewFactory::msNextSlidePreviewViewURL)
793         {
794             bActivate = !bIsSlideSorterActive && ! bIsHelpViewActive;
795         }
796         else if (sViewURL == PresenterViewFactory::msToolBarViewURL)
797         {
798             bActivate = true;
799         }
800         else if (sViewURL == PresenterViewFactory::msHelpViewURL)
801         {
802             bActivate = bIsHelpViewActive;
803         }
804 
805         if (bActivate)
806             ShowView(sViewURL);
807         else
808             HideView(sViewURL);
809     }
810 }
811 
812 
813 
814 
815 //----- XConfigurationChangeListener ------------------------------------------
816 
817 void SAL_CALL PresenterController::notifyConfigurationChange (
818     const ConfigurationChangeEvent& rEvent)
819     throw (RuntimeException)
820 {
821     ThrowIfDisposed();
822 
823     sal_Int32 nType (0);
824     if ( ! (rEvent.UserData >>= nType))
825         return;
826 
827     switch (nType)
828     {
829         case ResourceActivationEventType:
830             if (rEvent.ResourceId->compareTo(mxMainPaneId) == 0)
831             {
832                 InitializeMainPane(Reference<XPane>(rEvent.ResourceObject,UNO_QUERY));
833             }
834             else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_DIRECT))
835             {
836                 // A pane bound to the main pane has been created and is
837                 // stored in the pane container.
838                 Reference<XPane> xPane (rEvent.ResourceObject,UNO_QUERY);
839                 if (xPane.is())
840                 {
841                     PresenterPaneContainer::SharedPaneDescriptor pDescriptor (
842                         mpPaneContainer->FindPaneId(xPane->getResourceId()));
843 
844                     // When there is a call out anchor location set then tell the
845                     // window about it.
846                     if (pDescriptor->mbHasCalloutAnchor)
847                         pDescriptor->mxPane->SetCalloutAnchor(
848                             pDescriptor->maCalloutAnchorLocation);
849                 }
850             }
851             else if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
852             {
853                 // A view bound to one of the panes has been created and is
854                 // stored in the pane container along with its pane.
855                 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
856                 if (xView.is())
857                 {
858                     SharedBitmapDescriptor pViewBackground(
859                         GetViewBackground(xView->getResourceId()->getResourceURL()));
860                     mpPaneContainer->StoreView(xView, pViewBackground);
861                     UpdateViews();
862                     mpWindowManager->NotifyViewCreation(xView);
863                 }
864             }
865             break;
866 
867         case ResourceDeactivationEventType:
868             if (rEvent.ResourceId->isBoundTo(mxMainPaneId,AnchorBindingMode_INDIRECT))
869             {
870                 // If this is a view then remove it from the pane container.
871                 Reference<XView> xView (rEvent.ResourceObject,UNO_QUERY);
872                 if (xView.is())
873                 {
874                     PresenterPaneContainer::SharedPaneDescriptor pDescriptor(
875                         mpPaneContainer->RemoveView(xView));
876 
877                     // A possibly opaque view has been removed.  Update()
878                     // updates the clip polygon.
879                     mpWindowManager->Update();
880                     // Request the repainting of the area previously
881                     // occupied by the view.
882                     if (pDescriptor.get() != NULL)
883                         GetPaintManager()->Invalidate(pDescriptor->mxBorderWindow);
884                 }
885             }
886             break;
887 
888         case ConfigurationUpdateEndEventType:
889             if (IsAccessibilityActive())
890             {
891                 mpAccessibleObject->UpdateAccessibilityHierarchy();
892                 UpdateCurrentSlide(0);
893             }
894             break;
895     }
896 }
897 
898 
899 
900 
901 //----- XEventListener --------------------------------------------------------
902 
903 void SAL_CALL PresenterController::disposing (
904     const lang::EventObject& rEvent)
905     throw (RuntimeException)
906 {
907     if (rEvent.Source == mxController)
908         mxController = NULL;
909     else if (rEvent.Source == mxConfigurationController)
910         mxConfigurationController = NULL;
911     else if (rEvent.Source == mxSlideShowController)
912         mxSlideShowController = NULL;
913     else if (rEvent.Source == mxMainWindow)
914         mxMainWindow = NULL;
915 }
916 
917 
918 
919 
920 //----- XFrameActionListener --------------------------------------------------
921 
922 void SAL_CALL PresenterController::frameAction (
923     const frame::FrameActionEvent& rEvent)
924     throw (RuntimeException)
925 {
926     if (rEvent.Action == frame::FrameAction_FRAME_ACTIVATED)
927     {
928         if (mxSlideShowController.is())
929             mxSlideShowController->activate();
930     }
931 }
932 
933 
934 
935 
936 //----- XKeyListener ----------------------------------------------------------
937 
938 void SAL_CALL PresenterController::keyPressed (const awt::KeyEvent& rEvent)
939     throw (RuntimeException)
940 {
941     // Tell all views about the unhandled key event.
942     PresenterPaneContainer::PaneList::const_iterator iPane;
943     for (iPane=mpPaneContainer->maPanes.begin(); iPane!=mpPaneContainer->maPanes.end(); ++iPane)
944     {
945         if ( ! (*iPane)->mbIsActive)
946             continue;
947 
948         Reference<awt::XKeyListener> xKeyListener ((*iPane)->mxView, UNO_QUERY);
949         if (xKeyListener.is())
950             xKeyListener->keyPressed(rEvent);
951     }
952 }
953 
954 
955 
956 
957 void SAL_CALL PresenterController::keyReleased (const awt::KeyEvent& rEvent)
958     throw (RuntimeException)
959 {
960     if (rEvent.Source != mxMainWindow)
961         return;
962 
963     switch (rEvent.KeyCode)
964     {
965         case awt::Key::ESCAPE:
966         case awt::Key::SUBTRACT:
967         {
968 			if( mxController.is() )
969 			{
970 				Reference< XPresentationSupplier > xPS( mxController->getModel(), UNO_QUERY );
971 				if( xPS.is() )
972 				{
973 					Reference< XPresentation > xP( xPS->getPresentation() );
974 					if( xP.is() )
975 						xP->end();
976 				}
977 			}
978         }
979         break;
980 
981         case awt::Key::PAGEDOWN:
982             if (mxSlideShowController.is())
983             {
984                 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
985                     mxSlideShowController->gotoNextSlide();
986                 else
987                     mxSlideShowController->gotoNextEffect();
988             }
989             break;
990 
991         case awt::Key::RIGHT:
992         case awt::Key::SPACE:
993         case awt::Key::DOWN:
994         case awt::Key::N:
995             if (mxSlideShowController.is())
996             {
997                 mxSlideShowController->gotoNextEffect();
998             }
999             break;
1000 
1001         case awt::Key::LEFT:
1002         case awt::Key::PAGEUP:
1003             if (mxSlideShowController.is())
1004             {
1005                 if (rEvent.Modifiers == awt::KeyModifier::MOD2)
1006                     mxSlideShowController->gotoPreviousSlide();
1007                 else
1008                     mxSlideShowController->gotoPreviousEffect();
1009             }
1010             break;
1011 
1012         case awt::Key::UP:
1013         case awt::Key::P:
1014         case awt::Key::BACKSPACE:
1015             if (mxSlideShowController.is())
1016             {
1017                 mxSlideShowController->gotoPreviousEffect();
1018             }
1019             break;
1020 
1021         case awt::Key::HOME:
1022             if (mxSlideShowController.is())
1023             {
1024                 mxSlideShowController->gotoFirstSlide();
1025             }
1026             break;
1027 
1028         case awt::Key::END:
1029             if (mxSlideShowController.is())
1030             {
1031                 mxSlideShowController->gotoLastSlide();
1032             }
1033             break;
1034 
1035         case awt::Key::W:
1036         case awt::Key::COMMA:
1037             if (mxSlideShowController.is())
1038             {
1039                 if (mxSlideShowController->isPaused())
1040                     mxSlideShowController->resume();
1041                 else
1042                     mxSlideShowController->blankScreen(0x00ffffff);
1043             }
1044             break;
1045 
1046         case awt::Key::B:
1047         case awt::Key::POINT:
1048             if (mxSlideShowController.is())
1049             {
1050                 if (mxSlideShowController->isPaused())
1051                     mxSlideShowController->resume();
1052                 else
1053                     mxSlideShowController->blankScreen(0x00000000);
1054             }
1055             break;
1056 
1057         case awt::Key::NUM0:
1058         case awt::Key::NUM1:
1059         case awt::Key::NUM2:
1060         case awt::Key::NUM3:
1061         case awt::Key::NUM4:
1062         case awt::Key::NUM5:
1063         case awt::Key::NUM6:
1064         case awt::Key::NUM7:
1065         case awt::Key::NUM8:
1066         case awt::Key::NUM9:
1067             HandleNumericKeyPress(rEvent.KeyCode-awt::Key::NUM0, rEvent.Modifiers);
1068             break;
1069 
1070         case awt::Key::RETURN:
1071             if (mnPendingSlideNumber > 0)
1072             {
1073                 if (mxSlideShowController.is())
1074                     mxSlideShowController->gotoSlideIndex(mnPendingSlideNumber - 1);
1075                 mnPendingSlideNumber = -1;
1076             }
1077             else
1078             {
1079                 if (mxSlideShowController.is())
1080                     mxSlideShowController->gotoNextEffect();
1081             }
1082 
1083             break;
1084 
1085         case awt::Key::F1:
1086             // Toggle the help view.
1087             if (mpWindowManager.get() != NULL)
1088             {
1089                 if (mpWindowManager->GetViewMode() != PresenterWindowManager::VM_Help)
1090                     mpWindowManager->SetViewMode(PresenterWindowManager::VM_Help);
1091                 else
1092                     mpWindowManager->SetHelpViewState(false);
1093             }
1094 
1095             break;
1096 
1097         default:
1098             // Tell all views about the unhandled key event.
1099             PresenterPaneContainer::PaneList::const_iterator iPane;
1100             for (iPane=mpPaneContainer->maPanes.begin(); iPane!=mpPaneContainer->maPanes.end(); ++iPane)
1101             {
1102                 if ( ! (*iPane)->mbIsActive)
1103                     continue;
1104 
1105                 Reference<awt::XKeyListener> xKeyListener ((*iPane)->mxView, UNO_QUERY);
1106                 if (xKeyListener.is())
1107                     xKeyListener->keyReleased(rEvent);
1108             }
1109             break;
1110     }
1111 }
1112 
1113 
1114 
1115 
1116 void PresenterController::HandleNumericKeyPress (
1117     const sal_Int32 nKey,
1118     const sal_Int32 nModifiers)
1119 {
1120     switch (nModifiers)
1121     {
1122         case 0:
1123             if (mnPendingSlideNumber == -1)
1124                 mnPendingSlideNumber = 0;
1125             UpdatePendingSlideNumber(mnPendingSlideNumber * 10 + nKey);
1126             break;
1127 
1128         case awt::KeyModifier::MOD1:
1129             // Ctrl-1, Ctrl-2, and Ctrl-3 are used to switch between views
1130             // (slide view, notes view, normal)
1131             mnPendingSlideNumber = -1;
1132             if (mpWindowManager.get() == NULL)
1133                 return;
1134             switch(nKey)
1135             {
1136                 case 1:
1137                     mpWindowManager->SetViewMode(PresenterWindowManager::VM_Standard);
1138                     break;
1139                 case 2:
1140                     mpWindowManager->SetViewMode(PresenterWindowManager::VM_Notes);
1141                     break;
1142                 case 3:
1143                     mpWindowManager->SetViewMode(PresenterWindowManager::VM_SlideOverview);
1144                     break;
1145                 default:
1146                     // Ignore unsupported key.
1147                     break;
1148             }
1149 
1150         default:
1151             // Ignore unsupported modifiers.
1152             break;
1153     }
1154 }
1155 
1156 
1157 
1158 
1159 //----- XFocusListener --------------------------------------------------------
1160 
1161 void SAL_CALL PresenterController::focusGained (const css::awt::FocusEvent& rEvent)
1162     throw (css::uno::RuntimeException)
1163 {
1164     (void)rEvent;
1165 }
1166 
1167 
1168 
1169 
1170 void SAL_CALL PresenterController::focusLost (const css::awt::FocusEvent& rEvent)
1171     throw (css::uno::RuntimeException)
1172 {
1173     (void)rEvent;
1174 }
1175 
1176 
1177 
1178 
1179 //----- XMouseListener --------------------------------------------------------
1180 
1181 void SAL_CALL PresenterController::mousePressed (const css::awt::MouseEvent& rEvent)
1182     throw (css::uno::RuntimeException)
1183 {
1184     (void)rEvent;
1185     if (mxMainWindow.is())
1186         mxMainWindow->setFocus();
1187 }
1188 
1189 
1190 
1191 
1192 void SAL_CALL PresenterController::mouseReleased (const css::awt::MouseEvent& rEvent)
1193     throw (css::uno::RuntimeException)
1194 {
1195     (void)rEvent;
1196 }
1197 
1198 
1199 
1200 
1201 void SAL_CALL PresenterController::mouseEntered (const css::awt::MouseEvent& rEvent)
1202     throw (css::uno::RuntimeException)
1203 {
1204     (void)rEvent;
1205 }
1206 
1207 
1208 
1209 
1210 void SAL_CALL PresenterController::mouseExited (const css::awt::MouseEvent& rEvent)
1211     throw (css::uno::RuntimeException)
1212 {
1213     (void)rEvent;
1214 }
1215 
1216 
1217 
1218 
1219 //----- XMouseMotionListener --------------------------------------------------
1220 
1221 void SAL_CALL PresenterController::mouseMoved (const css::awt::MouseEvent& rEvent)
1222     throw (css::uno::RuntimeException)
1223 {
1224     (void)rEvent;
1225 }
1226 
1227 
1228 
1229 
1230 void SAL_CALL PresenterController::mouseDragged (const css::awt::MouseEvent& rEvent)
1231     throw (css::uno::RuntimeException)
1232 {
1233     (void)rEvent;
1234 }
1235 
1236 
1237 
1238 
1239 //-----------------------------------------------------------------------------
1240 
1241 void PresenterController::InitializeMainPane (const Reference<XPane>& rxPane)
1242 {
1243     if ( ! rxPane.is())
1244         return;
1245 
1246     mpAccessibleObject = new PresenterAccessible(
1247         mxComponentContext,
1248         this,
1249         rxPane);
1250 
1251     LoadTheme(rxPane);
1252 
1253     // Main pane has been created and is now observed by the window
1254     // manager.
1255     mpWindowManager->SetParentPane(rxPane);
1256     mpWindowManager->SetTheme(mpTheme);
1257 
1258     if (mpPaneBorderPainter.get() != NULL)
1259         mpPaneBorderPainter->SetTheme(mpTheme);
1260 
1261     // Add key listener
1262     mxMainWindow = rxPane->getWindow();
1263     if (mxMainWindow.is())
1264     {
1265         mxMainWindow->addKeyListener(this);
1266         mxMainWindow->addFocusListener(this);
1267         mxMainWindow->addMouseListener(this);
1268         mxMainWindow->addMouseMotionListener(this);
1269     }
1270     Reference<XPane2> xPane2 (rxPane, UNO_QUERY);
1271     if (xPane2.is())
1272         xPane2->setVisible(sal_True);
1273 
1274     mpPaintManager.reset(new PresenterPaintManager(mxMainWindow, mxPresenterHelper, mpPaneContainer));
1275 
1276     mxCanvas = Reference<rendering::XSpriteCanvas>(rxPane->getCanvas(), UNO_QUERY);
1277 
1278     if (mxSlideShowController.is())
1279         mxSlideShowController->activate();
1280 
1281     UpdateCurrentSlide(0);
1282 }
1283 
1284 
1285 
1286 
1287 void PresenterController::LoadTheme (const Reference<XPane>& rxPane)
1288 {
1289     // Create (load) the current theme.
1290     if (rxPane.is())
1291         mpTheme.reset(new PresenterTheme(mxComponentContext, OUString(), rxPane->getCanvas()));
1292 }
1293 
1294 
1295 
1296 
1297 double PresenterController::GetSlideAspectRatio (void) const
1298 {
1299     double nSlideAspectRatio (28.0/21.0);
1300 
1301     try
1302     {
1303         if (mxController.is())
1304         {
1305             Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
1306                 mxController->getModel(), UNO_QUERY_THROW);
1307             Reference<drawing::XDrawPages> xSlides (xSlideSupplier->getDrawPages());
1308             if (xSlides.is() && xSlides->getCount()>0)
1309             {
1310                 Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
1311                 sal_Int32 nWidth (28000);
1312                 sal_Int32 nHeight (21000);
1313                 if ((xProperties->getPropertyValue(OUString::createFromAscii("Width")) >>= nWidth)
1314                     && (xProperties->getPropertyValue(OUString::createFromAscii("Height")) >>= nHeight)
1315                     && nHeight > 0)
1316                 {
1317                     nSlideAspectRatio = double(nWidth) / double(nHeight);
1318                 }
1319             }
1320         }
1321     }
1322     catch (RuntimeException&)
1323     {
1324         OSL_ASSERT(false);
1325     }
1326 
1327     return nSlideAspectRatio;
1328 }
1329 
1330 
1331 
1332 
1333 void PresenterController::UpdatePendingSlideNumber (const sal_Int32 nPendingSlideNumber)
1334 {
1335     mnPendingSlideNumber = nPendingSlideNumber;
1336 
1337     if (mpTheme.get() == NULL)
1338         return;
1339 
1340     if ( ! mxMainWindow.is())
1341         return;
1342 
1343     PresenterTheme::SharedFontDescriptor pFont (
1344         mpTheme->GetFont(A2S("PendingSlideNumberFont")));
1345     if (pFont.get() == NULL)
1346         return;
1347 
1348     pFont->PrepareFont(Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY));
1349     if ( ! pFont->mxFont.is())
1350         return;
1351 
1352     const OUString sText (OUString::valueOf(mnPendingSlideNumber));
1353     rendering::StringContext aContext (sText, 0, sText.getLength());
1354     Reference<rendering::XTextLayout> xLayout (
1355         pFont->mxFont->createTextLayout(
1356             aContext,
1357             rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1358             0));
1359 }
1360 
1361 
1362 
1363 
1364 void PresenterController::ThrowIfDisposed (void) const
1365     throw (::com::sun::star::lang::DisposedException)
1366 {
1367 	if (rBHelper.bDisposed || rBHelper.bInDispose)
1368 	{
1369         throw lang::DisposedException (
1370             OUString(RTL_CONSTASCII_USTRINGPARAM(
1371                 "PresenterController object has already been disposed")),
1372             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1373     }
1374 }
1375 
1376 
1377 } } // end of namespace ::sdext::presenter
1378 
1379