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