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 master page observer will listen to events of this document and
42 detect changes of the use of master pages.
44 void RegisterDocument (SdDrawDocument
& rDocument
);
46 /** The master page observer will stop to listen to events of this
49 void UnregisterDocument (SdDrawDocument
& rDocument
);
51 /** Add a listener that is informed of master pages that are newly
52 assigned to slides or become unassigned.
54 The event listener to call for future events. Call
55 RemoveEventListener() before the listener is destroyed.
57 void AddEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
);
59 /** Remove the given listener from the list of listeners.
61 After this method returns the given listener is not called back
62 from this object. Passing a listener that has not
63 been registered before is safe and is silently ignored.
65 void RemoveEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
);
68 ::std::vector
<Link
<MasterPageObserverEvent
&,void>> maListeners
;
71 size_t operator()(SdDrawDocument
* argument
) const
72 { return reinterpret_cast<sal_uIntPtr
>(argument
); }
74 typedef std::unordered_map
<SdDrawDocument
*,
75 MasterPageObserver::MasterPageNameSet
,
78 MasterPageContainer maUsedMasterPages
;
81 SfxBroadcaster
& rBroadcaster
,
82 const SfxHint
& rHint
) override
;
84 void AnalyzeUsedMasterPages (SdDrawDocument
& rDocument
);
86 void SendEvent (MasterPageObserverEvent
& rEvent
);
89 //===== MasterPageObserver ====================================================
91 MasterPageObserver
& MasterPageObserver::Instance()
93 static MasterPageObserver
* gInstance
= []()
95 MasterPageObserver
* pInstance
= new MasterPageObserver ();
96 SdGlobalResourceContainer::Instance().AddResource (
97 ::std::unique_ptr
<SdGlobalResource
>(pInstance
));
103 void MasterPageObserver::RegisterDocument (SdDrawDocument
& rDocument
)
105 mpImpl
->RegisterDocument (rDocument
);
108 void MasterPageObserver::UnregisterDocument (SdDrawDocument
& rDocument
)
110 mpImpl
->UnregisterDocument (rDocument
);
113 void MasterPageObserver::AddEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
116 mpImpl
->AddEventListener (rEventListener
);
119 void MasterPageObserver::RemoveEventListener (const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
121 mpImpl
->RemoveEventListener (rEventListener
);
124 MasterPageObserver::MasterPageObserver()
125 : mpImpl (new Implementation
)
128 MasterPageObserver::~MasterPageObserver()
131 //===== MasterPageObserver::Implementation ====================================
133 void MasterPageObserver::Implementation::RegisterDocument (
134 SdDrawDocument
& rDocument
)
136 // Gather the names of all the master pages in the given document.
137 MasterPageContainer::mapped_type aMasterPageSet
;
138 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PageKind::Standard
);
139 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
141 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PageKind::Standard
);
142 if (pMasterPage
!= nullptr)
143 aMasterPageSet
.insert (pMasterPage
->GetName());
146 bool bAlreadyExists
= maUsedMasterPages
.find(&rDocument
) != maUsedMasterPages
.end();
147 maUsedMasterPages
[&rDocument
] = std::move(aMasterPageSet
);
150 StartListening (rDocument
);
153 void MasterPageObserver::Implementation::UnregisterDocument (
154 SdDrawDocument
& rDocument
)
156 EndListening (rDocument
);
158 MasterPageContainer::iterator
aMasterPageDescriptor(maUsedMasterPages
.find(&rDocument
));
159 if(aMasterPageDescriptor
!= maUsedMasterPages
.end())
160 maUsedMasterPages
.erase(aMasterPageDescriptor
);
163 void MasterPageObserver::Implementation::AddEventListener (
164 const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
169 rEventListener
) != maListeners
.end())
172 maListeners
.push_back (rEventListener
);
174 // Tell the new listener about all the master pages that are
176 for (const auto& rDocument
: maUsedMasterPages
)
178 ::std::set
<OUString
>::reverse_iterator aNameIterator
;
179 for (aNameIterator
=rDocument
.second
.rbegin();
180 aNameIterator
!=rDocument
.second
.rend();
183 MasterPageObserverEvent
aEvent (
184 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
,
191 void MasterPageObserver::Implementation::RemoveEventListener (
192 const Link
<MasterPageObserverEvent
&,void>& rEventListener
)
201 void MasterPageObserver::Implementation::Notify(
202 SfxBroadcaster
& rBroadcaster
,
203 const SfxHint
& rHint
)
205 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
207 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
209 switch (pSdrHint
->GetKind())
211 case SdrHintKind::PageOrderChange
:
212 // Process the modified set of pages only when the number of
213 // standard and notes master pages are equal. This test
214 // filters out events that are sent in between the insertion
215 // of a new standard master page and a new notes master
217 if (auto pDrawDocument
= dynamic_cast<SdDrawDocument
*>( &rBroadcaster
))
219 if (pDrawDocument
->GetMasterSdPageCount(PageKind::Standard
)
220 == pDrawDocument
->GetMasterSdPageCount(PageKind::Notes
))
222 AnalyzeUsedMasterPages (*pDrawDocument
);
232 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
233 SdDrawDocument
& rDocument
)
235 // Create a set of names of the master pages used by the given document.
236 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PageKind::Standard
);
237 ::std::set
<OUString
> aCurrentMasterPages
;
238 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
240 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PageKind::Standard
);
241 if (pMasterPage
!= nullptr)
242 aCurrentMasterPages
.insert (pMasterPage
->GetName());
245 std::vector
<OUString
> aNewMasterPages
;
246 std::vector
<OUString
> aRemovedMasterPages
;
247 MasterPageContainer::iterator
aOldMasterPagesDescriptor (
248 maUsedMasterPages
.find(&rDocument
));
249 if (aOldMasterPagesDescriptor
== maUsedMasterPages
.end())
252 // Send events about the newly used master pages.
253 ::std::set_difference (
254 aCurrentMasterPages
.begin(),
255 aCurrentMasterPages
.end(),
256 aOldMasterPagesDescriptor
->second
.begin(),
257 aOldMasterPagesDescriptor
->second
.end(),
258 std::back_inserter(aNewMasterPages
));
259 for (const auto& aNewMasterPage
: aNewMasterPages
)
261 MasterPageObserverEvent
aEvent (
262 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
,
267 // Send events about master pages that are not used any longer.
268 ::std::set_difference (
269 aOldMasterPagesDescriptor
->second
.begin(),
270 aOldMasterPagesDescriptor
->second
.end(),
271 aCurrentMasterPages
.begin(),
272 aCurrentMasterPages
.end(),
273 std::back_inserter(aRemovedMasterPages
));
274 for (const auto& aRemovedMasterPage
: aRemovedMasterPages
)
276 MasterPageObserverEvent
aEvent (
277 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
,
282 // Store the new list of master pages.
283 aOldMasterPagesDescriptor
->second
= std::move(aCurrentMasterPages
);
286 void MasterPageObserver::Implementation::SendEvent (
287 MasterPageObserverEvent
& rEvent
)
289 for (const auto& aLink
: maListeners
)
295 } // end of namespace sd
297 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */