bump product version to 7.2.5.1
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_content.cxx
blobdcb800ee91c82a2c4b308c920053feb5493288f2
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 *************************************************************************/
27 #include <sal/config.h>
29 #include <string_view>
31 #include <tools/diagnose_ex.h>
32 #include <rtl/ustrbuf.hxx>
33 #include <com/sun/star/beans/IllegalTypeException.hpp>
34 #include <com/sun/star/beans/PropertyAttribute.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/embed/InvalidStorageException.hpp>
37 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
38 #include <com/sun/star/embed/XTransactedObject.hpp>
39 #include <com/sun/star/io/BufferSizeExceededException.hpp>
40 #include <com/sun/star/io/IOException.hpp>
41 #include <com/sun/star/io/NotConnectedException.hpp>
42 #include <com/sun/star/io/XActiveDataSink.hpp>
43 #include <com/sun/star/io/XActiveDataStreamer.hpp>
44 #include <com/sun/star/lang/IllegalAccessException.hpp>
45 #include <com/sun/star/packages/WrongPasswordException.hpp>
46 #include <com/sun/star/task/DocumentPasswordRequest.hpp>
47 #include <com/sun/star/task/XInteractionPassword.hpp>
48 #include <com/sun/star/ucb/CommandFailedException.hpp>
49 #include <com/sun/star/ucb/ContentAction.hpp>
50 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
51 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
52 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
53 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
54 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
55 #include <com/sun/star/ucb/NameClash.hpp>
56 #include <com/sun/star/ucb/NameClashException.hpp>
57 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
58 #include <com/sun/star/ucb/OpenMode.hpp>
59 #include <com/sun/star/ucb/TransferInfo.hpp>
60 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
61 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
62 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
63 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
64 #include <com/sun/star/ucb/XCommandInfo.hpp>
65 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
67 #include <comphelper/propertysequence.hxx>
68 #include <cppuhelper/queryinterface.hxx>
69 #include <ucbhelper/cancelcommandexecution.hxx>
70 #include <ucbhelper/contentidentifier.hxx>
71 #include <ucbhelper/propertyvalueset.hxx>
72 #include <ucbhelper/macros.hxx>
74 #include "tdoc_content.hxx"
75 #include "tdoc_resultset.hxx"
76 #include "tdoc_passwordrequest.hxx"
78 #include "../inc/urihelper.hxx"
80 using namespace com::sun::star;
81 using namespace tdoc_ucp;
84 static ContentType lcl_getContentType( std::u16string_view rType )
86 if ( rType == TDOC_ROOT_CONTENT_TYPE )
87 return ROOT;
88 else if ( rType == TDOC_DOCUMENT_CONTENT_TYPE )
89 return DOCUMENT;
90 else if ( rType == TDOC_FOLDER_CONTENT_TYPE )
91 return FOLDER;
92 else if ( rType == TDOC_STREAM_CONTENT_TYPE )
93 return STREAM;
94 else
96 OSL_FAIL( "Content::Content - unsupported content type string" );
97 return STREAM;
102 // Content Implementation.
105 // static ( "virtual" ctor )
106 rtl::Reference<Content> Content::create(
107 const uno::Reference< uno::XComponentContext >& rxContext,
108 ContentProvider* pProvider,
109 const uno::Reference< ucb::XContentIdentifier >& Identifier )
111 // Fail, if resource does not exist.
112 ContentProperties aProps;
113 if ( !Content::loadData( pProvider,
114 Uri( Identifier->getContentIdentifier() ),
115 aProps ) )
116 return nullptr;
118 return new Content( rxContext, pProvider, Identifier, aProps );
122 // static ( "virtual" ctor )
123 rtl::Reference<Content> Content::create(
124 const uno::Reference< uno::XComponentContext >& rxContext,
125 ContentProvider* pProvider,
126 const uno::Reference< ucb::XContentIdentifier >& Identifier,
127 const ucb::ContentInfo& Info )
129 if ( Info.Type.isEmpty() )
130 return nullptr;
132 if ( Info.Type != TDOC_FOLDER_CONTENT_TYPE && Info.Type != TDOC_STREAM_CONTENT_TYPE )
134 OSL_FAIL( "Content::create - unsupported content type!" );
135 return nullptr;
138 return new Content( rxContext, pProvider, Identifier, Info );
142 Content::Content(
143 const uno::Reference< uno::XComponentContext > & rxContext,
144 ContentProvider * pProvider,
145 const uno::Reference< ucb::XContentIdentifier > & Identifier,
146 const ContentProperties & rProps )
147 : ContentImplHelper( rxContext, pProvider, Identifier ),
148 m_aProps( rProps ),
149 m_eState( PERSISTENT ),
150 m_pProvider( pProvider )
155 // ctor for a content just created via XContentCreator::createNewContent()
156 Content::Content(
157 const uno::Reference< uno::XComponentContext >& rxContext,
158 ContentProvider* pProvider,
159 const uno::Reference< ucb::XContentIdentifier >& Identifier,
160 const ucb::ContentInfo& Info )
161 : ContentImplHelper( rxContext, pProvider, Identifier ),
162 m_aProps( lcl_getContentType( Info.Type ), OUString() ), // no Title (yet)
163 m_eState( TRANSIENT ),
164 m_pProvider( pProvider )
169 // virtual
170 Content::~Content()
175 // XInterface methods.
178 // virtual
179 void SAL_CALL Content::acquire()
180 noexcept
182 ContentImplHelper::acquire();
186 // virtual
187 void SAL_CALL Content::release()
188 noexcept
190 ContentImplHelper::release();
194 // virtual
195 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
197 uno::Any aRet = ContentImplHelper::queryInterface( rType );
199 if ( !aRet.hasValue() )
201 aRet = cppu::queryInterface(
202 rType, static_cast< ucb::XContentCreator * >( this ) );
203 if ( aRet.hasValue() )
205 if ( !m_aProps.isContentCreator() )
206 return uno::Any();
210 return aRet;
214 // XTypeProvider methods.
217 XTYPEPROVIDER_COMMON_IMPL( Content );
220 // virtual
221 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
223 if ( m_aProps.isContentCreator() )
225 static cppu::OTypeCollection s_aFolderTypes(
226 CPPU_TYPE_REF( lang::XTypeProvider ),
227 CPPU_TYPE_REF( lang::XServiceInfo ),
228 CPPU_TYPE_REF( lang::XComponent ),
229 CPPU_TYPE_REF( ucb::XContent ),
230 CPPU_TYPE_REF( ucb::XCommandProcessor ),
231 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
232 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
233 CPPU_TYPE_REF( beans::XPropertyContainer ),
234 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
235 CPPU_TYPE_REF( container::XChild ),
236 CPPU_TYPE_REF( ucb::XContentCreator ) );
238 return s_aFolderTypes.getTypes();
240 else
242 static cppu::OTypeCollection s_aDocumentTypes(
243 CPPU_TYPE_REF( lang::XTypeProvider ),
244 CPPU_TYPE_REF( lang::XServiceInfo ),
245 CPPU_TYPE_REF( lang::XComponent ),
246 CPPU_TYPE_REF( ucb::XContent ),
247 CPPU_TYPE_REF( ucb::XCommandProcessor ),
248 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
249 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
250 CPPU_TYPE_REF( beans::XPropertyContainer ),
251 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
252 CPPU_TYPE_REF( container::XChild ) );
254 return s_aDocumentTypes.getTypes();
259 // XServiceInfo methods.
262 // virtual
263 OUString SAL_CALL Content::getImplementationName()
265 return "com.sun.star.comp.ucb.TransientDocumentsContent";
269 // virtual
270 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
272 osl::Guard< osl::Mutex > aGuard( m_aMutex );
274 uno::Sequence< OUString > aSNS( 1 );
276 if ( m_aProps.getType() == STREAM )
277 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsStreamContent";
278 else if ( m_aProps.getType() == FOLDER )
279 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsFolderContent";
280 else if ( m_aProps.getType() == DOCUMENT )
281 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsDocumentContent";
282 else
283 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsRootContent";
285 return aSNS;
289 // XContent methods.
292 // virtual
293 OUString SAL_CALL Content::getContentType()
295 osl::Guard< osl::Mutex > aGuard( m_aMutex );
296 return m_aProps.getContentType();
300 // virtual
301 uno::Reference< ucb::XContentIdentifier > SAL_CALL
302 Content::getIdentifier()
305 osl::Guard< osl::Mutex > aGuard( m_aMutex );
307 // Transient?
308 if ( m_eState == TRANSIENT )
310 // Transient contents have no identifier.
311 return uno::Reference< ucb::XContentIdentifier >();
314 return ContentImplHelper::getIdentifier();
318 // XCommandProcessor methods.
321 // virtual
322 uno::Any SAL_CALL Content::execute(
323 const ucb::Command& aCommand,
324 sal_Int32 /*CommandId*/,
325 const uno::Reference< ucb::XCommandEnvironment >& Environment )
327 uno::Any aRet;
329 if ( aCommand.Name == "getPropertyValues" )
332 // getPropertyValues
335 uno::Sequence< beans::Property > Properties;
336 if ( !( aCommand.Argument >>= Properties ) )
338 ucbhelper::cancelCommandExecution(
339 uno::makeAny( lang::IllegalArgumentException(
340 "Wrong argument type!",
341 static_cast< cppu::OWeakObject * >( this ),
342 -1 ) ),
343 Environment );
344 // Unreachable
347 aRet <<= getPropertyValues( Properties );
349 else if ( aCommand.Name == "setPropertyValues" )
352 // setPropertyValues
355 uno::Sequence< beans::PropertyValue > aProperties;
356 if ( !( aCommand.Argument >>= aProperties ) )
358 ucbhelper::cancelCommandExecution(
359 uno::makeAny( lang::IllegalArgumentException(
360 "Wrong argument type!",
361 static_cast< cppu::OWeakObject * >( this ),
362 -1 ) ),
363 Environment );
364 // Unreachable
367 if ( !aProperties.hasElements() )
369 ucbhelper::cancelCommandExecution(
370 uno::makeAny( lang::IllegalArgumentException(
371 "No properties!",
372 static_cast< cppu::OWeakObject * >( this ),
373 -1 ) ),
374 Environment );
375 // Unreachable
378 aRet <<= setPropertyValues( aProperties, Environment );
380 else if ( aCommand.Name == "getPropertySetInfo" )
383 // getPropertySetInfo
386 aRet <<= getPropertySetInfo( Environment );
388 else if ( aCommand.Name == "getCommandInfo" )
391 // getCommandInfo
394 aRet <<= getCommandInfo( Environment );
396 else if ( aCommand.Name == "open" )
399 // open
402 ucb::OpenCommandArgument2 aOpenCommand;
403 if ( !( aCommand.Argument >>= aOpenCommand ) )
405 ucbhelper::cancelCommandExecution(
406 uno::makeAny( lang::IllegalArgumentException(
407 "Wrong argument type!",
408 static_cast< cppu::OWeakObject * >( this ),
409 -1 ) ),
410 Environment );
411 // Unreachable
414 aRet = open( aOpenCommand, Environment );
416 else if ( aCommand.Name == "insert" )
419 // insert ( Supported by folders and streams only )
422 ContentType eType = m_aProps.getType();
423 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
425 ucbhelper::cancelCommandExecution(
426 uno::makeAny( ucb::UnsupportedCommandException(
427 "insert command only supported by "
428 "folders and streams!",
429 static_cast< cppu::OWeakObject * >( this ) ) ),
430 Environment );
431 // Unreachable
434 if ( eType == STREAM )
436 Uri aUri( m_xIdentifier->getContentIdentifier() );
437 Uri aParentUri( aUri.getParentUri() );
438 if ( aParentUri.isDocument() )
440 ucbhelper::cancelCommandExecution(
441 uno::makeAny( ucb::UnsupportedCommandException(
442 "insert command not supported by "
443 "streams that are direct children "
444 "of document root!",
445 static_cast< cppu::OWeakObject * >(
446 this ) ) ),
447 Environment );
448 // Unreachable
452 ucb::InsertCommandArgument aArg;
453 if ( !( aCommand.Argument >>= aArg ) )
455 ucbhelper::cancelCommandExecution(
456 uno::makeAny( lang::IllegalArgumentException(
457 "Wrong argument type!",
458 static_cast< cppu::OWeakObject * >( this ),
459 -1 ) ),
460 Environment );
461 // Unreachable
464 sal_Int32 nNameClash = aArg.ReplaceExisting
465 ? ucb::NameClash::OVERWRITE
466 : ucb::NameClash::ERROR;
467 insert( aArg.Data, nNameClash, Environment );
469 else if ( aCommand.Name == "delete" )
472 // delete ( Supported by folders and streams only )
476 osl::MutexGuard aGuard( m_aMutex );
478 ContentType eType = m_aProps.getType();
479 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
481 ucbhelper::cancelCommandExecution(
482 uno::makeAny( ucb::UnsupportedCommandException(
483 "delete command only supported by "
484 "folders and streams!",
485 static_cast< cppu::OWeakObject * >(
486 this ) ) ),
487 Environment );
488 // Unreachable
492 bool bDeletePhysical = false;
493 aCommand.Argument >>= bDeletePhysical;
494 destroy( bDeletePhysical, Environment );
496 // Remove own and all children's persistent data.
497 if ( !removeData() )
499 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
501 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
502 }));
503 ucbhelper::cancelCommandExecution(
504 ucb::IOErrorCode_CANT_WRITE,
505 aArgs,
506 Environment,
507 "Cannot remove persistent data!",
508 this );
509 // Unreachable
512 // Remove own and all children's Additional Core Properties.
513 removeAdditionalPropertySet();
515 else if ( aCommand.Name == "transfer" )
518 // transfer ( Supported by document and folders only )
522 osl::MutexGuard aGuard( m_aMutex );
524 ContentType eType = m_aProps.getType();
525 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
527 ucbhelper::cancelCommandExecution(
528 uno::makeAny( ucb::UnsupportedCommandException(
529 "transfer command only supported "
530 "by folders and documents!",
531 static_cast< cppu::OWeakObject * >(
532 this ) ) ),
533 Environment );
534 // Unreachable
538 ucb::TransferInfo aInfo;
539 if ( !( aCommand.Argument >>= aInfo ) )
541 OSL_FAIL( "Wrong argument type!" );
542 ucbhelper::cancelCommandExecution(
543 uno::makeAny( lang::IllegalArgumentException(
544 "Wrong argument type!",
545 static_cast< cppu::OWeakObject * >( this ),
546 -1 ) ),
547 Environment );
548 // Unreachable
551 transfer( aInfo, Environment );
553 else if ( aCommand.Name == "createNewContent" )
556 // createNewContent ( Supported by document and folders only )
560 osl::MutexGuard aGuard( m_aMutex );
562 ContentType eType = m_aProps.getType();
563 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
565 ucbhelper::cancelCommandExecution(
566 uno::makeAny( ucb::UnsupportedCommandException(
567 "createNewContent command only "
568 "supported by folders and "
569 "documents!",
570 static_cast< cppu::OWeakObject * >(
571 this ) ) ),
572 Environment );
573 // Unreachable
577 ucb::ContentInfo aInfo;
578 if ( !( aCommand.Argument >>= aInfo ) )
580 OSL_FAIL( "Wrong argument type!" );
581 ucbhelper::cancelCommandExecution(
582 uno::makeAny( lang::IllegalArgumentException(
583 "Wrong argument type!",
584 static_cast< cppu::OWeakObject * >( this ),
585 -1 ) ),
586 Environment );
587 // Unreachable
590 aRet <<= createNewContent( aInfo );
592 else
595 // Unsupported command
598 ucbhelper::cancelCommandExecution(
599 uno::makeAny( ucb::UnsupportedCommandException(
600 OUString(),
601 static_cast< cppu::OWeakObject * >( this ) ) ),
602 Environment );
603 // Unreachable
606 return aRet;
610 // virtual
611 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
616 // XContentCreator methods.
619 // virtual
620 uno::Sequence< ucb::ContentInfo > SAL_CALL
621 Content::queryCreatableContentsInfo()
623 return m_aProps.getCreatableContentsInfo();
627 // virtual
628 uno::Reference< ucb::XContent > SAL_CALL
629 Content::createNewContent( const ucb::ContentInfo& Info )
631 if ( m_aProps.isContentCreator() )
633 osl::Guard< osl::Mutex > aGuard( m_aMutex );
635 if ( Info.Type.isEmpty() )
636 return uno::Reference< ucb::XContent >();
638 bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
640 // streams cannot be created as direct children of document root
641 if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
643 OSL_FAIL( "Content::createNewContent - streams cannot be "
644 "created as direct children of document root!" );
645 return uno::Reference< ucb::XContent >();
647 if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
649 OSL_FAIL( "Content::createNewContent - unsupported type!" );
650 return uno::Reference< ucb::XContent >();
653 OUString aURL = m_xIdentifier->getContentIdentifier();
655 OSL_ENSURE( !aURL.isEmpty(),
656 "Content::createNewContent - empty identifier!" );
658 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
659 aURL += "/";
661 if ( bCreateFolder )
662 aURL += "New_Folder";
663 else
664 aURL += "New_Stream";
666 uno::Reference< ucb::XContentIdentifier > xId
667 = new ::ucbhelper::ContentIdentifier( aURL );
669 return create( m_xContext, m_pProvider, xId, Info );
671 else
673 OSL_FAIL( "createNewContent called on non-contentcreator object!" );
674 return uno::Reference< ucb::XContent >();
679 // virtual
680 OUString Content::getParentURL()
682 osl::Guard< osl::Mutex > aGuard( m_aMutex );
683 Uri aUri( m_xIdentifier->getContentIdentifier() );
684 return aUri.getParentUri();
688 uno::Reference< ucb::XContentIdentifier >
689 Content::makeNewIdentifier( const OUString& rTitle )
691 osl::Guard< osl::Mutex > aGuard( m_aMutex );
693 // Assemble new content identifier...
694 Uri aUri( m_xIdentifier->getContentIdentifier() );
695 OUStringBuffer aNewURL = aUri.getParentUri();
696 aNewURL.append( ::ucb_impl::urihelper::encodeSegment( rTitle ) );
698 return
699 uno::Reference< ucb::XContentIdentifier >(
700 new ::ucbhelper::ContentIdentifier( aNewURL.makeStringAndClear() ) );
704 void Content::queryChildren( ContentRefList& rChildren )
706 osl::Guard< osl::Mutex > aGuard( m_aMutex );
708 // Only folders (root, documents, folders) have children.
709 if ( !m_aProps.getIsFolder() )
710 return;
712 // Obtain a list with a snapshot of all currently instantiated contents
713 // from provider and extract the contents which are direct children
714 // of this content.
716 ::ucbhelper::ContentRefList aAllContents;
717 m_xProvider->queryExistingContents( aAllContents );
719 OUString aURL = m_xIdentifier->getContentIdentifier();
720 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
722 if ( nURLPos != ( aURL.getLength() - 1 ) )
724 // No trailing slash found. Append.
725 aURL += "/";
728 sal_Int32 nLen = aURL.getLength();
730 for ( const auto& rContent : aAllContents )
732 ::ucbhelper::ContentImplHelperRef xChild = rContent;
733 OUString aChildURL
734 = xChild->getIdentifier()->getContentIdentifier();
736 // Is aURL a prefix of aChildURL?
737 if ( ( aChildURL.getLength() > nLen ) &&
738 ( aChildURL.startsWith( aURL ) ) )
740 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
742 if ( ( nPos == -1 ) ||
743 ( nPos == ( aChildURL.getLength() - 1 ) ) )
745 // No further slashes / only a final slash. It's a child!
746 rChildren.emplace_back(
747 static_cast< Content * >( xChild.get() ) );
754 bool Content::exchangeIdentity(
755 const uno::Reference< ucb::XContentIdentifier >& xNewId )
757 if ( !xNewId.is() )
758 return false;
760 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
762 uno::Reference< ucb::XContent > xThis = this;
764 // Already persistent?
765 if ( m_eState != PERSISTENT )
767 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
768 return false;
771 // Only folders and streams can be renamed -> exchange identity.
772 ContentType eType = m_aProps.getType();
773 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
775 OSL_FAIL( "Content::exchangeIdentity - "
776 "Not supported by root or document!" );
777 return false;
780 // Exchange own identity.
782 // Fail, if a content with given id already exists.
783 if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
785 OUString aOldURL = m_xIdentifier->getContentIdentifier();
787 aGuard.clear();
788 if ( exchange( xNewId ) )
790 if ( eType == FOLDER )
792 // Process instantiated children...
794 ContentRefList aChildren;
795 queryChildren( aChildren );
797 for ( const auto& rChild : aChildren )
799 ContentRef xChild = rChild;
801 // Create new content identifier for the child...
802 uno::Reference< ucb::XContentIdentifier > xOldChildId
803 = xChild->getIdentifier();
804 OUString aOldChildURL
805 = xOldChildId->getContentIdentifier();
806 OUString aNewChildURL
807 = aOldChildURL.replaceAt(
809 aOldURL.getLength(),
810 xNewId->getContentIdentifier() );
811 uno::Reference< ucb::XContentIdentifier > xNewChildId
812 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
814 if ( !xChild->exchangeIdentity( xNewChildId ) )
815 return false;
818 return true;
822 OSL_FAIL( "Content::exchangeIdentity - "
823 "Panic! Cannot exchange identity!" );
824 return false;
828 // static
829 uno::Reference< sdbc::XRow > Content::getPropertyValues(
830 const uno::Reference< uno::XComponentContext >& rxContext,
831 const uno::Sequence< beans::Property >& rProperties,
832 ContentProvider* pProvider,
833 const OUString& rContentId )
835 ContentProperties aData;
836 if ( loadData( pProvider, Uri(rContentId), aData ) )
838 return getPropertyValues(
839 rxContext, rProperties, aData, pProvider, rContentId );
841 else
843 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
844 = new ::ucbhelper::PropertyValueSet( rxContext );
846 for ( const beans::Property& rProp : rProperties )
847 xRow->appendVoid( rProp );
849 return xRow;
854 // static
855 uno::Reference< sdbc::XRow > Content::getPropertyValues(
856 const uno::Reference< uno::XComponentContext >& rxContext,
857 const uno::Sequence< beans::Property >& rProperties,
858 const ContentProperties& rData,
859 ContentProvider* pProvider,
860 const OUString& rContentId )
862 // Note: Empty sequence means "get values of all supported properties".
864 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
865 = new ::ucbhelper::PropertyValueSet( rxContext );
867 if ( rProperties.hasElements() )
869 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
870 bool bTriedToGetAdditionalPropSet = false;
872 for ( const beans::Property& rProp : rProperties )
874 // Process Core properties.
876 if ( rProp.Name == "ContentType" )
878 xRow->appendString ( rProp, rData.getContentType() );
880 else if ( rProp.Name == "Title" )
882 xRow->appendString ( rProp, rData.getTitle() );
884 else if ( rProp.Name == "IsDocument" )
886 xRow->appendBoolean( rProp, rData.getIsDocument() );
888 else if ( rProp.Name == "IsFolder" )
890 xRow->appendBoolean( rProp, rData.getIsFolder() );
892 else if ( rProp.Name == "CreatableContentsInfo" )
894 xRow->appendObject(
895 rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
897 else if ( rProp.Name == "Storage" )
899 // Storage is only supported by folders.
900 ContentType eType = rData.getType();
901 if ( eType == FOLDER )
902 xRow->appendObject(
903 rProp,
904 uno::makeAny(
905 pProvider->queryStorageClone( rContentId ) ) );
906 else
907 xRow->appendVoid( rProp );
909 else if ( rProp.Name == "DocumentModel" )
911 // DocumentModel is only supported by documents.
912 ContentType eType = rData.getType();
913 if ( eType == DOCUMENT )
914 xRow->appendObject(
915 rProp,
916 uno::makeAny(
917 pProvider->queryDocumentModel( rContentId ) ) );
918 else
919 xRow->appendVoid( rProp );
921 else
923 // Not a Core Property! Maybe it's an Additional Core Property?!
925 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
927 xAdditionalPropSet =
928 pProvider->getAdditionalPropertySet( rContentId,
929 false );
930 bTriedToGetAdditionalPropSet = true;
933 if ( xAdditionalPropSet.is() )
935 if ( !xRow->appendPropertySetValue(
936 xAdditionalPropSet,
937 rProp ) )
939 // Append empty entry.
940 xRow->appendVoid( rProp );
943 else
945 // Append empty entry.
946 xRow->appendVoid( rProp );
951 else
953 // Append all Core Properties.
954 xRow->appendString (
955 beans::Property( "ContentType",
957 cppu::UnoType<OUString>::get(),
958 beans::PropertyAttribute::BOUND
959 | beans::PropertyAttribute::READONLY ),
960 rData.getContentType() );
962 ContentType eType = rData.getType();
964 xRow->appendString (
965 beans::Property( "Title",
967 cppu::UnoType<OUString>::get(),
968 // Title is read-only for root and documents.
969 beans::PropertyAttribute::BOUND |
970 ( ( eType == ROOT ) || ( eType == DOCUMENT )
971 ? beans::PropertyAttribute::READONLY
972 : 0 ) ),
973 rData.getTitle() );
974 xRow->appendBoolean(
975 beans::Property( "IsDocument",
977 cppu::UnoType<bool>::get(),
978 beans::PropertyAttribute::BOUND
979 | beans::PropertyAttribute::READONLY ),
980 rData.getIsDocument() );
981 xRow->appendBoolean(
982 beans::Property( "IsFolder",
984 cppu::UnoType<bool>::get(),
985 beans::PropertyAttribute::BOUND
986 | beans::PropertyAttribute::READONLY ),
987 rData.getIsFolder() );
988 xRow->appendObject(
989 beans::Property(
990 "CreatableContentsInfo",
992 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
993 beans::PropertyAttribute::BOUND
994 | beans::PropertyAttribute::READONLY ),
995 uno::makeAny( rData.getCreatableContentsInfo() ) );
997 // Storage is only supported by folders.
998 if ( eType == FOLDER )
999 xRow->appendObject(
1000 beans::Property( "Storage",
1002 cppu::UnoType<embed::XStorage>::get(),
1003 beans::PropertyAttribute::BOUND
1004 | beans::PropertyAttribute::READONLY ),
1005 uno::makeAny( pProvider->queryStorageClone( rContentId ) ) );
1007 // DocumentModel is only supported by documents.
1008 if ( eType == DOCUMENT )
1009 xRow->appendObject(
1010 beans::Property( "DocumentModel",
1012 cppu::UnoType<frame::XModel>::get(),
1013 beans::PropertyAttribute::BOUND
1014 | beans::PropertyAttribute::READONLY ),
1015 uno::makeAny(
1016 pProvider->queryDocumentModel( rContentId ) ) );
1018 // Append all Additional Core Properties.
1020 uno::Reference< beans::XPropertySet > xSet =
1021 pProvider->getAdditionalPropertySet( rContentId, false );
1022 xRow->appendPropertySet( xSet );
1025 return xRow;
1029 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1030 const uno::Sequence< beans::Property >& rProperties )
1032 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1033 return getPropertyValues( m_xContext,
1034 rProperties,
1035 m_aProps,
1036 m_pProvider,
1037 m_xIdentifier->getContentIdentifier() );
1041 uno::Sequence< uno::Any > Content::setPropertyValues(
1042 const uno::Sequence< beans::PropertyValue >& rValues,
1043 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1045 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1047 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1048 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1049 sal_Int32 nChanged = 0;
1051 beans::PropertyChangeEvent aEvent;
1052 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1053 aEvent.Further = false;
1054 // aEvent.PropertyName =
1055 aEvent.PropertyHandle = -1;
1056 // aEvent.OldValue =
1057 // aEvent.NewValue =
1059 const beans::PropertyValue* pValues = rValues.getConstArray();
1060 sal_Int32 nCount = rValues.getLength();
1062 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1063 bool bTriedToGetAdditionalPropSet = false;
1065 bool bExchange = false;
1066 OUString aOldTitle;
1067 sal_Int32 nTitlePos = -1;
1069 for ( sal_Int32 n = 0; n < nCount; ++n )
1071 const beans::PropertyValue& rValue = pValues[ n ];
1073 if ( rValue.Name == "ContentType" )
1075 // Read-only property!
1076 aRet[ n ] <<= lang::IllegalAccessException(
1077 "Property is read-only!",
1078 static_cast< cppu::OWeakObject * >( this ) );
1080 else if ( rValue.Name == "IsDocument" )
1082 // Read-only property!
1083 aRet[ n ] <<= lang::IllegalAccessException(
1084 "Property is read-only!",
1085 static_cast< cppu::OWeakObject * >( this ) );
1087 else if ( rValue.Name == "IsFolder" )
1089 // Read-only property!
1090 aRet[ n ] <<= lang::IllegalAccessException(
1091 "Property is read-only!",
1092 static_cast< cppu::OWeakObject * >( this ) );
1094 else if ( rValue.Name == "CreatableContentsInfo" )
1096 // Read-only property!
1097 aRet[ n ] <<= lang::IllegalAccessException(
1098 "Property is read-only!",
1099 static_cast< cppu::OWeakObject * >( this ) );
1101 else if ( rValue.Name == "Title" )
1103 // Title is read-only for root and documents.
1104 ContentType eType = m_aProps.getType();
1105 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1107 aRet[ n ] <<= lang::IllegalAccessException(
1108 "Property is read-only!",
1109 static_cast< cppu::OWeakObject * >( this ) );
1111 else
1113 OUString aNewValue;
1114 if ( rValue.Value >>= aNewValue )
1116 // No empty titles!
1117 if ( !aNewValue.isEmpty() )
1119 if ( aNewValue != m_aProps.getTitle() )
1121 // modified title -> modified URL -> exchange !
1122 if ( m_eState == PERSISTENT )
1123 bExchange = true;
1125 aOldTitle = m_aProps.getTitle();
1126 m_aProps.setTitle( aNewValue );
1128 // property change event will be sent later...
1130 // remember position within sequence of values
1131 // (for error handling).
1132 nTitlePos = n;
1135 else
1137 aRet[ n ] <<= lang::IllegalArgumentException(
1138 "Empty Title not allowed!",
1139 static_cast< cppu::OWeakObject * >( this ),
1140 -1 );
1143 else
1145 aRet[ n ] <<= beans::IllegalTypeException(
1146 "Title Property value has wrong type!",
1147 static_cast< cppu::OWeakObject * >( this ) );
1151 else if ( rValue.Name == "Storage" )
1153 ContentType eType = m_aProps.getType();
1154 if ( eType == FOLDER )
1156 aRet[ n ] <<= lang::IllegalAccessException(
1157 "Property is read-only!",
1158 static_cast< cppu::OWeakObject * >( this ) );
1160 else
1162 // Storage is only supported by folders.
1163 aRet[ n ] <<= beans::UnknownPropertyException(
1164 "Storage property only supported by folders",
1165 static_cast< cppu::OWeakObject * >( this ) );
1168 else if ( rValue.Name == "DocumentModel" )
1170 ContentType eType = m_aProps.getType();
1171 if ( eType == DOCUMENT )
1173 aRet[ n ] <<= lang::IllegalAccessException(
1174 "Property is read-only!",
1175 static_cast< cppu::OWeakObject * >( this ) );
1177 else
1179 // Storage is only supported by folders.
1180 aRet[ n ] <<= beans::UnknownPropertyException(
1181 "DocumentModel property only supported by documents",
1182 static_cast< cppu::OWeakObject * >( this ) );
1185 else
1187 // Not a Core Property! Maybe it's an Additional Core Property?!
1189 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1191 xAdditionalPropSet = getAdditionalPropertySet( false );
1192 bTriedToGetAdditionalPropSet = true;
1195 if ( xAdditionalPropSet.is() )
1199 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1200 rValue.Name );
1201 if ( aOldValue != rValue.Value )
1203 xAdditionalPropSet->setPropertyValue(
1204 rValue.Name, rValue.Value );
1206 aEvent.PropertyName = rValue.Name;
1207 aEvent.OldValue = aOldValue;
1208 aEvent.NewValue = rValue.Value;
1210 aChanges.getArray()[ nChanged ] = aEvent;
1211 nChanged++;
1214 catch ( beans::UnknownPropertyException const & e )
1216 aRet[ n ] <<= e;
1218 catch ( lang::WrappedTargetException const & e )
1220 aRet[ n ] <<= e;
1222 catch ( beans::PropertyVetoException const & e )
1224 aRet[ n ] <<= e;
1226 catch ( lang::IllegalArgumentException const & e )
1228 aRet[ n ] <<= e;
1231 else
1233 aRet[ n ] <<= uno::Exception(
1234 "No property set for storing the value!",
1235 static_cast< cppu::OWeakObject * >( this ) );
1240 if ( bExchange )
1242 uno::Reference< ucb::XContentIdentifier > xOldId
1243 = m_xIdentifier;
1244 uno::Reference< ucb::XContentIdentifier > xNewId
1245 = makeNewIdentifier( m_aProps.getTitle() );
1247 aGuard.clear();
1248 if ( exchangeIdentity( xNewId ) )
1250 // Adapt persistent data.
1251 renameData( xOldId, xNewId );
1253 // Adapt Additional Core Properties.
1254 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1255 xNewId->getContentIdentifier() );
1257 else
1259 // Roll-back.
1260 m_aProps.setTitle( aOldTitle );
1261 aOldTitle.clear();
1263 // Set error .
1264 aRet[ nTitlePos ] <<= uno::Exception(
1265 "Exchange failed!",
1266 static_cast< cppu::OWeakObject * >( this ) );
1270 if ( !aOldTitle.isEmpty() )
1272 aEvent.PropertyName = "Title";
1273 aEvent.OldValue <<= aOldTitle;
1274 aEvent.NewValue <<= m_aProps.getTitle();
1276 aChanges.getArray()[ nChanged ] = aEvent;
1277 nChanged++;
1280 if ( nChanged > 0 )
1282 // Save changes, if content was already made persistent.
1283 if ( !bExchange && ( m_eState == PERSISTENT ) )
1285 if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1287 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1289 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1290 }));
1291 ucbhelper::cancelCommandExecution(
1292 ucb::IOErrorCode_CANT_WRITE,
1293 aArgs,
1294 xEnv,
1295 "Cannot store persistent data!",
1296 this );
1297 // Unreachable
1301 aChanges.realloc( nChanged );
1303 aGuard.clear();
1304 notifyPropertiesChange( aChanges );
1307 return aRet;
1311 uno::Any Content::open(
1312 const ucb::OpenCommandArgument2& rArg,
1313 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1315 if ( rArg.Mode == ucb::OpenMode::ALL ||
1316 rArg.Mode == ucb::OpenMode::FOLDERS ||
1317 rArg.Mode == ucb::OpenMode::DOCUMENTS )
1320 // open command for a folder content
1323 uno::Reference< ucb::XDynamicResultSet > xSet
1324 = new DynamicResultSet( m_xContext, this, rArg );
1325 return uno::makeAny( xSet );
1327 else
1330 // open command for a document content
1333 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1334 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1336 // Currently(?) unsupported.
1337 ucbhelper::cancelCommandExecution(
1338 uno::makeAny( ucb::UnsupportedOpenModeException(
1339 OUString(),
1340 static_cast< cppu::OWeakObject * >( this ),
1341 sal_Int16( rArg.Mode ) ) ),
1342 xEnv );
1343 // Unreachable
1346 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1348 uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1349 rArg.Sink, uno::UNO_QUERY );
1350 if ( xDataStreamer.is() )
1352 // May throw CommandFailedException, DocumentPasswordRequest!
1353 uno::Reference< io::XStream > xStream = getStream( xEnv );
1354 if ( !xStream.is() )
1356 // No interaction if we are not persistent!
1357 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1359 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1360 }));
1361 ucbhelper::cancelCommandExecution(
1362 ucb::IOErrorCode_CANT_READ,
1363 aArgs,
1364 m_eState == PERSISTENT
1365 ? xEnv
1366 : uno::Reference< ucb::XCommandEnvironment >(),
1367 "Got no data stream!",
1368 this );
1369 // Unreachable
1372 // Done.
1373 xDataStreamer->setStream( xStream );
1375 else
1377 uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1378 if ( xOut.is() )
1380 // PUSH: write data into xOut
1382 // May throw CommandFailedException, DocumentPasswordRequest!
1383 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1384 if ( !xIn.is() )
1386 // No interaction if we are not persistent!
1387 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1389 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1390 }));
1391 ucbhelper::cancelCommandExecution(
1392 ucb::IOErrorCode_CANT_READ,
1393 aArgs,
1394 m_eState == PERSISTENT
1395 ? xEnv
1396 : uno::Reference< ucb::XCommandEnvironment >(),
1397 "Got no data stream!",
1398 this );
1399 // Unreachable
1404 uno::Sequence< sal_Int8 > aBuffer;
1406 while (true)
1408 sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1409 if (!nRead)
1410 break;
1411 aBuffer.realloc( nRead );
1412 xOut->writeBytes( aBuffer );
1415 xOut->closeOutput();
1417 catch ( io::NotConnectedException const & )
1419 // closeOutput, readSomeBytes, writeBytes
1421 catch ( io::BufferSizeExceededException const & )
1423 // closeOutput, readSomeBytes, writeBytes
1425 catch ( io::IOException const & )
1427 // closeOutput, readSomeBytes, writeBytes
1430 else
1432 uno::Reference< io::XActiveDataSink > xDataSink(
1433 rArg.Sink, uno::UNO_QUERY );
1434 if ( xDataSink.is() )
1436 // PULL: wait for client read
1438 // May throw CommandFailedException, DocumentPasswordRequest!
1439 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1440 if ( !xIn.is() )
1442 // No interaction if we are not persistent!
1443 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1445 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1446 }));
1447 ucbhelper::cancelCommandExecution(
1448 ucb::IOErrorCode_CANT_READ,
1449 aArgs,
1450 m_eState == PERSISTENT
1451 ? xEnv
1452 : uno::Reference<
1453 ucb::XCommandEnvironment >(),
1454 "Got no data stream!",
1455 this );
1456 // Unreachable
1459 // Done.
1460 xDataSink->setInputStream( xIn );
1462 else
1464 ucbhelper::cancelCommandExecution(
1465 uno::makeAny(
1466 ucb::UnsupportedDataSinkException(
1467 OUString(),
1468 static_cast< cppu::OWeakObject * >( this ),
1469 rArg.Sink ) ),
1470 xEnv );
1471 // Unreachable
1477 return uno::Any();
1481 void Content::insert( const uno::Reference< io::XInputStream >& xData,
1482 sal_Int32 nNameClashResolve,
1483 const uno::Reference<
1484 ucb::XCommandEnvironment > & xEnv )
1486 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1488 ContentType eType = m_aProps.getType();
1490 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1491 "insert command only supported by streams and folders!" );
1493 Uri aUri( m_xIdentifier->getContentIdentifier() );
1495 #if OSL_DEBUG_LEVEL > 0
1496 if ( eType == STREAM )
1498 Uri aParentUri( aUri.getParentUri() );
1499 OSL_ENSURE( !aParentUri.isDocument(),
1500 "insert command not supported by streams that are direct "
1501 "children of document root!" );
1503 #endif
1505 // Check, if all required properties were set.
1506 if ( eType == FOLDER )
1508 // Required: Title
1510 if ( m_aProps.getTitle().isEmpty() )
1511 m_aProps.setTitle( aUri.getDecodedName() );
1513 else // stream
1515 // Required: data
1517 if ( !xData.is() )
1519 ucbhelper::cancelCommandExecution(
1520 uno::makeAny( ucb::MissingInputStreamException(
1521 OUString(),
1522 static_cast< cppu::OWeakObject * >( this ) ) ),
1523 xEnv );
1524 // Unreachable
1527 // Required: Title
1529 if ( m_aProps.getTitle().isEmpty() )
1530 m_aProps.setTitle( aUri.getDecodedName() );
1533 OUStringBuffer aNewURL = aUri.getParentUri();
1534 aNewURL.append( m_aProps.getTitle() );
1535 Uri aNewUri( aNewURL.makeStringAndClear() );
1537 // Handle possible name clash...
1538 switch ( nNameClashResolve )
1540 // fail.
1541 case ucb::NameClash::ERROR:
1542 if ( hasData( aNewUri ) )
1544 ucbhelper::cancelCommandExecution(
1545 uno::makeAny( ucb::NameClashException(
1546 OUString(),
1547 static_cast< cppu::OWeakObject * >( this ),
1548 task::InteractionClassification_ERROR,
1549 m_aProps.getTitle() ) ),
1550 xEnv );
1551 // Unreachable
1553 break;
1555 // replace (possibly) existing object.
1556 case ucb::NameClash::OVERWRITE:
1557 break;
1559 // "invent" a new valid title.
1560 case ucb::NameClash::RENAME:
1561 if ( hasData( aNewUri ) )
1563 sal_Int32 nTry = 0;
1567 OUStringBuffer aNew = aNewUri.getUri();
1568 aNew.append( "_" );
1569 aNew.append( ++nTry );
1570 aNewUri.setUri( aNew.makeStringAndClear() );
1572 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1574 if ( nTry == 1000 )
1576 ucbhelper::cancelCommandExecution(
1577 uno::makeAny(
1578 ucb::UnsupportedNameClashException(
1579 "Unable to resolve name clash!",
1580 static_cast< cppu::OWeakObject * >( this ),
1581 nNameClashResolve ) ),
1582 xEnv );
1583 // Unreachable
1585 else
1587 OUStringBuffer aNewTitle = m_aProps.getTitle();
1588 aNewTitle.append( "_" );
1589 aNewTitle.append( ++nTry );
1590 m_aProps.setTitle( aNewTitle.makeStringAndClear() );
1593 break;
1595 case ucb::NameClash::KEEP: // deprecated
1596 case ucb::NameClash::ASK:
1597 default:
1598 if ( hasData( aNewUri ) )
1600 ucbhelper::cancelCommandExecution(
1601 uno::makeAny(
1602 ucb::UnsupportedNameClashException(
1603 OUString(),
1604 static_cast< cppu::OWeakObject * >( this ),
1605 nNameClashResolve ) ),
1606 xEnv );
1607 // Unreachable
1609 break;
1612 // Identifier changed?
1613 bool bNewId = ( aUri != aNewUri );
1615 if ( bNewId )
1617 m_xIdentifier
1618 = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1621 if ( !storeData( xData, xEnv ) )
1623 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1625 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1626 }));
1627 ucbhelper::cancelCommandExecution(
1628 ucb::IOErrorCode_CANT_WRITE,
1629 aArgs,
1630 xEnv,
1631 "Cannot store persistent data!",
1632 this );
1633 // Unreachable
1636 m_eState = PERSISTENT;
1638 if ( bNewId )
1640 //loadData( m_pProvider, m_aUri, m_aProps );
1642 aGuard.clear();
1643 inserted();
1648 void Content::destroy( bool bDeletePhysical,
1649 const uno::Reference<
1650 ucb::XCommandEnvironment > & xEnv )
1652 // @@@ take care about bDeletePhysical -> trashcan support
1654 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1656 ContentType eType = m_aProps.getType();
1658 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1659 "delete command only supported by streams and folders!" );
1661 uno::Reference< ucb::XContent > xThis = this;
1663 // Persistent?
1664 if ( m_eState != PERSISTENT )
1666 ucbhelper::cancelCommandExecution(
1667 uno::makeAny( ucb::UnsupportedCommandException(
1668 "Not persistent!",
1669 static_cast< cppu::OWeakObject * >( this ) ) ),
1670 xEnv );
1671 // Unreachable
1674 m_eState = DEAD;
1676 aGuard.clear();
1677 deleted();
1679 if ( eType == FOLDER )
1681 // Process instantiated children...
1683 ContentRefList aChildren;
1684 queryChildren( aChildren );
1686 for ( auto& rChild : aChildren )
1688 rChild->destroy( bDeletePhysical, xEnv );
1694 void Content::notifyDocumentClosed()
1696 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1698 m_eState = DEAD;
1700 // @@@ anything else to reset or such?
1702 // callback follows!
1703 aGuard.clear();
1705 // Propagate destruction to content event listeners
1706 // Remove this from provider's content list.
1707 deleted();
1711 uno::Reference< ucb::XContent >
1712 Content::queryChildContent( const OUString & rRelativeChildUri )
1714 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1716 const OUString aMyId = getIdentifier()->getContentIdentifier();
1717 OUStringBuffer aBuf( aMyId );
1718 if ( !aMyId.endsWith("/") )
1719 aBuf.append( "/" );
1720 if ( !rRelativeChildUri.startsWith("/") )
1721 aBuf.append( rRelativeChildUri );
1722 else
1723 aBuf.append( rRelativeChildUri.subView(1) );
1725 uno::Reference< ucb::XContentIdentifier > xChildId
1726 = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1728 uno::Reference< ucb::XContent > xChild;
1731 xChild = m_pProvider->queryContent( xChildId );
1733 catch ( ucb::IllegalIdentifierException const & )
1735 // handled below.
1738 OSL_ENSURE( xChild.is(),
1739 "Content::queryChildContent - unable to create child content!" );
1740 return xChild;
1744 void Content::notifyChildRemoved( const OUString & rRelativeChildUri )
1746 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1748 // Ugly! Need to create child content object, just to fill event properly.
1749 uno::Reference< ucb::XContent > xChild
1750 = queryChildContent( rRelativeChildUri );
1752 if ( !xChild.is() )
1753 return;
1755 // callback follows!
1756 aGuard.clear();
1758 // Notify "REMOVED" event.
1759 ucb::ContentEvent aEvt(
1760 static_cast< cppu::OWeakObject * >( this ),
1761 ucb::ContentAction::REMOVED,
1762 xChild,
1763 getIdentifier() );
1764 notifyContentEvent( aEvt );
1768 void Content::notifyChildInserted( const OUString & rRelativeChildUri )
1770 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1772 // Ugly! Need to create child content object, just to fill event properly.
1773 uno::Reference< ucb::XContent > xChild
1774 = queryChildContent( rRelativeChildUri );
1776 if ( !xChild.is() )
1777 return;
1779 // callback follows!
1780 aGuard.clear();
1782 // Notify "INSERTED" event.
1783 ucb::ContentEvent aEvt(
1784 static_cast< cppu::OWeakObject * >( this ),
1785 ucb::ContentAction::INSERTED,
1786 xChild,
1787 getIdentifier() );
1788 notifyContentEvent( aEvt );
1792 void Content::transfer(
1793 const ucb::TransferInfo& rInfo,
1794 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1796 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1798 // Persistent?
1799 if ( m_eState != PERSISTENT )
1801 ucbhelper::cancelCommandExecution(
1802 uno::makeAny( ucb::UnsupportedCommandException(
1803 "Not persistent!",
1804 static_cast< cppu::OWeakObject * >( this ) ) ),
1805 xEnv );
1806 // Unreachable
1809 // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1811 if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1813 // Invalid length (to short).
1814 ucbhelper::cancelCommandExecution(
1815 uno::makeAny( ucb::InteractiveBadTransferURLException(
1816 OUString(),
1817 static_cast< cppu::OWeakObject * >( this ) ) ),
1818 xEnv );
1819 // Unreachable
1822 OUString aScheme
1823 = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1824 .toAsciiLowerCase();
1825 if ( aScheme != TDOC_URL_SCHEME ":/" )
1827 // Invalid scheme.
1828 ucbhelper::cancelCommandExecution(
1829 uno::makeAny( ucb::InteractiveBadTransferURLException(
1830 OUString(),
1831 static_cast< cppu::OWeakObject * >( this ) ) ),
1832 xEnv );
1833 // Unreachable
1836 // Does source URI describe a tdoc folder or stream?
1837 Uri aSourceUri( rInfo.SourceURL );
1838 if ( !aSourceUri.isValid() )
1840 ucbhelper::cancelCommandExecution(
1841 uno::makeAny( lang::IllegalArgumentException(
1842 "Invalid source URI! Syntax!",
1843 static_cast< cppu::OWeakObject * >( this ),
1844 -1 ) ),
1845 xEnv );
1846 // Unreachable
1849 if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1851 ucbhelper::cancelCommandExecution(
1852 uno::makeAny( lang::IllegalArgumentException(
1853 "Invalid source URI! Must describe a folder or stream!",
1854 static_cast< cppu::OWeakObject * >( this ),
1855 -1 ) ),
1856 xEnv );
1857 // Unreachable
1860 // Is source not a parent of me / not me?
1861 OUString aId = m_xIdentifier->getContentIdentifier();
1862 sal_Int32 nPos = aId.lastIndexOf( '/' );
1863 if ( nPos != ( aId.getLength() - 1 ) )
1865 // No trailing slash found. Append.
1866 aId += "/";
1869 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1871 if ( aId.startsWith( rInfo.SourceURL ) )
1873 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1875 {"Uri", uno::Any(rInfo.SourceURL)}
1876 }));
1877 ucbhelper::cancelCommandExecution(
1878 ucb::IOErrorCode_RECURSIVE,
1879 aArgs,
1880 xEnv,
1881 "Target is equal to or is a child of source!",
1882 this );
1883 // Unreachable
1887 if ( m_aProps.getType() == DOCUMENT )
1889 bool bOK = false;
1891 uno::Reference< embed::XStorage > xStorage
1892 = m_pProvider->queryStorage(
1893 aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1894 if ( xStorage.is() )
1898 if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1900 ucbhelper::cancelCommandExecution(
1901 uno::makeAny( lang::IllegalArgumentException(
1902 "Invalid source URI! "
1903 "Streams cannot be created as "
1904 "children of document root!",
1905 static_cast< cppu::OWeakObject * >(
1906 this ),
1907 -1 ) ),
1908 xEnv );
1909 // Unreachable
1911 bOK = true;
1913 catch ( container::NoSuchElementException const & )
1915 // handled below.
1917 catch ( lang::IllegalArgumentException const & )
1919 // handled below.
1921 catch ( embed::InvalidStorageException const & )
1923 // handled below.
1927 if ( !bOK )
1929 ucbhelper::cancelCommandExecution(
1930 uno::makeAny( lang::IllegalArgumentException(
1931 "Invalid source URI! Unable to determine source type!",
1932 static_cast< cppu::OWeakObject * >( this ),
1933 -1 ) ),
1934 xEnv );
1935 // Unreachable
1940 // Copy data.
1943 OUString aNewName( !rInfo.NewTitle.isEmpty()
1944 ? rInfo.NewTitle
1945 : aSourceUri.getDecodedName() );
1947 if ( !copyData( aSourceUri, aNewName ) )
1949 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1951 {"Uri", uno::Any(rInfo.SourceURL)}
1952 }));
1953 ucbhelper::cancelCommandExecution(
1954 ucb::IOErrorCode_CANT_WRITE,
1955 aArgs,
1956 xEnv,
1957 "Cannot copy data!",
1958 this );
1959 // Unreachable
1963 // Copy own and all children's Additional Core Properties.
1966 OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1967 if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1968 aTargetUri += "/";
1970 if ( !rInfo.NewTitle.isEmpty() )
1971 aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1972 else
1973 aTargetUri += aSourceUri.getName();
1975 if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1977 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1979 {"Uri", uno::Any(rInfo.SourceURL)}
1980 }));
1981 ucbhelper::cancelCommandExecution(
1982 ucb::IOErrorCode_CANT_WRITE,
1983 aArgs,
1984 xEnv,
1985 "Cannot copy additional properties!",
1986 this );
1987 // Unreachable
1991 // Propagate new content.
1994 rtl::Reference< Content > xTarget;
1997 uno::Reference< ucb::XContentIdentifier > xTargetId
1998 = new ::ucbhelper::ContentIdentifier( aTargetUri );
2000 // Note: The static cast is okay here, because its sure that
2001 // m_xProvider is always the WebDAVContentProvider.
2002 xTarget = static_cast< Content * >(
2003 m_pProvider->queryContent( xTargetId ).get() );
2006 catch ( ucb::IllegalIdentifierException const & )
2008 // queryContent
2011 if ( !xTarget.is() )
2013 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2015 {"Uri", uno::Any(aTargetUri)}
2016 }));
2017 ucbhelper::cancelCommandExecution(
2018 ucb::IOErrorCode_CANT_READ,
2019 aArgs,
2020 xEnv,
2021 "Cannot instantiate target object!",
2022 this );
2023 // Unreachable
2026 // Announce transferred content in its new folder.
2027 xTarget->inserted();
2030 // Remove source, if requested
2033 if ( !rInfo.MoveData )
2034 return;
2036 rtl::Reference< Content > xSource;
2039 uno::Reference< ucb::XContentIdentifier >
2040 xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2042 // Note: The static cast is okay here, because its sure
2043 // that m_xProvider is always the ContentProvider.
2044 xSource = static_cast< Content * >(
2045 m_xProvider->queryContent( xSourceId ).get() );
2047 catch ( ucb::IllegalIdentifierException const & )
2049 // queryContent
2052 if ( !xSource.is() )
2054 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2056 {"Uri", uno::Any(rInfo.SourceURL)}
2057 }));
2058 ucbhelper::cancelCommandExecution(
2059 ucb::IOErrorCode_CANT_READ,
2060 aArgs,
2061 xEnv,
2062 "Cannot instantiate target object!",
2063 this );
2064 // Unreachable
2067 // Propagate destruction (recursively).
2068 xSource->destroy( true, xEnv );
2070 // Remove all persistent data of source and its children.
2071 if ( !xSource->removeData() )
2073 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2075 {"Uri", uno::Any(rInfo.SourceURL)}
2076 }));
2077 ucbhelper::cancelCommandExecution(
2078 ucb::IOErrorCode_CANT_WRITE,
2079 aArgs,
2080 xEnv,
2081 "Cannot remove persistent data of source object!",
2082 this );
2083 // Unreachable
2086 // Remove own and all children's Additional Core Properties.
2087 if ( xSource->removeAdditionalPropertySet() )
2088 return;
2090 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2092 {"Uri", uno::Any(rInfo.SourceURL)}
2093 }));
2094 ucbhelper::cancelCommandExecution(
2095 ucb::IOErrorCode_CANT_WRITE,
2096 aArgs,
2097 xEnv,
2098 "Cannot remove additional properties of source object!",
2099 this );
2100 // Unreachable
2104 //static
2105 bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2107 if ( rUri.isRoot() )
2109 return true; // root has no storage
2111 else if ( rUri.isDocument() )
2113 uno::Reference< embed::XStorage > xStorage
2114 = pProvider->queryStorage( rUri.getUri(), READ );
2115 return xStorage.is();
2117 else
2119 // folder or stream
2121 // Ask parent storage. In case that rUri describes a stream,
2122 // ContentProvider::queryStorage( rUri ) would return null.
2124 uno::Reference< embed::XStorage > xStorage
2125 = pProvider->queryStorage( rUri.getParentUri(), READ );
2127 if ( !xStorage.is() )
2128 return false;
2130 return xStorage->hasByName( rUri.getDecodedName() );
2135 //static
2136 bool Content::loadData( ContentProvider const * pProvider,
2137 const Uri & rUri,
2138 ContentProperties& rProps )
2140 if ( rUri.isRoot() ) // root has no storage, but can always be created
2142 rProps
2143 = ContentProperties(
2144 ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2146 else if ( rUri.isDocument() ) // document must have storage
2148 uno::Reference< embed::XStorage > xStorage
2149 = pProvider->queryStorage( rUri.getUri(), READ );
2151 if ( !xStorage.is() )
2152 return false;
2154 rProps
2155 = ContentProperties(
2156 DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2158 else // stream or folder; stream has no storage; folder has storage
2160 uno::Reference< embed::XStorage > xStorage
2161 = pProvider->queryStorage( rUri.getParentUri(), READ );
2163 if ( !xStorage.is() )
2164 return false;
2166 // Check whether exists at all, is stream or folder
2169 // return: true -> folder
2170 // return: false -> stream
2171 // NoSuchElementException -> neither folder nor stream
2172 bool bIsFolder
2173 = xStorage->isStorageElement( rUri.getDecodedName() );
2175 rProps
2176 = ContentProperties(
2177 bIsFolder ? FOLDER : STREAM,
2178 pProvider->queryStorageTitle( rUri.getUri() ) );
2180 catch ( container::NoSuchElementException const & )
2182 // there is no element with such name
2183 //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2184 return false;
2186 catch ( lang::IllegalArgumentException const & )
2188 // an illegal argument is provided
2189 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2190 return false;
2192 catch ( embed::InvalidStorageException const & )
2194 // this storage is in invalid state for any reason
2195 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2196 return false;
2199 return true;
2203 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2204 const uno::Reference<
2205 ucb::XCommandEnvironment >& xEnv )
2207 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2209 ContentType eType = m_aProps.getType();
2210 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2212 OSL_FAIL( "storeData not supported by root and documents!" );
2213 return false;
2216 Uri aUri( m_xIdentifier->getContentIdentifier() );
2218 if ( eType == FOLDER )
2220 uno::Reference< embed::XStorage > xStorage
2221 = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2223 if ( !xStorage.is() )
2224 return false;
2226 uno::Reference< beans::XPropertySet > xPropSet(
2227 xStorage, uno::UNO_QUERY );
2228 OSL_ENSURE( xPropSet.is(),
2229 "Content::storeData - Got no XPropertySet interface!" );
2230 if ( !xPropSet.is() )
2231 return false;
2235 // According to MBA, if no mediatype is set, folder and all
2236 // its contents will be lost on save of the document!!!
2237 xPropSet->setPropertyValue(
2238 "MediaType",
2239 uno::makeAny(
2240 OUString( // @@@ better mediatype
2241 "application/binary" ) ) );
2243 catch ( beans::UnknownPropertyException const & )
2245 OSL_FAIL( "Property MediaType not supported!" );
2246 return false;
2248 catch ( beans::PropertyVetoException const & )
2250 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2251 return false;
2253 catch ( lang::IllegalArgumentException const & )
2255 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2256 return false;
2258 catch ( lang::WrappedTargetException const & )
2260 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2261 return false;
2264 if ( !commitStorage( xStorage ) )
2265 return false;
2267 else if ( eType == STREAM )
2269 // stream
2271 // Important: Parent storage and output stream must be kept alive until
2272 // changes have been committed!
2273 uno::Reference< embed::XStorage > xStorage
2274 = m_pProvider->queryStorage(
2275 aUri.getParentUri(), READ_WRITE_CREATE );
2276 uno::Reference< io::XOutputStream > xOut;
2278 if ( !xStorage.is() )
2279 return false;
2281 if ( xData.is() )
2283 // May throw CommandFailedException, DocumentPasswordRequest!
2284 xOut = getTruncatedOutputStream( xEnv );
2286 OSL_ENSURE( xOut.is(), "No target data stream!" );
2290 uno::Sequence< sal_Int8 > aBuffer;
2291 while (true)
2293 sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2294 if (!nRead)
2295 break;
2296 aBuffer.realloc( nRead );
2297 xOut->writeBytes( aBuffer );
2300 closeOutputStream( xOut );
2302 catch ( io::NotConnectedException const & )
2304 // readSomeBytes, writeBytes
2305 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2306 closeOutputStream( xOut );
2307 return false;
2309 catch ( io::BufferSizeExceededException const & )
2311 // readSomeBytes, writeBytes
2312 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2313 closeOutputStream( xOut );
2314 return false;
2316 catch ( io::IOException const & )
2318 // readSomeBytes, writeBytes
2319 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2320 closeOutputStream( xOut );
2321 return false;
2323 catch ( ... )
2325 closeOutputStream( xOut );
2326 throw;
2330 // Commit changes.
2331 if ( !commitStorage( xStorage ) )
2332 return false;
2334 else
2336 OSL_FAIL( "Unknown content type!" );
2337 return false;
2339 return true;
2343 void Content::renameData(
2344 const uno::Reference< ucb::XContentIdentifier >& xOldId,
2345 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2347 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2349 ContentType eType = m_aProps.getType();
2350 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2352 OSL_FAIL( "renameData not supported by root and documents!" );
2353 return;
2356 Uri aOldUri( xOldId->getContentIdentifier() );
2357 uno::Reference< embed::XStorage > xStorage
2358 = m_pProvider->queryStorage(
2359 aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2361 if ( !xStorage.is() )
2362 return;
2366 Uri aNewUri( xNewId->getContentIdentifier() );
2367 xStorage->renameElement(
2368 aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2370 catch ( embed::InvalidStorageException const & )
2372 // this storage is in invalid state for any reason
2373 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2374 return;
2376 catch ( lang::IllegalArgumentException const & )
2378 // an illegal argument is provided
2379 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2380 return;
2382 catch ( container::NoSuchElementException const & )
2384 // there is no element with old name in this storage
2385 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2386 return;
2388 catch ( container::ElementExistException const & )
2390 // an element with new name already exists in this storage
2391 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2392 return;
2394 catch ( io::IOException const & )
2396 // in case of io errors during renaming
2397 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2398 return;
2400 catch ( embed::StorageWrappedTargetException const & )
2402 // wraps other exceptions
2403 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2404 return;
2407 commitStorage( xStorage );
2411 bool Content::removeData()
2413 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2415 ContentType eType = m_aProps.getType();
2416 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2418 OSL_FAIL( "removeData not supported by root and documents!" );
2419 return false;
2422 Uri aUri( m_xIdentifier->getContentIdentifier() );
2423 uno::Reference< embed::XStorage > xStorage
2424 = m_pProvider->queryStorage(
2425 aUri.getParentUri(), READ_WRITE_NOCREATE );
2427 if ( !xStorage.is() )
2428 return false;
2432 xStorage->removeElement( aUri.getDecodedName() );
2434 catch ( embed::InvalidStorageException const & )
2436 // this storage is in invalid state for any reason
2437 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2438 return false;
2440 catch ( lang::IllegalArgumentException const & )
2442 // an illegal argument is provided
2443 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2444 return false;
2446 catch ( container::NoSuchElementException const & )
2448 // there is no element with this name in this storage
2449 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2450 return false;
2452 catch ( io::IOException const & )
2454 // in case of io errors during renaming
2455 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2456 return false;
2458 catch ( embed::StorageWrappedTargetException const & )
2460 // wraps other exceptions
2461 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2462 return false;
2465 return commitStorage( xStorage );
2469 bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2471 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2473 ContentType eType = m_aProps.getType();
2474 if ( ( eType == ROOT ) || ( eType == STREAM ) )
2476 OSL_FAIL( "copyData not supported by root and streams!" );
2477 return false;
2480 Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2481 uno::Reference< embed::XStorage > xDestStorage
2482 = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2484 if ( !xDestStorage.is() )
2485 return false;
2487 uno::Reference< embed::XStorage > xSourceStorage
2488 = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2490 if ( !xSourceStorage.is() )
2491 return false;
2495 xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2496 xDestStorage,
2497 rNewName );
2499 catch ( embed::InvalidStorageException const & )
2501 // this storage is in invalid state for any reason
2502 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2503 return false;
2505 catch ( lang::IllegalArgumentException const & )
2507 // an illegal argument is provided
2508 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2509 return false;
2511 catch ( container::NoSuchElementException const & )
2513 // there is no element with this name in this storage
2514 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2515 return false;
2517 catch ( container::ElementExistException const & )
2519 // there is no element with this name in this storage
2520 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2521 return false;
2523 catch ( io::IOException const & )
2525 // in case of io errors during renaming
2526 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2527 return false;
2529 catch ( embed::StorageWrappedTargetException const & )
2531 // wraps other exceptions
2532 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2533 return false;
2536 return commitStorage( xDestStorage );
2540 // static
2541 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2543 // Commit changes
2544 uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2546 OSL_ENSURE( xTO.is(),
2547 "Required interface css.embed.XTransactedObject missing!" );
2550 xTO->commit();
2552 catch ( io::IOException const & )
2554 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2555 return false;
2557 catch ( lang::WrappedTargetException const & )
2559 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2560 return false;
2563 return true;
2567 // static
2568 bool Content::closeOutputStream(
2569 const uno::Reference< io::XOutputStream > & xOut )
2571 if ( xOut.is() )
2575 xOut->closeOutput();
2576 return true;
2578 catch ( io::NotConnectedException const & )
2580 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2582 catch ( io::BufferSizeExceededException const & )
2584 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2586 catch ( io::IOException const & )
2588 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2591 return false;
2594 /// @throws ucb::CommandFailedException
2595 /// @throws task::DocumentPasswordRequest
2596 static OUString obtainPassword(
2597 const OUString & rName,
2598 task::PasswordRequestMode eMode,
2599 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2601 rtl::Reference< DocumentPasswordRequest > xRequest
2602 = new DocumentPasswordRequest( eMode, rName );
2604 if ( xEnv.is() )
2606 uno::Reference< task::XInteractionHandler > xIH
2607 = xEnv->getInteractionHandler();
2608 if ( xIH.is() )
2610 xIH->handle( xRequest );
2612 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
2613 = xRequest->getSelection();
2615 if ( xSelection.is() )
2617 // Handler handled the request.
2618 uno::Reference< task::XInteractionAbort > xAbort(
2619 xSelection.get(), uno::UNO_QUERY );
2620 if ( xAbort.is() )
2622 throw ucb::CommandFailedException(
2623 "Abort requested by Interaction Handler.",
2624 uno::Reference< uno::XInterface >(),
2625 xRequest->getRequest() );
2628 uno::Reference< task::XInteractionPassword > xPassword(
2629 xSelection.get(), uno::UNO_QUERY );
2630 if ( xPassword.is() )
2632 return xPassword->getPassword();
2635 // Unknown selection. Should never happen.
2636 throw ucb::CommandFailedException(
2637 "Interaction Handler selected unknown continuation!",
2638 uno::Reference< uno::XInterface >(),
2639 xRequest->getRequest() );
2644 // No IH or IH did not handle exception.
2645 task::DocumentPasswordRequest aRequest;
2646 xRequest->getRequest() >>= aRequest;
2647 throw aRequest;
2651 uno::Reference< io::XInputStream > Content::getInputStream(
2652 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2654 OUString aUri;
2655 OUString aPassword;
2656 bool bPasswordRequested = false;
2659 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2661 OSL_ENSURE( m_aProps.getType() == STREAM,
2662 "Content::getInputStream - content is no stream!" );
2664 aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2667 for ( ;; )
2671 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2672 return m_pProvider->queryInputStream( aUri, aPassword );
2674 catch ( packages::WrongPasswordException const & )
2676 // Obtain (new) password.
2677 aPassword
2678 = obtainPassword( aUri, /* @@@ find better title */
2679 bPasswordRequested
2680 ? task::PasswordRequestMode_PASSWORD_REENTER
2681 : task::PasswordRequestMode_PASSWORD_ENTER,
2682 xEnv );
2683 bPasswordRequested = true;
2688 /// @throws ucb::CommandFailedException
2689 /// @throws task::DocumentPasswordRequest
2690 /// @throws uno::RuntimeException
2691 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2692 const OUString & rUri,
2693 ContentProvider const * pProvider,
2694 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2696 OUString aPassword;
2697 bool bPasswordRequested = false;
2698 for ( ;; )
2702 return pProvider->queryOutputStream(
2703 rUri, aPassword, true /* truncate */ );
2705 catch ( packages::WrongPasswordException const & )
2707 // Obtain (new) password.
2708 aPassword
2709 = obtainPassword( rUri, /* @@@ find better title */
2710 bPasswordRequested
2711 ? task::PasswordRequestMode_PASSWORD_REENTER
2712 : task::PasswordRequestMode_PASSWORD_ENTER,
2713 xEnv );
2714 bPasswordRequested = true;
2720 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2721 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2723 OSL_ENSURE( m_aProps.getType() == STREAM,
2724 "Content::getTruncatedOutputStream - content is no stream!" );
2726 return lcl_getTruncatedOutputStream(
2727 Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2728 m_pProvider,
2729 xEnv );
2733 uno::Reference< io::XStream > Content::getStream(
2734 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2736 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2738 OSL_ENSURE( m_aProps.getType() == STREAM,
2739 "Content::getStream - content is no stream!" );
2741 OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2742 OUString aPassword;
2743 bool bPasswordRequested = false;
2744 for ( ;; )
2748 return m_pProvider->queryStream(
2749 aUri, aPassword, false /* no truncate */ );
2751 catch ( packages::WrongPasswordException const & )
2753 // Obtain (new) password.
2754 aPassword
2755 = obtainPassword( aUri, /* @@@ find better title */
2756 bPasswordRequested
2757 ? task::PasswordRequestMode_PASSWORD_REENTER
2758 : task::PasswordRequestMode_PASSWORD_ENTER,
2759 xEnv );
2760 bPasswordRequested = true;
2766 // ContentProperties Implementation.
2769 uno::Sequence< ucb::ContentInfo >
2770 ContentProperties::getCreatableContentsInfo() const
2772 if ( isContentCreator() )
2774 uno::Sequence< beans::Property > aProps( 1 );
2775 aProps.getArray()[ 0 ] = beans::Property(
2776 "Title",
2778 cppu::UnoType<OUString>::get(),
2779 beans::PropertyAttribute::BOUND );
2781 if ( getType() == DOCUMENT )
2783 // streams cannot be created as direct children of document root
2784 uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2786 // Folder.
2787 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2788 aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2789 aSeq.getArray()[ 0 ].Properties = aProps;
2791 return aSeq;
2793 else
2795 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2797 // Folder.
2798 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2799 aSeq.getArray()[ 0 ].Attributes
2800 = ucb::ContentInfoAttribute::KIND_FOLDER;
2801 aSeq.getArray()[ 0 ].Properties = aProps;
2803 // Stream.
2804 aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2805 aSeq.getArray()[ 1 ].Attributes
2806 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2807 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2808 aSeq.getArray()[ 1 ].Properties = aProps;
2810 return aSeq;
2813 else
2815 OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2816 "object!" );
2818 return uno::Sequence< ucb::ContentInfo >( 0 );
2823 bool ContentProperties::isContentCreator() const
2825 return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */