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