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::beans
;
43 using namespace ::com::sun::star::container
;
44 using namespace ::com::sun::star::configuration
;
46 //= OConfigurationNode
48 OConfigurationNode::OConfigurationNode(const Reference
< XInterface
>& _rxNode
)
49 :m_bEscapeNames(false)
51 OSL_ENSURE(_rxNode
.is(), "OConfigurationNode::OConfigurationNode: invalid node interface!");
54 // collect all interfaces necessary
55 m_xHierarchyAccess
.set(_rxNode
, UNO_QUERY
);
56 m_xDirectAccess
.set(_rxNode
, UNO_QUERY
);
58 // reset _all_ interfaces if _one_ of them is not supported
59 if (!m_xHierarchyAccess
.is() || !m_xDirectAccess
.is())
61 m_xHierarchyAccess
= nullptr;
62 m_xDirectAccess
= nullptr;
65 // now for the non-critical interfaces
66 m_xReplaceAccess
.set(_rxNode
, UNO_QUERY
);
67 m_xContainerAccess
.set(_rxNode
, UNO_QUERY
);
70 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
71 if (xConfigNodeComp
.is())
72 startComponentListening(xConfigNodeComp
);
75 m_bEscapeNames
= isSetNode() && Reference
< XStringEscape
>::query(m_xDirectAccess
).is();
78 OConfigurationNode::OConfigurationNode(const OConfigurationNode
& _rSource
)
79 : OEventListenerAdapter()
80 , m_xHierarchyAccess(_rSource
.m_xHierarchyAccess
)
81 , m_xDirectAccess(_rSource
.m_xDirectAccess
)
82 , m_xReplaceAccess(_rSource
.m_xReplaceAccess
)
83 , m_xContainerAccess(_rSource
.m_xContainerAccess
)
84 , m_bEscapeNames(_rSource
.m_bEscapeNames
)
86 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
87 if (xConfigNodeComp
.is())
88 startComponentListening(xConfigNodeComp
);
91 OConfigurationNode::OConfigurationNode(OConfigurationNode
&& _rSource
)
92 : OEventListenerAdapter()
93 , m_xHierarchyAccess(std::move(_rSource
.m_xHierarchyAccess
))
94 , m_xDirectAccess(std::move(_rSource
.m_xDirectAccess
))
95 , m_xReplaceAccess(std::move(_rSource
.m_xReplaceAccess
))
96 , m_xContainerAccess(std::move(_rSource
.m_xContainerAccess
))
97 , m_bEscapeNames(std::move(_rSource
.m_bEscapeNames
))
99 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
100 if (xConfigNodeComp
.is())
101 startComponentListening(xConfigNodeComp
);
104 OConfigurationNode
& OConfigurationNode::operator=(const OConfigurationNode
& _rSource
)
106 stopAllComponentListening();
108 m_xHierarchyAccess
= _rSource
.m_xHierarchyAccess
;
109 m_xDirectAccess
= _rSource
.m_xDirectAccess
;
110 m_xContainerAccess
= _rSource
.m_xContainerAccess
;
111 m_xReplaceAccess
= _rSource
.m_xReplaceAccess
;
112 m_bEscapeNames
= _rSource
.m_bEscapeNames
;
114 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
115 if (xConfigNodeComp
.is())
116 startComponentListening(xConfigNodeComp
);
121 OConfigurationNode
& OConfigurationNode::operator=(OConfigurationNode
&& _rSource
)
123 stopAllComponentListening();
125 m_xHierarchyAccess
= std::move(_rSource
.m_xHierarchyAccess
);
126 m_xDirectAccess
= std::move(_rSource
.m_xDirectAccess
);
127 m_xContainerAccess
= std::move(_rSource
.m_xContainerAccess
);
128 m_xReplaceAccess
= std::move(_rSource
.m_xReplaceAccess
);
129 m_bEscapeNames
= std::move(_rSource
.m_bEscapeNames
);
131 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
132 if (xConfigNodeComp
.is())
133 startComponentListening(xConfigNodeComp
);
138 void OConfigurationNode::_disposing( const EventObject
& _rSource
)
140 Reference
< XComponent
> xDisposingSource(_rSource
.Source
, UNO_QUERY
);
141 Reference
< XComponent
> xConfigNodeComp(m_xDirectAccess
, UNO_QUERY
);
142 if (xDisposingSource
.get() == xConfigNodeComp
.get())
146 OUString
OConfigurationNode::getLocalName() const
151 Reference
< XNamed
> xNamed( m_xDirectAccess
, UNO_QUERY_THROW
);
152 sLocalName
= xNamed
->getName();
154 catch( const Exception
& )
156 DBG_UNHANDLED_EXCEPTION("unotools");
161 OUString
OConfigurationNode::normalizeName(const OUString
& _rName
, NAMEORIGIN _eOrigin
) const
163 OUString
sName(_rName
);
166 Reference
< XStringEscape
> xEscaper(m_xDirectAccess
, UNO_QUERY
);
167 if (xEscaper
.is() && !sName
.isEmpty())
171 if (NO_CALLER
== _eOrigin
)
172 sName
= xEscaper
->escapeString(sName
);
174 sName
= xEscaper
->unescapeString(sName
);
178 DBG_UNHANDLED_EXCEPTION("unotools");
185 Sequence
< OUString
> OConfigurationNode::getNodeNames() const noexcept
187 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::getNodeNames: object is invalid!");
188 Sequence
< OUString
> aReturn
;
189 if (m_xDirectAccess
.is())
193 aReturn
= m_xDirectAccess
->getElementNames();
194 // normalize the names
195 std::transform(std::cbegin(aReturn
), std::cend(aReturn
), aReturn
.getArray(),
196 [this](const OUString
& rName
) -> OUString
{ return normalizeName(rName
, NO_CONFIGURATION
); });
200 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::getNodeNames");
207 bool OConfigurationNode::removeNode(const OUString
& _rName
) const noexcept
209 OSL_ENSURE(m_xContainerAccess
.is(), "OConfigurationNode::removeNode: object is invalid!");
210 if (m_xContainerAccess
.is())
214 OUString sName
= normalizeName(_rName
, NO_CALLER
);
215 m_xContainerAccess
->removeByName(sName
);
218 catch (NoSuchElementException
&)
220 SAL_WARN( "unotools", "OConfigurationNode::removeNode: there is no element named: " << _rName
);
224 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::removeNode");
230 OConfigurationNode
OConfigurationNode::insertNode(const OUString
& _rName
,const Reference
< XInterface
>& _xNode
) const noexcept
236 OUString sName
= normalizeName(_rName
, NO_CALLER
);
237 m_xContainerAccess
->insertByName(sName
, Any(_xNode
));
238 // if we're here, all was ok ...
239 return OConfigurationNode( _xNode
);
241 catch(const Exception
&)
243 DBG_UNHANDLED_EXCEPTION("unotools");
246 // dispose the child if it has already been created, but could not be inserted
247 Reference
< XComponent
> xChildComp(_xNode
, UNO_QUERY
);
249 try { xChildComp
->dispose(); } catch(Exception
&) { }
252 return OConfigurationNode();
255 OConfigurationNode
OConfigurationNode::createNode(const OUString
& _rName
) const noexcept
257 Reference
< XSingleServiceFactory
> xChildFactory(m_xContainerAccess
, UNO_QUERY
);
258 OSL_ENSURE(xChildFactory
.is(), "OConfigurationNode::createNode: object is invalid or read-only!");
260 if (xChildFactory
.is()) // implies m_xContainerAccess.is()
262 Reference
< XInterface
> xNewChild
;
265 xNewChild
= xChildFactory
->createInstance();
267 catch(const Exception
&)
269 DBG_UNHANDLED_EXCEPTION("unotools");
271 return insertNode(_rName
,xNewChild
);
274 return OConfigurationNode();
277 OConfigurationNode
OConfigurationNode::openNode(const OUString
& _rPath
) const noexcept
279 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::openNode: object is invalid!");
280 OSL_ENSURE(m_xHierarchyAccess
.is(), "OConfigurationNode::openNode: object is invalid!");
283 OUString sNormalized
= normalizeName(_rPath
, NO_CALLER
);
285 Reference
< XInterface
> xNode
;
286 if (m_xDirectAccess
.is() && m_xDirectAccess
->hasByName(sNormalized
))
289 m_xDirectAccess
->getByName(sNormalized
), css::uno::UNO_QUERY
);
291 OSL_FAIL("OConfigurationNode::openNode: could not open the node!");
293 else if (m_xHierarchyAccess
.is())
296 m_xHierarchyAccess
->getByHierarchicalName(_rPath
),
297 css::uno::UNO_QUERY
);
299 OSL_FAIL("OConfigurationNode::openNode: could not open the node!");
302 return OConfigurationNode( xNode
);
304 catch(const NoSuchElementException
&)
306 SAL_WARN( "unotools", "OConfigurationNode::openNode: there is no element named " << _rPath
);
310 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::openNode: caught an exception while retrieving the node!");
312 return OConfigurationNode();
315 bool OConfigurationNode::isSetNode() const
318 Reference
< XServiceInfo
> xSI(m_xHierarchyAccess
, UNO_QUERY
);
321 try { bIsSet
= xSI
->supportsService("com.sun.star.configuration.SetAccess"); }
322 catch(Exception
&) { }
327 bool OConfigurationNode::hasByHierarchicalName( const OUString
& _rName
) const noexcept
329 OSL_ENSURE( m_xHierarchyAccess
.is(), "OConfigurationNode::hasByHierarchicalName: no hierarchy access!" );
332 if ( m_xHierarchyAccess
.is() )
334 OUString sName
= normalizeName( _rName
, NO_CALLER
);
335 return m_xHierarchyAccess
->hasByHierarchicalName( sName
);
344 bool OConfigurationNode::hasByName(const OUString
& _rName
) const noexcept
346 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::hasByName: object is invalid!");
349 OUString sName
= normalizeName(_rName
, NO_CALLER
);
350 if (m_xDirectAccess
.is())
351 return m_xDirectAccess
->hasByName(sName
);
359 bool OConfigurationNode::setNodeValue(const OUString
& _rPath
, const Any
& _rValue
) const noexcept
361 bool bResult
= false;
363 OSL_ENSURE(m_xReplaceAccess
.is(), "OConfigurationNode::setNodeValue: object is invalid!");
364 if (m_xReplaceAccess
.is())
368 // check if _rPath is a level-1 path
369 OUString sNormalizedName
= normalizeName(_rPath
, NO_CALLER
);
370 if (m_xReplaceAccess
->hasByName(sNormalizedName
))
372 m_xReplaceAccess
->replaceByName(sNormalizedName
, _rValue
);
376 // check if the name refers to an indirect descendant
377 else if (m_xHierarchyAccess
.is() && m_xHierarchyAccess
->hasByHierarchicalName(_rPath
))
379 OSL_ASSERT(!_rPath
.isEmpty());
381 OUString sParentPath
, sLocalName
;
383 if ( splitLastFromConfigurationPath(_rPath
, sParentPath
, sLocalName
) )
385 OConfigurationNode aParentAccess
= openNode(sParentPath
);
386 if (aParentAccess
.isValid())
387 bResult
= aParentAccess
.setNodeValue(sLocalName
, _rValue
);
391 m_xReplaceAccess
->replaceByName(sLocalName
, _rValue
);
399 TOOLS_WARN_EXCEPTION( "unotools", "OConfigurationNode::setNodeValue: could not replace the value");
406 Any
OConfigurationNode::getNodeValue(const OUString
& _rPath
) const noexcept
408 OSL_ENSURE(m_xDirectAccess
.is(), "OConfigurationNode::hasByName: object is invalid!");
409 OSL_ENSURE(m_xHierarchyAccess
.is(), "OConfigurationNode::hasByName: object is invalid!");
413 OUString sNormalizedPath
= normalizeName(_rPath
, NO_CALLER
);
414 if (m_xDirectAccess
.is() && m_xDirectAccess
->hasByName(sNormalizedPath
) )
416 aReturn
= m_xDirectAccess
->getByName(sNormalizedPath
);
418 else if (m_xHierarchyAccess
.is())
420 aReturn
= m_xHierarchyAccess
->getByHierarchicalName(_rPath
);
423 catch(const NoSuchElementException
&)
425 DBG_UNHANDLED_EXCEPTION("unotools");
430 void OConfigurationNode::clear() noexcept
432 m_xHierarchyAccess
.clear();
433 m_xDirectAccess
.clear();
434 m_xReplaceAccess
.clear();
435 m_xContainerAccess
.clear();
443 Reference
< XMultiServiceFactory
> lcl_getConfigProvider( const Reference
<XComponentContext
> & i_rContext
)
447 Reference
< XMultiServiceFactory
> xProvider
= theDefaultProvider::get( i_rContext
);
450 catch ( const Exception
& )
452 DBG_UNHANDLED_EXCEPTION("unotools");
457 Reference
< XInterface
> lcl_createConfigurationRoot( const Reference
< XMultiServiceFactory
>& i_rxConfigProvider
,
458 const OUString
& i_rNodePath
, const bool i_bUpdatable
, const sal_Int32 i_nDepth
)
460 ENSURE_OR_RETURN( i_rxConfigProvider
.is(), "invalid provider", nullptr );
463 ::comphelper::NamedValueCollection aArgs
;
464 aArgs
.put( "nodepath", i_rNodePath
);
465 aArgs
.put( "depth", i_nDepth
);
467 OUString
sAccessService( i_bUpdatable
?
468 OUString( "com.sun.star.configuration.ConfigurationUpdateAccess" ) :
469 OUString( "com.sun.star.configuration.ConfigurationAccess" ));
471 Reference
< XInterface
> xRoot(
472 i_rxConfigProvider
->createInstanceWithArguments( sAccessService
, aArgs
.getWrappedPropertyValues() ),
477 catch ( const Exception
& )
479 DBG_UNHANDLED_EXCEPTION("unotools");
485 OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference
< XInterface
>& _rxRootNode
)
486 :OConfigurationNode( _rxRootNode
)
487 ,m_xCommitter( _rxRootNode
, UNO_QUERY
)
491 OConfigurationTreeRoot::OConfigurationTreeRoot( const Reference
<XComponentContext
> & i_rContext
, const OUString
& i_rNodePath
, const bool i_bUpdatable
)
492 :OConfigurationNode( lcl_createConfigurationRoot( lcl_getConfigProvider( i_rContext
),
493 i_rNodePath
, i_bUpdatable
, -1 ) )
498 m_xCommitter
.set( getUNONode(), UNO_QUERY
);
499 OSL_ENSURE( m_xCommitter
.is(), "OConfigurationTreeRoot::OConfigurationTreeRoot: could not create an updatable node!" );
503 void OConfigurationTreeRoot::clear() noexcept
505 OConfigurationNode::clear();
506 m_xCommitter
.clear();
509 bool OConfigurationTreeRoot::commit() const noexcept
511 OSL_ENSURE(isValid(), "OConfigurationTreeRoot::commit: object is invalid!");
514 OSL_ENSURE(m_xCommitter
.is(), "OConfigurationTreeRoot::commit: I'm a readonly node!");
515 if (!m_xCommitter
.is())
520 m_xCommitter
->commitChanges();
523 catch(const Exception
&)
525 DBG_UNHANDLED_EXCEPTION("unotools");
530 OConfigurationTreeRoot
OConfigurationTreeRoot::createWithProvider(const Reference
< XMultiServiceFactory
>& _rxConfProvider
, const OUString
& _rPath
, sal_Int32 _nDepth
, CREATION_MODE _eMode
)
532 Reference
< XInterface
> xRoot( lcl_createConfigurationRoot(
533 _rxConfProvider
, _rPath
, _eMode
!= CM_READONLY
, _nDepth
) );
535 return OConfigurationTreeRoot( xRoot
);
536 return OConfigurationTreeRoot();
539 OConfigurationTreeRoot
OConfigurationTreeRoot::createWithComponentContext( const Reference
< XComponentContext
>& _rxContext
, const OUString
& _rPath
, sal_Int32 _nDepth
, CREATION_MODE _eMode
)
541 return createWithProvider( lcl_getConfigProvider( _rxContext
), _rPath
, _nDepth
, _eMode
);
544 OConfigurationTreeRoot
OConfigurationTreeRoot::tryCreateWithComponentContext( const Reference
< XComponentContext
>& rxContext
,
545 const OUString
& _rPath
, sal_Int32 _nDepth
, CREATION_MODE _eMode
)
547 OSL_ENSURE( rxContext
.is(), "OConfigurationTreeRoot::tryCreateWithComponentContext: invalid XComponentContext!" );
550 Reference
< XMultiServiceFactory
> xConfigFactory
= theDefaultProvider::get( rxContext
);
551 return createWithProvider( xConfigFactory
, _rPath
, _nDepth
, _eMode
);
553 catch(const Exception
&)
555 // silence this, 'cause the contract of this method states "no assertions"
557 return OConfigurationTreeRoot();
562 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */