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 .
21 #include "MasterPageObserver.hxx"
24 #include "drawdoc.hxx"
26 #include <boost/unordered_map.hpp>
29 #include <svl/lstner.hxx>
30 #include <osl/doublecheckedlocking.h>
31 #include <osl/getglobalmutex.hxx>
36 class MasterPageObserver::Implementation
40 /** The single instance of this class. It is created on demand when
41 Instance() is called for the first time.
43 static MasterPageObserver
* mpInstance
;
45 /** The master page observer will listen to events of this document and
46 detect changes of the use of master pages.
48 void RegisterDocument (SdDrawDocument
& rDocument
);
50 /** The master page observer will stop to listen to events of this
53 void UnregisterDocument (SdDrawDocument
& rDocument
);
55 /** Add a listener that is informed of master pages that are newly
56 assigned to slides or become unassigned.
58 The event listener to call for future events. Call
59 RemoveEventListener() before the listener is destroyed.
61 void AddEventListener (const Link
& rEventListener
);
63 /** Remove the given listener from the list of listeners.
65 After this method returns the given listener is not called back
66 from this object. Passing a listener that has not
67 been registered before is safe and is silently ignored.
69 void RemoveEventListener (const Link
& rEventListener
);
71 /** Return a set of the names of master pages for the given document.
72 This convenience method exists because this set is part of the
73 internal data structure and thus takes no time to create.
75 inline MasterPageObserver::MasterPageNameSet
GetMasterPageNames (
76 SdDrawDocument
& rDocument
);
79 ::std::vector
<Link
> maListeners
;
82 size_t operator()(SdDrawDocument
* argument
) const
83 { return reinterpret_cast<unsigned long>(argument
); }
85 typedef ::boost::unordered_map
<SdDrawDocument
*,
86 MasterPageObserver::MasterPageNameSet
,
89 MasterPageContainer maUsedMasterPages
;
92 SfxBroadcaster
& rBroadcaster
,
93 const SfxHint
& rHint
);
95 void AnalyzeUsedMasterPages (SdDrawDocument
& rDocument
);
97 void SendEvent (MasterPageObserverEvent
& rEvent
);
100 MasterPageObserver
* MasterPageObserver::Implementation::mpInstance
= NULL
;
104 //===== MasterPageObserver ====================================================
106 MasterPageObserver
& MasterPageObserver::Instance (void)
108 if (Implementation::mpInstance
== NULL
)
110 ::osl::GetGlobalMutex aMutexFunctor
;
111 ::osl::MutexGuard
aGuard (aMutexFunctor());
112 if (Implementation::mpInstance
== NULL
)
114 MasterPageObserver
* pInstance
= new MasterPageObserver ();
115 SdGlobalResourceContainer::Instance().AddResource (
116 ::std::auto_ptr
<SdGlobalResource
>(pInstance
));
117 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
118 Implementation::mpInstance
= pInstance
;
123 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
126 DBG_ASSERT(Implementation::mpInstance
!=NULL
,
127 "MasterPageObserver::Instance(): instance is NULL");
128 return *Implementation::mpInstance
;
134 void MasterPageObserver::RegisterDocument (SdDrawDocument
& rDocument
)
136 mpImpl
->RegisterDocument (rDocument
);
142 void MasterPageObserver::UnregisterDocument (SdDrawDocument
& rDocument
)
144 mpImpl
->UnregisterDocument (rDocument
);
150 void MasterPageObserver::AddEventListener (const Link
& rEventListener
)
153 mpImpl
->AddEventListener (rEventListener
);
159 void MasterPageObserver::RemoveEventListener (const Link
& rEventListener
)
161 mpImpl
->RemoveEventListener (rEventListener
);
167 MasterPageObserver::MasterPageObserver (void)
168 : mpImpl (new Implementation())
174 MasterPageObserver::~MasterPageObserver (void)
180 //===== MasterPageObserver::Implementation ====================================
182 void MasterPageObserver::Implementation::RegisterDocument (
183 SdDrawDocument
& rDocument
)
185 // Gather the names of all the master pages in the given document.
186 MasterPageContainer::mapped_type aMasterPageSet
;
187 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
188 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
190 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
191 if (pMasterPage
!= NULL
)
192 aMasterPageSet
.insert (pMasterPage
->GetName());
195 maUsedMasterPages
[&rDocument
] = aMasterPageSet
;
197 StartListening (rDocument
);
203 void MasterPageObserver::Implementation::UnregisterDocument (
204 SdDrawDocument
& rDocument
)
206 EndListening (rDocument
);
208 MasterPageContainer::iterator
aMasterPageDescriptor(maUsedMasterPages
.find(&rDocument
));
209 if(aMasterPageDescriptor
!= maUsedMasterPages
.end())
210 maUsedMasterPages
.erase(aMasterPageDescriptor
);
216 void MasterPageObserver::Implementation::AddEventListener (
217 const Link
& rEventListener
)
222 rEventListener
) == maListeners
.end())
224 maListeners
.push_back (rEventListener
);
226 // Tell the new listener about all the master pages that are
228 MasterPageContainer::iterator aDocumentIterator
;
229 for (aDocumentIterator
=maUsedMasterPages
.begin();
230 aDocumentIterator
!=maUsedMasterPages
.end();
233 ::std::set
<String
>::reverse_iterator aNameIterator
;
234 for (aNameIterator
=aDocumentIterator
->second
.rbegin();
235 aNameIterator
!=aDocumentIterator
->second
.rend();
238 MasterPageObserverEvent
aEvent (
239 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
,
240 *aDocumentIterator
->first
,
251 void MasterPageObserver::Implementation::RemoveEventListener (
252 const Link
& rEventListener
)
264 MasterPageObserver::MasterPageNameSet
265 MasterPageObserver::Implementation::GetMasterPageNames (
266 SdDrawDocument
& rDocument
)
268 MasterPageContainer::iterator
aMasterPageDescriptor (
269 maUsedMasterPages
.find(&rDocument
));
270 if (aMasterPageDescriptor
!= maUsedMasterPages
.end())
271 return aMasterPageDescriptor
->second
;
273 // Not found so return an empty set.
274 return MasterPageObserver::MasterPageNameSet();
280 void MasterPageObserver::Implementation::Notify(
281 SfxBroadcaster
& rBroadcaster
,
282 const SfxHint
& rHint
)
284 if (rHint
.ISA(SdrHint
))
286 SdrHint
& rSdrHint (*PTR_CAST(SdrHint
,&rHint
));
287 switch (rSdrHint
.GetKind())
289 case HINT_PAGEORDERCHG
:
290 // Process the modified set of pages only when the number of
291 // standard and notes master pages are equal. This test
292 // filters out events that are sent in between the insertion
293 // of a new standard master page and a new notes master
295 if (rBroadcaster
.ISA(SdDrawDocument
))
297 SdDrawDocument
& rDocument (
298 static_cast<SdDrawDocument
&>(rBroadcaster
));
299 if (rDocument
.GetMasterSdPageCount(PK_STANDARD
)
300 == rDocument
.GetMasterSdPageCount(PK_NOTES
))
302 AnalyzeUsedMasterPages (rDocument
);
316 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
317 SdDrawDocument
& rDocument
)
319 // Create a set of names of the master pages used by the given document.
320 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
321 ::std::set
<String
> aCurrentMasterPages
;
322 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
324 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
325 if (pMasterPage
!= NULL
)
326 aCurrentMasterPages
.insert (pMasterPage
->GetName());
327 OSL_TRACE("currently used master page %d is %s",
329 OUStringToOString(pMasterPage
->GetName(),
330 RTL_TEXTENCODING_UTF8
).getStr());
333 typedef ::std::vector
<String
> StringList
;
334 StringList aNewMasterPages
;
335 StringList aRemovedMasterPages
;
336 MasterPageContainer::iterator
aOldMasterPagesDescriptor (
337 maUsedMasterPages
.find(&rDocument
));
338 if (aOldMasterPagesDescriptor
!= maUsedMasterPages
.end())
340 StringList::iterator I
;
342 ::std::set
<String
>::iterator J
;
344 for (J
=aOldMasterPagesDescriptor
->second
.begin();
345 J
!=aOldMasterPagesDescriptor
->second
.end();
347 OSL_TRACE("old used master page %d is %s",
349 OUStringToOString(*J
,
350 RTL_TEXTENCODING_UTF8
).getStr());
352 // Send events about the newly used master pages.
353 ::std::set_difference (
354 aCurrentMasterPages
.begin(),
355 aCurrentMasterPages
.end(),
356 aOldMasterPagesDescriptor
->second
.begin(),
357 aOldMasterPagesDescriptor
->second
.end(),
358 ::std::back_insert_iterator
<StringList
>(aNewMasterPages
));
359 for (I
=aNewMasterPages
.begin(); I
!=aNewMasterPages
.end(); ++I
)
361 OSL_TRACE(" added master page %s",
362 OUStringToOString(*I
,
363 RTL_TEXTENCODING_UTF8
).getStr());
365 MasterPageObserverEvent
aEvent (
366 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
,
372 // Send events about master pages that are not used any longer.
373 ::std::set_difference (
374 aOldMasterPagesDescriptor
->second
.begin(),
375 aOldMasterPagesDescriptor
->second
.end(),
376 aCurrentMasterPages
.begin(),
377 aCurrentMasterPages
.end(),
378 ::std::back_insert_iterator
<StringList
>(aRemovedMasterPages
));
379 for (I
=aRemovedMasterPages
.begin(); I
!=aRemovedMasterPages
.end(); ++I
)
381 OSL_TRACE(" removed master page %s",
382 OUStringToOString(*I
,
383 RTL_TEXTENCODING_UTF8
).getStr());
385 MasterPageObserverEvent
aEvent (
386 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
,
392 // Store the new list of master pages.
393 aOldMasterPagesDescriptor
->second
= aCurrentMasterPages
;
400 void MasterPageObserver::Implementation::SendEvent (
401 MasterPageObserverEvent
& rEvent
)
403 ::std::vector
<Link
>::iterator
aLink (maListeners
.begin());
404 ::std::vector
<Link
>::iterator
aEnd (maListeners
.end());
407 aLink
->Call (&rEvent
);
413 } // end of namespace sd
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */