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