CWS-TOOLING: integrate CWS os150
[LibreOffice.git] / sd / source / ui / toolpanel / controls / MasterPageObserver.cxx
blob6524dc429c56e60e6aedbcdeaaf2156a999bb285
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"
33 #include <algorithm>
34 #include "drawdoc.hxx"
35 #include "sdpage.hxx"
36 #include <hash_map>
37 #include <set>
38 #include <vector>
39 #include <svl/lstner.hxx>
40 #include <osl/doublecheckedlocking.h>
41 #include <osl/getglobalmutex.hxx>
44 namespace sd {
46 class MasterPageObserver::Implementation
47 : public SfxListener
49 public:
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
61 document.
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.
67 @param rEventListener
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.
74 @param rEventListener
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);
88 private:
89 ::std::vector<Link> maListeners;
91 struct DrawDocHash {
92 size_t operator()(SdDrawDocument* argument) const
93 { return reinterpret_cast<unsigned long>(argument); }
95 typedef ::std::hash_map<SdDrawDocument*,
96 MasterPageObserver::MasterPageNameSet,
97 DrawDocHash>
98 MasterPageContainer;
99 MasterPageContainer maUsedMasterPages;
101 virtual void Notify(
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;
131 else
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)
229 if (::std::find (
230 maListeners.begin(),
231 maListeners.end(),
232 rEventListener) == maListeners.end())
234 maListeners.push_back (rEventListener);
236 // Tell the new listener about all the master pages that are
237 // currently in use.
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();
244 ++aDocumentIterator)
246 ::std::set<String>::reverse_iterator aNameIterator;
247 for (aNameIterator=aDocumentIterator->second.rbegin();
248 aNameIterator!=aDocumentIterator->second.rend();
249 ++aNameIterator)
251 MasterPageObserverEvent aEvent (
252 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
253 *aDocumentIterator->first,
254 *aNameIterator);
255 SendEvent (aEvent);
264 void MasterPageObserver::Implementation::RemoveEventListener (
265 const Link& rEventListener)
267 maListeners.erase (
268 ::std::find (
269 maListeners.begin(),
270 maListeners.end(),
271 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;
285 else
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
307 // page.
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);
318 break;
320 default:
321 break;
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",
341 nIndex,
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;
356 int i=0;
357 for (J=aOldMasterPagesDescriptor->second.begin();
358 J!=aOldMasterPagesDescriptor->second.end();
359 ++J)
360 OSL_TRACE("old used master page %d is %s",
361 i++,
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,
380 rDocument,
381 *I);
382 SendEvent (aEvent);
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,
400 rDocument,
401 *I);
402 SendEvent (aEvent);
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());
418 while (aLink!=aEnd)
420 aLink->Call (&rEvent);
421 ++aLink;
426 } // end of namespace sd