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