xref: /trunk/main/ucb/source/ucp/hierarchy/hierarchydata.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_ucb.hxx"
30 
31 /**************************************************************************
32                                 TODO
33  **************************************************************************
34 
35  - HierarchyEntry::move
36    --> Rewrite to use XNamed ( once this is supported by config db api ).
37 
38  *************************************************************************/
39 #include "hierarchydata.hxx"
40 
41 #include <vector>
42 #include <osl/diagnose.h>
43 #include <rtl/ustrbuf.hxx>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
46 #include <com/sun/star/container/XNameContainer.hpp>
47 #include <com/sun/star/container/XNameReplace.hpp>
48 #include <com/sun/star/util/XChangesBatch.hpp>
49 #ifndef _COM_SUN_STAR_UTIL_XOFFICEINSTALLTIONDIRECTORIES_HPP_
50 #include <com/sun/star/util/XOfficeInstallationDirectories.hpp>
51 #endif
52 #include "hierarchyprovider.hxx"
53 #include "hierarchyuri.hxx"
54 
55 using namespace com::sun::star;
56 
57 namespace hierarchy_ucp
58 {
59 
60 //=========================================================================
61 struct HierarchyEntry::iterator_Impl
62 {
63     HierarchyEntryData                                     entry;
64     uno::Reference< container::XHierarchicalNameAccess >   dir;
65     uno::Reference< util::XOfficeInstallationDirectories > officeDirs;
66     uno::Sequence< rtl::OUString>                          names;
67     sal_Int32                                              pos;
68     iterator_Impl()
69     : officeDirs( 0 ), pos( -1 /* before first */ ) {};
70 };
71 
72 //=========================================================================
73 void makeXMLName( const rtl::OUString & rIn, rtl::OUStringBuffer & rBuffer  )
74 {
75     sal_Int32 nCount = rIn.getLength();
76     for ( sal_Int32 n = 0; n < nCount; ++n )
77     {
78         const sal_Unicode c = rIn.getStr()[ n ];
79         switch ( c )
80         {
81             case '&':
82                 rBuffer.appendAscii( "&amp;" );
83                 break;
84 
85             case '"':
86                 rBuffer.appendAscii( "&quot;" );
87                 break;
88 
89             case '\'':
90                 rBuffer.appendAscii( "&apos;" );
91                 break;
92 
93             case '<':
94                 rBuffer.appendAscii( "&lt;" );
95                 break;
96 
97             case '>':
98                 rBuffer.appendAscii( "&gt;" );
99                 break;
100 
101             default:
102                 rBuffer.append( c );
103                 break;
104         }
105     }
106 }
107 
108 //=========================================================================
109 //=========================================================================
110 //
111 // HierarchyEntry Implementation.
112 //
113 //=========================================================================
114 //=========================================================================
115 
116 #define READ_SERVICE_NAME      "com.sun.star.ucb.HierarchyDataReadAccess"
117 #define READWRITE_SERVICE_NAME "com.sun.star.ucb.HierarchyDataReadWriteAccess"
118 
119 // describe path of cfg entry
120 #define CFGPROPERTY_NODEPATH    "nodepath"
121 
122 //=========================================================================
123 HierarchyEntry::HierarchyEntry(
124                 const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
125                 HierarchyContentProvider* pProvider,
126                 const rtl::OUString& rURL )
127 : m_xSMgr( rSMgr ),
128   m_xOfficeInstDirs( pProvider->getOfficeInstallationDirectories() ),
129   m_bTriedToGetRootReadAccess( sal_False )
130 {
131     HierarchyUri aUri( rURL );
132     m_aServiceSpecifier = aUri.getService();
133 
134     if ( pProvider )
135     {
136         m_xConfigProvider
137             = pProvider->getConfigProvider( m_aServiceSpecifier );
138         m_xRootReadAccess
139             = pProvider->getRootConfigReadNameAccess( m_aServiceSpecifier );
140     }
141 
142     // Note: do not init m_aPath in init list. createPathFromHierarchyURL
143     //       needs m_xSMgr and m_aMutex.
144     m_aPath = createPathFromHierarchyURL( aUri );
145 
146     // Extract language independent name from URL.
147     sal_Int32 nPos = rURL.lastIndexOf( '/' );
148     if ( nPos > HIERARCHY_URL_SCHEME_LENGTH )
149         m_aName = rURL.copy( nPos + 1 );
150     else
151         OSL_ENSURE( sal_False, "HierarchyEntry - Invalid URL!" );
152 }
153 
154 //=========================================================================
155 sal_Bool HierarchyEntry::hasData()
156 {
157     osl::Guard< osl::Mutex > aGuard( m_aMutex );
158     uno::Reference< container::XHierarchicalNameAccess > xRootReadAccess
159         = getRootReadAccess();
160 
161     OSL_ENSURE( xRootReadAccess.is(), "HierarchyEntry::hasData - No root!" );
162 
163     if ( xRootReadAccess.is() )
164         return xRootReadAccess->hasByHierarchicalName( m_aPath );
165 
166     return sal_False;
167 }
168 
169 //=========================================================================
170 sal_Bool HierarchyEntry::getData( HierarchyEntryData& rData )
171 {
172     try
173     {
174         osl::Guard< osl::Mutex > aGuard( m_aMutex );
175 
176         uno::Reference< container::XHierarchicalNameAccess > xRootReadAccess
177             = getRootReadAccess();
178 
179         OSL_ENSURE( xRootReadAccess.is(),
180                     "HierarchyEntry::getData - No root!" );
181 
182         if ( xRootReadAccess.is() )
183         {
184             rtl::OUString aTitlePath = m_aPath;
185             aTitlePath += rtl::OUString::createFromAscii( "/Title" );
186 
187             // Note: Avoid NoSuchElementExceptions, because exceptions are
188             //       relatively 'expensive'. Checking for availability of
189             //       title value is sufficient here, because if it is
190             //       there, the other values will be available too.
191             if ( !xRootReadAccess->hasByHierarchicalName( aTitlePath ) )
192                 return sal_False;
193 
194             rtl::OUString aValue;
195 
196             // Get Title value.
197             if ( !( xRootReadAccess->getByHierarchicalName( aTitlePath )
198                     >>= aValue ) )
199             {
200                 OSL_ENSURE( sal_False,
201                             "HierarchyEntry::getData - "
202                             "Got no Title value!" );
203                 return sal_False;
204             }
205 
206             rData.setTitle( aValue );
207 
208             // Get TargetURL value.
209             rtl::OUString aTargetURLPath = m_aPath;
210             aTargetURLPath += rtl::OUString::createFromAscii( "/TargetURL" );
211             if ( !( xRootReadAccess->getByHierarchicalName( aTargetURLPath )
212                     >>= aValue ) )
213             {
214                 OSL_ENSURE( sal_False,
215                             "HierarchyEntry::getData - "
216                             "Got no TargetURL value!" );
217                 return sal_False;
218             }
219 
220             // TargetURL property may contain a reference to the Office
221             // installation directory. To ensure a reloctable office
222             // installation, the path to the office installtion directory must
223             // never be stored directly. A placeholder is used instead. Replace
224             // it by actual installation directory.
225             if ( m_xOfficeInstDirs.is() && ( aValue.getLength() > 0 ) )
226                 aValue = m_xOfficeInstDirs->makeAbsoluteURL( aValue );
227             rData.setTargetURL( aValue );
228 
229             rtl::OUString aTypePath = m_aPath;
230             aTypePath += rtl::OUString::createFromAscii( "/Type" );
231             if ( xRootReadAccess->hasByHierarchicalName( aTypePath ) )
232             {
233                 // Might not be present since it was introduced long after
234                 // Title and TargetURL (#82433#)... So not getting it is
235                 // not an error.
236 
237                 // Get Type value.
238                 sal_Int32 nType = 0;
239                 if ( xRootReadAccess->getByHierarchicalName( aTypePath )
240                      >>= nType )
241                 {
242                     if ( nType == 0 )
243                     {
244                         rData.setType( HierarchyEntryData::LINK );
245                     }
246                     else if ( nType == 1 )
247                     {
248                         rData.setType( HierarchyEntryData::FOLDER );
249                     }
250                     else
251                     {
252                         OSL_ENSURE( sal_False,
253                                     "HierarchyEntry::getData - "
254                                     "Unknown Type value!" );
255                         return sal_False;
256                     }
257                 }
258             }
259 
260             rData.setName( m_aName );
261             return sal_True;
262         }
263     }
264     catch ( uno::RuntimeException const & )
265     {
266         throw;
267     }
268     catch ( container::NoSuchElementException const & )
269     {
270         // getByHierarchicalName
271 
272         OSL_ENSURE( sal_False,
273                     "HierarchyEntry::getData - caught NoSuchElementException!" );
274     }
275     return sal_False;
276 }
277 
278 //=========================================================================
279 sal_Bool HierarchyEntry::setData(
280                     const HierarchyEntryData& rData, sal_Bool bCreate )
281 {
282     try
283     {
284         osl::Guard< osl::Mutex > aGuard( m_aMutex );
285 
286         if ( !m_xConfigProvider.is() )
287             m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >(
288                 m_xSMgr->createInstance( m_aServiceSpecifier ),
289                 uno::UNO_QUERY );
290 
291         if ( m_xConfigProvider.is() )
292         {
293             // Create parent's key. It must exist!
294 
295             rtl::OUString aParentPath;
296             sal_Bool bRoot = sal_True;
297 
298             sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
299             if ( nPos != -1 )
300             {
301                 // Skip "/Children" segment of the path, too.
302                 nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
303 
304                 OSL_ENSURE( nPos != -1,
305                             "HierarchyEntry::setData - Wrong path!" );
306 
307                 aParentPath += m_aPath.copy( 0, nPos );
308                 bRoot = sal_False;
309             }
310 
311             uno::Sequence< uno::Any > aArguments( 1 );
312             beans::PropertyValue      aProperty;
313 
314             aProperty.Name    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
315                                                     CFGPROPERTY_NODEPATH ) );
316             aProperty.Value <<= aParentPath;
317             aArguments[ 0 ] <<= aProperty;
318 
319             uno::Reference< util::XChangesBatch > xBatch(
320                     m_xConfigProvider->createInstanceWithArguments(
321                         rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
322                             READWRITE_SERVICE_NAME ) ),
323                         aArguments ),
324                     uno::UNO_QUERY );
325 
326             OSL_ENSURE( xBatch.is(),
327                         "HierarchyEntry::setData - No batch!" );
328 
329             uno::Reference< container::XNameAccess > xParentNameAccess(
330                 xBatch, uno::UNO_QUERY );
331 
332             OSL_ENSURE( xParentNameAccess.is(),
333                         "HierarchyEntry::setData - No name access!" );
334 
335             if ( xBatch.is() && xParentNameAccess.is() )
336             {
337                 // Try to create own key. It must not exist!
338 
339                 sal_Bool bExists = sal_True;
340                 uno::Any aMyKey;
341 
342                 try
343                 {
344                     uno::Reference< container::XNameAccess > xNameAccess;
345 
346                     if ( bRoot )
347                     {
348                         xNameAccess = xParentNameAccess;
349                     }
350                     else
351                     {
352                         xParentNameAccess->getByName(
353                             rtl::OUString::createFromAscii( "Children" ) )
354                                 >>= xNameAccess;
355                     }
356 
357                     if ( xNameAccess->hasByName( m_aName ) )
358                         aMyKey = xNameAccess->getByName( m_aName );
359                     else
360                         bExists = sal_False;
361                 }
362                 catch ( container::NoSuchElementException const & )
363                 {
364                     bExists = sal_False;
365                 }
366 
367                 uno::Reference< container::XNameReplace >   xNameReplace;
368                 uno::Reference< container::XNameContainer > xContainer;
369 
370                 if ( bExists )
371                 {
372                     // Key exists. Replace values.
373 
374                     aMyKey >>= xNameReplace;
375 
376                     OSL_ENSURE( xNameReplace.is(),
377                                 "HierarchyEntry::setData - No name replace!" );
378                 }
379                 else
380                 {
381                     if ( !bCreate )
382                         return sal_True;
383 
384                     // Key does not exist. Create / fill / insert it.
385 
386                     uno::Reference< lang::XSingleServiceFactory > xFac;
387 
388                     if ( bRoot )
389                     {
390                         // Special handling for children of root,
391                         // which is not an entry. It's only a set
392                         // of entries.
393                         xFac = uno::Reference< lang::XSingleServiceFactory >(
394                             xParentNameAccess, uno::UNO_QUERY );
395                     }
396                     else
397                     {
398                         // Append new entry to parents child list,
399                         // which is a set of entries.
400                         xParentNameAccess->getByName(
401                                         rtl::OUString::createFromAscii(
402                                             "Children" ) ) >>= xFac;
403                     }
404 
405                     OSL_ENSURE( xFac.is(),
406                                 "HierarchyEntry::setData - No factory!" );
407 
408                     if ( xFac.is() )
409                     {
410                         xNameReplace
411                             = uno::Reference< container::XNameReplace >(
412                                 xFac->createInstance(), uno::UNO_QUERY );
413 
414                         OSL_ENSURE( xNameReplace.is(),
415                                 "HierarchyEntry::setData - No name replace!" );
416 
417                         if ( xNameReplace.is() )
418                         {
419                             xContainer
420                                 = uno::Reference< container::XNameContainer >(
421                                     xFac, uno::UNO_QUERY );
422 
423                             OSL_ENSURE( xContainer.is(),
424                                 "HierarchyEntry::setData - No container!" );
425                         }
426                     }
427                 }
428 
429                 if ( xNameReplace.is() )
430                 {
431                     // Set Title value.
432                     xNameReplace->replaceByName(
433                         rtl::OUString::createFromAscii( "Title" ),
434                         uno::makeAny( rData.getTitle() ) );
435 
436                     // Set TargetURL value.
437 
438                     // TargetURL property may contain a reference to the Office
439                     // installation directory. To ensure a reloctable office
440                     // installation, the path to the office installtion
441                     // directory must never be stored directly. Use a
442                     // placeholder instead.
443                     rtl::OUString aValue( rData.getTargetURL() );
444                     if ( m_xOfficeInstDirs.is() && ( aValue.getLength() > 0 ) )
445                         aValue
446                             = m_xOfficeInstDirs->makeRelocatableURL( aValue );
447 
448                     xNameReplace->replaceByName(
449                         rtl::OUString::createFromAscii( "TargetURL" ),
450                         uno::makeAny( aValue ) );
451 
452                     // Set Type value.
453                     sal_Int32 nType
454                         = rData.getType() == HierarchyEntryData::LINK ? 0 : 1;
455                     xNameReplace->replaceByName(
456                         rtl::OUString::createFromAscii( "Type" ),
457                         uno::makeAny( nType ) );
458 
459                     if ( xContainer.is() )
460                         xContainer->insertByName(
461                             m_aName, uno::makeAny( xNameReplace ) );
462 
463                     // Commit changes.
464                     xBatch->commitChanges();
465                     return sal_True;
466                 }
467             }
468         }
469     }
470     catch ( uno::RuntimeException const & )
471     {
472         throw;
473     }
474     catch ( lang::IllegalArgumentException const & )
475     {
476         // replaceByName, insertByName
477 
478         OSL_ENSURE(
479             sal_False,
480             "HierarchyEntry::setData - caught IllegalArgumentException!" );
481     }
482     catch ( container::NoSuchElementException const & )
483     {
484         // replaceByName, getByName
485 
486         OSL_ENSURE(
487             sal_False,
488             "HierarchyEntry::setData - caught NoSuchElementException!" );
489     }
490     catch ( container::ElementExistException const & )
491     {
492         // insertByName
493 
494         OSL_ENSURE(
495             sal_False,
496             "HierarchyEntry::setData - caught ElementExistException!" );
497     }
498     catch ( lang::WrappedTargetException const & )
499     {
500         // replaceByName, insertByName, getByName, commitChanges
501 
502         OSL_ENSURE(
503             sal_False,
504             "HierarchyEntry::setData - caught WrappedTargetException!" );
505     }
506     catch ( uno::Exception const & )
507     {
508         // createInstance, createInstanceWithArguments
509 
510         OSL_ENSURE(
511             sal_False,
512             "HierarchyEntry::setData - caught Exception!" );
513     }
514 
515     return sal_False;
516 }
517 
518 //=========================================================================
519 sal_Bool HierarchyEntry::move(
520     const rtl::OUString& rNewURL, const HierarchyEntryData& rData )
521 {
522     osl::Guard< osl::Mutex > aGuard( m_aMutex );
523 
524     rtl::OUString aNewPath = createPathFromHierarchyURL( rNewURL );
525 
526     if ( aNewPath == m_aPath )
527         return sal_True;
528 
529 #if 0
530        // In the "near future"... ( not yet implemented in config db )
531 
532        - get update access for m_aPath
533        - update access -> XNamed
534        - xNamed::setName( newName )
535        - updateaccess commit
536 #else
537 
538     sal_Bool bOldRoot = sal_True;
539     uno::Reference< util::XChangesBatch > xOldParentBatch;
540 
541     rtl::OUString aNewKey;
542     sal_Int32 nURLPos = rNewURL.lastIndexOf( '/' );
543     if ( nURLPos > HIERARCHY_URL_SCHEME_LENGTH )
544         aNewKey = rNewURL.copy( nURLPos + 1 );
545     else
546     {
547         OSL_ENSURE( sal_False, "HierarchyEntry::move - Invalid URL!" );
548         return sal_False;
549     }
550 
551     sal_Bool bNewRoot = sal_True;
552     uno::Reference< util::XChangesBatch > xNewParentBatch;
553 
554     sal_Bool bDifferentParents = sal_True;
555 
556     try
557     {
558         if ( !m_xConfigProvider.is() )
559             m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >(
560                 m_xSMgr->createInstance( m_aServiceSpecifier ),
561                 uno::UNO_QUERY );
562 
563         if ( !m_xConfigProvider.is() )
564             return sal_False;
565 
566         rtl::OUString aOldParentPath;
567         sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
568         if ( nPos != -1 )
569         {
570             // Skip "/Children" segment of the path, too.
571             nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
572 
573             OSL_ENSURE( nPos != -1, "HierarchyEntry::move - Wrong path!" );
574 
575             aOldParentPath += m_aPath.copy( 0, nPos );
576             bOldRoot = sal_False;
577         }
578 
579         rtl::OUString aNewParentPath;
580         nPos = aNewPath.lastIndexOf( '/' );
581         if ( nPos != -1 )
582         {
583             // Skip "/Children" segment of the path, too.
584             nPos = aNewPath.lastIndexOf( '/', nPos - 1 );
585 
586             OSL_ENSURE( nPos != -1, "HierarchyEntry::move - Wrong path!" );
587 
588             aNewParentPath += aNewPath.copy( 0, nPos );
589             bNewRoot = sal_False;
590         }
591 
592         uno::Sequence< uno::Any > aArguments( 1 );
593         beans::PropertyValue      aProperty;
594 
595         aProperty.Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
596                                                     CFGPROPERTY_NODEPATH ) );
597         aProperty.Value <<= aOldParentPath;
598         aArguments[ 0 ] <<= aProperty;
599 
600         xOldParentBatch = uno::Reference< util::XChangesBatch >(
601             m_xConfigProvider->createInstanceWithArguments(
602                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
603                     READWRITE_SERVICE_NAME ) ),
604                 aArguments ),
605             uno::UNO_QUERY );
606 
607         OSL_ENSURE( xOldParentBatch.is(), "HierarchyEntry::move - No batch!" );
608 
609         if ( !xOldParentBatch.is() )
610             return sal_False;
611 
612         if ( aOldParentPath == aNewParentPath )
613         {
614             bDifferentParents = sal_False;
615             xNewParentBatch = xOldParentBatch;
616         }
617         else
618         {
619             bDifferentParents = sal_True;
620 
621             aProperty.Name    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
622                                                     CFGPROPERTY_NODEPATH ) );
623             aProperty.Value <<= aNewParentPath;
624             aArguments[ 0 ] <<= aProperty;
625 
626             xNewParentBatch = uno::Reference< util::XChangesBatch >(
627                 m_xConfigProvider->createInstanceWithArguments(
628                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
629                         READWRITE_SERVICE_NAME ) ),
630                     aArguments ),
631                 uno::UNO_QUERY );
632 
633             OSL_ENSURE(
634                 xNewParentBatch.is(), "HierarchyEntry::move - No batch!" );
635 
636             if ( !xNewParentBatch.is() )
637                 return sal_False;
638         }
639     }
640     catch ( uno::RuntimeException const & )
641     {
642         throw;
643     }
644     catch ( uno::Exception const & )
645     {
646         // createInstance, createInstanceWithArguments
647 
648         OSL_ENSURE( sal_False, "HierarchyEntry::move - caught Exception!" );
649         return sal_False;
650     }
651 
652     //////////////////////////////////////////////////////////////////////
653     // (1) Get entry...
654     //////////////////////////////////////////////////////////////////////
655 
656     uno::Any aEntry;
657     uno::Reference< container::XNameAccess >    xOldParentNameAccess;
658     uno::Reference< container::XNameContainer > xOldNameContainer;
659 
660     try
661     {
662         xOldParentNameAccess
663             = uno::Reference< container::XNameAccess >(
664                 xOldParentBatch, uno::UNO_QUERY );
665 
666         OSL_ENSURE( xOldParentNameAccess.is(),
667                     "HierarchyEntry::move - No name access!" );
668 
669         if ( !xOldParentNameAccess.is() )
670             return sal_False;
671 
672         if ( bOldRoot )
673         {
674             xOldNameContainer = uno::Reference< container::XNameContainer >(
675                                         xOldParentNameAccess, uno::UNO_QUERY );
676         }
677         else
678         {
679             xOldParentNameAccess->getByName(
680                 rtl::OUString::createFromAscii( "Children" ) )
681                     >>= xOldNameContainer;
682         }
683 
684         aEntry = xOldNameContainer->getByName( m_aName );
685     }
686     catch ( container::NoSuchElementException const & )
687     {
688         // getByName
689 
690         OSL_ENSURE( sal_False,
691                     "HierarchyEntry::move - caught NoSuchElementException!" );
692         return sal_False;
693     }
694     catch ( lang::WrappedTargetException const & )
695     {
696         // getByName
697 
698         OSL_ENSURE( sal_False,
699                     "HierarchyEntry::move - caught WrappedTargetException!" );
700         return sal_False;
701     }
702 
703     //////////////////////////////////////////////////////////////////////
704     // (2) Remove entry... Note: Insert BEFORE remove does not work!
705     //////////////////////////////////////////////////////////////////////
706 
707     try
708     {
709         xOldNameContainer->removeByName( m_aName );
710         xOldParentBatch->commitChanges();
711     }
712     catch ( container::NoSuchElementException const & )
713     {
714         // getByName, removeByName
715 
716         OSL_ENSURE( sal_False,
717                     "HierarchyEntry::move - caught NoSuchElementException!" );
718         return sal_False;
719     }
720 
721     //////////////////////////////////////////////////////////////////////
722     // (3) Insert entry at new parent...
723     //////////////////////////////////////////////////////////////////////
724 
725     try
726     {
727         uno::Reference< container::XNameReplace > xNewNameReplace;
728         aEntry >>= xNewNameReplace;
729 
730         OSL_ENSURE( xNewNameReplace.is(),
731                     "HierarchyEntry::move - No name replace!" );
732 
733         if ( !xNewNameReplace.is() )
734             return sal_False;
735 
736         uno::Reference< container::XNameAccess > xNewParentNameAccess;
737         if ( bDifferentParents )
738             xNewParentNameAccess
739                 = uno::Reference< container::XNameAccess >(
740                     xNewParentBatch, uno::UNO_QUERY );
741         else
742             xNewParentNameAccess = xOldParentNameAccess;
743 
744         OSL_ENSURE( xNewParentNameAccess.is(),
745                     "HierarchyEntry::move - No name access!" );
746 
747         if ( !xNewParentNameAccess.is() )
748             return sal_False;
749 
750         uno::Reference< container::XNameContainer > xNewNameContainer;
751         if ( bDifferentParents )
752         {
753             if ( bNewRoot )
754             {
755                 xNewNameContainer
756                     = uno::Reference< container::XNameContainer >(
757                         xNewParentNameAccess, uno::UNO_QUERY );
758             }
759             else
760             {
761                 xNewParentNameAccess->getByName(
762                     rtl::OUString::createFromAscii( "Children" ) )
763                         >>= xNewNameContainer;
764             }
765         }
766         else
767             xNewNameContainer = xOldNameContainer;
768 
769         if ( !xNewNameContainer.is() )
770             return sal_False;
771 
772         xNewNameReplace->replaceByName(
773             rtl::OUString::createFromAscii( "Title" ),
774             uno::makeAny( rData.getTitle() ) );
775 
776         // TargetURL property may contain a reference to the Office
777         // installation directory. To ensure a reloctable office
778         // installation, the path to the office installtion
779         // directory must never be stored directly. Use a placeholder
780         // instead.
781         rtl::OUString aValue( rData.getTargetURL() );
782         if ( m_xOfficeInstDirs.is() && ( aValue.getLength() > 0 ) )
783             aValue = m_xOfficeInstDirs->makeRelocatableURL( aValue );
784         xNewNameReplace->replaceByName(
785             rtl::OUString::createFromAscii( "TargetURL" ),
786             uno::makeAny( aValue ) );
787         sal_Int32 nType = rData.getType() == HierarchyEntryData::LINK ? 0 : 1;
788         xNewNameReplace->replaceByName(
789             rtl::OUString::createFromAscii( "Type" ),
790             uno::makeAny( nType ) );
791 
792         xNewNameContainer->insertByName( aNewKey, aEntry );
793         xNewParentBatch->commitChanges();
794     }
795     catch ( container::NoSuchElementException const & )
796     {
797         // replaceByName, insertByName, getByName
798 
799         OSL_ENSURE( sal_False,
800                     "HierarchyEntry::move - caught NoSuchElementException!" );
801         return sal_False;
802     }
803     catch ( lang::IllegalArgumentException const & )
804     {
805         // replaceByName, insertByName
806 
807         OSL_ENSURE(
808             sal_False,
809             "HierarchyEntry::move - caught IllegalArgumentException!" );
810         return sal_False;
811     }
812     catch ( container::ElementExistException const & )
813     {
814         // insertByName
815 
816         OSL_ENSURE( sal_False,
817                     "HierarchyEntry::move - caught ElementExistException!" );
818         return sal_False;
819     }
820     catch ( lang::WrappedTargetException const & )
821     {
822         // replaceByName, insertByName, getByName
823 
824         OSL_ENSURE( sal_False,
825                     "HierarchyEntry::move - caught WrappedTargetException!" );
826         return sal_False;
827     }
828 
829 #if 0
830     //////////////////////////////////////////////////////////////////////
831     // (4) Commit changes...
832     //////////////////////////////////////////////////////////////////////
833 
834     try
835     {
836         xNewParentBatch->commitChanges();
837 
838         if ( bDifferentParents )
839             xOldParentBatch->commitChanges();
840     }
841     catch ( lang::WrappedTargetException const & )
842     {
843         // commitChanges
844 
845         OSL_ENSURE( sal_False,
846                     "HierarchyEntry::move - caught WrappedTargetException!" );
847         return sal_False;
848     }
849 #endif
850 
851     return sal_True;
852 #endif
853 }
854 
855 //=========================================================================
856 sal_Bool HierarchyEntry::remove()
857 {
858     try
859     {
860         osl::Guard< osl::Mutex > aGuard( m_aMutex );
861 
862         if ( !m_xConfigProvider.is() )
863             m_xConfigProvider = uno::Reference< lang::XMultiServiceFactory >(
864                 m_xSMgr->createInstance( m_aServiceSpecifier ),
865                 uno::UNO_QUERY );
866 
867         if ( m_xConfigProvider.is() )
868         {
869             // Create parent's key. It must exist!
870 
871             rtl::OUString aParentPath;
872             sal_Bool bRoot = sal_True;
873 
874             sal_Int32 nPos = m_aPath.lastIndexOf( '/' );
875             if ( nPos != -1 )
876             {
877                 // Skip "/Children" segment of the path, too.
878                 nPos = m_aPath.lastIndexOf( '/', nPos - 1 );
879 
880                 OSL_ENSURE( nPos != -1,
881                             "HierarchyEntry::remove - Wrong path!" );
882 
883                 aParentPath += m_aPath.copy( 0, nPos );
884                 bRoot = sal_False;
885             }
886 
887             uno::Sequence< uno::Any > aArguments( 1 );
888             beans::PropertyValue      aProperty;
889 
890             aProperty.Name    = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
891                                                     CFGPROPERTY_NODEPATH ) );
892             aProperty.Value <<= aParentPath;
893             aArguments[ 0 ] <<= aProperty;
894 
895             uno::Reference< util::XChangesBatch > xBatch(
896                 m_xConfigProvider->createInstanceWithArguments(
897                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
898                         READWRITE_SERVICE_NAME ) ),
899                     aArguments ),
900                 uno::UNO_QUERY );
901 
902             OSL_ENSURE( xBatch.is(),
903                         "HierarchyEntry::remove - No batch!" );
904 
905             uno::Reference< container::XNameAccess > xParentNameAccess(
906                 xBatch, uno::UNO_QUERY );
907 
908             OSL_ENSURE( xParentNameAccess.is(),
909                         "HierarchyEntry::remove - No name access!" );
910 
911             if ( xBatch.is() && xParentNameAccess.is() )
912             {
913                 uno::Reference< container::XNameContainer > xContainer;
914 
915                 if ( bRoot )
916                 {
917                     // Special handling for children of root,
918                     // which is not an entry. It's only a set
919                     // of entries.
920                     xContainer = uno::Reference< container::XNameContainer >(
921                         xParentNameAccess, uno::UNO_QUERY );
922                 }
923                 else
924                 {
925                     // Append new entry to parents child list,
926                     // which is a set of entries.
927                     xParentNameAccess->getByName(
928                         rtl::OUString::createFromAscii( "Children" ) )
929                             >>= xContainer;
930                 }
931 
932                 OSL_ENSURE( xContainer.is(),
933                             "HierarchyEntry::remove - No container!" );
934 
935                 if ( xContainer.is() )
936                 {
937                     xContainer->removeByName( m_aName );
938                     xBatch->commitChanges();
939                     return sal_True;
940                 }
941             }
942         }
943     }
944     catch ( uno::RuntimeException const & )
945     {
946         throw;
947     }
948     catch ( container::NoSuchElementException const & )
949     {
950         // getByName, removeByName
951 
952         OSL_ENSURE(
953             sal_False,
954             "HierarchyEntry::remove - caught NoSuchElementException!" );
955     }
956     catch ( lang::WrappedTargetException const & )
957     {
958         // getByName, commitChanges
959 
960         OSL_ENSURE(
961             sal_False,
962             "HierarchyEntry::remove - caught WrappedTargetException!" );
963     }
964     catch ( uno::Exception const & )
965     {
966         // createInstance, createInstanceWithArguments
967 
968         OSL_ENSURE( sal_False,
969                     "HierarchyEntry::remove - caught Exception!" );
970     }
971 
972     return sal_False;
973 }
974 
975 //=========================================================================
976 sal_Bool HierarchyEntry::first( iterator& it )
977 {
978     osl::Guard< osl::Mutex > aGuard( m_aMutex );
979 
980     if ( it.m_pImpl->pos == -1 )
981     {
982         // Init...
983 
984         try
985         {
986             uno::Reference< container::XHierarchicalNameAccess >
987                 xRootHierNameAccess = getRootReadAccess();
988 
989             if ( xRootHierNameAccess.is() )
990             {
991                 uno::Reference< container::XNameAccess > xNameAccess;
992 
993                 if ( m_aPath.getLength() > 0 )
994                 {
995                     rtl::OUString aPath = m_aPath;
996                     aPath += rtl::OUString::createFromAscii( "/Children" );
997 
998                     xRootHierNameAccess->getByHierarchicalName( aPath )
999                         >>= xNameAccess;
1000                 }
1001                 else
1002                     xNameAccess
1003                         = uno::Reference< container::XNameAccess >(
1004                                 xRootHierNameAccess, uno::UNO_QUERY );
1005 
1006                 OSL_ENSURE( xNameAccess.is(),
1007                             "HierarchyEntry::first - No name access!" );
1008 
1009                 if ( xNameAccess.is() )
1010                     it.m_pImpl->names = xNameAccess->getElementNames();
1011 
1012                 uno::Reference< container::XHierarchicalNameAccess >
1013                     xHierNameAccess( xNameAccess, uno::UNO_QUERY );
1014 
1015                 OSL_ENSURE( xHierNameAccess.is(),
1016                             "HierarchyEntry::first - No hier. name access!" );
1017 
1018                 it.m_pImpl->dir = xHierNameAccess;
1019 
1020                 it.m_pImpl->officeDirs = m_xOfficeInstDirs;
1021             }
1022         }
1023         catch ( uno::RuntimeException const & )
1024         {
1025             throw;
1026         }
1027         catch ( container::NoSuchElementException const& )
1028         {
1029             // getByHierarchicalName
1030 
1031             OSL_ENSURE(
1032                 sal_False,
1033                 "HierarchyEntry::first - caught NoSuchElementException!" );
1034         }
1035         catch ( uno::Exception const & )
1036         {
1037             OSL_ENSURE( sal_False,
1038                     "HierarchyEntry::first - caught Exception!" );
1039         }
1040     }
1041 
1042     if ( it.m_pImpl->names.getLength() == 0 )
1043         return sal_False;
1044 
1045     it.m_pImpl->pos = 0;
1046     return sal_True;
1047 }
1048 
1049 //=========================================================================
1050 sal_Bool HierarchyEntry::next( iterator& it )
1051 {
1052     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1053 
1054     if ( it.m_pImpl->pos == -1 )
1055         return first( it );
1056 
1057     ++(it.m_pImpl->pos);
1058 
1059     return ( it.m_pImpl->pos < it.m_pImpl->names.getLength() );
1060 }
1061 
1062 //=========================================================================
1063 rtl::OUString HierarchyEntry::createPathFromHierarchyURL(
1064     const HierarchyUri& rURI )
1065 {
1066     // Transform path....
1067     // folder/subfolder/subsubfolder
1068     //      --> ['folder']/Children/['subfolder']/Children/['subsubfolder']
1069 
1070     const rtl::OUString aPath = rURI.getPath().copy( 1 ); // skip leading slash.
1071     sal_Int32 nLen = aPath.getLength();
1072 
1073     if ( nLen )
1074     {
1075         rtl::OUStringBuffer aNewPath;
1076         aNewPath.appendAscii( "['" );
1077 
1078         sal_Int32 nStart = 0;
1079         sal_Int32 nEnd   = aPath.indexOf( '/' );
1080 
1081         do
1082         {
1083             if ( nEnd == -1 )
1084                 nEnd = nLen;
1085 
1086             rtl::OUString aToken = aPath.copy( nStart, nEnd - nStart );
1087             makeXMLName( aToken, aNewPath );
1088 
1089             if ( nEnd != nLen )
1090             {
1091                 aNewPath.appendAscii( "']/Children/['" );
1092                 nStart = nEnd + 1;
1093                 nEnd   = aPath.indexOf( '/', nStart );
1094             }
1095             else
1096                 aNewPath.appendAscii( "']" );
1097         }
1098         while ( nEnd != nLen );
1099 
1100         return aNewPath.makeStringAndClear();
1101     }
1102 
1103     return aPath;
1104 }
1105 
1106 //=========================================================================
1107 uno::Reference< container::XHierarchicalNameAccess >
1108 HierarchyEntry::getRootReadAccess()
1109 {
1110     if ( !m_xRootReadAccess.is() )
1111     {
1112         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1113         if ( !m_xRootReadAccess.is() )
1114         {
1115             if ( m_bTriedToGetRootReadAccess ) // #82494#
1116             {
1117                 OSL_ENSURE( sal_False,
1118                             "HierarchyEntry::getRootReadAccess - "
1119                             "Unable to read any config data! -> #82494#" );
1120                 return uno::Reference< container::XHierarchicalNameAccess >();
1121             }
1122 
1123             try
1124             {
1125                 if ( !m_xConfigProvider.is() )
1126                     m_xConfigProvider
1127                         = uno::Reference< lang::XMultiServiceFactory >(
1128                             m_xSMgr->createInstance( m_aServiceSpecifier ),
1129                             uno::UNO_QUERY );
1130 
1131                 if ( m_xConfigProvider.is() )
1132                 {
1133                     // Create Root object.
1134 
1135                     uno::Sequence< uno::Any > aArguments( 1 );
1136                     beans::PropertyValue      aProperty;
1137                     aProperty.Name = rtl::OUString(
1138                         RTL_CONSTASCII_USTRINGPARAM( CFGPROPERTY_NODEPATH ) );
1139                     aProperty.Value <<= rtl::OUString(); // root path
1140                     aArguments[ 0 ] <<= aProperty;
1141 
1142                     m_bTriedToGetRootReadAccess = sal_True;
1143 
1144                     m_xRootReadAccess
1145                         = uno::Reference< container::XHierarchicalNameAccess >(
1146                             m_xConfigProvider->createInstanceWithArguments(
1147                                 rtl::OUString(
1148                                     RTL_CONSTASCII_USTRINGPARAM(
1149                                         READ_SERVICE_NAME ) ),
1150                                 aArguments ),
1151                             uno::UNO_QUERY );
1152                 }
1153             }
1154             catch ( uno::RuntimeException const & )
1155             {
1156                 throw;
1157             }
1158             catch ( uno::Exception const & )
1159             {
1160                 // createInstance, createInstanceWithArguments
1161 
1162                 OSL_ENSURE( sal_False,
1163                             "HierarchyEntry::getRootReadAccess - "
1164                             "caught Exception!" );
1165             }
1166         }
1167     }
1168     return m_xRootReadAccess;
1169 }
1170 
1171 //=========================================================================
1172 //=========================================================================
1173 //
1174 // HierarchyEntry::iterator Implementation.
1175 //
1176 //=========================================================================
1177 //=========================================================================
1178 
1179 HierarchyEntry::iterator::iterator()
1180 {
1181     m_pImpl = new iterator_Impl;
1182 }
1183 
1184 //=========================================================================
1185 HierarchyEntry::iterator::~iterator()
1186 {
1187     delete m_pImpl;
1188 }
1189 
1190 //=========================================================================
1191 const HierarchyEntryData& HierarchyEntry::iterator::operator*() const
1192 {
1193     if ( ( m_pImpl->pos != -1 )
1194          && ( m_pImpl->dir.is() )
1195          && ( m_pImpl->pos < m_pImpl->names.getLength() ) )
1196     {
1197         try
1198         {
1199             rtl::OUStringBuffer aKey;
1200             aKey.appendAscii( "['" );
1201             makeXMLName( m_pImpl->names.getConstArray()[ m_pImpl->pos ], aKey );
1202             aKey.appendAscii( "']" );
1203 
1204             rtl::OUString aTitle     = aKey.makeStringAndClear();
1205             rtl::OUString aTargetURL = aTitle;
1206             rtl::OUString aType      = aTitle;
1207 
1208             aTitle     += rtl::OUString::createFromAscii( "/Title" );
1209             aTargetURL += rtl::OUString::createFromAscii( "/TargetURL" );
1210             aType      += rtl::OUString::createFromAscii( "/Type" );
1211 
1212             rtl::OUString aValue;
1213             m_pImpl->dir->getByHierarchicalName( aTitle ) >>= aValue;
1214             m_pImpl->entry.setTitle( aValue );
1215 
1216             m_pImpl->dir->getByHierarchicalName( aTargetURL ) >>= aValue;
1217 
1218             // TargetURL property may contain a reference to the Office
1219             // installation directory. To ensure a reloctable office
1220             // installation, the path to the office installtion directory must
1221             // never be stored directly. A placeholder is used instead. Replace
1222             // it by actual installation directory.
1223             if ( m_pImpl->officeDirs.is() && ( aValue.getLength() > 0 ) )
1224                 aValue = m_pImpl->officeDirs->makeAbsoluteURL( aValue );
1225             m_pImpl->entry.setTargetURL( aValue );
1226 
1227             if ( m_pImpl->dir->hasByHierarchicalName( aType ) )
1228             {
1229                 // Might not be present since it was introduced long
1230                 // after Title and TargetURL (#82433#)... So not getting
1231                 // it is not an error.
1232 
1233                 // Get Type value.
1234                 sal_Int32 nType = 0;
1235                 if ( m_pImpl->dir->getByHierarchicalName( aType ) >>= nType )
1236                 {
1237                     if ( nType == 0 )
1238                     {
1239                         m_pImpl->entry.setType( HierarchyEntryData::LINK );
1240                     }
1241                     else if ( nType == 1 )
1242                     {
1243                         m_pImpl->entry.setType( HierarchyEntryData::FOLDER );
1244                     }
1245                     else
1246                     {
1247                         OSL_ENSURE( sal_False,
1248                                     "HierarchyEntry::getData - "
1249                                     "Unknown Type value!" );
1250                     }
1251                 }
1252             }
1253 
1254             m_pImpl->entry.setName(
1255                 m_pImpl->names.getConstArray()[ m_pImpl->pos ] );
1256         }
1257         catch ( container::NoSuchElementException const & )
1258         {
1259             m_pImpl->entry = HierarchyEntryData();
1260         }
1261     }
1262 
1263     return m_pImpl->entry;
1264 }
1265 
1266 } // namespace hierarchy_ucp
1267