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