1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: MasterPageObserver.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sd.hxx"
34 #include "MasterPageObserver.hxx"
37 #include "drawdoc.hxx"
42 #include <svtools/lstner.hxx>
43 #include <osl/doublecheckedlocking.h>
44 #include <osl/getglobalmutex.hxx>
49 class MasterPageObserver::Implementation
53 /** The single instance of this class. It is created on demand when
54 Instance() is called for the first time.
56 static MasterPageObserver
* mpInstance
;
58 /** The master page observer will listen to events of this document and
59 detect changes of the use of master pages.
61 void RegisterDocument (SdDrawDocument
& rDocument
);
63 /** The master page observer will stop to listen to events of this
66 void UnregisterDocument (SdDrawDocument
& rDocument
);
68 /** Add a listener that is informed of master pages that are newly
69 assigned to slides or become unassigned.
71 The event listener to call for future events. Call
72 RemoveEventListener() before the listener is destroyed.
74 void AddEventListener (const Link
& rEventListener
);
76 /** Remove the given listener from the list of listeners.
78 After this method returns the given listener is not called back
79 from this object. Passing a listener that has not
80 been registered before is safe and is silently ignored.
82 void RemoveEventListener (const Link
& rEventListener
);
84 /** Return a set of the names of master pages for the given document.
85 This convenience method exists because this set is part of the
86 internal data structure and thus takes no time to create.
88 inline MasterPageObserver::MasterPageNameSet
GetMasterPageNames (
89 SdDrawDocument
& rDocument
);
92 ::std::vector
<Link
> maListeners
;
95 size_t operator()(SdDrawDocument
* argument
) const
96 { return reinterpret_cast<unsigned long>(argument
); }
98 typedef ::std::hash_map
<SdDrawDocument
*,
99 MasterPageObserver::MasterPageNameSet
,
102 MasterPageContainer maUsedMasterPages
;
105 SfxBroadcaster
& rBroadcaster
,
106 const SfxHint
& rHint
);
108 void AnalyzeUsedMasterPages (SdDrawDocument
& rDocument
);
110 void SendEvent (MasterPageObserverEvent
& rEvent
);
113 MasterPageObserver
* MasterPageObserver::Implementation::mpInstance
= NULL
;
117 //===== MasterPageObserver ====================================================
119 MasterPageObserver
& MasterPageObserver::Instance (void)
121 if (Implementation::mpInstance
== NULL
)
123 ::osl::GetGlobalMutex aMutexFunctor
;
124 ::osl::MutexGuard
aGuard (aMutexFunctor());
125 if (Implementation::mpInstance
== NULL
)
127 MasterPageObserver
* pInstance
= new MasterPageObserver ();
128 SdGlobalResourceContainer::Instance().AddResource (
129 ::std::auto_ptr
<SdGlobalResource
>(pInstance
));
130 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
131 Implementation::mpInstance
= pInstance
;
136 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
139 DBG_ASSERT(Implementation::mpInstance
!=NULL
,
140 "MasterPageObserver::Instance(): instance is NULL");
141 return *Implementation::mpInstance
;
147 void MasterPageObserver::RegisterDocument (SdDrawDocument
& rDocument
)
149 mpImpl
->RegisterDocument (rDocument
);
155 void MasterPageObserver::UnregisterDocument (SdDrawDocument
& rDocument
)
157 mpImpl
->UnregisterDocument (rDocument
);
163 void MasterPageObserver::AddEventListener (const Link
& rEventListener
)
166 mpImpl
->AddEventListener (rEventListener
);
172 void MasterPageObserver::RemoveEventListener (const Link
& rEventListener
)
174 mpImpl
->RemoveEventListener (rEventListener
);
180 MasterPageObserver::MasterPageObserver (void)
181 : mpImpl (new Implementation())
187 MasterPageObserver::~MasterPageObserver (void)
193 MasterPageObserver::MasterPageNameSet
MasterPageObserver::GetMasterPageNames (
194 SdDrawDocument
& rDocument
)
196 return mpImpl
->GetMasterPageNames (rDocument
);
202 //===== MasterPageObserver::Implementation ====================================
204 void MasterPageObserver::Implementation::RegisterDocument (
205 SdDrawDocument
& rDocument
)
207 // Gather the names of all the master pages in the given document.
208 MasterPageContainer::data_type aMasterPageSet
;
209 USHORT nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
210 for (USHORT nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
212 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
213 if (pMasterPage
!= NULL
)
214 aMasterPageSet
.insert (pMasterPage
->GetName());
217 maUsedMasterPages
[&rDocument
] = aMasterPageSet
;
219 StartListening (rDocument
);
225 void MasterPageObserver::Implementation::UnregisterDocument (
226 SdDrawDocument
& rDocument
)
228 EndListening (rDocument
);
230 MasterPageContainer::iterator
aMasterPageDescriptor(maUsedMasterPages
.find(&rDocument
));
231 if(aMasterPageDescriptor
!= maUsedMasterPages
.end())
232 maUsedMasterPages
.erase(aMasterPageDescriptor
);
238 void MasterPageObserver::Implementation::AddEventListener (
239 const Link
& rEventListener
)
244 rEventListener
) == maListeners
.end())
246 maListeners
.push_back (rEventListener
);
248 // Tell the new listener about all the master pages that are
250 typedef ::std::vector
<String
> StringList
;
251 StringList aNewMasterPages
;
252 StringList aRemovedMasterPages
;
253 MasterPageContainer::iterator aDocumentIterator
;
254 for (aDocumentIterator
=maUsedMasterPages
.begin();
255 aDocumentIterator
!=maUsedMasterPages
.end();
258 ::std::set
<String
>::reverse_iterator aNameIterator
;
259 for (aNameIterator
=aDocumentIterator
->second
.rbegin();
260 aNameIterator
!=aDocumentIterator
->second
.rend();
263 MasterPageObserverEvent
aEvent (
264 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
,
265 *aDocumentIterator
->first
,
276 void MasterPageObserver::Implementation::RemoveEventListener (
277 const Link
& rEventListener
)
289 MasterPageObserver::MasterPageNameSet
290 MasterPageObserver::Implementation::GetMasterPageNames (
291 SdDrawDocument
& rDocument
)
293 MasterPageContainer::iterator
aMasterPageDescriptor (
294 maUsedMasterPages
.find(&rDocument
));
295 if (aMasterPageDescriptor
!= maUsedMasterPages
.end())
296 return aMasterPageDescriptor
->second
;
298 // Not found so return an empty set.
299 return MasterPageObserver::MasterPageNameSet();
305 void MasterPageObserver::Implementation::Notify(
306 SfxBroadcaster
& rBroadcaster
,
307 const SfxHint
& rHint
)
309 if (rHint
.ISA(SdrHint
))
311 SdrHint
& rSdrHint (*PTR_CAST(SdrHint
,&rHint
));
312 switch (rSdrHint
.GetKind())
314 case HINT_PAGEORDERCHG
:
315 // Process the modified set of pages only when the number of
316 // standard and notes master pages are equal. This test
317 // filters out events that are sent in between the insertion
318 // of a new standard master page and a new notes master
320 if (rBroadcaster
.ISA(SdDrawDocument
))
322 SdDrawDocument
& rDocument (
323 static_cast<SdDrawDocument
&>(rBroadcaster
));
324 if (rDocument
.GetMasterSdPageCount(PK_STANDARD
)
325 == rDocument
.GetMasterSdPageCount(PK_NOTES
))
327 AnalyzeUsedMasterPages (rDocument
);
341 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
342 SdDrawDocument
& rDocument
)
344 // Create a set of names of the master pages used by the given document.
345 USHORT nMasterPageCount
= rDocument
.GetMasterSdPageCount(PK_STANDARD
);
346 ::std::set
<String
> aCurrentMasterPages
;
347 for (USHORT nIndex
=0; nIndex
<nMasterPageCount
; nIndex
++)
349 SdPage
* pMasterPage
= rDocument
.GetMasterSdPage (nIndex
, PK_STANDARD
);
350 if (pMasterPage
!= NULL
)
351 aCurrentMasterPages
.insert (pMasterPage
->GetName());
352 OSL_TRACE("currently used master page %d is %s",
354 ::rtl::OUStringToOString(pMasterPage
->GetName(),
355 RTL_TEXTENCODING_UTF8
).getStr());
358 typedef ::std::vector
<String
> StringList
;
359 StringList aNewMasterPages
;
360 StringList aRemovedMasterPages
;
361 MasterPageContainer::iterator
aOldMasterPagesDescriptor (
362 maUsedMasterPages
.find(&rDocument
));
363 if (aOldMasterPagesDescriptor
!= maUsedMasterPages
.end())
365 StringList::iterator I
;
367 ::std::set
<String
>::iterator J
;
369 for (J
=aOldMasterPagesDescriptor
->second
.begin();
370 J
!=aOldMasterPagesDescriptor
->second
.end();
372 OSL_TRACE("old used master page %d is %s",
374 ::rtl::OUStringToOString(*J
,
375 RTL_TEXTENCODING_UTF8
).getStr());
377 // Send events about the newly used master pages.
378 ::std::set_difference (
379 aCurrentMasterPages
.begin(),
380 aCurrentMasterPages
.end(),
381 aOldMasterPagesDescriptor
->second
.begin(),
382 aOldMasterPagesDescriptor
->second
.end(),
383 ::std::back_insert_iterator
<StringList
>(aNewMasterPages
));
384 for (I
=aNewMasterPages
.begin(); I
!=aNewMasterPages
.end(); ++I
)
386 OSL_TRACE(" added master page %s",
387 ::rtl::OUStringToOString(*I
,
388 RTL_TEXTENCODING_UTF8
).getStr());
390 MasterPageObserverEvent
aEvent (
391 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
,
397 // Send events about master pages that are not used any longer.
398 ::std::set_difference (
399 aOldMasterPagesDescriptor
->second
.begin(),
400 aOldMasterPagesDescriptor
->second
.end(),
401 aCurrentMasterPages
.begin(),
402 aCurrentMasterPages
.end(),
403 ::std::back_insert_iterator
<StringList
>(aRemovedMasterPages
));
404 for (I
=aRemovedMasterPages
.begin(); I
!=aRemovedMasterPages
.end(); ++I
)
406 OSL_TRACE(" removed master page %s",
407 ::rtl::OUStringToOString(*I
,
408 RTL_TEXTENCODING_UTF8
).getStr());
410 MasterPageObserverEvent
aEvent (
411 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
,
417 // Store the new list of master pages.
418 aOldMasterPagesDescriptor
->second
= aCurrentMasterPages
;
425 void MasterPageObserver::Implementation::SendEvent (
426 MasterPageObserverEvent
& rEvent
)
428 ::std::vector
<Link
>::iterator
aLink (maListeners
.begin());
429 ::std::vector
<Link
>::iterator
aEnd (maListeners
.end());
432 aLink
->Call (&rEvent
);
438 } // end of namespace sd