cid#1607171 Data race condition
[LibreOffice.git] / sd / source / ui / framework / tools / FrameworkHelper.cxx
blob16bc1192dcd3e722d8237200d4b2b2eb2496dad2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <osl/time.h>
22 #include <framework/FrameworkHelper.hxx>
24 #include <framework/ConfigurationController.hxx>
25 #include <framework/ResourceId.hxx>
26 #include <framework/ViewShellWrapper.hxx>
27 #include <ViewShellBase.hxx>
28 #include <DrawViewShell.hxx>
29 #include <ViewShellHint.hxx>
30 #include <DrawController.hxx>
31 #include <app.hrc>
32 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
33 #include <com/sun/star/frame/XController.hpp>
34 #include <comphelper/servicehelper.hxx>
35 #include <comphelper/compbase.hxx>
36 #include <svl/lstner.hxx>
37 #include <rtl/ustrbuf.hxx>
39 #include <sfx2/request.hxx>
41 #include <utility>
42 #include <vcl/svapp.hxx>
43 #include <comphelper/diagnose_ex.hxx>
44 #include <memory>
45 #include <unordered_map>
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star::drawing::framework;
51 namespace {
53 //----- CallbackCaller --------------------------------------------------------
55 typedef comphelper::WeakComponentImplHelper <
56 css::drawing::framework::XConfigurationChangeListener
57 > CallbackCallerInterfaceBase;
59 /** A CallbackCaller registers as listener at an XConfigurationController
60 object and waits for the notification of one type of event. When that
61 event is received, or when the CallbackCaller detects at its
62 construction that the event will not be sent in the near future, the
63 actual callback object is called and the CallbackCaller destroys itself.
65 class CallbackCaller
66 : public CallbackCallerInterfaceBase
68 public:
69 /** Create a new CallbackCaller object. This object controls its own
70 lifetime by acquiring a reference to itself in the constructor.
71 When it detects that the event will not be notified in the near
72 future (because the queue of pending configuration change operations
73 is empty and therefore no event will be sent int the near future, it
74 does not acquires a reference and thus initiates its destruction in
75 the constructor.)
76 @param rBase
77 This ViewShellBase object is used to determine the
78 XConfigurationController at which to register.
79 @param rsEventType
80 The event type which the callback is waiting for.
81 @param pCallback
82 The callback object which is to be notified. The caller will
83 typically release his reference to the caller so that when the
84 CallbackCaller dies (after having called the callback) the
85 callback is destroyed.
87 CallbackCaller (
88 const ::sd::ViewShellBase& rBase,
89 OUString sEventType,
90 ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter aFilter,
91 ::sd::framework::FrameworkHelper::Callback aCallback);
93 virtual void disposing(std::unique_lock<std::mutex>&) override;
94 // XEventListener
95 virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override;
96 // XConfigurationChangeListener
97 virtual void SAL_CALL notifyConfigurationChange (const ConfigurationChangeEvent& rEvent) override;
99 private:
100 OUString msEventType;
101 Reference<XConfigurationController> mxConfigurationController;
102 ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter maFilter;
103 ::sd::framework::FrameworkHelper::Callback maCallback;
106 //----- LifetimeController ----------------------------------------------------
108 typedef comphelper::WeakComponentImplHelper <
109 css::lang::XEventListener
110 > LifetimeControllerInterfaceBase;
112 /** This class helps controlling the lifetime of the
113 FrameworkHelper. Register at a ViewShellBase object and an XController
114 object and call Dispose() at the associated FrameworkHelper object when
115 one of them and Release() when both of them are destroyed.
117 class LifetimeController
118 : public LifetimeControllerInterfaceBase,
119 public SfxListener
121 public:
122 explicit LifetimeController (::sd::ViewShellBase& rBase);
123 virtual ~LifetimeController() override;
125 /** XEventListener. This method is called when the frame::XController
126 is being destroyed.
128 using WeakComponentImplHelperBase::disposing;
129 virtual void SAL_CALL disposing (const lang::EventObject& rEvent) override;
131 /** This method is called when the ViewShellBase is being destroyed.
133 virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override;
135 private:
136 ::sd::ViewShellBase& mrBase;
137 bool mbListeningToViewShellBase;
138 bool mbListeningToController;
140 /** When one or both of the mbListeningToViewShellBase and
141 mbListeningToController members were modified then call this method
142 to either dispose or release the associated FrameworkHelper.
144 void Update();
147 } // end of anonymous namespace
149 namespace sd::framework {
151 namespace {
153 class FrameworkHelperAllPassFilter
155 public:
156 bool operator() (const css::drawing::framework::ConfigurationChangeEvent&) { return true; }
159 class FrameworkHelperResourceIdFilter
161 public:
162 explicit FrameworkHelperResourceIdFilter (
163 const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId);
164 bool operator() (const css::drawing::framework::ConfigurationChangeEvent& rEvent)
165 { return mxResourceId.is() && rEvent.ResourceId.is()
166 && mxResourceId->compareTo(rEvent.ResourceId) == 0; }
167 private:
168 css::uno::Reference<css::drawing::framework::XResourceId> mxResourceId;
171 } // end of anonymous namespace
173 // Pane URLS.
175 const OUString FrameworkHelper::msCenterPaneURL( msPaneURLPrefix + "CenterPane");
176 const OUString FrameworkHelper::msFullScreenPaneURL( msPaneURLPrefix + "FullScreenPane");
177 const OUString FrameworkHelper::msLeftImpressPaneURL( msPaneURLPrefix + "LeftImpressPane");
178 const OUString FrameworkHelper::msBottomImpressPaneURL( msPaneURLPrefix + "BottomImpressPane");
179 const OUString FrameworkHelper::msLeftDrawPaneURL( msPaneURLPrefix + "LeftDrawPane");
181 // View URLs.
183 const OUString FrameworkHelper::msImpressViewURL( msViewURLPrefix + "ImpressView");
184 const OUString FrameworkHelper::msDrawViewURL( msViewURLPrefix + "GraphicView");
185 const OUString FrameworkHelper::msOutlineViewURL( msViewURLPrefix + "OutlineView");
186 const OUString FrameworkHelper::msNotesViewURL( msViewURLPrefix + "NotesView");
187 const OUString FrameworkHelper::msHandoutViewURL( msViewURLPrefix + "HandoutView");
188 const OUString FrameworkHelper::msSlideSorterURL( msViewURLPrefix + "SlideSorter");
189 const OUString FrameworkHelper::msPresentationViewURL( msViewURLPrefix + "PresentationView");
190 const OUString FrameworkHelper::msSidebarViewURL( msViewURLPrefix + "SidebarView");
191 const OUString FrameworkHelper::msNotesPanelViewURL( msViewURLPrefix + "NotesPanelView");
193 // Tool bar URLs.
195 const OUString FrameworkHelper::msViewTabBarURL( msToolBarURLPrefix + "ViewTabBar");
197 //----- helper ----------------------------------------------------------------
198 namespace
200 ::std::shared_ptr< ViewShell > lcl_getViewShell( const Reference< XResource >& i_rViewShellWrapper )
202 ::std::shared_ptr< ViewShell > pViewShell;
205 if (auto pWrapper = dynamic_cast<ViewShellWrapper*>(i_rViewShellWrapper.get()))
206 pViewShell = pWrapper->GetViewShell();
208 catch( const Exception& )
210 DBG_UNHANDLED_EXCEPTION("sd");
212 return pViewShell;
214 Reference< XResource > lcl_getFirstViewInPane( const Reference< XConfigurationController >& i_rConfigController,
215 const Reference< XResourceId >& i_rPaneId )
219 Reference< XConfiguration > xConfiguration( i_rConfigController->getRequestedConfiguration(), UNO_SET_THROW );
220 Sequence< Reference< XResourceId > > aViewIds( xConfiguration->getResources(
221 i_rPaneId, FrameworkHelper::msViewURLPrefix, AnchorBindingMode_DIRECT ) );
222 if ( aViewIds.hasElements() )
223 return i_rConfigController->getResource( aViewIds[0] );
225 catch( const Exception& )
227 DBG_UNHANDLED_EXCEPTION("sd");
229 return nullptr;
233 //----- FrameworkHelper::ViewURLMap -------------------------------------------
235 /** The ViewURLMap is used to translate between the view URLs used by the
236 drawing framework and the enums defined in the ViewShell class.
238 class FrameworkHelper::ViewURLMap
239 : public std::unordered_map<
240 OUString,
241 ViewShell::ShellType>
243 public:
244 ViewURLMap() {}
247 //----- Framework::DisposeListener ---------------------------------------------
249 namespace {
250 typedef comphelper::WeakComponentImplHelper <
251 css::lang::XEventListener
252 > FrameworkHelperDisposeListenerInterfaceBase;
255 class FrameworkHelper::DisposeListener
256 : public FrameworkHelperDisposeListenerInterfaceBase
258 public:
259 explicit DisposeListener (::std::shared_ptr<FrameworkHelper> pHelper);
261 virtual void disposing(std::unique_lock<std::mutex>&) override;
263 virtual void SAL_CALL disposing (const lang::EventObject& rEventObject) override;
265 private:
266 ::std::shared_ptr<FrameworkHelper> mpHelper;
269 //----- FrameworkHelper::Deleter ----------------------------------------------
271 class FrameworkHelper::Deleter
273 public:
274 void operator()(FrameworkHelper* pObject)
276 delete pObject;
280 //----- FrameworkHelper -------------------------------------------------------
282 FrameworkHelper::ViewURLMap FrameworkHelper::maViewURLMap;
284 FrameworkHelper::InstanceMap FrameworkHelper::maInstanceMap;
285 std::mutex FrameworkHelper::maInstanceMapMutex;
287 ::std::shared_ptr<FrameworkHelper> FrameworkHelper::Instance (ViewShellBase& rBase)
289 std::unique_lock aGuard(maInstanceMapMutex);
291 InstanceMap::const_iterator iHelper (maInstanceMap.find(&rBase));
292 if (iHelper != maInstanceMap.end())
293 return iHelper->second;
295 ::std::shared_ptr<FrameworkHelper> pHelper(
296 new FrameworkHelper(rBase),
297 FrameworkHelper::Deleter());
298 pHelper->Initialize();
299 maInstanceMap[&rBase] = pHelper;
301 return pHelper;
304 void FrameworkHelper::DisposeInstance (const ViewShellBase& rBase)
306 InstanceMap::iterator iHelper (maInstanceMap.find(&rBase));
307 if (iHelper != maInstanceMap.end())
309 iHelper->second->Dispose();
313 void FrameworkHelper::ReleaseInstance (const ViewShellBase& rBase)
315 InstanceMap::iterator iHelper (maInstanceMap.find(&rBase));
316 if (iHelper != maInstanceMap.end())
317 maInstanceMap.erase(iHelper);
320 FrameworkHelper::FrameworkHelper (ViewShellBase& rBase)
321 : mrBase(rBase)
323 DrawController* pDrawController = rBase.GetDrawController();
324 if (pDrawController)
326 mxConfigurationController = pDrawController->getConfigurationController();
329 new LifetimeController(mrBase);
332 void FrameworkHelper::Initialize()
334 mxDisposeListener = new DisposeListener(shared_from_this());
337 FrameworkHelper::~FrameworkHelper()
341 void FrameworkHelper::Dispose()
343 if (mxDisposeListener.is())
344 mxDisposeListener->dispose();
345 mxConfigurationController = nullptr;
348 bool FrameworkHelper::IsValid() const
350 return mxConfigurationController.is();
353 ::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const OUString& rsPaneURL)
355 if ( !mxConfigurationController.is() )
356 return ::std::shared_ptr<ViewShell>();
358 Reference<XResourceId> xPaneId( CreateResourceId( rsPaneURL ) );
359 return lcl_getViewShell( lcl_getFirstViewInPane( mxConfigurationController, xPaneId ) );
362 ::std::shared_ptr<ViewShell> FrameworkHelper::GetViewShell (const Reference<XView>& rxView)
364 return lcl_getViewShell( rxView );
367 Reference<XView> FrameworkHelper::GetView (const Reference<XResourceId>& rxPaneOrViewId)
369 Reference<XView> xView;
371 if ( ! rxPaneOrViewId.is() || ! mxConfigurationController.is())
372 return nullptr;
376 if (rxPaneOrViewId->getResourceURL().match(msViewURLPrefix))
378 xView.set( mxConfigurationController->getResource( rxPaneOrViewId ), UNO_QUERY );
380 else
382 xView.set( lcl_getFirstViewInPane( mxConfigurationController, rxPaneOrViewId ), UNO_QUERY );
385 catch (lang::DisposedException&)
387 Dispose();
389 catch (RuntimeException&)
393 return xView;
396 Reference<XResourceId> FrameworkHelper::RequestView (
397 const OUString& rsResourceURL,
398 const OUString& rsAnchorURL)
400 Reference<XResourceId> xViewId;
404 if (mxConfigurationController.is())
406 mxConfigurationController->requestResourceActivation(
407 CreateResourceId(rsAnchorURL),
408 ResourceActivationMode_ADD);
409 xViewId = CreateResourceId(rsResourceURL, rsAnchorURL);
410 mxConfigurationController->requestResourceActivation(
411 xViewId,
412 ResourceActivationMode_REPLACE);
415 catch (lang::DisposedException&)
417 Dispose();
418 xViewId = nullptr;
420 catch (RuntimeException&)
422 xViewId = nullptr;
425 return xViewId;
428 ViewShell::ShellType FrameworkHelper::GetViewId (const OUString& rsViewURL)
430 if (maViewURLMap.empty())
432 maViewURLMap[msImpressViewURL] = ViewShell::ST_IMPRESS;
433 maViewURLMap[msDrawViewURL] = ViewShell::ST_DRAW;
434 maViewURLMap[msOutlineViewURL] = ViewShell::ST_OUTLINE;
435 maViewURLMap[msNotesViewURL] = ViewShell::ST_NOTES;
436 maViewURLMap[msHandoutViewURL] = ViewShell::ST_HANDOUT;
437 maViewURLMap[msSlideSorterURL] = ViewShell::ST_SLIDE_SORTER;
438 maViewURLMap[msPresentationViewURL] = ViewShell::ST_PRESENTATION;
439 maViewURLMap[msSidebarViewURL] = ViewShell::ST_SIDEBAR;
440 maViewURLMap[msNotesPanelViewURL] = ViewShell::ST_NOTESPANEL;
442 ViewURLMap::const_iterator iView (maViewURLMap.find(rsViewURL));
443 if (iView != maViewURLMap.end())
444 return iView->second;
445 else
446 return ViewShell::ST_NONE;
449 const OUString & FrameworkHelper::GetViewURL (ViewShell::ShellType eType)
451 switch (eType)
453 case ViewShell::ST_IMPRESS : return msImpressViewURL;
454 case ViewShell::ST_DRAW : return msDrawViewURL;
455 case ViewShell::ST_OUTLINE : return msOutlineViewURL;
456 case ViewShell::ST_NOTES : return msNotesViewURL;
457 case ViewShell::ST_HANDOUT : return msHandoutViewURL;
458 case ViewShell::ST_SLIDE_SORTER : return msSlideSorterURL;
459 case ViewShell::ST_PRESENTATION : return msPresentationViewURL;
460 case ViewShell::ST_SIDEBAR : return msSidebarViewURL;
461 case ViewShell::ST_NOTESPANEL: return msNotesPanelViewURL;
462 default:
463 return EMPTY_OUSTRING;
467 namespace
470 void updateEditMode(const Reference<XView> &xView, const EditMode eEMode, bool updateFrameView)
472 // Ensure we have the expected edit mode
473 // The check is only for DrawViewShell as OutlineViewShell
474 // and SlideSorterViewShell have no master mode
475 const ::std::shared_ptr<ViewShell> pCenterViewShell (FrameworkHelper::GetViewShell(xView));
476 DrawViewShell* pDrawViewShell
477 = dynamic_cast<DrawViewShell*>(pCenterViewShell.get());
478 if (pDrawViewShell != nullptr)
480 pCenterViewShell->Broadcast (
481 ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
483 pDrawViewShell->ChangeEditMode(eEMode, pDrawViewShell->IsLayerModeActive());
484 if (updateFrameView)
485 pDrawViewShell->WriteFrameViewData();
487 pCenterViewShell->Broadcast (
488 ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
492 void asyncUpdateEditMode(FrameworkHelper* const pHelper, const EditMode eEMode)
494 Reference<XResourceId> xPaneId (
495 FrameworkHelper::CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
496 Reference<XView> xView (pHelper->GetView(xPaneId));
497 updateEditMode(xView, eEMode, true);
502 void FrameworkHelper::HandleModeChangeSlot (
503 sal_uInt16 nSlotId,
504 SfxRequest const & rRequest)
506 if ( ! mxConfigurationController.is())
507 return;
509 // Parameters are allowed for NotesMasterPage and SlideMasterPage
510 // for these command, transfor xxxxMasterPage with param = false
511 // to ActivatexxxxxMode
512 if (nSlotId == SID_NOTES_MASTER_MODE || nSlotId == SID_SLIDE_MASTER_MODE)
514 const SfxItemSet* pRequestArguments = rRequest.GetArgs();
515 if (pRequestArguments)
517 const SfxBoolItem* pIsActive = rRequest.GetArg<SfxBoolItem>(nSlotId);
518 if (!pIsActive->GetValue ())
520 if (nSlotId == SID_NOTES_MASTER_MODE)
521 nSlotId = SID_NOTES_MODE;
522 else
523 nSlotId = SID_NORMAL_MULTI_PANE_GUI;
530 if ( ! mxConfigurationController.is())
531 throw RuntimeException();
533 Reference<XResourceId> xPaneId (
534 CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
535 Reference<XView> xView (GetView(xPaneId));
537 // Compute requested view
538 OUString sRequestedView;
539 switch (nSlotId)
541 // draw
542 case SID_DRAWINGMODE:
543 // impress
544 case SID_NORMAL_MULTI_PANE_GUI:
545 case SID_SLIDE_MASTER_MODE:
546 sRequestedView = FrameworkHelper::msImpressViewURL;
547 break;
549 case SID_NOTES_MODE:
550 case SID_NOTES_MASTER_MODE:
551 sRequestedView = FrameworkHelper::msNotesViewURL;
552 break;
554 case SID_HANDOUT_MASTER_MODE:
555 sRequestedView = FrameworkHelper::msHandoutViewURL;
556 break;
558 case SID_SLIDE_SORTER_MULTI_PANE_GUI:
559 case SID_SLIDE_SORTER_MODE:
560 sRequestedView = FrameworkHelper::msSlideSorterURL;
561 break;
563 case SID_OUTLINE_MODE:
564 sRequestedView = FrameworkHelper::msOutlineViewURL;
565 break;
568 // Compute requested mode
569 EditMode eEMode = EditMode::Page;
570 if (nSlotId == SID_SLIDE_MASTER_MODE
571 || nSlotId == SID_NOTES_MASTER_MODE
572 || nSlotId == SID_HANDOUT_MASTER_MODE)
573 eEMode = EditMode::MasterPage;
574 // Ensure we have the expected view shell
575 if (!(xView.is() && xView->getResourceId()->getResourceURL() == sRequestedView))
578 const auto xId = CreateResourceId(sRequestedView, msCenterPaneURL);
579 mxConfigurationController->requestResourceActivation(
580 xId,
581 ResourceActivationMode_REPLACE);
582 RunOnResourceActivation(xId, std::bind(&asyncUpdateEditMode, this, eEMode));
584 else
586 updateEditMode(xView, eEMode, false);
589 catch (RuntimeException&)
591 DBG_UNHANDLED_EXCEPTION("sd");
595 void FrameworkHelper::RunOnConfigurationEvent(
596 const OUString& rsEventType,
597 const Callback& rCallback)
599 RunOnEvent(
600 rsEventType,
601 FrameworkHelperAllPassFilter(),
602 rCallback);
605 void FrameworkHelper::RunOnResourceActivation(
606 const css::uno::Reference<css::drawing::framework::XResourceId>& rxResourceId,
607 const Callback& rCallback)
609 if (mxConfigurationController.is()
610 && mxConfigurationController->getResource(rxResourceId).is())
612 rCallback(false);
614 else
616 RunOnEvent(
617 msResourceActivationEvent,
618 FrameworkHelperResourceIdFilter(rxResourceId),
619 rCallback);
623 namespace {
625 /** A callback that sets a flag to a specified value when the callback is
626 called.
628 class FlagUpdater
630 public:
631 explicit FlagUpdater (bool& rFlag) : mrFlag(rFlag) {}
632 void operator() (bool) const {mrFlag = true;}
633 private:
634 bool& mrFlag;
639 void FrameworkHelper::RequestSynchronousUpdate()
641 rtl::Reference<ConfigurationController> pCC (
642 dynamic_cast<ConfigurationController*>(mxConfigurationController.get()));
643 if (pCC.is())
644 pCC->RequestSynchronousUpdate();
647 void FrameworkHelper::WaitForEvent (const OUString& rsEventType) const
649 bool bConfigurationUpdateSeen (false);
651 RunOnEvent(
652 rsEventType,
653 FrameworkHelperAllPassFilter(),
654 FlagUpdater(bConfigurationUpdateSeen));
656 sal_uInt32 nStartTime = osl_getGlobalTimer();
657 while ( ! bConfigurationUpdateSeen)
659 Application::Reschedule();
661 if( (osl_getGlobalTimer() - nStartTime) > 60000 )
663 OSL_FAIL("FrameworkHelper::WaitForEvent(), no event for a minute? giving up!");
664 break;
669 void FrameworkHelper::WaitForUpdate() const
671 WaitForEvent(msConfigurationUpdateEndEvent);
674 void FrameworkHelper::RunOnEvent(
675 const OUString& rsEventType,
676 const ConfigurationChangeEventFilter& rFilter,
677 const Callback& rCallback) const
679 new CallbackCaller(mrBase,rsEventType,rFilter,rCallback);
682 void FrameworkHelper::disposing (const lang::EventObject& rEventObject)
684 if (rEventObject.Source == mxConfigurationController)
685 mxConfigurationController = nullptr;
688 void FrameworkHelper::UpdateConfiguration()
690 if (!mxConfigurationController.is())
691 return;
695 if (mxConfigurationController.is())
696 mxConfigurationController->update();
698 catch (lang::DisposedException&)
700 Dispose();
702 catch (RuntimeException&)
704 DBG_UNHANDLED_EXCEPTION("sd");
708 OUString FrameworkHelper::ResourceIdToString (const Reference<XResourceId>& rxResourceId)
710 OUStringBuffer sString;
711 if (rxResourceId.is())
713 sString.append(rxResourceId->getResourceURL());
714 if (rxResourceId->hasAnchor())
716 const Sequence<OUString> aAnchorURLs (rxResourceId->getAnchorURLs());
717 for (const auto& rAnchorURL : aAnchorURLs)
719 sString.append(" | " + rAnchorURL);
723 return sString.makeStringAndClear();
726 Reference<XResourceId> FrameworkHelper::CreateResourceId (const OUString& rsResourceURL)
728 return new ::sd::framework::ResourceId(rsResourceURL);
731 Reference<XResourceId> FrameworkHelper::CreateResourceId (
732 const OUString& rsResourceURL,
733 const OUString& rsAnchorURL)
735 return new ::sd::framework::ResourceId(rsResourceURL, rsAnchorURL);
738 Reference<XResourceId> FrameworkHelper::CreateResourceId (
739 const OUString& rsResourceURL,
740 const Reference<XResourceId>& rxAnchorId)
742 if (rxAnchorId.is())
743 return new ::sd::framework::ResourceId(
744 rsResourceURL,
745 rxAnchorId->getResourceURL(),
746 rxAnchorId->getAnchorURLs());
747 else
748 return new ::sd::framework::ResourceId(rsResourceURL);
751 //----- FrameworkHelper::DisposeListener --------------------------------------
753 FrameworkHelper::DisposeListener::DisposeListener (
754 ::std::shared_ptr<FrameworkHelper> pHelper)
755 : mpHelper(std::move(pHelper))
757 Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY);
758 if (xComponent.is())
759 xComponent->addEventListener(this);
762 void FrameworkHelper::DisposeListener::disposing(std::unique_lock<std::mutex>&)
764 Reference<XComponent> xComponent (mpHelper->mxConfigurationController, UNO_QUERY);
765 if (xComponent.is())
766 xComponent->removeEventListener(this);
768 mpHelper.reset();
771 void SAL_CALL FrameworkHelper::DisposeListener::disposing (const lang::EventObject& rEventObject)
773 if (mpHelper != nullptr)
774 mpHelper->disposing(rEventObject);
777 //===== FrameworkHelperResourceIdFilter =======================================
779 FrameworkHelperResourceIdFilter::FrameworkHelperResourceIdFilter (
780 const Reference<XResourceId>& rxResourceId)
781 : mxResourceId(rxResourceId)
785 } // end of namespace sd::framework
787 namespace {
789 //===== CallbackCaller ========================================================
791 CallbackCaller::CallbackCaller (
792 const ::sd::ViewShellBase& rBase,
793 OUString rsEventType,
794 ::sd::framework::FrameworkHelper::ConfigurationChangeEventFilter aFilter,
795 ::sd::framework::FrameworkHelper::Callback aCallback)
796 : msEventType(std::move(rsEventType)),
797 maFilter(std::move(aFilter)),
798 maCallback(std::move(aCallback))
802 sd::DrawController* pDrawController = rBase.GetDrawController();
803 if (!pDrawController)
804 return;
805 mxConfigurationController = pDrawController->getConfigurationController();
806 if (mxConfigurationController.is())
808 if (mxConfigurationController->hasPendingRequests())
809 mxConfigurationController->addConfigurationChangeListener(this,msEventType,Any());
810 else
812 // There are no requests waiting to be processed. Therefore
813 // no event, especially not the one we are waiting for, will
814 // be sent in the near future and the callback would never be
815 // called.
816 // Call the callback now and tell him that the event it is
817 // waiting for was not sent.
818 mxConfigurationController = nullptr;
819 maCallback(false);
823 catch (RuntimeException&)
825 DBG_UNHANDLED_EXCEPTION("sd");
829 void CallbackCaller::disposing(std::unique_lock<std::mutex>&)
833 if (mxConfigurationController.is())
835 Reference<XConfigurationController> xCC (mxConfigurationController);
836 mxConfigurationController = nullptr;
837 xCC->removeConfigurationChangeListener(this);
840 catch (RuntimeException&)
842 DBG_UNHANDLED_EXCEPTION("sd");
846 void SAL_CALL CallbackCaller::disposing (const lang::EventObject& rEvent)
848 if (rEvent.Source == mxConfigurationController)
850 mxConfigurationController = nullptr;
851 maCallback(false);
855 void SAL_CALL CallbackCaller::notifyConfigurationChange (
856 const ConfigurationChangeEvent& rEvent)
858 if (!(rEvent.Type == msEventType && maFilter(rEvent)))
859 return;
861 maCallback(true);
862 if (mxConfigurationController.is())
864 // Reset the reference to the configuration controller so that
865 // dispose() will not try to remove the listener a second time.
866 Reference<XConfigurationController> xCC (mxConfigurationController);
867 mxConfigurationController = nullptr;
869 // Removing this object from the controller may very likely lead
870 // to its destruction, so no calls after that.
871 xCC->removeConfigurationChangeListener(this);
875 //----- LifetimeController -------------------------------------------------
877 LifetimeController::LifetimeController (::sd::ViewShellBase& rBase)
878 : mrBase(rBase),
879 mbListeningToViewShellBase(false),
880 mbListeningToController(false)
882 // Register as listener at the ViewShellBase. Because that is not done
883 // via a reference we have to increase the reference count manually.
884 // This is necessary even though listening to the XController did
885 // increase the reference count because the controller may release its
886 // reference to us before the ViewShellBase is destroyed.
887 StartListening(mrBase);
888 acquire();
889 mbListeningToViewShellBase = true;
891 Reference<XComponent> xComponent = rBase.GetController();
892 if (xComponent.is())
894 xComponent->addEventListener(this);
895 mbListeningToController = true;
899 LifetimeController::~LifetimeController()
901 OSL_ASSERT(!mbListeningToController && !mbListeningToViewShellBase);
904 void SAL_CALL LifetimeController::disposing (const lang::EventObject&)
906 mbListeningToController = false;
907 Update();
910 void LifetimeController::Notify (SfxBroadcaster&, const SfxHint& rHint)
912 if (rHint.GetId() == SfxHintId::Dying)
914 mbListeningToViewShellBase = false;
915 Update();
916 release();
920 void LifetimeController::Update()
922 if (mbListeningToViewShellBase && mbListeningToController)
924 // Both the controller and the ViewShellBase are alive. Keep
925 // waiting for their destruction.
927 else if (mbListeningToViewShellBase)
929 // The controller has been destroyed but the ViewShellBase is still
930 // alive. Dispose the associated FrameworkHelper but keep it around
931 // so that no new instance is created for the dying framework.
932 ::sd::framework::FrameworkHelper::DisposeInstance(mrBase);
934 else
936 // Both the controller and the ViewShellBase have been destroyed.
937 // Remove the FrameworkHelper so that the next call its Instance()
938 // method can create a new instance.
939 ::sd::framework::FrameworkHelper::ReleaseInstance(mrBase);
943 } // end of anonymous namespace.
945 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */