1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sd.hxx"
30 
31 #include "MasterPageObserver.hxx"
32 
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>
42 
43 
44 namespace sd {
45 
46 class MasterPageObserver::Implementation
47     : public SfxListener
48 {
49 public:
50     /** The single instance of this class.  It is created on demand when
51         Instance() is called for the first time.
52     */
53     static MasterPageObserver* mpInstance;
54 
55     /** The master page observer will listen to events of this document and
56         detect changes of the use of master pages.
57     */
58     void RegisterDocument (SdDrawDocument& rDocument);
59 
60     /** The master page observer will stop to listen to events of this
61         document.
62     */
63     void UnregisterDocument (SdDrawDocument& rDocument);
64 
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.
70     */
71     void AddEventListener (const Link& rEventListener);
72 
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.
78     */
79     void RemoveEventListener (const Link& rEventListener);
80 
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.
84     */
85     inline MasterPageObserver::MasterPageNameSet GetMasterPageNames (
86         SdDrawDocument& rDocument);
87 
88 private:
89     ::std::vector<Link> maListeners;
90 
91     struct DrawDocHash {
92         size_t operator()(SdDrawDocument* argument) const
93         { return reinterpret_cast<unsigned long>(argument); }
94     };
95     typedef ::std::hash_map<SdDrawDocument*,
96                             MasterPageObserver::MasterPageNameSet,
97                             DrawDocHash>
98         MasterPageContainer;
99     MasterPageContainer maUsedMasterPages;
100 
101     virtual void Notify(
102         SfxBroadcaster& rBroadcaster,
103         const SfxHint& rHint);
104 
105     void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);
106 
107     void SendEvent (MasterPageObserverEvent& rEvent);
108 };
109 
110 MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;
111 
112 
113 
114 //===== MasterPageObserver ====================================================
115 
116 MasterPageObserver&  MasterPageObserver::Instance (void)
117 {
118     if (Implementation::mpInstance == NULL)
119     {
120         ::osl::GetGlobalMutex aMutexFunctor;
121         ::osl::MutexGuard aGuard (aMutexFunctor());
122         if (Implementation::mpInstance == NULL)
123         {
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;
129         }
130     }
131     else
132     {
133         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
134     }
135 
136     DBG_ASSERT(Implementation::mpInstance!=NULL,
137         "MasterPageObserver::Instance(): instance is NULL");
138     return *Implementation::mpInstance;
139 }
140 
141 
142 
143 
144 void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
145 {
146     mpImpl->RegisterDocument (rDocument);
147 }
148 
149 
150 
151 
152 void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
153 {
154     mpImpl->UnregisterDocument (rDocument);
155 }
156 
157 
158 
159 
160 void MasterPageObserver::AddEventListener (const Link& rEventListener)
161 {
162 
163     mpImpl->AddEventListener (rEventListener);
164 }
165 
166 
167 
168 
169 void MasterPageObserver::RemoveEventListener (const Link& rEventListener)
170 {
171     mpImpl->RemoveEventListener (rEventListener);
172 }
173 
174 
175 
176 
177 MasterPageObserver::MasterPageObserver (void)
178     : mpImpl (new Implementation())
179 {}
180 
181 
182 
183 
184 MasterPageObserver::~MasterPageObserver (void)
185 {}
186 
187 
188 
189 
190 //===== MasterPageObserver::Implementation ====================================
191 
192 void MasterPageObserver::Implementation::RegisterDocument (
193     SdDrawDocument& rDocument)
194 {
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++)
199     {
200         SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
201         if (pMasterPage != NULL)
202             aMasterPageSet.insert (pMasterPage->GetName());
203     }
204 
205     maUsedMasterPages[&rDocument] = aMasterPageSet;
206 
207     StartListening (rDocument);
208 }
209 
210 
211 
212 
213 void MasterPageObserver::Implementation::UnregisterDocument (
214     SdDrawDocument& rDocument)
215 {
216     EndListening (rDocument);
217 
218 	MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
219 	if(aMasterPageDescriptor != maUsedMasterPages.end())
220 		maUsedMasterPages.erase(aMasterPageDescriptor);
221 }
222 
223 
224 
225 
226 void MasterPageObserver::Implementation::AddEventListener (
227     const Link& rEventListener)
228 {
229     if (::std::find (
230         maListeners.begin(),
231         maListeners.end(),
232         rEventListener) == maListeners.end())
233     {
234         maListeners.push_back (rEventListener);
235 
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)
245         {
246             ::std::set<String>::reverse_iterator aNameIterator;
247             for (aNameIterator=aDocumentIterator->second.rbegin();
248                  aNameIterator!=aDocumentIterator->second.rend();
249                  ++aNameIterator)
250             {
251 			  MasterPageObserverEvent aEvent (
252 				  MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
253 				  *aDocumentIterator->first,
254 				  *aNameIterator);
255 			  SendEvent (aEvent);
256             }
257         }
258     }
259 }
260 
261 
262 
263 
264 void MasterPageObserver::Implementation::RemoveEventListener (
265     const Link& rEventListener)
266 {
267     maListeners.erase (
268         ::std::find (
269             maListeners.begin(),
270             maListeners.end(),
271             rEventListener));
272 }
273 
274 
275 
276 
277 MasterPageObserver::MasterPageNameSet
278     MasterPageObserver::Implementation::GetMasterPageNames (
279         SdDrawDocument& rDocument)
280 {
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();
288 }
289 
290 
291 
292 
293 void MasterPageObserver::Implementation::Notify(
294     SfxBroadcaster& rBroadcaster,
295     const SfxHint& rHint)
296 {
297     if (rHint.ISA(SdrHint))
298     {
299         SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
300         switch (rSdrHint.GetKind())
301         {
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))
309                 {
310                     SdDrawDocument& rDocument (
311                         static_cast<SdDrawDocument&>(rBroadcaster));
312                     if (rDocument.GetMasterSdPageCount(PK_STANDARD)
313                         == rDocument.GetMasterSdPageCount(PK_NOTES))
314                     {
315                         AnalyzeUsedMasterPages (rDocument);
316                     }
317                 }
318                 break;
319 
320 			default:
321 				break;
322         }
323     }
324 }
325 
326 
327 
328 
329 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
330     SdDrawDocument& rDocument)
331 {
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++)
336     {
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());
344     }
345 
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())
352     {
353         StringList::iterator I;
354 
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());
364 
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)
373         {
374             OSL_TRACE("    added master page %s",
375                 ::rtl::OUStringToOString(*I,
376                     RTL_TEXTENCODING_UTF8).getStr());
377 
378 			MasterPageObserverEvent aEvent (
379 				MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
380 				rDocument,
381 				*I);
382             SendEvent (aEvent);
383         }
384 
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)
393         {
394             OSL_TRACE("    removed master page %s",
395                 ::rtl::OUStringToOString(*I,
396                     RTL_TEXTENCODING_UTF8).getStr());
397 
398 			MasterPageObserverEvent aEvent (
399 				MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
400 				rDocument,
401 				*I);
402 			SendEvent (aEvent);
403         }
404 
405         // Store the new list of master pages.
406         aOldMasterPagesDescriptor->second = aCurrentMasterPages;
407     }
408 }
409 
410 
411 
412 
413 void MasterPageObserver::Implementation::SendEvent (
414     MasterPageObserverEvent& rEvent)
415 {
416     ::std::vector<Link>::iterator aLink (maListeners.begin());
417     ::std::vector<Link>::iterator aEnd (maListeners.end());
418     while (aLink!=aEnd)
419     {
420         aLink->Call (&rEvent);
421         ++aLink;
422     }
423 }
424 
425 
426 } // end of namespace sd
427