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