Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
42 :
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;
50 :
51 : #include <cppuhelper/implbase1.hxx>
52 :
53 : #ifdef DBG_UTIL
54 : static inline void lcl_CFG_DBG_EXCEPTION(const sal_Char* cText, const Exception& rEx)
55 : {
56 : OString sMsg(cText);
57 : sMsg += OString(rEx.Message.getStr(), rEx.Message.getLength(), RTL_TEXTENCODING_ASCII_US);
58 : OSL_FAIL(sMsg.getStr());
59 : }
60 : #define CATCH_INFO(a) \
61 : catch(const Exception& rEx) \
62 : { \
63 : lcl_CFG_DBG_EXCEPTION(a, rEx);\
64 : }
65 : #else
66 : #define CATCH_INFO(a) catch(const Exception&){}
67 : #endif
68 :
69 : /*
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.
74 : */
75 :
76 : namespace utl{
77 : class ConfigChangeListener_Impl : public cppu::WeakImplHelper1
78 : <
79 : com::sun::star::util::XChangesListener
80 : >
81 : {
82 : public:
83 : ConfigItem* pParent;
84 : const Sequence< OUString > aPropertyNames;
85 : ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames);
86 : virtual ~ConfigChangeListener_Impl();
87 :
88 : //XChangesListener
89 : virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
90 :
91 : //XEventListener
92 : virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
93 : };
94 : }
95 :
96 : class ValueCounter_Impl
97 : {
98 : sal_Int16& rCnt;
99 : public:
100 0 : ValueCounter_Impl(sal_Int16& rCounter):
101 0 : rCnt(rCounter)
102 0 : {rCnt++;}
103 0 : ~ValueCounter_Impl()
104 : {
105 : OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
106 0 : rCnt--;
107 0 : }
108 : };
109 :
110 0 : ConfigChangeListener_Impl::ConfigChangeListener_Impl(
111 : ConfigItem& rItem, const Sequence< OUString >& rNames) :
112 : pParent(&rItem),
113 0 : aPropertyNames(rNames)
114 : {
115 0 : }
116 :
117 0 : ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
118 : {
119 0 : }
120 :
121 0 : static bool lcl_Find(
122 : const OUString& rTemp,
123 : const OUString* pCheckPropertyNames,
124 : sal_Int32 nLength)
125 : {
126 : //return true if the path is completely correct or if it is longer
127 : //i.e ...Print/Content/Graphic and .../Print
128 0 : for(sal_Int32 nIndex = 0; nIndex < nLength; nIndex++)
129 0 : if( isPrefixOfConfigurationPath(rTemp, pCheckPropertyNames[nIndex]) )
130 0 : return true;
131 0 : return false;
132 : }
133 :
134 0 : void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) throw(RuntimeException, std::exception)
135 : {
136 0 : const ElementChange* pElementChanges = rEvent.Changes.getConstArray();
137 :
138 0 : Sequence<OUString> aChangedNames(rEvent.Changes.getLength());
139 0 : OUString* pNames = aChangedNames.getArray();
140 :
141 0 : const OUString* pCheckPropertyNames = aPropertyNames.getConstArray();
142 :
143 0 : sal_Int32 nNotify = 0;
144 0 : for(int i = 0; i < aChangedNames.getLength(); i++)
145 : {
146 0 : OUString sTemp;
147 0 : pElementChanges[i].Accessor >>= sTemp;
148 0 : if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength()))
149 0 : pNames[nNotify++] = sTemp;
150 0 : }
151 0 : if( nNotify )
152 : {
153 0 : if ( ::tools::SolarMutex::Acquire() )
154 : {
155 0 : aChangedNames.realloc(nNotify);
156 0 : pParent->CallNotify(aChangedNames);
157 0 : ::tools::SolarMutex::Release();
158 : }
159 0 : }
160 0 : }
161 :
162 0 : void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException, std::exception)
163 : {
164 0 : pParent->RemoveChangesListener();
165 0 : }
166 :
167 0 : ConfigItem::ConfigItem(const OUString &rSubTree, sal_Int16 nSetMode ) :
168 : sSubTree(rSubTree),
169 : m_nMode(nSetMode),
170 : m_bIsModified(false),
171 : m_bEnableInternalNotification(false),
172 0 : m_nInValueChange(0)
173 : {
174 0 : if(0 != (nSetMode&CONFIG_MODE_RELEASE_TREE))
175 0 : ConfigManager::getConfigManager().addConfigItem(*this);
176 : else
177 0 : m_xHierarchyAccess = ConfigManager::getConfigManager().addConfigItem(*this);
178 0 : }
179 :
180 0 : ConfigItem::~ConfigItem()
181 : {
182 0 : RemoveChangesListener();
183 0 : ConfigManager::getConfigManager().removeConfigItem(*this);
184 0 : }
185 :
186 0 : void ConfigItem::CallNotify( const com::sun::star::uno::Sequence<OUString>& rPropertyNames )
187 : {
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 0 : if(!IsInValueChange() || m_bEnableInternalNotification)
192 0 : Notify(rPropertyNames);
193 0 : }
194 :
195 0 : void ConfigItem::impl_packLocalizedProperties( const Sequence< OUString >& lInNames ,
196 : const Sequence< Any >& lInValues ,
197 : Sequence< Any >& lOutValues )
198 : {
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" );
202 :
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 0 : Sequence< OUString > lPropertyNames; // list of all locales for localized entry
209 0 : Sequence< PropertyValue > lProperties; // localized values of an configuration entry packed for return
210 0 : Reference< XInterface > xLocalizedNode; // if cfg entry is localized ... lInValues contains an XInterface!
211 :
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 0 : nSourceSize = lInNames.getLength();
220 0 : lOutValues.realloc( nSourceSize );
221 :
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.
227 :
228 0 : nDestinationCounter = 0;
229 0 : for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
230 : {
231 : // If item a special localized one ... convert and pack it ...
232 0 : if( lInValues[nSourceCounter].getValueTypeName() == "com.sun.star.uno.XInterface" )
233 : {
234 0 : lInValues[nSourceCounter] >>= xLocalizedNode;
235 0 : Reference< XNameContainer > xSetAccess( xLocalizedNode, UNO_QUERY );
236 0 : if( xSetAccess.is() )
237 : {
238 0 : lPropertyNames = xSetAccess->getElementNames();
239 0 : nPropertiesSize = lPropertyNames.getLength();
240 0 : lProperties.realloc( nPropertiesSize );
241 :
242 0 : for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
243 : {
244 : #if OSL_DEBUG_LEVEL > 1
245 : // Sometimes it's better to see what's going on :-)
246 : OUString sPropName = lInNames[nSourceCounter];
247 : OUString sLocaleName = lPropertyNames[nPropertyCounter];
248 : #endif
249 0 : lProperties[nPropertyCounter].Name = lPropertyNames[nPropertyCounter];
250 0 : OUString sLocaleValue;
251 0 : xSetAccess->getByName( lPropertyNames[nPropertyCounter] ) >>= sLocaleValue;
252 0 : lProperties[nPropertyCounter].Value <<= sLocaleValue;
253 0 : }
254 :
255 0 : lOutValues[nDestinationCounter] <<= lProperties;
256 0 : }
257 : }
258 : // ... or copy normal items to return lists directly.
259 : else
260 : {
261 0 : lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
262 : }
263 0 : ++nDestinationCounter;
264 0 : }
265 0 : }
266 :
267 0 : void ConfigItem::impl_unpackLocalizedProperties( const Sequence< OUString >& lInNames ,
268 : const Sequence< Any >& lInValues ,
269 : Sequence< OUString >& lOutNames ,
270 : Sequence< Any >& lOutValues )
271 : {
272 : // Safe impossible cases.
273 : // This method should be called for special ConfigItem-mode only!
274 : OSL_ENSURE( ((m_nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES), "ConfigItem::impl_unpackLocalizedProperties()\nWrong call of this method detected!\n" );
275 :
276 : sal_Int32 nSourceCounter; // used to step during input lists
277 : sal_Int32 nSourceSize; // marks end of loop over input lists
278 : sal_Int32 nDestinationCounter; // actual position in output lists
279 : sal_Int32 nPropertyCounter; // counter of inner loop for Sequence< PropertyValue >
280 : sal_Int32 nPropertiesSize; // marks end of inner loop
281 0 : OUString sNodeName; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
282 0 : Sequence< PropertyValue > lProperties; // localized values of an configuration entry getted from lInValues-Any
283 :
284 : // Optimise follow algorithm ... A LITTLE BIT :-)
285 : // There exist two different possibilities:
286 : // i ) There exist no localized entries ... => size of lOutNames/lOutValues will be the same like lInNames/lInValues!
287 : // ii) There exist some (mostly one or two) localized entries ... => size of lOutNames/lOutValues will be some bytes greater then lInNames/lInValues.
288 : // => I think we should make it fast for i). ii) is a special case and mustn't be SOOOO... fast.
289 : // We should reserve same space for output list like input ones first.
290 : // Follow algorithm looks for these borders and change it for ii) only!
291 : // It will be faster then a "realloc()" call in every loop ...
292 0 : nSourceSize = lInNames.getLength();
293 :
294 0 : lOutNames.realloc ( nSourceSize );
295 0 : lOutValues.realloc ( nSourceSize );
296 :
297 : // Algorithm:
298 : // Copy all names and values from const to return lists.
299 : // Look for special localized entries ... You can detect it as Sequence< PropertyValue > packed into an Any.
300 : // Split it ... insert PropertyValue.Name to lOutNames and PropertyValue.Value to lOutValues.
301 :
302 0 : nDestinationCounter = 0;
303 0 : for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
304 : {
305 : // If item a special localized one ... split it and insert his parts to output lists ...
306 0 : if( lInValues[nSourceCounter].getValueType() == ::getCppuType( (const Sequence< PropertyValue >*)NULL ) )
307 : {
308 0 : lInValues[nSourceCounter] >>= lProperties;
309 0 : nPropertiesSize = lProperties.getLength();
310 :
311 0 : sNodeName = lInNames[nSourceCounter] + "/";
312 :
313 0 : if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() )
314 : {
315 0 : lOutNames.realloc ( nDestinationCounter+nPropertiesSize );
316 0 : lOutValues.realloc ( nDestinationCounter+nPropertiesSize );
317 : }
318 :
319 0 : for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
320 : {
321 0 : lOutNames [nDestinationCounter] = sNodeName + lProperties[nPropertyCounter].Name;
322 0 : lOutValues[nDestinationCounter] = lProperties[nPropertyCounter].Value;
323 0 : ++nDestinationCounter;
324 : }
325 : }
326 : // ... or copy normal items to return lists directly.
327 : else
328 : {
329 0 : if( (nDestinationCounter+1) > lOutNames.getLength() )
330 : {
331 0 : lOutNames.realloc ( nDestinationCounter+1 );
332 0 : lOutValues.realloc ( nDestinationCounter+1 );
333 : }
334 :
335 0 : lOutNames [nDestinationCounter] = lInNames [nSourceCounter];
336 0 : lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
337 0 : ++nDestinationCounter;
338 : }
339 0 : }
340 0 : }
341 :
342 0 : Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence< OUString >& rNames)
343 : {
344 : sal_Int32 i;
345 :
346 : // size of return list is fix!
347 : // Every item must match to length of incoming name list.
348 0 : sal_Int32 nCount = rNames.getLength();
349 0 : Sequence< sal_Bool > lStates(nCount);
350 :
351 : // We must be shure to return a valid information everytime!
352 : // Set default to non readonly ... similar to the configuration handling of this property.
353 0 : for ( i=0; i<nCount; ++i)
354 0 : lStates[i] = sal_False;
355 :
356 : // no access - no information ...
357 0 : Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree();
358 0 : if (!xHierarchyAccess.is())
359 0 : return lStates;
360 :
361 0 : for (i=0; i<nCount; ++i)
362 : {
363 : try
364 : {
365 0 : OUString sName = rNames[i];
366 0 : OUString sPath;
367 0 : OUString sProperty;
368 :
369 0 : ::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
370 0 : if (sPath.isEmpty() && sProperty.isEmpty())
371 : {
372 : OSL_FAIL("ConfigItem::IsReadonly()\nsplitt failed\n");
373 0 : continue;
374 : }
375 :
376 0 : Reference< XInterface > xNode;
377 0 : Reference< XPropertySet > xSet;
378 0 : Reference< XPropertySetInfo > xInfo;
379 0 : if (!sPath.isEmpty())
380 : {
381 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(sPath);
382 0 : if (!(aNode >>= xNode) || !xNode.is())
383 : {
384 : OSL_FAIL("ConfigItem::IsReadonly()\nno set available\n");
385 0 : continue;
386 0 : }
387 : }
388 : else
389 : {
390 0 : xNode = xHierarchyAccess;
391 : }
392 :
393 0 : xSet = Reference< XPropertySet >(xNode, UNO_QUERY);
394 0 : if (xSet.is())
395 : {
396 0 : xInfo = xSet->getPropertySetInfo();
397 : OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
398 : }
399 : else
400 : {
401 0 : xInfo = Reference< XPropertySetInfo >(xNode, UNO_QUERY);
402 : OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
403 : }
404 :
405 0 : if (!xInfo.is())
406 : {
407 : OSL_FAIL("ConfigItem::IsReadonly()\nno prop info available\n");
408 0 : continue;
409 : }
410 :
411 0 : Property aProp = xInfo->getPropertyByName(sProperty);
412 0 : lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY);
413 : }
414 0 : catch (const Exception&)
415 : {
416 : }
417 : }
418 :
419 0 : return lStates;
420 : }
421 :
422 0 : Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames)
423 : {
424 0 : Sequence< Any > aRet(rNames.getLength());
425 0 : const OUString* pNames = rNames.getConstArray();
426 0 : Any* pRet = aRet.getArray();
427 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
428 0 : if(xHierarchyAccess.is())
429 : {
430 0 : for(int i = 0; i < rNames.getLength(); i++)
431 : {
432 : try
433 : {
434 0 : pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]);
435 : }
436 0 : catch (const Exception& rEx)
437 : {
438 : SAL_WARN(
439 : "unotools.config",
440 : "ignoring XHierarchicalNameAccess to /org.openoffice."
441 : << sSubTree << "/" << pNames[i] << " Exception: "
442 : << rEx.Message);
443 : }
444 : }
445 :
446 : // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
447 0 : if((m_nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES)
448 : {
449 0 : Sequence< Any > lValues;
450 0 : impl_packLocalizedProperties( rNames, aRet, lValues );
451 0 : aRet = lValues;
452 : }
453 : }
454 0 : return aRet;
455 : }
456 :
457 0 : bool ConfigItem::PutProperties( const Sequence< OUString >& rNames,
458 : const Sequence< Any>& rValues)
459 : {
460 0 : ValueCounter_Impl aCounter(m_nInValueChange);
461 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
462 0 : Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
463 0 : bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is();
464 0 : if(bRet)
465 : {
466 0 : Sequence< OUString > lNames;
467 0 : Sequence< Any > lValues;
468 0 : const OUString* pNames = NULL;
469 0 : const Any* pValues = NULL;
470 : sal_Int32 nNameCount;
471 0 : if(( m_nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES )
472 : {
473 : // If ConfigItem works in "ALL_LOCALES"-mode ... we must support a Sequence< PropertyValue >
474 : // as value of an localized configuration entry!
475 : // How we can do that?
476 : // We must split all PropertyValues to "Sequence< OUString >" AND "Sequence< Any >"!
477 0 : impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues );
478 0 : pNames = lNames.getConstArray ();
479 0 : pValues = lValues.getConstArray ();
480 0 : nNameCount = lNames.getLength ();
481 : }
482 : else
483 : {
484 : // This is the normal mode ...
485 : // Use given input lists directly.
486 0 : pNames = rNames.getConstArray ();
487 0 : pValues = rValues.getConstArray ();
488 0 : nNameCount = rNames.getLength ();
489 : }
490 0 : for(int i = 0; i < nNameCount; i++)
491 : {
492 : try
493 : {
494 0 : OUString sNode, sProperty;
495 0 : if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
496 : {
497 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);
498 :
499 0 : Reference<XNameAccess> xNodeAcc;
500 0 : aNode >>= xNodeAcc;
501 0 : Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY);
502 0 : Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY);
503 :
504 0 : bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
505 0 : if (bExist && xNodeReplace.is())
506 0 : xNodeReplace->replaceByName(sProperty, pValues[i]);
507 : else
508 0 : if (!bExist && xNodeCont.is())
509 0 : xNodeCont->insertByName(sProperty, pValues[i]);
510 : else
511 0 : bRet = false;
512 : }
513 : else //direct value
514 : {
515 0 : xTopNodeReplace->replaceByName(sProperty, pValues[i]);
516 0 : }
517 : }
518 0 : CATCH_INFO("Exception from PutProperties: ");
519 : }
520 : try
521 : {
522 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
523 0 : xBatch->commitChanges();
524 : }
525 0 : CATCH_INFO("Exception from commitChanges(): ")
526 : }
527 :
528 0 : return bRet;
529 : }
530 :
531 0 : void ConfigItem::DisableNotification()
532 : {
533 : OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
534 0 : RemoveChangesListener();
535 0 : }
536 :
537 0 : bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames,
538 : bool bEnableInternalNotification )
539 :
540 : {
541 : OSL_ENSURE(0 == (m_nMode&CONFIG_MODE_RELEASE_TREE), "notification in CONFIG_MODE_RELEASE_TREE mode not possible");
542 0 : m_bEnableInternalNotification = bEnableInternalNotification;
543 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
544 0 : Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
545 0 : if(!xChgNot.is())
546 0 : return false;
547 :
548 : OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
549 0 : if(xChangeLstnr.is())
550 0 : xChgNot->removeChangesListener( xChangeLstnr );
551 0 : bool bRet = true;
552 :
553 : try
554 : {
555 0 : xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
556 0 : xChgNot->addChangesListener( xChangeLstnr );
557 : }
558 0 : catch (const RuntimeException&)
559 : {
560 0 : bRet = false;
561 : }
562 0 : return bRet;
563 : }
564 :
565 0 : void ConfigItem::RemoveChangesListener()
566 : {
567 0 : Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY);
568 0 : if(xChgNot.is() && xChangeLstnr.is())
569 : {
570 : try
571 : {
572 0 : xChgNot->removeChangesListener( xChangeLstnr );
573 0 : xChangeLstnr = 0;
574 : }
575 0 : catch (const Exception&)
576 : {
577 : }
578 0 : }
579 0 : }
580 :
581 0 : static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
582 : {
583 0 : switch (_eFormat)
584 : {
585 : case CONFIG_NAME_LOCAL_NAME:
586 : // unaltered - this is our input format
587 0 : break;
588 :
589 : case CONFIG_NAME_FULL_PATH:
590 : {
591 0 : Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY);
592 0 : if (xFormatter.is())
593 : {
594 0 : OUString * pNames = _rNames.getArray();
595 0 : for(int i = 0; i<_rNames.getLength(); ++i)
596 : {
597 : try
598 : {
599 0 : pNames[i] = xFormatter->composeHierarchicalName(pNames[i]);
600 : }
601 0 : CATCH_INFO("Exception from composeHierarchicalName(): ")
602 : }
603 0 : break;
604 0 : }
605 : }
606 : OSL_FAIL("Cannot create absolute paths: missing interface");
607 : // make local paths instaed
608 :
609 : case CONFIG_NAME_LOCAL_PATH:
610 : {
611 0 : Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY);
612 0 : if (xTypeContainer.is())
613 : {
614 0 : OUString sTypeName = xTypeContainer->getElementTemplateName();
615 0 : sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1);
616 :
617 0 : OUString * pNames = _rNames.getArray();
618 0 : for(int i = 0; i<_rNames.getLength(); ++i)
619 : {
620 0 : pNames[i] = wrapConfigurationElementName(pNames[i],sTypeName);
621 0 : }
622 : }
623 : else
624 : {
625 0 : Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY);
626 0 : if (xSVI.is() && xSVI->supportsService("com.sun.star.configuration.SetAccess"))
627 : {
628 0 : OUString * pNames = _rNames.getArray();
629 0 : for(int i = 0; i<_rNames.getLength(); ++i)
630 : {
631 0 : pNames[i] = wrapConfigurationElementName(pNames[i]);
632 : }
633 0 : }
634 0 : }
635 : }
636 0 : break;
637 :
638 : case CONFIG_NAME_PLAINTEXT_NAME:
639 : {
640 0 : Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY);
641 0 : if (xEscaper.is())
642 : {
643 0 : OUString * pNames = _rNames.getArray();
644 0 : for(int i = 0; i<_rNames.getLength(); ++i)
645 : try
646 : {
647 0 : pNames[i] = xEscaper->unescapeString(pNames[i]);
648 : }
649 0 : CATCH_INFO("Exception from unescapeString(): ")
650 0 : }
651 : }
652 0 : break;
653 :
654 : }
655 0 : }
656 :
657 0 : Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode)
658 : {
659 0 : ConfigNameFormat const eDefaultFormat = CONFIG_NAME_LOCAL_NAME; // CONFIG_NAME_DEFAULT;
660 :
661 0 : return GetNodeNames(rNode, eDefaultFormat);
662 : }
663 :
664 0 : Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat)
665 : {
666 0 : Sequence< OUString > aRet;
667 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
668 0 : if(xHierarchyAccess.is())
669 : {
670 : try
671 : {
672 0 : Reference<XNameAccess> xCont;
673 0 : if(!rNode.isEmpty())
674 : {
675 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
676 0 : aNode >>= xCont;
677 : }
678 : else
679 0 : xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY);
680 0 : if(xCont.is())
681 : {
682 0 : aRet = xCont->getElementNames();
683 0 : lcl_normalizeLocalNames(aRet,eFormat,xCont);
684 0 : }
685 :
686 : }
687 0 : CATCH_INFO("Exception from GetNodeNames: ");
688 : }
689 0 : return aRet;
690 : }
691 :
692 0 : bool ConfigItem::ClearNodeSet(const OUString& rNode)
693 : {
694 0 : ValueCounter_Impl aCounter(m_nInValueChange);
695 0 : bool bRet = false;
696 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
697 0 : if(xHierarchyAccess.is())
698 : {
699 : try
700 : {
701 0 : Reference<XNameContainer> xCont;
702 0 : if(!rNode.isEmpty())
703 : {
704 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
705 0 : aNode >>= xCont;
706 : }
707 : else
708 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
709 0 : if(!xCont.is())
710 0 : return false;
711 0 : Sequence< OUString > aNames = xCont->getElementNames();
712 0 : const OUString* pNames = aNames.getConstArray();
713 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
714 0 : for(sal_Int32 i = 0; i < aNames.getLength(); i++)
715 : {
716 : try
717 : {
718 0 : xCont->removeByName(pNames[i]);
719 : }
720 0 : CATCH_INFO("Exception from removeByName(): ")
721 : }
722 0 : xBatch->commitChanges();
723 0 : bRet = true;
724 : }
725 0 : CATCH_INFO("Exception from ClearNodeSet")
726 : }
727 0 : return bRet;
728 : }
729 :
730 0 : bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements)
731 : {
732 0 : ValueCounter_Impl aCounter(m_nInValueChange);
733 0 : bool bRet = false;
734 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
735 0 : if(xHierarchyAccess.is())
736 : {
737 0 : const OUString* pElements = rElements.getConstArray();
738 : try
739 : {
740 0 : Reference<XNameContainer> xCont;
741 0 : if(!rNode.isEmpty())
742 : {
743 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
744 0 : aNode >>= xCont;
745 : }
746 : else
747 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
748 0 : if(!xCont.is())
749 0 : return false;
750 : try
751 : {
752 0 : for(sal_Int32 nElement = 0; nElement < rElements.getLength(); nElement++)
753 : {
754 0 : xCont->removeByName(pElements[nElement]);
755 : }
756 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
757 0 : xBatch->commitChanges();
758 : }
759 0 : CATCH_INFO("Exception from commitChanges(): ")
760 0 : bRet = true;
761 : }
762 0 : CATCH_INFO("Exception from GetNodeNames: ")
763 : }
764 0 : return bRet;
765 : }
766 :
767 : static inline
768 0 : OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix )
769 : {
770 0 : OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
771 0 : return extractFirstFromConfigurationPath( sSubPath );
772 : }
773 :
774 : static
775 0 : Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix )
776 : {
777 0 : const PropertyValue* pProperties = rValues.getConstArray();
778 :
779 0 : Sequence< OUString > aSubNodeNames(rValues.getLength());
780 0 : OUString* pSubNodeNames = aSubNodeNames.getArray();
781 :
782 0 : OUString sLastSubNode;
783 0 : sal_Int32 nSubIndex = 0;
784 :
785 0 : for(sal_Int32 i = 0; i < rValues.getLength(); i++)
786 : {
787 0 : OUString const sSubPath = dropPrefixFromConfigurationPath( pProperties[i].Name, rPrefix);
788 0 : OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath );
789 :
790 0 : if(sLastSubNode != sSubNode)
791 : {
792 0 : pSubNodeNames[nSubIndex++] = sSubNode;
793 : }
794 :
795 0 : sLastSubNode = sSubNode;
796 0 : }
797 0 : aSubNodeNames.realloc(nSubIndex);
798 :
799 0 : return aSubNodeNames;
800 : }
801 :
802 : // Add or change properties
803 0 : bool ConfigItem::SetSetProperties(
804 : const OUString& rNode, Sequence< PropertyValue > rValues)
805 : {
806 0 : ValueCounter_Impl aCounter(m_nInValueChange);
807 0 : bool bRet = true;
808 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
809 0 : if(xHierarchyAccess.is())
810 : {
811 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
812 : try
813 : {
814 0 : Reference<XNameContainer> xCont;
815 0 : if(!rNode.isEmpty())
816 : {
817 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
818 0 : aNode >>= xCont;
819 : }
820 : else
821 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
822 0 : if(!xCont.is())
823 0 : return false;
824 :
825 0 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
826 :
827 0 : if(xFac.is())
828 : {
829 0 : const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
830 :
831 0 : const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
832 :
833 0 : for(sal_Int32 j = 0; j <nSubNodeCount; j++)
834 : {
835 0 : if(!xCont->hasByName(aSubNodeNames[j]))
836 : {
837 0 : Reference<XInterface> xInst = xFac->createInstance();
838 0 : Any aVal; aVal <<= xInst;
839 0 : xCont->insertByName(aSubNodeNames[j], aVal);
840 : }
841 : //set values
842 : }
843 : try
844 : {
845 0 : xBatch->commitChanges();
846 : }
847 0 : CATCH_INFO("Exception from commitChanges(): ")
848 :
849 0 : const PropertyValue* pProperties = rValues.getConstArray();
850 :
851 0 : Sequence< OUString > aSetNames(rValues.getLength());
852 0 : OUString* pSetNames = aSetNames.getArray();
853 :
854 0 : Sequence< Any> aSetValues(rValues.getLength());
855 0 : Any* pSetValues = aSetValues.getArray();
856 :
857 0 : bool bEmptyNode = rNode.isEmpty();
858 0 : for(sal_Int32 k = 0; k < rValues.getLength(); k++)
859 : {
860 0 : pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
861 0 : pSetValues[k] = pProperties[k].Value;
862 : }
863 0 : bRet = PutProperties(aSetNames, aSetValues);
864 : }
865 : else
866 : {
867 : //if no factory is available then the node contains basic data elements
868 0 : const PropertyValue* pValues = rValues.getConstArray();
869 0 : for(int nValue = 0; nValue < rValues.getLength();nValue++)
870 : {
871 : try
872 : {
873 0 : OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
874 :
875 0 : if(xCont->hasByName(sSubNode))
876 0 : xCont->replaceByName(sSubNode, pValues[nValue].Value);
877 : else
878 0 : xCont->insertByName(sSubNode, pValues[nValue].Value);
879 :
880 : OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(pValues[nValue].Name),
881 0 : "Invalid config path" );
882 : }
883 0 : CATCH_INFO("Exception form insert/replaceByName(): ")
884 : }
885 0 : xBatch->commitChanges();
886 0 : }
887 : }
888 : #ifdef DBG_UTIL
889 : catch (const Exception& rEx)
890 : {
891 : lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx);
892 : #else
893 0 : catch (const Exception&)
894 : {
895 : #endif
896 0 : bRet = false;
897 0 : }
898 : }
899 0 : return bRet;
900 : }
901 :
902 0 : bool ConfigItem::ReplaceSetProperties(
903 : const OUString& rNode, Sequence< PropertyValue > rValues)
904 : {
905 0 : ValueCounter_Impl aCounter(m_nInValueChange);
906 0 : bool bRet = true;
907 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
908 0 : if(xHierarchyAccess.is())
909 : {
910 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
911 : try
912 : {
913 0 : Reference<XNameContainer> xCont;
914 0 : if(!rNode.isEmpty())
915 : {
916 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
917 0 : aNode >>= xCont;
918 : }
919 : else
920 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
921 0 : if(!xCont.is())
922 0 : return false;
923 :
924 : // JB: Change: now the same name handling for sets of simple values
925 0 : const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
926 0 : const OUString* pSubNodeNames = aSubNodeNames.getConstArray();
927 0 : const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
928 :
929 0 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
930 0 : const bool isSimpleValueSet = !xFac.is();
931 :
932 : //remove unknown members first
933 : {
934 0 : const Sequence<OUString> aContainerSubNodes = xCont->getElementNames();
935 0 : const OUString* pContainerSubNodes = aContainerSubNodes.getConstArray();
936 :
937 0 : for(sal_Int32 nContSub = 0; nContSub < aContainerSubNodes.getLength(); nContSub++)
938 : {
939 0 : bool bFound = false;
940 0 : for(sal_Int32 j = 0; j < nSubNodeCount; j++)
941 : {
942 0 : if(pSubNodeNames[j] == pContainerSubNodes[nContSub])
943 : {
944 0 : bFound = true;
945 0 : break;
946 : }
947 : }
948 0 : if(!bFound)
949 : try
950 : {
951 0 : xCont->removeByName(pContainerSubNodes[nContSub]);
952 : }
953 0 : catch (const Exception&)
954 : {
955 0 : if (isSimpleValueSet)
956 : {
957 : try
958 : {
959 : // #i37322#: fallback action: replace with <void/>
960 0 : xCont->replaceByName(pContainerSubNodes[nContSub], Any());
961 : // fallback successful: continue looping
962 0 : continue;
963 : }
964 0 : catch (Exception &)
965 : {} // propagate original exception, if fallback fails
966 : }
967 0 : throw;
968 : }
969 : }
970 0 : try { xBatch->commitChanges(); }
971 0 : CATCH_INFO("Exception from commitChanges(): ")
972 : }
973 :
974 0 : if(xFac.is()) // !isSimpleValueSet
975 : {
976 0 : for(sal_Int32 j = 0; j < nSubNodeCount; j++)
977 : {
978 0 : if(!xCont->hasByName(pSubNodeNames[j]))
979 : {
980 : //create if not available
981 0 : Reference<XInterface> xInst = xFac->createInstance();
982 0 : Any aVal; aVal <<= xInst;
983 0 : xCont->insertByName(pSubNodeNames[j], aVal);
984 : }
985 : }
986 0 : try { xBatch->commitChanges(); }
987 0 : CATCH_INFO("Exception from commitChanges(): ")
988 :
989 0 : const PropertyValue* pProperties = rValues.getConstArray();
990 :
991 0 : Sequence< OUString > aSetNames(rValues.getLength());
992 0 : OUString* pSetNames = aSetNames.getArray();
993 :
994 0 : Sequence< Any> aSetValues(rValues.getLength());
995 0 : Any* pSetValues = aSetValues.getArray();
996 :
997 0 : bool bEmptyNode = rNode.isEmpty();
998 0 : for(sal_Int32 k = 0; k < rValues.getLength(); k++)
999 : {
1000 0 : pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
1001 0 : pSetValues[k] = pProperties[k].Value;
1002 : }
1003 0 : bRet = PutProperties(aSetNames, aSetValues);
1004 : }
1005 : else
1006 : {
1007 0 : const PropertyValue* pValues = rValues.getConstArray();
1008 :
1009 : //if no factory is available then the node contains basic data elements
1010 0 : for(int nValue = 0; nValue < rValues.getLength();nValue++)
1011 : {
1012 : try
1013 : {
1014 0 : OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
1015 :
1016 0 : if(xCont->hasByName(sSubNode))
1017 0 : xCont->replaceByName(sSubNode, pValues[nValue].Value);
1018 : else
1019 0 : xCont->insertByName(sSubNode, pValues[nValue].Value);
1020 : }
1021 0 : CATCH_INFO("Exception from insert/replaceByName(): ");
1022 : }
1023 0 : xBatch->commitChanges();
1024 0 : }
1025 : }
1026 : #ifdef DBG_UTIL
1027 : catch (const Exception& rEx)
1028 : {
1029 : lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx);
1030 : #else
1031 0 : catch (const Exception&)
1032 : {
1033 : #endif
1034 0 : bRet = false;
1035 0 : }
1036 : }
1037 0 : return bRet;
1038 : }
1039 :
1040 0 : bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode)
1041 : {
1042 0 : ValueCounter_Impl aCounter(m_nInValueChange);
1043 0 : bool bRet = true;
1044 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1045 0 : if(xHierarchyAccess.is())
1046 : {
1047 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
1048 : try
1049 : {
1050 0 : Reference<XNameContainer> xCont;
1051 0 : if(!rNode.isEmpty())
1052 : {
1053 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
1054 0 : aNode >>= xCont;
1055 : }
1056 : else
1057 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1058 0 : if(!xCont.is())
1059 0 : return false;
1060 :
1061 0 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1062 :
1063 0 : if(xFac.is())
1064 : {
1065 0 : if(!xCont->hasByName(rNewNode))
1066 : {
1067 0 : Reference<XInterface> xInst = xFac->createInstance();
1068 0 : Any aVal; aVal <<= xInst;
1069 0 : xCont->insertByName(rNewNode, aVal);
1070 : }
1071 : try
1072 : {
1073 0 : xBatch->commitChanges();
1074 : }
1075 0 : CATCH_INFO("Exception from commitChanges(): ")
1076 : }
1077 : else
1078 : {
1079 : //if no factory is available then the node contains basic data elements
1080 : try
1081 : {
1082 0 : if(!xCont->hasByName(rNewNode))
1083 0 : xCont->insertByName(rNewNode, Any());
1084 : }
1085 0 : CATCH_INFO("Exception from AddNode(): ")
1086 : }
1087 0 : xBatch->commitChanges();
1088 : }
1089 : #ifdef DBG_UTIL
1090 : catch (const Exception& rEx)
1091 : {
1092 : lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx);
1093 : #else
1094 0 : catch (const Exception&)
1095 : {
1096 : #endif
1097 0 : bRet = false;
1098 0 : }
1099 : }
1100 0 : return bRet;
1101 : }
1102 :
1103 0 : sal_Int16 ConfigItem::GetMode() const
1104 : {
1105 0 : return m_nMode;
1106 : }
1107 :
1108 0 : void ConfigItem::SetModified()
1109 : {
1110 0 : m_bIsModified = true;
1111 0 : }
1112 :
1113 0 : void ConfigItem::ClearModified()
1114 : {
1115 0 : m_bIsModified = false;
1116 0 : }
1117 :
1118 0 : bool ConfigItem::IsModified() const
1119 : {
1120 0 : return m_bIsModified;
1121 : }
1122 :
1123 0 : bool ConfigItem::IsInValueChange() const
1124 : {
1125 0 : return m_nInValueChange > 0;
1126 : }
1127 :
1128 0 : Reference< XHierarchicalNameAccess> ConfigItem::GetTree()
1129 : {
1130 0 : Reference< XHierarchicalNameAccess> xRet;
1131 0 : if(!m_xHierarchyAccess.is())
1132 0 : xRet = ConfigManager::acquireTree(*this);
1133 : else
1134 0 : xRet = m_xHierarchyAccess;
1135 0 : return xRet;
1136 : }
1137 :
1138 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|