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