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 <sal/config.h>
21 :
22 : #include <sal/log.hxx>
23 : #include <unotools/configitem.hxx>
24 : #include <unotools/configmgr.hxx>
25 : #include <unotools/configpaths.hxx>
26 : #include <comphelper/processfactory.hxx>
27 : #include <com/sun/star/beans/XMultiPropertySet.hpp>
28 : #include <com/sun/star/beans/XPropertySet.hpp>
29 : #include <com/sun/star/util/XChangesListener.hpp>
30 : #include <com/sun/star/util/XChangesNotifier.hpp>
31 : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
32 : #include <com/sun/star/container/XHierarchicalName.hpp>
33 : #include <com/sun/star/configuration/XTemplateContainer.hpp>
34 : #include <com/sun/star/container/XNameContainer.hpp>
35 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
36 : #include <com/sun/star/lang/XServiceInfo.hpp>
37 : #include <com/sun/star/awt/XRequestCallback.hpp>
38 : #include <com/sun/star/beans/PropertyValue.hpp>
39 : #include <com/sun/star/beans/PropertyAttribute.hpp>
40 : #include <com/sun/star/util/XStringEscape.hpp>
41 : #include <com/sun/star/util/XChangesBatch.hpp>
42 : #include <osl/diagnose.h>
43 : #include <tools/solarmutex.hxx>
44 : #include <rtl/ustrbuf.hxx>
45 :
46 : using namespace utl;
47 : using namespace com::sun::star::uno;
48 : using namespace com::sun::star::util;
49 : using namespace com::sun::star::lang;
50 : using namespace com::sun::star::beans;
51 : using namespace com::sun::star::container;
52 : using namespace com::sun::star::configuration;
53 :
54 : #include <cppuhelper/implbase1.hxx>
55 :
56 : #ifdef DBG_UTIL
57 : static inline void lcl_CFG_DBG_EXCEPTION(const sal_Char* cText, const Exception& rEx)
58 : {
59 : OString sMsg(cText);
60 : sMsg += OString(rEx.Message.getStr(), rEx.Message.getLength(), RTL_TEXTENCODING_ASCII_US);
61 : OSL_FAIL(sMsg.getStr());
62 : }
63 : #define CATCH_INFO(a) \
64 : catch(const Exception& rEx) \
65 : { \
66 : lcl_CFG_DBG_EXCEPTION(a, rEx);\
67 : }
68 : #else
69 : #define CATCH_INFO(a) catch(const Exception&){}
70 : #endif
71 :
72 : /*
73 : The ConfigChangeListener_Impl receives notifications from the configuration about changes that
74 : have happened. It forwards this notification to the ConfigItem it knows a pParent by calling its
75 : "CallNotify" method. As ConfigItems are most probably not thread safe, the SolarMutex is acquired
76 : before doing so.
77 : */
78 :
79 : namespace utl{
80 : class ConfigChangeListener_Impl : public cppu::WeakImplHelper1
81 : <
82 : com::sun::star::util::XChangesListener
83 : >
84 : {
85 : public:
86 : ConfigItem* pParent;
87 : const Sequence< OUString > aPropertyNames;
88 : ConfigChangeListener_Impl(ConfigItem& rItem, const Sequence< OUString >& rNames);
89 : virtual ~ConfigChangeListener_Impl();
90 :
91 : //XChangesListener
92 : virtual void SAL_CALL changesOccurred( const ChangesEvent& Event ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
93 :
94 : //XEventListener
95 : virtual void SAL_CALL disposing( const EventObject& Source ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
96 : };
97 : }
98 :
99 : class ValueCounter_Impl
100 : {
101 : sal_Int16& rCnt;
102 : public:
103 1053 : explicit ValueCounter_Impl(sal_Int16& rCounter)
104 1053 : : rCnt(rCounter)
105 : {
106 1053 : rCnt++;
107 1053 : }
108 1053 : ~ValueCounter_Impl()
109 : {
110 : OSL_ENSURE(rCnt>0, "RefCount < 0 ??");
111 1053 : rCnt--;
112 1053 : }
113 : };
114 :
115 12987 : ConfigChangeListener_Impl::ConfigChangeListener_Impl(
116 : ConfigItem& rItem, const Sequence< OUString >& rNames) :
117 : pParent(&rItem),
118 12987 : aPropertyNames(rNames)
119 : {
120 12987 : }
121 :
122 23802 : ConfigChangeListener_Impl::~ConfigChangeListener_Impl()
123 : {
124 23802 : }
125 :
126 10202 : static bool lcl_Find(
127 : const OUString& rTemp,
128 : const OUString* pCheckPropertyNames,
129 : sal_Int32 nLength)
130 : {
131 : //return true if the path is completely correct or if it is longer
132 : //i.e ...Print/Content/Graphic and .../Print
133 119507 : for(sal_Int32 nIndex = 0; nIndex < nLength; nIndex++)
134 113718 : if( isPrefixOfConfigurationPath(rTemp, pCheckPropertyNames[nIndex]) )
135 4413 : return true;
136 5789 : return false;
137 : }
138 :
139 8058 : void ConfigChangeListener_Impl::changesOccurred( const ChangesEvent& rEvent ) throw(RuntimeException, std::exception)
140 : {
141 8058 : const ElementChange* pElementChanges = rEvent.Changes.getConstArray();
142 :
143 8058 : Sequence<OUString> aChangedNames(rEvent.Changes.getLength());
144 8058 : OUString* pNames = aChangedNames.getArray();
145 :
146 8058 : const OUString* pCheckPropertyNames = aPropertyNames.getConstArray();
147 :
148 8058 : sal_Int32 nNotify = 0;
149 18260 : for(int i = 0; i < aChangedNames.getLength(); i++)
150 : {
151 10202 : OUString sTemp;
152 10202 : pElementChanges[i].Accessor >>= sTemp;
153 10202 : if(lcl_Find(sTemp, pCheckPropertyNames, aPropertyNames.getLength()))
154 4413 : pNames[nNotify++] = sTemp;
155 10202 : }
156 8058 : if( nNotify )
157 : {
158 3483 : if ( ::tools::SolarMutex::Acquire() )
159 : {
160 3483 : aChangedNames.realloc(nNotify);
161 3483 : pParent->CallNotify(aChangedNames);
162 3483 : ::tools::SolarMutex::Release();
163 : }
164 8058 : }
165 8058 : }
166 :
167 0 : void ConfigChangeListener_Impl::disposing( const EventObject& /*rSource*/ ) throw(RuntimeException, std::exception)
168 : {
169 0 : pParent->RemoveChangesListener();
170 0 : }
171 :
172 24815 : ConfigItem::ConfigItem(const OUString &rSubTree, ConfigItemMode nSetMode ) :
173 : sSubTree(rSubTree),
174 : m_nMode(nSetMode),
175 : m_bIsModified(false),
176 : m_bEnableInternalNotification(false),
177 24815 : m_nInValueChange(0)
178 : {
179 24815 : if(nSetMode & ConfigItemMode::ReleaseTree)
180 1083 : ConfigManager::getConfigManager().addConfigItem(*this);
181 : else
182 23732 : m_xHierarchyAccess = ConfigManager::getConfigManager().addConfigItem(*this);
183 24815 : }
184 :
185 46270 : ConfigItem::~ConfigItem()
186 : {
187 23135 : RemoveChangesListener();
188 23135 : ConfigManager::getConfigManager().removeConfigItem(*this);
189 23135 : }
190 :
191 3483 : void ConfigItem::CallNotify( const com::sun::star::uno::Sequence<OUString>& rPropertyNames )
192 : {
193 : // the call is forwarded to the virtual Notify() method
194 : // it is pure virtual, so all classes deriving from ConfigItem have to decide how they
195 : // want to notify listeners
196 3483 : if(!IsInValueChange() || m_bEnableInternalNotification)
197 111 : Notify(rPropertyNames);
198 3483 : }
199 :
200 0 : void ConfigItem::impl_packLocalizedProperties( const Sequence< OUString >& lInNames ,
201 : const Sequence< Any >& lInValues ,
202 : Sequence< Any >& lOutValues )
203 : {
204 : // Safe impossible cases.
205 : // This method should be called for special ConfigItem-mode only!
206 : OSL_ENSURE( ((m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales), "ConfigItem::impl_packLocalizedProperties()\nWrong call of this method detected!\n" );
207 :
208 : sal_Int32 nSourceCounter; // used to step during input lists
209 : sal_Int32 nSourceSize; // marks end of loop over input lists
210 : sal_Int32 nDestinationCounter; // actual position in output lists
211 : sal_Int32 nPropertyCounter; // counter of inner loop for Sequence< PropertyValue >
212 : sal_Int32 nPropertiesSize; // marks end of inner loop
213 0 : Sequence< OUString > lPropertyNames; // list of all locales for localized entry
214 0 : Sequence< PropertyValue > lProperties; // localized values of an configuration entry packed for return
215 0 : Reference< XInterface > xLocalizedNode; // if cfg entry is localized ... lInValues contains an XInterface!
216 :
217 : // Optimise follow algorithm ... A LITTLE BIT :-)
218 : // There exist two different possibilities:
219 : // i ) There exist no localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
220 : // ii) There exist some (mostly one or two) localized entries ... => size of lOutValues will be the same like lInNames/lInValues!
221 : // ... Why? If a localized value exist - the any is filled with an XInterface object (is a SetNode-service).
222 : // We read all his child nodes and pack it into Sequence< PropertyValue >.
223 : // The result list we pack into the return any. We never change size of lists!
224 0 : nSourceSize = lInNames.getLength();
225 0 : lOutValues.realloc( nSourceSize );
226 :
227 : // Algorithm:
228 : // Copy all names and values from in to out lists.
229 : // Look for special localized entries ... You can detect it as "XInterface" packed into an Any.
230 : // Use this XInterface-object to read all localized values and pack it into Sequence< PropertValue >.
231 : // Add this list to out lists then.
232 :
233 0 : nDestinationCounter = 0;
234 0 : for( nSourceCounter=0; nSourceCounter<nSourceSize; ++nSourceCounter )
235 : {
236 : // If item a special localized one ... convert and pack it ...
237 0 : if( lInValues[nSourceCounter].getValueTypeName() == "com.sun.star.uno.XInterface" )
238 : {
239 0 : lInValues[nSourceCounter] >>= xLocalizedNode;
240 0 : Reference< XNameContainer > xSetAccess( xLocalizedNode, UNO_QUERY );
241 0 : if( xSetAccess.is() )
242 : {
243 0 : lPropertyNames = xSetAccess->getElementNames();
244 0 : nPropertiesSize = lPropertyNames.getLength();
245 0 : lProperties.realloc( nPropertiesSize );
246 :
247 0 : for( nPropertyCounter=0; nPropertyCounter<nPropertiesSize; ++nPropertyCounter )
248 : {
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 & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales), "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() == cppu::UnoType<Sequence<PropertyValue>>::get() )
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 1102 : 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 1102 : sal_Int32 nCount = rNames.getLength();
349 1102 : Sequence< sal_Bool > lStates(nCount);
350 :
351 : // We must be sure to return a valid information every time!
352 : // Set default to non readonly... similar to the configuration handling of this property.
353 14260 : for ( i=0; i<nCount; ++i)
354 13158 : lStates[i] = sal_False;
355 :
356 : // no access - no information...
357 2204 : Reference< XHierarchicalNameAccess > xHierarchyAccess = GetTree();
358 1102 : if (!xHierarchyAccess.is())
359 0 : return lStates;
360 :
361 14260 : for (i=0; i<nCount; ++i)
362 : {
363 : try
364 : {
365 13158 : OUString sName = rNames[i];
366 26316 : OUString sPath;
367 26316 : OUString sProperty;
368 :
369 13158 : (void)::utl::splitLastFromConfigurationPath(sName,sPath,sProperty);
370 13158 : if (sPath.isEmpty() && sProperty.isEmpty())
371 : {
372 : OSL_FAIL("ConfigItem::IsReadonly()\nsplitt failed\n");
373 0 : continue;
374 : }
375 :
376 26316 : Reference< XInterface > xNode;
377 26316 : Reference< XPropertySet > xSet;
378 26316 : Reference< XPropertySetInfo > xInfo;
379 13158 : if (!sPath.isEmpty())
380 : {
381 5098 : Any aNode = xHierarchyAccess->getByHierarchicalName(sPath);
382 5098 : if (!(aNode >>= xNode) || !xNode.is())
383 : {
384 : OSL_FAIL("ConfigItem::IsReadonly()\nno set available\n");
385 0 : continue;
386 5098 : }
387 : }
388 : else
389 : {
390 8060 : xNode = Reference<XInterface>( xHierarchyAccess, UNO_QUERY );
391 : }
392 :
393 13158 : xSet = Reference< XPropertySet >(xNode, UNO_QUERY);
394 13158 : if (xSet.is())
395 : {
396 13158 : 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 13158 : if (!xInfo.is())
406 : {
407 : OSL_FAIL("ConfigItem::IsReadonly()\nno prop info available\n");
408 0 : continue;
409 : }
410 :
411 26316 : Property aProp = xInfo->getPropertyByName(sProperty);
412 26316 : lStates[i] = ((aProp.Attributes & PropertyAttribute::READONLY) == PropertyAttribute::READONLY);
413 : }
414 0 : catch (const Exception&)
415 : {
416 : }
417 : }
418 :
419 1102 : return lStates;
420 : }
421 :
422 109805 : Sequence< Any > ConfigItem::GetProperties(const Sequence< OUString >& rNames)
423 : {
424 109805 : Sequence< Any > aRet(rNames.getLength());
425 109805 : const OUString* pNames = rNames.getConstArray();
426 109805 : Any* pRet = aRet.getArray();
427 219610 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
428 109805 : if(xHierarchyAccess.is())
429 : {
430 833685 : for(int i = 0; i < rNames.getLength(); i++)
431 : {
432 : try
433 : {
434 723880 : pRet[i] = xHierarchyAccess->getByHierarchicalName(pNames[i]);
435 : }
436 2 : 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 109805 : if((m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales)
448 : {
449 0 : Sequence< Any > lValues;
450 0 : impl_packLocalizedProperties( rNames, aRet, lValues );
451 0 : aRet = lValues;
452 : }
453 : }
454 219610 : return aRet;
455 : }
456 :
457 371 : bool ConfigItem::PutProperties( const Sequence< OUString >& rNames,
458 : const Sequence< Any>& rValues)
459 : {
460 371 : ValueCounter_Impl aCounter(m_nInValueChange);
461 742 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
462 742 : Reference<XNameReplace> xTopNodeReplace(xHierarchyAccess, UNO_QUERY);
463 371 : bool bRet = xHierarchyAccess.is() && xTopNodeReplace.is();
464 371 : if(bRet)
465 : {
466 371 : Sequence< OUString > lNames;
467 742 : Sequence< Any > lValues;
468 371 : const OUString* pNames = NULL;
469 371 : const Any* pValues = NULL;
470 : sal_Int32 nNameCount;
471 371 : if(( m_nMode & ConfigItemMode::AllLocales ) == ConfigItemMode::AllLocales )
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 371 : pNames = rNames.getConstArray ();
487 371 : pValues = rValues.getConstArray ();
488 371 : nNameCount = rNames.getLength ();
489 : }
490 4996 : for(int i = 0; i < nNameCount; i++)
491 : {
492 : try
493 : {
494 9250 : OUString sNode, sProperty;
495 4625 : if (splitLastFromConfigurationPath(pNames[i],sNode, sProperty))
496 : {
497 1985 : Any aNode = xHierarchyAccess->getByHierarchicalName(sNode);
498 :
499 3970 : Reference<XNameAccess> xNodeAcc;
500 1985 : aNode >>= xNodeAcc;
501 3970 : Reference<XNameReplace> xNodeReplace(xNodeAcc, UNO_QUERY);
502 3970 : Reference<XNameContainer> xNodeCont (xNodeAcc, UNO_QUERY);
503 :
504 1985 : bool bExist = (xNodeAcc.is() && xNodeAcc->hasByName(sProperty));
505 1985 : if (bExist && xNodeReplace.is())
506 1985 : xNodeReplace->replaceByName(sProperty, pValues[i]);
507 : else
508 0 : if (!bExist && xNodeCont.is())
509 0 : xNodeCont->insertByName(sProperty, pValues[i]);
510 : else
511 1985 : bRet = false;
512 : }
513 : else //direct value
514 : {
515 2640 : xTopNodeReplace->replaceByName(sProperty, pValues[i]);
516 4625 : }
517 : }
518 3 : CATCH_INFO("Exception from PutProperties: ");
519 : }
520 : try
521 : {
522 371 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
523 371 : xBatch->commitChanges();
524 : }
525 371 : CATCH_INFO("Exception from commitChanges(): ")
526 : }
527 :
528 742 : return bRet;
529 : }
530 :
531 3228 : void ConfigItem::DisableNotification()
532 : {
533 : OSL_ENSURE( xChangeLstnr.is(), "ConfigItem::DisableNotification: notifications not enabled currently!" );
534 3228 : RemoveChangesListener();
535 3228 : }
536 :
537 12987 : bool ConfigItem::EnableNotification(const Sequence< OUString >& rNames,
538 : bool bEnableInternalNotification )
539 : {
540 : OSL_ENSURE(!(m_nMode & ConfigItemMode::ReleaseTree), "notification in ConfigItemMode::ReleaseTree mode not possible");
541 12987 : m_bEnableInternalNotification = bEnableInternalNotification;
542 12987 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
543 25974 : Reference<XChangesNotifier> xChgNot(xHierarchyAccess, UNO_QUERY);
544 12987 : if(!xChgNot.is())
545 0 : return false;
546 :
547 : OSL_ENSURE(!xChangeLstnr.is(), "EnableNotification already called");
548 12987 : if(xChangeLstnr.is())
549 0 : xChgNot->removeChangesListener( xChangeLstnr );
550 12987 : bool bRet = true;
551 :
552 : try
553 : {
554 12987 : xChangeLstnr = new ConfigChangeListener_Impl(*this, rNames);
555 12987 : xChgNot->addChangesListener( xChangeLstnr );
556 : }
557 0 : catch (const RuntimeException&)
558 : {
559 0 : bRet = false;
560 : }
561 25974 : return bRet;
562 : }
563 :
564 26363 : void ConfigItem::RemoveChangesListener()
565 : {
566 26363 : Reference<XChangesNotifier> xChgNot(m_xHierarchyAccess, UNO_QUERY);
567 26363 : if(xChgNot.is() && xChangeLstnr.is())
568 : {
569 : try
570 : {
571 11901 : xChgNot->removeChangesListener( xChangeLstnr );
572 11901 : xChangeLstnr = 0;
573 : }
574 0 : catch (const Exception&)
575 : {
576 : }
577 26363 : }
578 26363 : }
579 :
580 31554 : static void lcl_normalizeLocalNames(Sequence< OUString >& _rNames, ConfigNameFormat _eFormat, Reference<XInterface> const& _xParentNode)
581 : {
582 31554 : switch (_eFormat)
583 : {
584 : case CONFIG_NAME_LOCAL_NAME:
585 : // unaltered - this is our input format
586 30752 : break;
587 :
588 : case CONFIG_NAME_FULL_PATH:
589 : {
590 0 : Reference<XHierarchicalName> xFormatter(_xParentNode, UNO_QUERY);
591 0 : if (xFormatter.is())
592 : {
593 0 : OUString * pNames = _rNames.getArray();
594 0 : for(int i = 0; i<_rNames.getLength(); ++i)
595 : {
596 : try
597 : {
598 0 : pNames[i] = xFormatter->composeHierarchicalName(pNames[i]);
599 : }
600 0 : CATCH_INFO("Exception from composeHierarchicalName(): ")
601 : }
602 0 : break;
603 0 : }
604 : }
605 : OSL_FAIL("Cannot create absolute paths: missing interface");
606 : // make local paths instaed
607 :
608 : case CONFIG_NAME_LOCAL_PATH:
609 : {
610 802 : Reference<XTemplateContainer> xTypeContainer(_xParentNode, UNO_QUERY);
611 802 : if (xTypeContainer.is())
612 : {
613 0 : OUString sTypeName = xTypeContainer->getElementTemplateName();
614 0 : sTypeName = sTypeName.copy(sTypeName.lastIndexOf('/')+1);
615 :
616 0 : OUString * pNames = _rNames.getArray();
617 0 : for(int i = 0; i<_rNames.getLength(); ++i)
618 : {
619 0 : pNames[i] = wrapConfigurationElementName(pNames[i],sTypeName);
620 0 : }
621 : }
622 : else
623 : {
624 802 : Reference<XServiceInfo> xSVI(_xParentNode, UNO_QUERY);
625 802 : if (xSVI.is() && xSVI->supportsService("com.sun.star.configuration.SetAccess"))
626 : {
627 802 : OUString * pNames = _rNames.getArray();
628 2912 : for(int i = 0; i<_rNames.getLength(); ++i)
629 : {
630 2110 : pNames[i] = wrapConfigurationElementName(pNames[i]);
631 : }
632 802 : }
633 802 : }
634 : }
635 802 : break;
636 :
637 : case CONFIG_NAME_PLAINTEXT_NAME:
638 : {
639 0 : Reference<XStringEscape> xEscaper(_xParentNode, UNO_QUERY);
640 0 : if (xEscaper.is())
641 : {
642 0 : OUString * pNames = _rNames.getArray();
643 0 : for(int i = 0; i<_rNames.getLength(); ++i)
644 : try
645 : {
646 0 : pNames[i] = xEscaper->unescapeString(pNames[i]);
647 : }
648 0 : CATCH_INFO("Exception from unescapeString(): ")
649 0 : }
650 : }
651 0 : break;
652 :
653 : }
654 31554 : }
655 :
656 30752 : Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode)
657 : {
658 30752 : ConfigNameFormat const eDefaultFormat = CONFIG_NAME_LOCAL_NAME; // CONFIG_NAME_DEFAULT;
659 :
660 30752 : return GetNodeNames(rNode, eDefaultFormat);
661 : }
662 :
663 31554 : Sequence< OUString > ConfigItem::GetNodeNames(const OUString& rNode, ConfigNameFormat eFormat)
664 : {
665 31554 : Sequence< OUString > aRet;
666 63108 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
667 31554 : if(xHierarchyAccess.is())
668 : {
669 : try
670 : {
671 31554 : Reference<XNameAccess> xCont;
672 31554 : if(!rNode.isEmpty())
673 : {
674 31217 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
675 31217 : aNode >>= xCont;
676 : }
677 : else
678 337 : xCont = Reference<XNameAccess> (xHierarchyAccess, UNO_QUERY);
679 31554 : if(xCont.is())
680 : {
681 31554 : aRet = xCont->getElementNames();
682 31554 : lcl_normalizeLocalNames(aRet,eFormat,xCont);
683 31554 : }
684 :
685 : }
686 0 : CATCH_INFO("Exception from GetNodeNames: ");
687 : }
688 63108 : return aRet;
689 : }
690 :
691 4 : bool ConfigItem::ClearNodeSet(const OUString& rNode)
692 : {
693 4 : ValueCounter_Impl aCounter(m_nInValueChange);
694 4 : bool bRet = false;
695 8 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
696 4 : if(xHierarchyAccess.is())
697 : {
698 : try
699 : {
700 4 : Reference<XNameContainer> xCont;
701 4 : if(!rNode.isEmpty())
702 : {
703 4 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
704 4 : aNode >>= xCont;
705 : }
706 : else
707 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
708 4 : if(!xCont.is())
709 0 : return false;
710 8 : Sequence< OUString > aNames = xCont->getElementNames();
711 4 : const OUString* pNames = aNames.getConstArray();
712 8 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
713 19 : for(sal_Int32 i = 0; i < aNames.getLength(); i++)
714 : {
715 : try
716 : {
717 15 : xCont->removeByName(pNames[i]);
718 : }
719 0 : CATCH_INFO("Exception from removeByName(): ")
720 : }
721 4 : xBatch->commitChanges();
722 8 : bRet = true;
723 : }
724 0 : CATCH_INFO("Exception from ClearNodeSet")
725 : }
726 8 : return bRet;
727 : }
728 :
729 25 : bool ConfigItem::ClearNodeElements(const OUString& rNode, Sequence< OUString >& rElements)
730 : {
731 25 : ValueCounter_Impl aCounter(m_nInValueChange);
732 25 : bool bRet = false;
733 50 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
734 25 : if(xHierarchyAccess.is())
735 : {
736 25 : const OUString* pElements = rElements.getConstArray();
737 : try
738 : {
739 25 : Reference<XNameContainer> xCont;
740 25 : if(!rNode.isEmpty())
741 : {
742 25 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
743 25 : aNode >>= xCont;
744 : }
745 : else
746 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
747 25 : if(!xCont.is())
748 0 : return false;
749 : try
750 : {
751 35 : for(sal_Int32 nElement = 0; nElement < rElements.getLength(); nElement++)
752 : {
753 25 : xCont->removeByName(pElements[nElement]);
754 : }
755 10 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
756 10 : xBatch->commitChanges();
757 : }
758 15 : CATCH_INFO("Exception from commitChanges(): ")
759 25 : bRet = true;
760 : }
761 0 : CATCH_INFO("Exception from GetNodeNames: ")
762 : }
763 50 : return bRet;
764 : }
765 :
766 : static inline
767 688 : OUString lcl_extractSetPropertyName( const OUString& rInPath, const OUString& rPrefix )
768 : {
769 688 : OUString const sSubPath = dropPrefixFromConfigurationPath( rInPath, rPrefix);
770 688 : return extractFirstFromConfigurationPath( sSubPath );
771 : }
772 :
773 : static
774 653 : Sequence< OUString > lcl_extractSetPropertyNames( const Sequence< PropertyValue >& rValues, const OUString& rPrefix )
775 : {
776 653 : const PropertyValue* pProperties = rValues.getConstArray();
777 :
778 653 : Sequence< OUString > aSubNodeNames(rValues.getLength());
779 653 : OUString* pSubNodeNames = aSubNodeNames.getArray();
780 :
781 1306 : OUString sLastSubNode;
782 653 : sal_Int32 nSubIndex = 0;
783 :
784 2050 : for(sal_Int32 i = 0; i < rValues.getLength(); i++)
785 : {
786 1397 : OUString const sSubPath = dropPrefixFromConfigurationPath( pProperties[i].Name, rPrefix);
787 2794 : OUString const sSubNode = extractFirstFromConfigurationPath( sSubPath );
788 :
789 1397 : if(sLastSubNode != sSubNode)
790 : {
791 725 : pSubNodeNames[nSubIndex++] = sSubNode;
792 : }
793 :
794 1397 : sLastSubNode = sSubNode;
795 1397 : }
796 653 : aSubNodeNames.realloc(nSubIndex);
797 :
798 1306 : return aSubNodeNames;
799 : }
800 :
801 : // Add or change properties
802 37 : bool ConfigItem::SetSetProperties(
803 : const OUString& rNode, const Sequence< PropertyValue >& rValues)
804 : {
805 37 : ValueCounter_Impl aCounter(m_nInValueChange);
806 37 : bool bRet = true;
807 74 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
808 37 : if(xHierarchyAccess.is())
809 : {
810 37 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
811 : try
812 : {
813 37 : Reference<XNameContainer> xCont;
814 37 : if(!rNode.isEmpty())
815 : {
816 37 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
817 37 : aNode >>= xCont;
818 : }
819 : else
820 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
821 37 : if(!xCont.is())
822 0 : return false;
823 :
824 74 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
825 :
826 37 : if(xFac.is())
827 : {
828 37 : const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
829 :
830 37 : const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
831 :
832 74 : for(sal_Int32 j = 0; j <nSubNodeCount; j++)
833 : {
834 37 : if(!xCont->hasByName(aSubNodeNames[j]))
835 : {
836 25 : Reference<XInterface> xInst = xFac->createInstance();
837 50 : Any aVal; aVal <<= xInst;
838 50 : xCont->insertByName(aSubNodeNames[j], aVal);
839 : }
840 : //set values
841 : }
842 : try
843 : {
844 37 : xBatch->commitChanges();
845 : }
846 0 : CATCH_INFO("Exception from commitChanges(): ")
847 :
848 37 : const PropertyValue* pProperties = rValues.getConstArray();
849 :
850 74 : Sequence< OUString > aSetNames(rValues.getLength());
851 37 : OUString* pSetNames = aSetNames.getArray();
852 :
853 74 : Sequence< Any> aSetValues(rValues.getLength());
854 37 : Any* pSetValues = aSetValues.getArray();
855 :
856 37 : bool bEmptyNode = rNode.isEmpty();
857 746 : for(sal_Int32 k = 0; k < rValues.getLength(); k++)
858 : {
859 709 : pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
860 709 : pSetValues[k] = pProperties[k].Value;
861 : }
862 74 : bRet = PutProperties(aSetNames, aSetValues);
863 : }
864 : else
865 : {
866 : //if no factory is available then the node contains basic data elements
867 0 : const PropertyValue* pValues = rValues.getConstArray();
868 0 : for(int nValue = 0; nValue < rValues.getLength();nValue++)
869 : {
870 : try
871 : {
872 0 : OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
873 :
874 0 : if(xCont->hasByName(sSubNode))
875 0 : xCont->replaceByName(sSubNode, pValues[nValue].Value);
876 : else
877 0 : xCont->insertByName(sSubNode, pValues[nValue].Value);
878 :
879 : OSL_ENSURE( xHierarchyAccess->hasByHierarchicalName(pValues[nValue].Name),
880 0 : "Invalid config path" );
881 : }
882 0 : CATCH_INFO("Exception form insert/replaceByName(): ")
883 : }
884 0 : xBatch->commitChanges();
885 37 : }
886 : }
887 : #ifdef DBG_UTIL
888 : catch (const Exception& rEx)
889 : {
890 : lcl_CFG_DBG_EXCEPTION("Exception from SetSetProperties: ", rEx);
891 : #else
892 0 : catch (const Exception&)
893 : {
894 : #endif
895 0 : bRet = false;
896 37 : }
897 : }
898 74 : return bRet;
899 : }
900 :
901 616 : bool ConfigItem::ReplaceSetProperties(
902 : const OUString& rNode, const Sequence< PropertyValue >& rValues)
903 : {
904 616 : ValueCounter_Impl aCounter(m_nInValueChange);
905 616 : bool bRet = true;
906 1232 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
907 616 : if(xHierarchyAccess.is())
908 : {
909 616 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
910 : try
911 : {
912 616 : Reference<XNameContainer> xCont;
913 616 : if(!rNode.isEmpty())
914 : {
915 616 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
916 616 : aNode >>= xCont;
917 : }
918 : else
919 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
920 616 : if(!xCont.is())
921 0 : return false;
922 :
923 : // JB: Change: now the same name handling for sets of simple values
924 1232 : const Sequence< OUString > aSubNodeNames = lcl_extractSetPropertyNames(rValues, rNode);
925 616 : const OUString* pSubNodeNames = aSubNodeNames.getConstArray();
926 616 : const sal_Int32 nSubNodeCount = aSubNodeNames.getLength();
927 :
928 1232 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
929 616 : const bool isSimpleValueSet = !xFac.is();
930 :
931 : //remove unknown members first
932 : {
933 616 : const Sequence<OUString> aContainerSubNodes = xCont->getElementNames();
934 616 : const OUString* pContainerSubNodes = aContainerSubNodes.getConstArray();
935 :
936 696 : for(sal_Int32 nContSub = 0; nContSub < aContainerSubNodes.getLength(); nContSub++)
937 : {
938 80 : bool bFound = false;
939 290 : for(sal_Int32 j = 0; j < nSubNodeCount; j++)
940 : {
941 290 : if(pSubNodeNames[j] == pContainerSubNodes[nContSub])
942 : {
943 80 : bFound = true;
944 80 : break;
945 : }
946 : }
947 80 : if(!bFound)
948 : try
949 : {
950 0 : xCont->removeByName(pContainerSubNodes[nContSub]);
951 : }
952 0 : catch (const Exception&)
953 : {
954 0 : if (isSimpleValueSet)
955 : {
956 : try
957 : {
958 : // #i37322#: fallback action: replace with <void/>
959 0 : xCont->replaceByName(pContainerSubNodes[nContSub], Any());
960 : // fallback successful: continue looping
961 0 : continue;
962 : }
963 0 : catch (Exception &)
964 : {} // propagate original exception, if fallback fails
965 : }
966 0 : throw;
967 : }
968 : }
969 616 : try { xBatch->commitChanges(); }
970 616 : CATCH_INFO("Exception from commitChanges(): ")
971 : }
972 :
973 616 : if(xFac.is()) // !isSimpleValueSet
974 : {
975 0 : for(sal_Int32 j = 0; j < nSubNodeCount; j++)
976 : {
977 0 : if(!xCont->hasByName(pSubNodeNames[j]))
978 : {
979 : //create if not available
980 0 : Reference<XInterface> xInst = xFac->createInstance();
981 0 : Any aVal; aVal <<= xInst;
982 0 : xCont->insertByName(pSubNodeNames[j], aVal);
983 : }
984 : }
985 0 : try { xBatch->commitChanges(); }
986 0 : CATCH_INFO("Exception from commitChanges(): ")
987 :
988 0 : const PropertyValue* pProperties = rValues.getConstArray();
989 :
990 0 : Sequence< OUString > aSetNames(rValues.getLength());
991 0 : OUString* pSetNames = aSetNames.getArray();
992 :
993 0 : Sequence< Any> aSetValues(rValues.getLength());
994 0 : Any* pSetValues = aSetValues.getArray();
995 :
996 0 : bool bEmptyNode = rNode.isEmpty();
997 0 : for(sal_Int32 k = 0; k < rValues.getLength(); k++)
998 : {
999 0 : pSetNames[k] = pProperties[k].Name.copy( bEmptyNode ? 1 : 0);
1000 0 : pSetValues[k] = pProperties[k].Value;
1001 : }
1002 0 : bRet = PutProperties(aSetNames, aSetValues);
1003 : }
1004 : else
1005 : {
1006 616 : const PropertyValue* pValues = rValues.getConstArray();
1007 :
1008 : //if no factory is available then the node contains basic data elements
1009 1304 : for(int nValue = 0; nValue < rValues.getLength();nValue++)
1010 : {
1011 : try
1012 : {
1013 688 : OUString sSubNode = lcl_extractSetPropertyName( pValues[nValue].Name, rNode );
1014 :
1015 688 : if(xCont->hasByName(sSubNode))
1016 80 : xCont->replaceByName(sSubNode, pValues[nValue].Value);
1017 : else
1018 608 : xCont->insertByName(sSubNode, pValues[nValue].Value);
1019 : }
1020 0 : CATCH_INFO("Exception from insert/replaceByName(): ");
1021 : }
1022 616 : xBatch->commitChanges();
1023 616 : }
1024 : }
1025 : #ifdef DBG_UTIL
1026 : catch (const Exception& rEx)
1027 : {
1028 : lcl_CFG_DBG_EXCEPTION("Exception from ReplaceSetProperties: ", rEx);
1029 : #else
1030 0 : catch (const Exception&)
1031 : {
1032 : #endif
1033 0 : bRet = false;
1034 616 : }
1035 : }
1036 1232 : return bRet;
1037 : }
1038 :
1039 0 : bool ConfigItem::AddNode(const OUString& rNode, const OUString& rNewNode)
1040 : {
1041 0 : ValueCounter_Impl aCounter(m_nInValueChange);
1042 0 : bool bRet = true;
1043 0 : Reference<XHierarchicalNameAccess> xHierarchyAccess = GetTree();
1044 0 : if(xHierarchyAccess.is())
1045 : {
1046 0 : Reference<XChangesBatch> xBatch(xHierarchyAccess, UNO_QUERY);
1047 : try
1048 : {
1049 0 : Reference<XNameContainer> xCont;
1050 0 : if(!rNode.isEmpty())
1051 : {
1052 0 : Any aNode = xHierarchyAccess->getByHierarchicalName(rNode);
1053 0 : aNode >>= xCont;
1054 : }
1055 : else
1056 0 : xCont = Reference<XNameContainer> (xHierarchyAccess, UNO_QUERY);
1057 0 : if(!xCont.is())
1058 0 : return false;
1059 :
1060 0 : Reference<XSingleServiceFactory> xFac(xCont, UNO_QUERY);
1061 :
1062 0 : if(xFac.is())
1063 : {
1064 0 : if(!xCont->hasByName(rNewNode))
1065 : {
1066 0 : Reference<XInterface> xInst = xFac->createInstance();
1067 0 : Any aVal; aVal <<= xInst;
1068 0 : xCont->insertByName(rNewNode, aVal);
1069 : }
1070 : try
1071 : {
1072 0 : xBatch->commitChanges();
1073 : }
1074 0 : CATCH_INFO("Exception from commitChanges(): ")
1075 : }
1076 : else
1077 : {
1078 : //if no factory is available then the node contains basic data elements
1079 : try
1080 : {
1081 0 : if(!xCont->hasByName(rNewNode))
1082 0 : xCont->insertByName(rNewNode, Any());
1083 : }
1084 0 : CATCH_INFO("Exception from AddNode(): ")
1085 : }
1086 0 : xBatch->commitChanges();
1087 : }
1088 : #ifdef DBG_UTIL
1089 : catch (const Exception& rEx)
1090 : {
1091 : lcl_CFG_DBG_EXCEPTION("Exception from AddNode(): ", rEx);
1092 : #else
1093 0 : catch (const Exception&)
1094 : {
1095 : #endif
1096 0 : bRet = false;
1097 0 : }
1098 : }
1099 0 : return bRet;
1100 : }
1101 :
1102 :
1103 3614 : void ConfigItem::SetModified()
1104 : {
1105 3614 : m_bIsModified = true;
1106 3614 : }
1107 :
1108 771 : void ConfigItem::ClearModified()
1109 : {
1110 771 : m_bIsModified = false;
1111 771 : }
1112 :
1113 :
1114 :
1115 156501 : Reference< XHierarchicalNameAccess> ConfigItem::GetTree()
1116 : {
1117 156501 : Reference< XHierarchicalNameAccess> xRet;
1118 156501 : if(!m_xHierarchyAccess.is())
1119 1149 : xRet = ConfigManager::acquireTree(*this);
1120 : else
1121 155352 : xRet = m_xHierarchyAccess;
1122 156501 : return xRet;
1123 : }
1124 :
1125 327 : void ConfigItem::Commit()
1126 : {
1127 327 : ImplCommit();
1128 327 : ClearModified();
1129 327 : }
1130 :
1131 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|