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"
23 #include "drawdoc.hxx"
26 #include <unordered_map>
28 #include <svl/lstner.hxx>
29 #include <osl/doublecheckedlocking.h>
30 #include <osl/getglobalmutex.hxx>
34 class MasterPageObserver::Implementation
38 /** The single instance of this class. It is created on demand when
39 Instance() is called for the first time.
41 static MasterPageObserver
* mpInstance
;
43 /** The master page observer will listen to events of this document and
44 detect changes of the use of master pages.
46 void RegisterDocument (SdDrawDocument
& rDocument
);
48 /** The master page observer will stop to listen to events of this
51 void UnregisterDocument (SdDrawDocument
& rDocument
);
53 /** Add a listener that is informed of master pages that are newly
54 assigned to slides or become unassigned.
56 The event listener to call for future events. Call
57 RemoveEventListener() before the listener is destroyed.
59 void AddEventListener (const Link
<>& rEventListener
);
61 /** Remove the given listener from the list of listeners.
63 After this method returns the given listener is not called back
64 from this object. Passing a listener that has not
65 been registered before is safe and is silently ignored.
67 void RemoveEventListener (const Link
<>& rEventListener
);
70 ::std::vector
<Link
<>> maListeners
;
73 size_t operator()(SdDrawDocument
* argument
) const
74 { return reinterpret_cast<unsigned long>(argument
); }
76 typedef std::unordered_map
<SdDrawDocument
*,
77 MasterPageObserver::MasterPageNameSet
,
80 MasterPageContainer maUsedMasterPages
;
83 SfxBroadcaster
& rBroadcaster
,
84 const SfxHint
& rHint
) SAL_OVERRIDE
;
86 void AnalyzeUsedMasterPages (SdDrawDocument
& rDocument
);
88 void SendEvent (MasterPageObserverEvent
& rEvent
);
91 MasterPageObserver
* MasterPageObserver::Implementation::mpInstance
= NULL
;
93 //===== MasterPageObserver ====================================================
95 MasterPageObserver
& MasterPageObserver::Instance()
97 if (Implementation::mpInstance
== NULL
)
99 ::osl::GetGlobalMutex aMutexFunctor
;
100 ::osl::MutexGuard
aGuard (aMutexFunctor());
101 if (Implementation::mpInstance
== NULL
)
103 MasterPageObserver
* pInstance
= new MasterPageObserver ();
104 SdGlobalResourceContainer::Instance().AddResource (
105 ::std::unique_ptr
<SdGlobalResource
>(pInstance
));
106 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
107 Implementation::mpInstance
= pInstance
;
112 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
115 DBG_ASSERT(Implementation::mpInstance
!=NULL
,
116 "MasterPageObserver::Instance(): instance is NULL");
117 return *Implementation::mpInstance
;
120 void MasterPageObserver::RegisterDocument (SdDrawDocument
& rDocument
)
122 mpImpl
->RegisterDocument (rDocument
);
125 void MasterPageObserver::UnregisterDocument (SdDrawDocument
& rDocument
)
127 mpImpl
->UnregisterDocument (rDocument
);
130 void MasterPageObserver::AddEventListener (const Link
<>& rEventListener
)
133 mpImpl
->AddEventListener (rEventListener
);
136 void MasterPageObserver::RemoveEventListener (const Link
<>& rEventListener
)
138 mpImpl
->RemoveEventListener (rEventListener
);
141 MasterPageObserver::MasterPageObserver()
142 : mpImpl (new Implementation())
145 MasterPageObserver::~MasterPageObserver()
148 //===== MasterPageObserver::Implementation ====================================
150 void MasterPageObserver::Implementation::RegisterDocument (
151 SdDrawDocument
& rDocument
)
153 // Gather the names of all the master pages in the given document.
154 MasterPageContainer::mapped_type aMasterPageSet
;
155 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
156 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
158 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
159 if (pMasterPage
!= NULL
)
160 aMasterPageSet
.insert (pMasterPage
->GetName());
163 maUsedMasterPages
[&rDocument
] = aMasterPageSet
;
165 StartListening (rDocument
);
168 void MasterPageObserver::Implementation::UnregisterDocument (
169 SdDrawDocument
& rDocument
)
171 EndListening (rDocument
);
173 MasterPageContainer::iterator
aMasterPageDescriptor(maUsedMasterPages
.find(&rDocument
));
174 if(aMasterPageDescriptor
!= maUsedMasterPages
.end())
175 maUsedMasterPages
.erase(aMasterPageDescriptor
);
178 void MasterPageObserver::Implementation::AddEventListener (
179 const Link
<>& rEventListener
)
184 rEventListener
) == maListeners
.end())
186 maListeners
.push_back (rEventListener
);
188 // Tell the new listener about all the master pages that are
190 MasterPageContainer::iterator aDocumentIterator
;
191 for (aDocumentIterator
=maUsedMasterPages
.begin();
192 aDocumentIterator
!=maUsedMasterPages
.end();
195 ::std::set
<OUString
>::reverse_iterator aNameIterator
;
196 for (aNameIterator
=aDocumentIterator
->second
.rbegin();
197 aNameIterator
!=aDocumentIterator
->second
.rend();
200 MasterPageObserverEvent
aEvent (
201 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
,
202 *aDocumentIterator
->first
,
210 void MasterPageObserver::Implementation::RemoveEventListener (
211 const Link
<>& rEventListener
)
220 void MasterPageObserver::Implementation::Notify(
221 SfxBroadcaster
& rBroadcaster
,
222 const SfxHint
& rHint
)
224 const SdrHint
* pSdrHint
= dynamic_cast<const SdrHint
*>(&rHint
);
227 switch (pSdrHint
->GetKind())
229 case HINT_PAGEORDERCHG
:
230 // Process the modified set of pages only when the number of
231 // standard and notes master pages are equal. This test
232 // filters out events that are sent in between the insertion
233 // of a new standard master page and a new notes master
235 if (rBroadcaster
.ISA(SdDrawDocument
))
237 SdDrawDocument
& rDocument (
238 static_cast<SdDrawDocument
&>(rBroadcaster
));
239 if (rDocument
.GetMasterSdPageCount(PK_STANDARD
)
240 == rDocument
.GetMasterSdPageCount(PK_NOTES
))
242 AnalyzeUsedMasterPages (rDocument
);
253 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
254 SdDrawDocument
& rDocument
)
256 // Create a set of names of the master pages used by the given document.
257 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
258 ::std::set
<OUString
> aCurrentMasterPages
;
259 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
261 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
262 if (pMasterPage
!= NULL
)
263 aCurrentMasterPages
.insert (pMasterPage
->GetName());
264 OSL_TRACE("currently used master page %d is %s",
266 ::rtl::OUStringToOString(pMasterPage
->GetName(),
267 RTL_TEXTENCODING_UTF8
).getStr());
270 typedef ::std::vector
<OUString
> StringList
;
271 StringList aNewMasterPages
;
272 StringList aRemovedMasterPages
;
273 MasterPageContainer::iterator
aOldMasterPagesDescriptor (
274 maUsedMasterPages
.find(&rDocument
));
275 if (aOldMasterPagesDescriptor
!= maUsedMasterPages
.end())
277 StringList::iterator I
;
279 ::std::set
<OUString
>::iterator J
;
281 for (J
=aOldMasterPagesDescriptor
->second
.begin();
282 J
!=aOldMasterPagesDescriptor
->second
.end();
284 OSL_TRACE("old used master page %d is %s",
286 ::rtl::OUStringToOString(*J
,
287 RTL_TEXTENCODING_UTF8
).getStr());
289 // Send events about the newly used master pages.
290 ::std::set_difference (
291 aCurrentMasterPages
.begin(),
292 aCurrentMasterPages
.end(),
293 aOldMasterPagesDescriptor
->second
.begin(),
294 aOldMasterPagesDescriptor
->second
.end(),
295 ::std::back_insert_iterator
<StringList
>(aNewMasterPages
));
296 for (I
=aNewMasterPages
.begin(); I
!=aNewMasterPages
.end(); ++I
)
298 OSL_TRACE(" added master page %s",
299 ::rtl::OUStringToOString(*I
,
300 RTL_TEXTENCODING_UTF8
).getStr());
302 MasterPageObserverEvent
aEvent (
303 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
,
309 // Send events about master pages that are not used any longer.
310 ::std::set_difference (
311 aOldMasterPagesDescriptor
->second
.begin(),
312 aOldMasterPagesDescriptor
->second
.end(),
313 aCurrentMasterPages
.begin(),
314 aCurrentMasterPages
.end(),
315 ::std::back_insert_iterator
<StringList
>(aRemovedMasterPages
));
316 for (I
=aRemovedMasterPages
.begin(); I
!=aRemovedMasterPages
.end(); ++I
)
318 OSL_TRACE(" removed master page %s",
319 ::rtl::OUStringToOString(*I
,
320 RTL_TEXTENCODING_UTF8
).getStr());
322 MasterPageObserverEvent
aEvent (
323 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
,
329 // Store the new list of master pages.
330 aOldMasterPagesDescriptor
->second
= aCurrentMasterPages
;
334 void MasterPageObserver::Implementation::SendEvent (
335 MasterPageObserverEvent
& rEvent
)
337 ::std::vector
<Link
<>>::iterator
aLink (maListeners
.begin());
338 ::std::vector
<Link
<>>::iterator
aEnd (maListeners
.end());
341 aLink
->Call (&rEvent
);
346 } // end of namespace sd
348 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */