bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / sidebar / MasterPageObserver.cxx
blob1df0a078bb240f5da594b76f80d07dd1e99f2b7e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "MasterPageObserver.hxx"
22 #include <algorithm>
23 #include "drawdoc.hxx"
24 #include "sdpage.hxx"
25 #include <set>
26 #include <unordered_map>
27 #include <vector>
28 #include <svl/lstner.hxx>
29 #include <osl/doublecheckedlocking.h>
30 #include <osl/getglobalmutex.hxx>
32 namespace sd {
34 class MasterPageObserver::Implementation
35 : public SfxListener
37 public:
38 /** The single instance of this class. It is created on demand when
39 Instance() is called for the first time.
41 static MasterPageObserver* mpInstance;
43 /** The master page observer will listen to events of this document and
44 detect changes of the use of master pages.
46 void RegisterDocument (SdDrawDocument& rDocument);
48 /** The master page observer will stop to listen to events of this
49 document.
51 void UnregisterDocument (SdDrawDocument& rDocument);
53 /** Add a listener that is informed of master pages that are newly
54 assigned to slides or become unassigned.
55 @param rEventListener
56 The event listener to call for future events. Call
57 RemoveEventListener() before the listener is destroyed.
59 void AddEventListener (const Link<>& rEventListener);
61 /** Remove the given listener from the list of listeners.
62 @param rEventListener
63 After this method returns the given listener is not called back
64 from this object. Passing a listener that has not
65 been registered before is safe and is silently ignored.
67 void RemoveEventListener (const Link<>& rEventListener);
69 private:
70 ::std::vector<Link<>> maListeners;
72 struct DrawDocHash {
73 size_t operator()(SdDrawDocument* argument) const
74 { return reinterpret_cast<unsigned long>(argument); }
76 typedef std::unordered_map<SdDrawDocument*,
77 MasterPageObserver::MasterPageNameSet,
78 DrawDocHash>
79 MasterPageContainer;
80 MasterPageContainer maUsedMasterPages;
82 virtual void Notify(
83 SfxBroadcaster& rBroadcaster,
84 const SfxHint& rHint) SAL_OVERRIDE;
86 void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);
88 void SendEvent (MasterPageObserverEvent& rEvent);
91 MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;
93 //===== MasterPageObserver ====================================================
95 MasterPageObserver& MasterPageObserver::Instance()
97 if (Implementation::mpInstance == NULL)
99 ::osl::GetGlobalMutex aMutexFunctor;
100 ::osl::MutexGuard aGuard (aMutexFunctor());
101 if (Implementation::mpInstance == NULL)
103 MasterPageObserver* pInstance = new MasterPageObserver ();
104 SdGlobalResourceContainer::Instance().AddResource (
105 ::std::unique_ptr<SdGlobalResource>(pInstance));
106 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
107 Implementation::mpInstance = pInstance;
110 else
112 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
115 DBG_ASSERT(Implementation::mpInstance!=NULL,
116 "MasterPageObserver::Instance(): instance is NULL");
117 return *Implementation::mpInstance;
120 void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
122 mpImpl->RegisterDocument (rDocument);
125 void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
127 mpImpl->UnregisterDocument (rDocument);
130 void MasterPageObserver::AddEventListener (const Link<>& rEventListener)
133 mpImpl->AddEventListener (rEventListener);
136 void MasterPageObserver::RemoveEventListener (const Link<>& rEventListener)
138 mpImpl->RemoveEventListener (rEventListener);
141 MasterPageObserver::MasterPageObserver()
142 : mpImpl (new Implementation())
145 MasterPageObserver::~MasterPageObserver()
148 //===== MasterPageObserver::Implementation ====================================
150 void MasterPageObserver::Implementation::RegisterDocument (
151 SdDrawDocument& rDocument)
153 // Gather the names of all the master pages in the given document.
154 MasterPageContainer::mapped_type aMasterPageSet;
155 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
156 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
158 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
159 if (pMasterPage != NULL)
160 aMasterPageSet.insert (pMasterPage->GetName());
163 maUsedMasterPages[&rDocument] = aMasterPageSet;
165 StartListening (rDocument);
168 void MasterPageObserver::Implementation::UnregisterDocument (
169 SdDrawDocument& rDocument)
171 EndListening (rDocument);
173 MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
174 if(aMasterPageDescriptor != maUsedMasterPages.end())
175 maUsedMasterPages.erase(aMasterPageDescriptor);
178 void MasterPageObserver::Implementation::AddEventListener (
179 const Link<>& rEventListener)
181 if (::std::find (
182 maListeners.begin(),
183 maListeners.end(),
184 rEventListener) == maListeners.end())
186 maListeners.push_back (rEventListener);
188 // Tell the new listener about all the master pages that are
189 // currently in use.
190 MasterPageContainer::iterator aDocumentIterator;
191 for (aDocumentIterator=maUsedMasterPages.begin();
192 aDocumentIterator!=maUsedMasterPages.end();
193 ++aDocumentIterator)
195 ::std::set<OUString>::reverse_iterator aNameIterator;
196 for (aNameIterator=aDocumentIterator->second.rbegin();
197 aNameIterator!=aDocumentIterator->second.rend();
198 ++aNameIterator)
200 MasterPageObserverEvent aEvent (
201 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
202 *aDocumentIterator->first,
203 *aNameIterator);
204 SendEvent (aEvent);
210 void MasterPageObserver::Implementation::RemoveEventListener (
211 const Link<>& rEventListener)
213 maListeners.erase (
214 ::std::find (
215 maListeners.begin(),
216 maListeners.end(),
217 rEventListener));
220 void MasterPageObserver::Implementation::Notify(
221 SfxBroadcaster& rBroadcaster,
222 const SfxHint& rHint)
224 const SdrHint* pSdrHint = dynamic_cast<const SdrHint*>(&rHint);
225 if (pSdrHint)
227 switch (pSdrHint->GetKind())
229 case HINT_PAGEORDERCHG:
230 // Process the modified set of pages only when the number of
231 // standard and notes master pages are equal. This test
232 // filters out events that are sent in between the insertion
233 // of a new standard master page and a new notes master
234 // page.
235 if (rBroadcaster.ISA(SdDrawDocument))
237 SdDrawDocument& rDocument (
238 static_cast<SdDrawDocument&>(rBroadcaster));
239 if (rDocument.GetMasterSdPageCount(PK_STANDARD)
240 == rDocument.GetMasterSdPageCount(PK_NOTES))
242 AnalyzeUsedMasterPages (rDocument);
245 break;
247 default:
248 break;
253 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
254 SdDrawDocument& rDocument)
256 // Create a set of names of the master pages used by the given document.
257 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
258 ::std::set<OUString> aCurrentMasterPages;
259 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
261 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
262 if (pMasterPage != NULL)
263 aCurrentMasterPages.insert (pMasterPage->GetName());
264 OSL_TRACE("currently used master page %d is %s",
265 nIndex,
266 ::rtl::OUStringToOString(pMasterPage->GetName(),
267 RTL_TEXTENCODING_UTF8).getStr());
270 typedef ::std::vector<OUString> StringList;
271 StringList aNewMasterPages;
272 StringList aRemovedMasterPages;
273 MasterPageContainer::iterator aOldMasterPagesDescriptor (
274 maUsedMasterPages.find(&rDocument));
275 if (aOldMasterPagesDescriptor != maUsedMasterPages.end())
277 StringList::iterator I;
279 ::std::set<OUString>::iterator J;
280 int i=0;
281 for (J=aOldMasterPagesDescriptor->second.begin();
282 J!=aOldMasterPagesDescriptor->second.end();
283 ++J)
284 OSL_TRACE("old used master page %d is %s",
285 i++,
286 ::rtl::OUStringToOString(*J,
287 RTL_TEXTENCODING_UTF8).getStr());
289 // Send events about the newly used master pages.
290 ::std::set_difference (
291 aCurrentMasterPages.begin(),
292 aCurrentMasterPages.end(),
293 aOldMasterPagesDescriptor->second.begin(),
294 aOldMasterPagesDescriptor->second.end(),
295 ::std::back_insert_iterator<StringList>(aNewMasterPages));
296 for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I)
298 OSL_TRACE(" added master page %s",
299 ::rtl::OUStringToOString(*I,
300 RTL_TEXTENCODING_UTF8).getStr());
302 MasterPageObserverEvent aEvent (
303 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
304 rDocument,
305 *I);
306 SendEvent (aEvent);
309 // Send events about master pages that are not used any longer.
310 ::std::set_difference (
311 aOldMasterPagesDescriptor->second.begin(),
312 aOldMasterPagesDescriptor->second.end(),
313 aCurrentMasterPages.begin(),
314 aCurrentMasterPages.end(),
315 ::std::back_insert_iterator<StringList>(aRemovedMasterPages));
316 for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I)
318 OSL_TRACE(" removed master page %s",
319 ::rtl::OUStringToOString(*I,
320 RTL_TEXTENCODING_UTF8).getStr());
322 MasterPageObserverEvent aEvent (
323 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
324 rDocument,
325 *I);
326 SendEvent (aEvent);
329 // Store the new list of master pages.
330 aOldMasterPagesDescriptor->second = aCurrentMasterPages;
334 void MasterPageObserver::Implementation::SendEvent (
335 MasterPageObserverEvent& rEvent)
337 ::std::vector<Link<>>::iterator aLink (maListeners.begin());
338 ::std::vector<Link<>>::iterator aEnd (maListeners.end());
339 while (aLink!=aEnd)
341 aLink->Call (&rEvent);
342 ++aLink;
346 } // end of namespace sd
348 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */