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> // helper for implementations
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 ~ConfigChangeListener_Impl();
89 virtual void SAL_CALL
changesOccurred( const ChangesEvent
& Event
) throw(RuntimeException
);
92 virtual void SAL_CALL
disposing( const EventObject
& Source
) throw(RuntimeException
);
95 struct ConfigItem_Impl
97 utl::ConfigManager
* pManager
;
100 sal_Bool bEnableInternalNotification
;
102 sal_Int16 nInValueChange
;
106 bIsModified(sal_False
),
107 bEnableInternalNotification(sal_False
),
113 class ValueCounter_Impl
117 ValueCounter_Impl(sal_Int16
& rCounter
):
122 OSL_ENSURE(rCnt
>0, "RefCount < 0 ??");
129 // helper to achieve exception - safe handling of an Item under construction
131 class AutoDeleter
// : Noncopyable
135 AutoDeleter(TYP
* pItem
)
145 void keep() { m_pItem
= 0; }
149 ConfigChangeListener_Impl::ConfigChangeListener_Impl(
150 ConfigItem
& rItem
, const Sequence
< OUString
>& rNames
) :
152 aPropertyNames(rNames
)
156 ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
160 static sal_Bool
lcl_Find(
161 const OUString
& rTemp
,
162 const OUString
* pCheckPropertyNames
,
165 //return true if the path is completely correct or if it is longer
166 //i.e ...Print/Content/Graphic and .../Print
167 for(sal_Int32 nIndex
= 0; nIndex
< nLength
; nIndex
++)
168 if( isPrefixOfConfigurationPath(rTemp
, pCheckPropertyNames
[nIndex
]) )
172 //-----------------------------------------------------------------------------
173 void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent
& rEvent
) throw(RuntimeException
)
175 const ElementChange
* pElementChanges
= rEvent
.Changes
.getConstArray();
177 Sequence
<OUString
> aChangedNames(rEvent
.Changes
.getLength());
178 OUString
* pNames
= aChangedNames
.getArray();
180 const OUString
* pCheckPropertyNames
= aPropertyNames
.getConstArray();
182 sal_Int32 nNotify
= 0;
183 for(int i
= 0; i
< aChangedNames
.getLength(); i
++)
186 pElementChanges
[i
].Accessor
>>= sTemp
;
187 if(lcl_Find(sTemp
, pCheckPropertyNames
, aPropertyNames
.getLength()))
188 pNames
[nNotify
++] = sTemp
;
192 if ( ::tools::SolarMutex::Acquire() )
194 aChangedNames
.realloc(nNotify
);
195 pParent
->CallNotify(aChangedNames
);
196 ::tools::SolarMutex::Release();
202 void ConfigChangeListener_Impl::disposing( const EventObject
& /*rSource*/ ) throw(RuntimeException
)
204 pParent
->RemoveChangesListener();
207 ConfigItem::ConfigItem(const OUString
&rSubTree
, sal_Int16 nSetMode
) :
209 pImpl(new ConfigItem_Impl
)
211 AutoDeleter
<ConfigItem_Impl
> aNewImpl(pImpl
);
213 pImpl
->pManager
= &ConfigManager::getConfigManager();
214 pImpl
->nMode
= nSetMode
;
215 if(0 != (nSetMode
&CONFIG_MODE_RELEASE_TREE
))
216 pImpl
->pManager
->addConfigItem(*this);
218 m_xHierarchyAccess
= pImpl
->pManager
->addConfigItem(*this);
223 sal_Bool
ConfigItem::IsValidConfigMgr() const
225 return pImpl
->pManager
!= 0;
228 ConfigItem::~ConfigItem()
232 RemoveChangesListener();
233 pImpl
->pManager
->removeConfigItem(*this);
238 void ConfigItem::CallNotify( const com::sun::star::uno::Sequence
<OUString
>& rPropertyNames
)
240 // the call is forwarded to the virtual Notify() method
241 // it is pure virtual, so all classes deriving from ConfigItem have to decide how they
242 // want to notify listeners
243 if(!IsInValueChange() || pImpl
->bEnableInternalNotification
)
244 Notify(rPropertyNames
);
247 void ConfigItem::impl_packLocalizedProperties( const Sequence
< OUString
>& lInNames
,
248 const Sequence
< Any
>& lInValues
,
249 Sequence
< Any
>& lOutValues
)
251 // Safe impossible cases.
252 // This method should be called for special ConfigItem-mode only!
253 OSL_ENSURE( ((pImpl
->nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
), "ConfigItem::impl_packLocalizedProperties()\nWrong call of this method detected!\n" );
255 sal_Int32 nSourceCounter
; // used to step during input lists
256 sal_Int32 nSourceSize
; // marks end of loop over input lists
257 sal_Int32 nDestinationCounter
; // actual position in output lists
258 sal_Int32 nPropertyCounter
; // counter of inner loop for Sequence< PropertyValue >
259 sal_Int32 nPropertiesSize
; // marks end of inner loop
260 Sequence
< OUString
> lPropertyNames
; // list of all locales for localized entry
261 Sequence
< PropertyValue
> lProperties
; // localized values of an configuration entry packed for return
262 Reference
< XInterface
> xLocalizedNode
; // if cfg entry is localized ... lInValues contains an XInterface!
264 // Optimise follow algorithm ... A LITTLE BIT :-)
265 // There exist two different possibilities:
266 // i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
267 // ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
268 // ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service).
269 // We read all his child nodes and pack it into Sequence< PropertyValue >.
270 // The result list we pack into the return any. We never change size of lists!
271 nSourceSize
= lInNames
.getLength();
272 lOutValues
.realloc( nSourceSize
);
275 // Copy all names and values from in to out lists.
276 // Look for special localized entries ... You can detect it as "XInterface" packed into an Any.
277 // Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >.
278 // Add this list to out lists then.
280 nDestinationCounter
= 0;
281 for( nSourceCounter
=0; nSourceCounter
<nSourceSize
; ++nSourceCounter
)
283 // If item a special localized one ... convert and pack it ...
284 if( lInValues
[nSourceCounter
].getValueTypeName() == "com.sun.star.uno.XInterface" )
286 lInValues
[nSourceCounter
] >>= xLocalizedNode
;
287 Reference
< XNameContainer
> xSetAccess( xLocalizedNode
, UNO_QUERY
);
288 if( xSetAccess
.is() == sal_True
)
290 lPropertyNames
= xSetAccess
->getElementNames() ;
291 nPropertiesSize
= lPropertyNames
.getLength() ;
292 lProperties
.realloc( nPropertiesSize
) ;
294 for( nPropertyCounter
=0; nPropertyCounter
<nPropertiesSize
; ++nPropertyCounter
)
296 #if OSL_DEBUG_LEVEL > 1
297 // Sometimes it's better to see what's going on :-)
298 OUString sPropName
= lInNames
[nSourceCounter
];
299 OUString sLocaleName
= lPropertyNames
[nPropertyCounter
];
301 lProperties
[nPropertyCounter
].Name
= lPropertyNames
[nPropertyCounter
] ;
302 OUString sLocaleValue
;
303 xSetAccess
->getByName( lPropertyNames
[nPropertyCounter
] ) >>= sLocaleValue
;
304 lProperties
[nPropertyCounter
].Value
<<= sLocaleValue
;
307 lOutValues
[nDestinationCounter
] <<= lProperties
;
310 // ... or copy normal items to return lists directly.
313 lOutValues
[nDestinationCounter
] = lInValues
[nSourceCounter
];
315 ++nDestinationCounter
;
319 void ConfigItem::impl_unpackLocalizedProperties( const Sequence
< OUString
>& lInNames
,
320 const Sequence
< Any
>& lInValues
,
321 Sequence
< OUString
>& lOutNames
,
322 Sequence
< Any
>& lOutValues
)
324 // Safe impossible cases.
325 // This method should be called for special ConfigItem-mode only!
326 OSL_ENSURE( ((pImpl
->nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
), "ConfigItem::impl_unpackLocalizedProperties()\nWrong call of this method detected!\n" );
328 sal_Int32 nSourceCounter
; // used to step during input lists
329 sal_Int32 nSourceSize
; // marks end of loop over input lists
330 sal_Int32 nDestinationCounter
; // actual position in output lists
331 sal_Int32 nPropertyCounter
; // counter of inner loop for Sequence< PropertyValue >
332 sal_Int32 nPropertiesSize
; // marks end of inner loop
333 OUString sNodeName
; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
334 Sequence
< PropertyValue
> lProperties
; // localized values of an configuration entry getted from lInValues-Any
336 // Optimise follow algorithm ... A LITTLE BIT :-)
337 // There exist two different possibilities:
338 // i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues!
339 // ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues.
340 // => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast.
341 // We should reserve same space for output list like input ones first.
342 // Follow algorithm looks for these borders and change it for ii) only!
343 // It will be faster then a "realloc()" call in every loop ...
344 nSourceSize
= lInNames
.getLength();
346 lOutNames
.realloc ( nSourceSize
);
347 lOutValues
.realloc ( nSourceSize
);
350 // Copy all names and values from const to return lists.
351 // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any.
352 // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues.
354 nDestinationCounter
= 0;
355 for( nSourceCounter
=0; nSourceCounter
<nSourceSize
; ++nSourceCounter
)
357 // If item a special localized one ... split it and insert his parts to output lists ...
358 if( lInValues
[nSourceCounter
].getValueType() == ::getCppuType( (const Sequence
< PropertyValue
>*)NULL
) )
360 lInValues
[nSourceCounter
] >>= lProperties
;
361 nPropertiesSize
= lProperties
.getLength();
363 sNodeName
= lInNames
[nSourceCounter
] + "/";
365 if( (nDestinationCounter
+nPropertiesSize
) > lOutNames
.getLength() )
367 lOutNames
.realloc ( nDestinationCounter
+nPropertiesSize
);
368 lOutValues
.realloc ( nDestinationCounter
+nPropertiesSize
);
371 for( nPropertyCounter
=0; nPropertyCounter
<nPropertiesSize
; ++nPropertyCounter
)
373 lOutNames
[nDestinationCounter
] = sNodeName
+ lProperties
[nPropertyCounter
].Name
;
374 lOutValues
[nDestinationCounter
] = lProperties
[nPropertyCounter
].Value
;
375 ++nDestinationCounter
;
378 // ... or copy normal items to return lists directly.
381 if( (nDestinationCounter
+1) > lOutNames
.getLength() )
383 lOutNames
.realloc ( nDestinationCounter
+1 );
384 lOutValues
.realloc ( nDestinationCounter
+1 );
387 lOutNames
[nDestinationCounter
] = lInNames
[nSourceCounter
];
388 lOutValues
[nDestinationCounter
] = lInValues
[nSourceCounter
];
389 ++nDestinationCounter
;
394 Sequence
< sal_Bool
> ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence
< OUString
>& rNames
)
398 // size of return list is fix!
399 // Every item must match to length of incoming name list.
400 sal_Int32 nCount
= rNames
.getLength();
401 Sequence
< sal_Bool
> lStates(nCount
);
403 // We must be shure to return a valid information everytime!
404 // Set default to non readonly ... similar to the configuration handling of this property.
405 for ( i
=0; i
<nCount
; ++i
)
406 lStates
[i
] = sal_False
;
408 // no access - no information ...
409 Reference
< XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
410 if (!xHierarchyAccess
.is())
413 for (i
=0; i
<nCount
; ++i
)
417 OUString sName
= rNames
[i
];
421 ::utl::splitLastFromConfigurationPath(sName
,sPath
,sProperty
);
422 if (sPath
.isEmpty() && sProperty
.isEmpty())
424 OSL_FAIL("ConfigItem::IsReadonly()\nsplitt failed\n");
428 Reference
< XInterface
> xNode
;
429 Reference
< XPropertySet
> xSet
;
430 Reference
< XPropertySetInfo
> xInfo
;
431 if (!sPath
.isEmpty())
433 Any aNode
= xHierarchyAccess
->getByHierarchicalName(sPath
);
434 if (!(aNode
>>= xNode
) || !xNode
.is())
436 OSL_FAIL("ConfigItem::IsReadonly()\nno set available\n");
442 xNode
= Reference
< XInterface
>(xHierarchyAccess
, UNO_QUERY
);
445 xSet
= Reference
< XPropertySet
>(xNode
, UNO_QUERY
);
448 xInfo
= xSet
->getPropertySetInfo();
449 OSL_ENSURE(xInfo
.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
453 xInfo
= Reference
< XPropertySetInfo
>(xNode
, UNO_QUERY
);
454 OSL_ENSURE(xInfo
.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
459 OSL_FAIL("ConfigItem::IsReadonly()\nno prop info available\n");
463 Property aProp
= xInfo
->getPropertyByName(sProperty
);
464 lStates
[i
] = ((aProp
.Attributes
& PropertyAttribute::READONLY
) == PropertyAttribute::READONLY
);
466 catch (const Exception
&)
474 Sequence
< Any
> ConfigItem::GetProperties(const Sequence
< OUString
>& rNames
)
476 Sequence
< Any
> aRet(rNames
.getLength());
477 const OUString
* pNames
= rNames
.getConstArray();
478 Any
* pRet
= aRet
.getArray();
479 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
480 if(xHierarchyAccess
.is())
482 for(int i
= 0; i
< rNames
.getLength(); i
++)
486 pRet
[i
] = xHierarchyAccess
->getByHierarchicalName(pNames
[i
]);
488 catch (const Exception
& rEx
)
490 #if OSL_DEBUG_LEVEL > 0
491 OString
sMsg("XHierarchicalNameAccess: ");
492 sMsg
+= OString(rEx
.Message
.getStr(),
493 rEx
.Message
.getLength(),
494 RTL_TEXTENCODING_ASCII_US
);
495 sMsg
+= OString("\n/org.openoffice.");
496 sMsg
+= OString(sSubTree
.getStr(),
497 sSubTree
.getLength(),
498 RTL_TEXTENCODING_ASCII_US
);
499 sMsg
+= OString("/");
500 sMsg
+= OString(pNames
[i
].getStr(),
501 pNames
[i
].getLength(),
502 RTL_TEXTENCODING_ASCII_US
);
503 OSL_FAIL(sMsg
.getStr());
505 (void) rEx
; // avoid warning
510 // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
511 if((pImpl
->nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
)
513 Sequence
< Any
> lValues
;
514 impl_packLocalizedProperties( rNames
, aRet
, lValues
);
521 sal_Bool
ConfigItem::PutProperties( const Sequence
< OUString
>& rNames
,
522 const Sequence
< Any
>& rValues
)
524 ValueCounter_Impl
aCounter(pImpl
->nInValueChange
);
525 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
526 Reference
<XNameReplace
> xTopNodeReplace(xHierarchyAccess
, UNO_QUERY
);
527 sal_Bool bRet
= xHierarchyAccess
.is() && xTopNodeReplace
.is();
530 Sequence
< OUString
> lNames
;
531 Sequence
< Any
> lValues
;
532 const OUString
* pNames
= NULL
;
533 const Any
* pValues
= NULL
;
534 sal_Int32 nNameCount
;
535 if(( pImpl
->nMode
& CONFIG_MODE_ALL_LOCALES
) == CONFIG_MODE_ALL_LOCALES
)
537 // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
538 // as value of an localized configuration entry!
539 // How we can do that?
540 // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
541 impl_unpackLocalizedProperties( rNames
, rValues
, lNames
, lValues
);
542 pNames
= lNames
.getConstArray ();
543 pValues
= lValues
.getConstArray ();
544 nNameCount
= lNames
.getLength ();
548 // This is the normal mode ...
549 // Use given input lists directly.
550 pNames
= rNames
.getConstArray ();
551 pValues
= rValues
.getConstArray ();
552 nNameCount
= rNames
.getLength ();
554 for(int i
= 0; i
< nNameCount
; i
++)
558 OUString sNode
, sProperty
;
559 if (splitLastFromConfigurationPath(pNames
[i
],sNode
, sProperty
))
561 Any aNode
= xHierarchyAccess
->getByHierarchicalName(sNode
);
563 Reference
<XNameAccess
> xNodeAcc
;
565 Reference
<XNameReplace
> xNodeReplace(xNodeAcc
, UNO_QUERY
);
566 Reference
<XNameContainer
> xNodeCont (xNodeAcc
, UNO_QUERY
);
568 sal_Bool bExist
= (xNodeAcc
.is() && xNodeAcc
->hasByName(sProperty
));
569 if (bExist
&& xNodeReplace
.is())
570 xNodeReplace
->replaceByName(sProperty
, pValues
[i
]);
572 if (!bExist
&& xNodeCont
.is())
573 xNodeCont
->insertByName(sProperty
, pValues
[i
]);
579 xTopNodeReplace
->replaceByName(sProperty
, pValues
[i
]);
582 CATCH_INFO("Exception from PutProperties: ");
586 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
587 xBatch
->commitChanges();
589 CATCH_INFO("Exception from commitChanges(): ")
595 void ConfigItem::DisableNotification()
597 OSL_ENSURE( xChangeLstnr
.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
598 RemoveChangesListener();
601 sal_Bool
ConfigItem::EnableNotification(const Sequence
< OUString
>& rNames
,
602 sal_Bool bEnableInternalNotification
)
605 OSL_ENSURE(0 == (pImpl
->nMode
&CONFIG_MODE_RELEASE_TREE
), "notification in CONFIG_MODE_RELEASE_TREE mode not possible");
606 pImpl
->bEnableInternalNotification
= bEnableInternalNotification
;
607 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
608 Reference
<XChangesNotifier
> xChgNot(xHierarchyAccess
, UNO_QUERY
);
612 OSL_ENSURE(!xChangeLstnr
.is(), "EnableNotification already called");
613 if(xChangeLstnr
.is())
614 xChgNot
->removeChangesListener( xChangeLstnr
);
615 sal_Bool bRet
= sal_True
;
619 xChangeLstnr
= new ConfigChangeListener_Impl(*this, rNames
);
620 xChgNot
->addChangesListener( xChangeLstnr
);
622 catch (const RuntimeException
&)
629 void ConfigItem::RemoveChangesListener()
631 Reference
<XChangesNotifier
> xChgNot(m_xHierarchyAccess
, UNO_QUERY
);
632 if(xChgNot
.is() && xChangeLstnr
.is())
636 xChgNot
->removeChangesListener( xChangeLstnr
);
639 catch (const Exception
&)
645 static void lcl_normalizeLocalNames(Sequence
< OUString
>& _rNames
, ConfigNameFormat _eFormat
, Reference
<XInterface
> const& _xParentNode
)
649 case CONFIG_NAME_LOCAL_NAME
:
650 // unaltered - this is our input format
653 case CONFIG_NAME_FULL_PATH
:
655 Reference
<XHierarchicalName
> xFormatter(_xParentNode
, UNO_QUERY
);
658 OUString
* pNames
= _rNames
.getArray();
659 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
663 pNames
[i
] = xFormatter
->composeHierarchicalName(pNames
[i
]);
665 CATCH_INFO("Exception from composeHierarchicalName(): ")
670 OSL_FAIL("Cannot create absolute paths: missing interface");
671 // make local paths instaed
673 case CONFIG_NAME_LOCAL_PATH
:
675 Reference
<XTemplateContainer
> xTypeContainer(_xParentNode
, UNO_QUERY
);
676 if (xTypeContainer
.is())
678 OUString sTypeName
= xTypeContainer
->getElementTemplateName();
679 sTypeName
= sTypeName
.copy(sTypeName
.lastIndexOf('/')+1);
681 OUString
* pNames
= _rNames
.getArray();
682 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
684 pNames
[i
] = wrapConfigurationElementName(pNames
[i
],sTypeName
);
689 Reference
<XServiceInfo
> xSVI(_xParentNode
, UNO_QUERY
);
690 if (xSVI
.is() && xSVI
->supportsService("com.sun.star.configuration.SetAccess"))
692 OUString
* pNames
= _rNames
.getArray();
693 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
695 pNames
[i
] = wrapConfigurationElementName(pNames
[i
]);
702 case CONFIG_NAME_PLAINTEXT_NAME
:
704 Reference
<XStringEscape
> xEscaper(_xParentNode
, UNO_QUERY
);
707 OUString
* pNames
= _rNames
.getArray();
708 for(int i
= 0; i
<_rNames
.getLength(); ++i
)
711 pNames
[i
] = xEscaper
->unescapeString(pNames
[i
]);
713 CATCH_INFO("Exception from unescapeString(): ")
721 Sequence
< OUString
> ConfigItem::GetNodeNames(const OUString
& rNode
)
723 ConfigNameFormat
const eDefaultFormat
= CONFIG_NAME_LOCAL_NAME
; // CONFIG_NAME_DEFAULT;
725 return GetNodeNames(rNode
, eDefaultFormat
);
728 Sequence
< OUString
> ConfigItem::GetNodeNames(const OUString
& rNode
, ConfigNameFormat eFormat
)
730 Sequence
< OUString
> aRet
;
731 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
732 if(xHierarchyAccess
.is())
736 Reference
<XNameAccess
> xCont
;
739 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
743 xCont
= Reference
<XNameAccess
> (xHierarchyAccess
, UNO_QUERY
);
746 aRet
= xCont
->getElementNames();
747 lcl_normalizeLocalNames(aRet
,eFormat
,xCont
);
751 CATCH_INFO("Exception from GetNodeNames: ");
756 sal_Bool
ConfigItem::ClearNodeSet(const OUString
& rNode
)
758 ValueCounter_Impl
aCounter(pImpl
->nInValueChange
);
759 sal_Bool bRet
= sal_False
;
760 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
761 if(xHierarchyAccess
.is())
765 Reference
<XNameContainer
> xCont
;
768 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
772 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
775 Sequence
< OUString
> aNames
= xCont
->getElementNames();
776 const OUString
* pNames
= aNames
.getConstArray();
777 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
778 for(sal_Int32 i
= 0; i
< aNames
.getLength(); i
++)
782 xCont
->removeByName(pNames
[i
]);
784 CATCH_INFO("Exception from removeByName(): ")
786 xBatch
->commitChanges();
789 CATCH_INFO("Exception from ClearNodeSet")
794 sal_Bool
ConfigItem::ClearNodeElements(const OUString
& rNode
, Sequence
< OUString
>& rElements
)
796 ValueCounter_Impl
aCounter(pImpl
->nInValueChange
);
797 sal_Bool bRet
= sal_False
;
798 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
799 if(xHierarchyAccess
.is())
801 const OUString
* pElements
= rElements
.getConstArray();
804 Reference
<XNameContainer
> xCont
;
807 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
811 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
816 for(sal_Int32 nElement
= 0; nElement
< rElements
.getLength(); nElement
++)
818 xCont
->removeByName(pElements
[nElement
]);
820 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
821 xBatch
->commitChanges();
823 CATCH_INFO("Exception from commitChanges(): ")
826 CATCH_INFO("Exception from GetNodeNames: ")
830 //----------------------------------------------------------------------------
832 OUString
lcl_extractSetPropertyName( const OUString
& rInPath
, const OUString
& rPrefix
)
834 OUString
const sSubPath
= dropPrefixFromConfigurationPath( rInPath
, rPrefix
);
835 return extractFirstFromConfigurationPath( sSubPath
);
837 //----------------------------------------------------------------------------
839 Sequence
< OUString
> lcl_extractSetPropertyNames( const Sequence
< PropertyValue
>& rValues
, const OUString
& rPrefix
)
841 const PropertyValue
* pProperties
= rValues
.getConstArray();
843 Sequence
< OUString
> aSubNodeNames(rValues
.getLength());
844 OUString
* pSubNodeNames
= aSubNodeNames
.getArray();
846 OUString sLastSubNode
;
847 sal_Int32 nSubIndex
= 0;
849 for(sal_Int32 i
= 0; i
< rValues
.getLength(); i
++)
851 OUString
const sSubPath
= dropPrefixFromConfigurationPath( pProperties
[i
].Name
, rPrefix
);
852 OUString
const sSubNode
= extractFirstFromConfigurationPath( sSubPath
);
854 if(sLastSubNode
!= sSubNode
)
856 pSubNodeNames
[nSubIndex
++] = sSubNode
;
859 sLastSubNode
= sSubNode
;
861 aSubNodeNames
.realloc(nSubIndex
);
863 return aSubNodeNames
;
866 // Add or change properties
867 sal_Bool
ConfigItem::SetSetProperties(
868 const OUString
& rNode
, Sequence
< PropertyValue
> rValues
)
870 ValueCounter_Impl
aCounter(pImpl
->nInValueChange
);
871 sal_Bool bRet
= sal_True
;
872 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
873 if(xHierarchyAccess
.is())
875 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
878 Reference
<XNameContainer
> xCont
;
881 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
885 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
889 Reference
<XSingleServiceFactory
> xFac(xCont
, UNO_QUERY
);
893 const Sequence
< OUString
> aSubNodeNames
= lcl_extractSetPropertyNames(rValues
, rNode
);
895 const sal_Int32 nSubNodeCount
= aSubNodeNames
.getLength();
897 for(sal_Int32 j
= 0; j
<nSubNodeCount
; j
++)
899 if(!xCont
->hasByName(aSubNodeNames
[j
]))
901 Reference
<XInterface
> xInst
= xFac
->createInstance();
902 Any aVal
; aVal
<<= xInst
;
903 xCont
->insertByName(aSubNodeNames
[j
], aVal
);
909 xBatch
->commitChanges();
911 CATCH_INFO("Exception from commitChanges(): ")
913 const PropertyValue
* pProperties
= rValues
.getConstArray();
915 Sequence
< OUString
> aSetNames(rValues
.getLength());
916 OUString
* pSetNames
= aSetNames
.getArray();
918 Sequence
< Any
> aSetValues(rValues
.getLength());
919 Any
* pSetValues
= aSetValues
.getArray();
921 sal_Bool bEmptyNode
= rNode
.isEmpty();
922 for(sal_Int32 k
= 0; k
< rValues
.getLength(); k
++)
924 pSetNames
[k
] = pProperties
[k
].Name
.copy( bEmptyNode
? 1 : 0);
925 pSetValues
[k
] = pProperties
[k
].Value
;
927 bRet
= PutProperties(aSetNames
, aSetValues
);
931 //if no factory is available then the node contains basic data elements
932 const PropertyValue
* pValues
= rValues
.getConstArray();
933 for(int nValue
= 0; nValue
< rValues
.getLength();nValue
++)
937 OUString sSubNode
= lcl_extractSetPropertyName( pValues
[nValue
].Name
, rNode
);
939 if(xCont
->hasByName(sSubNode
))
940 xCont
->replaceByName(sSubNode
, pValues
[nValue
].Value
);
942 xCont
->insertByName(sSubNode
, pValues
[nValue
].Value
);
944 OSL_ENSURE( xHierarchyAccess
->hasByHierarchicalName(pValues
[nValue
].Name
),
945 "Invalid config path" );
947 CATCH_INFO("Exception form insert/replaceByName(): ")
949 xBatch
->commitChanges();
953 catch (const Exception
& rEx
)
955 lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx
);
957 catch (const Exception
&)
966 sal_Bool
ConfigItem::ReplaceSetProperties(
967 const OUString
& rNode
, Sequence
< PropertyValue
> rValues
)
969 ValueCounter_Impl
aCounter(pImpl
->nInValueChange
);
970 sal_Bool bRet
= sal_True
;
971 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
972 if(xHierarchyAccess
.is())
974 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
977 Reference
<XNameContainer
> xCont
;
980 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
984 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
988 // JB: Change: now the same name handling for sets of simple values
989 const Sequence
< OUString
> aSubNodeNames
= lcl_extractSetPropertyNames(rValues
, rNode
);
990 const OUString
* pSubNodeNames
= aSubNodeNames
.getConstArray();
991 const sal_Int32 nSubNodeCount
= aSubNodeNames
.getLength();
993 Reference
<XSingleServiceFactory
> xFac(xCont
, UNO_QUERY
);
994 const bool isSimpleValueSet
= !xFac
.is();
996 //remove unknown members first
998 const Sequence
<OUString
> aContainerSubNodes
= xCont
->getElementNames();
999 const OUString
* pContainerSubNodes
= aContainerSubNodes
.getConstArray();
1001 for(sal_Int32 nContSub
= 0; nContSub
< aContainerSubNodes
.getLength(); nContSub
++)
1003 sal_Bool bFound
= sal_False
;
1004 for(sal_Int32 j
= 0; j
< nSubNodeCount
; j
++)
1006 if(pSubNodeNames
[j
] == pContainerSubNodes
[nContSub
])
1015 xCont
->removeByName(pContainerSubNodes
[nContSub
]);
1017 catch (const Exception
&)
1019 if (isSimpleValueSet
)
1023 // #i37322#: fallback action: replace with <void/>
1024 xCont
->replaceByName(pContainerSubNodes
[nContSub
], Any());
1025 // fallback successful: continue looping
1029 {} // propagate original exception, if fallback fails
1034 try { xBatch
->commitChanges(); }
1035 CATCH_INFO("Exception from commitChanges(): ")
1038 if(xFac
.is()) // !isSimpleValueSet
1040 for(sal_Int32 j
= 0; j
< nSubNodeCount
; j
++)
1042 if(!xCont
->hasByName(pSubNodeNames
[j
]))
1044 //create if not available
1045 Reference
<XInterface
> xInst
= xFac
->createInstance();
1046 Any aVal
; aVal
<<= xInst
;
1047 xCont
->insertByName(pSubNodeNames
[j
], aVal
);
1050 try { xBatch
->commitChanges(); }
1051 CATCH_INFO("Exception from commitChanges(): ")
1053 const PropertyValue
* pProperties
= rValues
.getConstArray();
1055 Sequence
< OUString
> aSetNames(rValues
.getLength());
1056 OUString
* pSetNames
= aSetNames
.getArray();
1058 Sequence
< Any
> aSetValues(rValues
.getLength());
1059 Any
* pSetValues
= aSetValues
.getArray();
1061 sal_Bool bEmptyNode
= rNode
.isEmpty();
1062 for(sal_Int32 k
= 0; k
< rValues
.getLength(); k
++)
1064 pSetNames
[k
] = pProperties
[k
].Name
.copy( bEmptyNode
? 1 : 0);
1065 pSetValues
[k
] = pProperties
[k
].Value
;
1067 bRet
= PutProperties(aSetNames
, aSetValues
);
1071 const PropertyValue
* pValues
= rValues
.getConstArray();
1073 //if no factory is available then the node contains basic data elements
1074 for(int nValue
= 0; nValue
< rValues
.getLength();nValue
++)
1078 OUString sSubNode
= lcl_extractSetPropertyName( pValues
[nValue
].Name
, rNode
);
1080 if(xCont
->hasByName(sSubNode
))
1081 xCont
->replaceByName(sSubNode
, pValues
[nValue
].Value
);
1083 xCont
->insertByName(sSubNode
, pValues
[nValue
].Value
);
1085 CATCH_INFO("Exception from insert/replaceByName(): ");
1087 xBatch
->commitChanges();
1091 catch (const Exception
& rEx
)
1093 lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx
);
1095 catch (const Exception
&)
1104 sal_Bool
ConfigItem::getUniqueSetElementName( const OUString
& _rSetNode
, OUString
& _rName
)
1106 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
1107 sal_Bool bRet
= sal_False
;
1108 if(xHierarchyAccess
.is())
1112 Reference
< XNameAccess
> xSetNode
;
1113 xHierarchyAccess
->getByHierarchicalName(_rSetNode
) >>= xSetNode
;
1116 const sal_uInt32 nPrime
= 65521; // a prime number
1117 const sal_uInt32 nPrimeLess2
= nPrime
- 2;
1118 sal_uInt32 nEngendering
= (rand() % nPrimeLess2
) + 2; // the engendering of the field
1120 // the element which will loop through the field
1121 sal_uInt32 nFieldElement
= nEngendering
;
1123 for (; 1 != nFieldElement
; nFieldElement
= (nFieldElement
* nEngendering
) % nPrime
)
1125 OUString sThisRoundTrial
= _rName
;
1126 sThisRoundTrial
+= OUString::valueOf((sal_Int32
)nFieldElement
);
1128 if (!xSetNode
->hasByName(sThisRoundTrial
))
1130 _rName
= sThisRoundTrial
;
1137 CATCH_INFO("Exception from getUniqueSetElementName(): ")
1142 sal_Bool
ConfigItem::AddNode(const OUString
& rNode
, const OUString
& rNewNode
)
1144 ValueCounter_Impl
aCounter(pImpl
->nInValueChange
);
1145 sal_Bool bRet
= sal_True
;
1146 Reference
<XHierarchicalNameAccess
> xHierarchyAccess
= GetTree();
1147 if(xHierarchyAccess
.is())
1149 Reference
<XChangesBatch
> xBatch(xHierarchyAccess
, UNO_QUERY
);
1152 Reference
<XNameContainer
> xCont
;
1153 if(!rNode
.isEmpty())
1155 Any aNode
= xHierarchyAccess
->getByHierarchicalName(rNode
);
1159 xCont
= Reference
<XNameContainer
> (xHierarchyAccess
, UNO_QUERY
);
1163 Reference
<XSingleServiceFactory
> xFac(xCont
, UNO_QUERY
);
1167 if(!xCont
->hasByName(rNewNode
))
1169 Reference
<XInterface
> xInst
= xFac
->createInstance();
1170 Any aVal
; aVal
<<= xInst
;
1171 xCont
->insertByName(rNewNode
, aVal
);
1175 xBatch
->commitChanges();
1177 CATCH_INFO("Exception from commitChanges(): ")
1181 //if no factory is available then the node contains basic data elements
1184 if(!xCont
->hasByName(rNewNode
))
1185 xCont
->insertByName(rNewNode
, Any());
1187 CATCH_INFO("Exception from AddNode(): ")
1189 xBatch
->commitChanges();
1192 catch (const Exception
& rEx
)
1194 lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx
);
1196 catch (const Exception
&)
1205 sal_Int16
ConfigItem::GetMode() const
1207 return pImpl
->nMode
;
1210 void ConfigItem::SetModified()
1212 pImpl
->bIsModified
= sal_True
;
1215 void ConfigItem::ClearModified()
1217 pImpl
->bIsModified
= sal_False
;
1220 sal_Bool
ConfigItem::IsModified() const
1222 return pImpl
->bIsModified
;
1225 sal_Bool
ConfigItem::IsInValueChange() const
1227 return pImpl
->nInValueChange
> 0;
1230 Reference
< XHierarchicalNameAccess
> ConfigItem::GetTree()
1232 Reference
< XHierarchicalNameAccess
> xRet
;
1233 if(!m_xHierarchyAccess
.is())
1234 xRet
= ConfigManager::acquireTree(*this);
1236 xRet
= m_xHierarchyAccess
;
1240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */