Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sd / source / ui / sidebar / RecentlyUsedMasterPages.cxx
blob30785589e4ad4fe0a1eab559d51f5a5b5100a627
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 <MasterPageObserver.hxx>
22 #include "MasterPagesSelector.hxx"
23 #include "MasterPageDescriptor.hxx"
24 #include <tools/ConfigurationAccess.hxx>
25 #include <drawdoc.hxx>
26 #include <sdpage.hxx>
28 #include <algorithm>
29 #include <memory>
30 #include <vector>
32 #include <unomodel.hxx>
33 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
34 #include <com/sun/star/drawing/XDrawPages.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <com/sun/star/beans/PropertyState.hpp>
40 #include <unotools/confignode.hxx>
41 #include <osl/doublecheckedlocking.h>
42 #include <osl/getglobalmutex.hxx>
44 using namespace ::std;
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
48 namespace {
50 OUString GetPathToImpressConfigurationRoot()
52 return OUString("/org.openoffice.Office.Impress/");
54 OUString GetPathToSetNode()
56 return OUString("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
59 } // end of anonymous namespace
61 namespace sd { namespace sidebar {
63 RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = nullptr;
65 RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance()
67 if (mpInstance == nullptr)
69 ::osl::GetGlobalMutex aMutexFunctor;
70 ::osl::MutexGuard aGuard (aMutexFunctor());
71 if (mpInstance == nullptr)
73 RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages();
74 pInstance->LateInit();
75 SdGlobalResourceContainer::Instance().AddResource (
76 ::std::unique_ptr<SdGlobalResource>(pInstance));
77 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
78 mpInstance = pInstance;
81 else {
82 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
85 return *mpInstance;
88 RecentlyUsedMasterPages::RecentlyUsedMasterPages()
89 : maListeners(),
90 mvMasterPages(),
91 mnMaxListSize(8),
92 mpContainer(new MasterPageContainer())
96 RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
98 Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
99 mpContainer->RemoveChangeListener(aLink);
101 MasterPageObserver::Instance().RemoveEventListener(
102 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
105 void RecentlyUsedMasterPages::LateInit()
107 Link<MasterPageContainerChangeEvent&,void> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
108 mpContainer->AddChangeListener(aLink);
110 LoadPersistentValues ();
111 MasterPageObserver::Instance().AddEventListener(
112 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
115 void RecentlyUsedMasterPages::LoadPersistentValues()
119 tools::ConfigurationAccess aConfiguration (
120 GetPathToImpressConfigurationRoot(),
121 tools::ConfigurationAccess::READ_ONLY);
122 Reference<container::XNameAccess> xSet (
123 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
124 UNO_QUERY);
125 if ( ! xSet.is())
126 return;
128 const OUString sURLMemberName("URL");
129 const OUString sNameMemberName("Name");
130 OUString sURL;
131 OUString sName;
133 // Read the names and URLs of the master pages.
134 Sequence<OUString> aKeys (xSet->getElementNames());
135 mvMasterPages.clear();
136 mvMasterPages.reserve(aKeys.getLength());
137 for (int i=0; i<aKeys.getLength(); i++)
139 Reference<container::XNameAccess> xSetItem (
140 xSet->getByName(aKeys[i]), UNO_QUERY);
141 if (xSetItem.is())
143 Any aURL (xSetItem->getByName(sURLMemberName));
144 Any aName (xSetItem->getByName(sNameMemberName));
145 aURL >>= sURL;
146 aName >>= sName;
147 SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor(
148 MasterPageContainer::TEMPLATE,
150 sURL,
151 OUString(),
152 sName,
153 false,
154 std::shared_ptr<PageObjectProvider>(
155 new TemplatePageObjectProvider(sURL)),
156 std::shared_ptr<PreviewProvider>(
157 new TemplatePreviewProvider(sURL))));
158 // For user supplied templates we use a different
159 // preview provider: The preview in the document shows
160 // not only shapes on the master page but also shapes on
161 // the foreground. This is misleading and therefore
162 // these previews are discarded and created directly
163 // from the page objects.
164 if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
165 pDescriptor->mpPreviewProvider = std::shared_ptr<PreviewProvider>(
166 new PagePreviewProvider());
167 MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
168 mvMasterPages.emplace_back(aToken,sURL,sName);
172 ResolveList();
174 catch (Exception&)
176 // Ignore exception.
180 void RecentlyUsedMasterPages::SavePersistentValues()
184 tools::ConfigurationAccess aConfiguration (
185 GetPathToImpressConfigurationRoot(),
186 tools::ConfigurationAccess::READ_WRITE);
187 Reference<container::XNameContainer> xSet (
188 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
189 UNO_QUERY);
190 if ( ! xSet.is())
191 return;
193 // Clear the set.
194 Sequence<OUString> aKeys (xSet->getElementNames());
195 sal_Int32 i;
196 for (i=0; i<aKeys.getLength(); i++)
197 xSet->removeByName (aKeys[i]);
199 // Fill it with the URLs of this object.
200 const OUString sURLMemberName("URL");
201 const OUString sNameMemberName("Name");
202 Any aValue;
203 Reference<lang::XSingleServiceFactory> xChildFactory (
204 xSet, UNO_QUERY);
205 if ( ! xChildFactory.is())
206 return;
207 MasterPageList::const_iterator iDescriptor;
208 sal_Int32 nIndex(0);
209 for (iDescriptor=mvMasterPages.begin();
210 iDescriptor!=mvMasterPages.end();
211 ++iDescriptor,++nIndex)
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 <<= iDescriptor->msURL;
223 xChild->replaceByName (sURLMemberName, aValue);
225 aValue <<= iDescriptor->msName;
226 xChild->replaceByName (sNameMemberName, aValue);
230 // Write the data back to disk.
231 aConfiguration.CommitChanges();
233 catch (Exception&)
235 // Ignore exception.
239 void RecentlyUsedMasterPages::AddEventListener (const Link<LinkParamNone*,void>& rEventListener)
241 if (::std::find (
242 maListeners.begin(),
243 maListeners.end(),
244 rEventListener) == maListeners.end())
246 maListeners.push_back (rEventListener);
250 void RecentlyUsedMasterPages::RemoveEventListener (const Link<LinkParamNone*,void>& rEventListener)
252 maListeners.erase (
253 ::std::find (
254 maListeners.begin(),
255 maListeners.end(),
256 rEventListener));
259 int RecentlyUsedMasterPages::GetMasterPageCount() const
261 return mvMasterPages.size();
264 MasterPageContainer::Token RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex) const
266 if(nIndex<mvMasterPages.size())
267 return mvMasterPages[nIndex].maToken;
268 else
269 return MasterPageContainer::NIL_TOKEN;
272 void RecentlyUsedMasterPages::SendEvent()
274 for (auto& aLink : maListeners)
276 aLink.Call(nullptr);
280 IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
281 MasterPageObserverEvent&, rEvent, void)
283 switch (rEvent.meType)
285 case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED:
286 case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS:
287 AddMasterPage(
288 mpContainer->GetTokenForStyleName(rEvent.mrMasterPageName));
289 break;
291 case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED:
292 // Do not change the list of recently master pages (the deleted
293 // page was recently used) but tell the listeners. They may want
294 // to update their lists.
295 SendEvent();
296 break;
300 IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
301 MasterPageContainerChangeEvent&, rEvent, void)
303 switch (rEvent.meEventType)
305 case MasterPageContainerChangeEvent::EventType::CHILD_ADDED:
306 case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED:
307 case MasterPageContainerChangeEvent::EventType::INDEX_CHANGED:
308 ResolveList();
309 break;
311 default:
312 // Ignored.
313 break;
317 void RecentlyUsedMasterPages::AddMasterPage (
318 MasterPageContainer::Token aToken)
320 // For the page to be inserted the token has to be valid and the page
321 // has to have a valid URL. This excludes master pages that do not come
322 // from template files.
323 if (aToken != MasterPageContainer::NIL_TOKEN
324 && !mpContainer->GetURLForToken(aToken).isEmpty())
327 MasterPageList::iterator aIterator (
328 ::std::find_if(mvMasterPages.begin(),mvMasterPages.end(),
329 Descriptor::TokenComparator(aToken)));
330 if (aIterator != mvMasterPages.end())
332 // When an entry for the given token already exists then remove
333 // it now and insert it later at the head of the list.
334 mvMasterPages.erase (aIterator);
337 mvMasterPages.insert(mvMasterPages.begin(),
338 Descriptor(
339 aToken,
340 mpContainer->GetURLForToken(aToken),
341 mpContainer->GetStyleNameForToken(aToken)));
343 // Shorten list to maximal size.
344 while (mvMasterPages.size() > mnMaxListSize)
346 mvMasterPages.pop_back ();
349 SavePersistentValues ();
350 SendEvent();
354 void RecentlyUsedMasterPages::ResolveList()
356 bool bNotify (false);
358 MasterPageList::iterator iDescriptor;
359 for (iDescriptor=mvMasterPages.begin(); iDescriptor!=mvMasterPages.end(); ++iDescriptor)
361 if (iDescriptor->maToken == MasterPageContainer::NIL_TOKEN)
363 MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(iDescriptor->msURL));
364 iDescriptor->maToken = aToken;
365 if (aToken != MasterPageContainer::NIL_TOKEN)
366 bNotify = true;
368 else
370 if ( ! mpContainer->HasToken(iDescriptor->maToken))
372 iDescriptor->maToken = MasterPageContainer::NIL_TOKEN;
373 bNotify = true;
378 if (bNotify)
379 SendEvent();
382 } } // end of namespace sd::sidebar
384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */