LibreOffice Module sdext (master)  1
PresenterProtocolHandler.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 <memory>
22 #include "PresenterController.hxx"
23 #include "PresenterNotesView.hxx"
25 #include "PresenterViewFactory.hxx"
27 #include <cppuhelper/compbase.hxx>
29 #include <algorithm>
30 
31 using namespace ::com::sun::star;
32 using namespace ::com::sun::star::uno;
33 using namespace ::com::sun::star::drawing::framework;
34 
35 namespace sdext::presenter {
36 
37 namespace {
38  class Command
39  {
40  public:
41  virtual ~Command() {}
42  virtual void Execute() = 0;
43  virtual bool IsEnabled() const { return true; }
44  virtual Any GetState() const { return Any(false); }
45  };
46 
47  class GotoPreviousSlideCommand : public Command
48  {
49  public:
50  explicit GotoPreviousSlideCommand (
51  const rtl::Reference<PresenterController>& rpPresenterController);
52  virtual void Execute() override;
53  virtual bool IsEnabled() const override;
54  private:
56  };
57 
58  class GotoNextSlideCommand : public Command
59  {
60  public:
61  explicit GotoNextSlideCommand (
62  const rtl::Reference<PresenterController>& rpPresenterController);
63  virtual void Execute() override;
64  // The next slide command is always enabled, even when the current slide
65  // is the last slide: from the last slide it goes to the pause slide,
66  // and from there it ends the slide show.
67  virtual bool IsEnabled() const override { return true; }
68  private:
70  };
71 
72  class GotoNextEffectCommand : public Command
73  {
74  public:
75  explicit GotoNextEffectCommand (
76  const rtl::Reference<PresenterController>& rpPresenterController);
77  virtual void Execute() override;
78  virtual bool IsEnabled() const override;
79  private:
81  };
82 
83  class SwitchMonitorCommand : public Command
84  {
85  public:
86  explicit SwitchMonitorCommand (
87  const rtl::Reference<PresenterController>& rpPresenterController);
88  virtual void Execute() override;
89  private:
91  };
92 
94  class RestartTimerCommand : public Command
95  {
96  public:
97  explicit RestartTimerCommand(const rtl::Reference<PresenterController>& rpPresenterController);
98  virtual void Execute() override;
99  private:
101  };
102 
103  class SetNotesViewCommand : public Command
104  {
105  public:
106  SetNotesViewCommand (
107  const bool bOn,
108  const rtl::Reference<PresenterController>& rpPresenterController);
109  virtual void Execute() override;
110  virtual Any GetState() const override;
111  private:
112  bool mbOn;
114  };
115 
116  class SetSlideSorterCommand : public Command
117  {
118  public:
119  SetSlideSorterCommand (
120  const bool bOn,
121  const rtl::Reference<PresenterController>& rpPresenterController);
122  virtual void Execute() override;
123  virtual Any GetState() const override;
124  private:
125  bool mbOn;
127  };
128 
129  class SetHelpViewCommand : public Command
130  {
131  public:
132  SetHelpViewCommand (
133  const bool bOn,
134  const rtl::Reference<PresenterController>& rpPresenterController);
135  virtual void Execute() override;
136  virtual Any GetState() const override;
137  private:
138  bool mbOn;
140  };
141 
142  class NotesFontSizeCommand : public Command
143  {
144  public:
145  NotesFontSizeCommand(
146  const rtl::Reference<PresenterController>& rpPresenterController,
147  const sal_Int32 nSizeChange);
148  virtual void Execute() override;
149  virtual Any GetState() const override;
150  protected:
151  ::rtl::Reference<PresenterNotesView> GetNotesView() const;
152  private:
154  const sal_Int32 mnSizeChange;
155  };
156 
157 } // end of anonymous namespace
158 
159 namespace {
160  typedef ::cppu::WeakComponentImplHelper <
161  css::frame::XDispatch,
162  css::document::XEventListener
163  > PresenterDispatchInterfaceBase;
164 }
165 
167  : protected ::cppu::BaseMutex,
168  public PresenterDispatchInterfaceBase
169 {
170 public:
175  const OUString& rsURLPath,
176  const ::rtl::Reference<PresenterController>& rpPresenterController);
177 
178  void SAL_CALL disposing() override;
179  static Command* CreateCommand (
180  const OUString& rsURLPath,
181  const ::rtl::Reference<PresenterController>& rpPresenterController);
182 
183  // XDispatch
184  virtual void SAL_CALL dispatch(
185  const css::util::URL& aURL,
186  const css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
187 
188  virtual void SAL_CALL addStatusListener(
189  const css::uno::Reference<css::frame::XStatusListener>& rxListener,
190  const css::util::URL& rURL) override;
191 
192  virtual void SAL_CALL removeStatusListener (
193  const css::uno::Reference<css::frame::XStatusListener>& rxListener,
194  const css::util::URL& rURL) override;
195 
196  // document::XEventListener
197 
198  virtual void SAL_CALL notifyEvent (const css::document::EventObject& rEvent) override;
199 
200  // lang::XEventListener
201 
202  virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
203 
204 private:
205  OUString msURLPath;
206  std::unique_ptr<Command> mpCommand;
208  typedef ::std::vector<Reference<frame::XStatusListener> > StatusListenerContainer;
209  StatusListenerContainer maStatusListenerContainer;
211 
212  Dispatch (
213  const OUString& rsURLPath,
214  const ::rtl::Reference<PresenterController>& rpPresenterController);
215  virtual ~Dispatch() override;
216 };
217 
218 //----- Service ---------------------------------------------------------------
219 
221 {
222  return "org.libreoffice.comp.PresenterScreenProtocolHandler";
223 }
224 
226 {
227  return { "com.sun.star.frame.ProtocolHandler" };
228 }
229 
231  SAL_UNUSED_PARAMETER const Reference<uno::XComponentContext>&)
232 {
233  return Reference<XInterface>(static_cast<XWeak*>(new PresenterProtocolHandler));
234 }
235 
236 //===== PresenterProtocolHandler =========================================================
237 
240 {
241 }
242 
244 {
245 }
246 
248 {
249 }
250 
251 //----- XInitialize -----------------------------------------------------------
252 
253 void SAL_CALL PresenterProtocolHandler::initialize (const Sequence<Any>& aArguments)
254 {
255  ThrowIfDisposed();
256  if (aArguments.getLength() <= 0)
257  return;
258 
259  try
260  {
261  Reference<frame::XFrame> xFrame;
262  if (aArguments[0] >>= xFrame)
263  {
265  }
266  }
267  catch (RuntimeException&)
268  {
269  OSL_ASSERT(false);
270  }
271 }
272 
274 {
276 }
277 
279 {
280  return cppu::supportsService(this, ServiceName);
281 }
282 
283 css::uno::Sequence<OUString>
285 {
287 }
288 
289 //----- XDispatchProvider -----------------------------------------------------
290 
292  const css::util::URL& rURL,
293  const OUString&,
294  sal_Int32)
295 {
296  ThrowIfDisposed();
297 
299 
300  if (rURL.Protocol == "vnd.org.libreoffice.presenterscreen:")
301  {
302  xDispatch.set(Dispatch::Create(rURL.Path, mpPresenterController));
303  }
304 
305  return xDispatch;
306 }
307 
308 Sequence<Reference<frame::XDispatch> > SAL_CALL PresenterProtocolHandler::queryDispatches(
309  const Sequence<frame::DispatchDescriptor>&)
310 {
311  ThrowIfDisposed();
312  return Sequence<Reference<frame::XDispatch> >();
313 }
314 
315 
317 {
318  if (rBHelper.bDisposed || rBHelper.bInDispose)
319  {
320  throw lang::DisposedException (
321  "PresenterProtocolHandler object has already been disposed",
322  const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
323  }
324 }
325 
326 //===== PresenterProtocolHandler::Dispatch ====================================
327 
329  const OUString& rsURLPath,
330  const ::rtl::Reference<PresenterController>& rpPresenterController)
331 {
332  ::rtl::Reference<Dispatch> pDispatch (new Dispatch (rsURLPath, rpPresenterController));
333  if (pDispatch->mpCommand != nullptr)
334  return Reference<frame::XDispatch>(pDispatch.get());
335  else
336  return nullptr;
337 }
338 
340  const OUString& rsURLPath,
341  const ::rtl::Reference<PresenterController>& rpPresenterController)
342  : PresenterDispatchInterfaceBase(m_aMutex),
343  msURLPath(rsURLPath),
344  mpCommand(CreateCommand(rsURLPath, rpPresenterController)),
345  mpPresenterController(rpPresenterController),
346  maStatusListenerContainer(),
347  mbIsListeningToWindowManager(false)
348 {
349  if (mpCommand != nullptr)
350  {
351  mpPresenterController->GetWindowManager()->AddLayoutListener(this);
353  }
354 }
355 
357  const OUString& rsURLPath,
358  const ::rtl::Reference<PresenterController>& rpPresenterController)
359 {
360  if (rsURLPath.getLength() <= 5)
361  return nullptr;
362 
363  if (rsURLPath == "CloseNotes")
364  return new SetNotesViewCommand(false, rpPresenterController);
365  if (rsURLPath == "CloseSlideSorter")
366  return new SetSlideSorterCommand(false, rpPresenterController);
367  if (rsURLPath == "CloseHelp")
368  return new SetHelpViewCommand(false, rpPresenterController);
369  if (rsURLPath == "GrowNotesFont")
370  return new NotesFontSizeCommand(rpPresenterController, +1);
371  if (rsURLPath == "NextEffect")
372  return new GotoNextEffectCommand(rpPresenterController);
373  if (rsURLPath == "NextSlide")
374  return new GotoNextSlideCommand(rpPresenterController);
375  if (rsURLPath == "PrevSlide")
376  return new GotoPreviousSlideCommand(rpPresenterController);
377  if (rsURLPath == "SwitchMonitor")
378  return new SwitchMonitorCommand(rpPresenterController);
379  if (rsURLPath == "RestartTimer")
380  return new RestartTimerCommand(rpPresenterController);
381  if (rsURLPath == "ShowNotes")
382  return new SetNotesViewCommand(true, rpPresenterController);
383  if (rsURLPath == "ShowSlideSorter")
384  return new SetSlideSorterCommand(true, rpPresenterController);
385  if (rsURLPath == "ShowHelp")
386  return new SetHelpViewCommand(true, rpPresenterController);
387  if (rsURLPath == "ShrinkNotesFont")
388  return new NotesFontSizeCommand(rpPresenterController, -1);
389 
390  return nullptr;
391 }
392 
394 {
395 }
396 
398 {
399  if (mbIsListeningToWindowManager)
400  {
401  if (mpPresenterController.get() != nullptr)
402  mpPresenterController->GetWindowManager()->RemoveLayoutListener(this);
403  mbIsListeningToWindowManager = false;
404  }
405 
406  msURLPath.clear();
407  mpCommand.reset();
408 }
409 
410 //----- XDispatch -------------------------------------------------------------
411 
413  const css::util::URL& rURL,
414  const css::uno::Sequence<css::beans::PropertyValue>& /*rArguments*/)
415 {
416  if (rBHelper.bDisposed || rBHelper.bInDispose)
417  {
418  throw lang::DisposedException (
419  "PresenterProtocolHandler::Dispatch object has already been disposed",
420  static_cast<uno::XWeak*>(this));
421  }
422 
423  if (rURL.Protocol != "vnd.org.libreoffice.presenterscreen:"
424  || rURL.Path != msURLPath)
425  {
426  // We can not throw an IllegalArgumentException
427  throw RuntimeException();
428  }
429 
430  if (mpCommand != nullptr)
431  mpCommand->Execute();
432 }
433 
435  const css::uno::Reference<css::frame::XStatusListener>& rxListener,
436  const css::util::URL& rURL)
437 {
438  if (rURL.Path != msURLPath)
439  throw RuntimeException();
440 
441  maStatusListenerContainer.push_back(rxListener);
442 
443  frame::FeatureStateEvent aEvent;
444  aEvent.FeatureURL = rURL;
445  aEvent.IsEnabled = mpCommand->IsEnabled();
446  aEvent.Requery = false;
447  aEvent.State = mpCommand->GetState();
448  rxListener->statusChanged(aEvent);
449 }
450 
452  const css::uno::Reference<css::frame::XStatusListener>& rxListener,
453  const css::util::URL& rURL)
454 {
455  if (rURL.Path != msURLPath)
456  throw RuntimeException();
457 
458  StatusListenerContainer::iterator iListener (
459  ::std::find(
460  maStatusListenerContainer.begin(),
461  maStatusListenerContainer.end(),
462  rxListener));
463  if (iListener != maStatusListenerContainer.end())
464  maStatusListenerContainer.erase(iListener);
465 }
466 
467 //----- document::XEventListener ----------------------------------------------
468 
470  const css::document::EventObject&)
471 {
472  mpCommand->GetState();
473 }
474 
475 //----- lang::XEventListener --------------------------------------------------
476 
477 void SAL_CALL PresenterProtocolHandler::Dispatch::disposing (const css::lang::EventObject&)
478 {
479  mbIsListeningToWindowManager = false;
480 }
481 
482 //===== GotoPreviousSlideCommand ==============================================
483 
484 GotoPreviousSlideCommand::GotoPreviousSlideCommand (
485  const rtl::Reference<PresenterController>& rpPresenterController)
486  : mpPresenterController(rpPresenterController)
487 {
488 }
489 
490 void GotoPreviousSlideCommand::Execute()
491 {
492  if ( ! mpPresenterController.is())
493  return;
494 
495  if ( ! mpPresenterController->GetSlideShowController().is())
496  return;
497 
498  mpPresenterController->GetSlideShowController()->gotoPreviousSlide();
499 }
500 
501 bool GotoPreviousSlideCommand::IsEnabled() const
502 {
503  if ( ! mpPresenterController.is())
504  return false;
505 
506  if ( ! mpPresenterController->GetSlideShowController().is())
507  return false;
508 
509  return mpPresenterController->GetSlideShowController()->getCurrentSlideIndex()>0;
510 }
511 
512 //===== GotoNextEffect ========================================================
513 
514 GotoNextEffectCommand::GotoNextEffectCommand (
515  const rtl::Reference<PresenterController>& rpPresenterController)
516  : mpPresenterController(rpPresenterController)
517 {
518 }
519 
520 void GotoNextEffectCommand::Execute()
521 {
522  if ( ! mpPresenterController.is())
523  return;
524 
525  if ( ! mpPresenterController->GetSlideShowController().is())
526  return;
527 
528  mpPresenterController->GetSlideShowController()->gotoNextEffect();
529 }
530 
531 bool GotoNextEffectCommand::IsEnabled() const
532 {
533  if ( ! mpPresenterController.is())
534  return false;
535 
536  if ( ! mpPresenterController->GetSlideShowController().is())
537  return false;
538 
539  return ( mpPresenterController->GetSlideShowController()->getNextSlideIndex() < mpPresenterController->GetSlideShowController()->getSlideCount() );
540 
541 }
542 
543 //===== GotoNextSlide =========================================================
544 
545 GotoNextSlideCommand::GotoNextSlideCommand (
546  const rtl::Reference<PresenterController>& rpPresenterController)
547  : mpPresenterController(rpPresenterController)
548 {
549 }
550 
551 void GotoNextSlideCommand::Execute()
552 {
553  if ( ! mpPresenterController.is())
554  return;
555 
556  if ( ! mpPresenterController->GetSlideShowController().is())
557  return;
558 
559  mpPresenterController->GetSlideShowController()->gotoNextSlide();
560 }
561 
562 //===== SwitchMonitorCommand ==============================================
563 
564 SwitchMonitorCommand::SwitchMonitorCommand (
565  const rtl::Reference<PresenterController>& rpPresenterController)
566  : mpPresenterController(rpPresenterController)
567 {
568 }
569 
570 void SwitchMonitorCommand::Execute()
571 {
572  mpPresenterController->SwitchMonitors();
573 }
574 
575 RestartTimerCommand::RestartTimerCommand (const rtl::Reference<PresenterController>& rpPresenterController)
576 : mpPresenterController(rpPresenterController)
577 {
578 }
579 
580 void RestartTimerCommand::Execute()
581 {
582  if (IPresentationTime* pPresentationTime = mpPresenterController->GetPresentationTime())
583  pPresentationTime->restart();
584 }
585 
586 //===== SetNotesViewCommand ===================================================
587 
588 SetNotesViewCommand::SetNotesViewCommand (
589  const bool bOn,
590  const rtl::Reference<PresenterController>& rpPresenterController)
591  : mbOn(bOn),
592  mpPresenterController(rpPresenterController)
593 {
594 }
595 
596 void SetNotesViewCommand::Execute()
597 {
598  if ( ! mpPresenterController.is())
599  return;
600 
602  mpPresenterController->GetWindowManager());
603  if ( ! pWindowManager.is())
604  return;
605 
606  if (mbOn)
607  pWindowManager->SetViewMode(PresenterWindowManager::VM_Notes);
608  else
609  pWindowManager->SetViewMode(PresenterWindowManager::VM_Standard);
610 }
611 
612 Any SetNotesViewCommand::GetState() const
613 {
614  if ( ! mpPresenterController.is())
615  return Any(false);
616 
618  mpPresenterController->GetWindowManager());
619  if ( ! pWindowManager.is())
620  return Any(false);
621 
622  return Any(pWindowManager->GetViewMode() == PresenterWindowManager::VM_Notes);
623 }
624 
625 //===== SetSlideSorterCommand =================================================
626 
627 SetSlideSorterCommand::SetSlideSorterCommand (
628  const bool bOn,
629  const rtl::Reference<PresenterController>& rpPresenterController)
630  : mbOn(bOn),
631  mpPresenterController(rpPresenterController)
632 {
633 }
634 
635 void SetSlideSorterCommand::Execute()
636 {
637  if ( ! mpPresenterController.is())
638  return;
639 
641  mpPresenterController->GetWindowManager());
642  if ( ! pWindowManager.is())
643  return;
644 
645  pWindowManager->SetSlideSorterState(mbOn);
646 }
647 
648 Any SetSlideSorterCommand::GetState() const
649 {
650  if ( ! mpPresenterController.is())
651  return Any(false);
652 
654  mpPresenterController->GetWindowManager());
655  if ( ! pWindowManager.is())
656  return Any(false);
657 
658  return Any(pWindowManager->GetViewMode()==PresenterWindowManager::VM_SlideOverview);
659 }
660 
661 //===== SetHelpViewCommand ===================================================
662 
663 SetHelpViewCommand::SetHelpViewCommand (
664  const bool bOn,
665  const rtl::Reference<PresenterController>& rpPresenterController)
666  : mbOn(bOn),
667  mpPresenterController(rpPresenterController)
668 {
669 }
670 
671 void SetHelpViewCommand::Execute()
672 {
673  if ( ! mpPresenterController.is())
674  return;
675 
677  mpPresenterController->GetWindowManager());
678  if ( ! pWindowManager.is())
679  return;
680 
681  pWindowManager->SetHelpViewState(mbOn);
682 }
683 
684 Any SetHelpViewCommand::GetState() const
685 {
686  if ( ! mpPresenterController.is())
687  return Any(false);
688 
690  mpPresenterController->GetWindowManager());
691  if ( ! pWindowManager.is())
692  return Any(false);
693 
694  return Any(pWindowManager->GetViewMode()==PresenterWindowManager::VM_Help);
695 }
696 
697 //===== NotesFontSizeCommand ==================================================
698 
699 NotesFontSizeCommand::NotesFontSizeCommand(
700  const rtl::Reference<PresenterController>& rpPresenterController,
701  const sal_Int32 nSizeChange)
702  : mpPresenterController(rpPresenterController),
703  mnSizeChange(nSizeChange)
704 {
705 }
706 
707 ::rtl::Reference<PresenterNotesView> NotesFontSizeCommand::GetNotesView() const
708 {
709  if (mpPresenterController.get() == nullptr)
710  return nullptr;
711 
713  mpPresenterController->GetPaneContainer()->FindViewURL(
715  if (pDescriptor.get() == nullptr)
716  return nullptr;
717 
718  return dynamic_cast<PresenterNotesView*>(pDescriptor->mxView.get());
719 }
720 
721 void NotesFontSizeCommand::Execute()
722 {
723  ::rtl::Reference<PresenterNotesView> pView (GetNotesView());
724  if (pView.is())
725  pView->ChangeFontSize(mnSizeChange);
726 }
727 
728 Any NotesFontSizeCommand::GetState() const
729 {
730  return Any();
731 }
732 
733 } // end of namespace ::sdext::presenter
734 
735 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static::rtl::Reference< PresenterController > Instance(const css::uno::Reference< css::frame::XFrame > &rxFrame)
URL aURL
osl::Mutex m_aMutex
virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > &rxListener, const css::util::URL &rURL) override
Reference< XFrame > xFrame
css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
mutable::osl::Mutex m_aMutex
virtual void SAL_CALL dispatch(const css::util::URL &aURL, const css::uno::Sequence< css::beans::PropertyValue > &rArguments) override
static Reference< frame::XDispatch > Create(const OUString &rsURLPath, const ::rtl::Reference< PresenterController > &rpPresenterController)
Create a new Dispatch object.
static Command * CreateCommand(const OUString &rsURLPath, const ::rtl::Reference< PresenterController > &rpPresenterController)
::rtl::Reference< PresenterController > mpPresenterController
Dispatch(const OUString &rsURLPath, const ::rtl::Reference< PresenterController > &rpPresenterController)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > &rxListener, const css::util::URL &rURL) override
unsigned char sal_Bool
virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch(const css::util::URL &aURL, const OUString &aTargetFrameName, sal_Int32 nSearchFlags) override
const sal_Int32 mnSizeChange
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
::rtl::Reference< PresenterController > mpPresenterController
::cppu::WeakComponentImplHelper< css::lang::XInitialization, css::lang::XServiceInfo, css::frame::XDispatchProvider > PresenterProtocolHandlerInterfaceBase
Reference< XDispatch > xDispatch
rtl::Reference< PresenterController > mpPresenterController
static css::uno::Sequence< OUString > getSupportedServiceNames_static()
virtual void SAL_CALL notifyEvent(const css::document::EventObject &rEvent) override
std::shared_ptr< PaneDescriptor > SharedPaneDescriptor
virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches(const css::uno::Sequence< css::frame::DispatchDescriptor > &rDescriptors) override
sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
static css::uno::Reference< css::uno::XInterface > Create(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
AnyEventRef aEvent
::std::vector< Reference< frame::XStatusListener > > StatusListenerContainer