1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "RecentlyUsedMasterPages.hxx"
21 #include "MasterPageContainerProviders.hxx"
22 #include <MasterPageObserver.hxx>
23 #include "MasterPagesSelector.hxx"
24 #include "MasterPageDescriptor.hxx"
25 #include <tools/ConfigurationAccess.hxx>
26 #include <drawdoc.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/container/XNameAccess.hpp>
37 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.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>
46 using namespace ::std
;
47 using namespace ::com::sun::star
;
48 using namespace ::com::sun::star::uno
;
52 OUString
GetPathToImpressConfigurationRoot()
54 return OUString("/org.openoffice.Office.Impress/");
56 OUString
GetPathToSetNode()
58 return OUString("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
61 } // end of anonymous namespace
63 namespace sd
{ namespace sidebar
{
65 RecentlyUsedMasterPages
* RecentlyUsedMasterPages::mpInstance
= nullptr;
67 RecentlyUsedMasterPages
& RecentlyUsedMasterPages::Instance()
69 if (mpInstance
== nullptr)
71 ::osl::GetGlobalMutex aMutexFunctor
;
72 ::osl::MutexGuard
aGuard (aMutexFunctor());
73 if (mpInstance
== nullptr)
75 RecentlyUsedMasterPages
* pInstance
= new RecentlyUsedMasterPages();
76 pInstance
->LateInit();
77 SdGlobalResourceContainer::Instance().AddResource (
78 ::std::unique_ptr
<SdGlobalResource
>(pInstance
));
79 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
80 mpInstance
= pInstance
;
84 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
90 static constexpr size_t gnMaxListSize(8);
92 RecentlyUsedMasterPages::RecentlyUsedMasterPages()
95 mpContainer(new MasterPageContainer())
99 RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
101 Link
<MasterPageContainerChangeEvent
&,void> aLink (LINK(this,RecentlyUsedMasterPages
,MasterPageContainerChangeListener
));
102 mpContainer
->RemoveChangeListener(aLink
);
104 MasterPageObserver::Instance().RemoveEventListener(
105 LINK(this,RecentlyUsedMasterPages
,MasterPageChangeListener
));
108 void RecentlyUsedMasterPages::LateInit()
110 Link
<MasterPageContainerChangeEvent
&,void> aLink (LINK(this,RecentlyUsedMasterPages
,MasterPageContainerChangeListener
));
111 mpContainer
->AddChangeListener(aLink
);
113 LoadPersistentValues ();
114 MasterPageObserver::Instance().AddEventListener(
115 LINK(this,RecentlyUsedMasterPages
,MasterPageChangeListener
));
118 void RecentlyUsedMasterPages::LoadPersistentValues()
122 tools::ConfigurationAccess
aConfiguration (
123 GetPathToImpressConfigurationRoot(),
124 tools::ConfigurationAccess::READ_ONLY
);
125 Reference
<container::XNameAccess
> xSet (
126 aConfiguration
.GetConfigurationNode(GetPathToSetNode()),
131 const OUString
sURLMemberName("URL");
132 const OUString
sNameMemberName("Name");
136 // Read the names and URLs of the master pages.
137 Sequence
<OUString
> aKeys (xSet
->getElementNames());
138 mvMasterPages
.clear();
139 mvMasterPages
.reserve(aKeys
.getLength());
140 for (int i
=0; i
<aKeys
.getLength(); i
++)
142 Reference
<container::XNameAccess
> xSetItem (
143 xSet
->getByName(aKeys
[i
]), UNO_QUERY
);
146 Any
aURL (xSetItem
->getByName(sURLMemberName
));
147 Any
aName (xSetItem
->getByName(sNameMemberName
));
150 SharedMasterPageDescriptor
pDescriptor (new MasterPageDescriptor(
151 MasterPageContainer::TEMPLATE
,
157 std::shared_ptr
<PageObjectProvider
>(
158 new TemplatePageObjectProvider(sURL
)),
159 std::shared_ptr
<PreviewProvider
>(
160 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 if (pDescriptor
->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER
)
168 pDescriptor
->mpPreviewProvider
= std::shared_ptr
<PreviewProvider
>(
169 new PagePreviewProvider());
170 MasterPageContainer::Token
aToken (mpContainer
->PutMasterPage(pDescriptor
));
171 mvMasterPages
.emplace_back(aToken
,sURL
,sName
);
183 void RecentlyUsedMasterPages::SavePersistentValues()
187 tools::ConfigurationAccess
aConfiguration (
188 GetPathToImpressConfigurationRoot(),
189 tools::ConfigurationAccess::READ_WRITE
);
190 Reference
<container::XNameContainer
> xSet (
191 aConfiguration
.GetConfigurationNode(GetPathToSetNode()),
197 Sequence
<OUString
> aKeys (xSet
->getElementNames());
199 for (i
=0; i
<aKeys
.getLength(); i
++)
200 xSet
->removeByName (aKeys
[i
]);
202 // Fill it with the URLs of this object.
203 const OUString
sURLMemberName("URL");
204 const OUString
sNameMemberName("Name");
206 Reference
<lang::XSingleServiceFactory
> xChildFactory (
208 if ( ! xChildFactory
.is())
211 for (const auto& rDescriptor
: mvMasterPages
)
214 OUString
sKey ("index_");
215 sKey
+= OUString::number(nIndex
);
216 Reference
<container::XNameReplace
> xChild(
217 xChildFactory
->createInstance(), UNO_QUERY
);
220 xSet
->insertByName (sKey
, makeAny(xChild
));
222 aValue
<<= rDescriptor
.msURL
;
223 xChild
->replaceByName (sURLMemberName
, aValue
);
225 aValue
<<= rDescriptor
.msName
;
226 xChild
->replaceByName (sNameMemberName
, aValue
);
231 // Write the data back to disk.
232 aConfiguration
.CommitChanges();
240 void RecentlyUsedMasterPages::AddEventListener (const Link
<LinkParamNone
*,void>& rEventListener
)
245 rEventListener
) == maListeners
.end())
247 maListeners
.push_back (rEventListener
);
251 void RecentlyUsedMasterPages::RemoveEventListener (const Link
<LinkParamNone
*,void>& rEventListener
)
260 int RecentlyUsedMasterPages::GetMasterPageCount() const
262 return mvMasterPages
.size();
265 MasterPageContainer::Token
RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex
) const
267 if(nIndex
<mvMasterPages
.size())
268 return mvMasterPages
[nIndex
].maToken
;
270 return MasterPageContainer::NIL_TOKEN
;
273 void RecentlyUsedMasterPages::SendEvent()
275 for (auto& aLink
: maListeners
)
281 IMPL_LINK(RecentlyUsedMasterPages
, MasterPageChangeListener
,
282 MasterPageObserverEvent
&, rEvent
, void)
284 switch (rEvent
.meType
)
286 case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
:
287 case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
:
289 mpContainer
->GetTokenForStyleName(rEvent
.mrMasterPageName
));
292 case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
:
293 // Do not change the list of recently master pages (the deleted
294 // page was recently used) but tell the listeners. They may want
295 // to update their lists.
301 IMPL_LINK(RecentlyUsedMasterPages
, MasterPageContainerChangeListener
,
302 MasterPageContainerChangeEvent
&, rEvent
, void)
304 switch (rEvent
.meEventType
)
306 case MasterPageContainerChangeEvent::EventType::CHILD_ADDED
:
307 case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED
:
308 case MasterPageContainerChangeEvent::EventType::INDEX_CHANGED
:
318 void RecentlyUsedMasterPages::AddMasterPage (
319 MasterPageContainer::Token aToken
)
321 // For the page to be inserted the token has to be valid and the page
322 // has to have a valid URL. This excludes master pages that do not come
323 // from template files.
324 if (aToken
== MasterPageContainer::NIL_TOKEN
325 || mpContainer
->GetURLForToken(aToken
).isEmpty())
328 MasterPageList::iterator
aIterator (
329 ::std::find_if(mvMasterPages
.begin(),mvMasterPages
.end(),
330 Descriptor::TokenComparator(aToken
)));
331 if (aIterator
!= mvMasterPages
.end())
333 // When an entry for the given token already exists then remove
334 // it now and insert it later at the head of the list.
335 mvMasterPages
.erase (aIterator
);
338 mvMasterPages
.insert(mvMasterPages
.begin(),
341 mpContainer
->GetURLForToken(aToken
),
342 mpContainer
->GetStyleNameForToken(aToken
)));
344 // Shorten list to maximal size.
345 while (mvMasterPages
.size() > gnMaxListSize
)
347 mvMasterPages
.pop_back ();
350 SavePersistentValues ();
354 void RecentlyUsedMasterPages::ResolveList()
356 bool bNotify (false);
358 for (auto& rDescriptor
: mvMasterPages
)
360 if (rDescriptor
.maToken
== MasterPageContainer::NIL_TOKEN
)
362 MasterPageContainer::Token
aToken (mpContainer
->GetTokenForURL(rDescriptor
.msURL
));
363 rDescriptor
.maToken
= aToken
;
364 if (aToken
!= MasterPageContainer::NIL_TOKEN
)
369 if ( ! mpContainer
->HasToken(rDescriptor
.maToken
))
371 rDescriptor
.maToken
= MasterPageContainer::NIL_TOKEN
;
381 } } // end of namespace sd::sidebar
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */