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