bump product version to 4.1.6.2
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_content.cxx
blobc08faf6839590a8b01db65b56020d6d28c2bb6e3
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 "osl/diagnose.h"
28 #include "osl/doublecheckedlocking.h"
29 #include "rtl/ustrbuf.hxx"
31 #include "com/sun/star/beans/PropertyAttribute.hpp"
32 #include "com/sun/star/beans/PropertyValue.hpp"
33 #include "com/sun/star/beans/XPropertySet.hpp"
34 #include "com/sun/star/embed/ElementModes.hpp"
35 #include "com/sun/star/embed/XStorage.hpp"
36 #include "com/sun/star/embed/XTransactedObject.hpp"
37 #include "com/sun/star/io/XActiveDataSink.hpp"
38 #include "com/sun/star/io/XActiveDataStreamer.hpp"
39 #include "com/sun/star/lang/IllegalAccessException.hpp"
40 #include "com/sun/star/sdbc/XRow.hpp"
41 #include "com/sun/star/ucb/ContentAction.hpp"
42 #include "com/sun/star/ucb/ContentInfoAttribute.hpp"
43 #include "com/sun/star/ucb/InsertCommandArgument.hpp"
44 #include "com/sun/star/ucb/InteractiveBadTransferURLException.hpp"
45 #include "com/sun/star/ucb/MissingInputStreamException.hpp"
46 #include "com/sun/star/ucb/MissingPropertiesException.hpp"
47 #include "com/sun/star/ucb/NameClash.hpp"
48 #include "com/sun/star/ucb/NameClashException.hpp"
49 #include "com/sun/star/ucb/OpenCommandArgument2.hpp"
50 #include "com/sun/star/ucb/OpenMode.hpp"
51 #include "com/sun/star/ucb/TransferInfo.hpp"
52 #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
53 #include "com/sun/star/ucb/UnsupportedDataSinkException.hpp"
54 #include "com/sun/star/ucb/UnsupportedNameClashException.hpp"
55 #include "com/sun/star/ucb/UnsupportedOpenModeException.hpp"
56 #include "com/sun/star/ucb/XCommandInfo.hpp"
57 #include "com/sun/star/ucb/XPersistentPropertySet.hpp"
59 #include "comphelper/processfactory.hxx"
60 #include "ucbhelper/cancelcommandexecution.hxx"
61 #include "ucbhelper/contentidentifier.hxx"
62 #include "ucbhelper/propertyvalueset.hxx"
64 #include "tdoc_content.hxx"
65 #include "tdoc_resultset.hxx"
66 #include "tdoc_passwordrequest.hxx"
68 #include "../inc/urihelper.hxx"
70 using namespace com::sun::star;
71 using namespace tdoc_ucp;
73 //=========================================================================
74 static ContentType lcl_getContentType( const OUString & rType )
76 if ( rType == TDOC_ROOT_CONTENT_TYPE )
77 return ROOT;
78 else if ( rType == TDOC_DOCUMENT_CONTENT_TYPE )
79 return DOCUMENT;
80 else if ( rType == TDOC_FOLDER_CONTENT_TYPE )
81 return FOLDER;
82 else if ( rType == TDOC_STREAM_CONTENT_TYPE )
83 return STREAM;
84 else
86 OSL_FAIL( "Content::Content - unsupported content type string" );
87 return STREAM;
91 //=========================================================================
92 //=========================================================================
94 // Content Implementation.
96 //=========================================================================
97 //=========================================================================
99 // static ( "virtual" ctor )
100 Content* Content::create(
101 const uno::Reference< uno::XComponentContext >& rxContext,
102 ContentProvider* pProvider,
103 const uno::Reference< ucb::XContentIdentifier >& Identifier )
105 // Fail, if resource does not exist.
106 ContentProperties aProps;
107 if ( !Content::loadData( pProvider,
108 Uri( Identifier->getContentIdentifier() ),
109 aProps ) )
110 return 0;
112 return new Content( rxContext, pProvider, Identifier, aProps );
115 //=========================================================================
116 // static ( "virtual" ctor )
117 Content* Content::create(
118 const uno::Reference< uno::XComponentContext >& rxContext,
119 ContentProvider* pProvider,
120 const uno::Reference< ucb::XContentIdentifier >& Identifier,
121 const ucb::ContentInfo& Info )
123 if ( Info.Type.isEmpty() )
124 return 0;
126 if ( Info.Type != TDOC_FOLDER_CONTENT_TYPE && Info.Type != TDOC_STREAM_CONTENT_TYPE )
128 OSL_FAIL( "Content::create - unsupported content type!" );
129 return 0;
132 return new Content( rxContext, pProvider, Identifier, Info );
135 //=========================================================================
136 Content::Content(
137 const uno::Reference< uno::XComponentContext > & rxContext,
138 ContentProvider * pProvider,
139 const uno::Reference< ucb::XContentIdentifier > & Identifier,
140 const ContentProperties & rProps )
141 : ContentImplHelper( rxContext, pProvider, Identifier ),
142 m_aProps( rProps ),
143 m_eState( PERSISTENT ),
144 m_pProvider( pProvider )
148 //=========================================================================
149 // ctor for a content just created via XContentCreator::createNewContent()
150 Content::Content(
151 const uno::Reference< uno::XComponentContext >& rxContext,
152 ContentProvider* pProvider,
153 const uno::Reference< ucb::XContentIdentifier >& Identifier,
154 const ucb::ContentInfo& Info )
155 : ContentImplHelper( rxContext, pProvider, Identifier ),
156 m_aProps( lcl_getContentType( Info.Type ), OUString() ), // no Title (yet)
157 m_eState( TRANSIENT ),
158 m_pProvider( pProvider )
162 //=========================================================================
163 // virtual
164 Content::~Content()
168 //=========================================================================
170 // XInterface methods.
172 //=========================================================================
174 // virtual
175 void SAL_CALL Content::acquire()
176 throw( )
178 ContentImplHelper::acquire();
181 //=========================================================================
182 // virtual
183 void SAL_CALL Content::release()
184 throw( )
186 ContentImplHelper::release();
189 //=========================================================================
190 // virtual
191 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
192 throw ( uno::RuntimeException )
194 uno::Any aRet = ContentImplHelper::queryInterface( rType );
196 if ( !aRet.hasValue() )
198 aRet = cppu::queryInterface(
199 rType, static_cast< ucb::XContentCreator * >( this ) );
200 if ( aRet.hasValue() )
202 if ( !m_aProps.isContentCreator() )
203 return uno::Any();
207 return aRet;
210 //=========================================================================
212 // XTypeProvider methods.
214 //=========================================================================
216 XTYPEPROVIDER_COMMON_IMPL( Content );
218 //=========================================================================
219 // virtual
220 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
221 throw( uno::RuntimeException )
223 cppu::OTypeCollection * pCollection = 0;
225 if ( m_aProps.isContentCreator() )
227 static cppu::OTypeCollection* pFolderTypes = 0;
229 pCollection = pFolderTypes;
230 if ( !pCollection )
232 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
234 pCollection = pFolderTypes;
235 if ( !pCollection )
237 static cppu::OTypeCollection aCollection(
238 CPPU_TYPE_REF( lang::XTypeProvider ),
239 CPPU_TYPE_REF( lang::XServiceInfo ),
240 CPPU_TYPE_REF( lang::XComponent ),
241 CPPU_TYPE_REF( ucb::XContent ),
242 CPPU_TYPE_REF( ucb::XCommandProcessor ),
243 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
244 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
245 CPPU_TYPE_REF( beans::XPropertyContainer ),
246 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
247 CPPU_TYPE_REF( container::XChild ),
248 CPPU_TYPE_REF( ucb::XContentCreator ) ); // !!
249 pCollection = &aCollection;
250 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
251 pFolderTypes = pCollection;
254 else {
255 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
258 else
260 static cppu::OTypeCollection* pDocumentTypes = 0;
262 pCollection = pDocumentTypes;
263 if ( !pCollection )
265 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
267 pCollection = pDocumentTypes;
268 if ( !pCollection )
270 static cppu::OTypeCollection aCollection(
271 CPPU_TYPE_REF( lang::XTypeProvider ),
272 CPPU_TYPE_REF( lang::XServiceInfo ),
273 CPPU_TYPE_REF( lang::XComponent ),
274 CPPU_TYPE_REF( ucb::XContent ),
275 CPPU_TYPE_REF( ucb::XCommandProcessor ),
276 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
277 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
278 CPPU_TYPE_REF( beans::XPropertyContainer ),
279 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
280 CPPU_TYPE_REF( container::XChild ) );
281 pCollection = &aCollection;
282 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
283 pDocumentTypes = pCollection;
286 else {
287 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
291 return (*pCollection).getTypes();
294 //=========================================================================
296 // XServiceInfo methods.
298 //=========================================================================
300 // virtual
301 OUString SAL_CALL Content::getImplementationName()
302 throw( uno::RuntimeException )
304 return OUString( "com.sun.star.comp.ucb.TransientDocumentsContent" );
307 //=========================================================================
308 // virtual
309 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
310 throw( uno::RuntimeException )
312 osl::Guard< osl::Mutex > aGuard( m_aMutex );
314 uno::Sequence< OUString > aSNS( 1 );
316 if ( m_aProps.getType() == STREAM )
317 aSNS.getArray()[ 0 ] = OUString( TDOC_STREAM_CONTENT_SERVICE_NAME );
318 else if ( m_aProps.getType() == FOLDER )
319 aSNS.getArray()[ 0 ] = OUString( TDOC_FOLDER_CONTENT_SERVICE_NAME );
320 else if ( m_aProps.getType() == DOCUMENT )
321 aSNS.getArray()[ 0 ] = OUString( TDOC_DOCUMENT_CONTENT_SERVICE_NAME );
322 else
323 aSNS.getArray()[ 0 ] = OUString( TDOC_ROOT_CONTENT_SERVICE_NAME );
325 return aSNS;
328 //=========================================================================
330 // XContent methods.
332 //=========================================================================
334 // virtual
335 OUString SAL_CALL Content::getContentType()
336 throw( uno::RuntimeException )
338 osl::Guard< osl::Mutex > aGuard( m_aMutex );
339 return m_aProps.getContentType();
342 //=========================================================================
343 // virtual
344 uno::Reference< ucb::XContentIdentifier > SAL_CALL
345 Content::getIdentifier()
346 throw( uno::RuntimeException )
349 osl::Guard< osl::Mutex > aGuard( m_aMutex );
351 // Transient?
352 if ( m_eState == TRANSIENT )
354 // Transient contents have no identifier.
355 return uno::Reference< ucb::XContentIdentifier >();
358 return ContentImplHelper::getIdentifier();
361 //=========================================================================
363 // XCommandProcessor methods.
365 //=========================================================================
367 // virtual
368 uno::Any SAL_CALL Content::execute(
369 const ucb::Command& aCommand,
370 sal_Int32 /*CommandId*/,
371 const uno::Reference< ucb::XCommandEnvironment >& Environment )
372 throw( uno::Exception,
373 ucb::CommandAbortedException,
374 uno::RuntimeException )
376 uno::Any aRet;
378 if ( aCommand.Name == "getPropertyValues" )
380 //////////////////////////////////////////////////////////////////
381 // getPropertyValues
382 //////////////////////////////////////////////////////////////////
384 uno::Sequence< beans::Property > Properties;
385 if ( !( aCommand.Argument >>= Properties ) )
387 ucbhelper::cancelCommandExecution(
388 uno::makeAny( lang::IllegalArgumentException(
389 OUString( "Wrong argument type!" ),
390 static_cast< cppu::OWeakObject * >( this ),
391 -1 ) ),
392 Environment );
393 // Unreachable
396 aRet <<= getPropertyValues( Properties );
398 else if ( aCommand.Name == "setPropertyValues" )
400 //////////////////////////////////////////////////////////////////
401 // setPropertyValues
402 //////////////////////////////////////////////////////////////////
404 uno::Sequence< beans::PropertyValue > aProperties;
405 if ( !( aCommand.Argument >>= aProperties ) )
407 ucbhelper::cancelCommandExecution(
408 uno::makeAny( lang::IllegalArgumentException(
409 OUString( "Wrong argument type!" ),
410 static_cast< cppu::OWeakObject * >( this ),
411 -1 ) ),
412 Environment );
413 // Unreachable
416 if ( !aProperties.getLength() )
418 ucbhelper::cancelCommandExecution(
419 uno::makeAny( lang::IllegalArgumentException(
420 OUString( "No properties!" ),
421 static_cast< cppu::OWeakObject * >( this ),
422 -1 ) ),
423 Environment );
424 // Unreachable
427 aRet <<= setPropertyValues( aProperties, Environment );
429 else if ( aCommand.Name == "getPropertySetInfo" )
431 //////////////////////////////////////////////////////////////////
432 // getPropertySetInfo
433 //////////////////////////////////////////////////////////////////
435 aRet <<= getPropertySetInfo( Environment );
437 else if ( aCommand.Name == "getCommandInfo" )
439 //////////////////////////////////////////////////////////////////
440 // getCommandInfo
441 //////////////////////////////////////////////////////////////////
443 aRet <<= getCommandInfo( Environment );
445 else if ( aCommand.Name == "open" )
447 //////////////////////////////////////////////////////////////////
448 // open
449 //////////////////////////////////////////////////////////////////
451 ucb::OpenCommandArgument2 aOpenCommand;
452 if ( !( aCommand.Argument >>= aOpenCommand ) )
454 ucbhelper::cancelCommandExecution(
455 uno::makeAny( lang::IllegalArgumentException(
456 OUString( "Wrong argument type!" ),
457 static_cast< cppu::OWeakObject * >( this ),
458 -1 ) ),
459 Environment );
460 // Unreachable
463 aRet = open( aOpenCommand, Environment );
465 else if ( aCommand.Name == "insert" )
467 //////////////////////////////////////////////////////////////////
468 // insert ( Supported by folders and streams only )
469 //////////////////////////////////////////////////////////////////
471 ContentType eType = m_aProps.getType();
472 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
474 ucbhelper::cancelCommandExecution(
475 uno::makeAny( ucb::UnsupportedCommandException(
476 OUString( "insert command only supported by "
477 "folders and streams!" ),
478 static_cast< cppu::OWeakObject * >( this ) ) ),
479 Environment );
480 // Unreachable
483 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
484 if ( eType == STREAM )
486 Uri aUri( m_xIdentifier->getContentIdentifier() );
487 Uri aParentUri( aUri.getParentUri() );
488 if ( aParentUri.isDocument() )
490 ucbhelper::cancelCommandExecution(
491 uno::makeAny( ucb::UnsupportedCommandException(
492 OUString( "insert command not supported by "
493 "streams that are direct children "
494 "of document root!" ),
495 static_cast< cppu::OWeakObject * >(
496 this ) ) ),
497 Environment );
498 // Unreachable
501 #endif
502 ucb::InsertCommandArgument aArg;
503 if ( !( aCommand.Argument >>= aArg ) )
505 ucbhelper::cancelCommandExecution(
506 uno::makeAny( lang::IllegalArgumentException(
507 OUString( "Wrong argument type!" ),
508 static_cast< cppu::OWeakObject * >( this ),
509 -1 ) ),
510 Environment );
511 // Unreachable
514 sal_Int32 nNameClash = aArg.ReplaceExisting
515 ? ucb::NameClash::OVERWRITE
516 : ucb::NameClash::ERROR;
517 insert( aArg.Data, nNameClash, Environment );
519 else if ( aCommand.Name == "delete" )
521 //////////////////////////////////////////////////////////////////
522 // delete ( Supported by folders and streams only )
523 //////////////////////////////////////////////////////////////////
526 osl::MutexGuard aGuard( m_aMutex );
528 ContentType eType = m_aProps.getType();
529 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
531 ucbhelper::cancelCommandExecution(
532 uno::makeAny( ucb::UnsupportedCommandException(
533 OUString( "delete command only supported by "
534 "folders and streams!" ),
535 static_cast< cppu::OWeakObject * >(
536 this ) ) ),
537 Environment );
538 // Unreachable
542 sal_Bool bDeletePhysical = sal_False;
543 aCommand.Argument >>= bDeletePhysical;
544 destroy( bDeletePhysical, Environment );
546 // Remove own and all children's persistent data.
547 if ( !removeData() )
549 uno::Any aProps
550 = uno::makeAny(
551 beans::PropertyValue(
552 OUString( "Uri"),
554 uno::makeAny(m_xIdentifier->
555 getContentIdentifier()),
556 beans::PropertyState_DIRECT_VALUE));
557 ucbhelper::cancelCommandExecution(
558 ucb::IOErrorCode_CANT_WRITE,
559 uno::Sequence< uno::Any >(&aProps, 1),
560 Environment,
561 OUString( "Cannot remove persistent data!" ),
562 this );
563 // Unreachable
566 // Remove own and all children's Additional Core Properties.
567 removeAdditionalPropertySet( sal_True );
569 else if ( aCommand.Name == "transfer" )
571 //////////////////////////////////////////////////////////////////
572 // transfer ( Supported by document and folders only )
573 //////////////////////////////////////////////////////////////////
576 osl::MutexGuard aGuard( m_aMutex );
578 ContentType eType = m_aProps.getType();
579 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
581 ucbhelper::cancelCommandExecution(
582 uno::makeAny( ucb::UnsupportedCommandException(
583 OUString( "transfer command only supported "
584 "by folders and documents!" ),
585 static_cast< cppu::OWeakObject * >(
586 this ) ) ),
587 Environment );
588 // Unreachable
592 ucb::TransferInfo aInfo;
593 if ( !( aCommand.Argument >>= aInfo ) )
595 OSL_FAIL( "Wrong argument type!" );
596 ucbhelper::cancelCommandExecution(
597 uno::makeAny( lang::IllegalArgumentException(
598 OUString( "Wrong argument type!" ),
599 static_cast< cppu::OWeakObject * >( this ),
600 -1 ) ),
601 Environment );
602 // Unreachable
605 transfer( aInfo, Environment );
607 else if ( aCommand.Name == "createNewContent" )
609 //////////////////////////////////////////////////////////////////
610 // createNewContent ( Supported by document and folders only )
611 //////////////////////////////////////////////////////////////////
614 osl::MutexGuard aGuard( m_aMutex );
616 ContentType eType = m_aProps.getType();
617 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
619 ucbhelper::cancelCommandExecution(
620 uno::makeAny( ucb::UnsupportedCommandException(
621 OUString( "createNewContent command only "
622 "supported by folders and "
623 "documents!" ),
624 static_cast< cppu::OWeakObject * >(
625 this ) ) ),
626 Environment );
627 // Unreachable
631 ucb::ContentInfo aInfo;
632 if ( !( aCommand.Argument >>= aInfo ) )
634 OSL_FAIL( "Wrong argument type!" );
635 ucbhelper::cancelCommandExecution(
636 uno::makeAny( lang::IllegalArgumentException(
637 OUString( "Wrong argument type!" ),
638 static_cast< cppu::OWeakObject * >( this ),
639 -1 ) ),
640 Environment );
641 // Unreachable
644 aRet <<= createNewContent( aInfo );
646 else
648 //////////////////////////////////////////////////////////////////
649 // Unsupported command
650 //////////////////////////////////////////////////////////////////
652 ucbhelper::cancelCommandExecution(
653 uno::makeAny( ucb::UnsupportedCommandException(
654 OUString(),
655 static_cast< cppu::OWeakObject * >( this ) ) ),
656 Environment );
657 // Unreachable
660 return aRet;
663 //=========================================================================
664 // virtual
665 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
666 throw( uno::RuntimeException )
670 //=========================================================================
672 // XContentCreator methods.
674 //=========================================================================
676 // virtual
677 uno::Sequence< ucb::ContentInfo > SAL_CALL
678 Content::queryCreatableContentsInfo()
679 throw( uno::RuntimeException )
681 return m_aProps.getCreatableContentsInfo();
684 //=========================================================================
685 // virtual
686 uno::Reference< ucb::XContent > SAL_CALL
687 Content::createNewContent( const ucb::ContentInfo& Info )
688 throw( uno::RuntimeException )
690 if ( m_aProps.isContentCreator() )
692 osl::Guard< osl::Mutex > aGuard( m_aMutex );
694 if ( Info.Type.isEmpty() )
695 return uno::Reference< ucb::XContent >();
697 sal_Bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
699 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
700 // streams cannot be created as direct children of document root
701 if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
703 OSL_FAIL( "Content::createNewContent - streams cannot be "
704 "created as direct children of document root!" );
705 return uno::Reference< ucb::XContent >();
707 #endif
708 if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
710 OSL_FAIL( "Content::createNewContent - unsupported type!" );
711 return uno::Reference< ucb::XContent >();
714 OUString aURL = m_xIdentifier->getContentIdentifier();
716 OSL_ENSURE( !aURL.isEmpty(),
717 "Content::createNewContent - empty identifier!" );
719 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
720 aURL += OUString("/");
722 if ( bCreateFolder )
723 aURL += OUString("New_Folder");
724 else
725 aURL += OUString("New_Stream");
727 uno::Reference< ucb::XContentIdentifier > xId
728 = new ::ucbhelper::ContentIdentifier( aURL );
730 return create( m_xContext, m_pProvider, xId, Info );
732 else
734 OSL_FAIL( "createNewContent called on non-contentcreator object!" );
735 return uno::Reference< ucb::XContent >();
739 //=========================================================================
740 // virtual
741 OUString Content::getParentURL()
743 osl::Guard< osl::Mutex > aGuard( m_aMutex );
744 Uri aUri( m_xIdentifier->getContentIdentifier() );
745 return aUri.getParentUri();
748 //=========================================================================
749 uno::Reference< ucb::XContentIdentifier >
750 Content::makeNewIdentifier( const OUString& rTitle )
752 osl::Guard< osl::Mutex > aGuard( m_aMutex );
754 // Assemble new content identifier...
755 Uri aUri( m_xIdentifier->getContentIdentifier() );
756 OUStringBuffer aNewURL = aUri.getParentUri();
757 aNewURL.append( ::ucb_impl::urihelper::encodeSegment( rTitle ) );
759 return
760 uno::Reference< ucb::XContentIdentifier >(
761 new ::ucbhelper::ContentIdentifier( aNewURL.makeStringAndClear() ) );
764 //=========================================================================
765 void Content::queryChildren( ContentRefList& rChildren )
767 osl::Guard< osl::Mutex > aGuard( m_aMutex );
769 // Only folders (root, documents, folders) have children.
770 if ( !m_aProps.getIsFolder() )
771 return;
773 // Obtain a list with a snapshot of all currently instanciated contents
774 // from provider and extract the contents which are direct children
775 // of this content.
777 ::ucbhelper::ContentRefList aAllContents;
778 m_xProvider->queryExistingContents( aAllContents );
780 OUString aURL = m_xIdentifier->getContentIdentifier();
781 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
783 if ( nURLPos != ( aURL.getLength() - 1 ) )
785 // No trailing slash found. Append.
786 aURL += OUString("/");
789 sal_Int32 nLen = aURL.getLength();
791 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin();
792 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
794 while ( it != end )
796 ::ucbhelper::ContentImplHelperRef xChild = (*it);
797 OUString aChildURL
798 = xChild->getIdentifier()->getContentIdentifier();
800 // Is aURL a prefix of aChildURL?
801 if ( ( aChildURL.getLength() > nLen ) &&
802 ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
804 sal_Int32 nPos = nLen;
805 nPos = aChildURL.indexOf( '/', nPos );
807 if ( ( nPos == -1 ) ||
808 ( nPos == ( aChildURL.getLength() - 1 ) ) )
810 // No further slashes / only a final slash. It's a child!
811 rChildren.push_back(
812 ContentRef(
813 static_cast< Content * >( xChild.get() ) ) );
816 ++it;
820 //=========================================================================
821 sal_Bool Content::exchangeIdentity(
822 const uno::Reference< ucb::XContentIdentifier >& xNewId )
824 if ( !xNewId.is() )
825 return sal_False;
827 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
829 uno::Reference< ucb::XContent > xThis = this;
831 // Already persistent?
832 if ( m_eState != PERSISTENT )
834 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
835 return sal_False;
838 // Only folders and streams can be renamed -> exchange identity.
839 ContentType eType = m_aProps.getType();
840 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
842 OSL_FAIL( "Content::exchangeIdentity - "
843 "Not supported by root or document!" );
844 return sal_False;
847 // Exchange own identitity.
849 // Fail, if a content with given id already exists.
850 if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
852 OUString aOldURL = m_xIdentifier->getContentIdentifier();
854 aGuard.clear();
855 if ( exchange( xNewId ) )
857 if ( eType == FOLDER )
859 // Process instanciated children...
861 ContentRefList aChildren;
862 queryChildren( aChildren );
864 ContentRefList::const_iterator it = aChildren.begin();
865 ContentRefList::const_iterator end = aChildren.end();
867 while ( it != end )
869 ContentRef xChild = (*it);
871 // Create new content identifier for the child...
872 uno::Reference< ucb::XContentIdentifier > xOldChildId
873 = xChild->getIdentifier();
874 OUString aOldChildURL
875 = xOldChildId->getContentIdentifier();
876 OUString aNewChildURL
877 = aOldChildURL.replaceAt(
879 aOldURL.getLength(),
880 xNewId->getContentIdentifier() );
881 uno::Reference< ucb::XContentIdentifier > xNewChildId
882 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
884 if ( !xChild->exchangeIdentity( xNewChildId ) )
885 return sal_False;
887 ++it;
890 return sal_True;
894 OSL_FAIL( "Content::exchangeIdentity - "
895 "Panic! Cannot exchange identity!" );
896 return sal_False;
899 //=========================================================================
900 // static
901 uno::Reference< sdbc::XRow > Content::getPropertyValues(
902 const uno::Reference< uno::XComponentContext >& rxContext,
903 const uno::Sequence< beans::Property >& rProperties,
904 ContentProvider* pProvider,
905 const OUString& rContentId )
907 ContentProperties aData;
908 if ( loadData( pProvider, rContentId, aData ) )
910 return getPropertyValues(
911 rxContext, rProperties, aData, pProvider, rContentId );
913 else
915 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
916 = new ::ucbhelper::PropertyValueSet( rxContext );
918 sal_Int32 nCount = rProperties.getLength();
919 if ( nCount )
921 const beans::Property* pProps = rProperties.getConstArray();
922 for ( sal_Int32 n = 0; n < nCount; ++n )
923 xRow->appendVoid( pProps[ n ] );
926 return uno::Reference< sdbc::XRow >( xRow.get() );
930 //=========================================================================
931 // static
932 uno::Reference< sdbc::XRow > Content::getPropertyValues(
933 const uno::Reference< uno::XComponentContext >& rxContext,
934 const uno::Sequence< beans::Property >& rProperties,
935 const ContentProperties& rData,
936 ContentProvider* pProvider,
937 const OUString& rContentId )
939 // Note: Empty sequence means "get values of all supported properties".
941 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
942 = new ::ucbhelper::PropertyValueSet( rxContext );
944 sal_Int32 nCount = rProperties.getLength();
945 if ( nCount )
947 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
948 sal_Bool bTriedToGetAdditonalPropSet = sal_False;
950 const beans::Property* pProps = rProperties.getConstArray();
951 for ( sal_Int32 n = 0; n < nCount; ++n )
953 const beans::Property& rProp = pProps[ n ];
955 // Process Core properties.
957 if ( rProp.Name == "ContentType" )
959 xRow->appendString ( rProp, rData.getContentType() );
961 else if ( rProp.Name == "Title" )
963 xRow->appendString ( rProp, rData.getTitle() );
965 else if ( rProp.Name == "IsDocument" )
967 xRow->appendBoolean( rProp, rData.getIsDocument() );
969 else if ( rProp.Name == "IsFolder" )
971 xRow->appendBoolean( rProp, rData.getIsFolder() );
973 else if ( rProp.Name == "CreatableContentsInfo" )
975 xRow->appendObject(
976 rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
978 else if ( rProp.Name == "Storage" )
980 // Storage is only supported by folders.
981 ContentType eType = rData.getType();
982 if ( eType == FOLDER )
983 xRow->appendObject(
984 rProp,
985 uno::makeAny(
986 pProvider->queryStorageClone( rContentId ) ) );
987 else
988 xRow->appendVoid( rProp );
990 else if ( rProp.Name == "DocumentModel" )
992 // DocumentModel is only supported by documents.
993 ContentType eType = rData.getType();
994 if ( eType == DOCUMENT )
995 xRow->appendObject(
996 rProp,
997 uno::makeAny(
998 pProvider->queryDocumentModel( rContentId ) ) );
999 else
1000 xRow->appendVoid( rProp );
1002 else
1004 // Not a Core Property! Maybe it's an Additional Core Property?!
1006 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1008 xAdditionalPropSet
1009 = uno::Reference< beans::XPropertySet >(
1010 pProvider->getAdditionalPropertySet( rContentId,
1011 sal_False ),
1012 uno::UNO_QUERY );
1013 bTriedToGetAdditonalPropSet = sal_True;
1016 if ( xAdditionalPropSet.is() )
1018 if ( !xRow->appendPropertySetValue(
1019 xAdditionalPropSet,
1020 rProp ) )
1022 // Append empty entry.
1023 xRow->appendVoid( rProp );
1026 else
1028 // Append empty entry.
1029 xRow->appendVoid( rProp );
1034 else
1036 // Append all Core Properties.
1037 xRow->appendString (
1038 beans::Property( OUString("ContentType"),
1040 getCppuType( static_cast< const OUString * >( 0 ) ),
1041 beans::PropertyAttribute::BOUND
1042 | beans::PropertyAttribute::READONLY ),
1043 rData.getContentType() );
1045 ContentType eType = rData.getType();
1047 xRow->appendString (
1048 beans::Property( OUString("Title"),
1050 getCppuType( static_cast< const OUString * >( 0 ) ),
1051 // Title is read-only for root and documents.
1052 beans::PropertyAttribute::BOUND ||
1053 ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1054 ? beans::PropertyAttribute::READONLY
1055 : 0 ),
1056 rData.getTitle() );
1057 xRow->appendBoolean(
1058 beans::Property( OUString("IsDocument"),
1060 getCppuBooleanType(),
1061 beans::PropertyAttribute::BOUND
1062 | beans::PropertyAttribute::READONLY ),
1063 rData.getIsDocument() );
1064 xRow->appendBoolean(
1065 beans::Property( OUString("IsFolder"),
1067 getCppuBooleanType(),
1068 beans::PropertyAttribute::BOUND
1069 | beans::PropertyAttribute::READONLY ),
1070 rData.getIsFolder() );
1071 xRow->appendObject(
1072 beans::Property(
1073 OUString("CreatableContentsInfo"),
1075 getCppuType( static_cast<
1076 const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1077 beans::PropertyAttribute::BOUND
1078 | beans::PropertyAttribute::READONLY ),
1079 uno::makeAny( rData.getCreatableContentsInfo() ) );
1081 // Storage is only supported by folders.
1082 if ( eType == FOLDER )
1083 xRow->appendObject(
1084 beans::Property( OUString("Storage"),
1086 getCppuType(
1087 static_cast<
1088 const uno::Reference< embed::XStorage > * >( 0 ) ),
1089 beans::PropertyAttribute::BOUND
1090 | beans::PropertyAttribute::READONLY ),
1091 uno::makeAny( pProvider->queryStorageClone( rContentId ) ) );
1093 // DocumentModel is only supported by documents.
1094 if ( eType == DOCUMENT )
1095 xRow->appendObject(
1096 beans::Property( OUString("DocumentModel"),
1098 getCppuType(
1099 static_cast<
1100 const uno::Reference< frame::XModel > * >( 0 ) ),
1101 beans::PropertyAttribute::BOUND
1102 | beans::PropertyAttribute::READONLY ),
1103 uno::makeAny(
1104 pProvider->queryDocumentModel( rContentId ) ) );
1106 // Append all Additional Core Properties.
1108 uno::Reference< beans::XPropertySet > xSet(
1109 pProvider->getAdditionalPropertySet( rContentId, sal_False ),
1110 uno::UNO_QUERY );
1111 xRow->appendPropertySet( xSet );
1114 return uno::Reference< sdbc::XRow >( xRow.get() );
1117 //=========================================================================
1118 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1119 const uno::Sequence< beans::Property >& rProperties )
1121 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1122 return getPropertyValues( m_xContext,
1123 rProperties,
1124 m_aProps,
1125 m_pProvider,
1126 m_xIdentifier->getContentIdentifier() );
1129 //=========================================================================
1130 uno::Sequence< uno::Any > Content::setPropertyValues(
1131 const uno::Sequence< beans::PropertyValue >& rValues,
1132 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1133 throw( uno::Exception )
1135 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1137 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1138 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1139 sal_Int32 nChanged = 0;
1141 beans::PropertyChangeEvent aEvent;
1142 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1143 aEvent.Further = sal_False;
1144 // aEvent.PropertyName =
1145 aEvent.PropertyHandle = -1;
1146 // aEvent.OldValue =
1147 // aEvent.NewValue =
1149 const beans::PropertyValue* pValues = rValues.getConstArray();
1150 sal_Int32 nCount = rValues.getLength();
1152 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1153 sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1155 sal_Bool bExchange = sal_False;
1156 OUString aOldTitle;
1157 sal_Int32 nTitlePos = -1;
1159 for ( sal_Int32 n = 0; n < nCount; ++n )
1161 const beans::PropertyValue& rValue = pValues[ n ];
1163 if ( rValue.Name == "ContentType" )
1165 // Read-only property!
1166 aRet[ n ] <<= lang::IllegalAccessException(
1167 OUString( "Property is read-only!" ),
1168 static_cast< cppu::OWeakObject * >( this ) );
1170 else if ( rValue.Name == "IsDocument" )
1172 // Read-only property!
1173 aRet[ n ] <<= lang::IllegalAccessException(
1174 OUString( "Property is read-only!" ),
1175 static_cast< cppu::OWeakObject * >( this ) );
1177 else if ( rValue.Name == "IsFolder" )
1179 // Read-only property!
1180 aRet[ n ] <<= lang::IllegalAccessException(
1181 OUString( "Property is read-only!" ),
1182 static_cast< cppu::OWeakObject * >( this ) );
1184 else if ( rValue.Name == "CreatableContentsInfo" )
1186 // Read-only property!
1187 aRet[ n ] <<= lang::IllegalAccessException(
1188 OUString( "Property is read-only!" ),
1189 static_cast< cppu::OWeakObject * >( this ) );
1191 else if ( rValue.Name == "Title" )
1193 // Title is read-only for root and documents.
1194 ContentType eType = m_aProps.getType();
1195 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1197 aRet[ n ] <<= lang::IllegalAccessException(
1198 OUString( "Property is read-only!" ),
1199 static_cast< cppu::OWeakObject * >( this ) );
1201 else
1203 OUString aNewValue;
1204 if ( rValue.Value >>= aNewValue )
1206 // No empty titles!
1207 if ( !aNewValue.isEmpty() )
1209 if ( aNewValue != m_aProps.getTitle() )
1211 // modified title -> modified URL -> exchange !
1212 if ( m_eState == PERSISTENT )
1213 bExchange = sal_True;
1215 aOldTitle = m_aProps.getTitle();
1216 m_aProps.setTitle( aNewValue );
1218 // property change event will be sent later...
1220 // remember position within sequence of values
1221 // (for error handling).
1222 nTitlePos = n;
1225 else
1227 aRet[ n ] <<= lang::IllegalArgumentException(
1228 OUString( "Empty Title not allowed!" ),
1229 static_cast< cppu::OWeakObject * >( this ),
1230 -1 );
1233 else
1235 aRet[ n ] <<= beans::IllegalTypeException(
1236 OUString( "Title Property value has wrong type!" ),
1237 static_cast< cppu::OWeakObject * >( this ) );
1241 else if ( rValue.Name == "Storage" )
1243 ContentType eType = m_aProps.getType();
1244 if ( eType == FOLDER )
1246 aRet[ n ] <<= lang::IllegalAccessException(
1247 OUString( "Property is read-only!" ),
1248 static_cast< cppu::OWeakObject * >( this ) );
1250 else
1252 // Storage is only supported by folders.
1253 aRet[ n ] <<= beans::UnknownPropertyException(
1254 OUString( "Storage property only supported by folders" ),
1255 static_cast< cppu::OWeakObject * >( this ) );
1258 else if ( rValue.Name == "DocumentModel" )
1260 ContentType eType = m_aProps.getType();
1261 if ( eType == DOCUMENT )
1263 aRet[ n ] <<= lang::IllegalAccessException(
1264 OUString( "Property is read-only!" ),
1265 static_cast< cppu::OWeakObject * >( this ) );
1267 else
1269 // Storage is only supported by folders.
1270 aRet[ n ] <<= beans::UnknownPropertyException(
1271 OUString( "DocumentModel property only supported by "
1272 "documents" ),
1273 static_cast< cppu::OWeakObject * >( this ) );
1276 else
1278 // Not a Core Property! Maybe it's an Additional Core Property?!
1280 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1282 xAdditionalPropSet = getAdditionalPropertySet( sal_False );
1283 bTriedToGetAdditonalPropSet = sal_True;
1286 if ( xAdditionalPropSet.is() )
1290 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1291 rValue.Name );
1292 if ( aOldValue != rValue.Value )
1294 xAdditionalPropSet->setPropertyValue(
1295 rValue.Name, rValue.Value );
1297 aEvent.PropertyName = rValue.Name;
1298 aEvent.OldValue = aOldValue;
1299 aEvent.NewValue = rValue.Value;
1301 aChanges.getArray()[ nChanged ] = aEvent;
1302 nChanged++;
1305 catch ( beans::UnknownPropertyException const & e )
1307 aRet[ n ] <<= e;
1309 catch ( lang::WrappedTargetException const & e )
1311 aRet[ n ] <<= e;
1313 catch ( beans::PropertyVetoException const & e )
1315 aRet[ n ] <<= e;
1317 catch ( lang::IllegalArgumentException const & e )
1319 aRet[ n ] <<= e;
1322 else
1324 aRet[ n ] <<= uno::Exception(
1325 OUString( "No property set for storing the value!" ),
1326 static_cast< cppu::OWeakObject * >( this ) );
1331 if ( bExchange )
1333 uno::Reference< ucb::XContentIdentifier > xOldId
1334 = m_xIdentifier;
1335 uno::Reference< ucb::XContentIdentifier > xNewId
1336 = makeNewIdentifier( m_aProps.getTitle() );
1338 aGuard.clear();
1339 if ( exchangeIdentity( xNewId ) )
1341 // Adapt persistent data.
1342 renameData( xOldId, xNewId );
1344 // Adapt Additional Core Properties.
1345 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1346 xNewId->getContentIdentifier(),
1347 sal_True );
1349 else
1351 // Roll-back.
1352 m_aProps.setTitle( aOldTitle );
1353 aOldTitle = OUString();
1355 // Set error .
1356 aRet[ nTitlePos ] <<= uno::Exception(
1357 OUString("Exchange failed!"),
1358 static_cast< cppu::OWeakObject * >( this ) );
1362 if ( !aOldTitle.isEmpty() )
1364 aEvent.PropertyName = OUString("Title");
1365 aEvent.OldValue = uno::makeAny( aOldTitle );
1366 aEvent.NewValue = uno::makeAny( m_aProps.getTitle() );
1368 aChanges.getArray()[ nChanged ] = aEvent;
1369 nChanged++;
1372 if ( nChanged > 0 )
1374 // Save changes, if content was already made persistent.
1375 if ( !bExchange && ( m_eState == PERSISTENT ) )
1377 if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1379 uno::Any aProps
1380 = uno::makeAny(
1381 beans::PropertyValue(
1382 OUString( "Uri"),
1384 uno::makeAny(m_xIdentifier->
1385 getContentIdentifier()),
1386 beans::PropertyState_DIRECT_VALUE));
1387 ucbhelper::cancelCommandExecution(
1388 ucb::IOErrorCode_CANT_WRITE,
1389 uno::Sequence< uno::Any >(&aProps, 1),
1390 xEnv,
1391 OUString( "Cannot store persistent data!" ),
1392 this );
1393 // Unreachable
1397 aChanges.realloc( nChanged );
1399 aGuard.clear();
1400 notifyPropertiesChange( aChanges );
1403 return aRet;
1406 //=========================================================================
1407 uno::Any Content::open(
1408 const ucb::OpenCommandArgument2& rArg,
1409 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1410 throw( uno::Exception )
1412 if ( rArg.Mode == ucb::OpenMode::ALL ||
1413 rArg.Mode == ucb::OpenMode::FOLDERS ||
1414 rArg.Mode == ucb::OpenMode::DOCUMENTS )
1416 //////////////////////////////////////////////////////////////////
1417 // open command for a folder content
1418 //////////////////////////////////////////////////////////////////
1420 uno::Reference< ucb::XDynamicResultSet > xSet
1421 = new DynamicResultSet( m_xContext, this, rArg );
1422 return uno::makeAny( xSet );
1424 else
1426 //////////////////////////////////////////////////////////////////
1427 // open command for a document content
1428 //////////////////////////////////////////////////////////////////
1430 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1431 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1433 // Currently(?) unsupported.
1434 ucbhelper::cancelCommandExecution(
1435 uno::makeAny( ucb::UnsupportedOpenModeException(
1436 OUString(),
1437 static_cast< cppu::OWeakObject * >( this ),
1438 sal_Int16( rArg.Mode ) ) ),
1439 xEnv );
1440 // Unreachable
1443 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1445 uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1446 rArg.Sink, uno::UNO_QUERY );
1447 if ( xDataStreamer.is() )
1449 // May throw CommandFailedException, DocumentPasswordRequest!
1450 uno::Reference< io::XStream > xStream = getStream( xEnv );
1451 if ( !xStream.is() )
1453 // No interaction if we are not persistent!
1454 uno::Any aProps
1455 = uno::makeAny(
1456 beans::PropertyValue(
1457 OUString( "Uri"),
1459 uno::makeAny(m_xIdentifier->
1460 getContentIdentifier()),
1461 beans::PropertyState_DIRECT_VALUE));
1462 ucbhelper::cancelCommandExecution(
1463 ucb::IOErrorCode_CANT_READ,
1464 uno::Sequence< uno::Any >(&aProps, 1),
1465 m_eState == PERSISTENT
1466 ? xEnv
1467 : uno::Reference< ucb::XCommandEnvironment >(),
1468 OUString( "Got no data stream!" ),
1469 this );
1470 // Unreachable
1473 // Done.
1474 xDataStreamer->setStream( xStream );
1476 else
1478 uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1479 if ( xOut.is() )
1481 // PUSH: write data into xOut
1483 // May throw CommandFailedException, DocumentPasswordRequest!
1484 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1485 if ( !xIn.is() )
1487 // No interaction if we are not persistent!
1488 uno::Any aProps
1489 = uno::makeAny(
1490 beans::PropertyValue(
1491 OUString( "Uri"),
1493 uno::makeAny(m_xIdentifier->
1494 getContentIdentifier()),
1495 beans::PropertyState_DIRECT_VALUE));
1496 ucbhelper::cancelCommandExecution(
1497 ucb::IOErrorCode_CANT_READ,
1498 uno::Sequence< uno::Any >(&aProps, 1),
1499 m_eState == PERSISTENT
1500 ? xEnv
1501 : uno::Reference< ucb::XCommandEnvironment >(),
1502 OUString("Got no data stream!"),
1503 this );
1504 // Unreachable
1509 uno::Sequence< sal_Int8 > aBuffer;
1510 sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1512 while ( nRead > 0 )
1514 aBuffer.realloc( nRead );
1515 xOut->writeBytes( aBuffer );
1516 aBuffer.realloc( 0 );
1517 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1520 xOut->closeOutput();
1522 catch ( io::NotConnectedException const & )
1524 // closeOutput, readSomeBytes, writeBytes
1526 catch ( io::BufferSizeExceededException const & )
1528 // closeOutput, readSomeBytes, writeBytes
1530 catch ( io::IOException const & )
1532 // closeOutput, readSomeBytes, writeBytes
1535 else
1537 uno::Reference< io::XActiveDataSink > xDataSink(
1538 rArg.Sink, uno::UNO_QUERY );
1539 if ( xDataSink.is() )
1541 // PULL: wait for client read
1543 // May throw CommandFailedException, DocumentPasswordRequest!
1544 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1545 if ( !xIn.is() )
1547 // No interaction if we are not persistent!
1548 uno::Any aProps
1549 = uno::makeAny(
1550 beans::PropertyValue(
1551 OUString( "Uri"),
1553 uno::makeAny(m_xIdentifier->
1554 getContentIdentifier()),
1555 beans::PropertyState_DIRECT_VALUE));
1556 ucbhelper::cancelCommandExecution(
1557 ucb::IOErrorCode_CANT_READ,
1558 uno::Sequence< uno::Any >(&aProps, 1),
1559 m_eState == PERSISTENT
1560 ? xEnv
1561 : uno::Reference<
1562 ucb::XCommandEnvironment >(),
1563 OUString( "Got no data stream!" ),
1564 this );
1565 // Unreachable
1568 // Done.
1569 xDataSink->setInputStream( xIn );
1571 else
1573 ucbhelper::cancelCommandExecution(
1574 uno::makeAny(
1575 ucb::UnsupportedDataSinkException(
1576 OUString(),
1577 static_cast< cppu::OWeakObject * >( this ),
1578 rArg.Sink ) ),
1579 xEnv );
1580 // Unreachable
1586 return uno::Any();
1589 //=========================================================================
1590 void Content::insert( const uno::Reference< io::XInputStream >& xData,
1591 sal_Int32 nNameClashResolve,
1592 const uno::Reference<
1593 ucb::XCommandEnvironment > & xEnv )
1594 throw( uno::Exception )
1596 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1598 ContentType eType = m_aProps.getType();
1600 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1601 "insert command only supported by streams and folders!" );
1603 Uri aUri( m_xIdentifier->getContentIdentifier() );
1605 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
1606 #if OSL_DEBUG_LEVEL > 0
1607 if ( eType == STREAM )
1609 Uri aParentUri( aUri.getParentUri() );
1610 OSL_ENSURE( !aParentUri.isDocument(),
1611 "insert command not supported by streams that are direct "
1612 "children of document root!" );
1614 #endif
1615 #endif
1617 // Check, if all required properties were set.
1618 if ( eType == FOLDER )
1620 // Required: Title
1622 if ( m_aProps.getTitle().isEmpty() )
1623 m_aProps.setTitle( aUri.getDecodedName() );
1625 else // stream
1627 // Required: data
1629 if ( !xData.is() )
1631 ucbhelper::cancelCommandExecution(
1632 uno::makeAny( ucb::MissingInputStreamException(
1633 OUString(),
1634 static_cast< cppu::OWeakObject * >( this ) ) ),
1635 xEnv );
1636 // Unreachable
1639 // Required: Title
1641 if ( m_aProps.getTitle().isEmpty() )
1642 m_aProps.setTitle( aUri.getDecodedName() );
1645 OUStringBuffer aNewURL = aUri.getParentUri();
1646 aNewURL.append( m_aProps.getTitle() );
1647 Uri aNewUri( aNewURL.makeStringAndClear() );
1649 // Handle possible name clash...
1650 switch ( nNameClashResolve )
1652 // fail.
1653 case ucb::NameClash::ERROR:
1654 if ( hasData( aNewUri ) )
1656 ucbhelper::cancelCommandExecution(
1657 uno::makeAny( ucb::NameClashException(
1658 OUString(),
1659 static_cast< cppu::OWeakObject * >( this ),
1660 task::InteractionClassification_ERROR,
1661 m_aProps.getTitle() ) ),
1662 xEnv );
1663 // Unreachable
1665 break;
1667 // replace (possibly) existing object.
1668 case ucb::NameClash::OVERWRITE:
1669 break;
1671 // "invent" a new valid title.
1672 case ucb::NameClash::RENAME:
1673 if ( hasData( aNewUri ) )
1675 sal_Int32 nTry = 0;
1679 OUStringBuffer aNew = aNewUri.getUri();
1680 aNew.appendAscii( "_" );
1681 aNew.append( OUString::valueOf( ++nTry ) );
1682 aNewUri.setUri( aNew.makeStringAndClear() );
1684 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1686 if ( nTry == 1000 )
1688 ucbhelper::cancelCommandExecution(
1689 uno::makeAny(
1690 ucb::UnsupportedNameClashException(
1691 OUString( "Unable to resolve name clash!" ),
1692 static_cast< cppu::OWeakObject * >( this ),
1693 nNameClashResolve ) ),
1694 xEnv );
1695 // Unreachable
1697 else
1699 OUStringBuffer aNewTitle = m_aProps.getTitle();
1700 aNewTitle.appendAscii( "_" );
1701 aNewTitle.append( OUString::valueOf( ++nTry ) );
1702 m_aProps.setTitle( aNewTitle.makeStringAndClear() );
1705 break;
1707 case ucb::NameClash::KEEP: // deprecated
1708 case ucb::NameClash::ASK:
1709 default:
1710 if ( hasData( aNewUri ) )
1712 ucbhelper::cancelCommandExecution(
1713 uno::makeAny(
1714 ucb::UnsupportedNameClashException(
1715 OUString(),
1716 static_cast< cppu::OWeakObject * >( this ),
1717 nNameClashResolve ) ),
1718 xEnv );
1719 // Unreachable
1721 break;
1724 // Identifier changed?
1725 sal_Bool bNewId = ( aUri != aNewUri );
1727 if ( bNewId )
1729 m_xIdentifier
1730 = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1733 if ( !storeData( xData, xEnv ) )
1735 uno::Any aProps
1736 = uno::makeAny(beans::PropertyValue(
1737 OUString( "Uri"),
1739 uno::makeAny(m_xIdentifier->
1740 getContentIdentifier()),
1741 beans::PropertyState_DIRECT_VALUE));
1742 ucbhelper::cancelCommandExecution(
1743 ucb::IOErrorCode_CANT_WRITE,
1744 uno::Sequence< uno::Any >(&aProps, 1),
1745 xEnv,
1746 OUString("Cannot store persistent data!"),
1747 this );
1748 // Unreachable
1751 m_eState = PERSISTENT;
1753 if ( bNewId )
1755 //loadData( m_pProvider, m_aUri, m_aProps );
1757 aGuard.clear();
1758 inserted();
1762 //=========================================================================
1763 void Content::destroy( sal_Bool bDeletePhysical,
1764 const uno::Reference<
1765 ucb::XCommandEnvironment > & xEnv )
1766 throw( uno::Exception )
1768 // @@@ take care about bDeletePhysical -> trashcan support
1770 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1772 ContentType eType = m_aProps.getType();
1774 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1775 "delete command only supported by streams and folders!" );
1777 uno::Reference< ucb::XContent > xThis = this;
1779 // Persistent?
1780 if ( m_eState != PERSISTENT )
1782 ucbhelper::cancelCommandExecution(
1783 uno::makeAny( ucb::UnsupportedCommandException(
1784 OUString( "Not persistent!" ),
1785 static_cast< cppu::OWeakObject * >( this ) ) ),
1786 xEnv );
1787 // Unreachable
1790 m_eState = DEAD;
1792 aGuard.clear();
1793 deleted();
1795 if ( eType == FOLDER )
1797 // Process instanciated children...
1799 ContentRefList aChildren;
1800 queryChildren( aChildren );
1802 ContentRefList::const_iterator it = aChildren.begin();
1803 ContentRefList::const_iterator end = aChildren.end();
1805 while ( it != end )
1807 (*it)->destroy( bDeletePhysical, xEnv );
1808 ++it;
1813 //=========================================================================
1814 void Content::notifyDocumentClosed()
1816 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1818 m_eState = DEAD;
1820 // @@@ anything else to reset or such?
1822 // callback follows!
1823 aGuard.clear();
1825 // Propagate destruction to content event listeners
1826 // Remove this from provider's content list.
1827 deleted();
1830 //=========================================================================
1831 uno::Reference< ucb::XContent >
1832 Content::queryChildContent( const OUString & rRelativeChildUri )
1834 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1836 const OUString aMyId = getIdentifier()->getContentIdentifier();
1837 OUStringBuffer aBuf( aMyId );
1838 if ( aMyId.getStr()[ aMyId.getLength() - 1 ] != sal_Unicode( '/' ) )
1839 aBuf.appendAscii( "/" );
1840 if ( rRelativeChildUri.getStr()[ 0 ] != sal_Unicode( '/' ) )
1841 aBuf.append( rRelativeChildUri );
1842 else
1843 aBuf.append( rRelativeChildUri.copy( 1 ) );
1845 uno::Reference< ucb::XContentIdentifier > xChildId
1846 = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1848 uno::Reference< ucb::XContent > xChild;
1851 xChild = m_pProvider->queryContent( xChildId );
1853 catch ( ucb::IllegalIdentifierException const & )
1855 // handled below.
1858 OSL_ENSURE( xChild.is(),
1859 "Content::queryChildContent - unable to create child content!" );
1860 return xChild;
1863 //=========================================================================
1864 void Content::notifyChildRemoved( const OUString & rRelativeChildUri )
1866 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1868 // Ugly! Need to create child content object, just to fill event properly.
1869 uno::Reference< ucb::XContent > xChild
1870 = queryChildContent( rRelativeChildUri );
1872 if ( xChild.is() )
1874 // callback follows!
1875 aGuard.clear();
1877 // Notify "REMOVED" event.
1878 ucb::ContentEvent aEvt(
1879 static_cast< cppu::OWeakObject * >( this ),
1880 ucb::ContentAction::REMOVED,
1881 xChild,
1882 getIdentifier() );
1883 notifyContentEvent( aEvt );
1887 //=========================================================================
1888 void Content::notifyChildInserted( const OUString & rRelativeChildUri )
1890 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1892 // Ugly! Need to create child content object, just to fill event properly.
1893 uno::Reference< ucb::XContent > xChild
1894 = queryChildContent( rRelativeChildUri );
1896 if ( xChild.is() )
1898 // callback follows!
1899 aGuard.clear();
1901 // Notify "INSERTED" event.
1902 ucb::ContentEvent aEvt(
1903 static_cast< cppu::OWeakObject * >( this ),
1904 ucb::ContentAction::INSERTED,
1905 xChild,
1906 getIdentifier() );
1907 notifyContentEvent( aEvt );
1911 //=========================================================================
1912 void Content::transfer(
1913 const ucb::TransferInfo& rInfo,
1914 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1915 throw( uno::Exception )
1917 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1919 // Persistent?
1920 if ( m_eState != PERSISTENT )
1922 ucbhelper::cancelCommandExecution(
1923 uno::makeAny( ucb::UnsupportedCommandException(
1924 OUString( "Not persistent!" ),
1925 static_cast< cppu::OWeakObject * >( this ) ) ),
1926 xEnv );
1927 // Unreachable
1930 // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1932 if ( ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 ) )
1934 // Invaild length (to short).
1935 ucbhelper::cancelCommandExecution(
1936 uno::makeAny( ucb::InteractiveBadTransferURLException(
1937 OUString(),
1938 static_cast< cppu::OWeakObject * >( this ) ) ),
1939 xEnv );
1940 // Unreachable
1943 OUString aScheme
1944 = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1945 .toAsciiLowerCase();
1946 if ( aScheme != TDOC_URL_SCHEME ":/" )
1948 // Invalid scheme.
1949 ucbhelper::cancelCommandExecution(
1950 uno::makeAny( ucb::InteractiveBadTransferURLException(
1951 OUString(),
1952 static_cast< cppu::OWeakObject * >( this ) ) ),
1953 xEnv );
1954 // Unreachable
1957 // Does source URI describe a tdoc folder or stream?
1958 Uri aSourceUri( rInfo.SourceURL );
1959 if ( !aSourceUri.isValid() )
1961 ucbhelper::cancelCommandExecution(
1962 uno::makeAny( lang::IllegalArgumentException(
1963 OUString( "Invalid source URI! Syntax!" ),
1964 static_cast< cppu::OWeakObject * >( this ),
1965 -1 ) ),
1966 xEnv );
1967 // Unreachable
1970 if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1972 ucbhelper::cancelCommandExecution(
1973 uno::makeAny( lang::IllegalArgumentException(
1974 OUString( "Invalid source URI! "
1975 "Must describe a folder or stream!" ),
1976 static_cast< cppu::OWeakObject * >( this ),
1977 -1 ) ),
1978 xEnv );
1979 // Unreachable
1982 // Is source not a parent of me / not me?
1983 OUString aId = m_xIdentifier->getContentIdentifier();
1984 sal_Int32 nPos = aId.lastIndexOf( '/' );
1985 if ( nPos != ( aId.getLength() - 1 ) )
1987 // No trailing slash found. Append.
1988 aId += OUString("/");
1991 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1993 if ( aId.compareTo(
1994 rInfo.SourceURL, rInfo.SourceURL.getLength() ) == 0 )
1996 uno::Any aProps
1997 = uno::makeAny(beans::PropertyValue(
1998 OUString( "Uri"),
2000 uno::makeAny( rInfo.SourceURL ),
2001 beans::PropertyState_DIRECT_VALUE));
2002 ucbhelper::cancelCommandExecution(
2003 ucb::IOErrorCode_RECURSIVE,
2004 uno::Sequence< uno::Any >(&aProps, 1),
2005 xEnv,
2006 OUString( "Target is equal to or is a child of source!" ),
2007 this );
2008 // Unreachable
2012 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
2013 if ( m_aProps.getType() == DOCUMENT )
2015 bool bOK = false;
2017 uno::Reference< embed::XStorage > xStorage
2018 = m_pProvider->queryStorage(
2019 aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
2020 if ( xStorage.is() )
2024 if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
2026 ucbhelper::cancelCommandExecution(
2027 uno::makeAny( lang::IllegalArgumentException(
2028 OUString( "Invalid source URI! "
2029 "Streams cannot be created as "
2030 "children of document root!" ),
2031 static_cast< cppu::OWeakObject * >(
2032 this ),
2033 -1 ) ),
2034 xEnv );
2035 // Unreachable
2037 bOK = true;
2039 catch ( container::NoSuchElementException const & )
2041 // handled below.
2043 catch ( lang::IllegalArgumentException const & )
2045 // handled below.
2047 catch ( embed::InvalidStorageException const & )
2049 // handled below.
2053 if ( !bOK )
2055 ucbhelper::cancelCommandExecution(
2056 uno::makeAny( lang::IllegalArgumentException(
2057 OUString( "Invalid source URI! "
2058 "Unabale to determine source type!" ),
2059 static_cast< cppu::OWeakObject * >( this ),
2060 -1 ) ),
2061 xEnv );
2062 // Unreachable
2065 #endif
2067 /////////////////////////////////////////////////////////////////////////
2068 // Copy data.
2069 /////////////////////////////////////////////////////////////////////////
2071 OUString aNewName( !rInfo.NewTitle.isEmpty()
2072 ? rInfo.NewTitle
2073 : aSourceUri.getDecodedName() );
2075 if ( !copyData( aSourceUri, aNewName ) )
2077 uno::Any aProps
2078 = uno::makeAny(
2079 beans::PropertyValue(
2080 OUString( "Uri"),
2082 uno::makeAny( rInfo.SourceURL ),
2083 beans::PropertyState_DIRECT_VALUE));
2084 ucbhelper::cancelCommandExecution(
2085 ucb::IOErrorCode_CANT_WRITE,
2086 uno::Sequence< uno::Any >(&aProps, 1),
2087 xEnv,
2088 OUString( "Cannot copy data!" ),
2089 this );
2090 // Unreachable
2093 /////////////////////////////////////////////////////////////////////////
2094 // Copy own and all children's Additional Core Properties.
2095 /////////////////////////////////////////////////////////////////////////
2097 OUString aTargetUri = m_xIdentifier->getContentIdentifier();
2098 if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
2099 aTargetUri += OUString("/");
2101 if ( !rInfo.NewTitle.isEmpty() )
2102 aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
2103 else
2104 aTargetUri += aSourceUri.getName();
2106 if ( !copyAdditionalPropertySet(
2107 aSourceUri.getUri(), aTargetUri, sal_True ) )
2109 uno::Any aProps
2110 = uno::makeAny(
2111 beans::PropertyValue(
2112 OUString( "Uri"),
2114 uno::makeAny( rInfo.SourceURL ),
2115 beans::PropertyState_DIRECT_VALUE));
2116 ucbhelper::cancelCommandExecution(
2117 ucb::IOErrorCode_CANT_WRITE,
2118 uno::Sequence< uno::Any >(&aProps, 1),
2119 xEnv,
2120 OUString( "Cannot copy additional properties!" ),
2121 this );
2122 // Unreachable
2125 /////////////////////////////////////////////////////////////////////////
2126 // Propagate new content.
2127 /////////////////////////////////////////////////////////////////////////
2129 rtl::Reference< Content > xTarget;
2132 uno::Reference< ucb::XContentIdentifier > xTargetId
2133 = new ::ucbhelper::ContentIdentifier( aTargetUri );
2135 // Note: The static cast is okay here, because its sure that
2136 // m_xProvider is always the WebDAVContentProvider.
2137 xTarget = static_cast< Content * >(
2138 m_pProvider->queryContent( xTargetId ).get() );
2141 catch ( ucb::IllegalIdentifierException const & )
2143 // queryContent
2146 if ( !xTarget.is() )
2148 uno::Any aProps
2149 = uno::makeAny(beans::PropertyValue(
2150 OUString( "Uri"),
2152 uno::makeAny( aTargetUri ),
2153 beans::PropertyState_DIRECT_VALUE));
2154 ucbhelper::cancelCommandExecution(
2155 ucb::IOErrorCode_CANT_READ,
2156 uno::Sequence< uno::Any >(&aProps, 1),
2157 xEnv,
2158 OUString( "Cannot instanciate target object!" ),
2159 this );
2160 // Unreachable
2163 // Announce transferred content in its new folder.
2164 xTarget->inserted();
2166 /////////////////////////////////////////////////////////////////////////
2167 // Remove source, if requested
2168 /////////////////////////////////////////////////////////////////////////
2170 if ( rInfo.MoveData )
2172 rtl::Reference< Content > xSource;
2175 uno::Reference< ucb::XContentIdentifier >
2176 xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2178 // Note: The static cast is okay here, because its sure
2179 // that m_xProvider is always the ContentProvider.
2180 xSource = static_cast< Content * >(
2181 m_xProvider->queryContent( xSourceId ).get() );
2183 catch ( ucb::IllegalIdentifierException const & )
2185 // queryContent
2188 if ( !xSource.is() )
2190 uno::Any aProps
2191 = uno::makeAny(beans::PropertyValue(
2192 OUString( "Uri"),
2194 uno::makeAny( rInfo.SourceURL ),
2195 beans::PropertyState_DIRECT_VALUE));
2196 ucbhelper::cancelCommandExecution(
2197 ucb::IOErrorCode_CANT_READ,
2198 uno::Sequence< uno::Any >(&aProps, 1),
2199 xEnv,
2200 OUString( "Cannot instanciate target object!" ),
2201 this );
2202 // Unreachable
2205 // Propagate destruction (recursively).
2206 xSource->destroy( sal_True, xEnv );
2208 // Remove all persistent data of source and its children.
2209 if ( !xSource->removeData() )
2211 uno::Any aProps
2212 = uno::makeAny(
2213 beans::PropertyValue(
2214 OUString( "Uri"),
2216 uno::makeAny( rInfo.SourceURL ),
2217 beans::PropertyState_DIRECT_VALUE));
2218 ucbhelper::cancelCommandExecution(
2219 ucb::IOErrorCode_CANT_WRITE,
2220 uno::Sequence< uno::Any >(&aProps, 1),
2221 xEnv,
2222 OUString( "Cannot remove persistent data of source object!" ),
2223 this );
2224 // Unreachable
2227 // Remove own and all children's Additional Core Properties.
2228 if ( !xSource->removeAdditionalPropertySet( sal_True ) )
2230 uno::Any aProps
2231 = uno::makeAny(
2232 beans::PropertyValue(
2233 OUString( "Uri"),
2235 uno::makeAny( rInfo.SourceURL ),
2236 beans::PropertyState_DIRECT_VALUE));
2237 ucbhelper::cancelCommandExecution(
2238 ucb::IOErrorCode_CANT_WRITE,
2239 uno::Sequence< uno::Any >(&aProps, 1),
2240 xEnv,
2241 OUString( "Cannot remove additional properties of source object!" ),
2242 this );
2243 // Unreachable
2246 } // rInfo.MoveData
2249 //=========================================================================
2250 //static
2251 bool Content::hasData( ContentProvider* pProvider, const Uri & rUri )
2253 if ( rUri.isRoot() )
2255 return true; // root has no storage
2257 else if ( rUri.isDocument() )
2259 uno::Reference< embed::XStorage > xStorage
2260 = pProvider->queryStorage( rUri.getUri(), READ );
2261 return xStorage.is();
2263 else
2265 // folder or stream
2267 // Ask parent storage. In case that rUri describes a stream,
2268 // ContentProvider::queryStorage( rUri ) would return null.
2270 uno::Reference< embed::XStorage > xStorage
2271 = pProvider->queryStorage( rUri.getParentUri(), READ );
2273 if ( !xStorage.is() )
2274 return false;
2276 uno::Reference< container::XNameAccess > xParentNA(
2277 xStorage, uno::UNO_QUERY );
2279 OSL_ENSURE( xParentNA.is(), "Got no css.container.XNameAccess!" );
2281 return xParentNA->hasByName( rUri.getDecodedName() );
2285 //=========================================================================
2286 //static
2287 bool Content::loadData( ContentProvider* pProvider,
2288 const Uri & rUri,
2289 ContentProperties& rProps )
2291 if ( rUri.isRoot() ) // root has no storage, but can always be created
2293 rProps
2294 = ContentProperties(
2295 ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2297 else if ( rUri.isDocument() ) // document must have storage
2299 uno::Reference< embed::XStorage > xStorage
2300 = pProvider->queryStorage( rUri.getUri(), READ );
2302 if ( !xStorage.is() )
2303 return false;
2305 rProps
2306 = ContentProperties(
2307 DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2309 else // stream or folder; stream has no storage; folder has storage
2311 uno::Reference< embed::XStorage > xStorage
2312 = pProvider->queryStorage( rUri.getParentUri(), READ );
2314 if ( !xStorage.is() )
2315 return false;
2317 // Check whether exists at all, is stream or folder
2320 // return: true -> folder
2321 // return: false -> stream
2322 // NoSuchElementException -> neither folder nor stream
2323 bool bIsFolder
2324 = xStorage->isStorageElement( rUri.getDecodedName() );
2326 rProps
2327 = ContentProperties(
2328 bIsFolder ? FOLDER : STREAM,
2329 pProvider->queryStorageTitle( rUri.getUri() ) );
2331 catch ( container::NoSuchElementException const & )
2333 // there is no element with such name
2334 //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2335 return false;
2337 catch ( lang::IllegalArgumentException const & )
2339 // an illegal argument is provided
2340 OSL_FAIL( "Caught IllegalArgumentException!" );
2341 return false;
2343 catch ( embed::InvalidStorageException const & )
2345 // this storage is in invalid state for any reason
2346 OSL_FAIL( "Caught InvalidStorageException!" );
2347 return false;
2350 return true;
2353 //=========================================================================
2354 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2355 const uno::Reference<
2356 ucb::XCommandEnvironment >& xEnv )
2357 throw ( ucb::CommandFailedException,
2358 task::DocumentPasswordRequest )
2360 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2362 ContentType eType = m_aProps.getType();
2363 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2365 OSL_FAIL( "storeData not supported by root and documents!" );
2366 return false;
2369 Uri aUri( m_xIdentifier->getContentIdentifier() );
2371 if ( eType == FOLDER )
2373 uno::Reference< embed::XStorage > xStorage
2374 = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2376 if ( !xStorage.is() )
2377 return false;
2379 uno::Reference< beans::XPropertySet > xPropSet(
2380 xStorage, uno::UNO_QUERY );
2381 OSL_ENSURE( xPropSet.is(),
2382 "Content::storeData - Got no XPropertySet interface!" );
2383 if ( !xPropSet.is() )
2384 return false;
2388 // According to MBA, if no mediatype is set, folder and all
2389 // its contents will be lost on save of the document!!!
2390 xPropSet->setPropertyValue(
2391 OUString( "MediaType" ),
2392 uno::makeAny(
2393 OUString( // @@@ better mediatype
2394 "application/binary" ) ) );
2396 catch ( beans::UnknownPropertyException const & )
2398 OSL_FAIL( "Property MediaType not supported!" );
2399 return false;
2401 catch ( beans::PropertyVetoException const & )
2403 OSL_FAIL( "Caught PropertyVetoException!" );
2404 return false;
2406 catch ( lang::IllegalArgumentException const & )
2408 OSL_FAIL( "Caught IllegalArgumentException!" );
2409 return false;
2411 catch ( lang::WrappedTargetException const & )
2413 OSL_FAIL( "Caught WrappedTargetException!" );
2414 return false;
2417 if ( !commitStorage( xStorage ) )
2418 return false;
2420 else if ( eType == STREAM )
2422 // stream
2424 // Important: Parent storage and output stream must be kept alive until
2425 // changes have been committed!
2426 uno::Reference< embed::XStorage > xStorage
2427 = m_pProvider->queryStorage(
2428 aUri.getParentUri(), READ_WRITE_CREATE );
2429 uno::Reference< io::XOutputStream > xOut;
2431 if ( !xStorage.is() )
2432 return false;
2434 if ( xData.is() )
2436 // May throw CommandFailedException, DocumentPasswordRequest!
2437 xOut = getTruncatedOutputStream( xEnv );
2439 OSL_ENSURE( xOut.is(), "No target data stream!" );
2443 uno::Sequence< sal_Int8 > aBuffer;
2444 sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2446 while ( nRead > 0 )
2448 aBuffer.realloc( nRead );
2449 xOut->writeBytes( aBuffer );
2450 aBuffer.realloc( 0 );
2451 nRead = xData->readSomeBytes( aBuffer, 65536 );
2454 closeOutputStream( xOut );
2456 catch ( io::NotConnectedException const & )
2458 // readSomeBytes, writeBytes
2459 OSL_FAIL( "Caught NotConnectedException!" );
2460 closeOutputStream( xOut );
2461 return false;
2463 catch ( io::BufferSizeExceededException const & )
2465 // readSomeBytes, writeBytes
2466 OSL_FAIL( "Caught BufferSizeExceededException!" );
2467 closeOutputStream( xOut );
2468 return false;
2470 catch ( io::IOException const & )
2472 // readSomeBytes, writeBytes
2473 OSL_FAIL( "Caught IOException!" );
2474 closeOutputStream( xOut );
2475 return false;
2477 catch ( ... )
2479 closeOutputStream( xOut );
2480 throw;
2484 // Commit changes.
2485 if ( !commitStorage( xStorage ) )
2486 return false;
2488 else
2490 OSL_FAIL( "Unknown content type!" );
2491 return false;
2493 return true;
2496 //=========================================================================
2497 bool Content::renameData(
2498 const uno::Reference< ucb::XContentIdentifier >& xOldId,
2499 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2501 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2503 ContentType eType = m_aProps.getType();
2504 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2506 OSL_FAIL( "renameData not supported by root and documents!" );
2507 return false;
2510 Uri aOldUri( xOldId->getContentIdentifier() );
2511 uno::Reference< embed::XStorage > xStorage
2512 = m_pProvider->queryStorage(
2513 aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2515 if ( !xStorage.is() )
2516 return false;
2520 Uri aNewUri( xNewId->getContentIdentifier() );
2521 xStorage->renameElement(
2522 aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2524 catch ( embed::InvalidStorageException const & )
2526 // this storage is in invalid state for eny reason
2527 OSL_FAIL( "Caught InvalidStorageException!" );
2528 return false;
2530 catch ( lang::IllegalArgumentException const & )
2532 // an illegal argument is provided
2533 OSL_FAIL( "Caught IllegalArgumentException!" );
2534 return false;
2536 catch ( container::NoSuchElementException const & )
2538 // there is no element with old name in this storage
2539 OSL_FAIL( "Caught NoSuchElementException!" );
2540 return false;
2542 catch ( container::ElementExistException const & )
2544 // an element with new name already exists in this storage
2545 OSL_FAIL( "Caught ElementExistException!" );
2546 return false;
2548 catch ( io::IOException const & )
2550 // in case of io errors during renaming
2551 OSL_FAIL( "Caught IOException!" );
2552 return false;
2554 catch ( embed::StorageWrappedTargetException const & )
2556 // wraps other exceptions
2557 OSL_FAIL( "Caught StorageWrappedTargetException!" );
2558 return false;
2561 return commitStorage( xStorage );
2564 //=========================================================================
2565 bool Content::removeData()
2567 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2569 ContentType eType = m_aProps.getType();
2570 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2572 OSL_FAIL( "removeData not supported by root and documents!" );
2573 return false;
2576 Uri aUri( m_xIdentifier->getContentIdentifier() );
2577 uno::Reference< embed::XStorage > xStorage
2578 = m_pProvider->queryStorage(
2579 aUri.getParentUri(), READ_WRITE_NOCREATE );
2581 if ( !xStorage.is() )
2582 return false;
2586 xStorage->removeElement( aUri.getDecodedName() );
2588 catch ( embed::InvalidStorageException const & )
2590 // this storage is in invalid state for eny reason
2591 OSL_FAIL( "Caught InvalidStorageException!" );
2592 return false;
2594 catch ( lang::IllegalArgumentException const & )
2596 // an illegal argument is provided
2597 OSL_FAIL( "Caught IllegalArgumentException!" );
2598 return false;
2600 catch ( container::NoSuchElementException const & )
2602 // there is no element with this name in this storage
2603 OSL_FAIL( "Caught NoSuchElementException!" );
2604 return false;
2606 catch ( io::IOException const & )
2608 // in case of io errors during renaming
2609 OSL_FAIL( "Caught IOException!" );
2610 return false;
2612 catch ( embed::StorageWrappedTargetException const & )
2614 // wraps other exceptions
2615 OSL_FAIL( "Caught StorageWrappedTargetException!" );
2616 return false;
2619 return commitStorage( xStorage );
2622 //=========================================================================
2623 bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2625 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2627 ContentType eType = m_aProps.getType();
2628 if ( ( eType == ROOT ) || ( eType == STREAM ) )
2630 OSL_FAIL( "copyData not supported by root and streams!" );
2631 return false;
2634 Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2635 uno::Reference< embed::XStorage > xDestStorage
2636 = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2638 if ( !xDestStorage.is() )
2639 return false;
2641 uno::Reference< embed::XStorage > xSourceStorage
2642 = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2644 if ( !xSourceStorage.is() )
2645 return false;
2649 xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2650 xDestStorage,
2651 rNewName );
2653 catch ( embed::InvalidStorageException const & )
2655 // this storage is in invalid state for eny reason
2656 OSL_FAIL( "Caught InvalidStorageException!" );
2657 return false;
2659 catch ( lang::IllegalArgumentException const & )
2661 // an illegal argument is provided
2662 OSL_FAIL( "Caught IllegalArgumentException!" );
2663 return false;
2665 catch ( container::NoSuchElementException const & )
2667 // there is no element with this name in this storage
2668 OSL_FAIL( "Caught NoSuchElementException!" );
2669 return false;
2671 catch ( container::ElementExistException const & )
2673 // there is no element with this name in this storage
2674 OSL_FAIL( "Caught ElementExistException!" );
2675 return false;
2677 catch ( io::IOException const & )
2679 // in case of io errors during renaming
2680 OSL_FAIL( "Caught IOException!" );
2681 return false;
2683 catch ( embed::StorageWrappedTargetException const & )
2685 // wraps other exceptions
2686 OSL_FAIL( "Caught StorageWrappedTargetException!" );
2687 return false;
2690 return commitStorage( xDestStorage );
2693 //=========================================================================
2694 // static
2695 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2697 // Commit changes
2698 uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2700 OSL_ENSURE( xTO.is(),
2701 "Required interface css.embed.XTransactedObject missing!" );
2704 xTO->commit();
2706 catch ( io::IOException const & )
2708 OSL_FAIL( "Caught IOException!" );
2709 return false;
2711 catch ( lang::WrappedTargetException const & )
2713 OSL_FAIL( "Caught WrappedTargetException!" );
2714 return false;
2717 return true;
2720 //=========================================================================
2721 // static
2722 bool Content::closeOutputStream(
2723 const uno::Reference< io::XOutputStream > & xOut )
2725 if ( xOut.is() )
2729 xOut->closeOutput();
2730 return true;
2732 catch ( io::NotConnectedException const & )
2734 OSL_FAIL( "Caught NotConnectedException!" );
2736 catch ( io::BufferSizeExceededException const & )
2738 OSL_FAIL( "Caught BufferSizeExceededException!" );
2740 catch ( io::IOException const & )
2742 OSL_FAIL( "Caught IOException!" );
2745 return false;
2748 //=========================================================================
2749 static OUString obtainPassword(
2750 const OUString & rName,
2751 task::PasswordRequestMode eMode,
2752 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2753 throw ( ucb::CommandFailedException,
2754 task::DocumentPasswordRequest )
2756 rtl::Reference< DocumentPasswordRequest > xRequest
2757 = new DocumentPasswordRequest( eMode, rName );
2759 if ( xEnv.is() )
2761 uno::Reference< task::XInteractionHandler > xIH
2762 = xEnv->getInteractionHandler();
2763 if ( xIH.is() )
2765 xIH->handle( xRequest.get() );
2767 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
2768 = xRequest->getSelection();
2770 if ( xSelection.is() )
2772 // Handler handled the request.
2773 uno::Reference< task::XInteractionAbort > xAbort(
2774 xSelection.get(), uno::UNO_QUERY );
2775 if ( xAbort.is() )
2777 throw ucb::CommandFailedException(
2778 OUString( "Abort requested by Interaction Handler." ),
2779 uno::Reference< uno::XInterface >(),
2780 xRequest->getRequest() );
2783 uno::Reference< task::XInteractionPassword > xPassword(
2784 xSelection.get(), uno::UNO_QUERY );
2785 if ( xPassword.is() )
2787 return xPassword->getPassword();
2790 // Unknown selection. Should never happen.
2791 throw ucb::CommandFailedException(
2792 OUString( "Interaction Handler selected unknown continuation!" ),
2793 uno::Reference< uno::XInterface >(),
2794 xRequest->getRequest() );
2799 // No IH or IH did not handle exception.
2800 task::DocumentPasswordRequest aRequest;
2801 xRequest->getRequest() >>= aRequest;
2802 throw aRequest;
2805 //=========================================================================
2806 uno::Reference< io::XInputStream > Content::getInputStream(
2807 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2808 throw ( ucb::CommandFailedException,
2809 task::DocumentPasswordRequest )
2811 OUString aUri;
2812 OUString aPassword;
2813 bool bPasswordRequested = false;
2816 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2818 OSL_ENSURE( m_aProps.getType() == STREAM,
2819 "Content::getInputStream - content is no stream!" );
2821 aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2824 for ( ;; )
2828 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2829 return uno::Reference< io::XInputStream >(
2830 m_pProvider->queryInputStream( aUri, aPassword ) );
2832 catch ( packages::WrongPasswordException const & )
2834 // Obtain (new) password.
2835 aPassword
2836 = obtainPassword( aUri, /* @@@ find better title */
2837 bPasswordRequested
2838 ? task::PasswordRequestMode_PASSWORD_REENTER
2839 : task::PasswordRequestMode_PASSWORD_ENTER,
2840 xEnv );
2841 bPasswordRequested = true;
2846 //=========================================================================
2847 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2848 const OUString & rUri,
2849 ContentProvider * pProvider,
2850 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2851 throw ( ucb::CommandFailedException,
2852 task::DocumentPasswordRequest )
2854 OUString aPassword;
2855 bool bPasswordRequested = false;
2856 for ( ;; )
2860 return uno::Reference< io::XOutputStream >(
2861 pProvider->queryOutputStream(
2862 rUri, aPassword, true /* truncate */ ) );
2864 catch ( packages::WrongPasswordException const & )
2866 // Obtain (new) password.
2867 aPassword
2868 = obtainPassword( rUri, /* @@@ find better title */
2869 bPasswordRequested
2870 ? task::PasswordRequestMode_PASSWORD_REENTER
2871 : task::PasswordRequestMode_PASSWORD_ENTER,
2872 xEnv );
2873 bPasswordRequested = true;
2878 //=========================================================================
2879 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2880 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2881 throw ( ucb::CommandFailedException,
2882 task::DocumentPasswordRequest )
2884 OSL_ENSURE( m_aProps.getType() == STREAM,
2885 "Content::getTruncatedOutputStream - content is no stream!" );
2887 return lcl_getTruncatedOutputStream(
2888 Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2889 m_pProvider,
2890 xEnv );
2893 //=========================================================================
2894 uno::Reference< io::XStream > Content::getStream(
2895 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2896 throw ( ucb::CommandFailedException,
2897 task::DocumentPasswordRequest )
2899 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2901 OSL_ENSURE( m_aProps.getType() == STREAM,
2902 "Content::getStream - content is no stream!" );
2904 OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2905 OUString aPassword;
2906 bool bPasswordRequested = false;
2907 for ( ;; )
2911 return uno::Reference< io::XStream >(
2912 m_pProvider->queryStream(
2913 aUri, aPassword, false /* no truncate */ ) );
2915 catch ( packages::WrongPasswordException const & )
2917 // Obtain (new) password.
2918 aPassword
2919 = obtainPassword( aUri, /* @@@ find better title */
2920 bPasswordRequested
2921 ? task::PasswordRequestMode_PASSWORD_REENTER
2922 : task::PasswordRequestMode_PASSWORD_ENTER,
2923 xEnv );
2924 bPasswordRequested = true;
2929 //=========================================================================
2930 //=========================================================================
2932 // ContentProperties Implementation.
2934 //=========================================================================
2935 //=========================================================================
2937 uno::Sequence< ucb::ContentInfo >
2938 ContentProperties::getCreatableContentsInfo() const
2940 if ( isContentCreator() )
2942 uno::Sequence< beans::Property > aProps( 1 );
2943 aProps.getArray()[ 0 ] = beans::Property(
2944 OUString("Title"),
2946 getCppuType( static_cast< const OUString * >( 0 ) ),
2947 beans::PropertyAttribute::BOUND );
2949 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
2950 if ( getType() == DOCUMENT )
2952 // streams cannot be created as direct children of document root
2953 uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2955 // Folder.
2956 aSeq.getArray()[ 0 ].Type
2957 = OUString( TDOC_FOLDER_CONTENT_TYPE );
2958 aSeq.getArray()[ 0 ].Attributes
2959 = ucb::ContentInfoAttribute::KIND_FOLDER;
2960 aSeq.getArray()[ 0 ].Properties = aProps;
2962 return aSeq;
2964 else
2966 #endif
2967 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2969 // Folder.
2970 aSeq.getArray()[ 0 ].Type
2971 = OUString( TDOC_FOLDER_CONTENT_TYPE );
2972 aSeq.getArray()[ 0 ].Attributes
2973 = ucb::ContentInfoAttribute::KIND_FOLDER;
2974 aSeq.getArray()[ 0 ].Properties = aProps;
2976 // Stream.
2977 aSeq.getArray()[ 1 ].Type
2978 = OUString( TDOC_STREAM_CONTENT_TYPE );
2979 aSeq.getArray()[ 1 ].Attributes
2980 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2981 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2982 aSeq.getArray()[ 1 ].Properties = aProps;
2984 return aSeq;
2985 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
2987 #endif
2989 else
2991 OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2992 "object!" );
2994 return uno::Sequence< ucb::ContentInfo >( 0 );
2998 //=========================================================================
2999 bool ContentProperties::isContentCreator() const
3001 return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
3004 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */