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  - optimize transfer command. "Move" should be implementable much more
36    efficient!
37 
38  **************************************************************************
39 
40  - Root Folder vs. 'normal' Folder
41     - root doesn't support command 'delete'
42     - root doesn't support command 'insert'
43     - root needs not created via XContentCreator - queryContent with root
44       folder id ( HIERARCHY_ROOT_FOLDER_URL ) always returns a value != 0
45     - root has no parent.
46 
47  *************************************************************************/
48 #include <osl/diagnose.h>
49 
50 #include "osl/doublecheckedlocking.h"
51 #include <rtl/ustring.h>
52 #include <rtl/ustring.hxx>
53 #include <com/sun/star/beans/PropertyAttribute.hpp>
54 #include <com/sun/star/beans/PropertyState.hpp>
55 #include <com/sun/star/beans/PropertyValue.hpp>
56 #include <com/sun/star/beans/XPropertyAccess.hpp>
57 #include <com/sun/star/lang/IllegalAccessException.hpp>
58 #include <com/sun/star/sdbc/XRow.hpp>
59 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
60 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
61 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
62 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
63 #include <com/sun/star/ucb/NameClash.hpp>
64 #include <com/sun/star/ucb/NameClashException.hpp>
65 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
66 #include <com/sun/star/ucb/TransferInfo.hpp>
67 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
68 #include <com/sun/star/ucb/XCommandInfo.hpp>
69 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
70 #include <com/sun/star/uno/Any.hxx>
71 #include <com/sun/star/uno/Sequence.hxx>
72 #include <ucbhelper/contentidentifier.hxx>
73 #include <ucbhelper/propertyvalueset.hxx>
74 #include <ucbhelper/cancelcommandexecution.hxx>
75 #include "hierarchycontent.hxx"
76 #include "hierarchyprovider.hxx"
77 #include "dynamicresultset.hxx"
78 #include "hierarchyuri.hxx"
79 
80 #include "../inc/urihelper.hxx"
81 
82 using namespace com::sun::star;
83 using namespace hierarchy_ucp;
84 
85 //=========================================================================
86 //=========================================================================
87 //
88 // HierarchyContent Implementation.
89 //
90 //=========================================================================
91 //=========================================================================
92 
93 // static ( "virtual" ctor )
94 HierarchyContent* HierarchyContent::create(
95             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
96             HierarchyContentProvider* pProvider,
97             const uno::Reference< ucb::XContentIdentifier >& Identifier )
98 {
99     // Fail, if content does not exist.
100     HierarchyContentProperties aProps;
101     if ( !loadData( rxSMgr, pProvider, Identifier, aProps ) )
102         return 0;
103 
104     return new HierarchyContent( rxSMgr, pProvider, Identifier, aProps );
105 }
106 
107 //=========================================================================
108 // static ( "virtual" ctor )
109 HierarchyContent* HierarchyContent::create(
110             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
111             HierarchyContentProvider* pProvider,
112             const uno::Reference< ucb::XContentIdentifier >& Identifier,
113             const ucb::ContentInfo& Info )
114 {
115     if ( !Info.Type.getLength() )
116         return 0;
117 
118     if ( !Info.Type.equalsAsciiL(
119             RTL_CONSTASCII_STRINGPARAM( HIERARCHY_FOLDER_CONTENT_TYPE ) ) &&
120          !Info.Type.equalsAsciiL(
121             RTL_CONSTASCII_STRINGPARAM( HIERARCHY_LINK_CONTENT_TYPE ) ) )
122         return 0;
123 
124 #if 0
125     // Fail, if content does exist.
126     if ( hasData( rxSMgr, pProvider, Identifier ) )
127         return 0;
128 #endif
129 
130     return new HierarchyContent( rxSMgr, pProvider, Identifier, Info );
131 }
132 
133 //=========================================================================
134 HierarchyContent::HierarchyContent(
135             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
136             HierarchyContentProvider* pProvider,
137             const uno::Reference< ucb::XContentIdentifier >& Identifier,
138             const HierarchyContentProperties& rProps )
139 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
140   m_aProps( rProps ),
141   m_eState( PERSISTENT ),
142   m_pProvider( pProvider ),
143   m_bCheckedReadOnly( false ),
144   m_bIsReadOnly( true )
145 {
146     setKind( Identifier );
147 }
148 
149 //=========================================================================
150 HierarchyContent::HierarchyContent(
151             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
152             HierarchyContentProvider* pProvider,
153             const uno::Reference< ucb::XContentIdentifier >& Identifier,
154             const ucb::ContentInfo& Info )
155   : ContentImplHelper( rxSMgr, pProvider, Identifier ),
156   m_aProps( Info.Type.equalsAsciiL(
157                 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_FOLDER_CONTENT_TYPE ) )
158             ? HierarchyEntryData::FOLDER
159             : HierarchyEntryData::LINK ),
160   m_eState( TRANSIENT ),
161   m_pProvider( pProvider ),
162   m_bCheckedReadOnly( false ),
163   m_bIsReadOnly( true )
164 {
165     setKind( Identifier );
166 }
167 
168 //=========================================================================
169 // virtual
170 HierarchyContent::~HierarchyContent()
171 {
172 }
173 
174 //=========================================================================
175 //
176 // XInterface methods.
177 //
178 //=========================================================================
179 
180 // virtual
181 void SAL_CALL HierarchyContent::acquire()
182     throw( )
183 {
184     ContentImplHelper::acquire();
185 }
186 
187 //=========================================================================
188 // virtual
189 void SAL_CALL HierarchyContent::release()
190     throw( )
191 {
192     ContentImplHelper::release();
193 }
194 
195 //=========================================================================
196 // virtual
197 uno::Any SAL_CALL HierarchyContent::queryInterface( const uno::Type & rType )
198     throw ( uno::RuntimeException )
199 {
200     uno::Any aRet = ContentImplHelper::queryInterface( rType );
201 
202     if ( !aRet.hasValue() )
203     {
204         // Note: isReadOnly may be relative expensive. So avoid calling it
205         //       unless it is really necessary.
206         aRet = cppu::queryInterface(
207                 rType, static_cast< ucb::XContentCreator * >( this ) );
208         if ( aRet.hasValue() )
209         {
210             if ( !isFolder() || isReadOnly() )
211                 return uno::Any();
212         }
213     }
214 
215     return aRet;
216 }
217 
218 //=========================================================================
219 //
220 // XTypeProvider methods.
221 //
222 //=========================================================================
223 
224 XTYPEPROVIDER_COMMON_IMPL( HierarchyContent );
225 
226 //=========================================================================
227 // virtual
228 uno::Sequence< uno::Type > SAL_CALL HierarchyContent::getTypes()
229     throw( uno::RuntimeException )
230 {
231     cppu::OTypeCollection * pCollection = 0;
232 
233     if ( isFolder() && !isReadOnly() )
234     {
235         static cppu::OTypeCollection* pFolderTypes = 0;
236 
237         pCollection = pFolderTypes;
238         if ( !pCollection )
239         {
240             osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
241 
242             pCollection = pFolderTypes;
243             if ( !pCollection )
244             {
245                 static cppu::OTypeCollection aCollection(
246                     CPPU_TYPE_REF( lang::XTypeProvider ),
247                     CPPU_TYPE_REF( lang::XServiceInfo ),
248                     CPPU_TYPE_REF( lang::XComponent ),
249                     CPPU_TYPE_REF( ucb::XContent ),
250                     CPPU_TYPE_REF( ucb::XCommandProcessor ),
251                     CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
252                     CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
253                     CPPU_TYPE_REF( beans::XPropertyContainer ),
254                     CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
255                     CPPU_TYPE_REF( container::XChild ),
256                     CPPU_TYPE_REF( ucb::XContentCreator ) ); // !!
257                 pCollection = &aCollection;
258                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
259                 pFolderTypes = pCollection;
260             }
261         }
262         else {
263             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
264         }
265     }
266     else
267     {
268         static cppu::OTypeCollection* pDocumentTypes = 0;
269 
270         pCollection = pDocumentTypes;
271         if ( !pCollection )
272         {
273             osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
274 
275             pCollection = pDocumentTypes;
276             if ( !pCollection )
277             {
278                 static cppu::OTypeCollection aCollection(
279                     CPPU_TYPE_REF( lang::XTypeProvider ),
280                     CPPU_TYPE_REF( lang::XServiceInfo ),
281                     CPPU_TYPE_REF( lang::XComponent ),
282                     CPPU_TYPE_REF( ucb::XContent ),
283                     CPPU_TYPE_REF( ucb::XCommandProcessor ),
284                     CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
285                     CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
286                     CPPU_TYPE_REF( beans::XPropertyContainer ),
287                     CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
288                     CPPU_TYPE_REF( container::XChild ) );
289                 pCollection = &aCollection;
290                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
291                 pDocumentTypes = pCollection;
292             }
293         }
294         else {
295             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
296         }
297     }
298 
299     return (*pCollection).getTypes();
300 }
301 
302 //=========================================================================
303 //
304 // XServiceInfo methods.
305 //
306 //=========================================================================
307 
308 // virtual
309 rtl::OUString SAL_CALL HierarchyContent::getImplementationName()
310     throw( uno::RuntimeException )
311 {
312     return rtl::OUString::createFromAscii(
313                             "com.sun.star.comp.ucb.HierarchyContent" );
314 }
315 
316 //=========================================================================
317 // virtual
318 uno::Sequence< rtl::OUString > SAL_CALL
319 HierarchyContent::getSupportedServiceNames()
320     throw( uno::RuntimeException )
321 {
322     uno::Sequence< rtl::OUString > aSNS( 1 );
323 
324     if ( m_eKind == LINK )
325         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
326                                 HIERARCHY_LINK_CONTENT_SERVICE_NAME );
327     else if ( m_eKind == FOLDER )
328         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
329                                 HIERARCHY_FOLDER_CONTENT_SERVICE_NAME );
330     else
331         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
332                                 HIERARCHY_ROOT_FOLDER_CONTENT_SERVICE_NAME );
333 
334     return aSNS;
335 }
336 
337 //=========================================================================
338 //
339 // XContent methods.
340 //
341 //=========================================================================
342 
343 // virtual
344 rtl::OUString SAL_CALL HierarchyContent::getContentType()
345     throw( uno::RuntimeException )
346 {
347     return m_aProps.getContentType();
348 }
349 
350 //=========================================================================
351 // virtual
352 uno::Reference< ucb::XContentIdentifier > SAL_CALL
353 HierarchyContent::getIdentifier()
354     throw( uno::RuntimeException )
355 {
356     // Transient?
357     if ( m_eState == TRANSIENT )
358     {
359         // Transient contents have no identifier.
360         return uno::Reference< ucb::XContentIdentifier >();
361     }
362 
363     return ContentImplHelper::getIdentifier();
364 }
365 
366 //=========================================================================
367 //
368 // XCommandProcessor methods.
369 //
370 //=========================================================================
371 
372 // virtual
373 uno::Any SAL_CALL HierarchyContent::execute(
374         const ucb::Command& aCommand,
375         sal_Int32 /*CommandId*/,
376         const uno::Reference< ucb::XCommandEnvironment >& Environment )
377     throw( uno::Exception,
378            ucb::CommandAbortedException,
379            uno::RuntimeException )
380 {
381     uno::Any aRet;
382 
383     if ( aCommand.Name.equalsAsciiL(
384             RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
385     {
386         //////////////////////////////////////////////////////////////////
387         // getPropertyValues
388         //////////////////////////////////////////////////////////////////
389 
390         uno::Sequence< beans::Property > Properties;
391         if ( !( aCommand.Argument >>= Properties ) )
392         {
393             ucbhelper::cancelCommandExecution(
394                 uno::makeAny( lang::IllegalArgumentException(
395                                     rtl::OUString::createFromAscii(
396                                         "Wrong argument type!" ),
397                                     static_cast< cppu::OWeakObject * >( this ),
398                                     -1 ) ),
399                 Environment );
400             // Unreachable
401         }
402 
403         aRet <<= getPropertyValues( Properties );
404     }
405     else if ( aCommand.Name.equalsAsciiL(
406                 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
407     {
408         //////////////////////////////////////////////////////////////////
409         // setPropertyValues
410         //////////////////////////////////////////////////////////////////
411 
412         uno::Sequence< beans::PropertyValue > aProperties;
413         if ( !( aCommand.Argument >>= aProperties ) )
414         {
415             ucbhelper::cancelCommandExecution(
416                 uno::makeAny( lang::IllegalArgumentException(
417                                     rtl::OUString::createFromAscii(
418                                         "Wrong argument type!" ),
419                                     static_cast< cppu::OWeakObject * >( this ),
420                                     -1 ) ),
421                 Environment );
422             // Unreachable
423         }
424 
425         if ( !aProperties.getLength() )
426         {
427             ucbhelper::cancelCommandExecution(
428                 uno::makeAny( lang::IllegalArgumentException(
429                                     rtl::OUString::createFromAscii(
430                                         "No properties!" ),
431                                     static_cast< cppu::OWeakObject * >( this ),
432                                     -1 ) ),
433                 Environment );
434             // Unreachable
435         }
436 
437         aRet <<= setPropertyValues( aProperties, Environment );
438     }
439     else if ( aCommand.Name.equalsAsciiL(
440                 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
441     {
442         //////////////////////////////////////////////////////////////////
443         // getPropertySetInfo
444         //////////////////////////////////////////////////////////////////
445 
446         aRet <<= getPropertySetInfo( Environment );
447     }
448     else if ( aCommand.Name.equalsAsciiL(
449                 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
450     {
451         //////////////////////////////////////////////////////////////////
452         // getCommandInfo
453         //////////////////////////////////////////////////////////////////
454 
455         aRet <<= getCommandInfo( Environment );
456     }
457     else if ( aCommand.Name.equalsAsciiL(
458                   RTL_CONSTASCII_STRINGPARAM( "open" ) ) && isFolder() )
459     {
460         //////////////////////////////////////////////////////////////////
461         // open command for a folder content
462         //////////////////////////////////////////////////////////////////
463 
464         ucb::OpenCommandArgument2 aOpenCommand;
465         if ( !( aCommand.Argument >>= aOpenCommand ) )
466         {
467             ucbhelper::cancelCommandExecution(
468                 uno::makeAny( lang::IllegalArgumentException(
469                                     rtl::OUString::createFromAscii(
470                                         "Wrong argument type!" ),
471                                     static_cast< cppu::OWeakObject * >( this ),
472                                     -1 ) ),
473                 Environment );
474             // Unreachable
475         }
476 
477         uno::Reference< ucb::XDynamicResultSet > xSet
478                 = new DynamicResultSet( m_xSMgr, this, aOpenCommand );
479         aRet <<= xSet;
480     }
481     else if ( aCommand.Name.equalsAsciiL(
482                   RTL_CONSTASCII_STRINGPARAM( "insert" ) ) &&
483               ( m_eKind != ROOT ) && !isReadOnly() )
484     {
485         //////////////////////////////////////////////////////////////////
486         // insert
487         //  ( Not available at root folder )
488         //////////////////////////////////////////////////////////////////
489 
490         ucb::InsertCommandArgument aArg;
491         if ( !( aCommand.Argument >>= aArg ) )
492         {
493             ucbhelper::cancelCommandExecution(
494                 uno::makeAny( lang::IllegalArgumentException(
495                                     rtl::OUString::createFromAscii(
496                                         "Wrong argument type!" ),
497                                     static_cast< cppu::OWeakObject * >( this ),
498                                     -1 ) ),
499                 Environment );
500             // Unreachable
501         }
502 
503         sal_Int32 nNameClash = aArg.ReplaceExisting
504                              ? ucb::NameClash::OVERWRITE
505                              : ucb::NameClash::ERROR;
506         insert( nNameClash, Environment );
507     }
508     else if ( aCommand.Name.equalsAsciiL(
509                   RTL_CONSTASCII_STRINGPARAM( "delete" ) ) &&
510               ( m_eKind != ROOT ) && !isReadOnly() )
511     {
512         //////////////////////////////////////////////////////////////////
513         // delete
514         //  ( Not available at root folder )
515         //////////////////////////////////////////////////////////////////
516 
517         sal_Bool bDeletePhysical = sal_False;
518         aCommand.Argument >>= bDeletePhysical;
519         destroy( bDeletePhysical, Environment );
520 
521         // Remove own and all children's persistent data.
522         if ( !removeData() )
523         {
524             uno::Any aProps
525                 = uno::makeAny(
526                          beans::PropertyValue(
527                              rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
528                                                "Uri")),
529                              -1,
530                              uno::makeAny(m_xIdentifier->
531                                               getContentIdentifier()),
532                              beans::PropertyState_DIRECT_VALUE));
533             ucbhelper::cancelCommandExecution(
534                 ucb::IOErrorCode_CANT_WRITE,
535                 uno::Sequence< uno::Any >(&aProps, 1),
536                 Environment,
537                 rtl::OUString::createFromAscii(
538                     "Cannot remove persistent data!" ),
539                 this );
540             // Unreachable
541         }
542 
543         // Remove own and all children's Additional Core Properties.
544         removeAdditionalPropertySet( sal_True );
545     }
546     else if ( aCommand.Name.equalsAsciiL(
547                   RTL_CONSTASCII_STRINGPARAM( "transfer" ) ) &&
548               isFolder() && !isReadOnly() )
549     {
550         //////////////////////////////////////////////////////////////////
551         // transfer
552         //      ( Not available at link objects )
553         //////////////////////////////////////////////////////////////////
554 
555         ucb::TransferInfo aInfo;
556         if ( !( aCommand.Argument >>= aInfo ) )
557         {
558             OSL_ENSURE( sal_False, "Wrong argument type!" );
559             ucbhelper::cancelCommandExecution(
560                 uno::makeAny( lang::IllegalArgumentException(
561                                     rtl::OUString::createFromAscii(
562                                         "Wrong argument type!" ),
563                                     static_cast< cppu::OWeakObject * >( this ),
564                                     -1 ) ),
565                 Environment );
566             // Unreachable
567         }
568 
569         transfer( aInfo, Environment );
570     }
571     else if ( aCommand.Name.equalsAsciiL(
572                   RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) &&
573               isFolder() && !isReadOnly() )
574     {
575         //////////////////////////////////////////////////////////////////
576         // createNewContent
577         //      ( Not available at link objects )
578         //////////////////////////////////////////////////////////////////
579 
580         ucb::ContentInfo aInfo;
581         if ( !( aCommand.Argument >>= aInfo ) )
582         {
583             OSL_ENSURE( sal_False, "Wrong argument type!" );
584             ucbhelper::cancelCommandExecution(
585                 uno::makeAny( lang::IllegalArgumentException(
586                                     rtl::OUString::createFromAscii(
587                                         "Wrong argument type!" ),
588                                     static_cast< cppu::OWeakObject * >( this ),
589                                     -1 ) ),
590                 Environment );
591             // Unreachable
592         }
593 
594         aRet <<= createNewContent( aInfo );
595     }
596     else
597     {
598         //////////////////////////////////////////////////////////////////
599         // Unsupported command
600         //////////////////////////////////////////////////////////////////
601 
602         ucbhelper::cancelCommandExecution(
603             uno::makeAny( ucb::UnsupportedCommandException(
604                                 rtl::OUString(),
605                                 static_cast< cppu::OWeakObject * >( this ) ) ),
606             Environment );
607         // Unreachable
608     }
609 
610     return aRet;
611 }
612 
613 //=========================================================================
614 // virtual
615 void SAL_CALL HierarchyContent::abort( sal_Int32 /*CommandId*/ )
616     throw( uno::RuntimeException )
617 {
618     // @@@ Generally, no action takes much time...
619 }
620 
621 //=========================================================================
622 //
623 // XContentCreator methods.
624 //
625 //=========================================================================
626 
627 // virtual
628 uno::Sequence< ucb::ContentInfo > SAL_CALL
629 HierarchyContent::queryCreatableContentsInfo()
630     throw( uno::RuntimeException )
631 {
632     return m_aProps.getCreatableContentsInfo();
633 }
634 
635 //=========================================================================
636 // virtual
637 uno::Reference< ucb::XContent > SAL_CALL
638 HierarchyContent::createNewContent( const ucb::ContentInfo& Info )
639     throw( uno::RuntimeException )
640 {
641     if ( isFolder() )
642     {
643         osl::Guard< osl::Mutex > aGuard( m_aMutex );
644 
645         if ( !Info.Type.getLength() )
646             return uno::Reference< ucb::XContent >();
647 
648         sal_Bool bCreateFolder =
649             Info.Type.equalsAsciiL(
650                 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_FOLDER_CONTENT_TYPE ) );
651 
652         if ( !bCreateFolder &&
653              !Info.Type.equalsAsciiL(
654                 RTL_CONSTASCII_STRINGPARAM( HIERARCHY_LINK_CONTENT_TYPE ) ) )
655             return uno::Reference< ucb::XContent >();
656 
657         rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
658 
659         OSL_ENSURE( aURL.getLength() > 0,
660                     "HierarchyContent::createNewContent - empty identifier!" );
661 
662         if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
663             aURL += rtl::OUString::createFromAscii( "/" );
664 
665         if ( bCreateFolder )
666             aURL += rtl::OUString::createFromAscii( "New_Folder" );
667         else
668             aURL += rtl::OUString::createFromAscii( "New_Link" );
669 
670         uno::Reference< ucb::XContentIdentifier > xId
671             = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL );
672 
673         return create( m_xSMgr, m_pProvider, xId, Info );
674     }
675     else
676     {
677         OSL_ENSURE( sal_False,
678                     "createNewContent called on non-folder object!" );
679         return uno::Reference< ucb::XContent >();
680     }
681 }
682 
683 //=========================================================================
684 // virtual
685 rtl::OUString HierarchyContent::getParentURL()
686 {
687     HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
688     return aUri.getParentUri();
689 }
690 
691 //=========================================================================
692 //static
693 sal_Bool HierarchyContent::hasData(
694             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
695             HierarchyContentProvider* pProvider,
696             const uno::Reference< ucb::XContentIdentifier >& Identifier )
697 {
698     rtl::OUString aURL = Identifier->getContentIdentifier();
699 
700     // Am I a root folder?
701     HierarchyUri aUri( aURL );
702     if ( aUri.isRootFolder() )
703     {
704         // hasData must always return 'true' for root folder
705         // even if no persistent data exist!!!
706         return sal_True;
707     }
708 
709     return HierarchyEntry( rxSMgr, pProvider, aURL ).hasData();
710 }
711 
712 //=========================================================================
713 //static
714 sal_Bool HierarchyContent::loadData(
715             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
716             HierarchyContentProvider* pProvider,
717             const uno::Reference< ucb::XContentIdentifier >& Identifier,
718             HierarchyContentProperties& rProps )
719 {
720     rtl::OUString aURL = Identifier->getContentIdentifier();
721 
722     // Am I a root folder?
723     HierarchyUri aUri( aURL );
724     if ( aUri.isRootFolder() )
725     {
726         rProps = HierarchyContentProperties( HierarchyEntryData::FOLDER );
727     }
728     else
729     {
730         HierarchyEntry aEntry( rxSMgr, pProvider, aURL );
731         HierarchyEntryData aData;
732         if ( !aEntry.getData( aData ) )
733             return sal_False;
734 
735         rProps = HierarchyContentProperties( aData );
736     }
737     return sal_True;
738 }
739 
740 //=========================================================================
741 sal_Bool HierarchyContent::storeData()
742 {
743     HierarchyEntry aEntry(
744             m_xSMgr, m_pProvider, m_xIdentifier->getContentIdentifier() );
745     return aEntry.setData( m_aProps.getHierarchyEntryData(), sal_True );
746 }
747 
748 //=========================================================================
749 sal_Bool HierarchyContent::renameData(
750             const uno::Reference< ucb::XContentIdentifier >& xOldId,
751             const uno::Reference< ucb::XContentIdentifier >& xNewId )
752 {
753     HierarchyEntry aEntry(
754             m_xSMgr, m_pProvider, xOldId->getContentIdentifier() );
755     return aEntry.move( xNewId->getContentIdentifier(),
756                         m_aProps.getHierarchyEntryData() );
757 }
758 
759 //=========================================================================
760 sal_Bool HierarchyContent::removeData()
761 {
762     HierarchyEntry aEntry(
763         m_xSMgr, m_pProvider, m_xIdentifier->getContentIdentifier() );
764     return aEntry.remove();
765 }
766 
767 //=========================================================================
768 void HierarchyContent::setKind(
769             const uno::Reference< ucb::XContentIdentifier >& Identifier )
770 {
771     if ( m_aProps.getIsFolder() )
772     {
773         // Am I a root folder?
774         HierarchyUri aUri( Identifier->getContentIdentifier() );
775         if ( aUri.isRootFolder() )
776             m_eKind = ROOT;
777         else
778             m_eKind = FOLDER;
779     }
780     else
781         m_eKind = LINK;
782 }
783 
784 //=========================================================================
785 bool HierarchyContent::isReadOnly()
786 {
787     if ( !m_bCheckedReadOnly )
788     {
789         osl::Guard< osl::Mutex > aGuard( m_aMutex );
790         if ( !m_bCheckedReadOnly )
791         {
792             m_bCheckedReadOnly = true;
793             m_bIsReadOnly      = true;
794 
795             HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
796             uno::Reference< lang::XMultiServiceFactory > xConfigProv
797                 = m_pProvider->getConfigProvider( aUri.getService() );
798             if ( xConfigProv.is() )
799             {
800                 uno::Sequence< rtl::OUString > aNames
801                     = xConfigProv->getAvailableServiceNames();
802                 sal_Int32 nCount = aNames.getLength();
803                 for ( sal_Int32 n = 0; n < nCount; ++n )
804                 {
805                     if ( aNames[ n ].equalsAsciiL(
806                             RTL_CONSTASCII_STRINGPARAM(
807                                 "com.sun.star.ucb.HierarchyDataReadWriteAccess"
808                              ) ) )
809                     {
810                         m_bIsReadOnly = false;
811                         break;
812                     }
813                 }
814             }
815         }
816     }
817 
818     return m_bIsReadOnly;
819 }
820 
821 //=========================================================================
822 uno::Reference< ucb::XContentIdentifier >
823 HierarchyContent::makeNewIdentifier( const rtl::OUString& rTitle )
824 {
825     osl::Guard< osl::Mutex > aGuard( m_aMutex );
826 
827     // Assemble new content identifier...
828     HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
829     rtl::OUString aNewURL = aUri.getParentUri();
830     aNewURL += rtl::OUString::createFromAscii( "/" );
831     aNewURL += ::ucb_impl::urihelper::encodeSegment( rTitle );
832 
833     return uno::Reference< ucb::XContentIdentifier >(
834         new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewURL ) );
835 }
836 
837 //=========================================================================
838 void HierarchyContent::queryChildren( HierarchyContentRefList& rChildren )
839 {
840     if ( ( m_eKind != FOLDER ) && ( m_eKind != ROOT ) )
841         return;
842 
843     // Obtain a list with a snapshot of all currently instanciated contents
844     // from provider and extract the contents which are direct children
845     // of this content.
846 
847     ::ucbhelper::ContentRefList aAllContents;
848     m_xProvider->queryExistingContents( aAllContents );
849 
850     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
851     sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
852 
853     if ( nURLPos != ( aURL.getLength() - 1 ) )
854     {
855         // No trailing slash found. Append.
856         aURL += rtl::OUString::createFromAscii( "/" );
857     }
858 
859     sal_Int32 nLen = aURL.getLength();
860 
861     ::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
862     ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
863 
864     while ( it != end )
865     {
866         ::ucbhelper::ContentImplHelperRef xChild = (*it);
867         rtl::OUString aChildURL
868             = xChild->getIdentifier()->getContentIdentifier();
869 
870         // Is aURL a prefix of aChildURL?
871         if ( ( aChildURL.getLength() > nLen ) &&
872              ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
873         {
874             sal_Int32 nPos = nLen;
875             nPos = aChildURL.indexOf( '/', nPos );
876 
877             if ( ( nPos == -1 ) ||
878                  ( nPos == ( aChildURL.getLength() - 1 ) ) )
879             {
880                 // No further slashes/ only a final slash. It's a child!
881                 rChildren.push_back(
882                     HierarchyContentRef(
883                         static_cast< HierarchyContent * >( xChild.get() ) ) );
884             }
885         }
886         ++it;
887     }
888 }
889 
890 //=========================================================================
891 sal_Bool HierarchyContent::exchangeIdentity(
892             const uno::Reference< ucb::XContentIdentifier >& xNewId )
893 {
894     if ( !xNewId.is() )
895         return sal_False;
896 
897     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
898 
899     uno::Reference< ucb::XContent > xThis = this;
900 
901     // Already persistent?
902     if ( m_eState != PERSISTENT )
903     {
904         OSL_ENSURE( sal_False,
905                     "HierarchyContent::exchangeIdentity - Not persistent!" );
906         return sal_False;
907     }
908 
909     // Am I the root folder?
910     if ( m_eKind == ROOT )
911     {
912         OSL_ENSURE( sal_False, "HierarchyContent::exchangeIdentity - "
913                                "Not supported by root folder!" );
914         return sal_False;
915     }
916 
917     // Exchange own identitity.
918 
919     // Fail, if a content with given id already exists.
920     if ( !hasData( xNewId ) )
921     {
922         rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
923 
924         aGuard.clear();
925         if ( exchange( xNewId ) )
926         {
927             if ( m_eKind == FOLDER )
928             {
929                 // Process instanciated children...
930 
931                 HierarchyContentRefList aChildren;
932                 queryChildren( aChildren );
933 
934                 HierarchyContentRefList::const_iterator it  = aChildren.begin();
935                 HierarchyContentRefList::const_iterator end = aChildren.end();
936 
937                 while ( it != end )
938                 {
939                     HierarchyContentRef xChild = (*it);
940 
941                     // Create new content identifier for the child...
942                     uno::Reference< ucb::XContentIdentifier > xOldChildId
943                                                     = xChild->getIdentifier();
944                     rtl::OUString aOldChildURL
945                         = xOldChildId->getContentIdentifier();
946                     rtl::OUString aNewChildURL
947                         = aOldChildURL.replaceAt(
948                                         0,
949                                         aOldURL.getLength(),
950                                         xNewId->getContentIdentifier() );
951                     uno::Reference< ucb::XContentIdentifier > xNewChildId
952                         = new ::ucbhelper::ContentIdentifier(
953                             m_xSMgr, aNewChildURL );
954 
955                     if ( !xChild->exchangeIdentity( xNewChildId ) )
956                         return sal_False;
957 
958                     ++it;
959                 }
960             }
961             return sal_True;
962         }
963     }
964 
965     OSL_ENSURE( sal_False,
966                 "HierarchyContent::exchangeIdentity - "
967                 "Panic! Cannot exchange identity!" );
968     return sal_False;
969 }
970 
971 //=========================================================================
972 // static
973 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
974                 const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
975                 const uno::Sequence< beans::Property >& rProperties,
976                 const HierarchyContentProperties& rData,
977                 HierarchyContentProvider* pProvider,
978                 const rtl::OUString& rContentId )
979 {
980     // Note: Empty sequence means "get values of all supported properties".
981 
982     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
983         = new ::ucbhelper::PropertyValueSet( rSMgr );
984 
985     sal_Int32 nCount = rProperties.getLength();
986     if ( nCount )
987     {
988         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
989         sal_Bool bTriedToGetAdditonalPropSet = sal_False;
990 
991         const beans::Property* pProps = rProperties.getConstArray();
992         for ( sal_Int32 n = 0; n < nCount; ++n )
993         {
994             const beans::Property& rProp = pProps[ n ];
995 
996             // Process Core properties.
997 
998             if ( rProp.Name.equalsAsciiL(
999                         RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
1000             {
1001                 xRow->appendString ( rProp, rData.getContentType() );
1002             }
1003             else if ( rProp.Name.equalsAsciiL(
1004                         RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1005             {
1006                 xRow->appendString ( rProp, rData.getTitle() );
1007             }
1008             else if ( rProp.Name.equalsAsciiL(
1009                         RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1010             {
1011                 xRow->appendBoolean( rProp, rData.getIsDocument() );
1012             }
1013             else if ( rProp.Name.equalsAsciiL(
1014                         RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1015             {
1016                 xRow->appendBoolean( rProp, rData.getIsFolder() );
1017             }
1018             else if ( rProp.Name.equalsAsciiL(
1019                         RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1020             {
1021                 xRow->appendObject(
1022                     rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
1023             }
1024             else if ( rProp.Name.equalsAsciiL(
1025                         RTL_CONSTASCII_STRINGPARAM( "TargetURL" ) ) )
1026             {
1027                 // TargetURL is only supported by links.
1028 
1029                 if ( rData.getIsDocument() )
1030                     xRow->appendString( rProp, rData.getTargetURL() );
1031                 else
1032                     xRow->appendVoid( rProp );
1033             }
1034             else
1035             {
1036                 // Not a Core Property! Maybe it's an Additional Core Property?!
1037 
1038                 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1039                 {
1040                     xAdditionalPropSet
1041                         = uno::Reference< beans::XPropertySet >(
1042                             pProvider->getAdditionalPropertySet( rContentId,
1043                                                                  sal_False ),
1044                             uno::UNO_QUERY );
1045                     bTriedToGetAdditonalPropSet = sal_True;
1046                 }
1047 
1048                 if ( xAdditionalPropSet.is() )
1049                 {
1050                     if ( !xRow->appendPropertySetValue(
1051                                                 xAdditionalPropSet,
1052                                                 rProp ) )
1053                     {
1054                         // Append empty entry.
1055                         xRow->appendVoid( rProp );
1056                     }
1057                 }
1058                 else
1059                 {
1060                     // Append empty entry.
1061                     xRow->appendVoid( rProp );
1062                 }
1063             }
1064         }
1065     }
1066     else
1067     {
1068         // Append all Core Properties.
1069         xRow->appendString (
1070             beans::Property( rtl::OUString::createFromAscii( "ContentType" ),
1071                       -1,
1072                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1073                       beans::PropertyAttribute::BOUND
1074                         | beans::PropertyAttribute::READONLY ),
1075             rData.getContentType() );
1076         xRow->appendString (
1077             beans::Property( rtl::OUString::createFromAscii( "Title" ),
1078                       -1,
1079                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1080                           // @@@ Might actually be read-only!
1081                       beans::PropertyAttribute::BOUND ),
1082             rData.getTitle() );
1083         xRow->appendBoolean(
1084             beans::Property( rtl::OUString::createFromAscii( "IsDocument" ),
1085                       -1,
1086                       getCppuBooleanType(),
1087                       beans::PropertyAttribute::BOUND
1088                         | beans::PropertyAttribute::READONLY ),
1089             rData.getIsDocument() );
1090         xRow->appendBoolean(
1091             beans::Property( rtl::OUString::createFromAscii( "IsFolder" ),
1092                       -1,
1093                       getCppuBooleanType(),
1094                       beans::PropertyAttribute::BOUND
1095                         | beans::PropertyAttribute::READONLY ),
1096             rData.getIsFolder() );
1097 
1098         if ( rData.getIsDocument() )
1099             xRow->appendString(
1100                 beans::Property( rtl::OUString::createFromAscii( "TargetURL" ),
1101                           -1,
1102                           getCppuType(
1103                             static_cast< const rtl::OUString * >( 0 ) ),
1104                           // @@@ Might actually be read-only!
1105                           beans::PropertyAttribute::BOUND ),
1106                 rData.getTargetURL() );
1107         xRow->appendObject(
1108             beans::Property(
1109                 rtl::OUString::createFromAscii( "CreatableContentsInfo" ),
1110                 -1,
1111                 getCppuType( static_cast<
1112                         const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1113                 beans::PropertyAttribute::BOUND
1114                 | beans::PropertyAttribute::READONLY ),
1115             uno::makeAny( rData.getCreatableContentsInfo() ) );
1116 
1117         // Append all Additional Core Properties.
1118 
1119         uno::Reference< beans::XPropertySet > xSet(
1120             pProvider->getAdditionalPropertySet( rContentId, sal_False ),
1121             uno::UNO_QUERY );
1122         xRow->appendPropertySet( xSet );
1123     }
1124 
1125     return uno::Reference< sdbc::XRow >( xRow.get() );
1126 }
1127 
1128 //=========================================================================
1129 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
1130                         const uno::Sequence< beans::Property >& rProperties )
1131 {
1132     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1133     return getPropertyValues( m_xSMgr,
1134                               rProperties,
1135                               m_aProps,
1136                               m_pProvider,
1137                               m_xIdentifier->getContentIdentifier() );
1138 }
1139 
1140 //=========================================================================
1141 uno::Sequence< uno::Any > HierarchyContent::setPropertyValues(
1142         const uno::Sequence< beans::PropertyValue >& rValues,
1143         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1144     throw( uno::Exception )
1145 {
1146     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1147 
1148     uno::Sequence< uno::Any > aRet( rValues.getLength() );
1149     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1150     sal_Int32 nChanged = 0;
1151 
1152     beans::PropertyChangeEvent aEvent;
1153     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
1154     aEvent.Further        = sal_False;
1155 //    aEvent.PropertyName   =
1156     aEvent.PropertyHandle = -1;
1157 //    aEvent.OldValue       =
1158 //    aEvent.NewValue       =
1159 
1160     const beans::PropertyValue* pValues = rValues.getConstArray();
1161     sal_Int32 nCount = rValues.getLength();
1162 
1163     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1164     sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1165 
1166     sal_Bool bExchange = sal_False;
1167     rtl::OUString aOldTitle;
1168     rtl::OUString aOldName;
1169     sal_Int32 nTitlePos = -1;
1170 
1171     for ( sal_Int32 n = 0; n < nCount; ++n )
1172     {
1173         const beans::PropertyValue& rValue = pValues[ n ];
1174 
1175         if ( rValue.Name.equalsAsciiL(
1176                     RTL_CONSTASCII_STRINGPARAM(  "ContentType" ) ) )
1177         {
1178             // Read-only property!
1179             aRet[ n ] <<= lang::IllegalAccessException(
1180                             rtl::OUString::createFromAscii(
1181                                 "Property is read-only!" ),
1182                             static_cast< cppu::OWeakObject * >( this ) );
1183         }
1184         else if ( rValue.Name.equalsAsciiL(
1185                     RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1186         {
1187             // Read-only property!
1188             aRet[ n ] <<= lang::IllegalAccessException(
1189                             rtl::OUString::createFromAscii(
1190                                 "Property is read-only!" ),
1191                             static_cast< cppu::OWeakObject * >( this ) );
1192         }
1193         else if ( rValue.Name.equalsAsciiL(
1194                     RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1195         {
1196             // Read-only property!
1197             aRet[ n ] <<= lang::IllegalAccessException(
1198                             rtl::OUString::createFromAscii(
1199                                 "Property is read-only!" ),
1200                             static_cast< cppu::OWeakObject * >( this ) );
1201         }
1202         else if ( rValue.Name.equalsAsciiL(
1203                     RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1204         {
1205             // Read-only property!
1206             aRet[ n ] <<= lang::IllegalAccessException(
1207                             rtl::OUString::createFromAscii(
1208                                 "Property is read-only!" ),
1209                             static_cast< cppu::OWeakObject * >( this ) );
1210         }
1211         else if ( rValue.Name.equalsAsciiL(
1212                     RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1213         {
1214             if ( isReadOnly() )
1215             {
1216                 aRet[ n ] <<= lang::IllegalAccessException(
1217                                 rtl::OUString::createFromAscii(
1218                                     "Property is read-only!" ),
1219                                 static_cast< cppu::OWeakObject * >( this ) );
1220             }
1221             else
1222             {
1223                 rtl::OUString aNewValue;
1224                 if ( rValue.Value >>= aNewValue )
1225                 {
1226                     // No empty titles!
1227                     if ( aNewValue.getLength() > 0 )
1228                     {
1229                         if ( aNewValue != m_aProps.getTitle() )
1230                         {
1231                             // modified title -> modified URL -> exchange !
1232                             if ( m_eState == PERSISTENT )
1233                                 bExchange = sal_True;
1234 
1235                             aOldTitle = m_aProps.getTitle();
1236                             aOldName  = m_aProps.getName();
1237 
1238                             m_aProps.setTitle( aNewValue );
1239                             m_aProps.setName(
1240                                 ::ucb_impl::urihelper::encodeSegment(
1241                                     aNewValue ) );
1242 
1243                             // property change event will be set later...
1244 
1245                             // remember position within sequence of values
1246                             // (for error handling).
1247                             nTitlePos = n;
1248                         }
1249                     }
1250                     else
1251                     {
1252                         aRet[ n ] <<= lang::IllegalArgumentException(
1253                                     rtl::OUString::createFromAscii(
1254                                             "Empty title not allowed!" ),
1255                                     static_cast< cppu::OWeakObject * >( this ),
1256                                     -1 );
1257                     }
1258                 }
1259                 else
1260                 {
1261                     aRet[ n ] <<= beans::IllegalTypeException(
1262                                 rtl::OUString::createFromAscii(
1263                                         "Property value has wrong type!" ),
1264                                 static_cast< cppu::OWeakObject * >( this ) );
1265                 }
1266             }
1267         }
1268         else if ( rValue.Name.equalsAsciiL(
1269                     RTL_CONSTASCII_STRINGPARAM( "TargetURL" ) ) )
1270         {
1271             if ( isReadOnly() )
1272             {
1273                 aRet[ n ] <<= lang::IllegalAccessException(
1274                                 rtl::OUString::createFromAscii(
1275                                     "Property is read-only!" ),
1276                                 static_cast< cppu::OWeakObject * >( this ) );
1277             }
1278             else
1279             {
1280                 // TargetURL is only supported by links.
1281 
1282                 if ( m_eKind == LINK )
1283                 {
1284                     rtl::OUString aNewValue;
1285                     if ( rValue.Value >>= aNewValue )
1286                     {
1287                         // No empty target URL's!
1288                         if ( aNewValue.getLength() > 0 )
1289                         {
1290                             if ( aNewValue != m_aProps.getTargetURL() )
1291                             {
1292                                 aEvent.PropertyName = rValue.Name;
1293                                 aEvent.OldValue
1294                                     = uno::makeAny( m_aProps.getTargetURL() );
1295                                 aEvent.NewValue
1296                                     = uno::makeAny( aNewValue );
1297 
1298                                 aChanges.getArray()[ nChanged ] = aEvent;
1299 
1300                                 m_aProps.setTargetURL( aNewValue );
1301                                 nChanged++;
1302                             }
1303                         }
1304                         else
1305                         {
1306                             aRet[ n ] <<= lang::IllegalArgumentException(
1307                                     rtl::OUString::createFromAscii(
1308                                             "Empty target URL not allowed!" ),
1309                                     static_cast< cppu::OWeakObject * >( this ),
1310                                     -1 );
1311                         }
1312                     }
1313                     else
1314                     {
1315                         aRet[ n ] <<= beans::IllegalTypeException(
1316                                 rtl::OUString::createFromAscii(
1317                                         "Property value has wrong type!" ),
1318                                 static_cast< cppu::OWeakObject * >( this ) );
1319                     }
1320                 }
1321                 else
1322                 {
1323                     aRet[ n ] <<= beans::UnknownPropertyException(
1324                                 rtl::OUString::createFromAscii(
1325                                     "TargetURL only supported by links!" ),
1326                                 static_cast< cppu::OWeakObject * >( this ) );
1327                 }
1328             }
1329         }
1330         else
1331         {
1332             // Not a Core Property! Maybe it's an Additional Core Property?!
1333 
1334             if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1335             {
1336                 xAdditionalPropSet = getAdditionalPropertySet( sal_False );
1337                 bTriedToGetAdditonalPropSet = sal_True;
1338             }
1339 
1340             if ( xAdditionalPropSet.is() )
1341             {
1342                 try
1343                 {
1344                     uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1345                                                                 rValue.Name );
1346                     if ( aOldValue != rValue.Value )
1347                     {
1348                         xAdditionalPropSet->setPropertyValue(
1349                                                 rValue.Name, rValue.Value );
1350 
1351                         aEvent.PropertyName = rValue.Name;
1352                         aEvent.OldValue     = aOldValue;
1353                         aEvent.NewValue     = rValue.Value;
1354 
1355                         aChanges.getArray()[ nChanged ] = aEvent;
1356                         nChanged++;
1357                     }
1358                 }
1359                 catch ( beans::UnknownPropertyException const & e )
1360                 {
1361                     aRet[ n ] <<= e;
1362                 }
1363                 catch ( lang::WrappedTargetException const & e )
1364                 {
1365                     aRet[ n ] <<= e;
1366                 }
1367                 catch ( beans::PropertyVetoException const & e )
1368                 {
1369                     aRet[ n ] <<= e;
1370                 }
1371                 catch ( lang::IllegalArgumentException const & e )
1372                 {
1373                     aRet[ n ] <<= e;
1374                 }
1375             }
1376             else
1377             {
1378                 aRet[ n ] <<= uno::Exception(
1379                                 rtl::OUString::createFromAscii(
1380                                     "No property set for storing the value!" ),
1381                                 static_cast< cppu::OWeakObject * >( this ) );
1382             }
1383         }
1384     }
1385 
1386     if ( bExchange )
1387     {
1388         uno::Reference< ucb::XContentIdentifier > xOldId
1389             = m_xIdentifier;
1390         uno::Reference< ucb::XContentIdentifier > xNewId
1391             = makeNewIdentifier( m_aProps.getTitle() );
1392 
1393         aGuard.clear();
1394         if ( exchangeIdentity( xNewId ) )
1395         {
1396             // Adapt persistent data.
1397             renameData( xOldId, xNewId );
1398 
1399             // Adapt Additional Core Properties.
1400             renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1401                                          xNewId->getContentIdentifier(),
1402                                          sal_True );
1403         }
1404         else
1405         {
1406             // Roll-back.
1407             m_aProps.setTitle( aOldTitle );
1408             m_aProps.setName ( aOldName );
1409 
1410             aOldTitle = aOldName = rtl::OUString();
1411 
1412             // Set error .
1413             aRet[ nTitlePos ] <<= uno::Exception(
1414                     rtl::OUString::createFromAscii( "Exchange failed!" ),
1415                     static_cast< cppu::OWeakObject * >( this ) );
1416         }
1417     }
1418 
1419     if ( aOldTitle.getLength() )
1420     {
1421         aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
1422         aEvent.OldValue     = uno::makeAny( aOldTitle );
1423         aEvent.NewValue     = uno::makeAny( m_aProps.getTitle() );
1424 
1425         aChanges.getArray()[ nChanged ] = aEvent;
1426         nChanged++;
1427     }
1428 
1429     if ( nChanged > 0 )
1430     {
1431         // Save changes, if content was already made persistent.
1432         if ( !bExchange && ( m_eState == PERSISTENT ) )
1433         {
1434             if ( !storeData() )
1435             {
1436                 uno::Any aProps
1437                     = uno::makeAny(
1438                              beans::PropertyValue(
1439                                  rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1440                                      "Uri")),
1441                                  -1,
1442                                  uno::makeAny(m_xIdentifier->
1443                                                   getContentIdentifier()),
1444                                  beans::PropertyState_DIRECT_VALUE));
1445                 ucbhelper::cancelCommandExecution(
1446                     ucb::IOErrorCode_CANT_WRITE,
1447                     uno::Sequence< uno::Any >(&aProps, 1),
1448                     xEnv,
1449                     rtl::OUString::createFromAscii(
1450                         "Cannot store persistent data!" ),
1451                     this );
1452                 // Unreachable
1453             }
1454         }
1455 
1456         aChanges.realloc( nChanged );
1457 
1458         aGuard.clear();
1459         notifyPropertiesChange( aChanges );
1460     }
1461 
1462     return aRet;
1463 }
1464 
1465 //=========================================================================
1466 void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1467                                const uno::Reference<
1468                                     ucb::XCommandEnvironment > & xEnv )
1469     throw( uno::Exception )
1470 {
1471     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1472 
1473     // Am I the root folder?
1474     if ( m_eKind == ROOT )
1475     {
1476         ucbhelper::cancelCommandExecution(
1477             uno::makeAny( ucb::UnsupportedCommandException(
1478                                 rtl::OUString::createFromAscii(
1479                                     "Not supported by root folder!" ),
1480                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1481             xEnv );
1482         // Unreachable
1483     }
1484 
1485     // Check, if all required properties were set.
1486     if ( m_aProps.getTitle().getLength() == 0 )
1487     {
1488         uno::Sequence< rtl::OUString > aProps( 1 );
1489         aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
1490         ucbhelper::cancelCommandExecution(
1491             uno::makeAny( ucb::MissingPropertiesException(
1492                                 rtl::OUString(),
1493                                 static_cast< cppu::OWeakObject * >( this ),
1494                                 aProps ) ),
1495             xEnv );
1496         // Unreachable
1497     }
1498 
1499     // Assemble new content identifier...
1500 
1501     uno::Reference< ucb::XContentIdentifier > xId
1502         = makeNewIdentifier( m_aProps.getTitle() );
1503 
1504     // Handle possible name clash...
1505 
1506     switch ( nNameClashResolve )
1507     {
1508         // fail.
1509         case ucb::NameClash::ERROR:
1510             if ( hasData( xId ) )
1511             {
1512                 ucbhelper::cancelCommandExecution(
1513                     uno::makeAny(
1514                         ucb::NameClashException(
1515                             rtl::OUString(),
1516                             static_cast< cppu::OWeakObject * >( this ),
1517                             task::InteractionClassification_ERROR,
1518                             m_aProps.getTitle() ) ),
1519                     xEnv );
1520                 // Unreachable
1521             }
1522             break;
1523 
1524         // replace existing object.
1525         case ucb::NameClash::OVERWRITE:
1526             break;
1527 
1528         // "invent" a new valid title.
1529         case ucb::NameClash::RENAME:
1530             if ( hasData( xId ) )
1531             {
1532                 sal_Int32 nTry = 0;
1533 
1534                 do
1535                 {
1536                     rtl::OUString aNewId = xId->getContentIdentifier();
1537                     aNewId += rtl::OUString::createFromAscii( "_" );
1538                     aNewId += rtl::OUString::valueOf( ++nTry );
1539                     xId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewId );
1540                 }
1541                 while ( hasData( xId ) && ( nTry < 1000 ) );
1542 
1543                 if ( nTry == 1000 )
1544                 {
1545                     ucbhelper::cancelCommandExecution(
1546                         uno::makeAny(
1547                             ucb::UnsupportedNameClashException(
1548                                 rtl::OUString::createFromAscii(
1549                                     "Unable to resolve name clash!" ),
1550                                 static_cast< cppu::OWeakObject * >( this ),
1551                                 nNameClashResolve ) ),
1552                     xEnv );
1553                 // Unreachable
1554                 }
1555                 else
1556                 {
1557                     rtl::OUString aNewTitle( m_aProps.getTitle() );
1558                     aNewTitle += rtl::OUString::createFromAscii( "_" );
1559                     aNewTitle += rtl::OUString::valueOf( nTry );
1560                     m_aProps.setTitle( aNewTitle );
1561                 }
1562             }
1563             break;
1564 
1565         case ucb::NameClash::KEEP: // deprecated
1566         case ucb::NameClash::ASK:
1567         default:
1568             if ( hasData( xId ) )
1569             {
1570                 ucbhelper::cancelCommandExecution(
1571                     uno::makeAny(
1572                         ucb::UnsupportedNameClashException(
1573                                 rtl::OUString(),
1574                                 static_cast< cppu::OWeakObject * >( this ),
1575                                 nNameClashResolve ) ),
1576                     xEnv );
1577                 // Unreachable
1578             }
1579             break;
1580     }
1581 
1582     // Identifier changed?
1583     sal_Bool bNewId = ( xId->getContentIdentifier()
1584                             != m_xIdentifier->getContentIdentifier() );
1585     m_xIdentifier = xId;
1586 
1587     if ( !storeData() )
1588     {
1589         uno::Any aProps
1590             = uno::makeAny(beans::PropertyValue(
1591                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1592                                                     "Uri")),
1593                                   -1,
1594                                   uno::makeAny(m_xIdentifier->
1595                                                    getContentIdentifier()),
1596                                   beans::PropertyState_DIRECT_VALUE));
1597         ucbhelper::cancelCommandExecution(
1598             ucb::IOErrorCode_CANT_WRITE,
1599             uno::Sequence< uno::Any >(&aProps, 1),
1600             xEnv,
1601             rtl::OUString::createFromAscii( "Cannot store persistent data!" ),
1602             this );
1603         // Unreachable
1604     }
1605 
1606     m_eState = PERSISTENT;
1607 
1608     if ( bNewId )
1609     {
1610         aGuard.clear();
1611         inserted();
1612     }
1613 }
1614 
1615 //=========================================================================
1616 void HierarchyContent::destroy( sal_Bool bDeletePhysical,
1617                                 const uno::Reference<
1618                                     ucb::XCommandEnvironment > & xEnv )
1619     throw( uno::Exception )
1620 {
1621     // @@@ take care about bDeletePhysical -> trashcan support
1622 
1623     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1624 
1625     uno::Reference< ucb::XContent > xThis = this;
1626 
1627     // Persistent?
1628     if ( m_eState != PERSISTENT )
1629     {
1630         ucbhelper::cancelCommandExecution(
1631             uno::makeAny( ucb::UnsupportedCommandException(
1632                                 rtl::OUString::createFromAscii(
1633                                     "Not persistent!" ),
1634                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1635             xEnv );
1636         // Unreachable
1637     }
1638 
1639     // Am I the root folder?
1640     if ( m_eKind == ROOT )
1641     {
1642         ucbhelper::cancelCommandExecution(
1643             uno::makeAny( ucb::UnsupportedCommandException(
1644                                 rtl::OUString::createFromAscii(
1645                                     "Not supported by root folder!" ),
1646                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1647             xEnv );
1648         // Unreachable
1649     }
1650 
1651     m_eState = DEAD;
1652 
1653     aGuard.clear();
1654     deleted();
1655 
1656     if ( m_eKind == FOLDER )
1657     {
1658         // Process instanciated children...
1659 
1660         HierarchyContentRefList aChildren;
1661         queryChildren( aChildren );
1662 
1663         HierarchyContentRefList::const_iterator it  = aChildren.begin();
1664         HierarchyContentRefList::const_iterator end = aChildren.end();
1665 
1666         while ( it != end )
1667         {
1668             (*it)->destroy( bDeletePhysical, xEnv );
1669             ++it;
1670         }
1671     }
1672 }
1673 
1674 //=========================================================================
1675 void HierarchyContent::transfer(
1676             const ucb::TransferInfo& rInfo,
1677             const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1678     throw( uno::Exception )
1679 {
1680     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1681 
1682     // Persistent?
1683     if ( m_eState != PERSISTENT )
1684     {
1685         ucbhelper::cancelCommandExecution(
1686             uno::makeAny( ucb::UnsupportedCommandException(
1687                                 rtl::OUString::createFromAscii(
1688                                     "Not persistent!" ),
1689                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1690             xEnv );
1691         // Unreachable
1692     }
1693 
1694     // Is source a hierarchy content?
1695     if ( ( rInfo.SourceURL.getLength() < HIERARCHY_URL_SCHEME_LENGTH + 2 ) ||
1696          ( rInfo.SourceURL.compareToAscii( HIERARCHY_URL_SCHEME ":/",
1697                                            HIERARCHY_URL_SCHEME_LENGTH + 2 )
1698             != 0 ) )
1699     {
1700         ucbhelper::cancelCommandExecution(
1701             uno::makeAny( ucb::InteractiveBadTransferURLException(
1702                             rtl::OUString(),
1703                             static_cast< cppu::OWeakObject * >( this ) ) ),
1704             xEnv );
1705         // Unreachable
1706     }
1707 
1708     // Is source not a parent of me / not me?
1709     rtl::OUString aId = m_xIdentifier->getContentIdentifier();
1710     sal_Int32 nPos = aId.lastIndexOf( '/' );
1711     if ( nPos != ( aId.getLength() - 1 ) )
1712     {
1713         // No trailing slash found. Append.
1714         aId += rtl::OUString::createFromAscii( "/" );
1715     }
1716 
1717     if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1718     {
1719         if ( aId.compareTo(
1720                 rInfo.SourceURL, rInfo.SourceURL.getLength() ) == 0 )
1721         {
1722             uno::Any aProps
1723                 = uno::makeAny(beans::PropertyValue(
1724                                       rtl::OUString(
1725                                           RTL_CONSTASCII_USTRINGPARAM("Uri")),
1726                                       -1,
1727                                       uno::makeAny(rInfo.SourceURL),
1728                                       beans::PropertyState_DIRECT_VALUE));
1729             ucbhelper::cancelCommandExecution(
1730                 ucb::IOErrorCode_RECURSIVE,
1731                 uno::Sequence< uno::Any >(&aProps, 1),
1732                 xEnv,
1733                 rtl::OUString::createFromAscii(
1734                     "Target is equal to or is a child of source!" ),
1735                 this );
1736             // Unreachable
1737         }
1738     }
1739 
1740     //////////////////////////////////////////////////////////////////////
1741     // 0) Obtain content object for source.
1742     //////////////////////////////////////////////////////////////////////
1743 
1744     uno::Reference< ucb::XContentIdentifier > xId
1745         = new ::ucbhelper::ContentIdentifier( m_xSMgr, rInfo.SourceURL );
1746 
1747     // Note: The static cast is okay here, because its sure that
1748     //       m_xProvider is always the HierarchyContentProvider.
1749     rtl::Reference< HierarchyContent > xSource;
1750 
1751     try
1752     {
1753         xSource = static_cast< HierarchyContent * >(
1754                         m_xProvider->queryContent( xId ).get() );
1755     }
1756     catch ( ucb::IllegalIdentifierException const & )
1757     {
1758         // queryContent
1759     }
1760 
1761     if ( !xSource.is() )
1762     {
1763         uno::Any aProps
1764             = uno::makeAny(beans::PropertyValue(
1765                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1766                                       "Uri")),
1767                                   -1,
1768                                   uno::makeAny(xId->getContentIdentifier()),
1769                                   beans::PropertyState_DIRECT_VALUE));
1770         ucbhelper::cancelCommandExecution(
1771             ucb::IOErrorCode_CANT_READ,
1772             uno::Sequence< uno::Any >(&aProps, 1),
1773             xEnv,
1774             rtl::OUString::createFromAscii(
1775                 "Cannot instanciate source object!" ),
1776             this );
1777         // Unreachable
1778     }
1779 
1780     //////////////////////////////////////////////////////////////////////
1781     // 1) Create new child content.
1782     //////////////////////////////////////////////////////////////////////
1783 
1784     rtl::OUString aType = xSource->isFolder()
1785         ? rtl::OUString::createFromAscii( HIERARCHY_FOLDER_CONTENT_TYPE )
1786         : rtl::OUString::createFromAscii( HIERARCHY_LINK_CONTENT_TYPE );
1787     ucb::ContentInfo aContentInfo;
1788     aContentInfo.Type = aType;
1789     aContentInfo.Attributes = 0;
1790 
1791     // Note: The static cast is okay here, because its sure that
1792     //       createNewContent always creates a HierarchyContent.
1793     rtl::Reference< HierarchyContent > xTarget
1794         = static_cast< HierarchyContent * >(
1795             createNewContent( aContentInfo ).get() );
1796     if ( !xTarget.is() )
1797     {
1798         uno::Any aProps
1799             = uno::makeAny(beans::PropertyValue(
1800                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1801                                       "Folder")),
1802                                   -1,
1803                                   uno::makeAny(aId),
1804                                   beans::PropertyState_DIRECT_VALUE));
1805         ucbhelper::cancelCommandExecution(
1806             ucb::IOErrorCode_CANT_CREATE,
1807             uno::Sequence< uno::Any >(&aProps, 1),
1808             xEnv,
1809             rtl::OUString::createFromAscii(
1810                 "XContentCreator::createNewContent failed!" ),
1811             this );
1812         // Unreachable
1813     }
1814 
1815     //////////////////////////////////////////////////////////////////////
1816     // 2) Copy data from source content to child content.
1817     //////////////////////////////////////////////////////////////////////
1818 
1819     uno::Sequence< beans::Property > aSourceProps
1820                     = xSource->getPropertySetInfo( xEnv )->getProperties();
1821     sal_Int32 nCount = aSourceProps.getLength();
1822 
1823     if ( nCount )
1824     {
1825         sal_Bool bHadTitle = ( rInfo.NewTitle.getLength() == 0 );
1826 
1827         // Get all source values.
1828         uno::Reference< sdbc::XRow > xRow
1829             = xSource->getPropertyValues( aSourceProps );
1830 
1831         uno::Sequence< beans::PropertyValue > aValues( nCount );
1832         beans::PropertyValue* pValues = aValues.getArray();
1833 
1834         const beans::Property* pProps = aSourceProps.getConstArray();
1835         for ( sal_Int32 n = 0; n < nCount; ++n )
1836         {
1837             const beans::Property& rProp  = pProps[ n ];
1838             beans::PropertyValue&  rValue = pValues[ n ];
1839 
1840             rValue.Name   = rProp.Name;
1841             rValue.Handle = rProp.Handle;
1842 
1843             if ( !bHadTitle && rProp.Name.equalsAsciiL(
1844                                 RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1845             {
1846                 // Set new title instead of original.
1847                 bHadTitle = sal_True;
1848                 rValue.Value <<= rInfo.NewTitle;
1849             }
1850             else
1851                 rValue.Value = xRow->getObject(
1852                                 n + 1,
1853                                 uno::Reference< container::XNameAccess >() );
1854 
1855             rValue.State = beans::PropertyState_DIRECT_VALUE;
1856 
1857             if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1858             {
1859                 // Add Additional Core Property.
1860                 try
1861                 {
1862                     xTarget->addProperty( rProp.Name,
1863                                           rProp.Attributes,
1864                                           rValue.Value );
1865                 }
1866                 catch ( beans::PropertyExistException const & )
1867                 {
1868                 }
1869                 catch ( beans::IllegalTypeException const & )
1870                 {
1871                 }
1872                 catch ( lang::IllegalArgumentException const & )
1873                 {
1874                 }
1875             }
1876         }
1877 
1878         // Set target values.
1879         xTarget->setPropertyValues( aValues, xEnv );
1880     }
1881 
1882     //////////////////////////////////////////////////////////////////////
1883     // 3) Commit (insert) child.
1884     //////////////////////////////////////////////////////////////////////
1885 
1886     xTarget->insert( rInfo.NameClash, xEnv );
1887 
1888     //////////////////////////////////////////////////////////////////////
1889     // 4) Transfer (copy) children of source.
1890     //////////////////////////////////////////////////////////////////////
1891 
1892     if ( xSource->isFolder() )
1893     {
1894         HierarchyEntry aFolder(
1895             m_xSMgr, m_pProvider, xId->getContentIdentifier() );
1896         HierarchyEntry::iterator it;
1897 
1898         while ( aFolder.next( it ) )
1899         {
1900             const HierarchyEntryData& rResult = *it;
1901 
1902             rtl::OUString aChildId = xId->getContentIdentifier();
1903             if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() )
1904                 aChildId += rtl::OUString::createFromAscii( "/" );
1905 
1906             aChildId += rResult.getName();
1907 
1908             ucb::TransferInfo aInfo;
1909             aInfo.MoveData  = sal_False;
1910             aInfo.NewTitle  = rtl::OUString();
1911             aInfo.SourceURL = aChildId;
1912             aInfo.NameClash = rInfo.NameClash;
1913 
1914             // Transfer child to target.
1915             xTarget->transfer( aInfo, xEnv );
1916         }
1917     }
1918 
1919     //////////////////////////////////////////////////////////////////////
1920     // 5) Destroy source ( when moving only ) .
1921     //////////////////////////////////////////////////////////////////////
1922 
1923     if ( rInfo.MoveData )
1924     {
1925         xSource->destroy( sal_True, xEnv );
1926 
1927         // Remove all persistent data of source and its children.
1928         if ( !xSource->removeData() )
1929         {
1930             uno::Any aProps
1931                 = uno::makeAny(
1932                          beans::PropertyValue(
1933                              rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1934                                                "Uri")),
1935                              -1,
1936                              uno::makeAny(
1937                                  xSource->m_xIdentifier->
1938                                               getContentIdentifier()),
1939                              beans::PropertyState_DIRECT_VALUE));
1940             ucbhelper::cancelCommandExecution(
1941                 ucb::IOErrorCode_CANT_WRITE,
1942                 uno::Sequence< uno::Any >(&aProps, 1),
1943                 xEnv,
1944                 rtl::OUString::createFromAscii(
1945                     "Cannot remove persistent data of source object!" ),
1946                 this );
1947             // Unreachable
1948         }
1949 
1950         // Remove own and all children's Additional Core Properties.
1951         xSource->removeAdditionalPropertySet( sal_True );
1952     }
1953 }
1954 
1955 //=========================================================================
1956 //=========================================================================
1957 //
1958 // HierarchyContentProperties Implementation.
1959 //
1960 //=========================================================================
1961 //=========================================================================
1962 
1963 uno::Sequence< ucb::ContentInfo >
1964 HierarchyContentProperties::getCreatableContentsInfo() const
1965 {
1966     if ( getIsFolder() )
1967     {
1968         uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1969 
1970         // Folder.
1971         aSeq.getArray()[ 0 ].Type
1972             = rtl::OUString::createFromAscii( HIERARCHY_FOLDER_CONTENT_TYPE );
1973         aSeq.getArray()[ 0 ].Attributes
1974             = ucb::ContentInfoAttribute::KIND_FOLDER;
1975 
1976         uno::Sequence< beans::Property > aFolderProps( 1 );
1977         aFolderProps.getArray()[ 0 ] = beans::Property(
1978                     rtl::OUString::createFromAscii( "Title" ),
1979                     -1,
1980                     getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1981                     beans::PropertyAttribute::BOUND );
1982         aSeq.getArray()[ 0 ].Properties = aFolderProps;
1983 
1984         // Link.
1985         aSeq.getArray()[ 1 ].Type
1986             = rtl::OUString::createFromAscii( HIERARCHY_LINK_CONTENT_TYPE );
1987         aSeq.getArray()[ 1 ].Attributes
1988             = ucb::ContentInfoAttribute::KIND_LINK;
1989 
1990         uno::Sequence< beans::Property > aLinkProps( 2 );
1991         aLinkProps.getArray()[ 0 ] = beans::Property(
1992                     rtl::OUString::createFromAscii( "Title" ),
1993                     -1,
1994                     getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1995                     beans::PropertyAttribute::BOUND );
1996         aLinkProps.getArray()[ 1 ] = beans::Property(
1997                     rtl::OUString::createFromAscii( "TargetURL" ),
1998                     -1,
1999                     getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
2000                     beans::PropertyAttribute::BOUND );
2001         aSeq.getArray()[ 1 ].Properties = aLinkProps;
2002 
2003         return aSeq;
2004     }
2005     else
2006     {
2007         return uno::Sequence< ucb::ContentInfo >( 0 );
2008     }
2009 }
2010