bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / sidebar / RecentlyUsedMasterPages.cxx
blob89900189fed6cd677062156f73d919560d840fb8
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 <vector>
31 #include <comphelper/processfactory.hxx>
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/frame/XComponentLoader.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/beans/PropertyValue.hpp>
40 #include <com/sun/star/beans/PropertyState.hpp>
41 #include <unotools/confignode.hxx>
42 #include <osl/doublecheckedlocking.h>
43 #include <osl/getglobalmutex.hxx>
45 using namespace ::std;
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
49 namespace {
51 static OUString GetPathToImpressConfigurationRoot()
53 return OUString("/org.openoffice.Office.Impress/");
55 static OUString GetPathToSetNode()
57 return OUString("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
60 } // end of anonymous namespace
62 namespace sd { namespace sidebar {
64 RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = NULL;
66 RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance()
68 if (mpInstance == NULL)
70 ::osl::GetGlobalMutex aMutexFunctor;
71 ::osl::MutexGuard aGuard (aMutexFunctor());
72 if (mpInstance == NULL)
74 RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages();
75 pInstance->LateInit();
76 SdGlobalResourceContainer::Instance().AddResource (
77 ::std::unique_ptr<SdGlobalResource>(pInstance));
78 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
79 mpInstance = pInstance;
82 else {
83 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
86 return *mpInstance;
89 RecentlyUsedMasterPages::RecentlyUsedMasterPages()
90 : maListeners(),
91 mvMasterPages(),
92 mnMaxListSize(8),
93 mpContainer(new MasterPageContainer())
97 RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
99 Link<> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
100 mpContainer->RemoveChangeListener(aLink);
102 MasterPageObserver::Instance().RemoveEventListener(
103 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
106 void RecentlyUsedMasterPages::LateInit()
108 Link<> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
109 mpContainer->AddChangeListener(aLink);
111 LoadPersistentValues ();
112 MasterPageObserver::Instance().AddEventListener(
113 LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
116 void RecentlyUsedMasterPages::LoadPersistentValues()
120 tools::ConfigurationAccess aConfiguration (
121 GetPathToImpressConfigurationRoot(),
122 tools::ConfigurationAccess::READ_ONLY);
123 Reference<container::XNameAccess> xSet (
124 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
125 UNO_QUERY);
126 if ( ! xSet.is())
127 return;
129 const OUString sURLMemberName("URL");
130 const OUString sNameMemberName("Name");
131 OUString sURL;
132 OUString sName;
134 // Read the names and URLs of the master pages.
135 Sequence<OUString> aKeys (xSet->getElementNames());
136 mvMasterPages.clear();
137 mvMasterPages.reserve(aKeys.getLength());
138 for (int i=0; i<aKeys.getLength(); i++)
140 Reference<container::XNameAccess> xSetItem (
141 xSet->getByName(aKeys[i]), UNO_QUERY);
142 if (xSetItem.is())
144 Any aURL (xSetItem->getByName(sURLMemberName));
145 Any aName (xSetItem->getByName(sNameMemberName));
146 aURL >>= sURL;
147 aName >>= sName;
148 SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor(
149 MasterPageContainer::TEMPLATE,
151 sURL,
152 OUString(),
153 sName,
154 false,
155 ::boost::shared_ptr<PageObjectProvider>(
156 new TemplatePageObjectProvider(sURL)),
157 ::boost::shared_ptr<PreviewProvider>(
158 new TemplatePreviewProvider(sURL))));
159 // For user supplied templates we use a different
160 // preview provider: The preview in the document shows
161 // not only shapes on the master page but also shapes on
162 // the foreground. This is misleading and therefore
163 // these previews are discarded and created directly
164 // from the page objects.
165 if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
166 pDescriptor->mpPreviewProvider = ::boost::shared_ptr<PreviewProvider>(
167 new PagePreviewProvider());
168 MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
169 mvMasterPages.push_back(Descriptor(aToken,sURL,sName));
173 ResolveList();
175 catch (Exception&)
177 // Ignore exception.
181 void RecentlyUsedMasterPages::SavePersistentValues()
185 tools::ConfigurationAccess aConfiguration (
186 GetPathToImpressConfigurationRoot(),
187 tools::ConfigurationAccess::READ_WRITE);
188 Reference<container::XNameContainer> xSet (
189 aConfiguration.GetConfigurationNode(GetPathToSetNode()),
190 UNO_QUERY);
191 if ( ! xSet.is())
192 return;
194 // Clear the set.
195 Sequence<OUString> aKeys (xSet->getElementNames());
196 sal_Int32 i;
197 for (i=0; i<aKeys.getLength(); i++)
198 xSet->removeByName (aKeys[i]);
200 // Fill it with the URLs of this object.
201 const OUString sURLMemberName("URL");
202 const OUString sNameMemberName("Name");
203 Any aValue;
204 Reference<lang::XSingleServiceFactory> xChildFactory (
205 xSet, UNO_QUERY);
206 if ( ! xChildFactory.is())
207 return;
208 MasterPageList::const_iterator iDescriptor;
209 sal_Int32 nIndex(0);
210 for (iDescriptor=mvMasterPages.begin();
211 iDescriptor!=mvMasterPages.end();
212 ++iDescriptor,++nIndex)
214 // Create new child.
215 OUString sKey ("index_");
216 sKey += OUString::number(nIndex);
217 Reference<container::XNameReplace> xChild(
218 xChildFactory->createInstance(), UNO_QUERY);
219 if (xChild.is())
221 xSet->insertByName (sKey, makeAny(xChild));
223 aValue <<= OUString(iDescriptor->msURL);
224 xChild->replaceByName (sURLMemberName, aValue);
226 aValue <<= OUString(iDescriptor->msName);
227 xChild->replaceByName (sNameMemberName, aValue);
231 // Write the data back to disk.
232 aConfiguration.CommitChanges();
234 catch (Exception&)
236 // Ignore exception.
240 void RecentlyUsedMasterPages::AddEventListener (const Link<>& 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<>& 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 ::std::vector<Link<>>::iterator aLink (maListeners.begin());
276 ::std::vector<Link<>>::iterator aEnd (maListeners.end());
277 while (aLink!=aEnd)
279 aLink->Call (NULL);
280 ++aLink;
284 IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
285 MasterPageObserverEvent*, pEvent)
287 switch (pEvent->meType)
289 case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED:
290 case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS:
291 AddMasterPage(
292 mpContainer->GetTokenForStyleName(pEvent->mrMasterPageName));
293 break;
295 case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED:
296 // Do not change the list of recently master pages (the deleted
297 // page was recently used) but tell the listeners. They may want
298 // to update their lists.
299 SendEvent();
300 break;
302 return 0;
305 IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
306 MasterPageContainerChangeEvent*, pEvent)
308 if (pEvent != NULL)
309 switch (pEvent->meEventType)
311 case MasterPageContainerChangeEvent::CHILD_ADDED:
312 case MasterPageContainerChangeEvent::CHILD_REMOVED:
313 case MasterPageContainerChangeEvent::INDEX_CHANGED:
314 case MasterPageContainerChangeEvent::INDEXES_CHANGED:
315 ResolveList();
316 break;
318 default:
319 // Ignored.
320 break;
322 return 0;
325 void RecentlyUsedMasterPages::AddMasterPage (
326 MasterPageContainer::Token aToken,
327 bool bMakePersistent)
329 // For the page to be inserted the token has to be valid and the page
330 // has to have a valid URL. This excludes master pages that do not come
331 // from template files.
332 if (aToken != MasterPageContainer::NIL_TOKEN
333 && !mpContainer->GetURLForToken(aToken).isEmpty())
336 MasterPageList::iterator aIterator (
337 ::std::find_if(mvMasterPages.begin(),mvMasterPages.end(),
338 Descriptor::TokenComparator(aToken)));
339 if (aIterator != mvMasterPages.end())
341 // When an entry for the given token already exists then remove
342 // it now and insert it later at the head of the list.
343 mvMasterPages.erase (aIterator);
346 mvMasterPages.insert(mvMasterPages.begin(),
347 Descriptor(
348 aToken,
349 mpContainer->GetURLForToken(aToken),
350 mpContainer->GetStyleNameForToken(aToken)));
352 // Shorten list to maximal size.
353 while (mvMasterPages.size() > mnMaxListSize)
355 mvMasterPages.pop_back ();
358 if (bMakePersistent)
359 SavePersistentValues ();
360 SendEvent();
364 void RecentlyUsedMasterPages::ResolveList()
366 bool bNotify (false);
368 MasterPageList::iterator iDescriptor;
369 for (iDescriptor=mvMasterPages.begin(); iDescriptor!=mvMasterPages.end(); ++iDescriptor)
371 if (iDescriptor->maToken == MasterPageContainer::NIL_TOKEN)
373 MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(iDescriptor->msURL));
374 iDescriptor->maToken = aToken;
375 if (aToken != MasterPageContainer::NIL_TOKEN)
376 bNotify = true;
378 else
380 if ( ! mpContainer->HasToken(iDescriptor->maToken))
382 iDescriptor->maToken = MasterPageContainer::NIL_TOKEN;
383 bNotify = true;
388 if (bNotify)
389 SendEvent();
392 } } // end of namespace sd::sidebar
394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */