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/configitem.hxx>
21 #include <unotools/configmgr.hxx>
22 #include <unotools/configpaths.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <com/sun/star/beans/XMultiPropertySet.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/util/XChangesListener.hpp>
27 #include <com/sun/star/util/XChangesNotifier.hpp>
28 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
29 #include <com/sun/star/container/XHierarchicalName.hpp>
30 #include <com/sun/star/configuration/XTemplateContainer.hpp>
31 #include <com/sun/star/container/XNameContainer.hpp>
32 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
33 #include <com/sun/star/lang/XServiceInfo.hpp>
34 #include <com/sun/star/awt/XRequestCallback.hpp>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/beans/PropertyAttribute.hpp>
37 #include <com/sun/star/util/XStringEscape.hpp>
38 #include <com/sun/star/util/XChangesBatch.hpp>
39 #include <osl/diagnose.h>
40 #include <tools/solarmutex.hxx>
41 #include <rtl/ustrbuf.hxx>
44 using namespace com::sun::star::uno
;
45 using namespace com::sun::star::util
;
46 using namespace com::sun::star::lang
;
47 using namespace com::sun::star::beans
;
48 using namespace com::sun::star::container
;
49 using namespace com::sun::star::configuration
;
51 #include <cppuhelper/implbase1.hxx>
54 static inline void lcl_CFG_DBG_EXCEPTION(const sal_Char
* cText
, const Exception
& rEx
)
57 sMsg
+= OString(rEx
.Message
.getStr(), rEx
.Message
.getLength(), RTL_TEXTENCODING_ASCII_US
);
58 OSL_FAIL(sMsg
.getStr());
60 #define CATCH_INFO(a) \
61 catch(const Exception& rEx) \
63 lcl_CFG_DBG_EXCEPTION(a, rEx);\
66 #define CATCH_INFO(a) catch(const Exception&){}
70 The ConfigChangeListener_Impl receives notifications from the configuration about changes that
71 have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its
72 "CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired
77 class ConfigChangeListener_Impl
: public cppu::WeakImplHelper1
79 com::sun::star::util::XChangesListener
84 const Sequence
< OUString
> aPropertyNames
;
85 ConfigChangeListener_Impl(ConfigItem
& rItem
, const Sequence
< OUString
>& rNames
);
86 virtual ~ConfigChangeListener_Impl();
89 virtual void SAL_CALL
changesOccurred( const ChangesEvent
& Event
) throw(RuntimeException
, std::exception
) SAL_OVERRIDE
;
92 virtual void SAL_CALL
disposing( const EventObject
& Source
) throw(RuntimeException
, std::exception
) SAL_OVERRIDE
;
96 class ValueCounter_Impl
100 ValueCounter_Impl(sal_Int16
& rCounter
):
105 OSL_ENSURE(rCnt
>0, "RefCount < 0 ??");
110 ConfigChangeListener_Impl::ConfigChangeListener_Impl(
111 ConfigItem
& rItem
, const Sequence
< OUString
>& rNames
) :
113 aPropertyNames(rNames
)
117 ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
121 static bool lcl_Find(
122 const OUString
& rTemp
,
123 const OUString
* pCheckPropertyNames
,
126 //return true if the path is completely correct or if it is longer
127 //i.e ...Print/Content/Graphic and .../Print
128 for(sal_Int32 nIndex
= 0; nIndex
< nLength
; nIndex
++)
129 if( isPrefixOfConfigurationPath(rTemp
, pCheckPropertyNames
[nIndex
]) )
134 void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent
& rEvent
) throw(RuntimeException
, std::exception
)
136 const ElementChange
* pElementChanges
= rEvent
.Changes
.getConstArray();
138 Sequence
<OUString
> aChangedNames(rEvent
.Changes
.getLength());
139 OUString
* pNames
= aChangedNames
.getArray();
141 const OUString
* pCheckPropertyNames
= aPropertyNames
.getConstArray();
143 sal_Int32 nNotify
= 0;
144 for(int i
= 0; i
< aChangedNames
.getLength(); i
++)
147 pElementChanges
[i
].Accessor
>>= sTemp
;
148 if(lcl_Find(sTemp
, pCheckPropertyNames
, aPropertyNames
.getLength()))
149 pNames
[nNotify
++] = sTemp
;
153 if ( ::tools::SolarMutex::Acquire() )
155 aChangedNames
.realloc(nNotify
);
156 pParent
->CallNotify(aChangedNames
);
157 ::tools::SolarMutex::Release();
162 void ConfigChangeListener_Impl::disposing( const EventObject
& /*rSource*/ ) throw(RuntimeException
, std::exception
)
164 pParent
->RemoveChangesListener();
167 ConfigItem::ConfigItem(const OUString
&rSubTree
, sal_Int16 nSetMode
) :
170 m_bIsModified(false),
171 m_bEnableInternalNotification(false),
174 if(0 != (nSetMode
&CONFIG_MODE_RELEASE_TREE
))
175 ConfigManager::getConfigManager().addConfigItem(*this);
177 m_xHierarchyAccess
= ConfigManager::getConfigManager().addConfigItem(*this);
180 ConfigItem::~ConfigItem()
182 RemoveChangesListener();
183 ConfigManager::getConfigManager().removeConfigItem(*this);
186 void ConfigItem::CallNotify( const com::sun::star::uno::Sequence
<OUString
>& rPropertyNames
)
188 // the call is forwarded to the virtual Notify() method
189 // it is pure virtual, so all classes deriving from ConfigItem have to decide how they
190 // want to notify listeners
191 if(!IsInValueChange() || m_bEnableInternalNotification
)
192 Notify(rPropertyNames
);
195 void ConfigItem::impl_packLocalizedProperties( const Sequence
< OUString
>& lInNames
,
196 const Sequence
< Any
>& lInValues
,
197 Sequence
< Any
>& lOutValues
)
199 // Safe impossible cases.
200 // This method should be called for special ConfigItem-mode only!
201 OSL_ENSURE( ((m_nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
), "ConfigItem::impl_packLocalizedProperties()\nWrong call of this method detected!\n" );
203 sal_Int32 nSourceCounter
; // used to step during input lists
204 sal_Int32 nSourceSize
; // marks end of loop over input lists
205 sal_Int32 nDestinationCounter
; // actual position in output lists
206 sal_Int32 nPropertyCounter
; // counter of inner loop for Sequence< PropertyValue >
207 sal_Int32 nPropertiesSize
; // marks end of inner loop
208 Sequence
< OUString
> lPropertyNames
; // list of all locales for localized entry
209 Sequence
< PropertyValue
> lProperties
; // localized values of an configuration entry packed for return
210 Reference
< XInterface
> xLocalizedNode
; // if cfg entry is localized ... lInValues contains an XInterface!
212 // Optimise follow algorithm ... A LITTLE BIT :-)
213 // There exist two different possibilities:
214 // i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
215 // ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
216 // ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service).
217 // We read all his child nodes and pack it into Sequence< PropertyValue >.
218 // The result list we pack into the return any. We never change size of lists!
219 nSourceSize
= lInNames
.getLength();
220 lOutValues
.realloc( nSourceSize
);
223 // Copy all names and values from in to out lists.
224 // Look for special localized entries ... You can detect it as "XInterface" packed into an Any.
225 // Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >.
226 // Add this list to out lists then.
228 nDestinationCounter
= 0;
229 for( nSourceCounter
=0; nSourceCounter
<nSourceSize
; ++nSourceCounter
)
231 // If item a special localized one ... convert and pack it ...
232 if( lInValues
[nSourceCounter
].getValueTypeName() == "com.sun.star.uno.XInterface" )
234 lInValues
[nSourceCounter
] >>= xLocalizedNode
;
235 Reference
< XNameContainer
> xSetAccess( xLocalizedNode
, UNO_QUERY
);
236 if( xSetAccess
.is() )
238 lPropertyNames
= xSetAccess
->getElementNames();
239 nPropertiesSize
= lPropertyNames
.getLength();
240 lProperties
.realloc( nPropertiesSize
);
242 for( nPropertyCounter
=0; nPropertyCounter
<nPropertiesSize
; ++nPropertyCounter
)
244 lProperties
[nPropertyCounter
].Name
= lPropertyNames
[nPropertyCounter
];
245 OUString sLocaleValue
;
246 xSetAccess
->getByName( lPropertyNames
[nPropertyCounter
] ) >>= sLocaleValue
;
247 lProperties
[nPropertyCounter
].Value
<<= sLocaleValue
;
250 lOutValues
[nDestinationCounter
] <<= lProperties
;
253 // ... or copy normal items to return lists directly.
256 lOutValues
[nDestinationCounter
] = lInValues
[nSourceCounter
];
258 ++nDestinationCounter
;
262 void ConfigItem::impl_unpackLocalizedProperties( const Sequence
< OUString
>& lInNames
,
263 const Sequence
< Any
>& lInValues
,
264 Sequence
< OUString
>& lOutNames
,
265 Sequence
< Any
>& lOutValues
)
267 // Safe impossible cases.
268 // This method should be called for special ConfigItem-mode only!
269 OSL_ENSURE( ((m_nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
), "ConfigItem::impl_unpackLocalizedProperties()\nWrong call of this method detected!\n" );
271 sal_Int32 nSourceCounter
; // used to step during input lists
272 sal_Int32 nSourceSize
; // marks end of loop over input lists
273 sal_Int32 nDestinationCounter
; // actual position in output lists
274 sal_Int32 nPropertyCounter
; // counter of inner loop for Sequence< PropertyValue >
275 sal_Int32 nPropertiesSize
; // marks end of inner loop
276 OUString sNodeName
; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
277 Sequence
< PropertyValue
> lProperties
; // localized values of an configuration entry getted from lInValues-Any
279 // Optimise follow algorithm ... A LITTLE BIT :-)
280 // There exist two different possibilities:
281 // i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues!
282 // ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues.
283 // => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast.
284 // We should reserve same space for output list like input ones first.
285 // Follow algorithm looks for these borders and change it for ii) only!
286 // It will be faster then a "realloc()" call in every loop ...
287 nSourceSize
= lInNames
.getLength();
289 lOutNames
.realloc ( nSourceSize
);
290 lOutValues
.realloc ( nSourceSize
);
293 // Copy all names and values from const to return lists.
294 // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any.
295 // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues.
297 nDestinationCounter
= 0;
298 for( nSourceCounter
=0; nSourceCounter
<nSourceSize
; ++nSourceCounter
)
300 // If item a special localized one ... split it and insert his parts to output lists ...
301 if( lInValues
[nSourceCounter
].getValueType() == ::getCppuType( (const Sequence
< PropertyValue
>*)NULL
) )
303 lInValues
[nSourceCounter
] >>= lProperties
;
304 nPropertiesSize
= lProperties
.getLength();
306 sNodeName
= lInNames
[nSourceCounter
] + "/";
308 if( (nDestinationCounter
+nPropertiesSize
) > lOutNames
.getLength() )
310 lOutNames
.realloc ( nDestinationCounter
+nPropertiesSize
);
311 lOutValues
.realloc ( nDestinationCounter
+nPropertiesSize
);
314 for( nPropertyCounter
=0; nPropertyCounter
<nPropertiesSize
; ++nPropertyCounter
)
316 lOutNames
[nDestinationCounter
] = sNodeName
+ lProperties
[nPropertyCounter
].Name
;
317 lOutValues
[nDestinationCounter
] = lProperties
[nPropertyCounter
].Value
;
318 ++nDestinationCounter
;
321 // ... or copy normal items to return lists directly.
324 if( (nDestinationCounter
+1) > lOutNames
.getLength() )
326 lOutNames
.realloc ( nDestinationCounter
+1 );
327 lOutValues
.realloc ( nDestinationCounter
+1 );
330 lOutNames
[nDestinationCounter
] = lInNames
[nSourceCounter
];
331 lOutValues
[nDestinationCounter
] = lInValues
[nSourceCounter
];
332 ++nDestinationCounter
;
337 Sequence
< sal_Bool
> ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence
< OUString
>& rNames
)
341 // size of return list is fix!
342 // Every item must match to length of incoming name list.
343 sal_Int32 nCount
= rNames
.getLength();
344 Sequence
< sal_Bool
> lStates(nCount
);
346 // We must be sure to return a valid information everytime!
347 // Set default to non readonly ... similar to the configuration handling of this property.
348 for ( i
=0; i
<nCount
; ++i
)
349 lStates
[i
] = sal_False
;
351 // no access - no information ...
352 Reference
< XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
353 if (!xHierarchyAccess
.is())
356 for (i
=0; i
<nCount
; ++i
)
360 OUString sName
= rNames
[i
];
364 ::utl::splitLastFromConfigurationPath(sName
,sPath
,sProperty
);
365 if (sPath
.isEmpty() && sProperty
.isEmpty())
367 OSL_FAIL("ConfigItem::IsReadonly()\nsplitt failed\n");
371 Reference
< XInterface
> xNode
;
372 Reference
< XPropertySet
> xSet
;
373 Reference
< XPropertySetInfo
> xInfo
;
374 if (!sPath
.isEmpty())
376 Any aNode
= xHierarchyAccess
->getByHierarchicalName(sPath
);
377 if (!(aNode
>>= xNode
) || !xNode
.is())
379 OSL_FAIL("ConfigItem::IsReadonly()\nno set available\n");
385 xNode
= Reference
<XInterface
>( xHierarchyAccess
, UNO_QUERY
);
388 xSet
= Reference
< XPropertySet
>(xNode
, UNO_QUERY
);
391 xInfo
= xSet
->getPropertySetInfo();
392 OSL_ENSURE(xInfo
.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
396 xInfo
= Reference
< XPropertySetInfo
>(xNode
, UNO_QUERY
);
397 OSL_ENSURE(xInfo
.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
402 OSL_FAIL("ConfigItem::IsReadonly()\nno prop info available\n");
406 Property aProp
= xInfo
->getPropertyByName(sProperty
);
407 lStates
[i
] = ((aProp
.Attributes
& PropertyAttribute::READONLY
) == PropertyAttribute::READONLY
);
409 catch (const Exception
&)
417 Sequence
< Any
> ConfigItem::GetProperties(const Sequence
< OUString
>& rNames
)
419 Sequence
< Any
> aRet(rNames
.getLength());
420 const OUString
* pNames
= rNames
.getConstArray();
421 Any
* pRet
= aRet
.getArray();
422 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
423 if(xHierarchyAccess
.is())
425 for(int i
= 0; i
< rNames
.getLength(); i
++)
429 pRet
[i
] = xHierarchyAccess
->getByHierarchicalName(pNames
[i
]);
431 catch (const Exception
& rEx
)
435 "ignoring XHierarchicalNameAccess to /org.openoffice."
436 << sSubTree
<< "/" << pNames
[i
] << " Exception: "
441 // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
442 if((m_nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
)
444 Sequence
< Any
> lValues
;
445 impl_packLocalizedProperties( rNames
, aRet
, lValues
);
452 bool ConfigItem::PutProperties( const Sequence
< OUString
>& rNames
,
453 const Sequence
< Any
>& rValues
)
455 ValueCounter_Impl
aCounter(m_nInValueChange
);
456 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
457 Reference
<XNameReplace
> xTopNodeReplace(xHierarchyAccess
, UNO_QUERY
);
458 bool bRet
= xHierarchyAccess
.is() && xTopNodeReplace
.is();
461 Sequence
< OUString
> lNames
;
462 Sequence
< Any
> lValues
;
463 const OUString
* pNames
= NULL
;
464 const Any
* pValues
= NULL
;
465 sal_Int32 nNameCount
;
466 if(( m_nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
)
468 // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
469 // as value of an localized configuration entry!
470 // How we can do that?
471 // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
472 impl_unpackLocalizedProperties( rNames
, rValues
, lNames
, lValues
);
473 pNames
= lNames
.getConstArray ();
474 pValues
= lValues
.getConstArray ();
475 nNameCount
= lNames
.getLength ();
479 // This is the normal mode ...
480 // Use given input lists directly.
481 pNames
= rNames
.getConstArray ();
482 pValues
= rValues
.getConstArray ();
483 nNameCount
= rNames
.getLength ();
485 for(int i
= 0; i
< nNameCount
; i
++)
489 OUString sNode
, sProperty
;
490 if (splitLastFromConfigurationPath(pNames
[i
],sNode
, sProperty
))
492 Any aNode
= xHierarchyAccess
->getByHierarchicalName(sNode
);
494 Reference
<XNameAccess
> xNodeAcc
;
496 Reference
<XNameReplace
> xNodeReplace(xNodeAcc
, UNO_QUERY
);
497 Reference
<XNameContainer
> xNodeCont (xNodeAcc
, UNO_QUERY
);
499 bool bExist
= (xNodeAcc
.is() && xNodeAcc
->hasByName(sProperty
));
500 if (bExist
&& xNodeReplace
.is())
501 xNodeReplace
->replaceByName(sProperty
, pValues
[i
]);
503 if (!bExist
&& xNodeCont
.is())
504 xNodeCont
->insertByName(sProperty
, pValues
[i
]);
510 xTopNodeReplace
->replaceByName(sProperty
, pValues
[i
]);
513 CATCH_INFO("Exception from PutProperties: ");
517 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
518 xBatch
->commitChanges();
520 CATCH_INFO("Exception from commitChanges(): ")
526 void ConfigItem::DisableNotification()
528 OSL_ENSURE( xChangeLstnr
.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
529 RemoveChangesListener();
532 bool ConfigItem::EnableNotification(const Sequence
< OUString
>& rNames
,
533 bool bEnableInternalNotification
)
536 OSL_ENSURE(0 == (m_nMode
&CONFIG_MODE_RELEASE_TREE
), "notification in CONFIG_MODE_RELEASE_TREE mode not possible");
537 m_bEnableInternalNotification
= bEnableInternalNotification
;
538 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
539 Reference
<XChangesNotifier
> xChgNot(xHierarchyAccess
, UNO_QUERY
);
543 OSL_ENSURE(!xChangeLstnr
.is(), "EnableNotification already called");
544 if(xChangeLstnr
.is())
545 xChgNot
->removeChangesListener( xChangeLstnr
);
550 xChangeLstnr
= new ConfigChangeListener_Impl(*this, rNames
);
551 xChgNot
->addChangesListener( xChangeLstnr
);
553 catch (const RuntimeException
&)
560 void ConfigItem::RemoveChangesListener()
562 Reference
<XChangesNotifier
> xChgNot(m_xHierarchyAccess
, UNO_QUERY
);
563 if(xChgNot
.is() && xChangeLstnr
.is())
567 xChgNot
->removeChangesListener( xChangeLstnr
);
570 catch (const Exception
&)
576 static void lcl_normalizeLocalNames(Sequence
< OUString
>& _rNames
, ConfigNameFormat _eFormat
, Reference
<XInterface
> const& _xParentNode
)
580 case CONFIG_NAME_LOCAL_NAME
:
581 // unaltered - this is our input format
584 case CONFIG_NAME_FULL_PATH
:
586 Reference
<XHierarchicalName
> xFormatter(_xParentNode
, UNO_QUERY
);
589 OUString
* pNames
= _rNames
.getArray();
590 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
594 pNames
[i
] = xFormatter
->composeHierarchicalName(pNames
[i
]);
596 CATCH_INFO("Exception from composeHierarchicalName(): ")
601 OSL_FAIL("Cannot create absolute paths: missing interface");
602 // make local paths instaed
604 case CONFIG_NAME_LOCAL_PATH
:
606 Reference
<XTemplateContainer
> xTypeContainer(_xParentNode
, UNO_QUERY
);
607 if (xTypeContainer
.is())
609 OUString sTypeName
= xTypeContainer
->getElementTemplateName();
610 sTypeName
= sTypeName
.copy(sTypeName
.lastIndexOf('/')+1);
612 OUString
* pNames
= _rNames
.getArray();
613 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
615 pNames
[i
] = wrapConfigurationElementName(pNames
[i
],sTypeName
);
620 Reference
<XServiceInfo
> xSVI(_xParentNode
, UNO_QUERY
);
621 if (xSVI
.is() && xSVI
->supportsService("com.sun.star.configuration.SetAccess"))
623 OUString
* pNames
= _rNames
.getArray();
624 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
626 pNames
[i
] = wrapConfigurationElementName(pNames
[i
]);
633 case CONFIG_NAME_PLAINTEXT_NAME
:
635 Reference
<XStringEscape
> xEscaper(_xParentNode
, UNO_QUERY
);
638 OUString
* pNames
= _rNames
.getArray();
639 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
642 pNames
[i
] = xEscaper
->unescapeString(pNames
[i
]);
644 CATCH_INFO("Exception from unescapeString(): ")
652 Sequence
< OUString
> ConfigItem::GetNodeNames(const OUString
& rNode
)
654 ConfigNameFormat
const eDefaultFormat
= CONFIG_NAME_LOCAL_NAME
; // CONFIG_NAME_DEFAULT;
656 return GetNodeNames(rNode
, eDefaultFormat
);
659 Sequence
< OUString
> ConfigItem::GetNodeNames(const OUString
& rNode
, ConfigNameFormat eFormat
)
661 Sequence
< OUString
> aRet
;
662 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
663 if(xHierarchyAccess
.is())
667 Reference
<XNameAccess
> xCont
;
670 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
674 xCont
= Reference
<XNameAccess
> (xHierarchyAccess
, UNO_QUERY
);
677 aRet
= xCont
->getElementNames();
678 lcl_normalizeLocalNames(aRet
,eFormat
,xCont
);
682 CATCH_INFO("Exception from GetNodeNames: ");
687 bool ConfigItem::ClearNodeSet(const OUString
& rNode
)
689 ValueCounter_Impl
aCounter(m_nInValueChange
);
691 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
692 if(xHierarchyAccess
.is())
696 Reference
<XNameContainer
> xCont
;
699 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
703 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
706 Sequence
< OUString
> aNames
= xCont
->getElementNames();
707 const OUString
* pNames
= aNames
.getConstArray();
708 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
709 for(sal_Int32 i
= 0; i
< aNames
.getLength(); i
++)
713 xCont
->removeByName(pNames
[i
]);
715 CATCH_INFO("Exception from removeByName(): ")
717 xBatch
->commitChanges();
720 CATCH_INFO("Exception from ClearNodeSet")
725 bool ConfigItem::ClearNodeElements(const OUString
& rNode
, Sequence
< OUString
>& rElements
)
727 ValueCounter_Impl
aCounter(m_nInValueChange
);
729 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
730 if(xHierarchyAccess
.is())
732 const OUString
* pElements
= rElements
.getConstArray();
735 Reference
<XNameContainer
> xCont
;
738 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
742 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
747 for(sal_Int32 nElement
= 0; nElement
< rElements
.getLength(); nElement
++)
749 xCont
->removeByName(pElements
[nElement
]);
751 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
752 xBatch
->commitChanges();
754 CATCH_INFO("Exception from commitChanges(): ")
757 CATCH_INFO("Exception from GetNodeNames: ")
763 OUString
lcl_extractSetPropertyName( const OUString
& rInPath
, const OUString
& rPrefix
)
765 OUString
const sSubPath
= dropPrefixFromConfigurationPath( rInPath
, rPrefix
);
766 return extractFirstFromConfigurationPath( sSubPath
);
770 Sequence
< OUString
> lcl_extractSetPropertyNames( const Sequence
< PropertyValue
>& rValues
, const OUString
& rPrefix
)
772 const PropertyValue
* pProperties
= rValues
.getConstArray();
774 Sequence
< OUString
> aSubNodeNames(rValues
.getLength());
775 OUString
* pSubNodeNames
= aSubNodeNames
.getArray();
777 OUString sLastSubNode
;
778 sal_Int32 nSubIndex
= 0;
780 for(sal_Int32 i
= 0; i
< rValues
.getLength(); i
++)
782 OUString
const sSubPath
= dropPrefixFromConfigurationPath( pProperties
[i
].Name
, rPrefix
);
783 OUString
const sSubNode
= extractFirstFromConfigurationPath( sSubPath
);
785 if(sLastSubNode
!= sSubNode
)
787 pSubNodeNames
[nSubIndex
++] = sSubNode
;
790 sLastSubNode
= sSubNode
;
792 aSubNodeNames
.realloc(nSubIndex
);
794 return aSubNodeNames
;
797 // Add or change properties
798 bool ConfigItem::SetSetProperties(
799 const OUString
& rNode
, const Sequence
< PropertyValue
>& rValues
)
801 ValueCounter_Impl
aCounter(m_nInValueChange
);
803 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
804 if(xHierarchyAccess
.is())
806 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
809 Reference
<XNameContainer
> xCont
;
812 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
816 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
820 Reference
<XSingleServiceFactory
> xFac(xCont
, UNO_QUERY
);
824 const Sequence
< OUString
> aSubNodeNames
= lcl_extractSetPropertyNames(rValues
, rNode
);
826 const sal_Int32 nSubNodeCount
= aSubNodeNames
.getLength();
828 for(sal_Int32 j
= 0; j
<nSubNodeCount
; j
++)
830 if(!xCont
->hasByName(aSubNodeNames
[j
]))
832 Reference
<XInterface
> xInst
= xFac
->createInstance();
833 Any aVal
; aVal
<<= xInst
;
834 xCont
->insertByName(aSubNodeNames
[j
], aVal
);
840 xBatch
->commitChanges();
842 CATCH_INFO("Exception from commitChanges(): ")
844 const PropertyValue
* pProperties
= rValues
.getConstArray();
846 Sequence
< OUString
> aSetNames(rValues
.getLength());
847 OUString
* pSetNames
= aSetNames
.getArray();
849 Sequence
< Any
> aSetValues(rValues
.getLength());
850 Any
* pSetValues
= aSetValues
.getArray();
852 bool bEmptyNode
= rNode
.isEmpty();
853 for(sal_Int32 k
= 0; k
< rValues
.getLength(); k
++)
855 pSetNames
[k
] = pProperties
[k
].Name
.copy( bEmptyNode
? 1 : 0);
856 pSetValues
[k
] = pProperties
[k
].Value
;
858 bRet
= PutProperties(aSetNames
, aSetValues
);
862 //if no factory is available then the node contains basic data elements
863 const PropertyValue
* pValues
= rValues
.getConstArray();
864 for(int nValue
= 0; nValue
< rValues
.getLength();nValue
++)
868 OUString sSubNode
= lcl_extractSetPropertyName( pValues
[nValue
].Name
, rNode
);
870 if(xCont
->hasByName(sSubNode
))
871 xCont
->replaceByName(sSubNode
, pValues
[nValue
].Value
);
873 xCont
->insertByName(sSubNode
, pValues
[nValue
].Value
);
875 OSL_ENSURE( xHierarchyAccess
->hasByHierarchicalName(pValues
[nValue
].Name
),
876 "Invalid config path" );
878 CATCH_INFO("Exception form insert/replaceByName(): ")
880 xBatch
->commitChanges();
884 catch (const Exception
& rEx
)
886 lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx
);
888 catch (const Exception
&)
897 bool ConfigItem::ReplaceSetProperties(
898 const OUString
& rNode
, const Sequence
< PropertyValue
>& rValues
)
900 ValueCounter_Impl
aCounter(m_nInValueChange
);
902 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
903 if(xHierarchyAccess
.is())
905 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
908 Reference
<XNameContainer
> xCont
;
911 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
915 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
919 // JB: Change: now the same name handling for sets of simple values
920 const Sequence
< OUString
> aSubNodeNames
= lcl_extractSetPropertyNames(rValues
, rNode
);
921 const OUString
* pSubNodeNames
= aSubNodeNames
.getConstArray();
922 const sal_Int32 nSubNodeCount
= aSubNodeNames
.getLength();
924 Reference
<XSingleServiceFactory
> xFac(xCont
, UNO_QUERY
);
925 const bool isSimpleValueSet
= !xFac
.is();
927 //remove unknown members first
929 const Sequence
<OUString
> aContainerSubNodes
= xCont
->getElementNames();
930 const OUString
* pContainerSubNodes
= aContainerSubNodes
.getConstArray();
932 for(sal_Int32 nContSub
= 0; nContSub
< aContainerSubNodes
.getLength(); nContSub
++)
935 for(sal_Int32 j
= 0; j
< nSubNodeCount
; j
++)
937 if(pSubNodeNames
[j
] == pContainerSubNodes
[nContSub
])
946 xCont
->removeByName(pContainerSubNodes
[nContSub
]);
948 catch (const Exception
&)
950 if (isSimpleValueSet
)
954 // #i37322#: fallback action: replace with <void/>
955 xCont
->replaceByName(pContainerSubNodes
[nContSub
], Any());
956 // fallback successful: continue looping
960 {} // propagate original exception, if fallback fails
965 try { xBatch
->commitChanges(); }
966 CATCH_INFO("Exception from commitChanges(): ")
969 if(xFac
.is()) // !isSimpleValueSet
971 for(sal_Int32 j
= 0; j
< nSubNodeCount
; j
++)
973 if(!xCont
->hasByName(pSubNodeNames
[j
]))
975 //create if not available
976 Reference
<XInterface
> xInst
= xFac
->createInstance();
977 Any aVal
; aVal
<<= xInst
;
978 xCont
->insertByName(pSubNodeNames
[j
], aVal
);
981 try { xBatch
->commitChanges(); }
982 CATCH_INFO("Exception from commitChanges(): ")
984 const PropertyValue
* pProperties
= rValues
.getConstArray();
986 Sequence
< OUString
> aSetNames(rValues
.getLength());
987 OUString
* pSetNames
= aSetNames
.getArray();
989 Sequence
< Any
> aSetValues(rValues
.getLength());
990 Any
* pSetValues
= aSetValues
.getArray();
992 bool bEmptyNode
= rNode
.isEmpty();
993 for(sal_Int32 k
= 0; k
< rValues
.getLength(); k
++)
995 pSetNames
[k
] = pProperties
[k
].Name
.copy( bEmptyNode
? 1 : 0);
996 pSetValues
[k
] = pProperties
[k
].Value
;
998 bRet
= PutProperties(aSetNames
, aSetValues
);
1002 const PropertyValue
* pValues
= rValues
.getConstArray();
1004 //if no factory is available then the node contains basic data elements
1005 for(int nValue
= 0; nValue
< rValues
.getLength();nValue
++)
1009 OUString sSubNode
= lcl_extractSetPropertyName( pValues
[nValue
].Name
, rNode
);
1011 if(xCont
->hasByName(sSubNode
))
1012 xCont
->replaceByName(sSubNode
, pValues
[nValue
].Value
);
1014 xCont
->insertByName(sSubNode
, pValues
[nValue
].Value
);
1016 CATCH_INFO("Exception from insert/replaceByName(): ");
1018 xBatch
->commitChanges();
1022 catch (const Exception
& rEx
)
1024 lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx
);
1026 catch (const Exception
&)
1035 bool ConfigItem::AddNode(const OUString
& rNode
, const OUString
& rNewNode
)
1037 ValueCounter_Impl
aCounter(m_nInValueChange
);
1039 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
1040 if(xHierarchyAccess
.is())
1042 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
1045 Reference
<XNameContainer
> xCont
;
1046 if(!rNode
.isEmpty())
1048 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
1052 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
1056 Reference
<XSingleServiceFactory
> xFac(xCont
, UNO_QUERY
);
1060 if(!xCont
->hasByName(rNewNode
))
1062 Reference
<XInterface
> xInst
= xFac
->createInstance();
1063 Any aVal
; aVal
<<= xInst
;
1064 xCont
->insertByName(rNewNode
, aVal
);
1068 xBatch
->commitChanges();
1070 CATCH_INFO("Exception from commitChanges(): ")
1074 //if no factory is available then the node contains basic data elements
1077 if(!xCont
->hasByName(rNewNode
))
1078 xCont
->insertByName(rNewNode
, Any());
1080 CATCH_INFO("Exception from AddNode(): ")
1082 xBatch
->commitChanges();
1085 catch (const Exception
& rEx
)
1087 lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx
);
1089 catch (const Exception
&)
1098 sal_Int16
ConfigItem::GetMode() const
1103 void ConfigItem::SetModified()
1105 m_bIsModified
= true;
1108 void ConfigItem::ClearModified()
1110 m_bIsModified
= false;
1113 bool ConfigItem::IsModified() const
1115 return m_bIsModified
;
1118 bool ConfigItem::IsInValueChange() const
1120 return m_nInValueChange
> 0;
1123 Reference
< XHierarchicalNameAccess
> ConfigItem::GetTree()
1125 Reference
< XHierarchicalNameAccess
> xRet
;
1126 if(!m_xHierarchyAccess
.is())
1127 xRet
= ConfigManager::acquireTree(*this);
1129 xRet
= m_xHierarchyAccess
;
1133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */