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