Get the style color and number just once
[LibreOffice.git] / sd / source / ui / sidebar / MasterPageObserver.cxx
blob08677377a97ec16abf1243a43037c54313370057
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 master page observer will listen to events of this document and
42 detect changes of the use of master pages.
44 void RegisterDocument (SdDrawDocument& rDocument);
46 /** The master page observer will stop to listen to events of this
47 document.
49 void UnregisterDocument (SdDrawDocument& rDocument);
51 /** Add a listener that is informed of master pages that are newly
52 assigned to slides or become unassigned.
53 @param rEventListener
54 The event listener to call for future events. Call
55 RemoveEventListener() before the listener is destroyed.
57 void AddEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener);
59 /** Remove the given listener from the list of listeners.
60 @param rEventListener
61 After this method returns the given listener is not called back
62 from this object. Passing a listener that has not
63 been registered before is safe and is silently ignored.
65 void RemoveEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener);
67 private:
68 ::std::vector<Link<MasterPageObserverEvent&,void>> maListeners;
70 struct DrawDocHash {
71 size_t operator()(SdDrawDocument* argument) const
72 { return reinterpret_cast<sal_uIntPtr>(argument); }
74 typedef std::unordered_map<SdDrawDocument*,
75 MasterPageObserver::MasterPageNameSet,
76 DrawDocHash>
77 MasterPageContainer;
78 MasterPageContainer maUsedMasterPages;
80 virtual void Notify(
81 SfxBroadcaster& rBroadcaster,
82 const SfxHint& rHint) override;
84 void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);
86 void SendEvent (MasterPageObserverEvent& rEvent);
89 //===== MasterPageObserver ====================================================
91 MasterPageObserver& MasterPageObserver::Instance()
93 static MasterPageObserver* gInstance = []()
95 MasterPageObserver* pInstance = new MasterPageObserver ();
96 SdGlobalResourceContainer::Instance().AddResource (
97 ::std::unique_ptr<SdGlobalResource>(pInstance));
98 return pInstance;
99 }();
100 return *gInstance;
103 void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
105 mpImpl->RegisterDocument (rDocument);
108 void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
110 mpImpl->UnregisterDocument (rDocument);
113 void MasterPageObserver::AddEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener)
116 mpImpl->AddEventListener (rEventListener);
119 void MasterPageObserver::RemoveEventListener (const Link<MasterPageObserverEvent&,void>& rEventListener)
121 mpImpl->RemoveEventListener (rEventListener);
124 MasterPageObserver::MasterPageObserver()
125 : mpImpl (new Implementation)
128 MasterPageObserver::~MasterPageObserver()
131 //===== MasterPageObserver::Implementation ====================================
133 void MasterPageObserver::Implementation::RegisterDocument (
134 SdDrawDocument& rDocument)
136 // Gather the names of all the master pages in the given document.
137 MasterPageContainer::mapped_type aMasterPageSet;
138 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PageKind::Standard);
139 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
141 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PageKind::Standard);
142 if (pMasterPage != nullptr)
143 aMasterPageSet.insert (pMasterPage->GetName());
146 bool bAlreadyExists = maUsedMasterPages.find(&rDocument) != maUsedMasterPages.end();
147 maUsedMasterPages[&rDocument] = std::move(aMasterPageSet);
149 if (!bAlreadyExists)
150 StartListening (rDocument);
153 void MasterPageObserver::Implementation::UnregisterDocument (
154 SdDrawDocument& rDocument)
156 EndListening (rDocument);
158 MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
159 if(aMasterPageDescriptor != maUsedMasterPages.end())
160 maUsedMasterPages.erase(aMasterPageDescriptor);
163 void MasterPageObserver::Implementation::AddEventListener (
164 const Link<MasterPageObserverEvent&,void>& rEventListener)
166 if (::std::find (
167 maListeners.begin(),
168 maListeners.end(),
169 rEventListener) != maListeners.end())
170 return;
172 maListeners.push_back (rEventListener);
174 // Tell the new listener about all the master pages that are
175 // currently in use.
176 for (const auto& rDocument : maUsedMasterPages)
178 ::std::set<OUString>::reverse_iterator aNameIterator;
179 for (aNameIterator=rDocument.second.rbegin();
180 aNameIterator!=rDocument.second.rend();
181 ++aNameIterator)
183 MasterPageObserverEvent aEvent (
184 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
185 *aNameIterator);
186 SendEvent (aEvent);
191 void MasterPageObserver::Implementation::RemoveEventListener (
192 const Link<MasterPageObserverEvent&,void>& rEventListener)
194 maListeners.erase (
195 ::std::find (
196 maListeners.begin(),
197 maListeners.end(),
198 rEventListener));
201 void MasterPageObserver::Implementation::Notify(
202 SfxBroadcaster& rBroadcaster,
203 const SfxHint& rHint)
205 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
206 return;
207 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
209 switch (pSdrHint->GetKind())
211 case SdrHintKind::PageOrderChange:
212 // Process the modified set of pages only when the number of
213 // standard and notes master pages are equal. This test
214 // filters out events that are sent in between the insertion
215 // of a new standard master page and a new notes master
216 // page.
217 if (auto pDrawDocument = dynamic_cast<SdDrawDocument *>( &rBroadcaster ))
219 if (pDrawDocument->GetMasterSdPageCount(PageKind::Standard)
220 == pDrawDocument->GetMasterSdPageCount(PageKind::Notes))
222 AnalyzeUsedMasterPages (*pDrawDocument);
225 break;
227 default:
228 break;
232 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
233 SdDrawDocument& rDocument)
235 // Create a set of names of the master pages used by the given document.
236 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PageKind::Standard);
237 ::std::set<OUString> aCurrentMasterPages;
238 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++)
240 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PageKind::Standard);
241 if (pMasterPage != nullptr)
242 aCurrentMasterPages.insert (pMasterPage->GetName());
245 std::vector<OUString> aNewMasterPages;
246 std::vector<OUString> aRemovedMasterPages;
247 MasterPageContainer::iterator aOldMasterPagesDescriptor (
248 maUsedMasterPages.find(&rDocument));
249 if (aOldMasterPagesDescriptor == maUsedMasterPages.end())
250 return;
252 // Send events about the newly used master pages.
253 ::std::set_difference (
254 aCurrentMasterPages.begin(),
255 aCurrentMasterPages.end(),
256 aOldMasterPagesDescriptor->second.begin(),
257 aOldMasterPagesDescriptor->second.end(),
258 std::back_inserter(aNewMasterPages));
259 for (const auto& aNewMasterPage : aNewMasterPages)
261 MasterPageObserverEvent aEvent (
262 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
263 aNewMasterPage);
264 SendEvent (aEvent);
267 // Send events about master pages that are not used any longer.
268 ::std::set_difference (
269 aOldMasterPagesDescriptor->second.begin(),
270 aOldMasterPagesDescriptor->second.end(),
271 aCurrentMasterPages.begin(),
272 aCurrentMasterPages.end(),
273 std::back_inserter(aRemovedMasterPages));
274 for (const auto& aRemovedMasterPage : aRemovedMasterPages)
276 MasterPageObserverEvent aEvent (
277 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
278 aRemovedMasterPage);
279 SendEvent (aEvent);
282 // Store the new list of master pages.
283 aOldMasterPagesDescriptor->second = std::move(aCurrentMasterPages);
286 void MasterPageObserver::Implementation::SendEvent (
287 MasterPageObserverEvent& rEvent)
289 for (const auto& aLink : maListeners)
291 aLink.Call(rEvent);
295 } // end of namespace sd
297 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */