1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 /**************************************************************************
23 **************************************************************************
25 - optimize transfer command. "Move" should be implementable much more
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
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>
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
) )
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() )
108 if ( Info
.Type
!= HIERARCHY_FOLDER_CONTENT_TYPE
&& Info
.Type
!= HIERARCHY_LINK_CONTENT_TYPE
)
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
);
148 HierarchyContent::~HierarchyContent()
153 // XInterface methods.
157 void SAL_CALL
HierarchyContent::acquire()
160 ContentImplHelper::acquire();
165 void SAL_CALL
HierarchyContent::release()
168 ContentImplHelper::release();
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() )
194 // XTypeProvider methods.
197 XTYPEPROVIDER_COMMON_IMPL( HierarchyContent
);
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();
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.
244 OUString SAL_CALL
HierarchyContent::getImplementationName()
246 return u
"com.sun.star.comp.ucb.HierarchyContent"_ustr
;
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";
261 aSNS
.getArray()[ 0 ] = "com.sun.star.ucb.HierarchyRootFolderContent";
271 OUString SAL_CALL
HierarchyContent::getContentType()
273 return m_aProps
.getContentType();
278 uno::Reference
< ucb::XContentIdentifier
> SAL_CALL
279 HierarchyContent::getIdentifier()
282 if ( m_eState
== TRANSIENT
)
284 // Transient contents have no identifier.
285 return uno::Reference
< ucb::XContentIdentifier
>();
288 return ContentImplHelper::getIdentifier();
292 // XCommandProcessor methods.
296 uno::Any SAL_CALL
HierarchyContent::execute(
297 const ucb::Command
& aCommand
,
298 sal_Int32
/*CommandId*/,
299 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
303 if ( aCommand
.Name
== "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
,
321 aRet
<<= getPropertyValues( Properties
);
323 else if ( aCommand
.Name
== "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
,
341 if ( !aProperties
.hasElements() )
343 ucbhelper::cancelCommandExecution(
344 uno::Any( lang::IllegalArgumentException(
345 u
"No properties!"_ustr
,
352 aRet
<<= setPropertyValues( aProperties
, Environment
);
354 else if ( aCommand
.Name
== "getPropertySetInfo" )
357 // getPropertySetInfo
360 aRet
<<= getPropertySetInfo( Environment
);
362 else if ( aCommand
.Name
== "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
,
388 uno::Reference
< ucb::XDynamicResultSet
> xSet
389 = new DynamicResultSet( m_xContext
, this, aOpenCommand
);
392 else if ( aCommand
.Name
== "insert" && ( m_eKind
!= ROOT
) && !isReadOnly() )
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
,
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() )
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.
430 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
432 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
434 ucbhelper::cancelCommandExecution(
435 ucb::IOErrorCode_CANT_WRITE
,
438 u
"Cannot remove persistent data!"_ustr
,
443 // Remove own and all children's Additional Core Properties.
444 removeAdditionalPropertySet();
446 else if ( aCommand
.Name
== "transfer" && isFolder() && !isReadOnly() )
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
,
466 transfer( aInfo
, Environment
);
468 else if ( aCommand
.Name
== "createNewContent" && isFolder() && !isReadOnly() )
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
,
488 aRet
<<= createNewContent( aInfo
);
493 // Unsupported command
496 ucbhelper::cancelCommandExecution(
497 uno::Any( ucb::UnsupportedCommandException(
509 void SAL_CALL
HierarchyContent::abort( sal_Int32
/*CommandId*/ )
511 // @@@ Generally, no action takes much time...
515 // XContentCreator methods.
519 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
520 HierarchyContent::queryCreatableContentsInfo()
522 return m_aProps
.getCreatableContentsInfo();
527 uno::Reference
< ucb::XContent
> SAL_CALL
528 HierarchyContent::createNewContent( const ucb::ContentInfo
& Info
)
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() )
551 aURL
+= "New_Folder";
555 uno::Reference
< ucb::XContentIdentifier
> xId
556 = new ::ucbhelper::ContentIdentifier( aURL
);
558 return create( m_xContext
, m_pProvider
, xId
, Info
);
562 OSL_FAIL( "createNewContent called on non-folder object!" );
563 return uno::Reference
< ucb::XContent
>();
569 OUString
HierarchyContent::getParentURL()
571 HierarchyUri
aUri( m_xIdentifier
->getContentIdentifier() );
572 return aUri
.getParentUri();
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!!!
593 return HierarchyEntry( rxContext
, pProvider
, aURL
).hasData();
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
);
614 HierarchyEntry
aEntry( rxContext
, pProvider
, aURL
);
615 HierarchyEntryData aData
;
616 if ( !aEntry
.getData( aData
) )
619 rProps
= HierarchyContentProperties( aData
);
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() )
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
) )
715 // Obtain a list with a snapshot of all currently instantiated contents
716 // from provider and extract the contents which are direct children
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.
731 sal_Int32 nLen
= aURL
.getLength();
733 for ( const auto& rContent
: aAllContents
)
735 ::ucbhelper::ContentImplHelperRef xChild
= rContent
;
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
)
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!" );
774 // Am I the root folder?
775 if ( m_eKind
== ROOT
)
777 OSL_FAIL( "HierarchyContent::exchangeIdentity - "
778 "Not supported by root folder!" );
782 // Exchange own identity.
784 // Fail, if a content with given id already exists.
785 if ( !hasData( xNewId
) )
787 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
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(
812 xNewId
->getContentIdentifier() );
813 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
814 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
816 if ( !xChild
->exchangeIdentity( xNewChildId
) )
824 OSL_FAIL( "HierarchyContent::exchangeIdentity - "
825 "Panic! Cannot exchange identity!" );
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" )
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() );
880 xRow
->appendVoid( rProp
);
884 // Not a Core Property! Maybe it's an Additional Core Property?!
886 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
889 pProvider
->getAdditionalPropertySet( rContentId
,
891 bTriedToGetAdditionalPropSet
= true;
894 if ( xAdditionalPropSet
.is() )
896 if ( !xRow
->appendPropertySetValue(
900 // Append empty entry.
901 xRow
->appendVoid( rProp
);
906 // Append empty entry.
907 xRow
->appendVoid( rProp
);
914 // Append all Core Properties.
916 beans::Property( u
"ContentType"_ustr
,
918 cppu::UnoType
<OUString
>::get(),
919 beans::PropertyAttribute::BOUND
920 | beans::PropertyAttribute::READONLY
),
921 rData
.getContentType() );
923 beans::Property( u
"Title"_ustr
,
925 cppu::UnoType
<OUString
>::get(),
926 // @@@ Might actually be read-only!
927 beans::PropertyAttribute::BOUND
),
930 beans::Property( u
"IsDocument"_ustr
,
932 cppu::UnoType
<bool>::get(),
933 beans::PropertyAttribute::BOUND
934 | beans::PropertyAttribute::READONLY
),
935 rData
.getIsDocument() );
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() )
946 beans::Property( u
"TargetURL"_ustr
,
948 cppu::UnoType
<OUString
>::get(),
949 // @@@ Might actually be read-only!
950 beans::PropertyAttribute::BOUND
),
951 rData
.getTargetURL() );
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
);
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
,
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;
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
,
1025 else if ( rValue
.Name
== "IsDocument" )
1027 // Read-only property!
1028 aRetRange
[ n
] <<= lang::IllegalAccessException(
1029 u
"Property is read-only!"_ustr
,
1032 else if ( rValue
.Name
== "IsFolder" )
1034 // Read-only property!
1035 aRetRange
[ n
] <<= lang::IllegalAccessException(
1036 u
"Property is read-only!"_ustr
,
1039 else if ( rValue
.Name
== "CreatableContentsInfo" )
1041 // Read-only property!
1042 aRetRange
[ n
] <<= lang::IllegalAccessException(
1043 u
"Property is read-only!"_ustr
,
1046 else if ( rValue
.Name
== "Title" )
1050 aRetRange
[ n
] <<= lang::IllegalAccessException(
1051 u
"Property is read-only!"_ustr
,
1057 if ( rValue
.Value
>>= aNewValue
)
1060 if ( !aNewValue
.isEmpty() )
1062 if ( aNewValue
!= m_aProps
.getTitle() )
1064 // modified title -> modified URL -> exchange !
1065 if ( m_eState
== PERSISTENT
)
1068 aOldTitle
= m_aProps
.getTitle();
1069 aOldName
= m_aProps
.getName();
1071 m_aProps
.setTitle( aNewValue
);
1073 ::ucb_impl::urihelper::encodeSegment(
1076 // property change event will be set later...
1078 // remember position within sequence of values
1079 // (for error handling).
1085 aRetRange
[ n
] <<= lang::IllegalArgumentException(
1086 u
"Empty title not allowed!"_ustr
,
1093 aRetRange
[ n
] <<= beans::IllegalTypeException(
1094 u
"Property value has wrong type!"_ustr
,
1099 else if ( rValue
.Name
== "TargetURL" )
1103 aRetRange
[ n
] <<= lang::IllegalAccessException(
1104 u
"Property is read-only!"_ustr
,
1109 // TargetURL is only supported by links.
1111 if ( m_eKind
== LINK
)
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
);
1133 aRetRange
[ n
] <<= lang::IllegalArgumentException(
1134 u
"Empty target URL not allowed!"_ustr
,
1141 aRetRange
[ n
] <<= beans::IllegalTypeException(
1142 u
"Property value has wrong type!"_ustr
,
1148 aRetRange
[ n
] <<= beans::UnknownPropertyException(
1149 u
"TargetURL only supported by links!"_ustr
,
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(
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
;
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
;
1202 aRetRange
[ n
] <<= uno::Exception(
1203 u
"No property set for storing the value!"_ustr
,
1211 uno::Reference
< ucb::XContentIdentifier
> xOldId
1213 uno::Reference
< ucb::XContentIdentifier
> xNewId
1214 = makeNewIdentifier( m_aProps
.getTitle() );
1217 if ( exchangeIdentity( xNewId
) )
1219 // Adapt persistent data.
1220 renameData( xOldId
, xNewId
);
1222 // Adapt Additional Core Properties.
1223 renameAdditionalPropertySet( xOldId
->getContentIdentifier(),
1224 xNewId
->getContentIdentifier() );
1229 m_aProps
.setTitle( aOldTitle
);
1230 m_aProps
.setName ( aOldName
);
1236 aRetRange
[ nTitlePos
] <<= uno::Exception(
1237 u
"Exchange failed!"_ustr
,
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
);
1255 // Save changes, if content was already made persistent.
1256 if ( !bExchange
&& ( m_eState
== PERSISTENT
) )
1260 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1262 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1264 ucbhelper::cancelCommandExecution(
1265 ucb::IOErrorCode_CANT_WRITE
,
1268 u
"Cannot store persistent data!"_ustr
,
1274 aChanges
.realloc( nChanged
);
1277 notifyPropertiesChange( aChanges
);
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
,
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(
1314 // Assemble new content identifier...
1316 uno::Reference
< ucb::XContentIdentifier
> xId
1317 = makeNewIdentifier( m_aProps
.getTitle() );
1319 // Handle possible name clash...
1321 switch ( nNameClashResolve
)
1324 case ucb::NameClash::ERROR
:
1325 if ( hasData( xId
) )
1327 ucbhelper::cancelCommandExecution(
1329 ucb::NameClashException(
1332 task::InteractionClassification_ERROR
,
1333 m_aProps
.getTitle() ) ),
1339 // replace existing object.
1340 case ucb::NameClash::OVERWRITE
:
1343 // "invent" a new valid title.
1344 case ucb::NameClash::RENAME
:
1345 if ( hasData( xId
) )
1351 OUString aNewId
= xId
->getContentIdentifier() + "_" + OUString::number( ++nTry
);
1352 xId
= new ::ucbhelper::ContentIdentifier( aNewId
);
1354 while ( hasData( xId
) && ( nTry
< 1000 ) );
1358 ucbhelper::cancelCommandExecution(
1360 ucb::UnsupportedNameClashException(
1361 u
"Unable to resolve name clash!"_ustr
,
1363 nNameClashResolve
) ),
1369 OUString
aNewTitle( m_aProps
.getTitle() + "_" + OUString::number( nTry
) );
1370 m_aProps
.setTitle( aNewTitle
);
1375 case ucb::NameClash::KEEP
: // deprecated
1376 case ucb::NameClash::ASK
:
1378 if ( hasData( xId
) )
1380 ucbhelper::cancelCommandExecution(
1382 ucb::UnsupportedNameClashException(
1385 nNameClashResolve
) ),
1392 // Identifier changed?
1393 bool bNewId
= ( xId
->getContentIdentifier()
1394 != m_xIdentifier
->getContentIdentifier() );
1395 m_xIdentifier
= std::move(xId
);
1399 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1401 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1403 ucbhelper::cancelCommandExecution(
1404 ucb::IOErrorCode_CANT_WRITE
,
1407 u
"Cannot store persistent data!"_ustr
,
1412 m_eState
= PERSISTENT
;
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;
1433 if ( m_eState
!= PERSISTENT
)
1435 ucbhelper::cancelCommandExecution(
1436 uno::Any( ucb::UnsupportedCommandException(
1437 u
"Not persistent!"_ustr
,
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
,
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
);
1481 if ( m_eState
!= PERSISTENT
)
1483 ucbhelper::cancelCommandExecution(
1484 uno::Any( ucb::UnsupportedCommandException(
1485 u
"Not persistent!"_ustr
,
1491 // Is source a hierarchy content?
1492 if ( !rInfo
.SourceURL
.startsWith( HIERARCHY_URL_SCHEME
":/" ) )
1494 ucbhelper::cancelCommandExecution(
1495 uno::Any( ucb::InteractiveBadTransferURLException(
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.
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
)}
1519 ucbhelper::cancelCommandExecution(
1520 ucb::IOErrorCode_RECURSIVE
,
1523 u
"Target is equal to or is a child of source!"_ustr
,
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 & )
1550 if ( !xSource
.is() )
1552 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1554 {"Uri", uno::Any(xId
->getContentIdentifier())}
1556 ucbhelper::cancelCommandExecution(
1557 ucb::IOErrorCode_CANT_READ
,
1560 u
"Cannot instantiate source object!"_ustr
,
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
)}
1586 ucbhelper::cancelCommandExecution(
1587 ucb::IOErrorCode_CANT_CREATE
,
1590 u
"XContentCreator::createNewContent failed!"_ustr
,
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();
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.
1627 rValue
.Value
<<= rInfo
.NewTitle
;
1630 rValue
.Value
= xRow
->getObject(
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
,
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() )
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
)
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())}
1714 ucbhelper::cancelCommandExecution(
1715 ucb::IOErrorCode_CANT_WRITE
,
1718 u
"Cannot remove persistent data of source object!"_ustr
,
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 );
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(
1746 cppu::UnoType
<OUString
>::get(),
1747 beans::PropertyAttribute::BOUND
);
1748 aSeq
.getArray()[ 0 ].Properties
= std::move(aFolderProps
);
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(
1758 cppu::UnoType
<OUString
>::get(),
1759 beans::PropertyAttribute::BOUND
);
1760 aLinkProps
.getArray()[ 1 ] = beans::Property(
1763 cppu::UnoType
<OUString
>::get(),
1764 beans::PropertyAttribute::BOUND
);
1765 aSeq
.getArray()[ 1 ].Properties
= std::move(aLinkProps
);
1771 return uno::Sequence
< ucb::ContentInfo
>( 0 );
1775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */