bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / sidebar / RecentlyUsedMasterPages.cxx
blob353bd6e2fe5a8607f4d66b9d8794a3146b339510
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 "RecentlyUsedMasterPages.hxx"
21 #include "MasterPageContainerProviders.hxx"
22 #include <MasterPageObserver.hxx>
23 #include "MasterPagesSelector.hxx"
24 #include "MasterPageDescriptor.hxx"
25 #include <tools/ConfigurationAccess.hxx>
26 #include <drawdoc.hxx>
27 #include <sdpage.hxx>
29 #include <algorithm>
30 #include <memory>
31 #include <vector>
33 #include <unomodel.hxx>
34 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
35 #include <com/sun/star/drawing/XDrawPages.hpp>
36 #include <com/sun/star/container/XNameAccess.hpp>
37 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/beans/PropertyValue.hpp>
41 #include <com/sun/star/beans/PropertyState.hpp>
42 #include <unotools/confignode.hxx>
43 #include <osl/doublecheckedlocking.h>
44 #include <osl/getglobalmutex.hxx>
46 using namespace ::std;
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::uno;
50 namespace {
52 OUString GetPathToImpressConfigurationRoot()
54 return OUString("/org.openoffice.Office.Impress/");
56 OUString GetPathToSetNode()
58 return OUString("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
61 } // end of anonymous namespace
63 namespace sd { namespace sidebar {
65 RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = nullptr;
67 RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance()
69 if (mpInstance == nullptr)
71 ::osl::GetGlobalMutex aMutexFunctor;
72 ::osl::MutexGuard aGuard (aMutexFunctor());
73 if (mpInstance == nullptr)
75 RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages();
76 pInstance->LateInit();
77 SdGlobalResourceContainer::Instance().AddResource (
78 ::std::unique_ptr<SdGlobalResource>(pInstance));
79 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
80 mpInstance = pInstance;
83 else {
84 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
87 return *mpInstance;
90 static constexpr size_t gnMaxListSize(8);
92 RecentlyUsedMasterPages::RecentlyUsedMasterPages()
93 : maListeners(),
94 mvMasterPages(),
95 mpContainer(new MasterPageContainer())
99 RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
101 Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
102 mpContainer->RemoveChangeListener(aLink);
104 MasterPageObserver::Instance().RemoveEventListener(
105 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
108 void RecentlyUsedMasterPages::LateInit()
110 Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
111 mpContainer->AddChangeListener(aLink);
113 LoadPersistentValues ();
114 MasterPageObserver::Instance().AddEventListener(
115 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
118 void RecentlyUsedMasterPages::LoadPersistentValues()
122 tools::ConfigurationAccess aConfiguration (
123 GetPathToImpressConfigurationRoot(),
124 tools::ConfigurationAccess::READ_ONLY);
125 Reference<container::XNameAccess> xSet (
126 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
127 UNO_QUERY);
128 if ( ! xSet.is())
129 return;
131 const OUString sURLMemberName("URL");
132 const OUString sNameMemberName("Name");
133 OUString sURL;
134 OUString sName;
136 // Read the names and URLs of the master pages.
137 Sequence<OUString> aKeys (xSet->getElementNames());
138 mvMasterPages.clear();
139 mvMasterPages.reserve(aKeys.getLength());
140 for (int i=0; i<aKeys.getLength(); i++)
142 Reference<container::XNameAccess> xSetItem (
143 xSet->getByName(aKeys[i]), UNO_QUERY);
144 if (xSetItem.is())
146 Any aURL (xSetItem->getByName(sURLMemberName));
147 Any aName (xSetItem->getByName(sNameMemberName));
148 aURL >>= sURL;
149 aName >>= sName;
150 SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor(
151 MasterPageContainer::TEMPLATE,
153 sURL,
154 OUString(),
155 sName,
156 false,
157 std::shared_ptr<PageObjectProvider>(
158 new TemplatePageObjectProvider(sURL)),
159 std::shared_ptr<PreviewProvider>(
160 new TemplatePreviewProvider(sURL))));
161 // For user supplied templates we use a different
162 // preview provider: The preview in the document shows
163 // not only shapes on the master page but also shapes on
164 // the foreground. This is misleading and therefore
165 // these previews are discarded and created directly
166 // from the page objects.
167 if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
168 pDescriptor->mpPreviewProvider = std::shared_ptr<PreviewProvider>(
169 new PagePreviewProvider());
170 MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
171 mvMasterPages.emplace_back(aToken,sURL,sName);
175 ResolveList();
177 catch (Exception&)
179 // Ignore exception.
183 void RecentlyUsedMasterPages::SavePersistentValues()
187 tools::ConfigurationAccess aConfiguration (
188 GetPathToImpressConfigurationRoot(),
189 tools::ConfigurationAccess::READ_WRITE);
190 Reference<container::XNameContainer> xSet (
191 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
192 UNO_QUERY);
193 if ( ! xSet.is())
194 return;
196 // Clear the set.
197 Sequence<OUString> aKeys (xSet->getElementNames());
198 sal_Int32 i;
199 for (i=0; i<aKeys.getLength(); i++)
200 xSet->removeByName (aKeys[i]);
202 // Fill it with the URLs of this object.
203 const OUString sURLMemberName("URL");
204 const OUString sNameMemberName("Name");
205 Any aValue;
206 Reference<lang::XSingleServiceFactory> xChildFactory (
207 xSet, UNO_QUERY);
208 if ( ! xChildFactory.is())
209 return;
210 sal_Int32 nIndex(0);
211 for (const auto& rDescriptor : mvMasterPages)
213 // Create new child.
214 OUString sKey ("index_");
215 sKey += OUString::number(nIndex);
216 Reference<container::XNameReplace> xChild(
217 xChildFactory->createInstance(), UNO_QUERY);
218 if (xChild.is())
220 xSet->insertByName (sKey, makeAny(xChild));
222 aValue <<= rDescriptor.msURL;
223 xChild->replaceByName (sURLMemberName, aValue);
225 aValue <<= rDescriptor.msName;
226 xChild->replaceByName (sNameMemberName, aValue);
228 ++nIndex;
231 // Write the data back to disk.
232 aConfiguration.CommitChanges();
234 catch (Exception&)
236 // Ignore exception.
240 void RecentlyUsedMasterPages::AddEventListener (const Link<LinkParamNone*,void>& rEventListener)
242 if (::std::find (
243 maListeners.begin(),
244 maListeners.end(),
245 rEventListener) == maListeners.end())
247 maListeners.push_back (rEventListener);
251 void RecentlyUsedMasterPages::RemoveEventListener (const Link<LinkParamNone*,void>& rEventListener)
253 maListeners.erase (
254 ::std::find (
255 maListeners.begin(),
256 maListeners.end(),
257 rEventListener));
260 int RecentlyUsedMasterPages::GetMasterPageCount() const
262 return mvMasterPages.size();
265 MasterPageContainer::Token RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex) const
267 if(nIndex<mvMasterPages.size())
268 return mvMasterPages[nIndex].maToken;
269 else
270 return MasterPageContainer::NIL_TOKEN;
273 void RecentlyUsedMasterPages::SendEvent()
275 for (auto& aLink : maListeners)
277 aLink.Call(nullptr);
281 IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
282 MasterPageObserverEvent&, rEvent, void)
284 switch (rEvent.meType)
286 case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED:
287 case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS:
288 AddMasterPage(
289 mpContainer->GetTokenForStyleName(rEvent.mrMasterPageName));
290 break;
292 case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED:
293 // Do not change the list of recently master pages (the deleted
294 // page was recently used) but tell the listeners. They may want
295 // to update their lists.
296 SendEvent();
297 break;
301 IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
302 MasterPageContainerChangeEvent&, rEvent, void)
304 switch (rEvent.meEventType)
306 case MasterPageContainerChangeEvent::EventType::CHILD_ADDED:
307 case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED:
308 case MasterPageContainerChangeEvent::EventType::INDEX_CHANGED:
309 ResolveList();
310 break;
312 default:
313 // Ignored.
314 break;
318 void RecentlyUsedMasterPages::AddMasterPage (
319 MasterPageContainer::Token aToken)
321 // For the page to be inserted the token has to be valid and the page
322 // has to have a valid URL. This excludes master pages that do not come
323 // from template files.
324 if (aToken == MasterPageContainer::NIL_TOKEN
325 || mpContainer->GetURLForToken(aToken).isEmpty())
326 return;
328 MasterPageList::iterator aIterator (
329 ::std::find_if(mvMasterPages.begin(),mvMasterPages.end(),
330 Descriptor::TokenComparator(aToken)));
331 if (aIterator != mvMasterPages.end())
333 // When an entry for the given token already exists then remove
334 // it now and insert it later at the head of the list.
335 mvMasterPages.erase (aIterator);
338 mvMasterPages.insert(mvMasterPages.begin(),
339 Descriptor(
340 aToken,
341 mpContainer->GetURLForToken(aToken),
342 mpContainer->GetStyleNameForToken(aToken)));
344 // Shorten list to maximal size.
345 while (mvMasterPages.size() > gnMaxListSize)
347 mvMasterPages.pop_back ();
350 SavePersistentValues ();
351 SendEvent();
354 void RecentlyUsedMasterPages::ResolveList()
356 bool bNotify (false);
358 for (auto& rDescriptor : mvMasterPages)
360 if (rDescriptor.maToken == MasterPageContainer::NIL_TOKEN)
362 MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(rDescriptor.msURL));
363 rDescriptor.maToken = aToken;
364 if (aToken != MasterPageContainer::NIL_TOKEN)
365 bNotify = true;
367 else
369 if ( ! mpContainer->HasToken(rDescriptor.maToken))
371 rDescriptor.maToken = MasterPageContainer::NIL_TOKEN;
372 bNotify = true;
377 if (bNotify)
378 SendEvent();
381 } } // end of namespace sd::sidebar
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */