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