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 4736 : ValueCounter_Impl(sal_Int16& rCounter):
101 4736 : rCnt(rCounter)
102 4736 : {rCnt++;}
103 4736 : ~ValueCounter_Impl()
104 : {
105 : OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
106 4736 : rCnt--;
107 4736 : }
108 : };
109 :
110 20840 : ConfigChangeListener_Impl::ConfigChangeListener_Impl(
111 : ConfigItem& rItem, const Sequence< OUString >& rNames) :
112 : pParent(&rItem),
113 20840 : aPropertyNames(rNames)
114 : {
115 20840 : }
116 :
117 38700 : ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
118 : {
119 38700 : }
120 :
121 44854 : 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 434752 : for(sal_Int32 nIndex = 0; nIndex < nLength; nIndex++)
129 417936 : if( isPrefixOfConfigurationPath(rTemp, pCheckPropertyNames[nIndex]) )
130 28038 : return true;
131 16816 : return false;
132 : }
133 :
134 36244 : void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) throw(RuntimeException, std::exception)
135 : {
136 36244 : const ElementChange* pElementChanges = rEvent.Changes.getConstArray();
137 :
138 36244 : Sequence<OUString> aChangedNames(rEvent.Changes.getLength());
139 36244 : OUString* pNames = aChangedNames.getArray();
140 :
141 36244 : const OUString* pCheckPropertyNames = aPropertyNames.getConstArray();
142 :
143 36244 : sal_Int32 nNotify = 0;
144 81098 : for(int i = 0; i < aChangedNames.getLength(); i++)
145 : {
146 44854 : OUString sTemp;
147 44854 : pElementChanges[i].Accessor >>= sTemp;
148 44854 : if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength()))
149 28038 : pNames[nNotify++] = sTemp;
150 44854 : }
151 36244 : if( nNotify )
152 : {
153 23746 : if ( ::tools::SolarMutex::Acquire() )
154 : {
155 23746 : aChangedNames.realloc(nNotify);
156 23746 : pParent->CallNotify(aChangedNames);
157 23746 : ::tools::SolarMutex::Release();
158 : }
159 36244 : }
160 36244 : }
161 :
162 0 : void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException, std::exception)
163 : {
164 0 : pParent->RemoveChangesListener();
165 0 : }
166 :
167 40035 : ConfigItem::ConfigItem(const OUString &rSubTree, sal_Int16 nSetMode ) :
168 : sSubTree(rSubTree),
169 : m_nMode(nSetMode),
170 : m_bIsModified(false),
171 : m_bEnableInternalNotification(false),
172 40035 : m_nInValueChange(0)
173 : {
174 40035 : if(0 != (nSetMode&CONFIG_MODE_RELEASE_TREE))
175 1500 : ConfigManager::getConfigManager().addConfigItem(*this);
176 : else
177 38535 : m_xHierarchyAccess = ConfigManager::getConfigManager().addConfigItem(*this);
178 40035 : }
179 :
180 75306 : ConfigItem::~ConfigItem()
181 : {
182 37653 : RemoveChangesListener();
183 37653 : ConfigManager::getConfigManager().removeConfigItem(*this);
184 37653 : }
185 :
186 23746 : 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 23746 : if(!IsInValueChange() || m_bEnableInternalNotification)
192 180 : Notify(rPropertyNames);
193 23746 : }
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 0 : lProperties[nPropertyCounter].Name = lPropertyNames[nPropertyCounter];
245 0 : OUString sLocaleValue;
246 0 : xSetAccess->getByName( lPropertyNames[nPropertyCounter] ) >>= sLocaleValue;
247 0 : lProperties[nPropertyCounter].Value <<= sLocaleValue;
248 0 : }
249 :
250 0 : lOutValues[nDestinationCounter] <<= lProperties;
251 0 : }
252 : }
253 : // ... or copy normal items to return lists directly.
254 : else
255 : {
256 0 : lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
257 : }
258 0 : ++nDestinationCounter;
259 0 : }
260 0 : }
261 :
262 0 : void ConfigItem::impl_unpackLocalizedProperties( const Sequence< OUString >& lInNames ,
263 : const Sequence< Any >& lInValues ,
264 : Sequence< OUString >& lOutNames ,
265 : Sequence< Any >& lOutValues )
266 : {
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" );
270 :
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 0 : OUString sNodeName; // base name of node ( e.g. "UIName/" ) ... expand to locale ( e.g. "UIName/de" )
277 0 : Sequence< PropertyValue > lProperties; // localized values of an configuration entry getted from lInValues-Any
278 :
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 0 : nSourceSize = lInNames.getLength();
288 :
289 0 : lOutNames.realloc ( nSourceSize );
290 0 : lOutValues.realloc ( nSourceSize );
291 :
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.
296 :
297 0 : nDestinationCounter = 0;
298 0 : for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
299 : {
300 : // If item a special localized one ... split it and insert his parts to output lists ...
301 0 : if( lInValues[nSourceCounter].getValueType() == ::getCppuType( (const Sequence< PropertyValue >*)NULL ) )
302 : {
303 0 : lInValues[nSourceCounter] >>= lProperties;
304 0 : nPropertiesSize = lProperties.getLength();
305 :
306 0 : sNodeName = lInNames[nSourceCounter] + "/";
307 :
308 0 : if( (nDestinationCounter+nPropertiesSize) > lOutNames.getLength() )
309 : {
310 0 : lOutNames.realloc ( nDestinationCounter+nPropertiesSize );
311 0 : lOutValues.realloc ( nDestinationCounter+nPropertiesSize );
312 : }
313 :
314 0 : for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
315 : {
316 0 : lOutNames [nDestinationCounter] = sNodeName + lProperties[nPropertyCounter].Name;
317 0 : lOutValues[nDestinationCounter] = lProperties[nPropertyCounter].Value;
318 0 : ++nDestinationCounter;
319 : }
320 : }
321 : // ... or copy normal items to return lists directly.
322 : else
323 : {
324 0 : if( (nDestinationCounter+1) > lOutNames.getLength() )
325 : {
326 0 : lOutNames.realloc ( nDestinationCounter+1 );
327 0 : lOutValues.realloc ( nDestinationCounter+1 );
328 : }
329 :
330 0 : lOutNames [nDestinationCounter] = lInNames [nSourceCounter];
331 0 : lOutValues[nDestinationCounter] = lInValues[nSourceCounter];
332 0 : ++nDestinationCounter;
333 : }
334 0 : }
335 0 : }
336 :
337 1630 : Sequence< sal_Bool > ConfigItem::GetReadOnlyStates(const com::sun::star::uno::Sequence< OUString >& rNames)
338 : {
339 : sal_Int32 i;
340 :
341 : // size of return list is fix!
342 : // Every item must match to length of incoming name list.
343 1630 : sal_Int32 nCount = rNames.getLength();
344 1630 : Sequence< sal_Bool > lStates(nCount);
345 :
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 21120 : for ( i=0; i<nCount; ++i)
349 19490 : lStates[i] = sal_False;
350 :
351 : // no access - no information ...
352 3260 : Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree();
353 1630 : if (!xHierarchyAccess.is())
354 0 : return lStates;
355 :
356 21120 : for (i=0; i<nCount; ++i)
357 : {
358 : try
359 : {
360 19490 : OUString sName = rNames[i];
361 38980 : OUString sPath;
362 38980 : OUString sProperty;
363 :
364 19490 : (void)::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
365 19490 : if (sPath.isEmpty() && sProperty.isEmpty())
366 : {
367 : OSL_FAIL("ConfigItem::IsReadonly()\nsplitt failed\n");
368 0 : continue;
369 : }
370 :
371 38980 : Reference< XInterface > xNode;
372 38980 : Reference< XPropertySet > xSet;
373 38980 : Reference< XPropertySetInfo > xInfo;
374 19490 : if (!sPath.isEmpty())
375 : {
376 7596 : Any aNode = xHierarchyAccess->getByHierarchicalName(sPath);
377 7596 : if (!(aNode >>= xNode) || !xNode.is())
378 : {
379 : OSL_FAIL("ConfigItem::IsReadonly()\nno set available\n");
380 0 : continue;
381 7596 : }
382 : }
383 : else
384 : {
385 11894 : xNode = Reference<XInterface>( xHierarchyAccess, UNO_QUERY );
386 : }
387 :
388 19490 : xSet = Reference< XPropertySet >(xNode, UNO_QUERY);
389 19490 : if (xSet.is())
390 : {
391 19490 : xInfo = xSet->getPropertySetInfo();
392 : OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\ngetPropertySetInfo failed ...\n");
393 : }
394 : else
395 : {
396 0 : xInfo = Reference< XPropertySetInfo >(xNode, UNO_QUERY);
397 : OSL_ENSURE(xInfo.is(), "ConfigItem::IsReadonly()\nUNO_QUERY failed ...\n");
398 : }
399 :
400 19490 : if (!xInfo.is())
401 : {
402 : OSL_FAIL("ConfigItem::IsReadonly()\nno prop info available\n");
403 0 : continue;
404 : }
405 :
406 38980 : Property aProp = xInfo->getPropertyByName(sProperty);
407 38980 : lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY);
408 : }
409 0 : catch (const Exception&)
410 : {
411 : }
412 : }
413 :
414 1630 : return lStates;
415 : }
416 :
417 189485 : Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames)
418 : {
419 189485 : Sequence< Any > aRet(rNames.getLength());
420 189485 : const OUString* pNames = rNames.getConstArray();
421 189485 : Any* pRet = aRet.getArray();
422 378970 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
423 189485 : if(xHierarchyAccess.is())
424 : {
425 1405068 : for(int i = 0; i < rNames.getLength(); i++)
426 : {
427 : try
428 : {
429 1215583 : pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]);
430 : }
431 4 : catch (const Exception& rEx)
432 : {
433 : SAL_WARN(
434 : "unotools.config",
435 : "ignoring XHierarchicalNameAccess to /org.openoffice."
436 : << sSubTree << "/" << pNames[i] << " Exception: "
437 : << rEx.Message);
438 : }
439 : }
440 :
441 : // In special mode "ALL_LOCALES" we must convert localized values to Sequence< PropertyValue >.
442 189485 : if((m_nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES)
443 : {
444 0 : Sequence< Any > lValues;
445 0 : impl_packLocalizedProperties( rNames, aRet, lValues );
446 0 : aRet = lValues;
447 : }
448 : }
449 378970 : return aRet;
450 : }
451 :
452 3724 : bool ConfigItem::PutProperties( const Sequence< OUString >& rNames,
453 : const Sequence< Any>& rValues)
454 : {
455 3724 : ValueCounter_Impl aCounter(m_nInValueChange);
456 7448 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
457 7448 : Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
458 3724 : bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is();
459 3724 : if(bRet)
460 : {
461 3724 : Sequence< OUString > lNames;
462 7448 : Sequence< Any > lValues;
463 3724 : const OUString* pNames = NULL;
464 3724 : const Any* pValues = NULL;
465 : sal_Int32 nNameCount;
466 3724 : if(( m_nMode & CONFIG_MODE_ALL_LOCALES ) == CONFIG_MODE_ALL_LOCALES )
467 : {
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 0 : impl_unpackLocalizedProperties( rNames, rValues, lNames, lValues );
473 0 : pNames = lNames.getConstArray ();
474 0 : pValues = lValues.getConstArray ();
475 0 : nNameCount = lNames.getLength ();
476 : }
477 : else
478 : {
479 : // This is the normal mode ...
480 : // Use given input lists directly.
481 3724 : pNames = rNames.getConstArray ();
482 3724 : pValues = rValues.getConstArray ();
483 3724 : nNameCount = rNames.getLength ();
484 : }
485 29196 : for(int i = 0; i < nNameCount; i++)
486 : {
487 : try
488 : {
489 50944 : OUString sNode, sProperty;
490 25472 : if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
491 : {
492 3350 : Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);
493 :
494 6700 : Reference<XNameAccess> xNodeAcc;
495 3350 : aNode >>= xNodeAcc;
496 6700 : Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY);
497 6700 : Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY);
498 :
499 3350 : bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
500 3350 : if (bExist && xNodeReplace.is())
501 3350 : xNodeReplace->replaceByName(sProperty, pValues[i]);
502 : else
503 0 : if (!bExist && xNodeCont.is())
504 0 : xNodeCont->insertByName(sProperty, pValues[i]);
505 : else
506 3350 : bRet = false;
507 : }
508 : else //direct value
509 : {
510 22122 : xTopNodeReplace->replaceByName(sProperty, pValues[i]);
511 25472 : }
512 : }
513 0 : CATCH_INFO("Exception from PutProperties: ");
514 : }
515 : try
516 : {
517 3724 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
518 3724 : xBatch->commitChanges();
519 : }
520 3724 : CATCH_INFO("Exception from commitChanges(): ")
521 : }
522 :
523 7448 : return bRet;
524 : }
525 :
526 5450 : void ConfigItem::DisableNotification()
527 : {
528 : OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
529 5450 : RemoveChangesListener();
530 5450 : }
531 :
532 20840 : bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames,
533 : bool bEnableInternalNotification )
534 :
535 : {
536 : OSL_ENSURE(0 == (m_nMode&CONFIG_MODE_RELEASE_TREE), "notification in CONFIG_MODE_RELEASE_TREE mode not possible");
537 20840 : m_bEnableInternalNotification = bEnableInternalNotification;
538 20840 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
539 41680 : Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
540 20840 : if(!xChgNot.is())
541 0 : return false;
542 :
543 : OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
544 20840 : if(xChangeLstnr.is())
545 0 : xChgNot->removeChangesListener( xChangeLstnr );
546 20840 : bool bRet = true;
547 :
548 : try
549 : {
550 20840 : xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
551 20840 : xChgNot->addChangesListener( xChangeLstnr );
552 : }
553 0 : catch (const RuntimeException&)
554 : {
555 0 : bRet = false;
556 : }
557 41680 : return bRet;
558 : }
559 :
560 43103 : void ConfigItem::RemoveChangesListener()
561 : {
562 43103 : Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY);
563 43103 : if(xChgNot.is() && xChangeLstnr.is())
564 : {
565 : try
566 : {
567 19350 : xChgNot->removeChangesListener( xChangeLstnr );
568 19350 : xChangeLstnr = 0;
569 : }
570 0 : catch (const Exception&)
571 : {
572 : }
573 43103 : }
574 43103 : }
575 :
576 56169 : static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
577 : {
578 56169 : switch (_eFormat)
579 : {
580 : case CONFIG_NAME_LOCAL_NAME:
581 : // unaltered - this is our input format
582 54973 : break;
583 :
584 : case CONFIG_NAME_FULL_PATH:
585 : {
586 0 : Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY);
587 0 : if (xFormatter.is())
588 : {
589 0 : OUString * pNames = _rNames.getArray();
590 0 : for(int i = 0; i<_rNames.getLength(); ++i)
591 : {
592 : try
593 : {
594 0 : pNames[i] = xFormatter->composeHierarchicalName(pNames[i]);
595 : }
596 0 : CATCH_INFO("Exception from composeHierarchicalName(): ")
597 : }
598 0 : break;
599 0 : }
600 : }
601 : OSL_FAIL("Cannot create absolute paths: missing interface");
602 : // make local paths instaed
603 :
604 : case CONFIG_NAME_LOCAL_PATH:
605 : {
606 1196 : Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY);
607 1196 : if (xTypeContainer.is())
608 : {
609 0 : OUString sTypeName = xTypeContainer->getElementTemplateName();
610 0 : sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1);
611 :
612 0 : OUString * pNames = _rNames.getArray();
613 0 : for(int i = 0; i<_rNames.getLength(); ++i)
614 : {
615 0 : pNames[i] = wrapConfigurationElementName(pNames[i],sTypeName);
616 0 : }
617 : }
618 : else
619 : {
620 1196 : Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY);
621 1196 : if (xSVI.is() && xSVI->supportsService("com.sun.star.configuration.SetAccess"))
622 : {
623 1196 : OUString * pNames = _rNames.getArray();
624 4286 : for(int i = 0; i<_rNames.getLength(); ++i)
625 : {
626 3090 : pNames[i] = wrapConfigurationElementName(pNames[i]);
627 : }
628 1196 : }
629 1196 : }
630 : }
631 1196 : break;
632 :
633 : case CONFIG_NAME_PLAINTEXT_NAME:
634 : {
635 0 : Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY);
636 0 : if (xEscaper.is())
637 : {
638 0 : OUString * pNames = _rNames.getArray();
639 0 : for(int i = 0; i<_rNames.getLength(); ++i)
640 : try
641 : {
642 0 : pNames[i] = xEscaper->unescapeString(pNames[i]);
643 : }
644 0 : CATCH_INFO("Exception from unescapeString(): ")
645 0 : }
646 : }
647 0 : break;
648 :
649 : }
650 56169 : }
651 :
652 54973 : Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode)
653 : {
654 54973 : ConfigNameFormat const eDefaultFormat = CONFIG_NAME_LOCAL_NAME; // CONFIG_NAME_DEFAULT;
655 :
656 54973 : return GetNodeNames(rNode, eDefaultFormat);
657 : }
658 :
659 56169 : Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat)
660 : {
661 56169 : Sequence< OUString > aRet;
662 112338 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
663 56169 : if(xHierarchyAccess.is())
664 : {
665 : try
666 : {
667 56169 : Reference<XNameAccess> xCont;
668 56169 : if(!rNode.isEmpty())
669 : {
670 55675 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
671 55675 : aNode >>= xCont;
672 : }
673 : else
674 494 : xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY);
675 56169 : if(xCont.is())
676 : {
677 56169 : aRet = xCont->getElementNames();
678 56169 : lcl_normalizeLocalNames(aRet,eFormat,xCont);
679 56169 : }
680 :
681 : }
682 0 : CATCH_INFO("Exception from GetNodeNames: ");
683 : }
684 112338 : return aRet;
685 : }
686 :
687 8 : bool ConfigItem::ClearNodeSet(const OUString& rNode)
688 : {
689 8 : ValueCounter_Impl aCounter(m_nInValueChange);
690 8 : bool bRet = false;
691 16 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
692 8 : if(xHierarchyAccess.is())
693 : {
694 : try
695 : {
696 8 : Reference<XNameContainer> xCont;
697 8 : if(!rNode.isEmpty())
698 : {
699 8 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
700 8 : aNode >>= xCont;
701 : }
702 : else
703 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
704 8 : if(!xCont.is())
705 0 : return false;
706 16 : Sequence< OUString > aNames = xCont->getElementNames();
707 8 : const OUString* pNames = aNames.getConstArray();
708 16 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
709 38 : for(sal_Int32 i = 0; i < aNames.getLength(); i++)
710 : {
711 : try
712 : {
713 30 : xCont->removeByName(pNames[i]);
714 : }
715 0 : CATCH_INFO("Exception from removeByName(): ")
716 : }
717 8 : xBatch->commitChanges();
718 16 : bRet = true;
719 : }
720 0 : CATCH_INFO("Exception from ClearNodeSet")
721 : }
722 16 : return bRet;
723 : }
724 :
725 50 : bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements)
726 : {
727 50 : ValueCounter_Impl aCounter(m_nInValueChange);
728 50 : bool bRet = false;
729 100 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
730 50 : if(xHierarchyAccess.is())
731 : {
732 50 : const OUString* pElements = rElements.getConstArray();
733 : try
734 : {
735 50 : Reference<XNameContainer> xCont;
736 50 : if(!rNode.isEmpty())
737 : {
738 50 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
739 50 : aNode >>= xCont;
740 : }
741 : else
742 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
743 50 : if(!xCont.is())
744 0 : return false;
745 : try
746 : {
747 70 : for(sal_Int32 nElement = 0; nElement < rElements.getLength(); nElement++)
748 : {
749 50 : xCont->removeByName(pElements[nElement]);
750 : }
751 20 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
752 20 : xBatch->commitChanges();
753 : }
754 30 : CATCH_INFO("Exception from commitChanges(): ")
755 50 : bRet = true;
756 : }
757 0 : CATCH_INFO("Exception from GetNodeNames: ")
758 : }
759 100 : return bRet;
760 : }
761 :
762 : static inline
763 6160 : OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix )
764 : {
765 6160 : OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
766 6160 : return extractFirstFromConfigurationPath( sSubPath );
767 : }
768 :
769 : static
770 954 : Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix )
771 : {
772 954 : const PropertyValue* pProperties = rValues.getConstArray();
773 :
774 954 : Sequence< OUString > aSubNodeNames(rValues.getLength());
775 954 : OUString* pSubNodeNames = aSubNodeNames.getArray();
776 :
777 1908 : OUString sLastSubNode;
778 954 : sal_Int32 nSubIndex = 0;
779 :
780 8532 : for(sal_Int32 i = 0; i < rValues.getLength(); i++)
781 : {
782 7578 : OUString const sSubPath = dropPrefixFromConfigurationPath( pProperties[i].Name, rPrefix);
783 15156 : OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath );
784 :
785 7578 : if(sLastSubNode != sSubNode)
786 : {
787 6234 : pSubNodeNames[nSubIndex++] = sSubNode;
788 : }
789 :
790 7578 : sLastSubNode = sSubNode;
791 7578 : }
792 954 : aSubNodeNames.realloc(nSubIndex);
793 :
794 1908 : return aSubNodeNames;
795 : }
796 :
797 : // Add or change properties
798 74 : bool ConfigItem::SetSetProperties(
799 : const OUString& rNode, const Sequence< PropertyValue >& rValues)
800 : {
801 74 : ValueCounter_Impl aCounter(m_nInValueChange);
802 74 : bool bRet = true;
803 148 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
804 74 : if(xHierarchyAccess.is())
805 : {
806 74 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
807 : try
808 : {
809 74 : Reference<XNameContainer> xCont;
810 74 : if(!rNode.isEmpty())
811 : {
812 74 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
813 74 : aNode >>= xCont;
814 : }
815 : else
816 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
817 74 : if(!xCont.is())
818 0 : return false;
819 :
820 148 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
821 :
822 74 : if(xFac.is())
823 : {
824 74 : const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
825 :
826 74 : const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
827 :
828 148 : for(sal_Int32 j = 0; j <nSubNodeCount; j++)
829 : {
830 74 : if(!xCont->hasByName(aSubNodeNames[j]))
831 : {
832 50 : Reference<XInterface> xInst = xFac->createInstance();
833 100 : Any aVal; aVal <<= xInst;
834 100 : xCont->insertByName(aSubNodeNames[j], aVal);
835 : }
836 : //set values
837 : }
838 : try
839 : {
840 74 : xBatch->commitChanges();
841 : }
842 0 : CATCH_INFO("Exception from commitChanges(): ")
843 :
844 74 : const PropertyValue* pProperties = rValues.getConstArray();
845 :
846 148 : Sequence< OUString > aSetNames(rValues.getLength());
847 74 : OUString* pSetNames = aSetNames.getArray();
848 :
849 148 : Sequence< Any> aSetValues(rValues.getLength());
850 74 : Any* pSetValues = aSetValues.getArray();
851 :
852 74 : bool bEmptyNode = rNode.isEmpty();
853 1492 : for(sal_Int32 k = 0; k < rValues.getLength(); k++)
854 : {
855 1418 : pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
856 1418 : pSetValues[k] = pProperties[k].Value;
857 : }
858 148 : bRet = PutProperties(aSetNames, aSetValues);
859 : }
860 : else
861 : {
862 : //if no factory is available then the node contains basic data elements
863 0 : const PropertyValue* pValues = rValues.getConstArray();
864 0 : for(int nValue = 0; nValue < rValues.getLength();nValue++)
865 : {
866 : try
867 : {
868 0 : OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
869 :
870 0 : if(xCont->hasByName(sSubNode))
871 0 : xCont->replaceByName(sSubNode, pValues[nValue].Value);
872 : else
873 0 : xCont->insertByName(sSubNode, pValues[nValue].Value);
874 :
875 : OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(pValues[nValue].Name),
876 0 : "Invalid config path" );
877 : }
878 0 : CATCH_INFO("Exception form insert/replaceByName(): ")
879 : }
880 0 : xBatch->commitChanges();
881 74 : }
882 : }
883 : #ifdef DBG_UTIL
884 : catch (const Exception& rEx)
885 : {
886 : lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx);
887 : #else
888 0 : catch (const Exception&)
889 : {
890 : #endif
891 0 : bRet = false;
892 74 : }
893 : }
894 148 : return bRet;
895 : }
896 :
897 880 : bool ConfigItem::ReplaceSetProperties(
898 : const OUString& rNode, const Sequence< PropertyValue >& rValues)
899 : {
900 880 : ValueCounter_Impl aCounter(m_nInValueChange);
901 880 : bool bRet = true;
902 1760 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
903 880 : if(xHierarchyAccess.is())
904 : {
905 880 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
906 : try
907 : {
908 880 : Reference<XNameContainer> xCont;
909 880 : if(!rNode.isEmpty())
910 : {
911 880 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
912 880 : aNode >>= xCont;
913 : }
914 : else
915 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
916 880 : if(!xCont.is())
917 0 : return false;
918 :
919 : // JB: Change: now the same name handling for sets of simple values
920 1760 : const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
921 880 : const OUString* pSubNodeNames = aSubNodeNames.getConstArray();
922 880 : const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
923 :
924 1760 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
925 880 : const bool isSimpleValueSet = !xFac.is();
926 :
927 : //remove unknown members first
928 : {
929 880 : const Sequence<OUString> aContainerSubNodes = xCont->getElementNames();
930 880 : const OUString* pContainerSubNodes = aContainerSubNodes.getConstArray();
931 :
932 1440 : for(sal_Int32 nContSub = 0; nContSub < aContainerSubNodes.getLength(); nContSub++)
933 : {
934 560 : bool bFound = false;
935 6816 : for(sal_Int32 j = 0; j < nSubNodeCount; j++)
936 : {
937 6816 : if(pSubNodeNames[j] == pContainerSubNodes[nContSub])
938 : {
939 560 : bFound = true;
940 560 : break;
941 : }
942 : }
943 560 : if(!bFound)
944 : try
945 : {
946 0 : xCont->removeByName(pContainerSubNodes[nContSub]);
947 : }
948 0 : catch (const Exception&)
949 : {
950 0 : if (isSimpleValueSet)
951 : {
952 : try
953 : {
954 : // #i37322#: fallback action: replace with <void/>
955 0 : xCont->replaceByName(pContainerSubNodes[nContSub], Any());
956 : // fallback successful: continue looping
957 0 : continue;
958 : }
959 0 : catch (Exception &)
960 : {} // propagate original exception, if fallback fails
961 : }
962 0 : throw;
963 : }
964 : }
965 880 : try { xBatch->commitChanges(); }
966 880 : CATCH_INFO("Exception from commitChanges(): ")
967 : }
968 :
969 880 : if(xFac.is()) // !isSimpleValueSet
970 : {
971 0 : for(sal_Int32 j = 0; j < nSubNodeCount; j++)
972 : {
973 0 : if(!xCont->hasByName(pSubNodeNames[j]))
974 : {
975 : //create if not available
976 0 : Reference<XInterface> xInst = xFac->createInstance();
977 0 : Any aVal; aVal <<= xInst;
978 0 : xCont->insertByName(pSubNodeNames[j], aVal);
979 : }
980 : }
981 0 : try { xBatch->commitChanges(); }
982 0 : CATCH_INFO("Exception from commitChanges(): ")
983 :
984 0 : const PropertyValue* pProperties = rValues.getConstArray();
985 :
986 0 : Sequence< OUString > aSetNames(rValues.getLength());
987 0 : OUString* pSetNames = aSetNames.getArray();
988 :
989 0 : Sequence< Any> aSetValues(rValues.getLength());
990 0 : Any* pSetValues = aSetValues.getArray();
991 :
992 0 : bool bEmptyNode = rNode.isEmpty();
993 0 : for(sal_Int32 k = 0; k < rValues.getLength(); k++)
994 : {
995 0 : pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
996 0 : pSetValues[k] = pProperties[k].Value;
997 : }
998 0 : bRet = PutProperties(aSetNames, aSetValues);
999 : }
1000 : else
1001 : {
1002 880 : const PropertyValue* pValues = rValues.getConstArray();
1003 :
1004 : //if no factory is available then the node contains basic data elements
1005 7040 : for(int nValue = 0; nValue < rValues.getLength();nValue++)
1006 : {
1007 : try
1008 : {
1009 6160 : OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
1010 :
1011 6160 : if(xCont->hasByName(sSubNode))
1012 560 : xCont->replaceByName(sSubNode, pValues[nValue].Value);
1013 : else
1014 5600 : xCont->insertByName(sSubNode, pValues[nValue].Value);
1015 : }
1016 0 : CATCH_INFO("Exception from insert/replaceByName(): ");
1017 : }
1018 880 : xBatch->commitChanges();
1019 880 : }
1020 : }
1021 : #ifdef DBG_UTIL
1022 : catch (const Exception& rEx)
1023 : {
1024 : lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx);
1025 : #else
1026 0 : catch (const Exception&)
1027 : {
1028 : #endif
1029 0 : bRet = false;
1030 880 : }
1031 : }
1032 1760 : return bRet;
1033 : }
1034 :
1035 0 : bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode)
1036 : {
1037 0 : ValueCounter_Impl aCounter(m_nInValueChange);
1038 0 : bool bRet = true;
1039 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1040 0 : if(xHierarchyAccess.is())
1041 : {
1042 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
1043 : try
1044 : {
1045 0 : Reference<XNameContainer> xCont;
1046 0 : if(!rNode.isEmpty())
1047 : {
1048 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
1049 0 : aNode >>= xCont;
1050 : }
1051 : else
1052 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1053 0 : if(!xCont.is())
1054 0 : return false;
1055 :
1056 0 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1057 :
1058 0 : if(xFac.is())
1059 : {
1060 0 : if(!xCont->hasByName(rNewNode))
1061 : {
1062 0 : Reference<XInterface> xInst = xFac->createInstance();
1063 0 : Any aVal; aVal <<= xInst;
1064 0 : xCont->insertByName(rNewNode, aVal);
1065 : }
1066 : try
1067 : {
1068 0 : xBatch->commitChanges();
1069 : }
1070 0 : CATCH_INFO("Exception from commitChanges(): ")
1071 : }
1072 : else
1073 : {
1074 : //if no factory is available then the node contains basic data elements
1075 : try
1076 : {
1077 0 : if(!xCont->hasByName(rNewNode))
1078 0 : xCont->insertByName(rNewNode, Any());
1079 : }
1080 0 : CATCH_INFO("Exception from AddNode(): ")
1081 : }
1082 0 : xBatch->commitChanges();
1083 : }
1084 : #ifdef DBG_UTIL
1085 : catch (const Exception& rEx)
1086 : {
1087 : lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx);
1088 : #else
1089 0 : catch (const Exception&)
1090 : {
1091 : #endif
1092 0 : bRet = false;
1093 0 : }
1094 : }
1095 0 : return bRet;
1096 : }
1097 :
1098 :
1099 4534 : void ConfigItem::SetModified()
1100 : {
1101 4534 : m_bIsModified = true;
1102 4534 : }
1103 :
1104 844 : void ConfigItem::ClearModified()
1105 : {
1106 844 : m_bIsModified = false;
1107 844 : }
1108 :
1109 :
1110 :
1111 272860 : Reference< XHierarchicalNameAccess> ConfigItem::GetTree()
1112 : {
1113 272860 : Reference< XHierarchicalNameAccess> xRet;
1114 272860 : if(!m_xHierarchyAccess.is())
1115 1602 : xRet = ConfigManager::acquireTree(*this);
1116 : else
1117 271258 : xRet = m_xHierarchyAccess;
1118 272860 : return xRet;
1119 : }
1120 :
1121 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|