cid#1607171 Data race condition
[LibreOffice.git] / ucb / source / ucp / hierarchy / hierarchycontent.cxx
bloba526be72b8aeafb341d64f99253b6c75ffac9dc4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 - optimize transfer command. "Move" should be implementable much more
26 efficient!
28 **************************************************************************
30 - Root Folder vs. 'normal' Folder
31 - root doesn't support command 'delete'
32 - root doesn't support command 'insert'
33 - root needs not created via XContentCreator - queryContent with root
34 folder id ( HIERARCHY_ROOT_FOLDER_URL ) always returns a value != 0
35 - root has no parent.
37 *************************************************************************/
38 #include <osl/diagnose.h>
40 #include <rtl/ustring.hxx>
41 #include <com/sun/star/beans/IllegalTypeException.hpp>
42 #include <com/sun/star/beans/PropertyAttribute.hpp>
43 #include <com/sun/star/beans/PropertyExistException.hpp>
44 #include <com/sun/star/beans/PropertyState.hpp>
45 #include <com/sun/star/lang/IllegalAccessException.hpp>
46 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
47 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
48 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
49 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
50 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
51 #include <com/sun/star/ucb/NameClash.hpp>
52 #include <com/sun/star/ucb/NameClashException.hpp>
53 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
54 #include <com/sun/star/ucb/TransferInfo.hpp>
55 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
56 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
57 #include <com/sun/star/ucb/XCommandInfo.hpp>
58 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
59 #include <com/sun/star/uno/Any.hxx>
60 #include <com/sun/star/uno/Sequence.hxx>
61 #include <comphelper/propertysequence.hxx>
62 #include <comphelper/sequence.hxx>
63 #include <cppuhelper/queryinterface.hxx>
64 #include <ucbhelper/contentidentifier.hxx>
65 #include <ucbhelper/propertyvalueset.hxx>
66 #include <ucbhelper/cancelcommandexecution.hxx>
67 #include <ucbhelper/macros.hxx>
68 #include <utility>
69 #include "hierarchycontent.hxx"
70 #include "hierarchyprovider.hxx"
71 #include "dynamicresultset.hxx"
72 #include "hierarchyuri.hxx"
74 #include "../inc/urihelper.hxx"
76 using namespace com::sun::star;
77 using namespace hierarchy_ucp;
80 // HierarchyContent Implementation.
83 // static ( "virtual" ctor )
84 rtl::Reference<HierarchyContent> HierarchyContent::create(
85 const uno::Reference< uno::XComponentContext >& rxContext,
86 HierarchyContentProvider* pProvider,
87 const uno::Reference< ucb::XContentIdentifier >& Identifier )
89 // Fail, if content does not exist.
90 HierarchyContentProperties aProps;
91 if ( !loadData( rxContext, pProvider, Identifier, aProps ) )
92 return nullptr;
94 return new HierarchyContent( rxContext, pProvider, Identifier, std::move(aProps) );
98 // static ( "virtual" ctor )
99 rtl::Reference<HierarchyContent> HierarchyContent::create(
100 const uno::Reference< uno::XComponentContext >& rxContext,
101 HierarchyContentProvider* pProvider,
102 const uno::Reference< ucb::XContentIdentifier >& Identifier,
103 const ucb::ContentInfo& Info )
105 if ( Info.Type.isEmpty() )
106 return nullptr;
108 if ( Info.Type != HIERARCHY_FOLDER_CONTENT_TYPE && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
109 return nullptr;
111 return new HierarchyContent( rxContext, pProvider, Identifier, Info );
115 HierarchyContent::HierarchyContent(
116 const uno::Reference< uno::XComponentContext >& rxContext,
117 HierarchyContentProvider* pProvider,
118 const uno::Reference< ucb::XContentIdentifier >& Identifier,
119 HierarchyContentProperties aProps )
120 : ContentImplHelper( rxContext, pProvider, Identifier ),
121 m_aProps(std::move( aProps )),
122 m_eState( PERSISTENT ),
123 m_pProvider( pProvider ),
124 m_bCheckedReadOnly( false ),
125 m_bIsReadOnly( true )
127 setKind( Identifier );
131 HierarchyContent::HierarchyContent(
132 const uno::Reference< uno::XComponentContext >& rxContext,
133 HierarchyContentProvider* pProvider,
134 const uno::Reference< ucb::XContentIdentifier >& Identifier,
135 const ucb::ContentInfo& Info )
136 : ContentImplHelper( rxContext, pProvider, Identifier ),
137 m_aProps( Info.Type == HIERARCHY_FOLDER_CONTENT_TYPE ? HierarchyEntryData::FOLDER : HierarchyEntryData::LINK ),
138 m_eState( TRANSIENT ),
139 m_pProvider( pProvider ),
140 m_bCheckedReadOnly( false ),
141 m_bIsReadOnly( true )
143 setKind( Identifier );
147 // virtual
148 HierarchyContent::~HierarchyContent()
153 // XInterface methods.
156 // virtual
157 void SAL_CALL HierarchyContent::acquire()
158 noexcept
160 ContentImplHelper::acquire();
164 // virtual
165 void SAL_CALL HierarchyContent::release()
166 noexcept
168 ContentImplHelper::release();
172 // virtual
173 uno::Any SAL_CALL HierarchyContent::queryInterface( const uno::Type & rType )
175 uno::Any aRet = ContentImplHelper::queryInterface( rType );
177 if ( !aRet.hasValue() )
179 // Note: isReadOnly may be relative expensive. So avoid calling it
180 // unless it is really necessary.
181 aRet = cppu::queryInterface(
182 rType, static_cast< ucb::XContentCreator * >( this ) );
183 if ( aRet.hasValue() )
185 if ( !isFolder() || isReadOnly() )
186 return uno::Any();
190 return aRet;
194 // XTypeProvider methods.
197 XTYPEPROVIDER_COMMON_IMPL( HierarchyContent );
200 // virtual
201 uno::Sequence< uno::Type > SAL_CALL HierarchyContent::getTypes()
203 if ( isFolder() && !isReadOnly() )
205 static cppu::OTypeCollection s_aFolderTypes(
206 CPPU_TYPE_REF( lang::XTypeProvider ),
207 CPPU_TYPE_REF( lang::XServiceInfo ),
208 CPPU_TYPE_REF( lang::XComponent ),
209 CPPU_TYPE_REF( ucb::XContent ),
210 CPPU_TYPE_REF( ucb::XCommandProcessor ),
211 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
212 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
213 CPPU_TYPE_REF( beans::XPropertyContainer ),
214 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
215 CPPU_TYPE_REF( container::XChild ),
216 CPPU_TYPE_REF( ucb::XContentCreator ) );
219 return s_aFolderTypes.getTypes();
221 else
223 static cppu::OTypeCollection s_aDocumentTypes(
224 CPPU_TYPE_REF( lang::XTypeProvider ),
225 CPPU_TYPE_REF( lang::XServiceInfo ),
226 CPPU_TYPE_REF( lang::XComponent ),
227 CPPU_TYPE_REF( ucb::XContent ),
228 CPPU_TYPE_REF( ucb::XCommandProcessor ),
229 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
230 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
231 CPPU_TYPE_REF( beans::XPropertyContainer ),
232 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
233 CPPU_TYPE_REF( container::XChild ) );
235 return s_aDocumentTypes.getTypes();
240 // XServiceInfo methods.
243 // virtual
244 OUString SAL_CALL HierarchyContent::getImplementationName()
246 return u"com.sun.star.comp.ucb.HierarchyContent"_ustr;
250 // virtual
251 uno::Sequence< OUString > SAL_CALL
252 HierarchyContent::getSupportedServiceNames()
254 uno::Sequence< OUString > aSNS( 1 );
256 if ( m_eKind == LINK )
257 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyLinkContent";
258 else if ( m_eKind == FOLDER )
259 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyFolderContent";
260 else
261 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyRootFolderContent";
263 return aSNS;
267 // XContent methods.
270 // virtual
271 OUString SAL_CALL HierarchyContent::getContentType()
273 return m_aProps.getContentType();
277 // virtual
278 uno::Reference< ucb::XContentIdentifier > SAL_CALL
279 HierarchyContent::getIdentifier()
281 // Transient?
282 if ( m_eState == TRANSIENT )
284 // Transient contents have no identifier.
285 return uno::Reference< ucb::XContentIdentifier >();
288 return ContentImplHelper::getIdentifier();
292 // XCommandProcessor methods.
295 // virtual
296 uno::Any SAL_CALL HierarchyContent::execute(
297 const ucb::Command& aCommand,
298 sal_Int32 /*CommandId*/,
299 const uno::Reference< ucb::XCommandEnvironment >& Environment )
301 uno::Any aRet;
303 if ( aCommand.Name == "getPropertyValues" )
306 // getPropertyValues
309 uno::Sequence< beans::Property > Properties;
310 if ( !( aCommand.Argument >>= Properties ) )
312 ucbhelper::cancelCommandExecution(
313 uno::Any( lang::IllegalArgumentException(
314 u"Wrong argument type!"_ustr,
315 getXWeak(),
316 -1 ) ),
317 Environment );
318 // Unreachable
321 aRet <<= getPropertyValues( Properties );
323 else if ( aCommand.Name == "setPropertyValues" )
326 // setPropertyValues
329 uno::Sequence< beans::PropertyValue > aProperties;
330 if ( !( aCommand.Argument >>= aProperties ) )
332 ucbhelper::cancelCommandExecution(
333 uno::Any( lang::IllegalArgumentException(
334 u"Wrong argument type!"_ustr,
335 getXWeak(),
336 -1 ) ),
337 Environment );
338 // Unreachable
341 if ( !aProperties.hasElements() )
343 ucbhelper::cancelCommandExecution(
344 uno::Any( lang::IllegalArgumentException(
345 u"No properties!"_ustr,
346 getXWeak(),
347 -1 ) ),
348 Environment );
349 // Unreachable
352 aRet <<= setPropertyValues( aProperties, Environment );
354 else if ( aCommand.Name == "getPropertySetInfo" )
357 // getPropertySetInfo
360 aRet <<= getPropertySetInfo( Environment );
362 else if ( aCommand.Name == "getCommandInfo" )
365 // getCommandInfo
368 aRet <<= getCommandInfo( Environment );
370 else if ( aCommand.Name == "open" && isFolder() )
373 // open command for a folder content
376 ucb::OpenCommandArgument2 aOpenCommand;
377 if ( !( aCommand.Argument >>= aOpenCommand ) )
379 ucbhelper::cancelCommandExecution(
380 uno::Any( lang::IllegalArgumentException(
381 u"Wrong argument type!"_ustr,
382 getXWeak(),
383 -1 ) ),
384 Environment );
385 // Unreachable
388 uno::Reference< ucb::XDynamicResultSet > xSet
389 = new DynamicResultSet( m_xContext, this, aOpenCommand );
390 aRet <<= xSet;
392 else if ( aCommand.Name == "insert" && ( m_eKind != ROOT ) && !isReadOnly() )
395 // insert
396 // ( Not available at root folder )
399 ucb::InsertCommandArgument aArg;
400 if ( !( aCommand.Argument >>= aArg ) )
402 ucbhelper::cancelCommandExecution(
403 uno::Any( lang::IllegalArgumentException(
404 u"Wrong argument type!"_ustr,
405 getXWeak(),
406 -1 ) ),
407 Environment );
408 // Unreachable
411 sal_Int32 nNameClash = aArg.ReplaceExisting
412 ? ucb::NameClash::OVERWRITE
413 : ucb::NameClash::ERROR;
414 insert( nNameClash, Environment );
416 else if ( aCommand.Name == "delete" && ( m_eKind != ROOT ) && !isReadOnly() )
419 // delete
420 // ( Not available at root folder )
423 bool bDeletePhysical = false;
424 aCommand.Argument >>= bDeletePhysical;
425 destroy( bDeletePhysical, Environment );
427 // Remove own and all children's persistent data.
428 if ( !removeData() )
430 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
432 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
433 }));
434 ucbhelper::cancelCommandExecution(
435 ucb::IOErrorCode_CANT_WRITE,
436 aArgs,
437 Environment,
438 u"Cannot remove persistent data!"_ustr,
439 this );
440 // Unreachable
443 // Remove own and all children's Additional Core Properties.
444 removeAdditionalPropertySet();
446 else if ( aCommand.Name == "transfer" && isFolder() && !isReadOnly() )
449 // transfer
450 // ( Not available at link objects )
453 ucb::TransferInfo aInfo;
454 if ( !( aCommand.Argument >>= aInfo ) )
456 OSL_FAIL( "Wrong argument type!" );
457 ucbhelper::cancelCommandExecution(
458 uno::Any( lang::IllegalArgumentException(
459 u"Wrong argument type!"_ustr,
460 getXWeak(),
461 -1 ) ),
462 Environment );
463 // Unreachable
466 transfer( aInfo, Environment );
468 else if ( aCommand.Name == "createNewContent" && isFolder() && !isReadOnly() )
471 // createNewContent
472 // ( Not available at link objects )
475 ucb::ContentInfo aInfo;
476 if ( !( aCommand.Argument >>= aInfo ) )
478 OSL_FAIL( "Wrong argument type!" );
479 ucbhelper::cancelCommandExecution(
480 uno::Any( lang::IllegalArgumentException(
481 u"Wrong argument type!"_ustr,
482 getXWeak(),
483 -1 ) ),
484 Environment );
485 // Unreachable
488 aRet <<= createNewContent( aInfo );
490 else
493 // Unsupported command
496 ucbhelper::cancelCommandExecution(
497 uno::Any( ucb::UnsupportedCommandException(
498 OUString(),
499 getXWeak() ) ),
500 Environment );
501 // Unreachable
504 return aRet;
508 // virtual
509 void SAL_CALL HierarchyContent::abort( sal_Int32 /*CommandId*/ )
511 // @@@ Generally, no action takes much time...
515 // XContentCreator methods.
518 // virtual
519 uno::Sequence< ucb::ContentInfo > SAL_CALL
520 HierarchyContent::queryCreatableContentsInfo()
522 return m_aProps.getCreatableContentsInfo();
526 // virtual
527 uno::Reference< ucb::XContent > SAL_CALL
528 HierarchyContent::createNewContent( const ucb::ContentInfo& Info )
530 if ( isFolder() )
532 osl::Guard< osl::Mutex > aGuard( m_aMutex );
534 if ( Info.Type.isEmpty() )
535 return uno::Reference< ucb::XContent >();
537 bool bCreateFolder = Info.Type == HIERARCHY_FOLDER_CONTENT_TYPE;
539 if ( !bCreateFolder && Info.Type != HIERARCHY_LINK_CONTENT_TYPE )
540 return uno::Reference< ucb::XContent >();
542 OUString aURL = m_xIdentifier->getContentIdentifier();
544 OSL_ENSURE( !aURL.isEmpty(),
545 "HierarchyContent::createNewContent - empty identifier!" );
547 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
548 aURL += "/";
550 if ( bCreateFolder )
551 aURL += "New_Folder";
552 else
553 aURL += "New_Link";
555 uno::Reference< ucb::XContentIdentifier > xId
556 = new ::ucbhelper::ContentIdentifier( aURL );
558 return create( m_xContext, m_pProvider, xId, Info );
560 else
562 OSL_FAIL( "createNewContent called on non-folder object!" );
563 return uno::Reference< ucb::XContent >();
568 // virtual
569 OUString HierarchyContent::getParentURL()
571 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
572 return aUri.getParentUri();
576 //static
577 bool HierarchyContent::hasData(
578 const uno::Reference< uno::XComponentContext >& rxContext,
579 HierarchyContentProvider* pProvider,
580 const uno::Reference< ucb::XContentIdentifier >& Identifier )
582 OUString aURL = Identifier->getContentIdentifier();
584 // Am I a root folder?
585 HierarchyUri aUri( aURL );
586 if ( aUri.isRootFolder() )
588 // hasData must always return 'true' for root folder
589 // even if no persistent data exist!!!
590 return true;
593 return HierarchyEntry( rxContext, pProvider, aURL ).hasData();
597 //static
598 bool HierarchyContent::loadData(
599 const uno::Reference< uno::XComponentContext >& rxContext,
600 HierarchyContentProvider* pProvider,
601 const uno::Reference< ucb::XContentIdentifier >& Identifier,
602 HierarchyContentProperties& rProps )
604 OUString aURL = Identifier->getContentIdentifier();
606 // Am I a root folder?
607 HierarchyUri aUri( aURL );
608 if ( aUri.isRootFolder() )
610 rProps = HierarchyContentProperties( HierarchyEntryData::FOLDER );
612 else
614 HierarchyEntry aEntry( rxContext, pProvider, aURL );
615 HierarchyEntryData aData;
616 if ( !aEntry.getData( aData ) )
617 return false;
619 rProps = HierarchyContentProperties( aData );
621 return true;
625 bool HierarchyContent::storeData()
627 HierarchyEntry aEntry(
628 m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
629 return aEntry.setData( m_aProps.getHierarchyEntryData() );
633 void HierarchyContent::renameData(
634 const uno::Reference< ucb::XContentIdentifier >& xOldId,
635 const uno::Reference< ucb::XContentIdentifier >& xNewId )
637 HierarchyEntry aEntry(
638 m_xContext, m_pProvider, xOldId->getContentIdentifier() );
639 aEntry.move( xNewId->getContentIdentifier(),
640 m_aProps.getHierarchyEntryData() );
644 bool HierarchyContent::removeData()
646 HierarchyEntry aEntry(
647 m_xContext, m_pProvider, m_xIdentifier->getContentIdentifier() );
648 return aEntry.remove();
652 void HierarchyContent::setKind(
653 const uno::Reference< ucb::XContentIdentifier >& Identifier )
655 if ( m_aProps.getIsFolder() )
657 // Am I a root folder?
658 HierarchyUri aUri( Identifier->getContentIdentifier() );
659 if ( aUri.isRootFolder() )
660 m_eKind = ROOT;
661 else
662 m_eKind = FOLDER;
664 else
665 m_eKind = LINK;
669 bool HierarchyContent::isReadOnly()
671 if ( !m_bCheckedReadOnly )
673 osl::Guard< osl::Mutex > aGuard( m_aMutex );
674 if ( !m_bCheckedReadOnly )
676 m_bCheckedReadOnly = true;
677 m_bIsReadOnly = true;
679 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
680 uno::Reference< lang::XMultiServiceFactory > xConfigProv
681 = m_pProvider->getConfigProvider( aUri.getService() );
682 if ( xConfigProv.is() )
684 uno::Sequence< OUString > aNames
685 = xConfigProv->getAvailableServiceNames();
686 m_bIsReadOnly = comphelper::findValue(aNames, "com.sun.star.ucb.HierarchyDataReadWriteAccess") == -1;
691 return m_bIsReadOnly;
695 uno::Reference< ucb::XContentIdentifier >
696 HierarchyContent::makeNewIdentifier( const OUString& rTitle )
698 osl::Guard< osl::Mutex > aGuard( m_aMutex );
700 // Assemble new content identifier...
701 HierarchyUri aUri( m_xIdentifier->getContentIdentifier() );
702 OUString aNewURL = aUri.getParentUri() + "/" +
703 ::ucb_impl::urihelper::encodeSegment( rTitle );
705 return uno::Reference< ucb::XContentIdentifier >(
706 new ::ucbhelper::ContentIdentifier( aNewURL ) );
710 void HierarchyContent::queryChildren( HierarchyContentRefVector& rChildren )
712 if ( ( m_eKind != FOLDER ) && ( m_eKind != ROOT ) )
713 return;
715 // Obtain a list with a snapshot of all currently instantiated contents
716 // from provider and extract the contents which are direct children
717 // of this content.
719 ::ucbhelper::ContentRefList aAllContents;
720 m_xProvider->queryExistingContents( aAllContents );
722 OUString aURL = m_xIdentifier->getContentIdentifier();
723 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
725 if ( nURLPos != ( aURL.getLength() - 1 ) )
727 // No trailing slash found. Append.
728 aURL += "/";
731 sal_Int32 nLen = aURL.getLength();
733 for ( const auto& rContent : aAllContents )
735 ::ucbhelper::ContentImplHelperRef xChild = rContent;
736 OUString aChildURL
737 = xChild->getIdentifier()->getContentIdentifier();
739 // Is aURL a prefix of aChildURL?
740 if ( ( aChildURL.getLength() > nLen ) &&
741 ( aChildURL.startsWith( aURL ) ) )
743 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
745 if ( ( nPos == -1 ) ||
746 ( nPos == ( aChildURL.getLength() - 1 ) ) )
748 // No further slashes/ only a final slash. It's a child!
749 rChildren.emplace_back(
750 static_cast< HierarchyContent * >( xChild.get() ) );
757 bool HierarchyContent::exchangeIdentity(
758 const uno::Reference< ucb::XContentIdentifier >& xNewId )
760 if ( !xNewId.is() )
761 return false;
763 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
765 uno::Reference< ucb::XContent > xThis = this;
767 // Already persistent?
768 if ( m_eState != PERSISTENT )
770 OSL_FAIL( "HierarchyContent::exchangeIdentity - Not persistent!" );
771 return false;
774 // Am I the root folder?
775 if ( m_eKind == ROOT )
777 OSL_FAIL( "HierarchyContent::exchangeIdentity - "
778 "Not supported by root folder!" );
779 return false;
782 // Exchange own identity.
784 // Fail, if a content with given id already exists.
785 if ( !hasData( xNewId ) )
787 OUString aOldURL = m_xIdentifier->getContentIdentifier();
789 aGuard.clear();
790 if ( exchange( xNewId ) )
792 if ( m_eKind == FOLDER )
794 // Process instantiated children...
796 HierarchyContentRefVector aChildren;
797 queryChildren( aChildren );
799 for ( const auto& rChild : aChildren )
801 HierarchyContentRef xChild = rChild;
803 // Create new content identifier for the child...
804 uno::Reference< ucb::XContentIdentifier > xOldChildId
805 = xChild->getIdentifier();
806 OUString aOldChildURL
807 = xOldChildId->getContentIdentifier();
808 OUString aNewChildURL
809 = aOldChildURL.replaceAt(
811 aOldURL.getLength(),
812 xNewId->getContentIdentifier() );
813 uno::Reference< ucb::XContentIdentifier > xNewChildId
814 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
816 if ( !xChild->exchangeIdentity( xNewChildId ) )
817 return false;
820 return true;
824 OSL_FAIL( "HierarchyContent::exchangeIdentity - "
825 "Panic! Cannot exchange identity!" );
826 return false;
830 // static
831 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
832 const uno::Reference< uno::XComponentContext >& rxContext,
833 const uno::Sequence< beans::Property >& rProperties,
834 const HierarchyContentProperties& rData,
835 HierarchyContentProvider* pProvider,
836 const OUString& rContentId )
838 // Note: Empty sequence means "get values of all supported properties".
840 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
841 = new ::ucbhelper::PropertyValueSet( rxContext );
843 if ( rProperties.hasElements() )
845 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
846 bool bTriedToGetAdditionalPropSet = false;
848 for ( const beans::Property& rProp : rProperties )
850 // Process Core properties.
852 if ( rProp.Name == "ContentType" )
854 xRow->appendString ( rProp, rData.getContentType() );
856 else if ( rProp.Name == "Title" )
858 xRow->appendString ( rProp, rData.getTitle() );
860 else if ( rProp.Name == "IsDocument" )
862 xRow->appendBoolean( rProp, rData.getIsDocument() );
864 else if ( rProp.Name == "IsFolder" )
866 xRow->appendBoolean( rProp, rData.getIsFolder() );
868 else if ( rProp.Name == "CreatableContentsInfo" )
870 xRow->appendObject(
871 rProp, uno::Any( rData.getCreatableContentsInfo() ) );
873 else if ( rProp.Name == "TargetURL" )
875 // TargetURL is only supported by links.
877 if ( rData.getIsDocument() )
878 xRow->appendString( rProp, rData.getTargetURL() );
879 else
880 xRow->appendVoid( rProp );
882 else
884 // Not a Core Property! Maybe it's an Additional Core Property?!
886 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
888 xAdditionalPropSet =
889 pProvider->getAdditionalPropertySet( rContentId,
890 false );
891 bTriedToGetAdditionalPropSet = true;
894 if ( xAdditionalPropSet.is() )
896 if ( !xRow->appendPropertySetValue(
897 xAdditionalPropSet,
898 rProp ) )
900 // Append empty entry.
901 xRow->appendVoid( rProp );
904 else
906 // Append empty entry.
907 xRow->appendVoid( rProp );
912 else
914 // Append all Core Properties.
915 xRow->appendString (
916 beans::Property( u"ContentType"_ustr,
918 cppu::UnoType<OUString>::get(),
919 beans::PropertyAttribute::BOUND
920 | beans::PropertyAttribute::READONLY ),
921 rData.getContentType() );
922 xRow->appendString (
923 beans::Property( u"Title"_ustr,
925 cppu::UnoType<OUString>::get(),
926 // @@@ Might actually be read-only!
927 beans::PropertyAttribute::BOUND ),
928 rData.getTitle() );
929 xRow->appendBoolean(
930 beans::Property( u"IsDocument"_ustr,
932 cppu::UnoType<bool>::get(),
933 beans::PropertyAttribute::BOUND
934 | beans::PropertyAttribute::READONLY ),
935 rData.getIsDocument() );
936 xRow->appendBoolean(
937 beans::Property( u"IsFolder"_ustr,
939 cppu::UnoType<bool>::get(),
940 beans::PropertyAttribute::BOUND
941 | beans::PropertyAttribute::READONLY ),
942 rData.getIsFolder() );
944 if ( rData.getIsDocument() )
945 xRow->appendString(
946 beans::Property( u"TargetURL"_ustr,
948 cppu::UnoType<OUString>::get(),
949 // @@@ Might actually be read-only!
950 beans::PropertyAttribute::BOUND ),
951 rData.getTargetURL() );
952 xRow->appendObject(
953 beans::Property(
954 u"CreatableContentsInfo"_ustr,
956 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
957 beans::PropertyAttribute::BOUND
958 | beans::PropertyAttribute::READONLY ),
959 uno::Any( rData.getCreatableContentsInfo() ) );
961 // Append all Additional Core Properties.
963 uno::Reference< beans::XPropertySet > xSet =
964 pProvider->getAdditionalPropertySet( rContentId, false );
965 xRow->appendPropertySet( xSet );
968 return xRow;
972 uno::Reference< sdbc::XRow > HierarchyContent::getPropertyValues(
973 const uno::Sequence< beans::Property >& rProperties )
975 osl::Guard< osl::Mutex > aGuard( m_aMutex );
976 return getPropertyValues( m_xContext,
977 rProperties,
978 m_aProps,
979 m_pProvider,
980 m_xIdentifier->getContentIdentifier() );
984 uno::Sequence< uno::Any > HierarchyContent::setPropertyValues(
985 const uno::Sequence< beans::PropertyValue >& rValues,
986 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
988 osl::ResettableGuard< osl::Mutex > aGuard( m_aMutex );
990 uno::Sequence< uno::Any > aRet( rValues.getLength() );
991 auto aRetRange = asNonConstRange(aRet);
992 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
993 sal_Int32 nChanged = 0;
995 beans::PropertyChangeEvent aEvent;
996 aEvent.Source = getXWeak();
997 aEvent.Further = false;
998 // aEvent.PropertyName =
999 aEvent.PropertyHandle = -1;
1000 // aEvent.OldValue =
1001 // aEvent.NewValue =
1003 const beans::PropertyValue* pValues = rValues.getConstArray();
1004 sal_Int32 nCount = rValues.getLength();
1006 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1007 bool bTriedToGetAdditionalPropSet = false;
1009 bool bExchange = false;
1010 OUString aOldTitle;
1011 OUString aOldName;
1012 sal_Int32 nTitlePos = -1;
1014 for ( sal_Int32 n = 0; n < nCount; ++n )
1016 const beans::PropertyValue& rValue = pValues[ n ];
1018 if ( rValue.Name == "ContentType" )
1020 // Read-only property!
1021 aRetRange[ n ] <<= lang::IllegalAccessException(
1022 u"Property is read-only!"_ustr,
1023 getXWeak() );
1025 else if ( rValue.Name == "IsDocument" )
1027 // Read-only property!
1028 aRetRange[ n ] <<= lang::IllegalAccessException(
1029 u"Property is read-only!"_ustr,
1030 getXWeak() );
1032 else if ( rValue.Name == "IsFolder" )
1034 // Read-only property!
1035 aRetRange[ n ] <<= lang::IllegalAccessException(
1036 u"Property is read-only!"_ustr,
1037 getXWeak() );
1039 else if ( rValue.Name == "CreatableContentsInfo" )
1041 // Read-only property!
1042 aRetRange[ n ] <<= lang::IllegalAccessException(
1043 u"Property is read-only!"_ustr,
1044 getXWeak() );
1046 else if ( rValue.Name == "Title" )
1048 if ( isReadOnly() )
1050 aRetRange[ n ] <<= lang::IllegalAccessException(
1051 u"Property is read-only!"_ustr,
1052 getXWeak() );
1054 else
1056 OUString aNewValue;
1057 if ( rValue.Value >>= aNewValue )
1059 // No empty titles!
1060 if ( !aNewValue.isEmpty() )
1062 if ( aNewValue != m_aProps.getTitle() )
1064 // modified title -> modified URL -> exchange !
1065 if ( m_eState == PERSISTENT )
1066 bExchange = true;
1068 aOldTitle = m_aProps.getTitle();
1069 aOldName = m_aProps.getName();
1071 m_aProps.setTitle( aNewValue );
1072 m_aProps.setName(
1073 ::ucb_impl::urihelper::encodeSegment(
1074 aNewValue ) );
1076 // property change event will be set later...
1078 // remember position within sequence of values
1079 // (for error handling).
1080 nTitlePos = n;
1083 else
1085 aRetRange[ n ] <<= lang::IllegalArgumentException(
1086 u"Empty title not allowed!"_ustr,
1087 getXWeak(),
1088 -1 );
1091 else
1093 aRetRange[ n ] <<= beans::IllegalTypeException(
1094 u"Property value has wrong type!"_ustr,
1095 getXWeak() );
1099 else if ( rValue.Name == "TargetURL" )
1101 if ( isReadOnly() )
1103 aRetRange[ n ] <<= lang::IllegalAccessException(
1104 u"Property is read-only!"_ustr,
1105 getXWeak() );
1107 else
1109 // TargetURL is only supported by links.
1111 if ( m_eKind == LINK )
1113 OUString aNewValue;
1114 if ( rValue.Value >>= aNewValue )
1116 // No empty target URL's!
1117 if ( !aNewValue.isEmpty() )
1119 if ( aNewValue != m_aProps.getTargetURL() )
1121 aEvent.PropertyName = rValue.Name;
1122 aEvent.OldValue <<= m_aProps.getTargetURL();
1123 aEvent.NewValue <<= aNewValue;
1125 aChanges.getArray()[ nChanged ] = aEvent;
1127 m_aProps.setTargetURL( aNewValue );
1128 nChanged++;
1131 else
1133 aRetRange[ n ] <<= lang::IllegalArgumentException(
1134 u"Empty target URL not allowed!"_ustr,
1135 getXWeak(),
1136 -1 );
1139 else
1141 aRetRange[ n ] <<= beans::IllegalTypeException(
1142 u"Property value has wrong type!"_ustr,
1143 getXWeak() );
1146 else
1148 aRetRange[ n ] <<= beans::UnknownPropertyException(
1149 u"TargetURL only supported by links!"_ustr,
1150 getXWeak() );
1154 else
1156 // Not a Core Property! Maybe it's an Additional Core Property?!
1158 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1160 xAdditionalPropSet = getAdditionalPropertySet( false );
1161 bTriedToGetAdditionalPropSet = true;
1164 if ( xAdditionalPropSet.is() )
1168 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1169 rValue.Name );
1170 if ( aOldValue != rValue.Value )
1172 xAdditionalPropSet->setPropertyValue(
1173 rValue.Name, rValue.Value );
1175 aEvent.PropertyName = rValue.Name;
1176 aEvent.OldValue = std::move(aOldValue);
1177 aEvent.NewValue = rValue.Value;
1179 aChanges.getArray()[ nChanged ] = aEvent;
1180 nChanged++;
1183 catch ( beans::UnknownPropertyException const & e )
1185 aRetRange[ n ] <<= e;
1187 catch ( lang::WrappedTargetException const & e )
1189 aRetRange[ n ] <<= e;
1191 catch ( beans::PropertyVetoException const & e )
1193 aRetRange[ n ] <<= e;
1195 catch ( lang::IllegalArgumentException const & e )
1197 aRetRange[ n ] <<= e;
1200 else
1202 aRetRange[ n ] <<= uno::Exception(
1203 u"No property set for storing the value!"_ustr,
1204 getXWeak() );
1209 if ( bExchange )
1211 uno::Reference< ucb::XContentIdentifier > xOldId
1212 = m_xIdentifier;
1213 uno::Reference< ucb::XContentIdentifier > xNewId
1214 = makeNewIdentifier( m_aProps.getTitle() );
1216 aGuard.clear();
1217 if ( exchangeIdentity( xNewId ) )
1219 // Adapt persistent data.
1220 renameData( xOldId, xNewId );
1222 // Adapt Additional Core Properties.
1223 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1224 xNewId->getContentIdentifier() );
1226 else
1228 // Roll-back.
1229 m_aProps.setTitle( aOldTitle );
1230 m_aProps.setName ( aOldName );
1232 aOldTitle.clear();
1233 aOldName.clear();
1235 // Set error .
1236 aRetRange[ nTitlePos ] <<= uno::Exception(
1237 u"Exchange failed!"_ustr,
1238 getXWeak() );
1240 aGuard.reset();
1243 if ( !aOldTitle.isEmpty() )
1245 aEvent.PropertyName = "Title";
1246 aEvent.OldValue <<= aOldTitle;
1247 aEvent.NewValue <<= m_aProps.getTitle();
1249 aChanges.getArray()[ nChanged ] = std::move(aEvent);
1250 nChanged++;
1253 if ( nChanged > 0 )
1255 // Save changes, if content was already made persistent.
1256 if ( !bExchange && ( m_eState == PERSISTENT ) )
1258 if ( !storeData() )
1260 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1262 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1263 }));
1264 ucbhelper::cancelCommandExecution(
1265 ucb::IOErrorCode_CANT_WRITE,
1266 aArgs,
1267 xEnv,
1268 u"Cannot store persistent data!"_ustr,
1269 this );
1270 // Unreachable
1274 aChanges.realloc( nChanged );
1276 aGuard.clear();
1277 notifyPropertiesChange( aChanges );
1280 return aRet;
1284 void HierarchyContent::insert( sal_Int32 nNameClashResolve,
1285 const uno::Reference<
1286 ucb::XCommandEnvironment > & xEnv )
1288 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1290 // Am I the root folder?
1291 if ( m_eKind == ROOT )
1293 ucbhelper::cancelCommandExecution(
1294 uno::Any( ucb::UnsupportedCommandException(
1295 u"Not supported by root folder!"_ustr,
1296 getXWeak() ) ),
1297 xEnv );
1298 // Unreachable
1301 // Check, if all required properties were set.
1302 if ( m_aProps.getTitle().isEmpty() )
1304 uno::Sequence<OUString> aProps { u"Title"_ustr };
1305 ucbhelper::cancelCommandExecution(
1306 uno::Any( ucb::MissingPropertiesException(
1307 OUString(),
1308 getXWeak(),
1309 aProps ) ),
1310 xEnv );
1311 // Unreachable
1314 // Assemble new content identifier...
1316 uno::Reference< ucb::XContentIdentifier > xId
1317 = makeNewIdentifier( m_aProps.getTitle() );
1319 // Handle possible name clash...
1321 switch ( nNameClashResolve )
1323 // fail.
1324 case ucb::NameClash::ERROR:
1325 if ( hasData( xId ) )
1327 ucbhelper::cancelCommandExecution(
1328 uno::Any(
1329 ucb::NameClashException(
1330 OUString(),
1331 getXWeak(),
1332 task::InteractionClassification_ERROR,
1333 m_aProps.getTitle() ) ),
1334 xEnv );
1335 // Unreachable
1337 break;
1339 // replace existing object.
1340 case ucb::NameClash::OVERWRITE:
1341 break;
1343 // "invent" a new valid title.
1344 case ucb::NameClash::RENAME:
1345 if ( hasData( xId ) )
1347 sal_Int32 nTry = 0;
1351 OUString aNewId = xId->getContentIdentifier() + "_" + OUString::number( ++nTry );
1352 xId = new ::ucbhelper::ContentIdentifier( aNewId );
1354 while ( hasData( xId ) && ( nTry < 1000 ) );
1356 if ( nTry == 1000 )
1358 ucbhelper::cancelCommandExecution(
1359 uno::Any(
1360 ucb::UnsupportedNameClashException(
1361 u"Unable to resolve name clash!"_ustr,
1362 getXWeak(),
1363 nNameClashResolve ) ),
1364 xEnv );
1365 // Unreachable
1367 else
1369 OUString aNewTitle( m_aProps.getTitle() + "_" + OUString::number( nTry ) );
1370 m_aProps.setTitle( aNewTitle );
1373 break;
1375 case ucb::NameClash::KEEP: // deprecated
1376 case ucb::NameClash::ASK:
1377 default:
1378 if ( hasData( xId ) )
1380 ucbhelper::cancelCommandExecution(
1381 uno::Any(
1382 ucb::UnsupportedNameClashException(
1383 OUString(),
1384 getXWeak(),
1385 nNameClashResolve ) ),
1386 xEnv );
1387 // Unreachable
1389 break;
1392 // Identifier changed?
1393 bool bNewId = ( xId->getContentIdentifier()
1394 != m_xIdentifier->getContentIdentifier() );
1395 m_xIdentifier = std::move(xId);
1397 if ( !storeData() )
1399 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1401 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1402 }));
1403 ucbhelper::cancelCommandExecution(
1404 ucb::IOErrorCode_CANT_WRITE,
1405 aArgs,
1406 xEnv,
1407 u"Cannot store persistent data!"_ustr,
1408 this );
1409 // Unreachable
1412 m_eState = PERSISTENT;
1414 if ( bNewId )
1416 aGuard.clear();
1417 inserted();
1422 void HierarchyContent::destroy( bool bDeletePhysical,
1423 const uno::Reference<
1424 ucb::XCommandEnvironment > & xEnv )
1426 // @@@ take care about bDeletePhysical -> trashcan support
1428 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1430 uno::Reference< ucb::XContent > xThis = this;
1432 // Persistent?
1433 if ( m_eState != PERSISTENT )
1435 ucbhelper::cancelCommandExecution(
1436 uno::Any( ucb::UnsupportedCommandException(
1437 u"Not persistent!"_ustr,
1438 getXWeak() ) ),
1439 xEnv );
1440 // Unreachable
1443 // Am I the root folder?
1444 if ( m_eKind == ROOT )
1446 ucbhelper::cancelCommandExecution(
1447 uno::Any( ucb::UnsupportedCommandException(
1448 u"Not supported by root folder!"_ustr,
1449 getXWeak() ) ),
1450 xEnv );
1451 // Unreachable
1454 m_eState = DEAD;
1456 aGuard.clear();
1457 deleted();
1459 if ( m_eKind == FOLDER )
1461 // Process instantiated children...
1463 HierarchyContentRefVector aChildren;
1464 queryChildren( aChildren );
1466 for ( auto & child : aChildren)
1468 child->destroy( bDeletePhysical, xEnv );
1474 void HierarchyContent::transfer(
1475 const ucb::TransferInfo& rInfo,
1476 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1478 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1480 // Persistent?
1481 if ( m_eState != PERSISTENT )
1483 ucbhelper::cancelCommandExecution(
1484 uno::Any( ucb::UnsupportedCommandException(
1485 u"Not persistent!"_ustr,
1486 getXWeak() ) ),
1487 xEnv );
1488 // Unreachable
1491 // Is source a hierarchy content?
1492 if ( !rInfo.SourceURL.startsWith( HIERARCHY_URL_SCHEME ":/" ) )
1494 ucbhelper::cancelCommandExecution(
1495 uno::Any( ucb::InteractiveBadTransferURLException(
1496 OUString(),
1497 getXWeak() ) ),
1498 xEnv );
1499 // Unreachable
1502 // Is source not a parent of me / not me?
1503 OUString aId = m_xIdentifier->getContentIdentifier();
1504 sal_Int32 nPos = aId.lastIndexOf( '/' );
1505 if ( nPos != ( aId.getLength() - 1 ) )
1507 // No trailing slash found. Append.
1508 aId += "/";
1511 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1513 if ( aId.startsWith( rInfo.SourceURL ) )
1515 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1517 {"Uri", uno::Any(rInfo.SourceURL)}
1518 }));
1519 ucbhelper::cancelCommandExecution(
1520 ucb::IOErrorCode_RECURSIVE,
1521 aArgs,
1522 xEnv,
1523 u"Target is equal to or is a child of source!"_ustr,
1524 this );
1525 // Unreachable
1530 // 0) Obtain content object for source.
1533 uno::Reference< ucb::XContentIdentifier > xId
1534 = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1536 // Note: The static cast is okay here, because its sure that
1537 // m_xProvider is always the HierarchyContentProvider.
1538 rtl::Reference< HierarchyContent > xSource;
1542 xSource = static_cast< HierarchyContent * >(
1543 m_xProvider->queryContent( xId ).get() );
1545 catch ( ucb::IllegalIdentifierException const & )
1547 // queryContent
1550 if ( !xSource.is() )
1552 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1554 {"Uri", uno::Any(xId->getContentIdentifier())}
1555 }));
1556 ucbhelper::cancelCommandExecution(
1557 ucb::IOErrorCode_CANT_READ,
1558 aArgs,
1559 xEnv,
1560 u"Cannot instantiate source object!"_ustr,
1561 this );
1562 // Unreachable
1566 // 1) Create new child content.
1569 ucb::ContentInfo aContentInfo;
1570 aContentInfo.Type = xSource->isFolder()
1571 ? HIERARCHY_FOLDER_CONTENT_TYPE
1572 : HIERARCHY_LINK_CONTENT_TYPE;
1573 aContentInfo.Attributes = 0;
1575 // Note: The static cast is okay here, because its sure that
1576 // createNewContent always creates a HierarchyContent.
1577 rtl::Reference< HierarchyContent > xTarget
1578 = static_cast< HierarchyContent * >(
1579 createNewContent( aContentInfo ).get() );
1580 if ( !xTarget.is() )
1582 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1584 {"Folder", uno::Any(aId)}
1585 }));
1586 ucbhelper::cancelCommandExecution(
1587 ucb::IOErrorCode_CANT_CREATE,
1588 aArgs,
1589 xEnv,
1590 u"XContentCreator::createNewContent failed!"_ustr,
1591 this );
1592 // Unreachable
1596 // 2) Copy data from source content to child content.
1599 uno::Sequence< beans::Property > aSourceProps
1600 = xSource->getPropertySetInfo( xEnv )->getProperties();
1601 sal_Int32 nCount = aSourceProps.getLength();
1603 if ( nCount )
1605 bool bHadTitle = rInfo.NewTitle.isEmpty();
1607 // Get all source values.
1608 uno::Reference< sdbc::XRow > xRow
1609 = xSource->getPropertyValues( aSourceProps );
1611 uno::Sequence< beans::PropertyValue > aValues( nCount );
1612 beans::PropertyValue* pValues = aValues.getArray();
1614 const beans::Property* pProps = aSourceProps.getConstArray();
1615 for ( sal_Int32 n = 0; n < nCount; ++n )
1617 const beans::Property& rProp = pProps[ n ];
1618 beans::PropertyValue& rValue = pValues[ n ];
1620 rValue.Name = rProp.Name;
1621 rValue.Handle = rProp.Handle;
1623 if ( !bHadTitle && rProp.Name == "Title" )
1625 // Set new title instead of original.
1626 bHadTitle = true;
1627 rValue.Value <<= rInfo.NewTitle;
1629 else
1630 rValue.Value = xRow->getObject(
1631 n + 1,
1632 uno::Reference< container::XNameAccess >() );
1634 rValue.State = beans::PropertyState_DIRECT_VALUE;
1636 if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1638 // Add Additional Core Property.
1641 xTarget->addProperty( rProp.Name,
1642 rProp.Attributes,
1643 rValue.Value );
1645 catch ( beans::PropertyExistException const & )
1648 catch ( beans::IllegalTypeException const & )
1651 catch ( lang::IllegalArgumentException const & )
1657 // Set target values.
1658 xTarget->setPropertyValues( aValues, xEnv );
1662 // 3) Commit (insert) child.
1665 xTarget->insert( rInfo.NameClash, xEnv );
1668 // 4) Transfer (copy) children of source.
1671 if ( xSource->isFolder() )
1673 HierarchyEntry aFolder(
1674 m_xContext, m_pProvider, xId->getContentIdentifier() );
1675 HierarchyEntry::iterator it;
1677 while ( aFolder.next( it ) )
1679 const HierarchyEntryData& rResult = *it;
1681 OUString aChildId = xId->getContentIdentifier();
1682 if ( ( aChildId.lastIndexOf( '/' ) + 1 ) != aChildId.getLength() )
1683 aChildId += "/";
1685 aChildId += rResult.getName();
1687 ucb::TransferInfo aInfo;
1688 aInfo.MoveData = false;
1689 aInfo.NewTitle.clear();
1690 aInfo.SourceURL = aChildId;
1691 aInfo.NameClash = rInfo.NameClash;
1693 // Transfer child to target.
1694 xTarget->transfer( aInfo, xEnv );
1699 // 5) Destroy source ( when moving only ) .
1702 if ( !rInfo.MoveData )
1703 return;
1705 xSource->destroy( true, xEnv );
1707 // Remove all persistent data of source and its children.
1708 if ( !xSource->removeData() )
1710 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1712 {"Uri", uno::Any(xSource->m_xIdentifier->getContentIdentifier())}
1713 }));
1714 ucbhelper::cancelCommandExecution(
1715 ucb::IOErrorCode_CANT_WRITE,
1716 aArgs,
1717 xEnv,
1718 u"Cannot remove persistent data of source object!"_ustr,
1719 this );
1720 // Unreachable
1723 // Remove own and all children's Additional Core Properties.
1724 xSource->removeAdditionalPropertySet();
1728 // HierarchyContentProperties Implementation.
1731 uno::Sequence< ucb::ContentInfo >
1732 HierarchyContentProperties::getCreatableContentsInfo() const
1734 if ( getIsFolder() )
1736 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1738 // Folder.
1739 aSeq.getArray()[ 0 ].Type = HIERARCHY_FOLDER_CONTENT_TYPE;
1740 aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1742 uno::Sequence< beans::Property > aFolderProps( 1 );
1743 aFolderProps.getArray()[ 0 ] = beans::Property(
1744 u"Title"_ustr,
1746 cppu::UnoType<OUString>::get(),
1747 beans::PropertyAttribute::BOUND );
1748 aSeq.getArray()[ 0 ].Properties = std::move(aFolderProps);
1750 // Link.
1751 aSeq.getArray()[ 1 ].Type = HIERARCHY_LINK_CONTENT_TYPE;
1752 aSeq.getArray()[ 1 ].Attributes = ucb::ContentInfoAttribute::KIND_LINK;
1754 uno::Sequence< beans::Property > aLinkProps( 2 );
1755 aLinkProps.getArray()[ 0 ] = beans::Property(
1756 u"Title"_ustr,
1758 cppu::UnoType<OUString>::get(),
1759 beans::PropertyAttribute::BOUND );
1760 aLinkProps.getArray()[ 1 ] = beans::Property(
1761 u"TargetURL"_ustr,
1763 cppu::UnoType<OUString>::get(),
1764 beans::PropertyAttribute::BOUND );
1765 aSeq.getArray()[ 1 ].Properties = std::move(aLinkProps);
1767 return aSeq;
1769 else
1771 return uno::Sequence< ucb::ContentInfo >( 0 );
1775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */