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 <unotools/confignode.hxx>
21 #include <unotools/configpaths.hxx>
22 #include <comphelper/diagnose_ex.hxx>
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
25 #include <com/sun/star/configuration/theDefaultProvider.hpp>
26 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/util/XChangesBatch.hpp>
29 #include <com/sun/star/util/XStringEscape.hpp>
30 #include <com/sun/star/lang/XServiceInfo.hpp>
31 #include <com/sun/star/container/XNamed.hpp>
32 #include <com/sun/star/container/XNameContainer.hpp>
33 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
34 #include <comphelper/namedvaluecollection.hxx>
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::lang
;
41 using namespace ::com::sun::star::util
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::configuration
;
45 //= OConfigurationNode
47 OConfigurationNode::OConfigurationNode(const Reference
< XInterface
>& _rxNode
)
48 :m_bEscapeNames(false)
50 OSL_ENSURE(_rxNode
.is(), "OConfigurationNode::OConfigurationNode: invalid node interface!");
53 // collect all interfaces necessary
54 m_xHierarchyAccess
.set(_rxNode
, UNO_QUERY
);
55 m_xDirectAccess
.set(_rxNode
, UNO_QUERY
);
57 // reset _all_ interfaces if _one_ of them is not supported
58 if (!m_xHierarchyAccess
.is() || !m_xDirectAccess
.is())
60 m_xHierarchyAccess
= nullptr;
61 m_xDirectAccess
= nullptr;
64 // now for the non-critical interfaces
65 m_xReplaceAccess
.set(_rxNode
, UNO_QUERY
);
66 m_xContainerAccess
.set(_rxNode
, UNO_QUERY
);
69 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
70 if (xConfigNodeComp
.is())
71 startComponentListening(xConfigNodeComp
);
74 m_bEscapeNames
= isSetNode() && Reference
< XStringEscape
>::query(m_xDirectAccess
).is();
77 OConfigurationNode::OConfigurationNode(const OConfigurationNode
& _rSource
)
78 : OEventListenerAdapter()
79 , m_xHierarchyAccess(_rSource
.m_xHierarchyAccess
)
80 , m_xDirectAccess(_rSource
.m_xDirectAccess
)
81 , m_xReplaceAccess(_rSource
.m_xReplaceAccess
)
82 , m_xContainerAccess(_rSource
.m_xContainerAccess
)
83 , m_bEscapeNames(_rSource
.m_bEscapeNames
)
85 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
86 if (xConfigNodeComp
.is())
87 startComponentListening(xConfigNodeComp
);
90 OConfigurationNode::OConfigurationNode(OConfigurationNode
&& _rSource
)
91 : OEventListenerAdapter()
92 , m_xHierarchyAccess(std::move(_rSource
.m_xHierarchyAccess
))
93 , m_xDirectAccess(std::move(_rSource
.m_xDirectAccess
))
94 , m_xReplaceAccess(std::move(_rSource
.m_xReplaceAccess
))
95 , m_xContainerAccess(std::move(_rSource
.m_xContainerAccess
))
96 , m_bEscapeNames(std::move(_rSource
.m_bEscapeNames
))
98 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
99 if (xConfigNodeComp
.is())
100 startComponentListening(xConfigNodeComp
);
103 OConfigurationNode
& OConfigurationNode::operator=(const OConfigurationNode
& _rSource
)
105 stopAllComponentListening();
107 m_xHierarchyAccess
= _rSource
.m_xHierarchyAccess
;
108 m_xDirectAccess
= _rSource
.m_xDirectAccess
;
109 m_xContainerAccess
= _rSource
.m_xContainerAccess
;
110 m_xReplaceAccess
= _rSource
.m_xReplaceAccess
;
111 m_bEscapeNames
= _rSource
.m_bEscapeNames
;
113 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
114 if (xConfigNodeComp
.is())
115 startComponentListening(xConfigNodeComp
);
120 OConfigurationNode
& OConfigurationNode::operator=(OConfigurationNode
&& _rSource
)
122 stopAllComponentListening();
124 m_xHierarchyAccess
= std::move(_rSource
.m_xHierarchyAccess
);
125 m_xDirectAccess
= std::move(_rSource
.m_xDirectAccess
);
126 m_xContainerAccess
= std::move(_rSource
.m_xContainerAccess
);
127 m_xReplaceAccess
= std::move(_rSource
.m_xReplaceAccess
);
128 m_bEscapeNames
= std::move(_rSource
.m_bEscapeNames
);
130 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
131 if (xConfigNodeComp
.is())
132 startComponentListening(xConfigNodeComp
);
137 void OConfigurationNode::_disposing( const EventObject
& _rSource
)
139 Reference
< XComponent
> xDisposingSource(_rSource
.Source
, UNO_QUERY
);
140 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
141 if (xDisposingSource
.get() == xConfigNodeComp
.get())
145 OUString
OConfigurationNode::getLocalName() const
150 Reference
< XNamed
> xNamed( m_xDirectAccess
, UNO_QUERY_THROW
);
151 sLocalName
= xNamed
->getName();
153 catch( const Exception
& )
155 DBG_UNHANDLED_EXCEPTION("unotools");
160 OUString
OConfigurationNode::normalizeName(const OUString
& _rName
, NAMEORIGIN _eOrigin
) const
162 OUString
sName(_rName
);
165 Reference
< XStringEscape
> xEscaper(m_xDirectAccess
, UNO_QUERY
);
166 if (xEscaper
.is() && !sName
.isEmpty())
170 if (NO_CALLER
== _eOrigin
)
171 sName
= xEscaper
->escapeString(sName
);
173 sName
= xEscaper
->unescapeString(sName
);
177 DBG_UNHANDLED_EXCEPTION("unotools");
184 Sequence
< OUString
> OConfigurationNode::getNodeNames() const noexcept
186 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::getNodeNames: object is invalid!");
187 Sequence
< OUString
> aReturn
;
188 if (m_xDirectAccess
.is())
192 aReturn
= m_xDirectAccess
->getElementNames();
193 // normalize the names
194 std::transform(std::cbegin(aReturn
), std::cend(aReturn
), aReturn
.getArray(),
195 [this](const OUString
& rName
) -> OUString
{ return normalizeName(rName
, NO_CONFIGURATION
); });
199 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::getNodeNames");
206 bool OConfigurationNode::removeNode(const OUString
& _rName
) const noexcept
208 OSL_ENSURE(m_xContainerAccess
.is(), "OConfigurationNode::removeNode: object is invalid!");
209 if (m_xContainerAccess
.is())
213 OUString sName
= normalizeName(_rName
, NO_CALLER
);
214 m_xContainerAccess
->removeByName(sName
);
217 catch (NoSuchElementException
&)
219 SAL_WARN( "unotools", "OConfigurationNode::removeNode: there is no element named: " << _rName
);
223 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::removeNode");
229 OConfigurationNode
OConfigurationNode::insertNode(const OUString
& _rName
,const Reference
< XInterface
>& _xNode
) const noexcept
235 OUString sName
= normalizeName(_rName
, NO_CALLER
);
236 m_xContainerAccess
->insertByName(sName
, Any(_xNode
));
237 // if we're here, all was ok ...
238 return OConfigurationNode( _xNode
);
240 catch(const Exception
&)
242 DBG_UNHANDLED_EXCEPTION("unotools");
245 // dispose the child if it has already been created, but could not be inserted
246 Reference
< XComponent
> xChildComp(_xNode
, UNO_QUERY
);
248 try { xChildComp
->dispose(); } catch(Exception
&) { }
251 return OConfigurationNode();
254 OConfigurationNode
OConfigurationNode::createNode(const OUString
& _rName
) const noexcept
256 Reference
< XSingleServiceFactory
> xChildFactory(m_xContainerAccess
, UNO_QUERY
);
257 OSL_ENSURE(xChildFactory
.is(), "OConfigurationNode::createNode: object is invalid or read-only!");
259 if (xChildFactory
.is()) // implies m_xContainerAccess.is()
261 Reference
< XInterface
> xNewChild
;
264 xNewChild
= xChildFactory
->createInstance();
266 catch(const Exception
&)
268 DBG_UNHANDLED_EXCEPTION("unotools");
270 return insertNode(_rName
,xNewChild
);
273 return OConfigurationNode();
276 OConfigurationNode
OConfigurationNode::openNode(const OUString
& _rPath
) const noexcept
278 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::openNode: object is invalid!");
279 OSL_ENSURE(m_xHierarchyAccess
.is(), "OConfigurationNode::openNode: object is invalid!");
282 OUString sNormalized
= normalizeName(_rPath
, NO_CALLER
);
284 Reference
< XInterface
> xNode
;
285 if (m_xDirectAccess
.is() && m_xDirectAccess
->hasByName(sNormalized
))
288 m_xDirectAccess
->getByName(sNormalized
), css::uno::UNO_QUERY
);
290 OSL_FAIL("OConfigurationNode::openNode: could not open the node!");
292 else if (m_xHierarchyAccess
.is())
295 m_xHierarchyAccess
->getByHierarchicalName(_rPath
),
296 css::uno::UNO_QUERY
);
298 OSL_FAIL("OConfigurationNode::openNode: could not open the node!");
301 return OConfigurationNode( xNode
);
303 catch(const NoSuchElementException
&)
305 SAL_WARN( "unotools", "OConfigurationNode::openNode: there is no element named " << _rPath
);
309 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::openNode: caught an exception while retrieving the node!");
311 return OConfigurationNode();
314 bool OConfigurationNode::isSetNode() const
317 Reference
< XServiceInfo
> xSI(m_xHierarchyAccess
, UNO_QUERY
);
320 try { bIsSet
= xSI
->supportsService(u
"com.sun.star.configuration.SetAccess"_ustr
); }
321 catch(Exception
&) { }
326 bool OConfigurationNode::hasByHierarchicalName( const OUString
& _rName
) const noexcept
328 OSL_ENSURE( m_xHierarchyAccess
.is(), "OConfigurationNode::hasByHierarchicalName: no hierarchy access!" );
331 if ( m_xHierarchyAccess
.is() )
333 OUString sName
= normalizeName( _rName
, NO_CALLER
);
334 return m_xHierarchyAccess
->hasByHierarchicalName( sName
);
343 bool OConfigurationNode::hasByName(const OUString
& _rName
) const noexcept
345 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::hasByName: object is invalid!");
348 OUString sName
= normalizeName(_rName
, NO_CALLER
);
349 if (m_xDirectAccess
.is())
350 return m_xDirectAccess
->hasByName(sName
);
358 bool OConfigurationNode::setNodeValue(const OUString
& _rPath
, const Any
& _rValue
) const noexcept
360 bool bResult
= false;
362 OSL_ENSURE(m_xReplaceAccess
.is(), "OConfigurationNode::setNodeValue: object is invalid!");
363 if (m_xReplaceAccess
.is())
367 // check if _rPath is a level-1 path
368 OUString sNormalizedName
= normalizeName(_rPath
, NO_CALLER
);
369 if (m_xReplaceAccess
->hasByName(sNormalizedName
))
371 m_xReplaceAccess
->replaceByName(sNormalizedName
, _rValue
);
375 // check if the name refers to an indirect descendant
376 else if (m_xHierarchyAccess
.is() && m_xHierarchyAccess
->hasByHierarchicalName(_rPath
))
378 OSL_ASSERT(!_rPath
.isEmpty());
380 OUString sParentPath
, sLocalName
;
382 if ( splitLastFromConfigurationPath(_rPath
, sParentPath
, sLocalName
) )
384 OConfigurationNode aParentAccess
= openNode(sParentPath
);
385 if (aParentAccess
.isValid())
386 bResult
= aParentAccess
.setNodeValue(sLocalName
, _rValue
);
390 m_xReplaceAccess
->replaceByName(sLocalName
, _rValue
);
398 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::setNodeValue: could not replace the value");
405 Any
OConfigurationNode::getNodeValue(const OUString
& _rPath
) const noexcept
407 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::hasByName: object is invalid!");
408 OSL_ENSURE(m_xHierarchyAccess
.is(), "OConfigurationNode::hasByName: object is invalid!");
412 OUString sNormalizedPath
= normalizeName(_rPath
, NO_CALLER
);
413 if (m_xDirectAccess
.is() && m_xDirectAccess
->hasByName(sNormalizedPath
) )
415 aReturn
= m_xDirectAccess
->getByName(sNormalizedPath
);
417 else if (m_xHierarchyAccess
.is())
419 aReturn
= m_xHierarchyAccess
->getByHierarchicalName(_rPath
);
422 catch(const NoSuchElementException
&)
424 DBG_UNHANDLED_EXCEPTION("unotools");
429 void OConfigurationNode::clear() noexcept
431 m_xHierarchyAccess
.clear();
432 m_xDirectAccess
.clear();
433 m_xReplaceAccess
.clear();
434 m_xContainerAccess
.clear();
442 Reference
< XMultiServiceFactory
> lcl_getConfigProvider( const Reference
<XComponentContext
> & i_rContext
)
446 Reference
< XMultiServiceFactory
> xProvider
= theDefaultProvider::get( i_rContext
);
449 catch ( const Exception
& )
451 DBG_UNHANDLED_EXCEPTION("unotools");
456 Reference
< XInterface
> lcl_createConfigurationRoot( const Reference
< XMultiServiceFactory
>& i_rxConfigProvider
,
457 const OUString
& i_rNodePath
, const bool i_bUpdatable
, const sal_Int32 i_nDepth
)
459 ENSURE_OR_RETURN( i_rxConfigProvider
.is(), "invalid provider", nullptr );
462 ::comphelper::NamedValueCollection aArgs
;
463 aArgs
.put( u
"nodepath"_ustr
, i_rNodePath
);
464 aArgs
.put( u
"depth"_ustr
, i_nDepth
);
466 OUString
sAccessService( i_bUpdatable
?
467 u
"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr
:
468 u
"com.sun.star.configuration.ConfigurationAccess"_ustr
);
470 Reference
< XInterface
> xRoot(
471 i_rxConfigProvider
->createInstanceWithArguments( sAccessService
, aArgs
.getWrappedPropertyValues() ),
476 catch ( const Exception
& )
478 DBG_UNHANDLED_EXCEPTION("unotools");
484 OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference
< XInterface
>& _rxRootNode
)
485 :OConfigurationNode( _rxRootNode
)
486 ,m_xCommitter( _rxRootNode
, UNO_QUERY
)
490 OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference
<XComponentContext
> & i_rContext
, const OUString
& i_rNodePath
, const bool i_bUpdatable
)
491 :OConfigurationNode( lcl_createConfigurationRoot( lcl_getConfigProvider( i_rContext
),
492 i_rNodePath
, i_bUpdatable
, -1 ) )
497 m_xCommitter
.set( getUNONode(), UNO_QUERY
);
498 OSL_ENSURE( m_xCommitter
.is(), "OConfigurationTreeRoot::OConfigurationTreeRoot: could not create an updatable node!" );
502 void OConfigurationTreeRoot::clear() noexcept
504 OConfigurationNode::clear();
505 m_xCommitter
.clear();
508 bool OConfigurationTreeRoot::commit() const noexcept
510 OSL_ENSURE(isValid(), "OConfigurationTreeRoot::commit: object is invalid!");
513 OSL_ENSURE(m_xCommitter
.is(), "OConfigurationTreeRoot::commit: I'm a readonly node!");
514 if (!m_xCommitter
.is())
519 m_xCommitter
->commitChanges();
522 catch(const Exception
&)
524 DBG_UNHANDLED_EXCEPTION("unotools");
529 OConfigurationTreeRoot
OConfigurationTreeRoot::createWithProvider(const Reference
< XMultiServiceFactory
>& _rxConfProvider
, const OUString
& _rPath
, sal_Int32 _nDepth
, CREATION_MODE _eMode
)
531 Reference
< XInterface
> xRoot( lcl_createConfigurationRoot(
532 _rxConfProvider
, _rPath
, _eMode
!= CM_READONLY
, _nDepth
) );
534 return OConfigurationTreeRoot( xRoot
);
535 return OConfigurationTreeRoot();
538 OConfigurationTreeRoot
OConfigurationTreeRoot::createWithComponentContext( const Reference
< XComponentContext
>& _rxContext
, const OUString
& _rPath
, sal_Int32 _nDepth
, CREATION_MODE _eMode
)
540 return createWithProvider( lcl_getConfigProvider( _rxContext
), _rPath
, _nDepth
, _eMode
);
543 OConfigurationTreeRoot
OConfigurationTreeRoot::tryCreateWithComponentContext( const Reference
< XComponentContext
>& rxContext
,
544 const OUString
& _rPath
, sal_Int32 _nDepth
, CREATION_MODE _eMode
)
546 OSL_ENSURE( rxContext
.is(), "OConfigurationTreeRoot::tryCreateWithComponentContext: invalid XComponentContext!" );
549 Reference
< XMultiServiceFactory
> xConfigFactory
= theDefaultProvider::get( rxContext
);
550 return createWithProvider( xConfigFactory
, _rPath
, _nDepth
, _eMode
);
552 catch(const Exception
&)
554 // silence this, 'cause the contract of this method states "no assertions"
556 return OConfigurationTreeRoot();
561 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */