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 :
50 : namespace {
51 :
52 0 : static const OUString& GetPathToImpressConfigurationRoot (void)
53 : {
54 0 : static const OUString sPathToImpressConfigurationRoot ("/org.openoffice.Office.Impress/");
55 0 : return sPathToImpressConfigurationRoot;
56 : }
57 0 : static const OUString& GetPathToSetNode (void)
58 : {
59 0 : static const OUString sPathToSetNode("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
60 0 : return sPathToSetNode;
61 : }
62 :
63 :
64 0 : class Descriptor
65 : {
66 : public:
67 : OUString msURL;
68 : OUString msName;
69 : ::sd::sidebar::MasterPageContainer::Token maToken;
70 : Descriptor (const OUString& rsURL, const OUString& rsName)
71 : : msURL(rsURL),
72 : msName(rsName),
73 : maToken(::sd::sidebar::MasterPageContainer::NIL_TOKEN)
74 : {}
75 0 : Descriptor (::sd::sidebar::MasterPageContainer::Token aToken,
76 : const OUString& rsURL, const OUString& rsName)
77 : : msURL(rsURL),
78 : msName(rsName),
79 0 : maToken(aToken)
80 0 : {}
81 : class TokenComparator
82 : { public:
83 0 : TokenComparator(::sd::sidebar::MasterPageContainer::Token aToken)
84 0 : : maToken(aToken) {}
85 0 : bool operator () (const Descriptor& rDescriptor)
86 0 : { return maToken==rDescriptor.maToken; }
87 : private: ::sd::sidebar::MasterPageContainer::Token maToken;
88 : };
89 : };
90 :
91 : } // end of anonymous namespace
92 :
93 :
94 :
95 :
96 : namespace sd { namespace sidebar {
97 :
98 0 : class RecentlyUsedMasterPages::MasterPageList : public ::std::vector<Descriptor>
99 : {
100 : public:
101 0 : MasterPageList (void) {}
102 : };
103 :
104 :
105 : RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = NULL;
106 :
107 :
108 0 : RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance (void)
109 : {
110 0 : if (mpInstance == NULL)
111 : {
112 : ::osl::GetGlobalMutex aMutexFunctor;
113 0 : ::osl::MutexGuard aGuard (aMutexFunctor());
114 0 : if (mpInstance == NULL)
115 : {
116 0 : RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages();
117 0 : pInstance->LateInit();
118 0 : SdGlobalResourceContainer::Instance().AddResource (
119 0 : ::std::auto_ptr<SdGlobalResource>(pInstance));
120 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
121 0 : mpInstance = pInstance;
122 0 : }
123 : }
124 : else {
125 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
126 : }
127 :
128 0 : return *mpInstance;
129 : }
130 :
131 :
132 :
133 :
134 0 : RecentlyUsedMasterPages::RecentlyUsedMasterPages (void)
135 : : maListeners(),
136 0 : mpMasterPages(new MasterPageList()),
137 : mnMaxListSize(8),
138 0 : mpContainer(new MasterPageContainer())
139 : {
140 0 : }
141 :
142 :
143 :
144 :
145 0 : RecentlyUsedMasterPages::~RecentlyUsedMasterPages (void)
146 : {
147 0 : Link aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
148 0 : mpContainer->RemoveChangeListener(aLink);
149 :
150 0 : MasterPageObserver::Instance().RemoveEventListener(
151 0 : LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
152 0 : }
153 :
154 :
155 :
156 :
157 0 : void RecentlyUsedMasterPages::LateInit (void)
158 : {
159 0 : Link aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener));
160 0 : mpContainer->AddChangeListener(aLink);
161 :
162 0 : LoadPersistentValues ();
163 0 : MasterPageObserver::Instance().AddEventListener(
164 0 : LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener));
165 0 : }
166 :
167 :
168 :
169 :
170 0 : void RecentlyUsedMasterPages::LoadPersistentValues (void)
171 : {
172 : try
173 : {
174 : tools::ConfigurationAccess aConfiguration (
175 0 : GetPathToImpressConfigurationRoot(),
176 0 : tools::ConfigurationAccess::READ_ONLY);
177 : Reference<container::XNameAccess> xSet (
178 0 : aConfiguration.GetConfigurationNode(GetPathToSetNode()),
179 0 : UNO_QUERY);
180 0 : if ( ! xSet.is())
181 0 : return;
182 :
183 0 : const OUString sURLMemberName("URL");
184 0 : const OUString sNameMemberName("Name");
185 0 : OUString sURL;
186 0 : OUString sName;
187 :
188 : // Read the names and URLs of the master pages.
189 0 : Sequence<OUString> aKeys (xSet->getElementNames());
190 0 : mpMasterPages->clear();
191 0 : mpMasterPages->reserve(aKeys.getLength());
192 0 : for (int i=0; i<aKeys.getLength(); i++)
193 : {
194 : Reference<container::XNameAccess> xSetItem (
195 0 : xSet->getByName(aKeys[i]), UNO_QUERY);
196 0 : if (xSetItem.is())
197 : {
198 0 : Any aURL (xSetItem->getByName(sURLMemberName));
199 0 : Any aName (xSetItem->getByName(sNameMemberName));
200 0 : aURL >>= sURL;
201 0 : aName >>= sName;
202 : SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor(
203 : MasterPageContainer::TEMPLATE,
204 : -1,
205 : sURL,
206 : String(),
207 : sName,
208 : false,
209 : ::boost::shared_ptr<PageObjectProvider>(
210 0 : new TemplatePageObjectProvider(sURL)),
211 : ::boost::shared_ptr<PreviewProvider>(
212 0 : new TemplatePreviewProvider(sURL))));
213 : // For user supplied templates we use a different
214 : // preview provider: The preview in the document shows
215 : // not only shapes on the master page but also shapes on
216 : // the foreground. This is misleading and therefore
217 : // these previews are discarded and created directly
218 : // from the page objects.
219 0 : if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER)
220 0 : pDescriptor->mpPreviewProvider = ::boost::shared_ptr<PreviewProvider>(
221 0 : new PagePreviewProvider());
222 0 : MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor));
223 0 : mpMasterPages->push_back(Descriptor(aToken,sURL,sName));
224 : }
225 0 : }
226 :
227 0 : ResolveList();
228 : }
229 0 : catch (Exception&)
230 : {
231 : // Ignore exception.
232 : }
233 : }
234 :
235 :
236 :
237 :
238 0 : void RecentlyUsedMasterPages::SavePersistentValues (void)
239 : {
240 : try
241 : {
242 : tools::ConfigurationAccess aConfiguration (
243 0 : GetPathToImpressConfigurationRoot(),
244 0 : tools::ConfigurationAccess::READ_WRITE);
245 : Reference<container::XNameContainer> xSet (
246 0 : aConfiguration.GetConfigurationNode(GetPathToSetNode()),
247 0 : UNO_QUERY);
248 0 : if ( ! xSet.is())
249 0 : return;
250 :
251 : // Clear the set.
252 0 : Sequence<OUString> aKeys (xSet->getElementNames());
253 : sal_Int32 i;
254 0 : for (i=0; i<aKeys.getLength(); i++)
255 0 : xSet->removeByName (aKeys[i]);
256 :
257 : // Fill it with the URLs of this object.
258 0 : const OUString sURLMemberName("URL");
259 0 : const OUString sNameMemberName("Name");
260 0 : Any aValue;
261 : Reference<lang::XSingleServiceFactory> xChildFactory (
262 0 : xSet, UNO_QUERY);
263 0 : if ( ! xChildFactory.is())
264 0 : return;
265 0 : MasterPageList::const_iterator iDescriptor;
266 0 : sal_Int32 nIndex(0);
267 0 : for (iDescriptor=mpMasterPages->begin();
268 0 : iDescriptor!=mpMasterPages->end();
269 : ++iDescriptor,++nIndex)
270 : {
271 : // Create new child.
272 0 : OUString sKey ("index_");
273 0 : sKey += OUString::valueOf(nIndex);
274 : Reference<container::XNameReplace> xChild(
275 0 : xChildFactory->createInstance(), UNO_QUERY);
276 0 : if (xChild.is())
277 : {
278 0 : xSet->insertByName (sKey, makeAny(xChild));
279 :
280 0 : aValue <<= OUString(iDescriptor->msURL);
281 0 : xChild->replaceByName (sURLMemberName, aValue);
282 :
283 0 : aValue <<= OUString(iDescriptor->msName);
284 0 : xChild->replaceByName (sNameMemberName, aValue);
285 : }
286 0 : }
287 :
288 : // Write the data back to disk.
289 0 : aConfiguration.CommitChanges();
290 : }
291 0 : catch (Exception&)
292 : {
293 : // Ignore exception.
294 : }
295 : }
296 :
297 :
298 :
299 :
300 0 : void RecentlyUsedMasterPages::AddEventListener (const Link& rEventListener)
301 : {
302 0 : if (::std::find (
303 : maListeners.begin(),
304 : maListeners.end(),
305 0 : rEventListener) == maListeners.end())
306 : {
307 0 : maListeners.push_back (rEventListener);
308 : }
309 0 : }
310 :
311 :
312 :
313 :
314 0 : void RecentlyUsedMasterPages::RemoveEventListener (const Link& rEventListener)
315 : {
316 : maListeners.erase (
317 : ::std::find (
318 : maListeners.begin(),
319 : maListeners.end(),
320 0 : rEventListener));
321 0 : }
322 :
323 :
324 :
325 :
326 0 : int RecentlyUsedMasterPages::GetMasterPageCount (void) const
327 : {
328 0 : return mpMasterPages->size();
329 : }
330 :
331 :
332 :
333 :
334 0 : MasterPageContainer::Token RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex) const
335 : {
336 0 : if(nIndex<mpMasterPages->size())
337 0 : return (*mpMasterPages)[nIndex].maToken;
338 : else
339 0 : return MasterPageContainer::NIL_TOKEN;
340 : }
341 :
342 :
343 :
344 :
345 0 : void RecentlyUsedMasterPages::SendEvent (void)
346 : {
347 0 : ::std::vector<Link>::iterator aLink (maListeners.begin());
348 0 : ::std::vector<Link>::iterator aEnd (maListeners.end());
349 0 : while (aLink!=aEnd)
350 : {
351 0 : aLink->Call (NULL);
352 0 : ++aLink;
353 : }
354 0 : }
355 :
356 :
357 :
358 :
359 0 : IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener,
360 : MasterPageObserverEvent*, pEvent)
361 : {
362 0 : switch (pEvent->meType)
363 : {
364 : case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED:
365 : case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS:
366 : AddMasterPage(
367 0 : mpContainer->GetTokenForStyleName(pEvent->mrMasterPageName));
368 0 : break;
369 :
370 : case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED:
371 : // Do not change the list of recently master pages (the deleted
372 : // page was recently used) but tell the listeners. They may want
373 : // to update their lists.
374 0 : SendEvent();
375 0 : break;
376 : }
377 0 : return 0;
378 : }
379 :
380 :
381 :
382 :
383 0 : IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener,
384 : MasterPageContainerChangeEvent*, pEvent)
385 : {
386 0 : if (pEvent != NULL)
387 0 : switch (pEvent->meEventType)
388 : {
389 : case MasterPageContainerChangeEvent::CHILD_ADDED:
390 : case MasterPageContainerChangeEvent::CHILD_REMOVED:
391 : case MasterPageContainerChangeEvent::INDEX_CHANGED:
392 : case MasterPageContainerChangeEvent::INDEXES_CHANGED:
393 0 : ResolveList();
394 0 : break;
395 :
396 : default:
397 : // Ignored.
398 0 : break;
399 : }
400 0 : return 0;
401 : }
402 :
403 :
404 :
405 :
406 0 : void RecentlyUsedMasterPages::AddMasterPage (
407 : MasterPageContainer::Token aToken,
408 : bool bMakePersistent)
409 : {
410 : // For the page to be inserted the token has to be valid and the page
411 : // has to have a valid URL. This excludes master pages that do not come
412 : // from template files.
413 0 : if (aToken != MasterPageContainer::NIL_TOKEN
414 0 : && mpContainer->GetURLForToken(aToken).Len()>0)
415 : {
416 :
417 : MasterPageList::iterator aIterator (
418 0 : ::std::find_if(mpMasterPages->begin(),mpMasterPages->end(),
419 0 : Descriptor::TokenComparator(aToken)));
420 0 : if (aIterator != mpMasterPages->end())
421 : {
422 : // When an entry for the given token already exists then remove
423 : // it now and insert it later at the head of the list.
424 0 : mpMasterPages->erase (aIterator);
425 : }
426 :
427 0 : mpMasterPages->insert(mpMasterPages->begin(),
428 : Descriptor(
429 : aToken,
430 : mpContainer->GetURLForToken(aToken),
431 0 : mpContainer->GetStyleNameForToken(aToken)));
432 :
433 : // Shorten list to maximal size.
434 0 : while (mpMasterPages->size() > mnMaxListSize)
435 : {
436 0 : mpMasterPages->pop_back ();
437 : }
438 :
439 0 : if (bMakePersistent)
440 0 : SavePersistentValues ();
441 0 : SendEvent();
442 : }
443 0 : }
444 :
445 :
446 :
447 :
448 0 : void RecentlyUsedMasterPages::ResolveList (void)
449 : {
450 0 : bool bNotify (false);
451 :
452 0 : MasterPageList::iterator iDescriptor;
453 0 : for (iDescriptor=mpMasterPages->begin(); iDescriptor!=mpMasterPages->end(); ++iDescriptor)
454 : {
455 0 : if (iDescriptor->maToken == MasterPageContainer::NIL_TOKEN)
456 : {
457 0 : MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(iDescriptor->msURL));
458 0 : iDescriptor->maToken = aToken;
459 0 : if (aToken != MasterPageContainer::NIL_TOKEN)
460 0 : bNotify = true;
461 : }
462 : else
463 : {
464 0 : if ( ! mpContainer->HasToken(iDescriptor->maToken))
465 : {
466 0 : iDescriptor->maToken = MasterPageContainer::NIL_TOKEN;
467 0 : bNotify = true;
468 : }
469 : }
470 : }
471 :
472 0 : if (bNotify)
473 0 : SendEvent();
474 0 : }
475 :
476 :
477 33 : } } // end of namespace sd::sidebar
478 :
479 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|