Line data Source code
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 :
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"
27 :
28 : #include <algorithm>
29 : #include <vector>
30 :
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>
44 :
45 : using namespace ::std;
46 : using namespace ::com::sun::star;
47 : using namespace ::com::sun::star::uno;
48 :
49 : namespace {
50 :
51 0 : static OUString GetPathToImpressConfigurationRoot()
52 : {
53 0 : return OUString("/org.openoffice.Office.Impress/");
54 : }
55 0 : static OUString GetPathToSetNode()
56 : {
57 0 : return OUString("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
58 : }
59 :
60 : } // end of anonymous namespace
61 :
62 : namespace sd { namespace sidebar {
63 :
64 : RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = NULL;
65 :
66 0 : RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance()
67 : {
68 0 : if (mpInstance == NULL)
69 : {
70 : ::osl::GetGlobalMutex aMutexFunctor;
71 0 : ::osl::MutexGuard aGuard (aMutexFunctor());
72 0 : if (mpInstance == NULL)
73 : {
74 0 : RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages();
75 0 : pInstance->LateInit();
76 0 : SdGlobalResourceContainer::Instance().AddResource (
77 0 : ::std::unique_ptr<SdGlobalResource>(pInstance));
78 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
79 0 : mpInstance = pInstance;
80 0 : }
81 : }
82 : else {
83 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
84 : }
85 :
86 0 : return *mpInstance;
87 : }
88 :
89 0 : RecentlyUsedMasterPages::RecentlyUsedMasterPages()
90 : : maListeners(),
91 : mvMasterPages(),
92 : mnMaxListSize(8),
93 0 : mpContainer(new MasterPageContainer())
94 : {
95 0 : }
96 :
97 0 : RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
98 : {
99 0 : Link<> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
100 0 : mpContainer->RemoveChangeListener(aLink);
101 :
102 0 : MasterPageObserver::Instance().RemoveEventListener(
103 0 : LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
104 0 : }
105 :
106 0 : void RecentlyUsedMasterPages::LateInit()
107 : {
108 0 : Link<> aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
109 0 : mpContainer->AddChangeListener(aLink);
110 :
111 0 : LoadPersistentValues ();
112 0 : MasterPageObserver::Instance().AddEventListener(
113 0 : LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
114 0 : }
115 :
116 0 : void RecentlyUsedMasterPages::LoadPersistentValues()
117 : {
118 : try
119 : {
120 : tools::ConfigurationAccess aConfiguration (
121 : GetPathToImpressConfigurationRoot(),
122 0 : tools::ConfigurationAccess::READ_ONLY);
123 : Reference<container::XNameAccess> xSet (
124 : aConfiguration.GetConfigurationNode(GetPathToSetNode()),
125 0 : UNO_QUERY);
126 0 : if ( ! xSet.is())
127 0 : return;
128 :
129 0 : const OUString sURLMemberName("URL");
130 0 : const OUString sNameMemberName("Name");
131 0 : OUString sURL;
132 0 : OUString sName;
133 :
134 : // Read the names and URLs of the master pages.
135 0 : Sequence<OUString> aKeys (xSet->getElementNames());
136 0 : mvMasterPages.clear();
137 0 : mvMasterPages.reserve(aKeys.getLength());
138 0 : for (int i=0; i<aKeys.getLength(); i++)
139 : {
140 : Reference<container::XNameAccess> xSetItem (
141 0 : xSet->getByName(aKeys[i]), UNO_QUERY);
142 0 : if (xSetItem.is())
143 : {
144 0 : Any aURL (xSetItem->getByName(sURLMemberName));
145 0 : Any aName (xSetItem->getByName(sNameMemberName));
146 0 : aURL >>= sURL;
147 0 : aName >>= sName;
148 : SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor(
149 : MasterPageContainer::TEMPLATE,
150 : -1,
151 : sURL,
152 : OUString(),
153 : sName,
154 : false,
155 : ::boost::shared_ptr<PageObjectProvider>(
156 0 : new TemplatePageObjectProvider(sURL)),
157 : ::boost::shared_ptr<PreviewProvider>(
158 0 : 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 0 : if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
166 0 : pDescriptor->mpPreviewProvider = ::boost::shared_ptr<PreviewProvider>(
167 0 : new PagePreviewProvider());
168 0 : MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
169 0 : mvMasterPages.push_back(Descriptor(aToken,sURL,sName));
170 : }
171 0 : }
172 :
173 0 : ResolveList();
174 : }
175 0 : catch (Exception&)
176 : {
177 : // Ignore exception.
178 : }
179 : }
180 :
181 0 : void RecentlyUsedMasterPages::SavePersistentValues()
182 : {
183 : try
184 : {
185 : tools::ConfigurationAccess aConfiguration (
186 : GetPathToImpressConfigurationRoot(),
187 0 : tools::ConfigurationAccess::READ_WRITE);
188 : Reference<container::XNameContainer> xSet (
189 : aConfiguration.GetConfigurationNode(GetPathToSetNode()),
190 0 : UNO_QUERY);
191 0 : if ( ! xSet.is())
192 0 : return;
193 :
194 : // Clear the set.
195 0 : Sequence<OUString> aKeys (xSet->getElementNames());
196 : sal_Int32 i;
197 0 : for (i=0; i<aKeys.getLength(); i++)
198 0 : xSet->removeByName (aKeys[i]);
199 :
200 : // Fill it with the URLs of this object.
201 0 : const OUString sURLMemberName("URL");
202 0 : const OUString sNameMemberName("Name");
203 0 : Any aValue;
204 : Reference<lang::XSingleServiceFactory> xChildFactory (
205 0 : xSet, UNO_QUERY);
206 0 : if ( ! xChildFactory.is())
207 0 : return;
208 0 : MasterPageList::const_iterator iDescriptor;
209 0 : sal_Int32 nIndex(0);
210 0 : for (iDescriptor=mvMasterPages.begin();
211 0 : iDescriptor!=mvMasterPages.end();
212 : ++iDescriptor,++nIndex)
213 : {
214 : // Create new child.
215 0 : OUString sKey ("index_");
216 0 : sKey += OUString::number(nIndex);
217 : Reference<container::XNameReplace> xChild(
218 0 : xChildFactory->createInstance(), UNO_QUERY);
219 0 : if (xChild.is())
220 : {
221 0 : xSet->insertByName (sKey, makeAny(xChild));
222 :
223 0 : aValue <<= OUString(iDescriptor->msURL);
224 0 : xChild->replaceByName (sURLMemberName, aValue);
225 :
226 0 : aValue <<= OUString(iDescriptor->msName);
227 0 : xChild->replaceByName (sNameMemberName, aValue);
228 : }
229 0 : }
230 :
231 : // Write the data back to disk.
232 0 : aConfiguration.CommitChanges();
233 : }
234 0 : catch (Exception&)
235 : {
236 : // Ignore exception.
237 : }
238 : }
239 :
240 0 : void RecentlyUsedMasterPages::AddEventListener (const Link<>& rEventListener)
241 : {
242 0 : if (::std::find (
243 : maListeners.begin(),
244 : maListeners.end(),
245 0 : rEventListener) == maListeners.end())
246 : {
247 0 : maListeners.push_back (rEventListener);
248 : }
249 0 : }
250 :
251 0 : void RecentlyUsedMasterPages::RemoveEventListener (const Link<>& rEventListener)
252 : {
253 : maListeners.erase (
254 : ::std::find (
255 : maListeners.begin(),
256 : maListeners.end(),
257 0 : rEventListener));
258 0 : }
259 :
260 0 : int RecentlyUsedMasterPages::GetMasterPageCount() const
261 : {
262 0 : return mvMasterPages.size();
263 : }
264 :
265 0 : MasterPageContainer::Token RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex) const
266 : {
267 0 : if(nIndex<mvMasterPages.size())
268 0 : return mvMasterPages[nIndex].maToken;
269 : else
270 0 : return MasterPageContainer::NIL_TOKEN;
271 : }
272 :
273 0 : void RecentlyUsedMasterPages::SendEvent()
274 : {
275 0 : ::std::vector<Link<>>::iterator aLink (maListeners.begin());
276 0 : ::std::vector<Link<>>::iterator aEnd (maListeners.end());
277 0 : while (aLink!=aEnd)
278 : {
279 0 : aLink->Call (NULL);
280 0 : ++aLink;
281 : }
282 0 : }
283 :
284 0 : IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
285 : MasterPageObserverEvent*, pEvent)
286 : {
287 0 : switch (pEvent->meType)
288 : {
289 : case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED:
290 : case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS:
291 : AddMasterPage(
292 0 : mpContainer->GetTokenForStyleName(pEvent->mrMasterPageName));
293 0 : break;
294 :
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 0 : SendEvent();
300 0 : break;
301 : }
302 0 : return 0;
303 : }
304 :
305 0 : IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
306 : MasterPageContainerChangeEvent*, pEvent)
307 : {
308 0 : if (pEvent != NULL)
309 0 : switch (pEvent->meEventType)
310 : {
311 : case MasterPageContainerChangeEvent::CHILD_ADDED:
312 : case MasterPageContainerChangeEvent::CHILD_REMOVED:
313 : case MasterPageContainerChangeEvent::INDEX_CHANGED:
314 : case MasterPageContainerChangeEvent::INDEXES_CHANGED:
315 0 : ResolveList();
316 0 : break;
317 :
318 : default:
319 : // Ignored.
320 0 : break;
321 : }
322 0 : return 0;
323 : }
324 :
325 0 : void RecentlyUsedMasterPages::AddMasterPage (
326 : MasterPageContainer::Token aToken,
327 : bool bMakePersistent)
328 : {
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 0 : if (aToken != MasterPageContainer::NIL_TOKEN
333 0 : && !mpContainer->GetURLForToken(aToken).isEmpty())
334 : {
335 :
336 : MasterPageList::iterator aIterator (
337 : ::std::find_if(mvMasterPages.begin(),mvMasterPages.end(),
338 0 : Descriptor::TokenComparator(aToken)));
339 0 : if (aIterator != mvMasterPages.end())
340 : {
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 0 : mvMasterPages.erase (aIterator);
344 : }
345 :
346 : mvMasterPages.insert(mvMasterPages.begin(),
347 : Descriptor(
348 : aToken,
349 : mpContainer->GetURLForToken(aToken),
350 0 : mpContainer->GetStyleNameForToken(aToken)));
351 :
352 : // Shorten list to maximal size.
353 0 : while (mvMasterPages.size() > mnMaxListSize)
354 : {
355 0 : mvMasterPages.pop_back ();
356 : }
357 :
358 0 : if (bMakePersistent)
359 0 : SavePersistentValues ();
360 0 : SendEvent();
361 : }
362 0 : }
363 :
364 0 : void RecentlyUsedMasterPages::ResolveList()
365 : {
366 0 : bool bNotify (false);
367 :
368 0 : MasterPageList::iterator iDescriptor;
369 0 : for (iDescriptor=mvMasterPages.begin(); iDescriptor!=mvMasterPages.end(); ++iDescriptor)
370 : {
371 0 : if (iDescriptor->maToken == MasterPageContainer::NIL_TOKEN)
372 : {
373 0 : MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(iDescriptor->msURL));
374 0 : iDescriptor->maToken = aToken;
375 0 : if (aToken != MasterPageContainer::NIL_TOKEN)
376 0 : bNotify = true;
377 : }
378 : else
379 : {
380 0 : if ( ! mpContainer->HasToken(iDescriptor->maToken))
381 : {
382 0 : iDescriptor->maToken = MasterPageContainer::NIL_TOKEN;
383 0 : bNotify = true;
384 : }
385 : }
386 : }
387 :
388 0 : if (bNotify)
389 0 : SendEvent();
390 0 : }
391 :
392 66 : } } // end of namespace sd::sidebar
393 :
394 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|