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 <MasterPageObserver.hxx>
22 #include "MasterPagesSelector.hxx"
23 #include "MasterPageDescriptor.hxx"
24 #include <tools/ConfigurationAccess.hxx>
25 #include <drawdoc.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/container/XNameAccess.hpp>
36 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <com/sun/star/beans/PropertyState.hpp>
40 #include <unotools/confignode.hxx>
41 #include <osl/doublecheckedlocking.h>
42 #include <osl/getglobalmutex.hxx>
44 using namespace ::std
;
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::uno
;
50 OUString
GetPathToImpressConfigurationRoot()
52 return OUString("/org.openoffice.Office.Impress/");
54 OUString
GetPathToSetNode()
56 return OUString("MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages");
59 } // end of anonymous namespace
61 namespace sd
{ namespace sidebar
{
63 RecentlyUsedMasterPages
* RecentlyUsedMasterPages::mpInstance
= nullptr;
65 RecentlyUsedMasterPages
& RecentlyUsedMasterPages::Instance()
67 if (mpInstance
== nullptr)
69 ::osl::GetGlobalMutex aMutexFunctor
;
70 ::osl::MutexGuard
aGuard (aMutexFunctor());
71 if (mpInstance
== nullptr)
73 RecentlyUsedMasterPages
* pInstance
= new RecentlyUsedMasterPages();
74 pInstance
->LateInit();
75 SdGlobalResourceContainer::Instance().AddResource (
76 ::std::unique_ptr
<SdGlobalResource
>(pInstance
));
77 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
78 mpInstance
= pInstance
;
82 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
88 RecentlyUsedMasterPages::RecentlyUsedMasterPages()
92 mpContainer(new MasterPageContainer())
96 RecentlyUsedMasterPages::~RecentlyUsedMasterPages()
98 Link
<MasterPageContainerChangeEvent
&,void> aLink (LINK(this,RecentlyUsedMasterPages
,MasterPageContainerChangeListener
));
99 mpContainer
->RemoveChangeListener(aLink
);
101 MasterPageObserver::Instance().RemoveEventListener(
102 LINK(this,RecentlyUsedMasterPages
,MasterPageChangeListener
));
105 void RecentlyUsedMasterPages::LateInit()
107 Link
<MasterPageContainerChangeEvent
&,void> aLink (LINK(this,RecentlyUsedMasterPages
,MasterPageContainerChangeListener
));
108 mpContainer
->AddChangeListener(aLink
);
110 LoadPersistentValues ();
111 MasterPageObserver::Instance().AddEventListener(
112 LINK(this,RecentlyUsedMasterPages
,MasterPageChangeListener
));
115 void RecentlyUsedMasterPages::LoadPersistentValues()
119 tools::ConfigurationAccess
aConfiguration (
120 GetPathToImpressConfigurationRoot(),
121 tools::ConfigurationAccess::READ_ONLY
);
122 Reference
<container::XNameAccess
> xSet (
123 aConfiguration
.GetConfigurationNode(GetPathToSetNode()),
128 const OUString
sURLMemberName("URL");
129 const OUString
sNameMemberName("Name");
133 // Read the names and URLs of the master pages.
134 Sequence
<OUString
> aKeys (xSet
->getElementNames());
135 mvMasterPages
.clear();
136 mvMasterPages
.reserve(aKeys
.getLength());
137 for (int i
=0; i
<aKeys
.getLength(); i
++)
139 Reference
<container::XNameAccess
> xSetItem (
140 xSet
->getByName(aKeys
[i
]), UNO_QUERY
);
143 Any
aURL (xSetItem
->getByName(sURLMemberName
));
144 Any
aName (xSetItem
->getByName(sNameMemberName
));
147 SharedMasterPageDescriptor
pDescriptor (new MasterPageDescriptor(
148 MasterPageContainer::TEMPLATE
,
154 std::shared_ptr
<PageObjectProvider
>(
155 new TemplatePageObjectProvider(sURL
)),
156 std::shared_ptr
<PreviewProvider
>(
157 new TemplatePreviewProvider(sURL
))));
158 // For user supplied templates we use a different
159 // preview provider: The preview in the document shows
160 // not only shapes on the master page but also shapes on
161 // the foreground. This is misleading and therefore
162 // these previews are discarded and created directly
163 // from the page objects.
164 if (pDescriptor
->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER
)
165 pDescriptor
->mpPreviewProvider
= std::shared_ptr
<PreviewProvider
>(
166 new PagePreviewProvider());
167 MasterPageContainer::Token
aToken (mpContainer
->PutMasterPage(pDescriptor
));
168 mvMasterPages
.emplace_back(aToken
,sURL
,sName
);
180 void RecentlyUsedMasterPages::SavePersistentValues()
184 tools::ConfigurationAccess
aConfiguration (
185 GetPathToImpressConfigurationRoot(),
186 tools::ConfigurationAccess::READ_WRITE
);
187 Reference
<container::XNameContainer
> xSet (
188 aConfiguration
.GetConfigurationNode(GetPathToSetNode()),
194 Sequence
<OUString
> aKeys (xSet
->getElementNames());
196 for (i
=0; i
<aKeys
.getLength(); i
++)
197 xSet
->removeByName (aKeys
[i
]);
199 // Fill it with the URLs of this object.
200 const OUString
sURLMemberName("URL");
201 const OUString
sNameMemberName("Name");
203 Reference
<lang::XSingleServiceFactory
> xChildFactory (
205 if ( ! xChildFactory
.is())
207 MasterPageList::const_iterator iDescriptor
;
209 for (iDescriptor
=mvMasterPages
.begin();
210 iDescriptor
!=mvMasterPages
.end();
211 ++iDescriptor
,++nIndex
)
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
<<= iDescriptor
->msURL
;
223 xChild
->replaceByName (sURLMemberName
, aValue
);
225 aValue
<<= iDescriptor
->msName
;
226 xChild
->replaceByName (sNameMemberName
, aValue
);
230 // Write the data back to disk.
231 aConfiguration
.CommitChanges();
239 void RecentlyUsedMasterPages::AddEventListener (const Link
<LinkParamNone
*,void>& rEventListener
)
244 rEventListener
) == maListeners
.end())
246 maListeners
.push_back (rEventListener
);
250 void RecentlyUsedMasterPages::RemoveEventListener (const Link
<LinkParamNone
*,void>& rEventListener
)
259 int RecentlyUsedMasterPages::GetMasterPageCount() const
261 return mvMasterPages
.size();
264 MasterPageContainer::Token
RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex
) const
266 if(nIndex
<mvMasterPages
.size())
267 return mvMasterPages
[nIndex
].maToken
;
269 return MasterPageContainer::NIL_TOKEN
;
272 void RecentlyUsedMasterPages::SendEvent()
274 for (auto& aLink
: maListeners
)
280 IMPL_LINK(RecentlyUsedMasterPages
, MasterPageChangeListener
,
281 MasterPageObserverEvent
&, rEvent
, void)
283 switch (rEvent
.meType
)
285 case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED
:
286 case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS
:
288 mpContainer
->GetTokenForStyleName(rEvent
.mrMasterPageName
));
291 case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED
:
292 // Do not change the list of recently master pages (the deleted
293 // page was recently used) but tell the listeners. They may want
294 // to update their lists.
300 IMPL_LINK(RecentlyUsedMasterPages
, MasterPageContainerChangeListener
,
301 MasterPageContainerChangeEvent
&, rEvent
, void)
303 switch (rEvent
.meEventType
)
305 case MasterPageContainerChangeEvent::EventType::CHILD_ADDED
:
306 case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED
:
307 case MasterPageContainerChangeEvent::EventType::INDEX_CHANGED
:
317 void RecentlyUsedMasterPages::AddMasterPage (
318 MasterPageContainer::Token aToken
)
320 // For the page to be inserted the token has to be valid and the page
321 // has to have a valid URL. This excludes master pages that do not come
322 // from template files.
323 if (aToken
!= MasterPageContainer::NIL_TOKEN
324 && !mpContainer
->GetURLForToken(aToken
).isEmpty())
327 MasterPageList::iterator
aIterator (
328 ::std::find_if(mvMasterPages
.begin(),mvMasterPages
.end(),
329 Descriptor::TokenComparator(aToken
)));
330 if (aIterator
!= mvMasterPages
.end())
332 // When an entry for the given token already exists then remove
333 // it now and insert it later at the head of the list.
334 mvMasterPages
.erase (aIterator
);
337 mvMasterPages
.insert(mvMasterPages
.begin(),
340 mpContainer
->GetURLForToken(aToken
),
341 mpContainer
->GetStyleNameForToken(aToken
)));
343 // Shorten list to maximal size.
344 while (mvMasterPages
.size() > mnMaxListSize
)
346 mvMasterPages
.pop_back ();
349 SavePersistentValues ();
354 void RecentlyUsedMasterPages::ResolveList()
356 bool bNotify (false);
358 MasterPageList::iterator iDescriptor
;
359 for (iDescriptor
=mvMasterPages
.begin(); iDescriptor
!=mvMasterPages
.end(); ++iDescriptor
)
361 if (iDescriptor
->maToken
== MasterPageContainer::NIL_TOKEN
)
363 MasterPageContainer::Token
aToken (mpContainer
->GetTokenForURL(iDescriptor
->msURL
));
364 iDescriptor
->maToken
= aToken
;
365 if (aToken
!= MasterPageContainer::NIL_TOKEN
)
370 if ( ! mpContainer
->HasToken(iDescriptor
->maToken
))
372 iDescriptor
->maToken
= MasterPageContainer::NIL_TOKEN
;
382 } } // end of namespace sd::sidebar
384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */