1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <MasterPageObserver.hxx>
24 #include <drawdoc.hxx>
27 #include <unordered_map>
30 #include <svl/lstner.hxx>
31 #include <osl/doublecheckedlocking.h>
32 #include <osl/getglobalmutex.hxx>
33 #include <tools/debug.hxx>
37 class MasterPageObserver::Implementation
41 /** The single instance of this class. It is created on demand when
42 Instance() is called for the first time.
44 static MasterPageObserver
* mpInstance
;
46 /** The master page observer will listen to events of this document and
47 detect changes of the use of master pages.
49 void RegisterDocument (SdDrawDocument
& rDocument
);
51 /** The master page observer will stop to listen to events of this
54 void UnregisterDocument (SdDrawDocument
& rDocument
);
56 /** Add a listener that is informed of master pages that are newly
57 assigned to slides or become unassigned.
59 The event listener to call for future events. Call
60 RemoveEventListener() before the listener is destroyed.
62 void AddEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
);
64 /** Remove the given listener from the list of listeners.
66 After this method returns the given listener is not called back
67 from this object. Passing a listener that has not
68 been registered before is safe and is silently ignored.
70 void RemoveEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
);
73 ::std::vector
<Link
<MasterPageObserverEvent
&,void>> maListeners
;
76 size_t operator()(SdDrawDocument
* argument
) const
77 { return reinterpret_cast<unsigned long>(argument
); }
79 typedef std::unordered_map
<SdDrawDocument
*,
80 MasterPageObserver::MasterPageNameSet
,
83 MasterPageContainer maUsedMasterPages
;
86 SfxBroadcaster
& rBroadcaster
,
87 const SfxHint
& rHint
) override
;
89 void AnalyzeUsedMasterPages (SdDrawDocument
& rDocument
);
91 void SendEvent (MasterPageObserverEvent
& rEvent
);
94 MasterPageObserver
* MasterPageObserver::Implementation::mpInstance
= nullptr;
96 //===== MasterPageObserver ====================================================
98 MasterPageObserver
& MasterPageObserver::Instance()
100 if (Implementation::mpInstance
== nullptr)
102 ::osl::GetGlobalMutex aMutexFunctor
;
103 ::osl::MutexGuard
aGuard (aMutexFunctor());
104 if (Implementation::mpInstance
== nullptr)
106 MasterPageObserver
* pInstance
= new MasterPageObserver ();
107 SdGlobalResourceContainer::Instance().AddResource (
108 ::std::unique_ptr
<SdGlobalResource
>(pInstance
));
109 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
110 Implementation::mpInstance
= pInstance
;
115 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
118 DBG_ASSERT(Implementation::mpInstance
!=nullptr,
119 "MasterPageObserver::Instance(): instance is NULL");
120 return *Implementation::mpInstance
;
123 void MasterPageObserver::RegisterDocument (SdDrawDocument
& rDocument
)
125 mpImpl
->RegisterDocument (rDocument
);
128 void MasterPageObserver::UnregisterDocument (SdDrawDocument
& rDocument
)
130 mpImpl
->UnregisterDocument (rDocument
);
133 void MasterPageObserver::AddEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
136 mpImpl
->AddEventListener (rEventListener
);
139 void MasterPageObserver::RemoveEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
141 mpImpl
->RemoveEventListener (rEventListener
);
144 MasterPageObserver::MasterPageObserver()
145 : mpImpl (new Implementation
)
148 MasterPageObserver::~MasterPageObserver()
151 //===== MasterPageObserver::Implementation ====================================
153 void MasterPageObserver::Implementation::RegisterDocument (
154 SdDrawDocument
& rDocument
)
156 // Gather the names of all the master pages in the given document.
157 MasterPageContainer::mapped_type aMasterPageSet
;
158 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PageKind::Standard
);
159 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
161 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PageKind::Standard
);
162 if (pMasterPage
!= nullptr)
163 aMasterPageSet
.insert (pMasterPage
->GetName());
166 bool bAlreadyExists
= maUsedMasterPages
.find(&rDocument
) != maUsedMasterPages
.end();
167 maUsedMasterPages
[&rDocument
] = aMasterPageSet
;
170 StartListening (rDocument
);
173 void MasterPageObserver::Implementation::UnregisterDocument (
174 SdDrawDocument
& rDocument
)
176 EndListening (rDocument
);
178 MasterPageContainer::iterator
aMasterPageDescriptor(maUsedMasterPages
.find(&rDocument
));
179 if(aMasterPageDescriptor
!= maUsedMasterPages
.end())
180 maUsedMasterPages
.erase(aMasterPageDescriptor
);
183 void MasterPageObserver::Implementation::AddEventListener (
184 const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
189 rEventListener
) != maListeners
.end())
192 maListeners
.push_back (rEventListener
);
194 // Tell the new listener about all the master pages that are
196 for (const auto& rDocument
: maUsedMasterPages
)
198 ::std::set
<OUString
>::reverse_iterator aNameIterator
;
199 for (aNameIterator
=rDocument
.second
.rbegin();
200 aNameIterator
!=rDocument
.second
.rend();
203 MasterPageObserverEvent
aEvent (
204 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
,
211 void MasterPageObserver::Implementation::RemoveEventListener (
212 const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
221 void MasterPageObserver::Implementation::Notify(
222 SfxBroadcaster
& rBroadcaster
,
223 const SfxHint
& rHint
)
225 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
227 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
229 switch (pSdrHint
->GetKind())
231 case SdrHintKind::PageOrderChange
:
232 // Process the modified set of pages only when the number of
233 // standard and notes master pages are equal. This test
234 // filters out events that are sent in between the insertion
235 // of a new standard master page and a new notes master
237 if (dynamic_cast< const SdDrawDocument
*>( &rBroadcaster
) != nullptr)
239 SdDrawDocument
& rDocument (
240 static_cast<SdDrawDocument
&>(rBroadcaster
));
241 if (rDocument
.GetMasterSdPageCount(PageKind::Standard
)
242 == rDocument
.GetMasterSdPageCount(PageKind::Notes
))
244 AnalyzeUsedMasterPages (rDocument
);
254 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
255 SdDrawDocument
& rDocument
)
257 // Create a set of names of the master pages used by the given document.
258 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PageKind::Standard
);
259 ::std::set
<OUString
> aCurrentMasterPages
;
260 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
262 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PageKind::Standard
);
263 if (pMasterPage
!= nullptr)
264 aCurrentMasterPages
.insert (pMasterPage
->GetName());
267 std::vector
<OUString
> aNewMasterPages
;
268 std::vector
<OUString
> aRemovedMasterPages
;
269 MasterPageContainer::iterator
aOldMasterPagesDescriptor (
270 maUsedMasterPages
.find(&rDocument
));
271 if (aOldMasterPagesDescriptor
== maUsedMasterPages
.end())
274 // Send events about the newly used master pages.
275 ::std::set_difference (
276 aCurrentMasterPages
.begin(),
277 aCurrentMasterPages
.end(),
278 aOldMasterPagesDescriptor
->second
.begin(),
279 aOldMasterPagesDescriptor
->second
.end(),
280 std::back_inserter(aNewMasterPages
));
281 for (auto& aNewMasterPage
: aNewMasterPages
)
283 MasterPageObserverEvent
aEvent (
284 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
,
289 // Send events about master pages that are not used any longer.
290 ::std::set_difference (
291 aOldMasterPagesDescriptor
->second
.begin(),
292 aOldMasterPagesDescriptor
->second
.end(),
293 aCurrentMasterPages
.begin(),
294 aCurrentMasterPages
.end(),
295 std::back_inserter(aRemovedMasterPages
));
296 for (auto& aRemovedMasterPage
: aRemovedMasterPages
)
298 MasterPageObserverEvent
aEvent (
299 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
,
304 // Store the new list of master pages.
305 aOldMasterPagesDescriptor
->second
= aCurrentMasterPages
;
308 void MasterPageObserver::Implementation::SendEvent (
309 MasterPageObserverEvent
& rEvent
)
311 for (auto& aLink
: maListeners
)
317 } // end of namespace sd
319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */