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