bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / sidebar / MasterPageObserver.cxx
blob232ea0e3c73e8a41fbc8b31bf331e5b2bc034840
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 <iterator>
24 #include <drawdoc.hxx>
25 #include <sdpage.hxx>
26 #include <set>
27 #include <unordered_map>
28 #include <memory>
29 #include <vector>
30 #include <svl/lstner.hxx>
31 #include <osl/doublecheckedlocking.h>
32 #include <osl/getglobalmutex.hxx>
33 #include <tools/debug.hxx>
35 namespace sd {
37 class MasterPageObserver::Implementation
38 : public SfxListener
40 public:
41 /** The single instance of this class. It is created on demand when
42 Instance() is called for the first time.
44 static MasterPageObserver* mpInstance;
46 /** The master page observer will listen to events of this document and
47 detect changes of the use of master pages.
49 void RegisterDocument (SdDrawDocument& rDocument);
51 /** The master page observer will stop to listen to events of this
52 document.
54 void UnregisterDocument (SdDrawDocument& rDocument);
56 /** Add a listener that is informed of master pages that are newly
57 assigned to slides or become unassigned.
58 @param rEventListener
59 The event listener to call for future events. Call
60 RemoveEventListener() before the listener is destroyed.
62 void AddEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener);
64 /** Remove the given listener from the list of listeners.
65 @param rEventListener
66 After this method returns the given listener is not called back
67 from this object. Passing a listener that has not
68 been registered before is safe and is silently ignored.
70 void RemoveEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener);
72 private:
73 ::std::vector<Link<MasterPageObserverEvent&,void>> maListeners;
75 struct DrawDocHash {
76 size_t operator()(SdDrawDocument* argument) const
77 { return reinterpret_cast<unsigned long>(argument); }
79 typedef std::unordered_map<SdDrawDocument*,
80 MasterPageObserver::MasterPageNameSet,
81 DrawDocHash>
82 MasterPageContainer;
83 MasterPageContainer maUsedMasterPages;
85 virtual void Notify(
86 SfxBroadcaster& rBroadcaster,
87 const SfxHint& rHint) override;
89 void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);
91 void SendEvent (MasterPageObserverEvent& rEvent);
94 MasterPageObserver* MasterPageObserver::Implementation::mpInstance = nullptr;
96 //===== MasterPageObserver ====================================================
98 MasterPageObserver& MasterPageObserver::Instance()
100 if (Implementation::mpInstance == nullptr)
102 ::osl::GetGlobalMutex aMutexFunctor;
103 ::osl::MutexGuard aGuard (aMutexFunctor());
104 if (Implementation::mpInstance == nullptr)
106 MasterPageObserver* pInstance = new MasterPageObserver ();
107 SdGlobalResourceContainer::Instance().AddResource (
108 ::std::unique_ptr<SdGlobalResource>(pInstance));
109 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
110 Implementation::mpInstance = pInstance;
113 else
115 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
118 DBG_ASSERT(Implementation::mpInstance!=nullptr,
119 "MasterPageObserver::Instance(): instance is NULL");
120 return *Implementation::mpInstance;
123 void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
125 mpImpl->RegisterDocument (rDocument);
128 void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
130 mpImpl->UnregisterDocument (rDocument);
133 void MasterPageObserver::AddEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener)
136 mpImpl->AddEventListener (rEventListener);
139 void MasterPageObserver::RemoveEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener)
141 mpImpl->RemoveEventListener (rEventListener);
144 MasterPageObserver::MasterPageObserver()
145 : mpImpl (new Implementation)
148 MasterPageObserver::~MasterPageObserver()
151 //===== MasterPageObserver::Implementation ====================================
153 void MasterPageObserver::Implementation::RegisterDocument (
154 SdDrawDocument& rDocument)
156 // Gather the names of all the master pages in the given document.
157 MasterPageContainer::mapped_type aMasterPageSet;
158 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PageKind::Standard);
159 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
161 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PageKind::Standard);
162 if (pMasterPage != nullptr)
163 aMasterPageSet.insert (pMasterPage->GetName());
166 bool bAlreadyExists = maUsedMasterPages.find(&rDocument) != maUsedMasterPages.end();
167 maUsedMasterPages[&rDocument] = aMasterPageSet;
169 if (!bAlreadyExists)
170 StartListening (rDocument);
173 void MasterPageObserver::Implementation::UnregisterDocument (
174 SdDrawDocument& rDocument)
176 EndListening (rDocument);
178 MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
179 if(aMasterPageDescriptor != maUsedMasterPages.end())
180 maUsedMasterPages.erase(aMasterPageDescriptor);
183 void MasterPageObserver::Implementation::AddEventListener (
184 const Link<MasterPageObserverEvent&,void>& rEventListener)
186 if (::std::find (
187 maListeners.begin(),
188 maListeners.end(),
189 rEventListener) != maListeners.end())
190 return;
192 maListeners.push_back (rEventListener);
194 // Tell the new listener about all the master pages that are
195 // currently in use.
196 for (const auto& rDocument : maUsedMasterPages)
198 ::std::set<OUString>::reverse_iterator aNameIterator;
199 for (aNameIterator=rDocument.second.rbegin();
200 aNameIterator!=rDocument.second.rend();
201 ++aNameIterator)
203 MasterPageObserverEvent aEvent (
204 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
205 *aNameIterator);
206 SendEvent (aEvent);
211 void MasterPageObserver::Implementation::RemoveEventListener (
212 const Link<MasterPageObserverEvent&,void>& rEventListener)
214 maListeners.erase (
215 ::std::find (
216 maListeners.begin(),
217 maListeners.end(),
218 rEventListener));
221 void MasterPageObserver::Implementation::Notify(
222 SfxBroadcaster& rBroadcaster,
223 const SfxHint& rHint)
225 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
226 return;
227 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
229 switch (pSdrHint->GetKind())
231 case SdrHintKind::PageOrderChange:
232 // Process the modified set of pages only when the number of
233 // standard and notes master pages are equal. This test
234 // filters out events that are sent in between the insertion
235 // of a new standard master page and a new notes master
236 // page.
237 if (dynamic_cast< const SdDrawDocument *>( &rBroadcaster ) != nullptr)
239 SdDrawDocument& rDocument (
240 static_cast<SdDrawDocument&>(rBroadcaster));
241 if (rDocument.GetMasterSdPageCount(PageKind::Standard)
242 == rDocument.GetMasterSdPageCount(PageKind::Notes))
244 AnalyzeUsedMasterPages (rDocument);
247 break;
249 default:
250 break;
254 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
255 SdDrawDocument& rDocument)
257 // Create a set of names of the master pages used by the given document.
258 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PageKind::Standard);
259 ::std::set<OUString> aCurrentMasterPages;
260 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
262 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PageKind::Standard);
263 if (pMasterPage != nullptr)
264 aCurrentMasterPages.insert (pMasterPage->GetName());
267 std::vector<OUString> aNewMasterPages;
268 std::vector<OUString> aRemovedMasterPages;
269 MasterPageContainer::iterator aOldMasterPagesDescriptor (
270 maUsedMasterPages.find(&rDocument));
271 if (aOldMasterPagesDescriptor == maUsedMasterPages.end())
272 return;
274 // Send events about the newly used master pages.
275 ::std::set_difference (
276 aCurrentMasterPages.begin(),
277 aCurrentMasterPages.end(),
278 aOldMasterPagesDescriptor->second.begin(),
279 aOldMasterPagesDescriptor->second.end(),
280 std::back_inserter(aNewMasterPages));
281 for (auto& aNewMasterPage : aNewMasterPages)
283 MasterPageObserverEvent aEvent (
284 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
285 aNewMasterPage);
286 SendEvent (aEvent);
289 // Send events about master pages that are not used any longer.
290 ::std::set_difference (
291 aOldMasterPagesDescriptor->second.begin(),
292 aOldMasterPagesDescriptor->second.end(),
293 aCurrentMasterPages.begin(),
294 aCurrentMasterPages.end(),
295 std::back_inserter(aRemovedMasterPages));
296 for (auto& aRemovedMasterPage : aRemovedMasterPages)
298 MasterPageObserverEvent aEvent (
299 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
300 aRemovedMasterPage);
301 SendEvent (aEvent);
304 // Store the new list of master pages.
305 aOldMasterPagesDescriptor->second = aCurrentMasterPages;
308 void MasterPageObserver::Implementation::SendEvent (
309 MasterPageObserverEvent& rEvent)
311 for (auto& aLink : maListeners)
313 aLink.Call(rEvent);
317 } // end of namespace sd
319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */