LibreOffice Module sd (master) 1
RecentlyUsedMasterPages.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
25
26#include <algorithm>
27#include <memory>
28#include <vector>
29
30#include <com/sun/star/container/XNameAccess.hpp>
31#include <com/sun/star/container/XNameContainer.hpp>
32#include <com/sun/star/lang/XSingleServiceFactory.hpp>
33#include <osl/doublecheckedlocking.h>
34#include <osl/getglobalmutex.hxx>
35
36using namespace ::com::sun::star;
37using namespace ::com::sun::star::uno;
38
39namespace {
40
41OUString GetPathToImpressConfigurationRoot()
42{
43 return "/org.openoffice.Office.Impress/";
44}
45OUString GetPathToSetNode()
46{
47 return "MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages";
48}
49
50} // end of anonymous namespace
51
52namespace sd::sidebar {
53
54RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = nullptr;
55
57{
58 if (mpInstance == nullptr)
59 {
60 ::osl::GetGlobalMutex aMutexFunctor;
61 ::osl::MutexGuard aGuard (aMutexFunctor());
62 if (mpInstance == nullptr)
63 {
65 pInstance->LateInit();
67 ::std::unique_ptr<SdGlobalResource>(pInstance));
68 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
69 mpInstance = pInstance;
70 }
71 }
72 else {
73 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
74 }
75
76 return *mpInstance;
77}
78
79constexpr size_t gnMaxListSize(8);
80
82 : mpContainer(std::make_shared<MasterPageContainer>())
83{
84}
85
87{
88 Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
89 mpContainer->RemoveChangeListener(aLink);
90
92 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
93}
94
96{
97 Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
98 mpContainer->AddChangeListener(aLink);
99
102 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
103}
104
106{
107 try
108 {
109 tools::ConfigurationAccess aConfiguration (
110 GetPathToImpressConfigurationRoot(),
112 Reference<container::XNameAccess> xSet (
113 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
114 UNO_QUERY);
115 if ( ! xSet.is())
116 return;
117
118 static constexpr OUStringLiteral sURLMemberName(u"URL");
119 static constexpr OUStringLiteral sNameMemberName(u"Name");
120 OUString sURL;
121 OUString sName;
122
123 // Read the names and URLs of the master pages.
124 const Sequence<OUString> aKeys (xSet->getElementNames());
125 mvMasterPages.clear();
126 mvMasterPages.reserve(aKeys.getLength());
127 for (const auto& rKey : aKeys)
128 {
129 Reference<container::XNameAccess> xSetItem (
130 xSet->getByName(rKey), UNO_QUERY);
131 if (xSetItem.is())
132 {
133 Any aURL (xSetItem->getByName(sURLMemberName));
134 Any aName (xSetItem->getByName(sNameMemberName));
135 aURL >>= sURL;
136 aName >>= sName;
137 SharedMasterPageDescriptor pDescriptor = std::make_shared<MasterPageDescriptor>(
139 -1,
140 sURL,
141 OUString(),
142 sName,
143 false,
144 std::make_shared<TemplatePageObjectProvider>(sURL),
145 std::make_shared<TemplatePreviewProvider>(sURL));
146 // For user supplied templates we use a different
147 // preview provider: The preview in the document shows
148 // not only shapes on the master page but also shapes on
149 // the foreground. This is misleading and therefore
150 // these previews are discarded and created directly
151 // from the page objects.
152 if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
153 pDescriptor->mpPreviewProvider = std::make_shared<PagePreviewProvider>();
154 MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
155 mvMasterPages.emplace_back(aToken,sURL,sName);
156 }
157 }
158
159 ResolveList();
160 }
161 catch (Exception&)
162 {
163 // Ignore exception.
164 }
165}
166
168{
169 try
170 {
171 tools::ConfigurationAccess aConfiguration (
172 GetPathToImpressConfigurationRoot(),
174 Reference<container::XNameContainer> xSet (
175 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
176 UNO_QUERY);
177 if ( ! xSet.is())
178 return;
179
180 // Clear the set.
181 const Sequence<OUString> aKeys (xSet->getElementNames());
182 for (const auto& rKey : aKeys)
183 xSet->removeByName (rKey);
184
185 // Fill it with the URLs of this object.
186 static constexpr OUStringLiteral sURLMemberName(u"URL");
187 static constexpr OUStringLiteral sNameMemberName(u"Name");
188 Any aValue;
189 Reference<lang::XSingleServiceFactory> xChildFactory (
190 xSet, UNO_QUERY);
191 if ( ! xChildFactory.is())
192 return;
193 sal_Int32 nIndex(0);
194 for (const auto& rDescriptor : mvMasterPages)
195 {
196 // Create new child.
197 OUString sKey = "index_" + OUString::number(nIndex);
198 Reference<container::XNameReplace> xChild(
199 xChildFactory->createInstance(), UNO_QUERY);
200 if (xChild.is())
201 {
202 xSet->insertByName (sKey, Any(xChild));
203
204 aValue <<= rDescriptor.msURL;
205 xChild->replaceByName (sURLMemberName, aValue);
206
207 aValue <<= rDescriptor.msName;
208 xChild->replaceByName (sNameMemberName, aValue);
209 }
210 ++nIndex;
211 }
212
213 // Write the data back to disk.
214 aConfiguration.CommitChanges();
215 }
216 catch (Exception&)
217 {
218 // Ignore exception.
219 }
220}
221
223{
224 if (::std::find (
225 maListeners.begin(),
226 maListeners.end(),
227 rEventListener) == maListeners.end())
228 {
229 maListeners.push_back (rEventListener);
230 }
231}
232
234{
235 maListeners.erase (
236 ::std::find (
237 maListeners.begin(),
238 maListeners.end(),
239 rEventListener));
240}
241
243{
244 return mvMasterPages.size();
245}
246
248{
249 if(nIndex<mvMasterPages.size())
250 return mvMasterPages[nIndex].maToken;
251 else
253}
254
256{
257 for (const auto& aLink : maListeners)
258 {
259 aLink.Call(nullptr);
260 }
261}
262
263IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
264 MasterPageObserverEvent&, rEvent, void)
265{
266 switch (rEvent.meType)
267 {
270 AddMasterPage(
271 mpContainer->GetTokenForStyleName(rEvent.mrMasterPageName));
272 break;
273
275 // Do not change the list of recently master pages (the deleted
276 // page was recently used) but tell the listeners. They may want
277 // to update their lists.
278 SendEvent();
279 break;
280 }
281}
282
283IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
284 MasterPageContainerChangeEvent&, rEvent, void)
285{
286 switch (rEvent.meEventType)
287 {
291 ResolveList();
292 break;
293
294 default:
295 // Ignored.
296 break;
297 }
298}
299
302{
303 // For the page to be inserted the token has to be valid and the page
304 // has to have a valid URL. This excludes master pages that do not come
305 // from template files.
307 || mpContainer->GetURLForToken(aToken).isEmpty())
308 return;
309
310 MasterPageList::iterator aIterator (
311 ::std::find_if(mvMasterPages.begin(),mvMasterPages.end(),
313 if (aIterator != mvMasterPages.end())
314 {
315 // When an entry for the given token already exists then remove
316 // it now and insert it later at the head of the list.
317 mvMasterPages.erase (aIterator);
318 }
319
320 mvMasterPages.insert(mvMasterPages.begin(),
322 aToken,
323 mpContainer->GetURLForToken(aToken),
324 mpContainer->GetStyleNameForToken(aToken)));
325
326 // Shorten list to maximal size.
327 while (mvMasterPages.size() > gnMaxListSize)
328 {
329 mvMasterPages.pop_back ();
330 }
331
333 SendEvent();
334}
335
337{
338 bool bNotify (false);
339
340 for (auto& rDescriptor : mvMasterPages)
341 {
342 if (rDescriptor.maToken == MasterPageContainer::NIL_TOKEN)
343 {
344 MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(rDescriptor.msURL));
345 rDescriptor.maToken = aToken;
346 if (aToken != MasterPageContainer::NIL_TOKEN)
347 bNotify = true;
348 }
349 else
350 {
351 if ( ! mpContainer->HasToken(rDescriptor.maToken))
352 {
353 rDescriptor.maToken = MasterPageContainer::NIL_TOKEN;
354 bNotify = true;
355 }
356 }
357 }
358
359 if (bNotify)
360 SendEvent();
361}
362
363} // end of namespace sd::sidebar
364
365/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Objects of this class are sent to listeners of the MasterPageObserver singleton when the list of mast...
@ ET_MASTER_PAGE_EXISTS
Master page already exists when document is registered.
@ ET_MASTER_PAGE_ADDED
Master page has been added to a document.
@ ET_MASTER_PAGE_REMOVED
Master page has been removed from to a document.
void AddEventListener(const Link< MasterPageObserverEvent &, void > &rEventListener)
Add a listener that is informed of master pages that are newly assigned to slides or become unassigne...
static MasterPageObserver & Instance()
Return the single instance of this class.
void RemoveEventListener(const Link< MasterPageObserverEvent &, void > &rEventListener)
Remove the given listener from the list of listeners.
void AddResource(::std::unique_ptr< SdGlobalResource > pResource)
Add a resource to the container.
static SdGlobalResourceContainer & Instance()
For some changes to the set of master pages in a MasterPageContainer or to the data stored for each m...
This container manages the master pages used by the MasterPagesSelector controls.
This singleton holds a list of the most recently used master pages.
void LoadPersistentValues()
Load the list of recently used master pages from the registry where it was saved to make it persisten...
void SavePersistentValues()
Save the list of recently used master pages to the registry to make it persistent.
void RemoveEventListener(const Link< LinkParamNone *, void > &rEventListener)
void AddMasterPage(MasterPageContainer::Token aToken)
Add a descriptor for the specified master page to the end of the list of most recently used master pa...
std::shared_ptr< MasterPageContainer > mpContainer
static RecentlyUsedMasterPages * mpInstance
The single instance of this class.
static RecentlyUsedMasterPages & Instance()
Return the single instance of this class.
void AddEventListener(const Link< LinkParamNone *, void > &rEventListener)
void LateInit()
Call this method after a new object has been created.
::std::vector< Link< LinkParamNone *, void > > maListeners
MasterPageContainer::Token GetTokenForIndex(sal_uInt32 nIndex) const
This class gives access to the configuration.
void CommitChanges()
Write any changes that have been made back to the configuration.
css::uno::Any GetConfigurationNode(const OUString &rsPathToNode)
Return a configuration node below the root of the called object.
URL aURL
float u
OUString sName
sal_Int32 nIndex
OUString aName
@ Exception
std::shared_ptr< T > make_shared(Args &&... args)
constexpr size_t gnMaxListSize(8)
std::shared_ptr< MasterPageDescriptor > SharedMasterPageDescriptor
IMPL_LINK(CurrentMasterPagesSelector, EventMultiplexerListener, sd::tools::EventMultiplexerEvent &, rEvent, void)