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