Updated core
[LibreOffice.git] / ucb / source / core / ucbcmds.cxx
blob3c4fdd71fe022c24c6d7db19d9c7b97a2be22d30
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 *************************************************************************/
26 #include <osl/diagnose.h>
27 #include <comphelper/processfactory.hxx>
28 #include <cppuhelper/implbase1.hxx>
29 #include <cppuhelper/exc_hlp.hxx>
30 #include <rtl/ustring.h>
31 #include <rtl/ustring.hxx>
32 #include <com/sun/star/uno/XInterface.hpp>
33 #include <com/sun/star/beans/PropertyState.hpp>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/container/XChild.hpp>
36 #include <com/sun/star/beans/XPropertySetInfo.hpp>
37 #include <com/sun/star/io/Pipe.hpp>
38 #include <com/sun/star/io/XActiveDataSink.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/io/XSeekable.hpp>
41 #include <com/sun/star/sdbc/XRow.hpp>
42 #include <com/sun/star/task/XInteractionHandler.hpp>
43 #include <com/sun/star/ucb/CommandEnvironment.hpp>
44 #include <com/sun/star/ucb/CommandFailedException.hpp>
45 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
46 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
47 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
48 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
49 #include <com/sun/star/ucb/NameClash.hpp>
50 #include <com/sun/star/ucb/NameClashException.hpp>
51 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
52 #include <com/sun/star/ucb/OpenMode.hpp>
53 #include <com/sun/star/ucb/TransferInfo2.hpp>
54 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
55 #include <com/sun/star/ucb/XCommandInfo.hpp>
56 #include <com/sun/star/ucb/XContentAccess.hpp>
57 #include <com/sun/star/ucb/XContentCreator.hpp>
58 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
59 #include <com/sun/star/uno/Any.hxx>
60 #include <com/sun/star/uno/Sequence.hxx>
61 #include <ucbhelper/cancelcommandexecution.hxx>
62 #include <ucbhelper/simplenameclashresolverequest.hxx>
63 #include "ucbcmds.hxx"
64 #include "ucb.hxx"
66 using namespace com::sun::star;
68 namespace
71 //=========================================================================
73 // struct TransferCommandContext.
75 //=========================================================================
77 struct TransferCommandContext
79 uno::Reference< lang::XMultiServiceFactory > xSMgr;
80 uno::Reference< ucb::XCommandProcessor > xProcessor;
81 uno::Reference< ucb::XCommandEnvironment > xEnv;
82 uno::Reference< ucb::XCommandEnvironment > xOrigEnv;
83 ucb::GlobalTransferCommandArgument2 aArg;
85 TransferCommandContext(
86 const uno::Reference< lang::XMultiServiceFactory > & rxSMgr,
87 const uno::Reference< ucb::XCommandProcessor > & rxProcessor,
88 const uno::Reference< ucb::XCommandEnvironment > & rxEnv,
89 const uno::Reference< ucb::XCommandEnvironment > & rxOrigEnv,
90 const ucb::GlobalTransferCommandArgument2 & rArg )
91 : xSMgr( rxSMgr ), xProcessor( rxProcessor ), xEnv( rxEnv ),
92 xOrigEnv( rxOrigEnv ), aArg( rArg ) {}
95 //=========================================================================
97 // class InteractionHandlerProxy.
99 //=========================================================================
101 class InteractionHandlerProxy :
102 public cppu::WeakImplHelper1< task::XInteractionHandler >
104 uno::Reference< task::XInteractionHandler > m_xOrig;
106 public:
107 InteractionHandlerProxy(
108 const uno::Reference< task::XInteractionHandler > & xOrig )
109 : m_xOrig( xOrig ) {}
111 // XInteractionHandler methods.
112 virtual void SAL_CALL handle(
113 const uno::Reference< task::XInteractionRequest >& Request )
114 throw ( uno::RuntimeException );
117 //=========================================================================
118 // virtual
119 void SAL_CALL InteractionHandlerProxy::handle(
120 const uno::Reference< task::XInteractionRequest >& Request )
121 throw ( uno::RuntimeException )
123 if ( !m_xOrig.is() )
124 return;
126 // Filter unwanted requests by just not handling them.
127 uno::Any aRequest = Request->getRequest();
129 // "transfer"
130 ucb::InteractiveBadTransferURLException aBadTransferURLEx;
131 if ( aRequest >>= aBadTransferURLEx )
133 return;
135 else
137 // "transfer"
138 ucb::UnsupportedNameClashException aUnsupportedNameClashEx;
139 if ( aRequest >>= aUnsupportedNameClashEx )
141 if ( aUnsupportedNameClashEx.NameClash
142 != ucb::NameClash::ERROR )
143 return;
145 else
147 // "insert"
148 ucb::NameClashException aNameClashEx;
149 if ( aRequest >>= aNameClashEx )
151 return;
153 else
155 // "transfer"
156 ucb::UnsupportedCommandException aUnsupportedCommandEx;
157 if ( aRequest >>= aUnsupportedCommandEx )
159 return;
165 // not filtered; let the original handler do the work.
166 m_xOrig->handle( Request );
169 //=========================================================================
171 // class ActiveDataSink.
173 //=========================================================================
175 class ActiveDataSink : public cppu::WeakImplHelper1< io::XActiveDataSink >
177 uno::Reference< io::XInputStream > m_xStream;
179 public:
180 // XActiveDataSink methods.
181 virtual void SAL_CALL setInputStream(
182 const uno::Reference< io::XInputStream >& aStream )
183 throw( uno::RuntimeException );
184 virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
185 throw( uno::RuntimeException );
188 //=========================================================================
189 // virtual
190 void SAL_CALL ActiveDataSink::setInputStream(
191 const uno::Reference< io::XInputStream >& aStream )
192 throw( uno::RuntimeException )
194 m_xStream = aStream;
197 //=========================================================================
198 // virtual
199 uno::Reference< io::XInputStream > SAL_CALL ActiveDataSink::getInputStream()
200 throw( uno::RuntimeException )
202 return m_xStream;
205 //=========================================================================
207 // class CommandProcessorInfo.
209 //=========================================================================
211 class CommandProcessorInfo :
212 public cppu::WeakImplHelper1< ucb::XCommandInfo >
214 uno::Sequence< ucb::CommandInfo > * m_pInfo;
216 public:
217 CommandProcessorInfo();
218 virtual ~CommandProcessorInfo();
220 // XCommandInfo methods
221 virtual uno::Sequence< ucb::CommandInfo > SAL_CALL getCommands()
222 throw( uno::RuntimeException );
223 virtual ucb::CommandInfo SAL_CALL
224 getCommandInfoByName( const OUString& Name )
225 throw( ucb::UnsupportedCommandException, uno::RuntimeException );
226 virtual ucb::CommandInfo SAL_CALL
227 getCommandInfoByHandle( sal_Int32 Handle )
228 throw( ucb::UnsupportedCommandException, uno::RuntimeException );
229 virtual sal_Bool SAL_CALL hasCommandByName( const OUString& Name )
230 throw( uno::RuntimeException );
231 virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle )
232 throw( uno::RuntimeException );
235 //=========================================================================
236 CommandProcessorInfo::CommandProcessorInfo()
238 m_pInfo = new uno::Sequence< ucb::CommandInfo >( 2 );
240 (*m_pInfo)[ 0 ]
241 = ucb::CommandInfo(
242 OUString( GETCOMMANDINFO_NAME ), // Name
243 GETCOMMANDINFO_HANDLE, // Handle
244 getCppuVoidType() ); // ArgType
245 (*m_pInfo)[ 1 ]
246 = ucb::CommandInfo(
247 OUString( GLOBALTRANSFER_NAME ), // Name
248 GLOBALTRANSFER_HANDLE, // Handle
249 getCppuType(
250 static_cast<
251 ucb::GlobalTransferCommandArgument * >( 0 ) ) ); // ArgType
252 (*m_pInfo)[ 2 ]
253 = ucb::CommandInfo(
254 OUString( CHECKIN_NAME ), // Name
255 CHECKIN_HANDLE, // Handle
256 getCppuType(
257 static_cast<
258 ucb::GlobalTransferCommandArgument * >( 0 ) ) ); // ArgType
261 //=========================================================================
262 // virtual
263 CommandProcessorInfo::~CommandProcessorInfo()
265 delete m_pInfo;
268 //=========================================================================
269 // virtual
270 uno::Sequence< ucb::CommandInfo > SAL_CALL
271 CommandProcessorInfo::getCommands()
272 throw( uno::RuntimeException )
274 return uno::Sequence< ucb::CommandInfo >( *m_pInfo );
277 //=========================================================================
278 // virtual
279 ucb::CommandInfo SAL_CALL
280 CommandProcessorInfo::getCommandInfoByName( const OUString& Name )
281 throw( ucb::UnsupportedCommandException, uno::RuntimeException )
283 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
285 if ( (*m_pInfo)[ n ].Name == Name )
286 return ucb::CommandInfo( (*m_pInfo)[ n ] );
289 throw ucb::UnsupportedCommandException();
292 //=========================================================================
293 // virtual
294 ucb::CommandInfo SAL_CALL
295 CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
296 throw( ucb::UnsupportedCommandException, uno::RuntimeException )
298 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
300 if ( (*m_pInfo)[ n ].Handle == Handle )
301 return ucb::CommandInfo( (*m_pInfo)[ n ] );
304 throw ucb::UnsupportedCommandException();
307 //=========================================================================
308 // virtual
309 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
310 const OUString& Name )
311 throw( uno::RuntimeException )
313 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
315 if ( (*m_pInfo)[ n ].Name == Name )
316 return sal_True;
319 return sal_False;
322 //=========================================================================
323 // virtual
324 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
325 throw( uno::RuntimeException )
327 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
329 if ( (*m_pInfo)[ n ].Handle == Handle )
330 return sal_True;
333 return sal_False;
336 //=========================================================================
337 //=========================================================================
338 //=========================================================================
340 OUString createDesiredName(
341 const OUString & rSourceURL, const OUString & rNewTitle )
343 OUString aName( rNewTitle );
344 if ( aName.isEmpty() )
346 // calculate name using source URL
348 // @@@ It's not guaranteed that slashes contained in the URL are
349 // actually path separators. This depends on the fact whether the
350 // URL is hierarchical. Only then the slashes are path separators.
351 // Therefore this algorithm is not guaranteed to work! But, ATM
352 // I don't know a better solution. It would have been better to
353 // have a member for the clashing name in
354 // UnsupportedNameClashException...
356 sal_Int32 nLastSlash = rSourceURL.lastIndexOf( '/' );
357 bool bTrailingSlash = false;
358 if ( nLastSlash == rSourceURL.getLength() - 1 )
360 nLastSlash = rSourceURL.lastIndexOf( '/', nLastSlash );
361 bTrailingSlash = true;
364 if ( nLastSlash != -1 )
366 if ( bTrailingSlash )
367 aName = rSourceURL.copy(
368 nLastSlash + 1,
369 rSourceURL.getLength() - nLastSlash - 2 );
370 else
371 aName = rSourceURL.copy( nLastSlash + 1 );
373 else
375 aName = rSourceURL;
378 // query, fragment present?
379 sal_Int32 nPos = aName.indexOf( '?' );
380 if ( nPos == -1 )
381 nPos = aName.indexOf( '#' );
383 if ( nPos != -1 )
384 aName = aName.copy( 0, nPos );
386 return OUString( aName );
389 OUString createDesiredName(
390 const ucb::GlobalTransferCommandArgument & rArg )
392 return createDesiredName( rArg.SourceURL, rArg.NewTitle );
395 OUString createDesiredName(
396 const ucb::TransferInfo & rArg )
398 return createDesiredName( rArg.SourceURL, rArg.NewTitle );
401 //=========================================================================
402 enum NameClashContinuation { NOT_HANDLED, ABORT, OVERWRITE, NEW_NAME, UNKNOWN };
404 NameClashContinuation interactiveNameClashResolve(
405 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
406 const OUString & rTargetURL,
407 const OUString & rClashingName,
408 /* [out] */ uno::Any & rException,
409 /* [out] */ OUString & rNewName )
411 rtl::Reference< ucbhelper::SimpleNameClashResolveRequest > xRequest(
412 new ucbhelper::SimpleNameClashResolveRequest(
413 rTargetURL, // target folder URL
414 rClashingName, // clashing name
415 OUString(), // no proposal for new name
416 sal_True /* bSupportsOverwriteData */ ) );
418 rException = xRequest->getRequest();
419 if ( xEnv.is() )
421 uno::Reference< task::XInteractionHandler > xIH
422 = xEnv->getInteractionHandler();
423 if ( xIH.is() )
426 xIH->handle( xRequest.get() );
428 rtl::Reference< ucbhelper::InteractionContinuation >
429 xSelection( xRequest->getSelection() );
431 if ( xSelection.is() )
433 // Handler handled the request.
434 uno::Reference< task::XInteractionAbort > xAbort(
435 xSelection.get(), uno::UNO_QUERY );
436 if ( xAbort.is() )
438 // Abort.
439 return ABORT;
441 else
443 uno::Reference<
444 ucb::XInteractionReplaceExistingData >
445 xReplace(
446 xSelection.get(), uno::UNO_QUERY );
447 if ( xReplace.is() )
449 // Try again: Replace existing data.
450 return OVERWRITE;
452 else
454 uno::Reference<
455 ucb::XInteractionSupplyName >
456 xSupplyName(
457 xSelection.get(), uno::UNO_QUERY );
458 if ( xSupplyName.is() )
460 // Try again: Use new name.
461 rNewName = xRequest->getNewName();
462 return NEW_NAME;
464 else
466 OSL_FAIL( "Unknown interaction continuation!" );
467 return UNKNOWN;
474 return NOT_HANDLED;
477 //=========================================================================
478 bool setTitle(
479 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessor,
480 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
481 const OUString & rNewTitle )
482 throw( uno::RuntimeException )
486 uno::Sequence< beans::PropertyValue > aPropValues( 1 );
487 aPropValues[ 0 ].Name
488 = OUString( "Title" );
489 aPropValues[ 0 ].Handle = -1;
490 aPropValues[ 0 ].Value = uno::makeAny( rNewTitle );
492 ucb::Command aSetPropsCommand(
493 OUString( "setPropertyValues" ),
495 uno::makeAny( aPropValues ) );
497 uno::Any aResult
498 = xCommandProcessor->execute( aSetPropsCommand, 0, xEnv );
500 uno::Sequence< uno::Any > aErrors;
501 aResult >>= aErrors;
503 OSL_ENSURE( aErrors.getLength() == 1,
504 "getPropertyValues return value invalid!" );
506 if ( aErrors[ 0 ].hasValue() )
508 // error occurred.
509 OSL_FAIL( "error setting Title property!" );
510 return false;
513 catch ( uno::RuntimeException const & )
515 throw;
517 catch ( uno::Exception const & )
519 return false;
522 return true;
525 //=========================================================================
526 uno::Reference< ucb::XContent > createNew(
527 const TransferCommandContext & rContext,
528 const uno::Reference< ucb::XContent > & xTarget,
529 sal_Bool bSourceIsFolder,
530 sal_Bool bSourceIsDocument,
531 sal_Bool bSourceIsLink )
532 throw( uno::Exception )
534 //////////////////////////////////////////////////////////////////////
536 // (1) Obtain creatable types from target.
538 //////////////////////////////////////////////////////////////////////
540 // First, try it using "CreatabeleContentsInfo" property and
541 // "createNewContent" command -> the "new" way.
543 uno::Reference< ucb::XCommandProcessor > xCommandProcessorT(
544 xTarget, uno::UNO_QUERY );
545 if ( !xCommandProcessorT.is() )
547 uno::Any aProps
548 = uno::makeAny(beans::PropertyValue(
549 OUString( "Folder"),
551 uno::makeAny(rContext.aArg.TargetURL),
552 beans::PropertyState_DIRECT_VALUE));
553 ucbhelper::cancelCommandExecution(
554 ucb::IOErrorCode_CANT_CREATE,
555 uno::Sequence< uno::Any >(&aProps, 1),
556 rContext.xOrigEnv,
557 OUString("Target is no XCommandProcessor!"),
558 rContext.xProcessor );
559 // Unreachable
562 uno::Sequence< beans::Property > aPropsToObtain( 1 );
563 aPropsToObtain[ 0 ].Name
564 = OUString("CreatableContentsInfo");
565 aPropsToObtain[ 0 ].Handle
566 = -1;
568 ucb::Command aGetPropsCommand(
569 OUString("getPropertyValues"),
571 uno::makeAny( aPropsToObtain ) );
573 uno::Reference< sdbc::XRow > xRow;
574 xCommandProcessorT->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
576 uno::Sequence< ucb::ContentInfo > aTypesInfo;
577 bool bGotTypesInfo = false;
579 if ( xRow.is() )
581 uno::Any aValue = xRow->getObject(
582 1, uno::Reference< container::XNameAccess >() );
583 if ( aValue.hasValue() && ( aValue >>= aTypesInfo ) )
585 bGotTypesInfo = true;
589 uno::Reference< ucb::XContentCreator > xCreator;
591 if ( !bGotTypesInfo )
593 // Second, try it using XContentCreator interface -> the "old" way (not
594 // providing the chance to supply an XCommandEnvironment.
596 xCreator.set( xTarget, uno::UNO_QUERY );
598 if ( !xCreator.is() )
600 uno::Any aProps
601 = uno::makeAny(beans::PropertyValue(
602 OUString( "Folder"),
604 uno::makeAny(rContext.aArg.TargetURL),
605 beans::PropertyState_DIRECT_VALUE));
606 ucbhelper::cancelCommandExecution(
607 ucb::IOErrorCode_CANT_CREATE,
608 uno::Sequence< uno::Any >(&aProps, 1),
609 rContext.xOrigEnv,
610 OUString("Target is no XContentCreator!"),
611 rContext.xProcessor );
612 // Unreachable
615 aTypesInfo = xCreator->queryCreatableContentsInfo();
618 sal_Int32 nCount = aTypesInfo.getLength();
619 if ( !nCount )
621 uno::Any aProps
622 = uno::makeAny(beans::PropertyValue(
623 OUString("Folder"),
625 uno::makeAny(rContext.aArg.TargetURL),
626 beans::PropertyState_DIRECT_VALUE));
627 ucbhelper::cancelCommandExecution(
628 ucb::IOErrorCode_CANT_CREATE,
629 uno::Sequence< uno::Any >(&aProps, 1),
630 rContext.xOrigEnv,
631 OUString("No types creatable!"),
632 rContext.xProcessor );
633 // Unreachable
636 //////////////////////////////////////////////////////////////////////
638 // (2) Try to find a matching target type for the source object.
640 //////////////////////////////////////////////////////////////////////
642 uno::Reference< ucb::XContent > xNew;
643 for ( sal_Int32 n = 0; n < nCount; ++n )
645 sal_Int32 nAttribs = aTypesInfo[ n ].Attributes;
646 sal_Bool bMatch = sal_False;
648 if ( rContext.aArg.Operation == ucb::TransferCommandOperation_LINK )
650 // Create link
652 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
654 // Match!
655 bMatch = sal_True;
658 else if ( ( rContext.aArg.Operation
659 == ucb::TransferCommandOperation_COPY ) ||
660 ( rContext.aArg.Operation
661 == ucb::TransferCommandOperation_MOVE ) )
663 // Copy / Move
665 // Is source a link? Create link in target folder then.
666 if ( bSourceIsLink )
668 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
670 // Match!
671 bMatch = sal_True;
674 else
676 // (not a and not b) or (a and b)
677 // not( a or b) or (a and b)
679 if ( ( !!bSourceIsFolder ==
680 !!( nAttribs
681 & ucb::ContentInfoAttribute::KIND_FOLDER ) )
683 ( !!bSourceIsDocument ==
684 !!( nAttribs
685 & ucb::ContentInfoAttribute::KIND_DOCUMENT ) )
688 // Match!
689 bMatch = sal_True;
693 else
695 ucbhelper::cancelCommandExecution(
696 uno::makeAny( lang::IllegalArgumentException(
697 OUString( "Unknown transfer operation!" ),
698 rContext.xProcessor,
699 -1 ) ),
700 rContext.xOrigEnv );
701 // Unreachable
704 if ( bMatch )
706 //////////////////////////////////////////////////////////////
708 // (3) Create a new, empty object of matched type.
710 //////////////////////////////////////////////////////////////
712 if ( !xCreator.is() )
714 // First, try it using "CreatabeleContentsInfo" property and
715 // "createNewContent" command -> the "new" way.
716 ucb::Command aCreateNewCommand(
717 OUString("createNewContent"),
719 uno::makeAny( aTypesInfo[ n ] ) );
721 xCommandProcessorT->execute( aCreateNewCommand, 0, rContext.xEnv )
722 >>= xNew;
724 else
726 // Second, try it using XContentCreator interface -> the "old"
727 // way (not providing the chance to supply an XCommandEnvironment.
729 xNew = xCreator->createNewContent( aTypesInfo[ n ] );
732 if ( !xNew.is() )
734 uno::Any aProps
735 = uno::makeAny(
736 beans::PropertyValue(
737 OUString( "Folder"),
739 uno::makeAny(rContext.aArg.TargetURL),
740 beans::PropertyState_DIRECT_VALUE));
741 ucbhelper::cancelCommandExecution(
742 ucb::IOErrorCode_CANT_CREATE,
743 uno::Sequence< uno::Any >(&aProps, 1),
744 rContext.xOrigEnv,
745 OUString( "createNewContent failed!" ),
746 rContext.xProcessor );
747 // Unreachable
749 break; // escape from 'for' loop
751 } // for
753 return xNew;
756 //=========================================================================
757 void transferProperties(
758 const TransferCommandContext & rContext,
759 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS,
760 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorN )
761 throw( uno::Exception )
763 ucb::Command aGetPropertySetInfoCommand(
764 OUString("getPropertySetInfo"),
766 uno::Any() );
768 uno::Reference< beans::XPropertySetInfo > xInfo;
769 xCommandProcessorS->execute( aGetPropertySetInfoCommand, 0, rContext.xEnv )
770 >>= xInfo;
772 if ( !xInfo.is() )
774 uno::Any aProps
775 = uno::makeAny(beans::PropertyValue(
776 OUString( "Uri"),
778 uno::makeAny(rContext.aArg.SourceURL),
779 beans::PropertyState_DIRECT_VALUE));
780 ucbhelper::cancelCommandExecution(
781 ucb::IOErrorCode_CANT_READ,
782 uno::Sequence< uno::Any >(&aProps, 1),
783 rContext.xOrigEnv,
784 OUString( "Unable to get propertyset info from source object!" ),
785 rContext.xProcessor );
786 // Unreachable
789 uno::Sequence< beans::Property > aAllProps = xInfo->getProperties();
791 ucb::Command aGetPropsCommand1(
792 OUString("getPropertyValues"),
794 uno::makeAny( aAllProps ) );
796 uno::Reference< sdbc::XRow > xRow1;
797 xCommandProcessorS->execute(
798 aGetPropsCommand1, 0, rContext.xEnv ) >>= xRow1;
800 if ( !xRow1.is() )
802 uno::Any aProps
803 = uno::makeAny(beans::PropertyValue(
804 OUString( "Uri"),
806 uno::makeAny(rContext.aArg.SourceURL),
807 beans::PropertyState_DIRECT_VALUE));
808 ucbhelper::cancelCommandExecution(
809 ucb::IOErrorCode_CANT_READ,
810 uno::Sequence< uno::Any >(&aProps, 1),
811 rContext.xOrigEnv,
812 OUString( "Unable to get properties from source object!" ),
813 rContext.xProcessor );
814 // Unreachable
817 // Assemble data structure for setPropertyValues command.
819 // Note: Make room for additional Title and TargetURL too. -> + 2
820 uno::Sequence< beans::PropertyValue > aPropValues(
821 aAllProps.getLength() + 2 );
823 sal_Bool bHasTitle = rContext.aArg.NewTitle.isEmpty();
824 sal_Bool bHasTargetURL = ( rContext.aArg.Operation
825 != ucb::TransferCommandOperation_LINK );
827 sal_Int32 nWritePos = 0;
828 for ( sal_Int32 m = 0; m < aAllProps.getLength(); ++m )
830 const beans::Property & rCurrProp = aAllProps[ m ];
831 beans::PropertyValue & rCurrValue = aPropValues[ nWritePos ];
833 uno::Any aValue;
835 if ( rCurrProp.Name.compareToAscii( "Title" ) == 0 )
837 // Supply new title, if given.
838 if ( !bHasTitle )
840 bHasTitle = sal_True;
841 aValue <<= rContext.aArg.NewTitle;
844 else if ( rCurrProp.Name.compareToAscii( "TargetURL" ) == 0 )
846 // Supply source URL as link target for the new link to create.
847 if ( !bHasTargetURL )
849 bHasTargetURL = sal_True;
850 aValue <<= rContext.aArg.SourceURL;
854 if ( !aValue.hasValue() )
858 aValue = xRow1->getObject(
859 m + 1, uno::Reference< container::XNameAccess >() );
861 catch ( sdbc::SQLException const & )
863 // Argh! But try to bring things to an end. Perhaps the
864 // mad property is not really important...
868 if ( aValue.hasValue() )
870 rCurrValue.Name = rCurrProp.Name;
871 rCurrValue.Handle = rCurrProp.Handle;
872 rCurrValue.Value = aValue;
873 // rCurrValue.State =
875 nWritePos++;
879 // Title needed, but not set yet?
880 if ( !bHasTitle && !rContext.aArg.NewTitle.isEmpty() )
882 aPropValues[ nWritePos ].Name
883 = OUString("Title");
884 aPropValues[ nWritePos ].Handle = -1;
885 aPropValues[ nWritePos ].Value <<= rContext.aArg.NewTitle;
887 nWritePos++;
890 // TargetURL needed, but not set yet?
891 if ( !bHasTargetURL && ( rContext.aArg.Operation
892 == ucb::TransferCommandOperation_LINK ) )
894 aPropValues[ nWritePos ].Name
895 = OUString("TargetURL");
896 aPropValues[ nWritePos ].Handle = -1;
897 aPropValues[ nWritePos ].Value <<= rContext.aArg.SourceURL;
899 nWritePos++;
902 aPropValues.realloc( nWritePos );
904 // Set properties at new object.
906 ucb::Command aSetPropsCommand(
907 OUString("setPropertyValues"),
909 uno::makeAny( aPropValues ) );
911 xCommandProcessorN->execute( aSetPropsCommand, 0, rContext.xEnv );
913 // @@@ What to do with source props that are not supported by the
914 // new object? addProperty ???
917 //=========================================================================
918 uno::Reference< io::XInputStream > getInputStream(
919 const TransferCommandContext & rContext,
920 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
921 throw( uno::Exception )
923 uno::Reference< io::XInputStream > xInputStream;
925 //////////////////////////////////////////////////////////////////////
927 // (1) Try to get data as XInputStream via XActiveDataSink.
929 //////////////////////////////////////////////////////////////////////
933 uno::Reference< io::XActiveDataSink > xSink = new ActiveDataSink;
935 ucb::OpenCommandArgument2 aArg;
936 aArg.Mode = ucb::OpenMode::DOCUMENT;
937 aArg.Priority = 0; // unused
938 aArg.Sink = xSink;
939 aArg.Properties = uno::Sequence< beans::Property >( 0 ); // unused
941 ucb::Command aOpenCommand(
942 OUString("open"),
944 uno::makeAny( aArg ) );
946 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
947 xInputStream = xSink->getInputStream();
949 catch ( uno::RuntimeException const & )
951 throw;
953 catch ( uno::Exception const & )
955 // will be handled below.
958 if ( !xInputStream.is() )
960 //////////////////////////////////////////////////////////////////
962 // (2) Try to get data via XOutputStream.
964 //////////////////////////////////////////////////////////////////
968 uno::Reference< io::XOutputStream > xOutputStream( io::Pipe::create(comphelper::getComponentContext(rContext.xSMgr)), uno::UNO_QUERY_THROW );
970 ucb::OpenCommandArgument2 aArg;
971 aArg.Mode = ucb::OpenMode::DOCUMENT;
972 aArg.Priority = 0; // unused
973 aArg.Sink = xOutputStream;
974 aArg.Properties = uno::Sequence< beans::Property >( 0 );
976 ucb::Command aOpenCommand(
977 OUString("open"),
979 uno::makeAny( aArg ) );
981 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
983 xInputStream = uno::Reference< io::XInputStream >(
984 xOutputStream, uno::UNO_QUERY );
986 catch ( uno::RuntimeException const & )
988 throw;
990 catch ( uno::Exception const & )
992 OSL_FAIL( "unable to get input stream from document!" );
996 return xInputStream;
999 //=========================================================================
1000 uno::Reference< sdbc::XResultSet > getResultSet(
1001 const TransferCommandContext & rContext,
1002 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
1003 throw( uno::Exception )
1005 uno::Reference< sdbc::XResultSet > xResultSet;
1007 uno::Sequence< beans::Property > aProps( 3 );
1009 aProps[ 0 ].Name = OUString("IsFolder");
1010 aProps[ 0 ].Handle = -1; /* unknown */
1011 aProps[ 1 ].Name = OUString("IsDocument");
1012 aProps[ 1 ].Handle = -1; /* unknown */
1013 aProps[ 2 ].Name = OUString("TargetURL");
1014 aProps[ 2 ].Handle = -1; /* unknown */
1016 ucb::OpenCommandArgument2 aArg;
1017 aArg.Mode = ucb::OpenMode::ALL;
1018 aArg.Priority = 0; // unused
1019 aArg.Sink = 0;
1020 aArg.Properties = aProps;
1022 ucb::Command aOpenCommand( OUString("open"),
1024 uno::makeAny( aArg ) );
1027 uno::Reference< ucb::XDynamicResultSet > xSet;
1028 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv ) >>= xSet;
1030 if ( xSet.is() )
1031 xResultSet = xSet->getStaticResultSet();
1033 catch ( uno::RuntimeException const & )
1035 throw;
1037 catch ( uno::Exception const & )
1039 OSL_FAIL( "unable to get result set from folder!" );
1042 return xResultSet;
1045 //=========================================================================
1046 void handleNameClashRename(
1047 const TransferCommandContext & rContext,
1048 const uno::Reference< ucb::XContent > & xNew,
1049 const uno::Reference<
1050 ucb::XCommandProcessor > & xCommandProcessorN,
1051 const uno::Reference<
1052 ucb::XCommandProcessor > & xCommandProcessorS,
1053 /* [inout] */ uno::Reference< io::XInputStream > & xInputStream )
1054 throw( uno::Exception )
1056 sal_Int32 nTry = 0;
1058 // Obtain old title.
1059 uno::Sequence< beans::Property > aProps( 1 );
1060 aProps[ 0 ].Name = OUString("Title");
1061 aProps[ 0 ].Handle = -1;
1063 ucb::Command aGetPropsCommand(
1064 OUString("getPropertyValues"),
1066 uno::makeAny( aProps ) );
1068 uno::Reference< sdbc::XRow > xRow;
1069 xCommandProcessorN->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
1071 if ( !xRow.is() )
1073 uno::Any aProps2
1074 = uno::makeAny(
1075 beans::PropertyValue(
1076 OUString( "Uri" ),
1078 uno::makeAny(
1079 xNew->getIdentifier()->getContentIdentifier() ),
1080 beans::PropertyState_DIRECT_VALUE ) );
1081 ucbhelper::cancelCommandExecution(
1082 ucb::IOErrorCode_CANT_READ,
1083 uno::Sequence< uno::Any >( &aProps2, 1 ),
1084 rContext.xOrigEnv,
1085 OUString( "Unable to get properties from new object!" ),
1086 rContext.xProcessor );
1087 // Unreachable
1090 OUString aOldTitle = xRow->getString( 1 );
1091 if ( aOldTitle.isEmpty() )
1093 ucbhelper::cancelCommandExecution(
1094 uno::makeAny( beans::UnknownPropertyException(
1095 OUString( "Unable to get property 'Title' from new object!" ),
1096 rContext.xProcessor ) ),
1097 rContext.xOrigEnv );
1098 // Unreachable
1101 // Some pseudo-intelligence for not destroying file extensions.
1102 OUString aOldTitlePre;
1103 OUString aOldTitlePost;
1104 sal_Int32 nPos = aOldTitle.lastIndexOf( '.' );
1105 if ( nPos != -1 )
1107 aOldTitlePre = aOldTitle.copy( 0, nPos );
1108 aOldTitlePost = aOldTitle.copy( nPos );
1110 else
1111 aOldTitlePre = aOldTitle;
1113 if ( nPos > 0 )
1114 aOldTitlePre += OUString("_");
1116 sal_Bool bContinue = sal_True;
1119 nTry++;
1121 OUString aNewTitle = aOldTitlePre;
1122 aNewTitle += OUString::valueOf( nTry );
1123 aNewTitle += aOldTitlePost;
1125 // Set new title
1126 setTitle( xCommandProcessorN, rContext.xEnv, aNewTitle );
1128 // Retry inserting the content.
1131 // Previous try may have read from stream. Seek to begin (if
1132 // optional interface XSeekable is supported) or get a new stream.
1133 if ( xInputStream.is() )
1135 uno::Reference< io::XSeekable > xSeekable(
1136 xInputStream, uno::UNO_QUERY );
1137 if ( xSeekable.is() )
1141 xSeekable->seek( 0 );
1143 catch ( lang::IllegalArgumentException const & )
1145 xInputStream.clear();
1147 catch ( io::IOException const & )
1149 xInputStream.clear();
1152 else
1153 xInputStream.clear();
1155 if ( !xInputStream.is() )
1157 xInputStream
1158 = getInputStream( rContext, xCommandProcessorS );
1159 if ( !xInputStream.is() )
1161 uno::Any aProps2
1162 = uno::makeAny(
1163 beans::PropertyValue(
1164 OUString( "Uri" ),
1166 uno::makeAny(
1167 xNew->getIdentifier()->
1168 getContentIdentifier() ),
1169 beans::PropertyState_DIRECT_VALUE ) );
1170 ucbhelper::cancelCommandExecution(
1171 ucb::IOErrorCode_CANT_READ,
1172 uno::Sequence< uno::Any >( &aProps2, 1 ),
1173 rContext.xOrigEnv,
1174 OUString( "Got no data stream from source!" ),
1175 rContext.xProcessor );
1176 // Unreachable
1181 ucb::InsertCommandArgument2 aArg;
1182 aArg.Data = xInputStream;
1183 aArg.ReplaceExisting = sal_False;
1185 ucb::Command aInsertCommand(
1186 OUString("insert"),
1188 uno::makeAny( aArg ) );
1190 xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1192 // Success!
1193 bContinue = sal_False;
1195 catch ( uno::RuntimeException const & )
1197 throw;
1199 catch ( uno::Exception const & )
1203 while ( bContinue && ( nTry < 50 ) );
1205 if ( nTry == 50 )
1207 ucbhelper::cancelCommandExecution(
1208 uno::makeAny(
1209 ucb::UnsupportedNameClashException(
1210 OUString( "Unable to resolve name clash!" ),
1211 rContext.xProcessor,
1212 ucb::NameClash::RENAME ) ),
1213 rContext.xOrigEnv );
1214 // Unreachable
1218 //=========================================================================
1219 void globalTransfer_(
1220 const TransferCommandContext & rContext,
1221 const uno::Reference< ucb::XContent > & xSource,
1222 const uno::Reference< ucb::XContent > & xTarget,
1223 const uno::Reference< sdbc::XRow > & xSourceProps )
1224 throw( uno::Exception )
1226 // IsFolder: property is required.
1227 sal_Bool bSourceIsFolder = xSourceProps->getBoolean( 1 );
1228 if ( !bSourceIsFolder && xSourceProps->wasNull() )
1230 ucbhelper::cancelCommandExecution(
1231 uno::makeAny( beans::UnknownPropertyException(
1232 OUString( "Unable to get property 'IsFolder' "
1233 "from source object!" ),
1234 rContext.xProcessor ) ),
1235 rContext.xOrigEnv );
1236 // Unreachable
1239 // IsDocument: property is required.
1240 sal_Bool bSourceIsDocument = xSourceProps->getBoolean( 2 );
1241 if ( !bSourceIsDocument && xSourceProps->wasNull() )
1243 ucbhelper::cancelCommandExecution(
1244 uno::makeAny( beans::UnknownPropertyException(
1245 OUString( "Unable to get property 'IsDocument' "
1246 "from source object!" ),
1247 rContext.xProcessor ) ),
1248 rContext.xOrigEnv );
1249 // Unreachable
1252 // TargetURL: property is optional.
1253 sal_Bool bSourceIsLink = !xSourceProps->getString( 3 ).isEmpty();
1255 //////////////////////////////////////////////////////////////////////
1257 // (1) Try to find a matching target type for the source object and
1258 // create a new, empty object of that type.
1260 //////////////////////////////////////////////////////////////////////
1262 uno::Reference< ucb::XContent > xNew = createNew( rContext,
1263 xTarget,
1264 bSourceIsFolder,
1265 bSourceIsDocument,
1266 bSourceIsLink );
1267 if ( !xNew.is() )
1269 uno::Any aProps
1270 = uno::makeAny(beans::PropertyValue(
1271 OUString( "Folder"),
1273 uno::makeAny(rContext.aArg.TargetURL),
1274 beans::PropertyState_DIRECT_VALUE));
1275 ucbhelper::cancelCommandExecution(
1276 ucb::IOErrorCode_CANT_CREATE,
1277 uno::Sequence< uno::Any >(&aProps, 1),
1278 rContext.xOrigEnv,
1279 OUString( "No matching content type at target!" ),
1280 rContext.xProcessor );
1281 // Unreachable
1284 //////////////////////////////////////////////////////////////////////
1286 // (2) Transfer property values from source to new object.
1288 //////////////////////////////////////////////////////////////////////
1290 uno::Reference< ucb::XCommandProcessor > xCommandProcessorN(
1291 xNew, uno::UNO_QUERY );
1292 if ( !xCommandProcessorN.is() )
1294 uno::Any aProps
1295 = uno::makeAny(beans::PropertyValue(
1296 OUString( "Uri"),
1298 uno::makeAny(
1299 xNew->getIdentifier()->
1300 getContentIdentifier()),
1301 beans::PropertyState_DIRECT_VALUE));
1302 ucbhelper::cancelCommandExecution(
1303 ucb::IOErrorCode_CANT_WRITE,
1304 uno::Sequence< uno::Any >(&aProps, 1),
1305 rContext.xOrigEnv,
1306 OUString( "New content is not a XCommandProcessor!" ),
1307 rContext.xProcessor );
1308 // Unreachable
1311 // Obtain all properties from source.
1313 uno::Reference< ucb::XCommandProcessor > xCommandProcessorS(
1314 xSource, uno::UNO_QUERY );
1315 if ( !xCommandProcessorS.is() )
1317 uno::Any aProps
1318 = uno::makeAny(beans::PropertyValue(
1319 OUString( "Uri"),
1321 uno::makeAny(rContext.aArg.SourceURL),
1322 beans::PropertyState_DIRECT_VALUE));
1323 ucbhelper::cancelCommandExecution(
1324 ucb::IOErrorCode_CANT_READ,
1325 uno::Sequence< uno::Any >(&aProps, 1),
1326 rContext.xOrigEnv,
1327 OUString( "Source content is not a XCommandProcessor!" ),
1328 rContext.xProcessor );
1329 // Unreachable
1332 transferProperties( rContext, xCommandProcessorS, xCommandProcessorN );
1334 //////////////////////////////////////////////////////////////////////
1336 // (3) Try to obtain a data stream from source.
1338 //////////////////////////////////////////////////////////////////////
1340 uno::Reference< io::XInputStream > xInputStream;
1342 if ( bSourceIsDocument && ( rContext.aArg.Operation
1343 != ucb::TransferCommandOperation_LINK ) )
1344 xInputStream = getInputStream( rContext, xCommandProcessorS );
1346 //////////////////////////////////////////////////////////////////////
1348 // (4) Try to obtain a resultset (children) from source.
1350 //////////////////////////////////////////////////////////////////////
1352 uno::Reference< sdbc::XResultSet > xResultSet;
1354 if ( bSourceIsFolder && ( rContext.aArg.Operation
1355 != ucb::TransferCommandOperation_LINK ) )
1356 xResultSet = getResultSet( rContext, xCommandProcessorS );
1358 //////////////////////////////////////////////////////////////////////
1360 // (5) Insert (store) new content.
1362 //////////////////////////////////////////////////////////////////////
1364 ucb::InsertCommandArgument2 aArg;
1365 aArg.Data = xInputStream;
1366 aArg.MimeType = rContext.aArg.MimeType;
1368 switch ( rContext.aArg.NameClash )
1370 case ucb::NameClash::OVERWRITE:
1371 aArg.ReplaceExisting = sal_True;
1372 break;
1374 case ucb::NameClash::ERROR:
1375 case ucb::NameClash::RENAME:
1376 case ucb::NameClash::KEEP: // deprecated
1377 case ucb::NameClash::ASK:
1378 aArg.ReplaceExisting = sal_False;
1379 break;
1381 default:
1382 aArg.ReplaceExisting = sal_False;
1383 OSL_FAIL( "Unknown nameclash directive!" );
1384 break;
1387 OUString aDesiredName = createDesiredName( rContext.aArg );
1389 bool bRetry;
1392 bRetry = false;
1396 ucb::Command aInsertCommand(
1397 OUString("insert"),
1399 uno::makeAny( aArg ) );
1401 xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1403 catch ( ucb::UnsupportedNameClashException const & exc )
1405 OSL_ENSURE( !aArg.ReplaceExisting,
1406 "BUG: UnsupportedNameClashException not allowed here!" );
1408 if (exc.NameClash != ucb::NameClash::ERROR) {
1409 OSL_FAIL( "BUG: NameClash::ERROR expected!" );
1412 // No chance to solve name clashes, because I'm not able to detect
1413 // whether there is one.
1414 throw ucb::UnsupportedNameClashException(
1415 OUString(
1416 "Unable to resolve name clashes, no chance to detect "
1417 "that there is one!" ),
1418 rContext.xProcessor,
1419 rContext.aArg.NameClash );
1421 catch ( ucb::NameClashException const & )
1423 // The 'insert' command throws a NameClashException if the parameter
1424 // ReplaceExisting of the command's argument was set to false and
1425 // there exists a resource with a clashing name in the target folder
1426 // of the operation.
1428 // 'insert' command has no direct support for name clashes other
1429 // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1430 // ( ReplaceExisting == true ). So we have to implement the
1431 // other name clash handling directives on top of the content.
1433 // @@@ 'insert' command should be extended that it accepts a
1434 // name clash handling directive, exactly like 'transfer' command.
1436 switch ( rContext.aArg.NameClash )
1438 case ucb::NameClash::OVERWRITE:
1440 ucbhelper::cancelCommandExecution(
1441 uno::makeAny(
1442 ucb::UnsupportedNameClashException(
1443 OUString(
1444 "BUG: insert + replace == true MUST NOT "
1445 "throw NameClashException." ),
1446 rContext.xProcessor,
1447 rContext.aArg.NameClash ) ),
1448 rContext.xOrigEnv );
1449 // Unreachable
1452 case ucb::NameClash::ERROR:
1453 throw;
1455 case ucb::NameClash::RENAME:
1457 // "invent" a new valid title.
1458 handleNameClashRename( rContext,
1459 xNew,
1460 xCommandProcessorN,
1461 xCommandProcessorS,
1462 xInputStream );
1463 break;
1466 case ucb::NameClash::ASK:
1468 uno::Any aExc;
1469 OUString aNewTitle;
1470 NameClashContinuation eCont
1471 = interactiveNameClashResolve(
1472 rContext.xOrigEnv, // always use original environment!
1473 rContext.aArg.TargetURL, // target folder URL
1474 aDesiredName,
1475 aExc,
1476 aNewTitle );
1478 switch ( eCont )
1480 case NOT_HANDLED:
1481 // Not handled.
1482 cppu::throwException( aExc );
1483 // break;
1485 case UNKNOWN:
1486 // Handled, but not clear, how...
1487 // fall-thru intended.
1489 case ABORT:
1490 throw ucb::CommandFailedException(
1491 OUString(
1492 "abort requested via interaction "
1493 "handler" ),
1494 uno::Reference< uno::XInterface >(),
1495 aExc );
1496 // break;
1498 case OVERWRITE:
1499 OSL_ENSURE( aArg.ReplaceExisting == sal_False,
1500 "Hu? ReplaceExisting already true?"
1502 aArg.ReplaceExisting = sal_True;
1503 bRetry = true;
1504 break;
1506 case NEW_NAME:
1508 // set new name -> set "Title" property...
1509 if ( setTitle( xCommandProcessorN,
1510 rContext.xEnv,
1511 aNewTitle ) )
1513 // remember suggested title...
1514 aDesiredName = aNewTitle;
1516 // ... and try again.
1517 bRetry = true;
1519 else
1521 // error setting title. Abort.
1522 throw ucb::CommandFailedException(
1523 OUString( "error setting Title property!" ),
1524 uno::Reference< uno::XInterface >(),
1525 aExc );
1527 break;
1531 OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1533 break;
1535 case ucb::NameClash::KEEP: // deprecated
1536 default:
1538 ucbhelper::cancelCommandExecution(
1539 uno::makeAny(
1540 ucb::UnsupportedNameClashException(
1541 OUString(
1542 "default action, don't know how to "
1543 "handle name clash" ),
1544 rContext.xProcessor,
1545 rContext.aArg.NameClash ) ),
1546 rContext.xOrigEnv );
1547 // Unreachable
1552 while ( bRetry );
1554 //////////////////////////////////////////////////////////////////////
1556 // (6) Process children of source.
1558 //////////////////////////////////////////////////////////////////////
1560 if ( xResultSet.is() )
1564 // Iterate over children...
1566 uno::Reference< sdbc::XRow > xChildRow(
1567 xResultSet, uno::UNO_QUERY );
1569 if ( !xChildRow.is() )
1571 uno::Any aProps
1572 = uno::makeAny(
1573 beans::PropertyValue(
1574 OUString( "Uri"),
1576 uno::makeAny(rContext.aArg.SourceURL),
1577 beans::PropertyState_DIRECT_VALUE));
1578 ucbhelper::cancelCommandExecution(
1579 ucb::IOErrorCode_CANT_READ,
1580 uno::Sequence< uno::Any >(&aProps, 1),
1581 rContext.xOrigEnv,
1582 OUString( "Unable to get properties from children of source!" ),
1583 rContext.xProcessor );
1584 // Unreachable
1587 uno::Reference< ucb::XContentAccess > xChildAccess(
1588 xResultSet, uno::UNO_QUERY );
1590 if ( !xChildAccess.is() )
1592 uno::Any aProps
1593 = uno::makeAny(
1594 beans::PropertyValue(
1595 OUString( "Uri"),
1597 uno::makeAny(rContext.aArg.SourceURL),
1598 beans::PropertyState_DIRECT_VALUE));
1599 ucbhelper::cancelCommandExecution(
1600 ucb::IOErrorCode_CANT_READ,
1601 uno::Sequence< uno::Any >(&aProps, 1),
1602 rContext.xOrigEnv,
1603 OUString( "Unable to get children of source!" ),
1604 rContext.xProcessor );
1605 // Unreachable
1608 if ( xResultSet->first() )
1610 ucb::GlobalTransferCommandArgument2 aTransArg(
1611 rContext.aArg.Operation,
1612 OUString(), // SourceURL; filled later
1613 xNew->getIdentifier()
1614 ->getContentIdentifier(), // TargetURL
1615 OUString(), // NewTitle;
1616 rContext.aArg.NameClash,
1617 rContext.aArg.MimeType );
1619 TransferCommandContext aSubCtx(
1620 rContext.xSMgr,
1621 rContext.xProcessor,
1622 rContext.xEnv,
1623 rContext.xOrigEnv,
1624 aTransArg );
1627 uno::Reference< ucb::XContent > xChild
1628 = xChildAccess->queryContent();
1629 if ( xChild.is() )
1631 // Recursion!
1633 aSubCtx.aArg.SourceURL
1634 = xChild->getIdentifier()->getContentIdentifier();
1636 globalTransfer_( aSubCtx,
1637 xChild,
1638 xNew,
1639 xChildRow );
1642 while ( xResultSet->next() );
1645 catch ( sdbc::SQLException const & )
1650 try {
1651 uno::Reference< ucb::XCommandProcessor > xcp(
1652 xTarget, uno::UNO_QUERY );
1654 uno::Any aAny;
1655 uno::Reference< ucb::XCommandInfo > xci;
1656 if(xcp.is())
1657 aAny =
1658 xcp->execute(
1659 ucb::Command(
1660 OUString("getCommandInfo"),
1662 uno::Any()),
1664 rContext.xEnv );
1666 const OUString cmdName("flush");
1667 if((aAny >>= xci) && xci->hasCommandByName(cmdName))
1668 xcp->execute(
1669 ucb::Command(
1670 cmdName,
1672 uno::Any()) ,
1674 rContext.xEnv );
1676 catch( uno::Exception const & )
1681 } /* namescpace */
1683 //=========================================================================
1685 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1687 //=========================================================================
1689 uno::Reference< ucb::XCommandInfo >
1690 UniversalContentBroker::getCommandInfo()
1692 return uno::Reference< ucb::XCommandInfo >( new CommandProcessorInfo() );
1695 //=========================================================================
1696 void UniversalContentBroker::globalTransfer(
1697 const ucb::GlobalTransferCommandArgument2 & rArg,
1698 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1699 throw( uno::Exception )
1701 // Use own command environment with own interaction handler intercepting
1702 // some interaction requests that shall not be handled by the user-supplied
1703 // interaction handler.
1704 uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
1705 if (xEnv.is())
1707 uno::Reference< uno::XComponentContext > xCtx(
1708 comphelper::getComponentContext( m_xSMgr ) );
1710 xLocalEnv.set( ucb::CommandEnvironment::create(
1711 xCtx,
1712 new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
1713 xEnv->getProgressHandler() ) );
1716 //////////////////////////////////////////////////////////////////////
1718 // (1) Try to transfer the content using 'transfer' command.
1720 //////////////////////////////////////////////////////////////////////
1722 uno::Reference< ucb::XContent > xTarget;
1723 uno::Reference< ucb::XContentIdentifier > xId
1724 = createContentIdentifier( rArg.TargetURL );
1725 if ( xId.is() )
1729 xTarget = queryContent( xId );
1731 catch ( ucb::IllegalIdentifierException const & )
1736 if ( !xTarget.is() )
1738 uno::Any aProps
1739 = uno::makeAny(beans::PropertyValue(
1740 OUString( "Uri"),
1742 uno::makeAny(rArg.TargetURL),
1743 beans::PropertyState_DIRECT_VALUE));
1744 ucbhelper::cancelCommandExecution(
1745 ucb::IOErrorCode_CANT_READ,
1746 uno::Sequence< uno::Any >(&aProps, 1),
1747 xEnv,
1748 OUString( "Can't instanciate target object!" ),
1749 this );
1750 // Unreachable
1753 if ( ( rArg.Operation == ucb::TransferCommandOperation_COPY ) ||
1754 ( rArg.Operation == ucb::TransferCommandOperation_MOVE ) )
1756 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1757 xTarget, uno::UNO_QUERY );
1758 if ( !xCommandProcessor.is() )
1760 uno::Any aProps
1761 = uno::makeAny(
1762 beans::PropertyValue(
1763 OUString( "Uri"),
1765 uno::makeAny(rArg.TargetURL),
1766 beans::PropertyState_DIRECT_VALUE));
1767 ucbhelper::cancelCommandExecution(
1768 ucb::IOErrorCode_CANT_READ,
1769 uno::Sequence< uno::Any >(&aProps, 1),
1770 xEnv,
1771 OUString( "Target content is not a XCommandProcessor!" ),
1772 this );
1773 // Unreachable
1776 ucb::TransferInfo2 aTransferArg(
1777 ( rArg.Operation
1778 == ucb::TransferCommandOperation_MOVE ), // MoveData
1779 rArg.SourceURL,
1780 rArg.NewTitle,
1781 rArg.NameClash,
1782 rArg.MimeType );
1784 bool bRetry;
1787 bRetry = false;
1791 ucb::Command aCommand(
1792 OUString( "transfer" ), // Name
1793 -1, // Handle
1794 uno::makeAny( aTransferArg ) ); // Argument
1796 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
1798 // Command succeeded. We're done.
1799 return;
1801 catch ( ucb::InteractiveBadTransferURLException const & )
1803 // Source URL is not supported by target. Try to transfer
1804 // the content "manually".
1806 catch ( ucb::UnsupportedCommandException const & )
1808 // 'transfer' command is not supported by commandprocessor.
1809 // Try to transfer manually.
1811 catch ( ucb::UnsupportedNameClashException const & exc )
1813 OSL_ENSURE( aTransferArg.NameClash == exc.NameClash,
1814 "nameclash mismatch!" );
1815 if ( exc.NameClash == ucb::NameClash::ASK )
1817 // Try to detect a name clash by invoking "transfer" with
1818 // NameClash::ERROR.
1821 ucb::TransferInfo2 aTransferArg1(
1822 aTransferArg.MoveData,
1823 aTransferArg.SourceURL,
1824 aTransferArg.NewTitle,
1825 ucb::NameClash::ERROR,
1826 aTransferArg.MimeType );
1828 ucb::Command aCommand1(
1829 OUString("transfer"),
1831 uno::makeAny( aTransferArg1 ) );
1833 xCommandProcessor->execute( aCommand1, 0, xLocalEnv );
1835 // Command succeeded. We're done.
1836 return;
1838 catch ( ucb::UnsupportedNameClashException const & )
1840 // No chance to solve name clashes, because I'm not
1841 // able to detect whether there is one.
1842 throw exc; // Not just 'throw;'!
1844 catch ( ucb::NameClashException const & )
1846 // There's a clash. Use interaction handler to solve it.
1848 uno::Any aExc;
1849 OUString aNewTitle;
1850 NameClashContinuation eCont
1851 = interactiveNameClashResolve(
1852 xEnv, // always use original environment!
1853 rArg.TargetURL, // target folder URL
1854 createDesiredName(
1855 aTransferArg ), // clashing name
1856 aExc,
1857 aNewTitle );
1859 switch ( eCont )
1861 case NOT_HANDLED:
1862 // Not handled.
1863 cppu::throwException( aExc );
1864 // break;
1866 case UNKNOWN:
1867 // Handled, but not clear, how...
1868 // fall-thru intended.
1870 case ABORT:
1871 throw ucb::CommandFailedException(
1872 OUString(
1873 "abort requested via interaction "
1874 "handler" ),
1875 uno::Reference< uno::XInterface >(),
1876 aExc );
1877 // break;
1879 case OVERWRITE:
1880 aTransferArg.NameClash
1881 = ucb::NameClash::OVERWRITE;
1882 bRetry = true;
1883 break;
1885 case NEW_NAME:
1886 aTransferArg.NewTitle = aNewTitle;
1887 bRetry = true;
1888 break;
1891 OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1894 else
1896 throw;
1900 while ( bRetry );
1903 //////////////////////////////////////////////////////////////////////
1905 // (2) Try to transfer the content "manually".
1907 //////////////////////////////////////////////////////////////////////
1909 uno::Reference< ucb::XContent > xSource;
1912 uno::Reference< ucb::XContentIdentifier > xId2
1913 = createContentIdentifier( rArg.SourceURL );
1914 if ( xId2.is() )
1915 xSource = queryContent( xId2 );
1917 catch ( ucb::IllegalIdentifierException const & )
1919 // Error handling via "if ( !xSource.is() )" below.
1922 if ( !xSource.is() )
1924 uno::Any aProps
1925 = uno::makeAny(beans::PropertyValue(
1926 OUString( "Uri"),
1928 uno::makeAny(rArg.SourceURL),
1929 beans::PropertyState_DIRECT_VALUE));
1930 ucbhelper::cancelCommandExecution(
1931 ucb::IOErrorCode_CANT_READ,
1932 uno::Sequence< uno::Any >(&aProps, 1),
1933 xEnv,
1934 OUString( "Can't instanciate source object!" ),
1935 this );
1936 // Unreachable
1939 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1940 xSource, uno::UNO_QUERY );
1941 if ( !xCommandProcessor.is() )
1943 uno::Any aProps
1944 = uno::makeAny(beans::PropertyValue(
1945 OUString( "Uri"),
1947 uno::makeAny(rArg.SourceURL),
1948 beans::PropertyState_DIRECT_VALUE));
1949 ucbhelper::cancelCommandExecution(
1950 ucb::IOErrorCode_CANT_READ,
1951 uno::Sequence< uno::Any >(&aProps, 1),
1952 xEnv,
1953 OUString( "Source content is not a XCommandProcessor!" ),
1954 this );
1955 // Unreachable
1958 // Obtain interesting property values from source...
1960 uno::Sequence< beans::Property > aProps( 4 );
1962 aProps[ 0 ].Name = OUString("IsFolder");
1963 aProps[ 0 ].Handle = -1; /* unknown */
1964 aProps[ 1 ].Name = OUString("IsDocument");
1965 aProps[ 1 ].Handle = -1; /* unknown */
1966 aProps[ 2 ].Name = OUString("TargetURL");
1967 aProps[ 2 ].Handle = -1; /* unknown */
1968 aProps[ 3 ].Name = OUString("BaseURI");
1969 aProps[ 3 ].Handle = -1; /* unknown */
1971 ucb::Command aGetPropsCommand(
1972 OUString("getPropertyValues"),
1974 uno::makeAny( aProps ) );
1976 uno::Reference< sdbc::XRow > xRow;
1977 xCommandProcessor->execute( aGetPropsCommand, 0, xLocalEnv ) >>= xRow;
1979 if ( !xRow.is() )
1981 uno::Any aProps2
1982 = uno::makeAny(beans::PropertyValue(
1983 OUString( "Uri"),
1985 uno::makeAny(rArg.SourceURL),
1986 beans::PropertyState_DIRECT_VALUE));
1987 ucbhelper::cancelCommandExecution(
1988 ucb::IOErrorCode_CANT_READ,
1989 uno::Sequence< uno::Any >(&aProps2, 1),
1990 xEnv,
1991 OUString( "Unable to get properties from source object!" ),
1992 this );
1993 // Unreachable
1996 TransferCommandContext aTransferCtx(
1997 m_xSMgr, this, xLocalEnv, xEnv, rArg );
1999 if ( rArg.NewTitle.isEmpty() )
2001 // BaseURI: property is optional.
2002 OUString aBaseURI( xRow->getString( 4 ) );
2003 if ( !aBaseURI.isEmpty() )
2005 aTransferCtx.aArg.NewTitle
2006 = createDesiredName( aBaseURI, OUString() );
2010 // Do it!
2011 globalTransfer_( aTransferCtx, xSource, xTarget, xRow );
2013 //////////////////////////////////////////////////////////////////////
2015 // (3) Delete source, if operation is MOVE.
2017 //////////////////////////////////////////////////////////////////////
2019 if ( rArg.Operation == ucb::TransferCommandOperation_MOVE )
2023 ucb::Command aCommand(
2024 OUString("delete"), // Name
2025 -1, // Handle
2026 uno::makeAny( sal_Bool( sal_True ) ) ); // Argument
2028 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2030 catch ( uno::Exception const & )
2032 OSL_FAIL( "Cannot delete source object!" );
2033 throw;
2038 uno::Any UniversalContentBroker::checkIn( const ucb::CheckinArgument& rArg,
2039 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw ( uno::Exception )
2041 uno::Any aRet;
2042 // Use own command environment with own interaction handler intercepting
2043 // some interaction requests that shall not be handled by the user-supplied
2044 // interaction handler.
2045 uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
2046 if (xEnv.is())
2048 uno::Reference< uno::XComponentContext > xCtx(
2049 comphelper::getComponentContext( m_xSMgr ) );
2051 xLocalEnv.set( ucb::CommandEnvironment::create(
2052 xCtx,
2053 new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
2054 xEnv->getProgressHandler() ) );
2057 uno::Reference< ucb::XContent > xTarget;
2058 uno::Reference< ucb::XContentIdentifier > xId
2059 = createContentIdentifier( rArg.TargetURL );
2060 if ( xId.is() )
2064 xTarget = queryContent( xId );
2066 catch ( ucb::IllegalIdentifierException const & )
2071 if ( !xTarget.is() )
2073 uno::Any aProps
2074 = uno::makeAny(beans::PropertyValue(
2075 OUString( "Uri" ), -1,
2076 uno::makeAny( rArg.TargetURL ),
2077 beans::PropertyState_DIRECT_VALUE ) );
2078 ucbhelper::cancelCommandExecution(
2079 ucb::IOErrorCode_CANT_READ,
2080 uno::Sequence< uno::Any >( &aProps, 1 ),
2081 xEnv,
2082 OUString( "Can't instanciate target object!" ),
2083 this );
2084 // Unreachable
2087 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
2088 xTarget, uno::UNO_QUERY );
2089 if ( !xCommandProcessor.is() )
2091 uno::Any aProps
2092 = uno::makeAny(
2093 beans::PropertyValue(
2094 OUString( "Uri" ), -1,
2095 uno::makeAny( rArg.TargetURL ),
2096 beans::PropertyState_DIRECT_VALUE ) );
2097 ucbhelper::cancelCommandExecution(
2098 ucb::IOErrorCode_CANT_READ,
2099 uno::Sequence< uno::Any >( &aProps, 1 ),
2100 xEnv,
2101 OUString( "Target content is not a XCommandProcessor!" ),
2102 this );
2103 // Unreachable
2108 ucb::Command aCommand(
2109 OUString( "checkin" ), -1,
2110 uno::makeAny( rArg ) );
2112 aRet = xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2114 catch ( ucb::UnsupportedCommandException const & )
2116 // 'checkin' command is not supported by commandprocessor:
2117 // ignore.
2119 return aRet;
2122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */