1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 
27 #include "MasterPageObserver.hxx"
28 
29 #include <algorithm>
30 #include "drawdoc.hxx"
31 #include "sdpage.hxx"
32 #include <hash_map>
33 #include <set>
34 #include <vector>
35 #include <svl/lstner.hxx>
36 #include <osl/doublecheckedlocking.h>
37 #include <osl/getglobalmutex.hxx>
38 
39 
40 namespace sd {
41 
42 class MasterPageObserver::Implementation
43     : public SfxListener
44 {
45 public:
46     /** The single instance of this class.  It is created on demand when
47         Instance() is called for the first time.
48     */
49     static MasterPageObserver* mpInstance;
50 
51     /** The master page observer will listen to events of this document and
52         detect changes of the use of master pages.
53     */
54     void RegisterDocument (SdDrawDocument& rDocument);
55 
56     /** The master page observer will stop to listen to events of this
57         document.
58     */
59     void UnregisterDocument (SdDrawDocument& rDocument);
60 
61     /** Add a listener that is informed of master pages that are newly
62         assigned to slides or become unassigned.
63         @param rEventListener
64             The event listener to call for future events.  Call
65             RemoveEventListener() before the listener is destroyed.
66     */
67     void AddEventListener (const Link& rEventListener);
68 
69     /** Remove the given listener from the list of listeners.
70         @param rEventListener
71             After this method returns the given listener is not called back
72             from this object.  Passing a listener that has not
73             been registered before is safe and is silently ignored.
74     */
75     void RemoveEventListener (const Link& rEventListener);
76 
77     /** Return a set of the names of master pages for the given document.
78         This convenience method exists because this set is part of the
79         internal data structure and thus takes no time to create.
80     */
81     inline MasterPageObserver::MasterPageNameSet GetMasterPageNames (
82         SdDrawDocument& rDocument);
83 
84 private:
85     ::std::vector<Link> maListeners;
86 
87     struct DrawDocHash {
88         size_t operator()(SdDrawDocument* argument) const
89         { return reinterpret_cast<unsigned long>(argument); }
90     };
91     typedef ::std::hash_map<SdDrawDocument*,
92                             MasterPageObserver::MasterPageNameSet,
93                             DrawDocHash>
94         MasterPageContainer;
95     MasterPageContainer maUsedMasterPages;
96 
97     virtual void Notify(
98         SfxBroadcaster& rBroadcaster,
99         const SfxHint& rHint);
100 
101     void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);
102 
103     void SendEvent (MasterPageObserverEvent& rEvent);
104 };
105 
106 MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;
107 
108 
109 
110 //===== MasterPageObserver ====================================================
111 
112 MasterPageObserver&  MasterPageObserver::Instance (void)
113 {
114     if (Implementation::mpInstance == NULL)
115     {
116         ::osl::GetGlobalMutex aMutexFunctor;
117         ::osl::MutexGuard aGuard (aMutexFunctor());
118         if (Implementation::mpInstance == NULL)
119         {
120             MasterPageObserver* pInstance = new MasterPageObserver ();
121             SdGlobalResourceContainer::Instance().AddResource (
122                 ::std::auto_ptr<SdGlobalResource>(pInstance));
123             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
124             Implementation::mpInstance = pInstance;
125         }
126     }
127     else
128     {
129         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
130     }
131 
132     DBG_ASSERT(Implementation::mpInstance!=NULL,
133         "MasterPageObserver::Instance(): instance is NULL");
134     return *Implementation::mpInstance;
135 }
136 
137 
138 
139 
140 void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
141 {
142     mpImpl->RegisterDocument (rDocument);
143 }
144 
145 
146 
147 
148 void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
149 {
150     mpImpl->UnregisterDocument (rDocument);
151 }
152 
153 
154 
155 
156 void MasterPageObserver::AddEventListener (const Link& rEventListener)
157 {
158 
159     mpImpl->AddEventListener (rEventListener);
160 }
161 
162 
163 
164 
165 void MasterPageObserver::RemoveEventListener (const Link& rEventListener)
166 {
167     mpImpl->RemoveEventListener (rEventListener);
168 }
169 
170 
171 
172 
173 MasterPageObserver::MasterPageObserver (void)
174     : mpImpl (new Implementation())
175 {}
176 
177 
178 
179 
180 MasterPageObserver::~MasterPageObserver (void)
181 {}
182 
183 
184 
185 
186 //===== MasterPageObserver::Implementation ====================================
187 
188 void MasterPageObserver::Implementation::RegisterDocument (
189     SdDrawDocument& rDocument)
190 {
191     // Gather the names of all the master pages in the given document.
192     MasterPageContainer::data_type aMasterPageSet;
193     sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
194     for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
195     {
196         SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
197         if (pMasterPage != NULL)
198             aMasterPageSet.insert (pMasterPage->GetName());
199     }
200 
201     maUsedMasterPages[&rDocument] = aMasterPageSet;
202 
203     StartListening (rDocument);
204 }
205 
206 
207 
208 
209 void MasterPageObserver::Implementation::UnregisterDocument (
210     SdDrawDocument& rDocument)
211 {
212     EndListening (rDocument);
213 
214 	MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
215 	if(aMasterPageDescriptor != maUsedMasterPages.end())
216 		maUsedMasterPages.erase(aMasterPageDescriptor);
217 }
218 
219 
220 
221 
222 void MasterPageObserver::Implementation::AddEventListener (
223     const Link& rEventListener)
224 {
225     if (::std::find (
226         maListeners.begin(),
227         maListeners.end(),
228         rEventListener) == maListeners.end())
229     {
230         maListeners.push_back (rEventListener);
231 
232         // Tell the new listener about all the master pages that are
233         // currently in use.
234         typedef ::std::vector<String> StringList;
235         StringList aNewMasterPages;
236         StringList aRemovedMasterPages;
237         MasterPageContainer::iterator aDocumentIterator;
238         for (aDocumentIterator=maUsedMasterPages.begin();
239              aDocumentIterator!=maUsedMasterPages.end();
240              ++aDocumentIterator)
241         {
242             ::std::set<String>::reverse_iterator aNameIterator;
243             for (aNameIterator=aDocumentIterator->second.rbegin();
244                  aNameIterator!=aDocumentIterator->second.rend();
245                  ++aNameIterator)
246             {
247 			  MasterPageObserverEvent aEvent (
248 				  MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
249 				  *aDocumentIterator->first,
250 				  *aNameIterator);
251 			  SendEvent (aEvent);
252             }
253         }
254     }
255 }
256 
257 
258 
259 
260 void MasterPageObserver::Implementation::RemoveEventListener (
261     const Link& rEventListener)
262 {
263     maListeners.erase (
264         ::std::find (
265             maListeners.begin(),
266             maListeners.end(),
267             rEventListener));
268 }
269 
270 
271 
272 
273 MasterPageObserver::MasterPageNameSet
274     MasterPageObserver::Implementation::GetMasterPageNames (
275         SdDrawDocument& rDocument)
276 {
277     MasterPageContainer::iterator aMasterPageDescriptor (
278         maUsedMasterPages.find(&rDocument));
279     if (aMasterPageDescriptor != maUsedMasterPages.end())
280         return aMasterPageDescriptor->second;
281     else
282         // Not found so return an empty set.
283         return MasterPageObserver::MasterPageNameSet();
284 }
285 
286 
287 
288 
289 void MasterPageObserver::Implementation::Notify(
290     SfxBroadcaster& rBroadcaster,
291     const SfxHint& rHint)
292 {
293     if (rHint.ISA(SdrHint))
294     {
295         SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
296         switch (rSdrHint.GetKind())
297         {
298             case HINT_PAGEORDERCHG:
299                 // Process the modified set of pages only when the number of
300                 // standard and notes master pages are equal.  This test
301                 // filters out events that are sent in between the insertion
302                 // of a new standard master page and a new notes master
303                 // page.
304                 if (rBroadcaster.ISA(SdDrawDocument))
305                 {
306                     SdDrawDocument& rDocument (
307                         static_cast<SdDrawDocument&>(rBroadcaster));
308                     if (rDocument.GetMasterSdPageCount(PK_STANDARD)
309                         == rDocument.GetMasterSdPageCount(PK_NOTES))
310                     {
311                         AnalyzeUsedMasterPages (rDocument);
312                     }
313                 }
314                 break;
315 
316 			default:
317 				break;
318         }
319     }
320 }
321 
322 
323 
324 
325 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
326     SdDrawDocument& rDocument)
327 {
328     // Create a set of names of the master pages used by the given document.
329     sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
330     ::std::set<String> aCurrentMasterPages;
331     for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
332     {
333         SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
334         if (pMasterPage != NULL)
335             aCurrentMasterPages.insert (pMasterPage->GetName());
336         OSL_TRACE("currently used master page %d is %s",
337             nIndex,
338             ::rtl::OUStringToOString(pMasterPage->GetName(),
339                 RTL_TEXTENCODING_UTF8).getStr());
340     }
341 
342     typedef ::std::vector<String> StringList;
343     StringList aNewMasterPages;
344     StringList aRemovedMasterPages;
345     MasterPageContainer::iterator aOldMasterPagesDescriptor (
346         maUsedMasterPages.find(&rDocument));
347     if (aOldMasterPagesDescriptor != maUsedMasterPages.end())
348     {
349         StringList::iterator I;
350 
351         ::std::set<String>::iterator J;
352         int i=0;
353         for (J=aOldMasterPagesDescriptor->second.begin();
354              J!=aOldMasterPagesDescriptor->second.end();
355              ++J)
356             OSL_TRACE("old used master page %d is %s",
357             i++,
358             ::rtl::OUStringToOString(*J,
359                 RTL_TEXTENCODING_UTF8).getStr());
360 
361         // Send events about the newly used master pages.
362         ::std::set_difference (
363             aCurrentMasterPages.begin(),
364             aCurrentMasterPages.end(),
365             aOldMasterPagesDescriptor->second.begin(),
366             aOldMasterPagesDescriptor->second.end(),
367             ::std::back_insert_iterator<StringList>(aNewMasterPages));
368         for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I)
369         {
370             OSL_TRACE("    added master page %s",
371                 ::rtl::OUStringToOString(*I,
372                     RTL_TEXTENCODING_UTF8).getStr());
373 
374 			MasterPageObserverEvent aEvent (
375 				MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
376 				rDocument,
377 				*I);
378             SendEvent (aEvent);
379         }
380 
381         // Send events about master pages that are not used any longer.
382         ::std::set_difference (
383             aOldMasterPagesDescriptor->second.begin(),
384             aOldMasterPagesDescriptor->second.end(),
385             aCurrentMasterPages.begin(),
386             aCurrentMasterPages.end(),
387             ::std::back_insert_iterator<StringList>(aRemovedMasterPages));
388         for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I)
389         {
390             OSL_TRACE("    removed master page %s",
391                 ::rtl::OUStringToOString(*I,
392                     RTL_TEXTENCODING_UTF8).getStr());
393 
394 			MasterPageObserverEvent aEvent (
395 				MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
396 				rDocument,
397 				*I);
398 			SendEvent (aEvent);
399         }
400 
401         // Store the new list of master pages.
402         aOldMasterPagesDescriptor->second = aCurrentMasterPages;
403     }
404 }
405 
406 
407 
408 
409 void MasterPageObserver::Implementation::SendEvent (
410     MasterPageObserverEvent& rEvent)
411 {
412     ::std::vector<Link>::iterator aLink (maListeners.begin());
413     ::std::vector<Link>::iterator aEnd (maListeners.end());
414     while (aLink!=aEnd)
415     {
416         aLink->Call (&rEvent);
417         ++aLink;
418     }
419 }
420 
421 
422 } // end of namespace sd
423