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