1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sd.hxx"
31 #include "MasterPageObserver.hxx"
34 #include "drawdoc.hxx"
39 #include <svl/lstner.hxx>
40 #include <osl/doublecheckedlocking.h>
41 #include <osl/getglobalmutex.hxx>
46 class MasterPageObserver::Implementation
50 /** The single instance of this class. It is created on demand when
51 Instance() is called for the first time.
53 static MasterPageObserver
* mpInstance
;
55 /** The master page observer will listen to events of this document and
56 detect changes of the use of master pages.
58 void RegisterDocument (SdDrawDocument
& rDocument
);
60 /** The master page observer will stop to listen to events of this
63 void UnregisterDocument (SdDrawDocument
& rDocument
);
65 /** Add a listener that is informed of master pages that are newly
66 assigned to slides or become unassigned.
68 The event listener to call for future events. Call
69 RemoveEventListener() before the listener is destroyed.
71 void AddEventListener (const Link
& rEventListener
);
73 /** Remove the given listener from the list of listeners.
75 After this method returns the given listener is not called back
76 from this object. Passing a listener that has not
77 been registered before is safe and is silently ignored.
79 void RemoveEventListener (const Link
& rEventListener
);
81 /** Return a set of the names of master pages for the given document.
82 This convenience method exists because this set is part of the
83 internal data structure and thus takes no time to create.
85 inline MasterPageObserver::MasterPageNameSet
GetMasterPageNames (
86 SdDrawDocument
& rDocument
);
89 ::std::vector
<Link
> maListeners
;
92 size_t operator()(SdDrawDocument
* argument
) const
93 { return reinterpret_cast<unsigned long>(argument
); }
95 typedef ::std::hash_map
<SdDrawDocument
*,
96 MasterPageObserver::MasterPageNameSet
,
99 MasterPageContainer maUsedMasterPages
;
102 SfxBroadcaster
& rBroadcaster
,
103 const SfxHint
& rHint
);
105 void AnalyzeUsedMasterPages (SdDrawDocument
& rDocument
);
107 void SendEvent (MasterPageObserverEvent
& rEvent
);
110 MasterPageObserver
* MasterPageObserver::Implementation::mpInstance
= NULL
;
114 //===== MasterPageObserver ====================================================
116 MasterPageObserver
& MasterPageObserver::Instance (void)
118 if (Implementation::mpInstance
== NULL
)
120 ::osl::GetGlobalMutex aMutexFunctor
;
121 ::osl::MutexGuard
aGuard (aMutexFunctor());
122 if (Implementation::mpInstance
== NULL
)
124 MasterPageObserver
* pInstance
= new MasterPageObserver ();
125 SdGlobalResourceContainer::Instance().AddResource (
126 ::std::auto_ptr
<SdGlobalResource
>(pInstance
));
127 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
128 Implementation::mpInstance
= pInstance
;
133 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
136 DBG_ASSERT(Implementation::mpInstance
!=NULL
,
137 "MasterPageObserver::Instance(): instance is NULL");
138 return *Implementation::mpInstance
;
144 void MasterPageObserver::RegisterDocument (SdDrawDocument
& rDocument
)
146 mpImpl
->RegisterDocument (rDocument
);
152 void MasterPageObserver::UnregisterDocument (SdDrawDocument
& rDocument
)
154 mpImpl
->UnregisterDocument (rDocument
);
160 void MasterPageObserver::AddEventListener (const Link
& rEventListener
)
163 mpImpl
->AddEventListener (rEventListener
);
169 void MasterPageObserver::RemoveEventListener (const Link
& rEventListener
)
171 mpImpl
->RemoveEventListener (rEventListener
);
177 MasterPageObserver::MasterPageObserver (void)
178 : mpImpl (new Implementation())
184 MasterPageObserver::~MasterPageObserver (void)
190 //===== MasterPageObserver::Implementation ====================================
192 void MasterPageObserver::Implementation::RegisterDocument (
193 SdDrawDocument
& rDocument
)
195 // Gather the names of all the master pages in the given document.
196 MasterPageContainer::data_type aMasterPageSet
;
197 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
198 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
200 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
201 if (pMasterPage
!= NULL
)
202 aMasterPageSet
.insert (pMasterPage
->GetName());
205 maUsedMasterPages
[&rDocument
] = aMasterPageSet
;
207 StartListening (rDocument
);
213 void MasterPageObserver::Implementation::UnregisterDocument (
214 SdDrawDocument
& rDocument
)
216 EndListening (rDocument
);
218 MasterPageContainer::iterator
aMasterPageDescriptor(maUsedMasterPages
.find(&rDocument
));
219 if(aMasterPageDescriptor
!= maUsedMasterPages
.end())
220 maUsedMasterPages
.erase(aMasterPageDescriptor
);
226 void MasterPageObserver::Implementation::AddEventListener (
227 const Link
& rEventListener
)
232 rEventListener
) == maListeners
.end())
234 maListeners
.push_back (rEventListener
);
236 // Tell the new listener about all the master pages that are
238 typedef ::std::vector
<String
> StringList
;
239 StringList aNewMasterPages
;
240 StringList aRemovedMasterPages
;
241 MasterPageContainer::iterator aDocumentIterator
;
242 for (aDocumentIterator
=maUsedMasterPages
.begin();
243 aDocumentIterator
!=maUsedMasterPages
.end();
246 ::std::set
<String
>::reverse_iterator aNameIterator
;
247 for (aNameIterator
=aDocumentIterator
->second
.rbegin();
248 aNameIterator
!=aDocumentIterator
->second
.rend();
251 MasterPageObserverEvent
aEvent (
252 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
,
253 *aDocumentIterator
->first
,
264 void MasterPageObserver::Implementation::RemoveEventListener (
265 const Link
& rEventListener
)
277 MasterPageObserver::MasterPageNameSet
278 MasterPageObserver::Implementation::GetMasterPageNames (
279 SdDrawDocument
& rDocument
)
281 MasterPageContainer::iterator
aMasterPageDescriptor (
282 maUsedMasterPages
.find(&rDocument
));
283 if (aMasterPageDescriptor
!= maUsedMasterPages
.end())
284 return aMasterPageDescriptor
->second
;
286 // Not found so return an empty set.
287 return MasterPageObserver::MasterPageNameSet();
293 void MasterPageObserver::Implementation::Notify(
294 SfxBroadcaster
& rBroadcaster
,
295 const SfxHint
& rHint
)
297 if (rHint
.ISA(SdrHint
))
299 SdrHint
& rSdrHint (*PTR_CAST(SdrHint
,&rHint
));
300 switch (rSdrHint
.GetKind())
302 case HINT_PAGEORDERCHG
:
303 // Process the modified set of pages only when the number of
304 // standard and notes master pages are equal. This test
305 // filters out events that are sent in between the insertion
306 // of a new standard master page and a new notes master
308 if (rBroadcaster
.ISA(SdDrawDocument
))
310 SdDrawDocument
& rDocument (
311 static_cast<SdDrawDocument
&>(rBroadcaster
));
312 if (rDocument
.GetMasterSdPageCount(PK_STANDARD
)
313 == rDocument
.GetMasterSdPageCount(PK_NOTES
))
315 AnalyzeUsedMasterPages (rDocument
);
329 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
330 SdDrawDocument
& rDocument
)
332 // Create a set of names of the master pages used by the given document.
333 sal_uInt16 nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
334 ::std::set
<String
> aCurrentMasterPages
;
335 for (sal_uInt16 nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
337 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
338 if (pMasterPage
!= NULL
)
339 aCurrentMasterPages
.insert (pMasterPage
->GetName());
340 OSL_TRACE("currently used master page %d is %s",
342 ::rtl::OUStringToOString(pMasterPage
->GetName(),
343 RTL_TEXTENCODING_UTF8
).getStr());
346 typedef ::std::vector
<String
> StringList
;
347 StringList aNewMasterPages
;
348 StringList aRemovedMasterPages
;
349 MasterPageContainer::iterator
aOldMasterPagesDescriptor (
350 maUsedMasterPages
.find(&rDocument
));
351 if (aOldMasterPagesDescriptor
!= maUsedMasterPages
.end())
353 StringList::iterator I
;
355 ::std::set
<String
>::iterator J
;
357 for (J
=aOldMasterPagesDescriptor
->second
.begin();
358 J
!=aOldMasterPagesDescriptor
->second
.end();
360 OSL_TRACE("old used master page %d is %s",
362 ::rtl::OUStringToOString(*J
,
363 RTL_TEXTENCODING_UTF8
).getStr());
365 // Send events about the newly used master pages.
366 ::std::set_difference (
367 aCurrentMasterPages
.begin(),
368 aCurrentMasterPages
.end(),
369 aOldMasterPagesDescriptor
->second
.begin(),
370 aOldMasterPagesDescriptor
->second
.end(),
371 ::std::back_insert_iterator
<StringList
>(aNewMasterPages
));
372 for (I
=aNewMasterPages
.begin(); I
!=aNewMasterPages
.end(); ++I
)
374 OSL_TRACE(" added master page %s",
375 ::rtl::OUStringToOString(*I
,
376 RTL_TEXTENCODING_UTF8
).getStr());
378 MasterPageObserverEvent
aEvent (
379 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
,
385 // Send events about master pages that are not used any longer.
386 ::std::set_difference (
387 aOldMasterPagesDescriptor
->second
.begin(),
388 aOldMasterPagesDescriptor
->second
.end(),
389 aCurrentMasterPages
.begin(),
390 aCurrentMasterPages
.end(),
391 ::std::back_insert_iterator
<StringList
>(aRemovedMasterPages
));
392 for (I
=aRemovedMasterPages
.begin(); I
!=aRemovedMasterPages
.end(); ++I
)
394 OSL_TRACE(" removed master page %s",
395 ::rtl::OUStringToOString(*I
,
396 RTL_TEXTENCODING_UTF8
).getStr());
398 MasterPageObserverEvent
aEvent (
399 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
,
405 // Store the new list of master pages.
406 aOldMasterPagesDescriptor
->second
= aCurrentMasterPages
;
413 void MasterPageObserver::Implementation::SendEvent (
414 MasterPageObserverEvent
& rEvent
)
416 ::std::vector
<Link
>::iterator
aLink (maListeners
.begin());
417 ::std::vector
<Link
>::iterator
aEnd (maListeners
.end());
420 aLink
->Call (&rEvent
);
426 } // end of namespace sd