Bump version to 4.3-4
[LibreOffice.git] / unotools / source / config / configitem.cxx
blobf8ebe58de277567913b8fe0a3423931330a99267
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
43 using namespace utl;
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>
53 #ifdef DBG_UTIL
54 static inline void lcl_CFG_DBG_EXCEPTION(const sal_Char* cText, const Exception& rEx)
56 OString sMsg(cText);
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) \
62 { \
63 lcl_CFG_DBG_EXCEPTION(a, rEx);\
65 #else
66 #define CATCH_INFO(a) catch(const Exception&){}
67 #endif
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
73 before doing so.
76 namespace utl{
77 class ConfigChangeListener_Impl : public cppu::WeakImplHelper1
79 com::sun::star::util::XChangesListener
82 public:
83 ConfigItem* pParent;
84 const Sequence< OUString > aPropertyNames;
85 ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames);
86 virtual ~ConfigChangeListener_Impl();
88 //XChangesListener
89 virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
91 //XEventListener
92 virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
96 class ValueCounter_Impl
98 sal_Int16& rCnt;
99 public:
100 ValueCounter_Impl(sal_Int16& rCounter):
101 rCnt(rCounter)
102 {rCnt++;}
103 ~ValueCounter_Impl()
105 OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
106 rCnt--;
110 ConfigChangeListener_Impl::ConfigChangeListener_Impl(
111 ConfigItem& rItem, const Sequence< OUString >& rNames) :
112 pParent(&rItem),
113 aPropertyNames(rNames)
117 ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
121 static bool lcl_Find(
122 const OUString& rTemp,
123 const OUString* pCheckPropertyNames,
124 sal_Int32 nLength)
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]) )
130 return true;
131 return false;
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++)
146 OUString sTemp;
147 pElementChanges[i].Accessor >>= sTemp;
148 if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength()))
149 pNames[nNotify++] = sTemp;
151 if( nNotify )
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 ) :
168 sSubTree(rSubTree),
169 m_nMode(nSetMode),
170 m_bIsModified(false),
171 m_bEnableInternalNotification(false),
172 m_nInValueChange(0)
174 if(0 != (nSetMode&CONFIG_MODE_RELEASE_TREE))
175 ConfigManager::getConfigManager().addConfigItem(*this);
176 else
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 );
222 // Algorithm:
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.
254 else
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 );
292 // Algorithm:
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.
322 else
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)
339 sal_Int32 i;
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())
354 return lStates;
356 for (i=0; i<nCount; ++i)
360 OUString sName = rNames[i];
361 OUString sPath;
362 OUString sProperty;
364 ::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
365 if (sPath.isEmpty() && sProperty.isEmpty())
367 OSL_FAIL("ConfigItem::IsReadonly()\nsplitt failed\n");
368 continue;
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");
380 continue;
383 else
385 xNode = Reference<XInterface>( xHierarchyAccess, UNO_QUERY );
388 xSet = Reference< XPropertySet >(xNode, UNO_QUERY);
389 if (xSet.is())
391 xInfo = xSet->getPropertySetInfo();
392 OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
394 else
396 xInfo = Reference< XPropertySetInfo >(xNode, UNO_QUERY);
397 OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
400 if (!xInfo.is())
402 OSL_FAIL("ConfigItem::IsReadonly()\nno prop info available\n");
403 continue;
406 Property aProp = xInfo->getPropertyByName(sProperty);
407 lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY);
409 catch (const Exception&)
414 return lStates;
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)
433 SAL_WARN(
434 "unotools.config",
435 "ignoring XHierarchicalNameAccess to /org.openoffice."
436 << sSubTree << "/" << pNames[i] << " Exception: "
437 << rEx.Message);
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 );
446 aRet = lValues;
449 return aRet;
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();
459 if(bRet)
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 ();
477 else
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;
495 aNode >>= 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]);
502 else
503 if (!bExist && xNodeCont.is())
504 xNodeCont->insertByName(sProperty, pValues[i]);
505 else
506 bRet = false;
508 else //direct value
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(): ")
523 return bRet;
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);
540 if(!xChgNot.is())
541 return false;
543 OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
544 if(xChangeLstnr.is())
545 xChgNot->removeChangesListener( xChangeLstnr );
546 bool bRet = true;
550 xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
551 xChgNot->addChangesListener( xChangeLstnr );
553 catch (const RuntimeException&)
555 bRet = false;
557 return bRet;
560 void ConfigItem::RemoveChangesListener()
562 Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY);
563 if(xChgNot.is() && xChangeLstnr.is())
567 xChgNot->removeChangesListener( xChangeLstnr );
568 xChangeLstnr = 0;
570 catch (const Exception&)
576 static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
578 switch (_eFormat)
580 case CONFIG_NAME_LOCAL_NAME:
581 // unaltered - this is our input format
582 break;
584 case CONFIG_NAME_FULL_PATH:
586 Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY);
587 if (xFormatter.is())
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(): ")
598 break;
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);
618 else
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]);
631 break;
633 case CONFIG_NAME_PLAINTEXT_NAME:
635 Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY);
636 if (xEscaper.is())
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(): ")
647 break;
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;
668 if(!rNode.isEmpty())
670 Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
671 aNode >>= xCont;
673 else
674 xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY);
675 if(xCont.is())
677 aRet = xCont->getElementNames();
678 lcl_normalizeLocalNames(aRet,eFormat,xCont);
682 CATCH_INFO("Exception from GetNodeNames: ");
684 return aRet;
687 bool ConfigItem::ClearNodeSet(const OUString& rNode)
689 ValueCounter_Impl aCounter(m_nInValueChange);
690 bool bRet = false;
691 Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
692 if(xHierarchyAccess.is())
696 Reference<XNameContainer> xCont;
697 if(!rNode.isEmpty())
699 Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
700 aNode >>= xCont;
702 else
703 xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
704 if(!xCont.is())
705 return false;
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();
718 bRet = true;
720 CATCH_INFO("Exception from ClearNodeSet")
722 return bRet;
725 bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements)
727 ValueCounter_Impl aCounter(m_nInValueChange);
728 bool bRet = false;
729 Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
730 if(xHierarchyAccess.is())
732 const OUString* pElements = rElements.getConstArray();
735 Reference<XNameContainer> xCont;
736 if(!rNode.isEmpty())
738 Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
739 aNode >>= xCont;
741 else
742 xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
743 if(!xCont.is())
744 return false;
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(): ")
755 bRet = true;
757 CATCH_INFO("Exception from GetNodeNames: ")
759 return bRet;
762 static inline
763 OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix )
765 OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
766 return extractFirstFromConfigurationPath( sSubPath );
769 static
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);
802 bool bRet = true;
803 Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
804 if(xHierarchyAccess.is())
806 Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
809 Reference<XNameContainer> xCont;
810 if(!rNode.isEmpty())
812 Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
813 aNode >>= xCont;
815 else
816 xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
817 if(!xCont.is())
818 return false;
820 Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
822 if(xFac.is())
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);
836 //set values
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);
860 else
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);
872 else
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();
883 #ifdef DBG_UTIL
884 catch (const Exception& rEx)
886 lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx);
887 #else
888 catch (const Exception&)
890 #endif
891 bRet = false;
894 return bRet;
897 bool ConfigItem::ReplaceSetProperties(
898 const OUString& rNode, const Sequence< PropertyValue >& rValues)
900 ValueCounter_Impl aCounter(m_nInValueChange);
901 bool bRet = true;
902 Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
903 if(xHierarchyAccess.is())
905 Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
908 Reference<XNameContainer> xCont;
909 if(!rNode.isEmpty())
911 Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
912 aNode >>= xCont;
914 else
915 xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
916 if(!xCont.is())
917 return false;
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++)
934 bool bFound = false;
935 for(sal_Int32 j = 0; j < nSubNodeCount; j++)
937 if(pSubNodeNames[j] == pContainerSubNodes[nContSub])
939 bFound = true;
940 break;
943 if(!bFound)
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
957 continue;
959 catch (Exception &)
960 {} // propagate original exception, if fallback fails
962 throw;
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);
1000 else
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);
1013 else
1014 xCont->insertByName(sSubNode, pValues[nValue].Value);
1016 CATCH_INFO("Exception from insert/replaceByName(): ");
1018 xBatch->commitChanges();
1021 #ifdef DBG_UTIL
1022 catch (const Exception& rEx)
1024 lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx);
1025 #else
1026 catch (const Exception&)
1028 #endif
1029 bRet = false;
1032 return bRet;
1035 bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode)
1037 ValueCounter_Impl aCounter(m_nInValueChange);
1038 bool bRet = true;
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);
1049 aNode >>= xCont;
1051 else
1052 xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1053 if(!xCont.is())
1054 return false;
1056 Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1058 if(xFac.is())
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(): ")
1072 else
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();
1084 #ifdef DBG_UTIL
1085 catch (const Exception& rEx)
1087 lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx);
1088 #else
1089 catch (const Exception&)
1091 #endif
1092 bRet = false;
1095 return bRet;
1098 sal_Int16 ConfigItem::GetMode() const
1100 return m_nMode;
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);
1128 else
1129 xRet = m_xHierarchyAccess;
1130 return xRet;
1133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */